summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Documentation/.gitignore7
-rw-r--r--Documentation/ABI/testing/sysfs-driver-hid-roccat-kone7
-rw-r--r--Documentation/DocBook/drm.tmpl12
-rw-r--r--Documentation/DocBook/v4l/v4l2.xml2
-rw-r--r--Documentation/DocBook/v4l/vidioc-query-dv-preset.xml6
-rw-r--r--Documentation/cpu-hotplug.txt2
-rw-r--r--Documentation/edac.txt152
-rw-r--r--Documentation/feature-removal-schedule.txt27
-rw-r--r--Documentation/filesystems/nfs/nfsroot.txt2
-rw-r--r--Documentation/filesystems/xfs-delayed-logging-design.txt5
-rw-r--r--Documentation/hwmon/ltc424524
-rw-r--r--Documentation/i2c/busses/i2c-ali15354
-rw-r--r--Documentation/i2c/busses/i2c-ali15632
-rw-r--r--Documentation/i2c/busses/i2c-ali15x316
-rw-r--r--Documentation/i2c/busses/i2c-pca-isa14
-rw-r--r--Documentation/i2c/busses/i2c-sis559558
-rw-r--r--Documentation/i2c/busses/i2c-sis6308
-rw-r--r--Documentation/i2c/ten-bit-addresses6
-rw-r--r--Documentation/kbuild/kbuild.txt6
-rw-r--r--Documentation/kbuild/makefiles.txt100
-rw-r--r--Documentation/kernel-parameters.txt4
-rw-r--r--Documentation/mutex-design.txt4
-rw-r--r--Documentation/networking/bonding.txt84
-rw-r--r--Documentation/networking/ip-sysctl.txt2
-rw-r--r--Documentation/networking/packet_mmap.txt26
-rw-r--r--Documentation/rt-mutex-design.txt2
-rw-r--r--Documentation/timers/Makefile2
-rw-r--r--Documentation/video4linux/CARDLIST.saa71345
-rw-r--r--Documentation/video4linux/gspca.txt1
-rw-r--r--Documentation/vm/page-types.c2
-rw-r--r--MAINTAINERS51
-rw-r--r--Makefile69
-rw-r--r--arch/Kconfig7
-rw-r--r--arch/arm/common/sa1111.c9
-rw-r--r--arch/arm/configs/ap4evb_defconfig604
-rw-r--r--arch/arm/configs/g3evm_defconfig73
-rw-r--r--arch/arm/configs/g4evm_defconfig72
-rw-r--r--arch/arm/configs/mx25_defconfig1756
-rw-r--r--arch/arm/configs/mx3_defconfig695
-rw-r--r--arch/arm/mach-kirkwood/common.c38
-rw-r--r--arch/arm/mach-kirkwood/common.h2
-rw-r--r--arch/arm/mach-kirkwood/include/mach/kirkwood.h3
-rw-r--r--arch/arm/mach-kirkwood/openrd-setup.c13
-rw-r--r--arch/arm/mach-msm/acpuclock-arm11.c1
-rw-r--r--arch/arm/mach-msm/clock.c1
-rw-r--r--arch/arm/mach-msm/dma.c1
-rw-r--r--arch/arm/mach-mx2/Kconfig10
-rw-r--r--arch/arm/mach-mx2/devices.c18
-rw-r--r--arch/arm/mach-mx2/devices.h1
-rw-r--r--arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c181
-rw-r--r--arch/arm/mach-mx2/mach-cpuimx27.c93
-rw-r--r--arch/arm/mach-mx2/mach-pca100.c2
-rw-r--r--arch/arm/mach-mx25/clock.c2
-rw-r--r--arch/arm/mach-mx25/devices.c20
-rw-r--r--arch/arm/mach-mx25/devices.h1
-rw-r--r--arch/arm/mach-mx25/mach-mx25pdk.c36
-rw-r--r--arch/arm/mach-mx3/mach-mx31lilly.c34
-rw-r--r--arch/arm/mach-mx3/mach-pcm037.c3
-rw-r--r--arch/arm/mach-mx3/mach-pcm043.c2
-rw-r--r--arch/arm/mach-mx5/board-mx51_babbage.c26
-rw-r--r--arch/arm/mach-mx5/clock-mx51.c11
-rw-r--r--arch/arm/mach-mx5/devices.c58
-rw-r--r--arch/arm/mach-mx5/devices.h3
-rw-r--r--arch/arm/mach-nomadik/clock.c11
-rw-r--r--arch/arm/mach-nomadik/clock.h2
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c8
-rw-r--r--arch/arm/mach-omap2/board-omap3stalker.c4
-rw-r--r--arch/arm/mach-omap2/board-overo.c42
-rw-r--r--arch/arm/mach-omap2/mcbsp.c10
-rw-r--r--arch/arm/mach-omap2/pm34xx.c4
-rw-r--r--arch/arm/mach-omap2/usb-ehci.c2
-rw-r--r--arch/arm/mach-shmobile/Kconfig13
-rw-r--r--arch/arm/mach-shmobile/Makefile6
-rw-r--r--arch/arm/mach-shmobile/board-ap4evb.c499
-rw-r--r--arch/arm/mach-shmobile/board-g3evm.c58
-rw-r--r--arch/arm/mach-shmobile/board-g4evm.c153
-rw-r--r--arch/arm/mach-shmobile/clock-sh7367.c357
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c399
-rw-r--r--arch/arm/mach-shmobile/clock-sh7377.c369
-rw-r--r--arch/arm/mach-shmobile/clock.c44
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h10
-rw-r--r--arch/arm/mach-shmobile/include/mach/irqs.h6
-rw-r--r--arch/arm/mach-shmobile/include/mach/memory.h3
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h24
-rw-r--r--arch/arm/mach-shmobile/include/mach/vmalloc.h3
-rw-r--r--arch/arm/mach-shmobile/intc-sh7367.c178
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c232
-rw-r--r--arch/arm/mach-shmobile/intc-sh7377.c300
-rw-r--r--arch/arm/mach-shmobile/setup-sh7367.c30
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c391
-rw-r--r--arch/arm/mach-shmobile/setup-sh7377.c34
-rw-r--r--arch/arm/mach-ux500/clock.c104
-rw-r--r--arch/arm/mach-ux500/clock.h22
-rw-r--r--arch/arm/mach-ux500/cpu.c6
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c1
-rw-r--r--arch/arm/mm/init.c6
-rw-r--r--arch/arm/plat-mxc/clock.c37
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx25.h19
-rw-r--r--arch/arm/plat-mxc/include/mach/iomux-mx51.h18
-rw-r--r--arch/arm/plat-mxc/include/mach/mmc.h3
-rw-r--r--arch/arm/plat-mxc/include/mach/mx25.h2
-rw-r--r--arch/arm/plat-mxc/include/mach/mxc_nand.h4
-rw-r--r--arch/arm/plat-mxc/include/mach/ssi.h3
-rw-r--r--arch/arm/plat-nomadik/timer.c26
-rw-r--r--arch/arm/plat-omap/dmtimer.c6
-rw-r--r--arch/arm/plat-omap/gpio.c1
-rw-r--r--arch/arm/plat-omap/include/plat/mcbsp.h2
-rw-r--r--arch/arm/plat-omap/include/plat/uncompress.h6
-rw-r--r--arch/arm/plat-omap/mcbsp.c51
-rw-r--r--arch/arm/plat-orion/include/plat/audio.h11
-rw-r--r--arch/arm/vfp/vfphw.S2
-rw-r--r--arch/blackfin/include/asm/elf.h1
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF52x_base.h81
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF54x_base.h60
-rw-r--r--arch/cris/arch-v10/drivers/ds1302.c20
-rw-r--r--arch/cris/arch-v10/drivers/pcf8563.c19
-rw-r--r--arch/cris/arch-v10/kernel/irq.c8
-rw-r--r--arch/cris/arch-v10/lib/dmacopy.c15
-rw-r--r--arch/cris/arch-v10/lib/hw_settings.S14
-rw-r--r--arch/cris/arch-v32/drivers/Kconfig16
-rw-r--r--arch/cris/arch-v32/drivers/i2c.c22
-rw-r--r--arch/cris/arch-v32/drivers/pcf8563.c21
-rw-r--r--arch/cris/arch-v32/kernel/crisksyms.c4
-rw-r--r--arch/cris/arch-v32/kernel/irq.c14
-rw-r--r--arch/cris/arch-v32/kernel/smp.c4
-rw-r--r--arch/cris/include/arch-v10/arch/irq.h9
-rw-r--r--arch/cris/include/arch-v32/arch/irq.h4
-rw-r--r--arch/cris/include/asm/param.h17
-rw-r--r--arch/frv/kernel/break.S4
-rw-r--r--arch/frv/kernel/entry.S2
-rw-r--r--arch/frv/kernel/head.S2
-rw-r--r--arch/frv/kernel/vmlinux.lds.S10
-rw-r--r--arch/frv/mm/fault.c8
-rw-r--r--arch/frv/mm/tlb-miss.S2
-rw-r--r--arch/h8300/boot/compressed/head.S2
-rw-r--r--arch/h8300/boot/compressed/vmlinux.lds2
-rw-r--r--arch/ia64/include/asm/asmmacro.h12
-rw-r--r--arch/ia64/include/asm/cache.h2
-rw-r--r--arch/ia64/include/asm/percpu.h2
-rw-r--r--arch/ia64/kernel/Makefile.gate2
-rw-r--r--arch/ia64/kernel/gate-data.S2
-rw-r--r--arch/ia64/kernel/gate.S8
-rw-r--r--arch/ia64/kernel/gate.lds.S10
-rw-r--r--arch/ia64/kernel/init_task.c2
-rw-r--r--arch/ia64/kernel/ivt.S2
-rw-r--r--arch/ia64/kernel/minstate.h4
-rw-r--r--arch/ia64/kernel/paravirtentry.S2
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S28
-rw-r--r--arch/ia64/kvm/vmm_ivt.S2
-rw-r--r--arch/ia64/scripts/unwcheck.py2
-rw-r--r--arch/ia64/xen/gate-data.S2
-rw-r--r--arch/ia64/xen/xensetup.S2
-rw-r--r--arch/m32r/mm/fault.c14
-rw-r--r--arch/m68k/mac/config.c9
-rw-r--r--arch/m68k/mac/misc.c6
-rw-r--r--arch/m68k/sun3/leds.c4
-rw-r--r--arch/m68knommu/kernel/vmlinux.lds.S4
-rw-r--r--arch/m68knommu/platform/68360/head-ram.S2
-rw-r--r--arch/m68knommu/platform/68360/head-rom.S2
-rw-r--r--arch/microblaze/Kconfig3
-rw-r--r--arch/microblaze/include/asm/cacheflush.h13
-rw-r--r--arch/microblaze/include/asm/page.h2
-rw-r--r--arch/microblaze/include/asm/uaccess.h4
-rw-r--r--arch/microblaze/kernel/misc.S2
-rw-r--r--arch/microblaze/mm/fault.c1
-rw-r--r--arch/microblaze/mm/init.c7
-rw-r--r--arch/mips/Kbuild15
-rw-r--r--arch/mips/Kbuild.platforms31
-rw-r--r--arch/mips/Makefile519
-rw-r--r--arch/mips/alchemy/Platform109
-rw-r--r--arch/mips/alchemy/common/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/Makefile2
-rw-r--r--arch/mips/alchemy/devboards/pb1200/Makefile2
-rw-r--r--arch/mips/alchemy/mtx-1/Makefile5
-rw-r--r--arch/mips/alchemy/xxs1500/Makefile4
-rw-r--r--arch/mips/ar7/Makefile1
-rw-r--r--arch/mips/ar7/Platform6
-rw-r--r--arch/mips/bcm47xx/Platform7
-rw-r--r--arch/mips/bcm63xx/Makefile2
-rw-r--r--arch/mips/bcm63xx/Platform7
-rw-r--r--arch/mips/boot/Makefile49
-rw-r--r--arch/mips/boot/compressed/Makefile54
-rw-r--r--arch/mips/cavium-octeon/Makefile3
-rw-r--r--arch/mips/cavium-octeon/Platform11
-rw-r--r--arch/mips/cobalt/Makefile2
-rw-r--r--arch/mips/cobalt/Platform6
-rw-r--r--arch/mips/dec/Makefile2
-rw-r--r--arch/mips/dec/Platform8
-rw-r--r--arch/mips/dec/promcon.c3
-rw-r--r--arch/mips/emma/Makefile6
-rw-r--r--arch/mips/emma/Platform4
-rw-r--r--arch/mips/include/asm/mach-powertv/asic_reg_map.h2
-rw-r--r--arch/mips/include/asm/mach-powertv/dma-coherence.h8
-rw-r--r--arch/mips/include/asm/mach-powertv/ioremap.h165
-rw-r--r--arch/mips/jazz/Makefile2
-rw-r--r--arch/mips/jazz/Platform6
-rw-r--r--arch/mips/kernel/Makefile2
-rw-r--r--arch/mips/lasat/Makefile2
-rw-r--r--arch/mips/lasat/Platform7
-rw-r--r--arch/mips/lasat/image/head.S2
-rw-r--r--arch/mips/lasat/image/romscript.normal2
-rw-r--r--arch/mips/loongson/Platform32
-rw-r--r--arch/mips/loongson/common/cs5536/Makefile2
-rw-r--r--arch/mips/loongson/fuloong-2e/Makefile2
-rw-r--r--arch/mips/math-emu/Makefile1
-rw-r--r--arch/mips/math-emu/dp_modf.c2
-rw-r--r--arch/mips/math-emu/dp_tint.c3
-rw-r--r--arch/mips/math-emu/dp_tlong.c3
-rw-r--r--arch/mips/math-emu/sp_modf.c2
-rw-r--r--arch/mips/math-emu/sp_tint.c3
-rw-r--r--arch/mips/math-emu/sp_tlong.c3
-rw-r--r--arch/mips/mipssim/Makefile2
-rw-r--r--arch/mips/mipssim/Platform6
-rw-r--r--arch/mips/mm/Makefile2
-rw-r--r--arch/mips/mm/fault.c1
-rw-r--r--arch/mips/mti-malta/Makefile2
-rw-r--r--arch/mips/mti-malta/Platform7
-rw-r--r--arch/mips/nxp/pnx833x/stb22x/Makefile3
-rw-r--r--arch/mips/nxp/pnx8550/jbs/Makefile4
-rw-r--r--arch/mips/nxp/pnx8550/stb810/Makefile4
-rw-r--r--arch/mips/pci/ops-titan-ht.c4
-rw-r--r--arch/mips/pmc-sierra/Platform14
-rw-r--r--arch/mips/pmc-sierra/yosemite/ht-irq.c13
-rw-r--r--arch/mips/pnx833x/Makefile3
-rw-r--r--arch/mips/pnx833x/Platform5
-rw-r--r--arch/mips/pnx833x/common/Makefile (renamed from arch/mips/nxp/pnx833x/common/Makefile)2
-rw-r--r--arch/mips/pnx833x/common/interrupts.c (renamed from arch/mips/nxp/pnx833x/common/interrupts.c)0
-rw-r--r--arch/mips/pnx833x/common/platform.c (renamed from arch/mips/nxp/pnx833x/common/platform.c)0
-rw-r--r--arch/mips/pnx833x/common/prom.c (renamed from arch/mips/nxp/pnx833x/common/prom.c)0
-rw-r--r--arch/mips/pnx833x/common/reset.c (renamed from arch/mips/nxp/pnx833x/common/reset.c)0
-rw-r--r--arch/mips/pnx833x/common/setup.c (renamed from arch/mips/nxp/pnx833x/common/setup.c)0
-rw-r--r--arch/mips/pnx833x/stb22x/Makefile1
-rw-r--r--arch/mips/pnx833x/stb22x/board.c (renamed from arch/mips/nxp/pnx833x/stb22x/board.c)0
-rw-r--r--arch/mips/pnx8550/Makefile3
-rw-r--r--arch/mips/pnx8550/Platform7
-rw-r--r--arch/mips/pnx8550/common/Makefile (renamed from arch/mips/nxp/pnx8550/common/Makefile)2
-rw-r--r--arch/mips/pnx8550/common/int.c (renamed from arch/mips/nxp/pnx8550/common/int.c)0
-rw-r--r--arch/mips/pnx8550/common/pci.c (renamed from arch/mips/nxp/pnx8550/common/pci.c)0
-rw-r--r--arch/mips/pnx8550/common/platform.c (renamed from arch/mips/nxp/pnx8550/common/platform.c)0
-rw-r--r--arch/mips/pnx8550/common/proc.c (renamed from arch/mips/nxp/pnx8550/common/proc.c)0
-rw-r--r--arch/mips/pnx8550/common/prom.c (renamed from arch/mips/nxp/pnx8550/common/prom.c)0
-rw-r--r--arch/mips/pnx8550/common/reset.c (renamed from arch/mips/nxp/pnx8550/common/reset.c)0
-rw-r--r--arch/mips/pnx8550/common/setup.c (renamed from arch/mips/nxp/pnx8550/common/setup.c)0
-rw-r--r--arch/mips/pnx8550/common/time.c (renamed from arch/mips/nxp/pnx8550/common/time.c)0
-rw-r--r--arch/mips/pnx8550/jbs/Makefile4
-rw-r--r--arch/mips/pnx8550/jbs/board_setup.c (renamed from arch/mips/nxp/pnx8550/jbs/board_setup.c)0
-rw-r--r--arch/mips/pnx8550/jbs/init.c (renamed from arch/mips/nxp/pnx8550/jbs/init.c)0
-rw-r--r--arch/mips/pnx8550/jbs/irqmap.c (renamed from arch/mips/nxp/pnx8550/jbs/irqmap.c)0
-rw-r--r--arch/mips/pnx8550/stb810/Makefile4
-rw-r--r--arch/mips/pnx8550/stb810/board_setup.c (renamed from arch/mips/nxp/pnx8550/stb810/board_setup.c)0
-rw-r--r--arch/mips/pnx8550/stb810/irqmap.c (renamed from arch/mips/nxp/pnx8550/stb810/irqmap.c)0
-rw-r--r--arch/mips/pnx8550/stb810/prom_init.c (renamed from arch/mips/nxp/pnx8550/stb810/prom_init.c)0
-rw-r--r--arch/mips/powertv/Makefile5
-rw-r--r--arch/mips/powertv/Platform7
-rw-r--r--arch/mips/powertv/asic/asic-calliope.c2
-rw-r--r--arch/mips/powertv/asic/asic-cronus.c4
-rw-r--r--arch/mips/powertv/asic/asic-zeus.c2
-rw-r--r--arch/mips/powertv/asic/asic_devices.c24
-rw-r--r--arch/mips/powertv/ioremap.c136
-rw-r--r--arch/mips/powertv/memory.c342
-rw-r--r--arch/mips/rb532/Makefile2
-rw-r--r--arch/mips/rb532/Platform7
-rw-r--r--arch/mips/sgi-ip22/Makefile2
-rw-r--r--arch/mips/sgi-ip22/Platform34
-rw-r--r--arch/mips/sgi-ip27/Makefile2
-rw-r--r--arch/mips/sgi-ip27/Platform19
-rw-r--r--arch/mips/sgi-ip27/ip27-klconfig.c8
-rw-r--r--arch/mips/sgi-ip32/Makefile2
-rw-r--r--arch/mips/sgi-ip32/Platform11
-rw-r--r--arch/mips/sibyte/Makefile27
-rw-r--r--arch/mips/sibyte/Platform43
-rw-r--r--arch/mips/sibyte/bcm1480/Makefile2
-rw-r--r--arch/mips/sibyte/common/Makefile2
-rw-r--r--arch/mips/sibyte/sb1250/Makefile2
-rw-r--r--arch/mips/sni/Makefile2
-rw-r--r--arch/mips/sni/Platform11
-rw-r--r--arch/mips/txx9/Makefile17
-rw-r--r--arch/mips/txx9/Platform10
-rw-r--r--arch/mips/txx9/generic/Makefile2
-rw-r--r--arch/mips/txx9/jmr3927/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4927/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4938/Makefile2
-rw-r--r--arch/mips/txx9/rbtx4939/Makefile2
-rw-r--r--arch/mips/vr41xx/Platform32
-rw-r--r--arch/mips/vr41xx/common/Makefile2
-rw-r--r--arch/mips/wrppmc/Makefile (renamed from arch/mips/gt64120/wrppmc/Makefile)4
-rw-r--r--arch/mips/wrppmc/Platform7
-rw-r--r--arch/mips/wrppmc/irq.c (renamed from arch/mips/gt64120/wrppmc/irq.c)0
-rw-r--r--arch/mips/wrppmc/pci.c (renamed from arch/mips/gt64120/wrppmc/pci.c)0
-rw-r--r--arch/mips/wrppmc/reset.c (renamed from arch/mips/gt64120/wrppmc/reset.c)0
-rw-r--r--arch/mips/wrppmc/serial.c (renamed from arch/mips/gt64120/wrppmc/serial.c)0
-rw-r--r--arch/mips/wrppmc/setup.c (renamed from arch/mips/gt64120/wrppmc/setup.c)0
-rw-r--r--arch/mips/wrppmc/time.c (renamed from arch/mips/gt64120/wrppmc/time.c)0
-rw-r--r--arch/mn10300/mm/fault.c9
-rw-r--r--arch/parisc/include/asm/cache.h2
-rw-r--r--arch/parisc/include/asm/system.h2
-rw-r--r--arch/parisc/kernel/head.S2
-rw-r--r--arch/parisc/kernel/init_task.c6
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S12
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--arch/powerpc/Makefile5
-rw-r--r--arch/powerpc/boot/4xx.c12
-rw-r--r--arch/powerpc/boot/dts/icon.dts447
-rw-r--r--arch/powerpc/boot/dts/katmai.dts1
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts4
-rw-r--r--arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts15
-rw-r--r--arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts7
-rw-r--r--arch/powerpc/boot/dts/p1021mds.dts698
-rw-r--r--arch/powerpc/boot/dts/redwood.dts122
-rw-r--r--arch/powerpc/configs/44x/icon_defconfig1451
-rw-r--r--arch/powerpc/include/asm/cache.h2
-rw-r--r--arch/powerpc/include/asm/cputable.h1
-rw-r--r--arch/powerpc/include/asm/kexec.h13
-rw-r--r--arch/powerpc/include/asm/macio.h4
-rw-r--r--arch/powerpc/include/asm/page_64.h8
-rw-r--r--arch/powerpc/include/asm/reg_booke.h33
-rw-r--r--arch/powerpc/kernel/Makefile8
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/crash.c4
-rw-r--r--arch/powerpc/kernel/fsl_booke_entry_mapping.S237
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S200
-rw-r--r--arch/powerpc/kernel/kprobes.c14
-rw-r--r--arch/powerpc/kernel/misc_32.S17
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c2
-rw-r--r--arch/powerpc/kernel/swsusp_booke.S193
-rw-r--r--arch/powerpc/kernel/traps.c88
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S10
-rw-r--r--arch/powerpc/kvm/e500.c2
-rw-r--r--arch/powerpc/oprofile/op_model_cell.c2
-rw-r--r--arch/powerpc/platforms/44x/Kconfig11
-rw-r--r--arch/powerpc/platforms/44x/ppc44x_simple.c3
-rw-r--r--arch/powerpc/platforms/512x/Kconfig13
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c102
-rw-r--r--arch/powerpc/platforms/cell/iommu.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c4
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c117
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h3
-rw-r--r--arch/powerpc/sysdev/fsl_rio.c2
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c119
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.h58
-rw-r--r--arch/s390/appldata/appldata_os.c2
-rw-r--r--arch/s390/crypto/Makefile2
-rw-r--r--arch/s390/crypto/crypto_des.h2
-rw-r--r--arch/s390/crypto/des_s390.c238
-rw-r--r--arch/s390/defconfig23
-rw-r--r--arch/s390/include/asm/cache.h2
-rw-r--r--arch/s390/include/asm/ccwdev.h2
-rw-r--r--arch/s390/kernel/module.c6
-rw-r--r--arch/s390/kernel/swsusp_asm64.S2
-rw-r--r--arch/s390/kvm/kvm-s390.c2
-rw-r--r--arch/s390/kvm/sigp.c2
-rw-r--r--arch/s390/mm/cmm.c11
-rw-r--r--arch/s390/mm/extmem.c19
-rw-r--r--arch/sh/Kconfig16
-rw-r--r--arch/sh/boards/Kconfig3
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c2
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c102
-rw-r--r--arch/sh/boards/mach-migor/setup.c2
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c8
-rw-r--r--arch/sh/boot/compressed/vmlinux.scr2
-rw-r--r--arch/sh/boot/romimage/Makefile13
-rw-r--r--arch/sh/boot/romimage/head.S42
-rw-r--r--arch/sh/boot/romimage/mmcif-sh7724.c72
-rw-r--r--arch/sh/boot/romimage/vmlinux.scr2
-rw-r--r--arch/sh/drivers/pci/pci.c2
-rw-r--r--arch/sh/include/asm/cache.h2
-rw-r--r--arch/sh/include/asm/io.h8
-rw-r--r--arch/sh/include/asm/machvec.h9
-rw-r--r--arch/sh/include/cpu-sh4/cpu/sh7724.h1
-rw-r--r--arch/sh/include/mach-common/mach/romimage.h10
-rw-r--r--arch/sh/include/mach-ecovec24/mach/romimage.h27
-rw-r--r--arch/sh/include/mach-kfr2r09/mach/romimage.h10
-rw-r--r--arch/sh/kernel/Makefile3
-rw-r--r--arch/sh/kernel/dwarf.c19
-rw-r--r--arch/sh/kernel/io.c22
-rw-r--r--arch/sh/kernel/io_generic.c20
-rw-r--r--arch/sh/kernel/io_trapped.c4
-rw-r--r--arch/sh/kernel/machvec.c17
-rw-r--r--arch/sh/kernel/return_address.c2
-rw-r--r--arch/sparc/boot/btfixupprep.c2
-rw-r--r--arch/sparc/include/asm/cache.h2
-rw-r--r--arch/tile/Kbuild3
-rw-r--r--arch/tile/Kconfig352
-rw-r--r--arch/tile/Kconfig.debug43
-rw-r--r--arch/tile/Makefile52
-rw-r--r--arch/tile/configs/tile_defconfig1289
-rw-r--r--arch/tile/include/arch/abi.h93
-rw-r--r--arch/tile/include/arch/chip.h23
-rw-r--r--arch/tile/include/arch/chip_tile64.h252
-rw-r--r--arch/tile/include/arch/chip_tilepro.h252
-rw-r--r--arch/tile/include/arch/interrupts.h19
-rw-r--r--arch/tile/include/arch/interrupts_32.h304
-rw-r--r--arch/tile/include/arch/sim_def.h512
-rw-r--r--arch/tile/include/arch/spr_def.h19
-rw-r--r--arch/tile/include/arch/spr_def_32.h162
-rw-r--r--arch/tile/include/asm/Kbuild3
-rw-r--r--arch/tile/include/asm/asm-offsets.h1
-rw-r--r--arch/tile/include/asm/atomic.h159
-rw-r--r--arch/tile/include/asm/atomic_32.h353
-rw-r--r--arch/tile/include/asm/auxvec.h20
-rw-r--r--arch/tile/include/asm/backtrace.h193
-rw-r--r--arch/tile/include/asm/bitops.h126
-rw-r--r--arch/tile/include/asm/bitops_32.h132
-rw-r--r--arch/tile/include/asm/bitsperlong.h26
-rw-r--r--arch/tile/include/asm/bug.h1
-rw-r--r--arch/tile/include/asm/bugs.h1
-rw-r--r--arch/tile/include/asm/byteorder.h1
-rw-r--r--arch/tile/include/asm/cache.h50
-rw-r--r--arch/tile/include/asm/cacheflush.h145
-rw-r--r--arch/tile/include/asm/checksum.h24
-rw-r--r--arch/tile/include/asm/compat.h308
-rw-r--r--arch/tile/include/asm/cputime.h1
-rw-r--r--arch/tile/include/asm/current.h31
-rw-r--r--arch/tile/include/asm/delay.h34
-rw-r--r--arch/tile/include/asm/device.h1
-rw-r--r--arch/tile/include/asm/div64.h1
-rw-r--r--arch/tile/include/asm/dma-mapping.h102
-rw-r--r--arch/tile/include/asm/dma.h25
-rw-r--r--arch/tile/include/asm/elf.h169
-rw-r--r--arch/tile/include/asm/emergency-restart.h1
-rw-r--r--arch/tile/include/asm/errno.h1
-rw-r--r--arch/tile/include/asm/fcntl.h1
-rw-r--r--arch/tile/include/asm/fixmap.h124
-rw-r--r--arch/tile/include/asm/ftrace.h20
-rw-r--r--arch/tile/include/asm/futex.h136
-rw-r--r--arch/tile/include/asm/hardirq.h47
-rw-r--r--arch/tile/include/asm/highmem.h73
-rw-r--r--arch/tile/include/asm/homecache.h125
-rw-r--r--arch/tile/include/asm/hugetlb.h109
-rw-r--r--arch/tile/include/asm/hv_driver.h60
-rw-r--r--arch/tile/include/asm/hw_irq.h18
-rw-r--r--arch/tile/include/asm/ide.h25
-rw-r--r--arch/tile/include/asm/io.h279
-rw-r--r--arch/tile/include/asm/ioctl.h1
-rw-r--r--arch/tile/include/asm/ioctls.h1
-rw-r--r--arch/tile/include/asm/ipc.h1
-rw-r--r--arch/tile/include/asm/ipcbuf.h1
-rw-r--r--arch/tile/include/asm/irq.h37
-rw-r--r--arch/tile/include/asm/irq_regs.h1
-rw-r--r--arch/tile/include/asm/irqflags.h267
-rw-r--r--arch/tile/include/asm/kdebug.h1
-rw-r--r--arch/tile/include/asm/kexec.h53
-rw-r--r--arch/tile/include/asm/kmap_types.h43
-rw-r--r--arch/tile/include/asm/linkage.h51
-rw-r--r--arch/tile/include/asm/local.h1
-rw-r--r--arch/tile/include/asm/memprof.h33
-rw-r--r--arch/tile/include/asm/mman.h40
-rw-r--r--arch/tile/include/asm/mmu.h31
-rw-r--r--arch/tile/include/asm/mmu_context.h131
-rw-r--r--arch/tile/include/asm/mmzone.h81
-rw-r--r--arch/tile/include/asm/module.h1
-rw-r--r--arch/tile/include/asm/msgbuf.h1
-rw-r--r--arch/tile/include/asm/mutex.h1
-rw-r--r--arch/tile/include/asm/opcode-tile.h30
-rw-r--r--arch/tile/include/asm/opcode-tile_32.h1597
-rw-r--r--arch/tile/include/asm/opcode-tile_64.h1597
-rw-r--r--arch/tile/include/asm/opcode_constants.h26
-rw-r--r--arch/tile/include/asm/opcode_constants_32.h480
-rw-r--r--arch/tile/include/asm/opcode_constants_64.h480
-rw-r--r--arch/tile/include/asm/page.h334
-rw-r--r--arch/tile/include/asm/param.h1
-rw-r--r--arch/tile/include/asm/pci-bridge.h117
-rw-r--r--arch/tile/include/asm/pci.h128
-rw-r--r--arch/tile/include/asm/percpu.h24
-rw-r--r--arch/tile/include/asm/pgalloc.h119
-rw-r--r--arch/tile/include/asm/pgtable.h475
-rw-r--r--arch/tile/include/asm/pgtable_32.h117
-rw-r--r--arch/tile/include/asm/poll.h1
-rw-r--r--arch/tile/include/asm/posix_types.h1
-rw-r--r--arch/tile/include/asm/processor.h339
-rw-r--r--arch/tile/include/asm/ptrace.h163
-rw-r--r--arch/tile/include/asm/resource.h1
-rw-r--r--arch/tile/include/asm/scatterlist.h22
-rw-r--r--arch/tile/include/asm/sections.h37
-rw-r--r--arch/tile/include/asm/sembuf.h1
-rw-r--r--arch/tile/include/asm/setup.h32
-rw-r--r--arch/tile/include/asm/shmbuf.h1
-rw-r--r--arch/tile/include/asm/shmparam.h1
-rw-r--r--arch/tile/include/asm/sigcontext.h27
-rw-r--r--arch/tile/include/asm/sigframe.h33
-rw-r--r--arch/tile/include/asm/siginfo.h30
-rw-r--r--arch/tile/include/asm/signal.h31
-rw-r--r--arch/tile/include/asm/smp.h126
-rw-r--r--arch/tile/include/asm/socket.h1
-rw-r--r--arch/tile/include/asm/sockios.h1
-rw-r--r--arch/tile/include/asm/spinlock.h24
-rw-r--r--arch/tile/include/asm/spinlock_32.h200
-rw-r--r--arch/tile/include/asm/spinlock_types.h60
-rw-r--r--arch/tile/include/asm/stack.h68
-rw-r--r--arch/tile/include/asm/stat.h1
-rw-r--r--arch/tile/include/asm/statfs.h1
-rw-r--r--arch/tile/include/asm/string.h32
-rw-r--r--arch/tile/include/asm/swab.h29
-rw-r--r--arch/tile/include/asm/syscall.h79
-rw-r--r--arch/tile/include/asm/syscalls.h40
-rw-r--r--arch/tile/include/asm/system.h220
-rw-r--r--arch/tile/include/asm/termbits.h1
-rw-r--r--arch/tile/include/asm/termios.h1
-rw-r--r--arch/tile/include/asm/thread_info.h165
-rw-r--r--arch/tile/include/asm/timex.h47
-rw-r--r--arch/tile/include/asm/tlb.h25
-rw-r--r--arch/tile/include/asm/tlbflush.h128
-rw-r--r--arch/tile/include/asm/topology.h85
-rw-r--r--arch/tile/include/asm/traps.h36
-rw-r--r--arch/tile/include/asm/types.h1
-rw-r--r--arch/tile/include/asm/uaccess.h578
-rw-r--r--arch/tile/include/asm/ucontext.h1
-rw-r--r--arch/tile/include/asm/unaligned.h24
-rw-r--r--arch/tile/include/asm/unistd.h47
-rw-r--r--arch/tile/include/asm/user.h21
-rw-r--r--arch/tile/include/asm/xor.h1
-rw-r--r--arch/tile/include/hv/drv_pcie_rc_intf.h38
-rw-r--r--arch/tile/include/hv/hypervisor.h2366
-rw-r--r--arch/tile/include/hv/syscall_public.h42
-rw-r--r--arch/tile/kernel/Makefile16
-rw-r--r--arch/tile/kernel/asm-offsets.c76
-rw-r--r--arch/tile/kernel/backtrace.c634
-rw-r--r--arch/tile/kernel/compat.c183
-rw-r--r--arch/tile/kernel/compat_signal.c433
-rw-r--r--arch/tile/kernel/early_printk.c109
-rw-r--r--arch/tile/kernel/entry.S141
-rw-r--r--arch/tile/kernel/head_32.S180
-rw-r--r--arch/tile/kernel/hvglue.lds56
-rw-r--r--arch/tile/kernel/init_task.c59
-rw-r--r--arch/tile/kernel/intvec_32.S2006
-rw-r--r--arch/tile/kernel/irq.c227
-rw-r--r--arch/tile/kernel/machine_kexec.c291
-rw-r--r--arch/tile/kernel/messaging.c115
-rw-r--r--arch/tile/kernel/module.c257
-rw-r--r--arch/tile/kernel/pci-dma.c251
-rw-r--r--arch/tile/kernel/proc.c91
-rw-r--r--arch/tile/kernel/process.c647
-rw-r--r--arch/tile/kernel/ptrace.c203
-rw-r--r--arch/tile/kernel/reboot.c52
-rw-r--r--arch/tile/kernel/regs_32.S145
-rw-r--r--arch/tile/kernel/relocate_kernel.S280
-rw-r--r--arch/tile/kernel/setup.c1497
-rw-r--r--arch/tile/kernel/signal.c359
-rw-r--r--arch/tile/kernel/single_step.c656
-rw-r--r--arch/tile/kernel/smp.c202
-rw-r--r--arch/tile/kernel/smpboot.c293
-rw-r--r--arch/tile/kernel/stack.c485
-rw-r--r--arch/tile/kernel/sys.c122
-rw-r--r--arch/tile/kernel/tile-desc_32.c13826
-rw-r--r--arch/tile/kernel/time.c220
-rw-r--r--arch/tile/kernel/tlb.c97
-rw-r--r--arch/tile/kernel/traps.c237
-rw-r--r--arch/tile/kernel/vmlinux.lds.S98
-rw-r--r--arch/tile/lib/Makefile16
-rw-r--r--arch/tile/lib/__invalidate_icache.S106
-rw-r--r--arch/tile/lib/atomic_32.c347
-rw-r--r--arch/tile/lib/atomic_asm_32.S197
-rw-r--r--arch/tile/lib/checksum.c102
-rw-r--r--arch/tile/lib/cpumask.c51
-rw-r--r--arch/tile/lib/delay.c34
-rw-r--r--arch/tile/lib/exports.c78
-rw-r--r--arch/tile/lib/mb_incoherent.S34
-rw-r--r--arch/tile/lib/memchr_32.c68
-rw-r--r--arch/tile/lib/memcpy_32.S628
-rw-r--r--arch/tile/lib/memcpy_tile64.c271
-rw-r--r--arch/tile/lib/memmove_32.c63
-rw-r--r--arch/tile/lib/memset_32.c274
-rw-r--r--arch/tile/lib/spinlock_32.c221
-rw-r--r--arch/tile/lib/spinlock_common.h64
-rw-r--r--arch/tile/lib/strchr_32.c66
-rw-r--r--arch/tile/lib/strlen_32.c36
-rw-r--r--arch/tile/lib/uaccess.c31
-rw-r--r--arch/tile/lib/usercopy_32.S223
-rw-r--r--arch/tile/mm/Makefile9
-rw-r--r--arch/tile/mm/elf.c164
-rw-r--r--arch/tile/mm/extable.c30
-rw-r--r--arch/tile/mm/fault.c905
-rw-r--r--arch/tile/mm/highmem.c328
-rw-r--r--arch/tile/mm/homecache.c445
-rw-r--r--arch/tile/mm/hugetlbpage.c343
-rw-r--r--arch/tile/mm/init.c1082
-rw-r--r--arch/tile/mm/migrate.h50
-rw-r--r--arch/tile/mm/migrate_32.S211
-rw-r--r--arch/tile/mm/mmap.c75
-rw-r--r--arch/tile/mm/pgtable.c566
-rw-r--r--arch/um/drivers/hostaudio_kern.c10
-rw-r--r--arch/um/kernel/dyn.lds.S2
-rw-r--r--arch/um/kernel/init_task.c2
-rw-r--r--arch/um/kernel/skas/uaccess.c2
-rw-r--r--arch/um/kernel/uml.lds.S2
-rw-r--r--arch/x86/.gitignore3
-rw-r--r--arch/x86/Kconfig3
-rw-r--r--arch/x86/boot/compressed/mkpiggy.c2
-rw-r--r--arch/x86/boot/compressed/vmlinux.lds.S4
-rw-r--r--arch/x86/ia32/ia32entry.S2
-rw-r--r--arch/x86/ia32/sys_ia32.c9
-rw-r--r--arch/x86/include/asm/apb_timer.h1
-rw-r--r--arch/x86/include/asm/cache.h2
-rw-r--r--arch/x86/include/asm/mrst.h26
-rw-r--r--arch/x86/include/asm/msr-index.h1
-rw-r--r--arch/x86/include/asm/nmi.h2
-rw-r--r--arch/x86/include/asm/pci_x86.h3
-rw-r--r--arch/x86/include/asm/sys_ia32.h3
-rw-r--r--arch/x86/include/asm/unistd_32.h4
-rw-r--r--arch/x86/include/asm/unistd_64.h4
-rw-r--r--arch/x86/kernel/acpi/wakeup_32.S2
-rw-r--r--arch/x86/kernel/amd_iommu.c16
-rw-r--r--arch/x86/kernel/amd_iommu_init.c20
-rw-r--r--arch/x86/kernel/apb_timer.c37
-rw-r--r--arch/x86/kernel/apic/Makefile7
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c107
-rw-r--r--arch/x86/kernel/apic/nmi.c7
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/cpufreq/powernow-k8.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c11
-rw-r--r--arch/x86/kernel/cpu/perf_event.c22
-rw-r--r--arch/x86/kernel/e820.c2
-rw-r--r--arch/x86/kernel/init_task.c2
-rw-r--r--arch/x86/kernel/mrst.c105
-rw-r--r--arch/x86/kernel/process.c1
-rw-r--r--arch/x86/kernel/setup_percpu.c8
-rw-r--r--arch/x86/kernel/smpboot.c2
-rw-r--r--arch/x86/kernel/syscall_table_32.S2
-rw-r--r--arch/x86/kernel/traps.c7
-rw-r--r--arch/x86/kernel/vmlinux.lds.S4
-rw-r--r--arch/x86/kvm/mmu.c2
-rw-r--r--arch/x86/kvm/svm.c96
-rw-r--r--arch/x86/mm/numa.c6
-rw-r--r--arch/x86/oprofile/nmi_int.c16
-rw-r--r--arch/x86/pci/common.c20
-rw-r--r--arch/x86/pci/legacy.c42
-rw-r--r--arch/x86/xen/suspend.c4
-rw-r--r--arch/xtensa/Kconfig17
-rw-r--r--arch/xtensa/Makefile7
-rw-r--r--arch/xtensa/boot/Makefile1
-rw-r--r--arch/xtensa/configs/iss_defconfig1
-rw-r--r--arch/xtensa/include/asm/cacheflush.h1
-rw-r--r--arch/xtensa/include/asm/coprocessor.h9
-rw-r--r--arch/xtensa/include/asm/elf.h1
-rw-r--r--arch/xtensa/include/asm/io.h40
-rw-r--r--arch/xtensa/include/asm/irq.h7
-rw-r--r--arch/xtensa/include/asm/pgalloc.h1
-rw-r--r--arch/xtensa/include/asm/processor.h1
-rw-r--r--arch/xtensa/include/asm/ptrace.h2
-rw-r--r--arch/xtensa/include/asm/serial.h12
-rw-r--r--arch/xtensa/kernel/Makefile8
-rw-r--r--arch/xtensa/kernel/asm-offsets.c1
-rw-r--r--arch/xtensa/kernel/entry.S1
-rw-r--r--arch/xtensa/kernel/head.S4
-rw-r--r--arch/xtensa/kernel/time.c2
-rw-r--r--arch/xtensa/mm/fault.c14
-rw-r--r--arch/xtensa/platforms/iss/network.c22
-rw-r--r--arch/xtensa/platforms/xtavnet/Makefile10
-rw-r--r--arch/xtensa/platforms/xtavnet/include/platform/hardware.h85
-rw-r--r--arch/xtensa/platforms/xtavnet/include/platform/lcd.h22
-rw-r--r--arch/xtensa/platforms/xtavnet/include/platform/serial.h1
-rw-r--r--arch/xtensa/platforms/xtavnet/lcd.c79
-rw-r--r--arch/xtensa/platforms/xtavnet/setup.c269
-rw-r--r--block/blk-core.c20
-rw-r--r--block/cfq-iosched.c101
-rw-r--r--block/elevator.c8
-rw-r--r--crypto/Kconfig15
-rw-r--r--crypto/Makefile4
-rw-r--r--crypto/algboss.c4
-rw-r--r--crypto/authenc.c2
-rw-r--r--crypto/ctr.c2
-rw-r--r--crypto/testmgr.c14
-rw-r--r--crypto/twofish_generic.c (renamed from crypto/twofish.c)1
-rw-r--r--crypto/xts.c2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/acpi_pad.c36
-rw-r--r--drivers/acpi/acpica/acconfig.h4
-rw-r--r--drivers/acpi/acpica/acglobal.h8
-rw-r--r--drivers/acpi/acpica/aclocal.h5
-rw-r--r--drivers/acpi/acpica/acnamesp.h7
-rw-r--r--drivers/acpi/acpica/acobject.h16
-rw-r--r--drivers/acpi/acpica/acpredef.h13
-rw-r--r--drivers/acpi/acpica/acstruct.h32
-rw-r--r--drivers/acpi/acpica/dsinit.c14
-rw-r--r--drivers/acpi/acpica/dsmethod.c20
-rw-r--r--drivers/acpi/acpica/dsmthdat.c16
-rw-r--r--drivers/acpi/acpica/dsopcode.c6
-rw-r--r--drivers/acpi/acpica/dsutils.c4
-rw-r--r--drivers/acpi/acpica/evrgnini.c10
-rw-r--r--drivers/acpi/acpica/exdump.c6
-rw-r--r--drivers/acpi/acpica/exfldio.c4
-rw-r--r--drivers/acpi/acpica/exprep.c23
-rw-r--r--drivers/acpi/acpica/exregion.c6
-rw-r--r--drivers/acpi/acpica/exsystem.c8
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwvalid.c12
-rw-r--r--drivers/acpi/acpica/nsaccess.c9
-rw-r--r--drivers/acpi/acpica/nsalloc.c94
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c25
-rw-r--r--drivers/acpi/acpica/nsnames.c4
-rw-r--r--drivers/acpi/acpica/nsparse.c4
-rw-r--r--drivers/acpi/acpica/nsrepair2.c7
-rw-r--r--drivers/acpi/acpica/nssearch.c15
-rw-r--r--drivers/acpi/acpica/nsutils.c113
-rw-r--r--drivers/acpi/acpica/nswalk.c15
-rw-r--r--drivers/acpi/acpica/nsxfobj.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c2
-rw-r--r--drivers/acpi/apei/apei-base.c1
-rw-r--r--drivers/acpi/atomicio.c1
-rw-r--r--drivers/acpi/debug.c32
-rw-r--r--drivers/acpi/ec.c22
-rw-r--r--drivers/acpi/internal.h5
-rw-r--r--drivers/acpi/processor_idle.c17
-rw-r--r--drivers/acpi/sleep.c85
-rw-r--r--drivers/ata/Kconfig6
-rw-r--r--drivers/ata/libahci.c21
-rw-r--r--drivers/ata/libata-core.c6
-rw-r--r--drivers/ata/libata-scsi.c29
-rw-r--r--drivers/ata/pata_macio.c10
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/ata/sata_sil24.c12
-rw-r--r--drivers/ata/sata_via.c27
-rw-r--r--drivers/atm/Kconfig2
-rw-r--r--drivers/atm/he.c304
-rw-r--r--drivers/atm/he.h65
-rw-r--r--drivers/atm/nicstar.c5197
-rw-r--r--drivers/atm/nicstar.h602
-rw-r--r--drivers/atm/nicstarmac.c364
-rw-r--r--drivers/block/aoe/aoecmd.c8
-rw-r--r--drivers/block/brd.c53
-rw-r--r--drivers/block/cciss_scsi.c2
-rw-r--r--drivers/block/drbd/drbd_int.h14
-rw-r--r--drivers/block/drbd/drbd_main.c68
-rw-r--r--drivers/block/drbd/drbd_receiver.c45
-rw-r--r--drivers/block/drbd/drbd_req.c54
-rw-r--r--drivers/block/drbd/drbd_req.h1
-rw-r--r--drivers/block/drbd/drbd_worker.c24
-rw-r--r--drivers/block/swim3.c6
-rw-r--r--drivers/block/virtio_blk.c4
-rw-r--r--drivers/char/Kconfig1
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/intel-gtt.c46
-rw-r--r--drivers/char/agp/uninorth-agp.c2
-rw-r--r--drivers/char/hvc_iucv.c9
-rw-r--r--drivers/char/hvc_tile.c67
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c42
-rw-r--r--drivers/char/n_gsm.c9
-rw-r--r--drivers/char/sysrq.c2
-rw-r--r--drivers/char/virtio_console.c14
-rw-r--r--drivers/char/vt_ioctl.c4
-rw-r--r--drivers/clocksource/sh_cmt.c22
-rw-r--r--drivers/clocksource/sh_tmu.c20
-rw-r--r--drivers/cpufreq/cpufreq.c10
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c33
-rw-r--r--drivers/crypto/amcc/crypto4xx_core.c6
-rw-r--r--drivers/crypto/mv_cesa.c10
-rw-r--r--drivers/crypto/n2_core.c520
-rw-r--r--drivers/crypto/omap-sham.c1
-rw-r--r--drivers/dma/Kconfig2
-rw-r--r--drivers/dma/mpc512x_dma.c10
-rw-r--r--drivers/dma/ppc4xx/adma.c4
-rw-r--r--drivers/dma/shdma.c8
-rw-r--r--drivers/edac/Kconfig21
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/amd64_edac.c156
-rw-r--r--drivers/edac/amd64_edac.h47
-rw-r--r--drivers/edac/e752x_edac.c4
-rw-r--r--drivers/edac/edac_core.h40
-rw-r--r--drivers/edac/edac_mc_sysfs.c261
-rw-r--r--drivers/edac/edac_mce.c61
-rw-r--r--drivers/edac/edac_mce_amd.c16
-rw-r--r--drivers/edac/i5100_edac.c7
-rw-r--r--drivers/edac/i7core_edac.c2078
-rw-r--r--drivers/edac/mpc85xx_edac.c12
-rw-r--r--drivers/edac/ppc4xx_edac.c6
-rw-r--r--drivers/firewire/core-card.c24
-rw-r--r--drivers/firmware/Kconfig9
-rw-r--r--drivers/firmware/Makefile1
-rw-r--r--drivers/firmware/iscsi_boot_sysfs.c481
-rw-r--r--drivers/firmware/iscsi_ibft.c726
-rw-r--r--drivers/firmware/iscsi_ibft_find.c56
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c28
-rw-r--r--drivers/gpu/drm/i915/Makefile1
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c82
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c715
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c70
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h209
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c897
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c182
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h82
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h24
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c10
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c23
-rw-r--r--drivers/gpu/drm/i915/intel_display.c290
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c11
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c6
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c5
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c52
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c849
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h124
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c71
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c71
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c34
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_crtc.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.c29
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drv.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_mem.c3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_state.c6
-rw-r--r--drivers/gpu/drm/nouveau/nv04_cursor.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_cursor.c1
-rw-r--r--drivers/gpu/drm/nouveau/nv50_sor.c7
-rw-r--r--drivers/gpu/drm/radeon/Makefile7
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c5
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c1356
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h3
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h464
-rw-r--r--drivers/gpu/drm/radeon/r600.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c70
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c9
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c75
-rw-r--r--drivers/gpu/drm/radeon/reg_srcs/evergreen611
-rw-r--r--drivers/gpu/drm/radeon/rs600.c3
-rw-r--r--drivers/gpu/drm/radeon/rv770.c5
-rw-r--r--drivers/gpu/drm/ttm/ttm_page_alloc.c64
-rw-r--r--drivers/gpu/drm/vmwgfx/Makefile2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c24
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h49
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c9
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fb.c87
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fence.c173
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c23
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_irq.c17
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c203
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h4
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c189
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c2
-rw-r--r--drivers/gpu/vga/vgaarb.c61
-rw-r--r--drivers/hid/Kconfig1
-rw-r--r--drivers/hid/hid-core.c12
-rw-r--r--drivers/hid/hid-ids.h15
-rw-r--r--drivers/hid/hid-magicmouse.c13
-rw-r--r--drivers/hid/hid-roccat-kone.c17
-rw-r--r--drivers/hid/hid-roccat-kone.h2
-rw-r--r--drivers/hid/hid-roccat.c9
-rw-r--r--drivers/hid/hid-roccat.h2
-rw-r--r--drivers/hid/hidraw.c2
-rw-r--r--drivers/hwmon/adt7411.c2
-rw-r--r--drivers/hwmon/asc7621.c2
-rw-r--r--drivers/hwmon/emc1403.c33
-rw-r--r--drivers/hwmon/f75375s.c2
-rw-r--r--drivers/hwmon/g760a.c2
-rw-r--r--drivers/hwmon/k10temp.c14
-rw-r--r--drivers/hwmon/lm73.c1
-rw-r--r--drivers/hwmon/lm75.c41
-rw-r--r--drivers/hwmon/lm75.h1
-rw-r--r--drivers/hwmon/lm95241.c1
-rw-r--r--drivers/hwmon/ltc4245.c177
-rw-r--r--drivers/hwmon/tmp102.c2
-rw-r--r--drivers/hwmon/tmp421.c2
-rw-r--r--drivers/hwmon/w83781d.c2
-rw-r--r--drivers/i2c/busses/Kconfig42
-rw-r--r--drivers/i2c/busses/Makefile6
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c121
-rw-r--r--drivers/i2c/i2c-core.c179
-rw-r--r--drivers/i2c/i2c-dev.c26
-rw-r--r--drivers/i2c/i2c-smbus.c1
-rw-r--r--drivers/ide/ide-taskfile.c10
-rw-r--r--drivers/ide/ide.c20
-rw-r--r--drivers/ide/pmac.c7
-rw-r--r--drivers/ide/tx4938ide.c2
-rw-r--r--drivers/ide/tx4939ide.c2
-rw-r--r--drivers/ieee1394/video1394.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c4
-rw-r--r--drivers/input/keyboard/adp5588-keys.c1
-rw-r--r--drivers/input/keyboard/lm8323.c2
-rw-r--r--drivers/input/keyboard/max7359_keypad.c1
-rw-r--r--drivers/input/keyboard/qt2160.c1
-rw-r--r--drivers/input/keyboard/tca6416-keypad.c2
-rw-r--r--drivers/input/misc/ad714x-i2c.c1
-rw-r--r--drivers/input/misc/ati_remote2.c26
-rw-r--r--drivers/input/misc/pcf8574_keypad.c4
-rw-r--r--drivers/input/mouse/psmouse-base.c14
-rw-r--r--drivers/input/mouse/synaptics_i2c.c1
-rw-r--r--drivers/input/serio/Kconfig3
-rw-r--r--drivers/input/serio/i8042-ppcio.h75
-rw-r--r--drivers/input/tablet/wacom_sys.c1
-rw-r--r--drivers/input/tablet/wacom_wac.c73
-rw-r--r--drivers/input/tablet/wacom_wac.h1
-rw-r--r--drivers/input/touchscreen/Kconfig2
-rw-r--r--drivers/input/touchscreen/ad7879.c5
-rw-r--r--drivers/input/touchscreen/ads7846.c2
-rw-r--r--drivers/input/touchscreen/eeti_ts.c2
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c1
-rw-r--r--drivers/input/touchscreen/s3c2410_ts.c2
-rw-r--r--drivers/input/touchscreen/tps6507x-ts.c12
-rw-r--r--drivers/input/touchscreen/tsc2007.c2
-rw-r--r--drivers/isdn/capi/kcapi.c6
-rw-r--r--drivers/isdn/hardware/mISDN/hfcsusb.c4
-rw-r--r--drivers/isdn/hardware/mISDN/netjet.c4
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c11
-rw-r--r--drivers/isdn/pcbit/drv.c10
-rw-r--r--drivers/isdn/sc/ioctl.c23
-rw-r--r--drivers/leds/leds-bd2802.c2
-rw-r--r--drivers/leds/leds-lp3944.c1
-rw-r--r--drivers/leds/leds-pca9532.c5
-rw-r--r--drivers/leds/leds-pca955x.c2
-rw-r--r--drivers/macintosh/macio_asic.c8
-rw-r--r--drivers/macintosh/mediabay.c6
-rw-r--r--drivers/macintosh/rack-meter.c8
-rw-r--r--drivers/macintosh/therm_adt746x.c2
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c5
-rw-r--r--drivers/macintosh/windfarm_max6690_sensor.c1
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c1
-rw-r--r--drivers/md/dm-crypt.c3
-rw-r--r--drivers/md/dm-ioctl.c115
-rw-r--r--drivers/md/dm-snap-persistent.c6
-rw-r--r--drivers/media/IR/Kconfig2
-rw-r--r--drivers/media/IR/imon.c75
-rw-r--r--drivers/media/IR/ir-keytable.c17
-rw-r--r--drivers/media/IR/ir-sysfs.c7
-rw-r--r--drivers/media/IR/keymaps/Makefile3
-rw-r--r--drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c90
-rw-r--r--drivers/media/IR/keymaps/rc-avermedia-m135a.c147
-rw-r--r--drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c95
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c12
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig4
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c95
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c2
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c26
-rw-r--r--drivers/media/dvb/frontends/ds3000.c5
-rw-r--r--drivers/media/dvb/frontends/stv6110x.c5
-rw-r--r--drivers/media/dvb/ngene/ngene-cards.c15
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c80
-rw-r--r--drivers/media/dvb/ngene/ngene-dvb.c15
-rw-r--r--drivers/media/dvb/ngene/ngene-i2c.c1
-rw-r--r--drivers/media/dvb/ngene/ngene.h3
-rw-r--r--drivers/media/dvb/ttpci/Kconfig5
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c1
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c1
-rw-r--r--drivers/media/video/Kconfig14
-rw-r--r--drivers/media/video/Makefile2
-rw-r--r--drivers/media/video/ak881x.c3
-rw-r--r--drivers/media/video/bw-qcam.c759
-rw-r--r--drivers/media/video/bw-qcam.h69
-rw-r--r--drivers/media/video/c-qcam.c634
-rw-r--r--drivers/media/video/cx18/cx18-alsa-main.c2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.c2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.h2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.c2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.h2
-rw-r--r--drivers/media/video/cx18/cx18-alsa.h2
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c2
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c127
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h2
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c2
-rw-r--r--drivers/media/video/cx18/cx18-cards.c2
-rw-r--r--drivers/media/video/cx18/cx18-cards.h2
-rw-r--r--drivers/media/video/cx18/cx18-controls.c11
-rw-r--r--drivers/media/video/cx18/cx18-driver.c2
-rw-r--r--drivers/media/video/cx18/cx18-driver.h2
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c2
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c2
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c2
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c2
-rw-r--r--drivers/media/video/cx18/cx18-io.c2
-rw-r--r--drivers/media/video/cx18/cx18-io.h4
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c10
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.h2
-rw-r--r--drivers/media/video/cx18/cx18-irq.c2
-rw-r--r--drivers/media/video/cx18/cx18-irq.h2
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c2
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h2
-rw-r--r--drivers/media/video/cx18/cx18-queue.c2
-rw-r--r--drivers/media/video/cx18/cx18-queue.h2
-rw-r--r--drivers/media/video/cx18/cx18-scb.c2
-rw-r--r--drivers/media/video/cx18/cx18-scb.h2
-rw-r--r--drivers/media/video/cx18/cx18-streams.c2
-rw-r--r--drivers/media/video/cx18/cx18-streams.h2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c5
-rw-r--r--drivers/media/video/cx2341x.c6
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c12
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-input.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c5
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c2
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.h2
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c99
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c16
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c7
-rw-r--r--drivers/media/video/gspca/sonixb.c2
-rw-r--r--drivers/media/video/gspca/sonixj.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c10
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c23
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c14
-rw-r--r--drivers/media/video/mt9m001.c6
-rw-r--r--drivers/media/video/mt9m111.c6
-rw-r--r--drivers/media/video/mt9t031.c4
-rw-r--r--drivers/media/video/mt9t112.c6
-rw-r--r--drivers/media/video/mt9v011.c37
-rw-r--r--drivers/media/video/mt9v022.c6
-rw-r--r--drivers/media/video/mx3_camera.c4
-rw-r--r--drivers/media/video/omap/omap_vout.c3
-rw-r--r--drivers/media/video/ov772x.c6
-rw-r--r--drivers/media/video/ov9640.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c37
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c13
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c15
-rw-r--r--drivers/media/video/pxa_camera.c4
-rw-r--r--drivers/media/video/rj54n1cb0c.c6
-rw-r--r--drivers/media/video/saa7115.c19
-rw-r--r--drivers/media/video/saa7127.c8
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c46
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c55
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c9
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c18
-rw-r--r--drivers/media/video/saa7134/saa7134.h1
-rw-r--r--drivers/media/video/saa717x.c38
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c4
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h2
-rw-r--r--drivers/media/video/soc_camera.c3
-rw-r--r--drivers/media/video/soc_camera_platform.c2
-rw-r--r--drivers/media/video/tcm825x.c8
-rw-r--r--drivers/media/video/tvp514x.c223
-rw-r--r--drivers/media/video/tvp5150.c20
-rw-r--r--drivers/media/video/tw9910.c4
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c3
-rw-r--r--drivers/media/video/via-camera.c1369
-rw-r--r--drivers/media/video/via-camera.h93
-rw-r--r--drivers/message/fusion/mptbase.c3
-rw-r--r--drivers/mfd/88pm860x-i2c.c2
-rw-r--r--drivers/mfd/ab3100-core.c2
-rw-r--r--drivers/mfd/ab3550-core.c1
-rw-r--r--drivers/mfd/adp5520.c2
-rw-r--r--drivers/mfd/da903x.c2
-rw-r--r--drivers/mfd/max8925-i2c.c1
-rw-r--r--drivers/mfd/menelaus.c2
-rw-r--r--drivers/mfd/pcf50633-core.c2
-rw-r--r--drivers/mfd/tc35892.c2
-rw-r--r--drivers/mfd/tps65010.c1
-rw-r--r--drivers/mfd/wm8350-i2c.c2
-rw-r--r--drivers/mfd/wm8400-core.c2
-rw-r--r--drivers/misc/eeprom/at24.c1
-rw-r--r--drivers/misc/lkdtm.c4
-rw-r--r--drivers/misc/vmware_balloon.c18
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/mxcmmc.c16
-rw-r--r--drivers/mmc/host/omap.c1
-rw-r--r--drivers/mmc/host/sh_mmcif.c125
-rw-r--r--drivers/mtd/maps/physmap_of.c6
-rw-r--r--drivers/mtd/maps/pismo.c2
-rw-r--r--drivers/mtd/mtdchar.c11
-rw-r--r--drivers/mtd/nand/Kconfig21
-rw-r--r--drivers/mtd/nand/fsl_upm.c17
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c8
-rw-r--r--drivers/mtd/nand/mxc_nand.c33
-rw-r--r--drivers/mtd/nand/r852.c27
-rw-r--r--drivers/mtd/nand/socrates_nand.c4
-rw-r--r--drivers/mtd/ubi/eba.c7
-rw-r--r--drivers/mtd/ubi/io.c50
-rw-r--r--drivers/mtd/ubi/scan.c126
-rw-r--r--drivers/mtd/ubi/scan.h19
-rw-r--r--drivers/mtd/ubi/ubi.h10
-rw-r--r--drivers/net/3c527.h6
-rw-r--r--drivers/net/8139cp.c2
-rw-r--r--drivers/net/8139too.c8
-rw-r--r--drivers/net/Kconfig15
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/arcnet/capmode.c177
-rw-r--r--drivers/net/arm/ixp4xx_eth.c11
-rw-r--r--drivers/net/atl1c/atl1c.h9
-rw-r--r--drivers/net/atl1c/atl1c_hw.c107
-rw-r--r--drivers/net/atl1c/atl1c_hw.h49
-rw-r--r--drivers/net/atl1c/atl1c_main.c348
-rw-r--r--drivers/net/atlx/atl1.h4
-rw-r--r--drivers/net/b44.c144
-rw-r--r--drivers/net/benet/be_cmds.c24
-rw-r--r--drivers/net/benet/be_main.c95
-rw-r--r--drivers/net/bmac.c7
-rw-r--r--drivers/net/bnx2.c14
-rw-r--r--drivers/net/bonding/bond_alb.c33
-rw-r--r--drivers/net/bonding/bond_main.c111
-rw-r--r--drivers/net/bonding/bond_sysfs.c279
-rw-r--r--drivers/net/bonding/bonding.h14
-rw-r--r--drivers/net/caif/caif_serial.c11
-rw-r--r--drivers/net/can/mscan/mpc5xxx_can.c10
-rw-r--r--drivers/net/can/mscan/mscan.h2
-rw-r--r--drivers/net/can/usb/ems_usb.c2
-rw-r--r--drivers/net/chelsio/common.h1
-rw-r--r--drivers/net/chelsio/subr.c49
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c12
-rw-r--r--drivers/net/dm9000.c2
-rw-r--r--drivers/net/e1000e/netdev.c2
-rw-r--r--drivers/net/ehea/ehea_qmr.h2
-rw-r--r--drivers/net/enic/enic.h7
-rw-r--r--drivers/net/enic/enic_main.c200
-rw-r--r--drivers/net/enic/vnic_vic.h2
-rw-r--r--drivers/net/epic100.c7
-rw-r--r--drivers/net/fec.c56
-rw-r--r--drivers/net/fec_mpc52xx_phy.c24
-rw-r--r--drivers/net/fs_enet/mac-fcc.c49
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c4
-rw-r--r--drivers/net/fsl_pq_mdio.h2
-rw-r--r--drivers/net/gianfar.c8
-rw-r--r--drivers/net/greth.c11
-rw-r--r--drivers/net/irda/donauboe.h2
-rw-r--r--drivers/net/irda/irda-usb.c9
-rw-r--r--drivers/net/irda/irda-usb.h2
-rw-r--r--drivers/net/irda/ks959-sir.c2
-rw-r--r--drivers/net/irda/ksdazzle-sir.c2
-rw-r--r--drivers/net/irda/vlsi_ir.h6
-rw-r--r--drivers/net/ixgbe/ixgbe.h8
-rw-r--r--drivers/net/ixgbe/ixgbe_82599.c5
-rw-r--r--drivers/net/ixgbe/ixgbe_common.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_common.h26
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c43
-rw-r--r--drivers/net/ixgbe/ixgbe_fcoe.c35
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c283
-rw-r--r--drivers/net/ixgbe/ixgbe_sriov.c15
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h1
-rw-r--r--drivers/net/ixgbevf/ixgbevf_main.c1
-rw-r--r--drivers/net/korina.c32
-rw-r--r--drivers/net/ksz884x.c3
-rw-r--r--drivers/net/mac8390.c57
-rw-r--r--drivers/net/mace.c7
-rw-r--r--drivers/net/macvlan.c19
-rw-r--r--drivers/net/mlx4/en_netdev.c1
-rw-r--r--drivers/net/mlx4/eq.c14
-rw-r--r--drivers/net/mlx4/mr.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c54
-rw-r--r--drivers/net/ppp_generic.c20
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--drivers/net/ps3_gelic_wireless.h10
-rw-r--r--drivers/net/qlcnic/qlcnic.h120
-rw-r--r--drivers/net/qlcnic/qlcnic_ctx.c513
-rw-r--r--drivers/net/qlcnic/qlcnic_ethtool.c11
-rw-r--r--drivers/net/qlcnic/qlcnic_hdr.h84
-rw-r--r--drivers/net/qlcnic/qlcnic_hw.c14
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c40
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c312
-rw-r--r--drivers/net/qlge/qlge.h24
-rw-r--r--drivers/net/r6040.c302
-rw-r--r--drivers/net/r8169.c7
-rw-r--r--drivers/net/sfc/efx.c69
-rw-r--r--drivers/net/sfc/efx.h4
-rw-r--r--drivers/net/sfc/falcon.c8
-rw-r--r--drivers/net/sfc/mcdi_phy.c21
-rw-r--r--drivers/net/sfc/net_driver.h46
-rw-r--r--drivers/net/sfc/nic.c55
-rw-r--r--drivers/net/sfc/nic.h4
-rw-r--r--drivers/net/sfc/rx.c393
-rw-r--r--drivers/net/sfc/selftest.c28
-rw-r--r--drivers/net/sfc/siena.c4
-rw-r--r--drivers/net/sfc/workarounds.h2
-rw-r--r--drivers/net/sky2.h6
-rw-r--r--drivers/net/tehuti.c4
-rw-r--r--drivers/net/tehuti.h2
-rw-r--r--drivers/net/tg3.c163
-rw-r--r--drivers/net/tg3.h17
-rw-r--r--drivers/net/tulip/de2104x.c4
-rw-r--r--drivers/net/tulip/eeprom.c10
-rw-r--r--drivers/net/tulip/tulip.h64
-rw-r--r--drivers/net/tulip/tulip_core.c122
-rw-r--r--drivers/net/typhoon.c2
-rw-r--r--drivers/net/typhoon.h26
-rw-r--r--drivers/net/ucc_geth.h46
-rw-r--r--drivers/net/usb/asix.c2
-rw-r--r--drivers/net/usb/hso.c2
-rw-r--r--drivers/net/usb/kaweth.c2
-rw-r--r--drivers/net/usb/net1080.c4
-rw-r--r--drivers/net/usb/sierra_net.c2
-rw-r--r--drivers/net/vbus-enet.c1560
-rw-r--r--drivers/net/via-velocity.h12
-rw-r--r--drivers/net/virtio_net.c8
-rw-r--r--drivers/net/vxge/vxge-main.c93
-rw-r--r--drivers/net/wan/farsync.c14
-rw-r--r--drivers/net/wan/hd64570.h2
-rw-r--r--drivers/net/wan/hdlc_cisco.c4
-rw-r--r--drivers/net/wan/hdlc_fr.c2
-rw-r--r--drivers/net/wan/sdla.c13
-rw-r--r--drivers/net/wan/x25_asy.c2
-rw-r--r--drivers/net/wimax/i2400m/control.c2
-rw-r--r--drivers/net/wimax/i2400m/fw.c8
-rw-r--r--drivers/net/wimax/i2400m/op-rfkill.c2
-rw-r--r--drivers/net/wireless/adm8211.h6
-rw-r--r--drivers/net/wireless/airo.c32
-rw-r--r--drivers/net/wireless/at76c50x-usb.c2
-rw-r--r--drivers/net/wireless/at76c50x-usb.h40
-rw-r--r--drivers/net/wireless/ath/ar9170/usb.c14
-rw-r--r--drivers/net/wireless/ath/ath5k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath5k/ani.c20
-rw-r--r--drivers/net/wireless/ath/ath5k/ath5k.h6
-rw-r--r--drivers/net/wireless/ath/ath5k/attach.c2
-rw-r--r--drivers/net/wireless/ath/ath5k/base.c67
-rw-r--r--drivers/net/wireless/ath/ath5k/caps.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/debug.h8
-rw-r--r--drivers/net/wireless/ath/ath5k/desc.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/dma.c13
-rw-r--r--drivers/net/wireless/ath/ath5k/eeprom.c3
-rw-r--r--drivers/net/wireless/ath/ath5k/gpio.c7
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c24
-rw-r--r--drivers/net/wireless/ath/ath5k/phy.c53
-rw-r--r--drivers/net/wireless/ath/ath5k/qcu.c9
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c23
-rw-r--r--drivers/net/wireless/ath/ath5k/sysfs.c116
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c11
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_hw.c109
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9002_initvals.h6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h (renamed from drivers/net/wireless/ath/ath9k/ar9003_initvals.h)6
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h1785
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c10
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c163
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mac.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c119
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h66
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h68
-rw-r--r--drivers/net/wireless/ath/ath9k/common.c314
-rw-r--r--drivers/net/wireless/ath/ath9k/common.h77
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c56
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.c29
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c618
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c58
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h12
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_beacon.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c127
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_main.c397
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_txrx.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c41
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h14
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c19
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c255
-rw-r--r--drivers/net/wireless/ath/ath9k/rc.c177
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c278
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h62
-rw-r--r--drivers/net/wireless/ath/ath9k/wmi.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c66
-rw-r--r--drivers/net/wireless/b43/b43.h6
-rw-r--r--drivers/net/wireless/b43/dma.c69
-rw-r--r--drivers/net/wireless/b43/dma.h8
-rw-r--r--drivers/net/wireless/b43/xmit.h20
-rw-r--r--drivers/net/wireless/b43legacy/b43legacy.h6
-rw-r--r--drivers/net/wireless/b43legacy/dma.c49
-rw-r--r--drivers/net/wireless/b43legacy/dma.h8
-rw-r--r--drivers/net/wireless/b43legacy/xmit.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_80211.h18
-rw-r--r--drivers/net/wireless/hostap/hostap_common.h10
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c9
-rw-r--r--drivers/net/wireless/hostap/hostap_wlan.h32
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.c22
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2100.h16
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c3
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.h122
-rw-r--r--drivers/net/wireless/ipw2x00/libipw.h62
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-1000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-fh.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c202
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c83
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c58
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c345
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c26
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-hw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c252
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rs.c3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c77
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-ucode.c123
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c609
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h34
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h247
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c305
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h25
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c81
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h84
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fh.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-helpers.h27
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scan.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-spectrum.h10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.c72
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-sta.h29
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c33
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c183
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.h50
-rw-r--r--drivers/net/wireless/iwmc3200wifi/hal.c2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/iwm.h2
-rw-r--r--drivers/net/wireless/iwmc3200wifi/lmac.h32
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c4
-rw-r--r--drivers/net/wireless/iwmc3200wifi/umac.h60
-rw-r--r--drivers/net/wireless/libertas/cmd.c37
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c30
-rw-r--r--drivers/net/wireless/libertas/decl.h2
-rw-r--r--drivers/net/wireless/libertas/dev.h6
-rw-r--r--drivers/net/wireless/libertas/ethtool.c15
-rw-r--r--drivers/net/wireless/libertas/host.h120
-rw-r--r--drivers/net/wireless/libertas/if_sdio.c90
-rw-r--r--drivers/net/wireless/libertas/if_usb.c15
-rw-r--r--drivers/net/wireless/libertas/main.c79
-rw-r--r--drivers/net/wireless/libertas/radiotap.h4
-rw-r--r--drivers/net/wireless/libertas/rx.c13
-rw-r--r--drivers/net/wireless/libertas/scan.c2
-rw-r--r--drivers/net/wireless/libertas/types.h66
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c8
-rw-r--r--drivers/net/wireless/libertas_tf/libertas_tf.h4
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c2
-rw-r--r--drivers/net/wireless/mwl8k.c78
-rw-r--r--drivers/net/wireless/orinoco/airport.c7
-rw-r--r--drivers/net/wireless/orinoco/fw.c2
-rw-r--r--drivers/net/wireless/orinoco/hermes.h18
-rw-r--r--drivers/net/wireless/orinoco/hermes_dld.c10
-rw-r--r--drivers/net/wireless/orinoco/hw.c6
-rw-r--r--drivers/net/wireless/orinoco/main.c10
-rw-r--r--drivers/net/wireless/orinoco/orinoco.h2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c8
-rw-r--r--drivers/net/wireless/orinoco/wext.c6
-rw-r--r--drivers/net/wireless/p54/eeprom.c4
-rw-r--r--drivers/net/wireless/p54/net2280.h16
-rw-r--r--drivers/net/wireless/p54/p54pci.h6
-rw-r--r--drivers/net/wireless/p54/p54spi.c5
-rw-r--r--drivers/net/wireless/p54/p54spi.h2
-rw-r--r--drivers/net/wireless/p54/p54usb.c4
-rw-r--r--drivers/net/wireless/p54/p54usb.h6
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c13
-rw-r--r--drivers/net/wireless/prism54/isl_oid.h18
-rw-r--r--drivers/net/wireless/prism54/islpci_eth.h4
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.h2
-rw-r--r--drivers/net/wireless/rndis_wlan.c70
-rw-r--r--drivers/net/wireless/rt2x00/rt2400pci.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt2500pci.c17
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c31
-rw-r--r--drivers/net/wireless/rt2x00/rt2800.h55
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c154
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.h13
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.c103
-rw-r--r--drivers/net/wireless/rt2x00/rt2800pci.h19
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c102
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.h37
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00.h42
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dump.h7
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00ht.c47
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00lib.h26
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.c51
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00pci.h8
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c34
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c33
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.h19
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.c14
-rw-r--r--drivers/net/wireless/rt2x00/rt61pci.h4
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c48
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8180.h4
-rw-r--r--drivers/net/wireless/rtl818x/rtl8187.h8
-rw-r--r--drivers/net/wireless/rtl818x/rtl818x.h2
-rw-r--r--drivers/net/wireless/wl12xx/Kconfig4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_acx.h102
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_cmd.h22
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_event.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c4
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_rx.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_sdio.c1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_tx.h6
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h33
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_acx.h102
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c41
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.h66
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.c10
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_event.h4
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ini.h123
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c95
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_rx.h2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_sdio.c2
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_testmode.c11
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.c36
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_tx.h7
-rw-r--r--drivers/net/wireless/wl12xx/wl12xx_80211.h26
-rw-r--r--drivers/net/wireless/wl3501.h16
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h12
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h14
-rw-r--r--drivers/net/xen-netfront.c1
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c2
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c17
-rw-r--r--drivers/pci/quirks.c29
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c4
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c2
-rw-r--r--drivers/power/max17040_battery.c2
-rw-r--r--drivers/regulator/Kconfig6
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/ad5398.c288
-rw-r--r--drivers/regulator/lp3971.c2
-rw-r--r--drivers/regulator/max1586.c1
-rw-r--r--drivers/regulator/max8649.c2
-rw-r--r--drivers/regulator/max8660.c1
-rw-r--r--drivers/regulator/tps65023-regulator.c3
-rw-r--r--drivers/rtc/rtc-davinci.c1
-rw-r--r--drivers/rtc/rtc-ds1374.c2
-rw-r--r--drivers/rtc/rtc-mpc5121.c14
-rw-r--r--drivers/rtc/rtc-rx8025.c2
-rw-r--r--drivers/rtc/rtc-s35390a.c2
-rw-r--r--drivers/rtc/rtc-s3c.c9
-rw-r--r--drivers/s390/cio/chsc.c49
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/s390/cio/device.c37
-rw-r--r--drivers/s390/cio/itcw.c2
-rw-r--r--drivers/s390/net/smsgiucv_app.c7
-rw-r--r--drivers/scsi/bfa/bfad.c2
-rw-r--r--drivers/scsi/mac53c94.c7
-rw-r--r--drivers/scsi/mesh.c7
-rw-r--r--drivers/scsi/sd.c22
-rw-r--r--drivers/serial/68328serial.c8
-rw-r--r--drivers/serial/8250_pci.c71
-rw-r--r--drivers/serial/altera_uart.c44
-rw-r--r--drivers/serial/bfin_5xx.c9
-rw-r--r--drivers/serial/mpc52xx_uart.c145
-rw-r--r--drivers/serial/msm_serial.c21
-rw-r--r--drivers/serial/msm_serial.h56
-rw-r--r--drivers/serial/pmac_zilog.c7
-rw-r--r--drivers/serial/serial_cs.c18
-rw-r--r--drivers/serial/sh-sci.c42
-rw-r--r--drivers/serial/sh-sci.h29
-rw-r--r--drivers/sfi/sfi_core.c4
-rw-r--r--drivers/sh/Makefile5
-rw-r--r--drivers/sh/intc.c12
-rw-r--r--drivers/spi/mpc512x_psc_spi.c12
-rw-r--r--drivers/spi/spi_ppc4xx.c2
-rw-r--r--drivers/ssb/driver_chipcommon.c25
-rw-r--r--drivers/ssb/driver_chipcommon_pmu.c17
-rw-r--r--drivers/ssb/main.c76
-rw-r--r--drivers/ssb/pci.c20
-rw-r--r--drivers/ssb/sprom.c1
-rw-r--r--drivers/staging/Kconfig6
-rw-r--r--drivers/staging/Makefile3
-rw-r--r--drivers/staging/adis16255/Kconfig2
-rw-r--r--drivers/staging/adis16255/adis16255.c4
-rw-r--r--drivers/staging/batman-adv/device.c2
-rw-r--r--drivers/staging/batman-adv/main.c5
-rw-r--r--drivers/staging/batman-adv/send.c24
-rw-r--r--drivers/staging/comedi/Kconfig81
-rw-r--r--drivers/staging/comedi/comedi_fops.c44
-rw-r--r--drivers/staging/comedi/drivers/Makefile4
-rw-r--r--drivers/staging/comedi/drivers/addi-data/addi_common.c14
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_035.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1516.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1564.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_16xx.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1710.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2016.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2032.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_2200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3001.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3120.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3200.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3300.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c2
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3xxx.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci_dio.c180
-rw-r--r--drivers/staging/comedi/drivers/amplc_dio200.c35
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c3
-rw-r--r--drivers/staging/dream/synaptics_i2c_rmi.c2
-rw-r--r--drivers/staging/dt3155/allocator.c4
-rw-r--r--drivers/staging/go7007/wis-saa7113.c2
-rw-r--r--drivers/staging/go7007/wis-saa7115.c2
-rw-r--r--drivers/staging/go7007/wis-sony-tuner.c1
-rw-r--r--drivers/staging/go7007/wis-tw2804.c1
-rw-r--r--drivers/staging/go7007/wis-tw9903.c2
-rw-r--r--drivers/staging/iio/Documentation/iio_utils.h3
-rw-r--r--drivers/staging/iio/adc/max1363_core.c2
-rw-r--r--drivers/staging/iio/light/tsl2563.c2
-rw-r--r--drivers/staging/iio/ring_sw.c2
-rw-r--r--drivers/staging/mrst-touchscreen/Kconfig7
-rw-r--r--drivers/staging/mrst-touchscreen/Makefile3
-rw-r--r--drivers/staging/mrst-touchscreen/TODO2
-rw-r--r--drivers/staging/mrst-touchscreen/intel-mid-touch.c864
-rw-r--r--drivers/staging/msm/Kconfig134
-rw-r--r--drivers/staging/msm/Makefile93
-rw-r--r--drivers/staging/msm/TODO3
-rw-r--r--drivers/staging/msm/ebi2_l2f.c569
-rw-r--r--drivers/staging/msm/ebi2_lcd.c250
-rw-r--r--drivers/staging/msm/ebi2_tmd20.c1122
-rw-r--r--drivers/staging/msm/hdmi_sii9022.c248
-rw-r--r--drivers/staging/msm/lcdc.c239
-rw-r--r--drivers/staging/msm/lcdc_external.c54
-rw-r--r--drivers/staging/msm/lcdc_gordon.c446
-rw-r--r--drivers/staging/msm/lcdc_grapefruit.c60
-rw-r--r--drivers/staging/msm/lcdc_panel.c88
-rw-r--r--drivers/staging/msm/lcdc_prism.c64
-rw-r--r--drivers/staging/msm/lcdc_sharp_wvga_pt.c290
-rw-r--r--drivers/staging/msm/lcdc_st15.c237
-rw-r--r--drivers/staging/msm/lcdc_st1_wxga.c54
-rw-r--r--drivers/staging/msm/lcdc_toshiba_wvga_pt.c374
-rw-r--r--drivers/staging/msm/lcdc_wxga.c56
-rw-r--r--drivers/staging/msm/logo.c98
-rw-r--r--drivers/staging/msm/mddi.c375
-rw-r--r--drivers/staging/msm/mddi_ext.c320
-rw-r--r--drivers/staging/msm/mddi_ext_lcd.c91
-rw-r--r--drivers/staging/msm/mddi_prism.c114
-rw-r--r--drivers/staging/msm/mddi_sharp.c892
-rw-r--r--drivers/staging/msm/mddi_toshiba.c1741
-rw-r--r--drivers/staging/msm/mddi_toshiba.h52
-rw-r--r--drivers/staging/msm/mddi_toshiba_vga.c136
-rw-r--r--drivers/staging/msm/mddi_toshiba_wvga.c63
-rw-r--r--drivers/staging/msm/mddi_toshiba_wvga_pt.c64
-rw-r--r--drivers/staging/msm/mddihost.c377
-rw-r--r--drivers/staging/msm/mddihost.h225
-rw-r--r--drivers/staging/msm/mddihost_e.c63
-rw-r--r--drivers/staging/msm/mddihosti.c2239
-rw-r--r--drivers/staging/msm/mddihosti.h547
-rw-r--r--drivers/staging/msm/mdp.c1113
-rw-r--r--drivers/staging/msm/mdp.h695
-rw-r--r--drivers/staging/msm/mdp4.h352
-rw-r--r--drivers/staging/msm/mdp4_debugfs.c181
-rw-r--r--drivers/staging/msm/mdp4_overlay.c1259
-rw-r--r--drivers/staging/msm/mdp4_overlay_lcdc.c313
-rw-r--r--drivers/staging/msm/mdp4_overlay_mddi.c254
-rw-r--r--drivers/staging/msm/mdp4_util.c1686
-rw-r--r--drivers/staging/msm/mdp_cursor.c104
-rw-r--r--drivers/staging/msm/mdp_dma.c561
-rw-r--r--drivers/staging/msm/mdp_dma_lcdc.c379
-rw-r--r--drivers/staging/msm/mdp_dma_s.c139
-rw-r--r--drivers/staging/msm/mdp_dma_tv.c142
-rw-r--r--drivers/staging/msm/mdp_hw_init.c720
-rw-r--r--drivers/staging/msm/mdp_ppp.c1502
-rw-r--r--drivers/staging/msm/mdp_ppp_dq.c347
-rw-r--r--drivers/staging/msm/mdp_ppp_dq.h86
-rw-r--r--drivers/staging/msm/mdp_ppp_v20.c2486
-rw-r--r--drivers/staging/msm/mdp_ppp_v31.c828
-rw-r--r--drivers/staging/msm/mdp_vsync.c389
-rw-r--r--drivers/staging/msm/memory.c214
-rw-r--r--drivers/staging/msm/memory_ll.h61
-rw-r--r--drivers/staging/msm/msm_fb.c2354
-rw-r--r--drivers/staging/msm/msm_fb.h174
-rw-r--r--drivers/staging/msm/msm_fb_bl.c79
-rw-r--r--drivers/staging/msm/msm_fb_def.h201
-rw-r--r--drivers/staging/msm/msm_fb_panel.c136
-rw-r--r--drivers/staging/msm/msm_fb_panel.h145
-rw-r--r--drivers/staging/msm/msm_mdp.h245
-rw-r--r--drivers/staging/msm/staging-devices.c323
-rw-r--r--drivers/staging/msm/tv_ntsc.c163
-rw-r--r--drivers/staging/msm/tv_pal.c213
-rw-r--r--drivers/staging/msm/tvenc.c295
-rw-r--r--drivers/staging/msm/tvenc.h117
-rw-r--r--drivers/staging/phison/Kconfig2
-rw-r--r--drivers/staging/pohmelfs/inode.c14
-rw-r--r--drivers/staging/rt2860/sta_ioctl.c2
-rw-r--r--drivers/staging/rtl8187se/r8180_core.c6
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c6
-rw-r--r--drivers/staging/rtl8192su/r8192U_core.c6
-rw-r--r--drivers/staging/sep/sep_driver.c52
-rw-r--r--drivers/staging/tm6000/Kconfig3
-rw-r--r--drivers/staging/tm6000/tm6000-alsa.c26
-rw-r--r--drivers/staging/tm6000/tm6000-cards.c46
-rw-r--r--drivers/staging/tm6000/tm6000-core.c122
-rw-r--r--drivers/staging/tm6000/tm6000-dvb.c75
-rw-r--r--drivers/staging/tm6000/tm6000-video.c104
-rw-r--r--drivers/staging/tm6000/tm6000.h25
-rw-r--r--drivers/staging/usbip/usbip_common.c46
-rw-r--r--drivers/staging/vme/bridges/vme_ca91cx42.c2
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c2
-rw-r--r--drivers/staging/wlags49_h2/Kconfig12
-rw-r--r--drivers/staging/wlags49_h25/Kconfig12
-rw-r--r--drivers/staging/xgifb/Kconfig11
-rw-r--r--drivers/staging/xgifb/Makefile4
-rw-r--r--drivers/staging/xgifb/TODO15
-rw-r--r--drivers/staging/xgifb/XGI.h10
-rw-r--r--drivers/staging/xgifb/XGI_accel.c596
-rw-r--r--drivers/staging/xgifb/XGI_accel.h511
-rw-r--r--drivers/staging/xgifb/XGI_main.h1023
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c3773
-rw-r--r--drivers/staging/xgifb/XGIfb.h215
-rw-r--r--drivers/staging/xgifb/osdef.h153
-rw-r--r--drivers/staging/xgifb/vb_def.h1017
-rw-r--r--drivers/staging/xgifb/vb_ext.c1370
-rw-r--r--drivers/staging/xgifb/vb_ext.h32
-rw-r--r--drivers/staging/xgifb/vb_init.c3444
-rw-r--r--drivers/staging/xgifb/vb_init.h7
-rw-r--r--drivers/staging/xgifb/vb_setmode.c10736
-rw-r--r--drivers/staging/xgifb/vb_setmode.h40
-rw-r--r--drivers/staging/xgifb/vb_struct.h534
-rw-r--r--drivers/staging/xgifb/vb_table.h4406
-rw-r--r--drivers/staging/xgifb/vb_util.c263
-rw-r--r--drivers/staging/xgifb/vb_util.h15
-rw-r--r--drivers/staging/xgifb/vgatypes.h325
-rw-r--r--drivers/usb/atm/ueagle-atm.c2
-rw-r--r--drivers/usb/class/cdc-acm.c6
-rw-r--r--drivers/usb/core/driver.c2
-rw-r--r--drivers/usb/gadget/Kconfig1
-rw-r--r--drivers/usb/gadget/f_audio.c4
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c4
-rw-r--r--drivers/usb/gadget/m66592-udc.h22
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c4
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h24
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c57
-rw-r--r--drivers/usb/host/ehci-hcd.c20
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/isp1362.h2
-rw-r--r--drivers/usb/host/r8a66597-hcd.c4
-rw-r--r--drivers/usb/host/r8a66597.h26
-rw-r--r--drivers/usb/host/xhci-pci.c2
-rw-r--r--drivers/usb/host/xhci-ring.c31
-rw-r--r--drivers/usb/host/xhci.c57
-rw-r--r--drivers/usb/host/xhci.h12
-rw-r--r--drivers/usb/serial/digi_acceleport.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c4
-rw-r--r--drivers/usb/serial/mos7840.c1
-rw-r--r--drivers/uwb/i1480/i1480u-wlp/lc.c16
-rw-r--r--drivers/uwb/wlp/messages.c40
-rw-r--r--drivers/uwb/wlp/sysfs.c46
-rw-r--r--drivers/uwb/wlp/wlp-lc.c12
-rw-r--r--drivers/vbus/Kconfig25
-rw-r--r--drivers/vbus/Makefile6
-rw-r--r--drivers/vbus/bus-proxy.c248
-rw-r--r--drivers/vbus/pci-bridge.c1016
-rw-r--r--drivers/vhost/net.c13
-rw-r--r--drivers/vhost/vhost.c4
-rw-r--r--drivers/video/Kconfig14
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/aty/mach64_accel.c9
-rw-r--r--drivers/video/backlight/adp8860_bl.c2
-rw-r--r--drivers/video/backlight/tosa_bl.c2
-rw-r--r--drivers/video/bw2.c2
-rw-r--r--drivers/video/cg14.c2
-rw-r--r--drivers/video/cg3.c2
-rw-r--r--drivers/video/fb_defio.c52
-rw-r--r--drivers/video/leo.c2
-rw-r--r--drivers/video/mb862xx/mb862xxfb.c2
-rw-r--r--drivers/video/p9100.c2
-rw-r--r--drivers/video/sh_mipi_dsi.c505
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c6
-rw-r--r--drivers/video/tcx.c2
-rw-r--r--drivers/video/uvesafb.c7
-rw-r--r--drivers/video/via/accel.c2
-rw-r--r--drivers/video/via/via-core.c16
-rw-r--r--drivers/video/vt8623fb.c2
-rw-r--r--drivers/watchdog/gef_wdt.c2
-rw-r--r--drivers/watchdog/hpwdt.c20
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c17
-rw-r--r--drivers/watchdog/wm8350_wdt.c2
-rw-r--r--drivers/xen/xenbus/xenbus_xs.c2
-rw-r--r--drivers/zorro/proc.c15
-rw-r--r--fs/9p/fid.c3
-rw-r--r--fs/9p/v9fs.c2
-rw-r--r--fs/9p/vfs_dir.c134
-rw-r--r--fs/9p/vfs_file.c13
-rw-r--r--fs/9p/vfs_inode.c94
-rw-r--r--fs/adfs/inode.c16
-rw-r--r--fs/affs/file.c11
-rw-r--r--fs/affs/inode.c13
-rw-r--r--fs/afs/server.c5
-rw-r--r--fs/aio.c21
-rw-r--r--fs/attr.c88
-rw-r--r--fs/bfs/file.c14
-rw-r--r--fs/binfmt_elf_fdpic.c26
-rw-r--r--fs/binfmt_flat.c25
-rw-r--r--fs/block_dev.c10
-rw-r--r--fs/btrfs/inode.c12
-rw-r--r--fs/buffer.c180
-rw-r--r--fs/ceph/addr.c2
-rw-r--r--fs/ceph/caps.c40
-rw-r--r--fs/ceph/ceph_fs.c50
-rw-r--r--fs/ceph/ceph_fs.h3
-rw-r--r--fs/ceph/file.c24
-rw-r--r--fs/ceph/inode.c5
-rw-r--r--fs/ceph/ioctl.c24
-rw-r--r--fs/ceph/ioctl.h2
-rw-r--r--fs/cifs/file.c1
-rw-r--r--fs/cifs/inode.c74
-rw-r--r--fs/compat.c7
-rw-r--r--fs/configfs/inode.c9
-rw-r--r--fs/direct-io.c74
-rw-r--r--fs/ecryptfs/inode.c18
-rw-r--r--fs/exec.c4
-rw-r--r--fs/exofs/inode.c14
-rw-r--r--fs/ext2/acl.c1
-rw-r--r--fs/ext2/dir.c23
-rw-r--r--fs/ext2/ext2.h3
-rw-r--r--fs/ext2/inode.c39
-rw-r--r--fs/ext3/acl.c1
-rw-r--r--fs/ext3/inode.c26
-rw-r--r--fs/ext4/inode.c82
-rw-r--r--fs/ext4/move_extent.c3
-rw-r--r--fs/fat/fat.h1
-rw-r--r--fs/fat/file.c49
-rw-r--r--fs/fat/inode.c6
-rw-r--r--fs/fcntl.c7
-rw-r--r--fs/fs-writeback.c64
-rw-r--r--fs/fscache/page.c36
-rw-r--r--fs/fuse/dir.c17
-rw-r--r--fs/gfs2/aops.c10
-rw-r--r--fs/gfs2/inode.c25
-rw-r--r--fs/gfs2/ops_inode.c18
-rw-r--r--fs/gfs2/quota.c10
-rw-r--r--fs/gfs2/xattr.c24
-rw-r--r--fs/hfs/inode.c40
-rw-r--r--fs/hfsplus/inode.c50
-rw-r--r--fs/hostfs/hostfs_kern.c18
-rw-r--r--fs/hpfs/file.c11
-rw-r--r--fs/hpfs/inode.c12
-rw-r--r--fs/hugetlbfs/inode.c17
-rw-r--r--fs/inode.c8
-rw-r--r--fs/jffs2/dir.c127
-rw-r--r--fs/jffs2/fs.c11
-rw-r--r--fs/jfs/file.c14
-rw-r--r--fs/jfs/inode.c28
-rw-r--r--fs/libfs.c73
-rw-r--r--fs/logfs/dir.c2
-rw-r--r--fs/logfs/file.c24
-rw-r--r--fs/logfs/logfs.h4
-rw-r--r--fs/minix/dir.c25
-rw-r--r--fs/minix/file.c22
-rw-r--r--fs/minix/inode.c20
-rw-r--r--fs/minix/minix.h4
-rw-r--r--fs/namei.c5
-rw-r--r--fs/namespace.c5
-rw-r--r--fs/ncpfs/inode.c24
-rw-r--r--fs/nfs/callback.c11
-rw-r--r--fs/nfsd/nfs4callback.c34
-rw-r--r--fs/nfsd/nfs4state.c16
-rw-r--r--fs/nfsd/vfs.c4
-rw-r--r--fs/nilfs2/btree.h2
-rw-r--r--fs/nilfs2/dir.c25
-rw-r--r--fs/nilfs2/inode.c50
-rw-r--r--fs/nilfs2/recovery.c357
-rw-r--r--fs/nilfs2/segbuf.h26
-rw-r--r--fs/nilfs2/segment.c8
-rw-r--r--fs/nilfs2/segment.h12
-rw-r--r--fs/nilfs2/super.c8
-rw-r--r--fs/nilfs2/the_nilfs.c12
-rw-r--r--fs/nilfs2/the_nilfs.h2
-rw-r--r--fs/notify/Kconfig1
-rw-r--r--fs/notify/Makefile4
-rw-r--r--fs/notify/dnotify/dnotify.c198
-rw-r--r--fs/notify/fanotify/Kconfig26
-rw-r--r--fs/notify/fanotify/Makefile1
-rw-r--r--fs/notify/fanotify/fanotify.c255
-rw-r--r--fs/notify/fanotify/fanotify_user.c777
-rw-r--r--fs/notify/fsnotify.c141
-rw-r--r--fs/notify/fsnotify.h33
-rw-r--r--fs/notify/group.c178
-rw-r--r--fs/notify/inode_mark.c309
-rw-r--r--fs/notify/inotify/Kconfig15
-rw-r--r--fs/notify/inotify/Makefile1
-rw-r--r--fs/notify/inotify/inotify.c873
-rw-r--r--fs/notify/inotify/inotify.h7
-rw-r--r--fs/notify/inotify/inotify_fsnotify.c114
-rw-r--r--fs/notify/inotify/inotify_user.c307
-rw-r--r--fs/notify/mark.c325
-rw-r--r--fs/notify/notification.c180
-rw-r--r--fs/notify/vfsmount_mark.c175
-rw-r--r--fs/ntfs/inode.c3
-rw-r--r--fs/ocfs2/aops.c9
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c8
-rw-r--r--fs/ocfs2/file.c22
-rw-r--r--fs/ocfs2/reservations.c1
-rw-r--r--fs/omfs/file.c36
-rw-r--r--fs/open.c8
-rw-r--r--fs/pipe.c77
-rw-r--r--fs/proc/base.c16
-rw-r--r--fs/proc/generic.c18
-rw-r--r--fs/proc/proc_sysctl.c15
-rw-r--r--fs/qnx4/inode.c11
-rw-r--r--fs/quota/dquot.c38
-rw-r--r--fs/ramfs/file-nommu.c7
-rw-r--r--fs/read_write.c8
-rw-r--r--fs/reiserfs/inode.c119
-rw-r--r--fs/smbfs/inode.c4
-rw-r--r--fs/splice.c2
-rw-r--r--fs/sync.c2
-rw-r--r--fs/sysfs/inode.c8
-rw-r--r--fs/sysv/dir.c21
-rw-r--r--fs/sysv/file.c22
-rw-r--r--fs/sysv/itree.c19
-rw-r--r--fs/sysv/sysv.h4
-rw-r--r--fs/ubifs/file.c23
-rw-r--r--fs/ubifs/ubifs.h2
-rw-r--r--fs/udf/file.c23
-rw-r--r--fs/udf/inode.c13
-rw-r--r--fs/ufs/dir.c13
-rw-r--r--fs/ufs/inode.c20
-rw-r--r--fs/ufs/truncate.c16
-rw-r--r--fs/ufs/util.h4
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c36
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c16
-rw-r--r--fs/xfs/linux-2.6/xfs_quotaops.c11
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c9
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_trace.h356
-rw-r--r--fs/xfs/quota/xfs_qm.c4
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c32
-rw-r--r--fs/xfs/xfs_ag.h1
-rw-r--r--fs/xfs/xfs_iget.c29
-rw-r--r--fs/xfs/xfs_inode.c144
-rw-r--r--fs/xfs/xfs_log_recover.c11
-rw-r--r--fs/xfs/xfs_mount.c68
-rw-r--r--fs/xfs/xfs_rtalloc.c4
-rw-r--r--fs/xfs/xfs_rtalloc.h11
-rw-r--r--fs/xfs/xfs_trans.c446
-rw-r--r--fs/xfs/xfs_trans.h411
-rw-r--r--fs/xfs/xfs_vnodeops.c2
-rw-r--r--include/acpi/acexcep.h2
-rw-r--r--include/acpi/acpixf.h3
-rw-r--r--include/acpi/actbl2.h9
-rw-r--r--include/asm-generic/fcntl.h8
-rw-r--r--include/asm-generic/percpu.h10
-rw-r--r--include/asm-generic/unistd.h26
-rw-r--r--include/asm-generic/vmlinux.lds.h38
-rw-r--r--include/drm/drm_crtc_helper.h3
-rw-r--r--include/drm/i915_drm.h5
-rw-r--r--include/drm/nouveau_drm.h1
-rw-r--r--include/drm/vmwgfx_drm.h26
-rw-r--r--include/linux/Kbuild5
-rw-r--r--include/linux/backing-dev.h2
-rw-r--r--include/linux/blkdev.h9
-rw-r--r--include/linux/buffer_head.h19
-rw-r--r--include/linux/cache.h2
-rw-r--r--include/linux/cpufreq.h5
-rw-r--r--include/linux/dnotify.h1
-rw-r--r--include/linux/dqblk_xfs.h24
-rw-r--r--include/linux/drbd.h2
-rw-r--r--include/linux/edac_mce.h31
-rw-r--r--include/linux/fanotify.h105
-rw-r--r--include/linux/fs.h64
-rw-r--r--include/linux/fsnotify.h166
-rw-r--r--include/linux/fsnotify_backend.h169
-rw-r--r--include/linux/i2c/ltc4245.h21
-rw-r--r--include/linux/if_bonding.h1
-rw-r--r--include/linux/if_bridge.h2
-rw-r--r--include/linux/if_ether.h2
-rw-r--r--include/linux/if_fddi.h8
-rw-r--r--include/linux/if_frad.h2
-rw-r--r--include/linux/if_hippi.h8
-rw-r--r--include/linux/if_macvlan.h4
-rw-r--r--include/linux/if_packet.h1
-rw-r--r--include/linux/if_pppox.h8
-rw-r--r--include/linux/init.h2
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/inotify.h175
-rw-r--r--include/linux/iocontext.h1
-rw-r--r--include/linux/ioq.h414
-rw-r--r--include/linux/ipv6.h4
-rw-r--r--include/linux/iscsi_boot_sysfs.h123
-rw-r--r--include/linux/iscsi_ibft.h12
-rw-r--r--include/linux/isdnif.h2
-rw-r--r--include/linux/libata.h2
-rw-r--r--include/linux/linkage.h8
-rw-r--r--include/linux/mISDNif.h2
-rw-r--r--include/linux/mm.h1
-rw-r--r--include/linux/mmc/sh_mmcif.h161
-rw-r--r--include/linux/module.h44
-rw-r--r--include/linux/moduleparam.h282
-rw-r--r--include/linux/mount.h6
-rw-r--r--include/linux/nbd.h2
-rw-r--r--include/linux/ncp.h10
-rw-r--r--include/linux/ncp_fs_sb.h14
-rw-r--r--include/linux/netdevice.h17
-rw-r--r--include/linux/netfilter/x_tables.h2
-rw-r--r--include/linux/nl80211.h2
-rw-r--r--include/linux/nmi.h13
-rw-r--r--include/linux/notifier.h1
-rw-r--r--include/linux/pci.h1
-rw-r--r--include/linux/pci_ids.h53
-rw-r--r--include/linux/percpu-defs.h4
-rw-r--r--include/linux/perf_event.h9
-rw-r--r--include/linux/personality.h2
-rw-r--r--include/linux/phonet.h4
-rw-r--r--include/linux/pipe_fs_i.h4
-rw-r--r--include/linux/quotaops.h10
-rw-r--r--include/linux/rds.h12
-rw-r--r--include/linux/sched.h12
-rw-r--r--include/linux/sctp.h80
-rw-r--r--include/linux/security.h12
-rw-r--r--include/linux/serial_core.h3
-rw-r--r--include/linux/serial_sci.h4
-rw-r--r--include/linux/shm_signal.h189
-rw-r--r--include/linux/skbuff.h5
-rw-r--r--include/linux/snmp.h1
-rw-r--r--include/linux/spinlock.h2
-rw-r--r--include/linux/ssb/ssb.h159
-rw-r--r--include/linux/suspend.h26
-rw-r--r--include/linux/swiotlb.h27
-rw-r--r--include/linux/syscalls.h7
-rw-r--r--include/linux/usb/audio-v2.h31
-rw-r--r--include/linux/usb/audio.h90
-rw-r--r--include/linux/vbus_driver.h83
-rw-r--r--include/linux/vbus_pci.h145
-rw-r--r--include/linux/venet.h133
-rw-r--r--include/linux/vgaarb.h21
-rw-r--r--include/linux/via-core.h4
-rw-r--r--include/linux/virtio_9p.h1
-rw-r--r--include/linux/wlp.h24
-rw-r--r--include/linux/writeback.h10
-rw-r--r--include/media/rc-map.h3
-rw-r--r--include/media/soc_camera.h2
-rw-r--r--include/media/v4l2-chip-ident.h4
-rw-r--r--include/media/v4l2-mediabus.h21
-rw-r--r--include/media/v4l2-subdev.h2
-rw-r--r--include/net/9p/9p.h19
-rw-r--r--include/net/9p/client.h19
-rw-r--r--include/net/cfg80211.h18
-rw-r--r--include/net/dn_dev.h8
-rw-r--r--include/net/dn_nsp.h16
-rw-r--r--include/net/dst.h6
-rw-r--r--include/net/genetlink.h15
-rw-r--r--include/net/ip6_tunnel.h2
-rw-r--r--include/net/ipv6.h4
-rw-r--r--include/net/ipx.h8
-rw-r--r--include/net/mac80211.h31
-rw-r--r--include/net/mip6.h2
-rw-r--r--include/net/ndisc.h2
-rw-r--r--include/net/netfilter/nf_conntrack.h6
-rw-r--r--include/net/pkt_sched.h2
-rw-r--r--include/net/sch_generic.h27
-rw-r--r--include/net/sctp/structs.h4
-rw-r--r--include/net/sock.h25
-rw-r--r--include/rxrpc/packet.h8
-rw-r--r--include/scsi/scsi_host.h8
-rw-r--r--include/sound/asound.h6
-rw-r--r--include/sound/pcm.h4
-rw-r--r--include/sound/soc-dapm.h2
-rw-r--r--include/sound/soc.h21
-rw-r--r--include/trace/events/sched.h19
-rw-r--r--include/trace/ftrace.h2
-rw-r--r--include/video/mipi_display.h130
-rw-r--r--include/video/sh_mipi_dsi.h35
-rw-r--r--include/video/sh_mobile_lcdc.h39
-rw-r--r--init/Kconfig18
-rw-r--r--init/main.c8
-rw-r--r--ipc/mqueue.c1
-rw-r--r--kernel/Makefile7
-rw-r--r--kernel/audit.c1
-rw-r--r--kernel/audit.h26
-rw-r--r--kernel/audit_tree.c233
-rw-r--r--kernel/audit_watch.c295
-rw-r--r--kernel/auditfilter.c39
-rw-r--r--kernel/auditsc.c10
-rw-r--r--kernel/cgroup.c2
-rw-r--r--kernel/cpu.c2
-rw-r--r--kernel/debug/kdb/kdb_main.c21
-rw-r--r--kernel/exec_domain.c18
-rw-r--r--kernel/module.c1359
-rw-r--r--kernel/padata.c2
-rw-r--r--kernel/params.c233
-rw-r--r--kernel/perf_event.c351
-rw-r--r--kernel/power/Kconfig9
-rw-r--r--kernel/power/Makefile2
-rw-r--r--kernel/power/nvs.c (renamed from kernel/power/hibernate_nvs.c)24
-rw-r--r--kernel/power/suspend.c6
-rw-r--r--kernel/power/swap.c4
-rw-r--r--kernel/printk.c30
-rw-r--r--kernel/sched.c24
-rw-r--r--kernel/sched_fair.c22
-rw-r--r--kernel/softirq.c2
-rw-r--r--kernel/softlockup.c293
-rw-r--r--kernel/stop_machine.c2
-rw-r--r--kernel/sys_ni.c4
-rw-r--r--kernel/sysctl.c70
-rw-r--r--kernel/timer.c3
-rw-r--r--kernel/trace/blktrace.c2
-rw-r--r--kernel/trace/trace_event_perf.c15
-rw-r--r--kernel/trace/trace_kprobe.c4
-rw-r--r--kernel/trace/trace_syscalls.c4
-rw-r--r--kernel/watchdog.c567
-rw-r--r--lib/Kconfig21
-rw-r--r--lib/Kconfig.debug35
-rw-r--r--lib/Makefile2
-rw-r--r--lib/atomic64_test.c3
-rw-r--r--lib/ioq.c304
-rw-r--r--lib/kobject_uevent.c3
-rw-r--r--lib/shm_signal.c196
-rw-r--r--lib/swiotlb.c137
-rw-r--r--mm/page-writeback.c4
-rw-r--r--mm/shmem.c20
-rw-r--r--mm/truncate.c38
-rw-r--r--mm/vmscan.c29
-rw-r--r--net/8021q/vlan_dev.c3
-rw-r--r--net/9p/client.c71
-rw-r--r--net/9p/protocol.c27
-rw-r--r--net/bluetooth/bnep/bnep.h8
-rw-r--r--net/bridge/br.c2
-rw-r--r--net/bridge/br_if.c8
-rw-r--r--net/bridge/br_input.c12
-rw-r--r--net/bridge/br_private.h3
-rw-r--r--net/caif/caif_socket.c3
-rw-r--r--net/caif/cfcnfg.c8
-rw-r--r--net/caif/cfserl.c6
-rw-r--r--net/can/raw.c11
-rw-r--r--net/compat.c53
-rw-r--r--net/core/dev.c174
-rw-r--r--net/core/netpoll.c31
-rw-r--r--net/core/skbuff.c42
-rw-r--r--net/dccp/ipv6.c30
-rw-r--r--net/dccp/proto.c11
-rw-r--r--net/ipv4/Kconfig10
-rw-r--r--net/ipv4/arp.c11
-rw-r--r--net/ipv4/devinet.c1
-rw-r--r--net/ipv4/fib_frontend.c6
-rw-r--r--net/ipv4/igmp.c3
-rw-r--r--net/ipv4/ip_input.c3
-rw-r--r--net/ipv4/ipconfig.c7
-rw-r--r--net/ipv4/netfilter/ip_tables.c2
-rw-r--r--net/ipv4/proc.c1
-rw-r--r--net/ipv4/route.c73
-rw-r--r--net/ipv4/syncookies.c42
-rw-r--r--net/ipv4/tcp.c5
-rw-r--r--net/ipv4/tcp_hybla.c4
-rw-r--r--net/ipv4/tcp_input.c4
-rw-r--r--net/ipv4/tcp_ipv4.c33
-rw-r--r--net/ipv4/udp.c4
-rw-r--r--net/ipv6/addrlabel.c6
-rw-r--r--net/ipv6/af_inet6.c9
-rw-r--r--net/ipv6/datagram.c18
-rw-r--r--net/ipv6/exthdrs.c24
-rw-r--r--net/ipv6/inet6_connection_sock.c9
-rw-r--r--net/ipv6/ip6mr.c2
-rw-r--r--net/ipv6/mcast.c8
-rw-r--r--net/ipv6/netfilter/ip6_tables.c2
-rw-r--r--net/ipv6/raw.c10
-rw-r--r--net/ipv6/route.c2
-rw-r--r--net/ipv6/sit.c8
-rw-r--r--net/ipv6/syncookies.c50
-rw-r--r--net/ipv6/tcp_ipv6.c29
-rw-r--r--net/ipv6/udp.c11
-rw-r--r--net/iucv/iucv.c14
-rw-r--r--net/mac80211/Kconfig7
-rw-r--r--net/mac80211/Makefile4
-rw-r--r--net/mac80211/agg-tx.c13
-rw-r--r--net/mac80211/cfg.c24
-rw-r--r--net/mac80211/chan.c2
-rw-r--r--net/mac80211/debugfs.c154
-rw-r--r--net/mac80211/debugfs_sta.c48
-rw-r--r--net/mac80211/driver-ops.h25
-rw-r--r--net/mac80211/driver-trace.h35
-rw-r--r--net/mac80211/ibss.c14
-rw-r--r--net/mac80211/ieee80211_i.h9
-rw-r--r--net/mac80211/iface.c14
-rw-r--r--net/mac80211/key.c288
-rw-r--r--net/mac80211/key.h22
-rw-r--r--net/mac80211/main.c78
-rw-r--r--net/mac80211/mlme.c75
-rw-r--r--net/mac80211/rate.c2
-rw-r--r--net/mac80211/rate.h13
-rw-r--r--net/mac80211/rc80211_minstrel_ht.c824
-rw-r--r--net/mac80211/rc80211_minstrel_ht.h128
-rw-r--r--net/mac80211/rc80211_minstrel_ht_debugfs.c120
-rw-r--r--net/mac80211/rx.c56
-rw-r--r--net/mac80211/sta_info.c8
-rw-r--r--net/mac80211/sta_info.h44
-rw-r--r--net/mac80211/status.c2
-rw-r--r--net/mac80211/work.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c8
-rw-r--r--net/netfilter/x_tables.c17
-rw-r--r--net/packet/af_packet.c37
-rw-r--r--net/phonet/pep.c6
-rw-r--r--net/rds/ib_cm.c1
-rw-r--r--net/rds/iw_cm.c1
-rw-r--r--net/sched/act_nat.c4
-rw-r--r--net/sched/act_pedit.c24
-rw-r--r--net/sched/cls_u32.c49
-rw-r--r--net/sched/sch_generic.c23
-rw-r--r--net/sctp/sm_make_chunk.c2
-rw-r--r--net/socket.c164
-rw-r--r--net/sunrpc/xprtsock.c26
-rw-r--r--net/wireless/chan.c5
-rw-r--r--net/wireless/core.h1
-rw-r--r--net/wireless/mlme.c3
-rw-r--r--net/wireless/nl80211.c3
-rw-r--r--net/xfrm/xfrm_output.c4
-rw-r--r--net/xfrm/xfrm_policy.c1
-rw-r--r--scripts/Makefile.build28
-rw-r--r--scripts/Makefile.lib2
-rwxr-xr-xscripts/checkincludes.pl24
-rwxr-xr-xscripts/checkkconfigsymbols.sh2
-rwxr-xr-xscripts/checkstack.pl16
-rwxr-xr-xscripts/checkversion.pl23
-rwxr-xr-xscripts/decodecode48
-rw-r--r--scripts/export_report.pl37
-rw-r--r--scripts/gen_initramfs_list.sh3
-rw-r--r--scripts/genksyms/genksyms.c4
-rwxr-xr-xscripts/headerdep.pl3
-rw-r--r--scripts/headers_check.pl11
-rw-r--r--scripts/headers_install.pl19
-rw-r--r--scripts/kallsyms.c6
-rw-r--r--scripts/kconfig/.gitignore1
-rw-r--r--scripts/kconfig/Makefile28
-rw-r--r--scripts/kconfig/conf.c53
-rw-r--r--scripts/kconfig/expr.c27
-rw-r--r--scripts/kconfig/expr.h5
-rw-r--r--scripts/kconfig/gconf.c116
-rw-r--r--scripts/kconfig/gconf.glade26
-rw-r--r--scripts/kconfig/lkc.h7
-rw-r--r--scripts/kconfig/lkc_proto.h6
-rw-r--r--scripts/kconfig/lxdialog/checklist.c10
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c4
-rw-r--r--scripts/kconfig/lxdialog/menubox.c22
-rw-r--r--scripts/kconfig/mconf.c36
-rw-r--r--scripts/kconfig/menu.c48
-rw-r--r--scripts/kconfig/nconf.c1568
-rw-r--r--scripts/kconfig/nconf.gui.c617
-rw-r--r--scripts/kconfig/nconf.h95
-rw-r--r--scripts/kconfig/qconf.cc106
-rw-r--r--scripts/kconfig/qconf.h17
-rw-r--r--scripts/kconfig/symbol.c30
-rw-r--r--scripts/kconfig/util.c2
-rw-r--r--scripts/kconfig/zconf.tab.c_shipped25
-rw-r--r--scripts/kconfig/zconf.y25
-rw-r--r--scripts/markup_oops.pl54
-rwxr-xr-xscripts/mkcompile_h5
-rw-r--r--scripts/mod/modpost.c165
-rwxr-xr-xscripts/namespace.pl65
-rw-r--r--scripts/package/builddeb7
-rwxr-xr-xscripts/package/mkspec2
-rw-r--r--scripts/profile2linkerlist.pl8
-rw-r--r--scripts/rt-tester/rt-tester.py2
-rwxr-xr-xscripts/show_delta2
-rwxr-xr-xscripts/tags.sh45
-rw-r--r--security/capability.c3
-rw-r--r--security/keys/keyctl.c4
-rw-r--r--security/security.c21
-rw-r--r--security/selinux/avc.c1
-rw-r--r--security/selinux/netnode.c2
-rw-r--r--security/smack/smack_lsm.c14
-rw-r--r--security/tomoyo/Makefile2
-rw-r--r--security/tomoyo/common.c2000
-rw-r--r--security/tomoyo/common.h454
-rw-r--r--security/tomoyo/domain.c294
-rw-r--r--security/tomoyo/file.c1038
-rw-r--r--security/tomoyo/gc.c107
-rw-r--r--security/tomoyo/load_policy.c81
-rw-r--r--security/tomoyo/memory.c235
-rw-r--r--security/tomoyo/mount.c312
-rw-r--r--security/tomoyo/number_group.c175
-rw-r--r--security/tomoyo/path_group.c19
-rw-r--r--security/tomoyo/realpath.c409
-rw-r--r--security/tomoyo/securityfs_if.c140
-rw-r--r--security/tomoyo/tomoyo.c35
-rw-r--r--security/tomoyo/util.c963
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c8
-rw-r--r--sound/core/pcm_misc.c16
-rw-r--r--sound/pci/asihpi/asihpi.c3
-rw-r--r--sound/pci/hda/hda_intel.c7
-rw-r--r--sound/pci/hda/patch_realtek.c1
-rw-r--r--sound/soc/Kconfig3
-rw-r--r--sound/soc/Makefile3
-rw-r--r--sound/soc/atmel/atmel-pcm.c1
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c1
-rw-r--r--sound/soc/au1x/psc-ac97.c13
-rw-r--r--sound/soc/au1x/psc-i2s.c13
-rw-r--r--sound/soc/au1x/psc.h1
-rw-r--r--sound/soc/codecs/Kconfig4
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/ad193x.c41
-rw-r--r--sound/soc/codecs/ad193x.h5
-rw-r--r--sound/soc/codecs/cs42l51.c763
-rw-r--r--sound/soc/codecs/cs42l51.h163
-rw-r--r--sound/soc/codecs/spdif_transciever.c94
-rw-r--r--sound/soc/codecs/spdif_transciever.h1
-rw-r--r--sound/soc/codecs/tlv320dac33.c57
-rw-r--r--sound/soc/codecs/twl4030.c291
-rw-r--r--sound/soc/codecs/twl4030.h3
-rw-r--r--sound/soc/codecs/twl6040.c2
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/ep93xx/Kconfig9
-rw-r--r--sound/soc/ep93xx/Makefile8
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.c487
-rw-r--r--sound/soc/ep93xx/ep93xx-i2s.h18
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.c319
-rw-r--r--sound/soc/ep93xx/ep93xx-pcm.h22
-rw-r--r--sound/soc/imx/Kconfig20
-rw-r--r--sound/soc/imx/Makefile2
-rw-r--r--sound/soc/imx/eukrea-tlv320.c135
-rw-r--r--sound/soc/imx/imx-ssi.c11
-rw-r--r--sound/soc/kirkwood/Kconfig20
-rw-r--r--sound/soc/kirkwood/Makefile9
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.c383
-rw-r--r--sound/soc/kirkwood/kirkwood-dma.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.c484
-rw-r--r--sound/soc/kirkwood/kirkwood-i2s.h17
-rw-r--r--sound/soc/kirkwood/kirkwood-openrd.c126
-rw-r--r--sound/soc/kirkwood/kirkwood.h126
-rw-r--r--sound/soc/nuc900/Kconfig27
-rw-r--r--sound/soc/nuc900/Makefile11
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c430
-rw-r--r--sound/soc/nuc900/nuc900-audio.c81
-rw-r--r--sound/soc/nuc900/nuc900-audio.h117
-rw-r--r--sound/soc/nuc900/nuc900-pcm.c354
-rw-r--r--sound/soc/omap/omap-mcbsp.c112
-rw-r--r--sound/soc/s3c24xx/Kconfig4
-rw-r--r--sound/soc/s3c24xx/s3c-ac97.c1
-rw-r--r--sound/soc/s3c24xx/smdk_wm9713.c3
-rw-r--r--sound/soc/s6000/s6000-i2s.c38
-rw-r--r--sound/soc/soc-core.c95
-rw-r--r--sound/usb/Makefile3
-rw-r--r--sound/usb/card.c18
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/clock.c311
-rw-r--r--sound/usb/clock.h12
-rw-r--r--sound/usb/endpoint.c57
-rw-r--r--sound/usb/format.c16
-rw-r--r--sound/usb/mixer.c213
-rw-r--r--sound/usb/mixer.h2
-rw-r--r--sound/usb/mixer_maps.c4
-rw-r--r--sound/usb/pcm.c98
-rw-r--r--sound/usb/usbaudio.h5
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/builtin-sched.c1
-rw-r--r--tools/perf/scripts/python/check-perf-trace.py3
-rw-r--r--tools/perf/util/event.c13
-rw-r--r--tools/perf/util/hist.c2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c50
2243 files changed, 182630 insertions, 28327 deletions
diff --git a/.gitignore b/.gitignore
index a2939fc10b22..8faa6c02b39e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ modules.builtin
*.gz
*.bz2
*.lzma
+*.lzo
*.patch
*.gcno
diff --git a/Documentation/.gitignore b/Documentation/.gitignore
new file mode 100644
index 000000000000..bcd907b4141f
--- /dev/null
+++ b/Documentation/.gitignore
@@ -0,0 +1,7 @@
+filesystems/dnotify_test
+laptops/dslm
+timers/hpet_example
+vm/hugepage-mmap
+vm/hugepage-shm
+vm/map_hugetlb
+
diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
index 88340a23ce91..36bfa234f1e2 100644
--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
+++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
@@ -33,11 +33,10 @@ Description: When read, this file returns the raw integer version number of the
left. E.g. a returned value of 138 means 1.38
This file is readonly.
-What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version
-Date: March 2010
+What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/kone_abi_version
+Date: May 2010
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
-Description: When read, this file returns the driver version.
- The format of the string is "v<major>.<minor>.<patchlevel>".
+Description: When read, this file returns the abi version as an integer value.
This attribute is used by the userland tools to find the sysfs-
paths of installed kone-mice and determine the capabilites of
the driver. Versions of this driver for old kernels replace
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 7583dc7cf64d..910c923a9b86 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -389,7 +389,7 @@
</para>
<para>
If your driver supports memory management (it should!), you'll
- need to set that up at load time as well. How you intialize
+ need to set that up at load time as well. How you initialize
it depends on which memory manager you're using, TTM or GEM.
</para>
<sect3>
@@ -399,7 +399,7 @@
aperture space for graphics devices. TTM supports both UMA devices
and devices with dedicated video RAM (VRAM), i.e. most discrete
graphics devices. If your device has dedicated RAM, supporting
- TTM is desireable. TTM also integrates tightly with your
+ TTM is desirable. TTM also integrates tightly with your
driver specific buffer execution function. See the radeon
driver for examples.
</para>
@@ -443,7 +443,7 @@
likely eventually calling ttm_bo_global_init and
ttm_bo_global_release, respectively. Also like the previous
object, ttm_global_item_ref is used to create an initial reference
- count for the TTM, which will call your initalization function.
+ count for the TTM, which will call your initialization function.
</para>
</sect3>
<sect3>
@@ -557,7 +557,7 @@ void intel_crt_init(struct drm_device *dev)
CRT connector and encoder combination is created. A device
specific i2c bus is also created, for fetching EDID data and
performing monitor detection. Once the process is complete,
- the new connector is regsitered with sysfs, to make its
+ the new connector is registered with sysfs, to make its
properties available to applications.
</para>
<sect4>
@@ -581,12 +581,12 @@ void intel_crt_init(struct drm_device *dev)
<para>
For each encoder, CRTC and connector, several functions must
be provided, depending on the object type. Encoder objects
- need should provide a DPMS (basically on/off) function, mode fixup
+ need to provide a DPMS (basically on/off) function, mode fixup
(for converting requested modes into native hardware timings),
and prepare, set and commit functions for use by the core DRM
helper functions. Connector helpers need to provide mode fetch and
validity functions as well as an encoder matching function for
- returing an ideal encoder for a given connector. The core
+ returning an ideal encoder for a given connector. The core
connector functions include a DPMS callback, (deprecated)
save/restore routines, detection, mode probing, property handling,
and cleanup functions.
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 9737243377a3..7c3c098d5d08 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -58,7 +58,7 @@ MPEG stream embedded, sliced VBI data format in this specification.
</contrib>
<affiliation>
<address>
- <email>awalls@radix.net</email>
+ <email>awalls@md.metrocast.net</email>
</address>
</affiliation>
</author>
diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
index 87e4f0f6151c..402229ee06f6 100644
--- a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
+++ b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
@@ -53,8 +53,10 @@ input</refpurpose>
automatically, similar to sensing the video standard. To do so, applications
call <constant> VIDIOC_QUERY_DV_PRESET</constant> with a pointer to a
&v4l2-dv-preset; type. Once the hardware detects a preset, that preset is
-returned in the preset field of &v4l2-dv-preset;. When detection is not
-possible or fails, the value V4L2_DV_INVALID is returned.</para>
+returned in the preset field of &v4l2-dv-preset;. If the preset could not be
+detected because there was no signal, or the signal was unreliable, or the
+signal did not map to a supported preset, then the value V4L2_DV_INVALID is
+returned.</para>
</refsect1>
<refsect1>
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index a99d7031cdf9..45d5a217484f 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -2,7 +2,7 @@
Maintainers:
CPU Hotplug Core:
- Rusty Russell <rusty@rustycorp.com.au>
+ Rusty Russell <rusty@rustcorp.com.au>
Srivatsa Vaddagiri <vatsa@in.ibm.com>
i386:
Zwane Mwaikambo <zwane@arm.linux.org.uk>
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 79c533223762..0b875e8da969 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -6,6 +6,8 @@ Written by Doug Thompson <dougthompson@xmission.com>
7 Dec 2005
17 Jul 2007 Updated
+(c) Mauro Carvalho Chehab <mchehab@redhat.com>
+05 Aug 2009 Nehalem interface
EDAC is maintained and written by:
@@ -717,3 +719,153 @@ unique drivers for their hardware systems.
The 'test_device_edac' sample driver is located at the
bluesmoke.sourceforge.net project site for EDAC.
+=======================================================================
+NEHALEM USAGE OF EDAC APIs
+
+This chapter documents some EXPERIMENTAL mappings for EDAC API to handle
+Nehalem EDAC driver. They will likely be changed on future versions
+of the driver.
+
+Due to the way Nehalem exports Memory Controller data, some adjustments
+were done at i7core_edac driver. This chapter will cover those differences
+
+1) On Nehalem, there are one Memory Controller per Quick Patch Interconnect
+ (QPI). At the driver, the term "socket" means one QPI. This is
+ associated with a physical CPU socket.
+
+ Each MC have 3 physical read channels, 3 physical write channels and
+ 3 logic channels. The driver currenty sees it as just 3 channels.
+ Each channel can have up to 3 DIMMs.
+
+ The minimum known unity is DIMMs. There are no information about csrows.
+ As EDAC API maps the minimum unity is csrows, the driver sequencially
+ maps channel/dimm into different csrows.
+
+ For example, suposing the following layout:
+ Ch0 phy rd0, wr0 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ dimm 1 1024 Mb offset: 4, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ Ch1 phy rd1, wr1 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ Ch2 phy rd3, wr3 (0x063f4031): 2 ranks, UDIMMs
+ dimm 0 1024 Mb offset: 0, bank: 8, rank: 1, row: 0x4000, col: 0x400
+ The driver will map it as:
+ csrow0: channel 0, dimm0
+ csrow1: channel 0, dimm1
+ csrow2: channel 1, dimm0
+ csrow3: channel 2, dimm0
+
+exports one
+ DIMM per csrow.
+
+ Each QPI is exported as a different memory controller.
+
+2) Nehalem MC has the hability to generate errors. The driver implements this
+ functionality via some error injection nodes:
+
+ For injecting a memory error, there are some sysfs nodes, under
+ /sys/devices/system/edac/mc/mc?/:
+
+ inject_addrmatch/*:
+ Controls the error injection mask register. It is possible to specify
+ several characteristics of the address to match an error code:
+ dimm = the affected dimm. Numbers are relative to a channel;
+ rank = the memory rank;
+ channel = the channel that will generate an error;
+ bank = the affected bank;
+ page = the page address;
+ column (or col) = the address column.
+ each of the above values can be set to "any" to match any valid value.
+
+ At driver init, all values are set to any.
+
+ For example, to generate an error at rank 1 of dimm 2, for any channel,
+ any bank, any page, any column:
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+ echo 1 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+ To return to the default behaviour of matching any, you can do:
+ echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/dimm
+ echo any >/sys/devices/system/edac/mc/mc0/inject_addrmatch/rank
+
+ inject_eccmask:
+ specifies what bits will have troubles,
+
+ inject_section:
+ specifies what ECC cache section will get the error:
+ 3 for both
+ 2 for the highest
+ 1 for the lowest
+
+ inject_type:
+ specifies the type of error, being a combination of the following bits:
+ bit 0 - repeat
+ bit 1 - ecc
+ bit 2 - parity
+
+ inject_enable starts the error generation when something different
+ than 0 is written.
+
+ All inject vars can be read. root permission is needed for write.
+
+ Datasheet states that the error will only be generated after a write on an
+ address that matches inject_addrmatch. It seems, however, that reading will
+ also produce an error.
+
+ For example, the following code will generate an error for any write access
+ at socket 0, on any DIMM/address on channel 2:
+
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_addrmatch/channel
+ echo 2 >/sys/devices/system/edac/mc/mc0/inject_type
+ echo 64 >/sys/devices/system/edac/mc/mc0/inject_eccmask
+ echo 3 >/sys/devices/system/edac/mc/mc0/inject_section
+ echo 1 >/sys/devices/system/edac/mc/mc0/inject_enable
+ dd if=/dev/mem of=/dev/null seek=16k bs=4k count=1 >& /dev/null
+
+ For socket 1, it is needed to replace "mc0" by "mc1" at the above
+ commands.
+
+ The generated error message will look like:
+
+ EDAC MC0: UE row 0, channel-a= 0 channel-b= 0 labels "-": NON_FATAL (addr = 0x0075b980, socket=0, Dimm=0, Channel=2, syndrome=0x00000040, count=1, Err=8c0000400001009f:4000080482 (read error: read ECC error))
+
+3) Nehalem specific Corrected Error memory counters
+
+ Nehalem have some registers to count memory errors. The driver uses those
+ registers to report Corrected Errors on devices with Registered Dimms.
+
+ However, those counters don't work with Unregistered Dimms. As the chipset
+ offers some counters that also work with UDIMMS (but with a worse level of
+ granularity than the default ones), the driver exposes those registers for
+ UDIMM memories.
+
+ They can be read by looking at the contents of all_channel_counts/
+
+ $ for i in /sys/devices/system/edac/mc/mc0/all_channel_counts/*; do echo $i; cat $i; done
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm0
+ 0
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm1
+ 0
+ /sys/devices/system/edac/mc/mc0/all_channel_counts/udimm2
+ 0
+
+ What happens here is that errors on different csrows, but at the same
+ dimm number will increment the same counter.
+ So, in this memory mapping:
+ csrow0: channel 0, dimm0
+ csrow1: channel 0, dimm1
+ csrow2: channel 1, dimm0
+ csrow3: channel 2, dimm0
+ The hardware will increment udimm0 for an error at the first dimm at either
+ csrow0, csrow2 or csrow3;
+ The hardware will increment udimm1 for an error at the second dimm at either
+ csrow0, csrow2 or csrow3;
+ The hardware will increment udimm2 for an error at the third dimm at either
+ csrow0, csrow2 or csrow3;
+
+4) Standard error counters
+
+ The standard error counters are generated when an mcelog error is received
+ by the driver. Since, with udimm, this is counted by software, it is
+ possible that some errors could be lost. With rdimm's, they displays the
+ contents of the registers
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 672be0109d02..0903d344fd86 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -367,24 +367,6 @@ When: 2.6.33
Why: Should be implemented in userspace, policy daemon.
Who: Johannes Berg <johannes@sipsolutions.net>
----------------------------
-
-What: CONFIG_INOTIFY
-When: 2.6.33
-Why: last user (audit) will be converted to the newer more generic
- and more easily maintained fsnotify subsystem
-Who: Eric Paris <eparis@redhat.com>
-
-----------------------------
-
-What: lock_policy_rwsem_* and unlock_policy_rwsem_* will not be
- exported interface anymore.
-When: 2.6.33
-Why: cpu_policy_rwsem has a new cleaner definition making it local to
- cpufreq core and contained inside cpufreq.c. Other dependent
- drivers should not use it in order to safely avoid lockdep issues.
-Who: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
-
----------------------------
What: sound-slot/service-* module aliases and related clutters in
@@ -578,15 +560,6 @@ Who: Avi Kivity <avi@redhat.com>
----------------------------
-What: "acpi=ht" boot option
-When: 2.6.35
-Why: Useful in 2003, implementation is a hack.
- Generally invoked by accident today.
- Seen as doing more harm than good.
-Who: Len Brown <len.brown@intel.com>
-
-----------------------------
-
What: iwlwifi 50XX module parameters
When: 2.6.40
Why: The "..50" modules parameters were used to configure 5000 series and
diff --git a/Documentation/filesystems/nfs/nfsroot.txt b/Documentation/filesystems/nfs/nfsroot.txt
index 3ba0b945aaf8..f2430a7974e1 100644
--- a/Documentation/filesystems/nfs/nfsroot.txt
+++ b/Documentation/filesystems/nfs/nfsroot.txt
@@ -124,6 +124,8 @@ ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>
<hostname> Name of the client. May be supplied by autoconfiguration,
but its absence will not trigger autoconfiguration.
+ If specified and DHCP is used, the user provided hostname will
+ be carried in the DHCP request to hopefully update DNS record.
Default: Client IP address is used in ASCII notation.
diff --git a/Documentation/filesystems/xfs-delayed-logging-design.txt b/Documentation/filesystems/xfs-delayed-logging-design.txt
index d8119e9d2d60..96d0df28bed3 100644
--- a/Documentation/filesystems/xfs-delayed-logging-design.txt
+++ b/Documentation/filesystems/xfs-delayed-logging-design.txt
@@ -794,11 +794,6 @@ designed.
Roadmap:
-2.6.35 Inclusion in mainline as an experimental mount option
- => approximately 2-3 months to merge window
- => needs to be in xfs-dev tree in 4-6 weeks
- => code is nearing readiness for review
-
2.6.37 Remove experimental tag from mount option
=> should be roughly 6 months after initial merge
=> enough time to:
diff --git a/Documentation/hwmon/ltc4245 b/Documentation/hwmon/ltc4245
index 86b5880d8502..b478b0864965 100644
--- a/Documentation/hwmon/ltc4245
+++ b/Documentation/hwmon/ltc4245
@@ -72,9 +72,31 @@ in6_min_alarm 5v output undervoltage alarm
in7_min_alarm 3v output undervoltage alarm
in8_min_alarm Vee (-12v) output undervoltage alarm
-in9_input GPIO voltage data
+in9_input GPIO voltage data (see note 1)
+in10_input GPIO voltage data (see note 1)
+in11_input GPIO voltage data (see note 1)
power1_input 12v power usage (mW)
power2_input 5v power usage (mW)
power3_input 3v power usage (mW)
power4_input Vee (-12v) power usage (mW)
+
+
+Note 1
+------
+
+If you have NOT configured the driver to sample all GPIO pins as analog
+voltages, then the in10_input and in11_input sysfs attributes will not be
+created. The driver will sample the GPIO pin that is currently connected to the
+ADC as an analog voltage, and report the value in in9_input.
+
+If you have configured the driver to sample all GPIO pins as analog voltages,
+then they will be sampled in round-robin fashion. If userspace reads too
+slowly, -EAGAIN will be returned when you read the sysfs attribute containing
+the sensor reading.
+
+The LTC4245 chip can be configured to sample all GPIO pins with two methods:
+1) platform data -- see include/linux/i2c/ltc4245.h
+2) OF device tree -- add the "ltc4245,use-extra-gpios" property to each chip
+
+The default mode of operation is to sample a single GPIO pin.
diff --git a/Documentation/i2c/busses/i2c-ali1535 b/Documentation/i2c/busses/i2c-ali1535
index 0db3b4c74ad1..acbc65a08097 100644
--- a/Documentation/i2c/busses/i2c-ali1535
+++ b/Documentation/i2c/busses/i2c-ali1535
@@ -6,12 +6,12 @@ Supported adapters:
http://www.ali.com.tw/eng/support/datasheet_request.php
Authors:
- Frodo Looijaard <frodol@dds.nl>,
+ Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
Dan Eaton <dan.eaton@rocketlogix.com>,
Stephen Rousset<stephen.rousset@rocketlogix.com>
-
+
Description
-----------
diff --git a/Documentation/i2c/busses/i2c-ali1563 b/Documentation/i2c/busses/i2c-ali1563
index 99ad4b9bcc32..54691698d2dd 100644
--- a/Documentation/i2c/busses/i2c-ali1563
+++ b/Documentation/i2c/busses/i2c-ali1563
@@ -18,7 +18,7 @@ For an overview of these chips see http://www.acerlabs.com
The M1563 southbridge is deceptively similar to the M1533, with a few
notable exceptions. One of those happens to be the fact they upgraded the
i2c core to be SMBus 2.0 compliant, and happens to be almost identical to
-the i2c controller found in the Intel 801 south bridges.
+the i2c controller found in the Intel 801 south bridges.
Features
--------
diff --git a/Documentation/i2c/busses/i2c-ali15x3 b/Documentation/i2c/busses/i2c-ali15x3
index ff28d381bebe..600da90b8f12 100644
--- a/Documentation/i2c/busses/i2c-ali15x3
+++ b/Documentation/i2c/busses/i2c-ali15x3
@@ -6,8 +6,8 @@ Supported adapters:
http://www.ali.com.tw/eng/support/datasheet_request.php
Authors:
- Frodo Looijaard <frodol@dds.nl>,
- Philip Edelbrock <phil@netroedge.com>,
+ Frodo Looijaard <frodol@dds.nl>,
+ Philip Edelbrock <phil@netroedge.com>,
Mark D. Studebaker <mdsxyz123@yahoo.com>
Module Parameters
@@ -40,10 +40,10 @@ M1541 and M1543C South Bridges.
The M1543C is a South bridge for desktop systems.
The M1541 is a South bridge for portable systems.
They are part of the following ALI chipsets:
-
- * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and
+
+ * "Aladdin Pro 2" includes the M1621 Slot 1 North bridge with AGP and
100MHz CPU Front Side bus
- * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz
+ * "Aladdin V" includes the M1541 Socket 7 North bridge with AGP and 100MHz
CPU Front Side bus
Some Aladdin V motherboards:
Asus P5A
@@ -77,7 +77,7 @@ output of lspci will show something similar to the following:
** then run lspci.
** If you see the 1533 and 5229 devices but NOT the 7101 device,
** then you must enable ACPI, the PMU, SMB, or something similar
-** in the BIOS.
+** in the BIOS.
** The driver won't work if it can't find the M7101 device.
The SMB controller is part of the M7101 device, which is an ACPI-compliant
@@ -87,8 +87,8 @@ The whole M7101 device has to be enabled for the SMB to work. You can't
just enable the SMB alone. The SMB and the ACPI have separate I/O spaces.
We make sure that the SMB is enabled. We leave the ACPI alone.
-Features
---------
+Features
+--------
This driver controls the SMB Host only. The SMB Slave
controller on the M15X3 is not enabled. This driver does not use
diff --git a/Documentation/i2c/busses/i2c-pca-isa b/Documentation/i2c/busses/i2c-pca-isa
index 6fc8f4c27c3c..b044e5265488 100644
--- a/Documentation/i2c/busses/i2c-pca-isa
+++ b/Documentation/i2c/busses/i2c-pca-isa
@@ -1,10 +1,10 @@
Kernel driver i2c-pca-isa
Supported adapters:
-This driver supports ISA boards using the Philips PCA 9564
-Parallel bus to I2C bus controller
+This driver supports ISA boards using the Philips PCA 9564
+Parallel bus to I2C bus controller
-Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems
+Author: Ian Campbell <icampbell@arcom.com>, Arcom Control Systems
Module Parameters
-----------------
@@ -12,12 +12,12 @@ Module Parameters
* base int
I/O base address
* irq int
- IRQ interrupt
-* clock int
+ IRQ interrupt
+* clock int
Clock rate as described in table 1 of PCA9564 datasheet
Description
-----------
-This driver supports ISA boards using the Philips PCA 9564
-Parallel bus to I2C bus controller
+This driver supports ISA boards using the Philips PCA 9564
+Parallel bus to I2C bus controller
diff --git a/Documentation/i2c/busses/i2c-sis5595 b/Documentation/i2c/busses/i2c-sis5595
index cc47db7d00a9..ecd21fb49a8f 100644
--- a/Documentation/i2c/busses/i2c-sis5595
+++ b/Documentation/i2c/busses/i2c-sis5595
@@ -1,41 +1,41 @@
Kernel driver i2c-sis5595
-Authors:
+Authors:
Frodo Looijaard <frodol@dds.nl>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
- Philip Edelbrock <phil@netroedge.com>
+ Philip Edelbrock <phil@netroedge.com>
Supported adapters:
* Silicon Integrated Systems Corp. SiS5595 Southbridge
Datasheet: Publicly available at the Silicon Integrated Systems Corp. site.
-Note: all have mfr. ID 0x1039.
-
- SUPPORTED PCI ID
- 5595 0008
-
- Note: these chips contain a 0008 device which is incompatible with the
- 5595. We recognize these by the presence of the listed
- "blacklist" PCI ID and refuse to load.
-
- NOT SUPPORTED PCI ID BLACKLIST PCI ID
- 540 0008 0540
- 550 0008 0550
- 5513 0008 5511
- 5581 0008 5597
- 5582 0008 5597
- 5597 0008 5597
- 5598 0008 5597/5598
- 630 0008 0630
- 645 0008 0645
- 646 0008 0646
- 648 0008 0648
- 650 0008 0650
- 651 0008 0651
- 730 0008 0730
- 735 0008 0735
- 745 0008 0745
- 746 0008 0746
+Note: all have mfr. ID 0x1039.
+
+ SUPPORTED PCI ID
+ 5595 0008
+
+ Note: these chips contain a 0008 device which is incompatible with the
+ 5595. We recognize these by the presence of the listed
+ "blacklist" PCI ID and refuse to load.
+
+ NOT SUPPORTED PCI ID BLACKLIST PCI ID
+ 540 0008 0540
+ 550 0008 0550
+ 5513 0008 5511
+ 5581 0008 5597
+ 5582 0008 5597
+ 5597 0008 5597
+ 5598 0008 5597/5598
+ 630 0008 0630
+ 645 0008 0645
+ 646 0008 0646
+ 648 0008 0648
+ 650 0008 0650
+ 651 0008 0651
+ 730 0008 0730
+ 735 0008 0735
+ 745 0008 0745
+ 746 0008 0746
Module Parameters
-----------------
diff --git a/Documentation/i2c/busses/i2c-sis630 b/Documentation/i2c/busses/i2c-sis630
index 9aca6889f748..629ea2c356fd 100644
--- a/Documentation/i2c/busses/i2c-sis630
+++ b/Documentation/i2c/busses/i2c-sis630
@@ -14,9 +14,9 @@ Module Parameters
* force = [1|0] Forcibly enable the SIS630. DANGEROUS!
This can be interesting for chipsets not named
above to check if it works for you chipset, but DANGEROUS!
-
-* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,
- what your BIOS use). DANGEROUS! This should be a bit
+
+* high_clock = [1|0] Forcibly set Host Master Clock to 56KHz (default,
+ what your BIOS use). DANGEROUS! This should be a bit
faster, but freeze some systems (i.e. my Laptop).
@@ -44,6 +44,6 @@ Philip Edelbrock <phil@netroedge.com>
- testing SiS730 support
Mark M. Hoffman <mhoffman@lightlink.com>
- bug fixes
-
+
To anyone else which I forgot here ;), thanks!
diff --git a/Documentation/i2c/ten-bit-addresses b/Documentation/i2c/ten-bit-addresses
index 200074f81360..e9890709c508 100644
--- a/Documentation/i2c/ten-bit-addresses
+++ b/Documentation/i2c/ten-bit-addresses
@@ -1,17 +1,17 @@
-The I2C protocol knows about two kinds of device addresses: normal 7 bit
+The I2C protocol knows about two kinds of device addresses: normal 7 bit
addresses, and an extended set of 10 bit addresses. The sets of addresses
do not intersect: the 7 bit address 0x10 is not the same as the 10 bit
address 0x10 (though a single device could respond to both of them). You
select a 10 bit address by adding an extra byte after the address
byte:
- S Addr7 Rd/Wr ....
+ S Addr7 Rd/Wr ....
becomes
S 11110 Addr10 Rd/Wr
S is the start bit, Rd/Wr the read/write bit, and if you count the number
of bits, you will see the there are 8 after the S bit for 7 bit addresses,
and 16 after the S bit for 10 bit addresses.
-WARNING! The current 10 bit address support is EXPERIMENTAL. There are
+WARNING! The current 10 bit address support is EXPERIMENTAL. There are
several places in the code that will cause SEVERE PROBLEMS with 10 bit
addresses, even though there is some basic handling and hooks. Also,
almost no supported adapter handles the 10 bit addresses correctly.
diff --git a/Documentation/kbuild/kbuild.txt b/Documentation/kbuild/kbuild.txt
index 6f8c1cabbc5d..634c625da8ce 100644
--- a/Documentation/kbuild/kbuild.txt
+++ b/Documentation/kbuild/kbuild.txt
@@ -65,7 +65,7 @@ CROSS_COMPILE
Specify an optional fixed part of the binutils filename.
CROSS_COMPILE can be a part of the filename or the full path.
-CROSS_COMPILE is also used for ccache is some setups.
+CROSS_COMPILE is also used for ccache in some setups.
CF
--------------------------------------------------
@@ -162,3 +162,7 @@ For tags/TAGS/cscope targets, you can specify more than one arch
to be included in the databases, separated by blank space. E.g.:
$ make ALLSOURCE_ARCHS="x86 mips arm" tags
+
+To get all available archs you can also specify all. E.g.:
+
+ $ make ALLSOURCE_ARCHS=all tags
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index 71c602d61680..31bfcbf958fc 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -168,7 +168,7 @@ more details, with real examples.
#drivers/isdn/i4l/Makefile
# Makefile for the kernel ISDN subsystem and device drivers.
# Each configuration option enables a list of files.
- obj-$(CONFIG_ISDN) += isdn.o
+ obj-$(CONFIG_ISDN_I4L) += isdn.o
obj-$(CONFIG_ISDN_PPP_BSDCOMP) += isdn_bsdcomp.o
--- 3.3 Loadable module goals - obj-m
@@ -187,34 +187,35 @@ more details, with real examples.
Note: In this example $(CONFIG_ISDN_PPP_BSDCOMP) evaluates to 'm'
If a kernel module is built from several source files, you specify
- that you want to build a module in the same way as above.
-
- Kbuild needs to know which the parts that you want to build your
- module from, so you have to tell it by setting an
- $(<module_name>-objs) variable.
+ that you want to build a module in the same way as above; however,
+ kbuild needs to know which object files you want to build your
+ module from, so you have to tell it by setting a $(<module_name>-y)
+ variable.
Example:
#drivers/isdn/i4l/Makefile
- obj-$(CONFIG_ISDN) += isdn.o
- isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
+ obj-$(CONFIG_ISDN_I4L) += isdn.o
+ isdn-y := isdn_net_lib.o isdn_v110.o isdn_common.o
In this example, the module name will be isdn.o. Kbuild will
- compile the objects listed in $(isdn-objs) and then run
+ compile the objects listed in $(isdn-y) and then run
"$(LD) -r" on the list of these files to generate isdn.o.
- Kbuild recognises objects used for composite objects by the suffix
- -objs, and the suffix -y. This allows the Makefiles to use
- the value of a CONFIG_ symbol to determine if an object is part
- of a composite object.
+ Due to kbuild recognizing $(<module_name>-y) for composite objects,
+ you can use the value of a CONFIG_ symbol to optionally include an
+ object file as part of a composite object.
Example:
#fs/ext2/Makefile
- obj-$(CONFIG_EXT2_FS) += ext2.o
- ext2-y := balloc.o bitmap.o
- ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o
+ obj-$(CONFIG_EXT2_FS) += ext2.o
+ ext2-y := balloc.o dir.o file.o ialloc.o inode.o ioctl.o \
+ namei.o super.o symlink.o
+ ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o \
+ xattr_trusted.o
- In this example, xattr.o is only part of the composite object
- ext2.o if $(CONFIG_EXT2_FS_XATTR) evaluates to 'y'.
+ In this example, xattr.o, xattr_user.o and xattr_trusted.o are only
+ part of the composite object ext2.o if $(CONFIG_EXT2_FS_XATTR)
+ evaluates to 'y'.
Note: Of course, when you are building objects into the kernel,
the syntax above will also work. So, if you have CONFIG_EXT2_FS=y,
@@ -244,12 +245,12 @@ more details, with real examples.
may contain both a built-in.o and a lib.a file.
Example:
- #arch/i386/lib/Makefile
- lib-y := checksum.o delay.o
+ #arch/x86/lib/Makefile
+ lib-y := delay.o
- This will create a library lib.a based on checksum.o and delay.o.
- For kbuild to actually recognize that there is a lib.a being built,
- the directory shall be listed in libs-y.
+ This will create a library lib.a based on delay.o. For kbuild to
+ actually recognize that there is a lib.a being built, the directory
+ shall be listed in libs-y.
See also "6.3 List directories to visit when descending".
Use of lib-y is normally restricted to lib/ and arch/*/lib.
@@ -284,45 +285,42 @@ more details, with real examples.
--- 3.7 Compilation flags
ccflags-y, asflags-y and ldflags-y
- The three flags listed above applies only to the kbuild makefile
- where they are assigned. They are used for all the normal
- cc, as and ld invocation happenign during a recursive build.
+ The three flags listed above apply only to the kbuild makefile where
+ they are assigned (i.e., per-directory). They are used for all the
+ normal cc, as and ld invocation happening during a recursive build.
Note: Flags with the same behaviour were previously named:
- EXTRA_CFLAGS, EXTRA_AFLAGS and EXTRA_LDFLAGS.
- They are yet supported but their use are deprecated.
+ EXTRA_CFLAGS, EXTRA_AFLAGS and EXTRA_LDFLAGS. They are still
+ supported but their use is deprecated.
- ccflags-y specifies options for compiling C files with $(CC).
+ ccflags-y specifies options for compiling with $(CC).
Example:
- # drivers/sound/emu10k1/Makefile
- ccflags-y += -I$(obj)
- ccflags-$(DEBUG) += -DEMU10K1_DEBUG
-
+ # drivers/acpi/Makefile
+ ccflags-y := -Os
+ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT
This variable is necessary because the top Makefile owns the
variable $(KBUILD_CFLAGS) and uses it for compilation flags for the
entire tree.
- asflags-y is a similar string for per-directory options
- when compiling assembly language source.
+ asflags-y specifies options for assembling with $(AS).
Example:
- #arch/x86_64/kernel/Makefile
- asflags-y := -traditional
+ #arch/sparc/kernel/Makefile
+ asflags-y := -ansi
-
- ldflags-y is a string for per-directory options to $(LD).
+ ldflags-y specifies options for linking with $(LD).
Example:
- #arch/m68k/fpsp040/Makefile
- ldflags-y := -x
+ #arch/cris/boot/compressed/Makefile
+ ldflags-y += -T $(srctree)/$(src)/decompress_$(arch-y).lds
subdir-ccflags-y, subdir-asflags-y
- The two flags listed above are similar to ccflags-y and as-falgs-y.
- The difference is that the subdir- variants has effect for the kbuild
- file where tey are present and all subdirectories.
- Options specified using subdir-* are added to the commandline before
- the options specified using the non-subdir variants.
+ The two flags listed above are similar to ccflags-y and asflags-y.
+ The difference is that the subdir- variants affect the kbuild
+ file where they are present and all subdirectories. Options specified
+ using subdir-* are added to the commandline before the options
+ specified using the non-subdir variants.
Example:
subdir-ccflags-y := -Werror
@@ -340,18 +338,18 @@ more details, with real examples.
CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF
CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ \
-DGDTH_STATISTICS
- CFLAGS_seagate.o = -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
- These three lines specify compilation flags for aha152x.o,
- gdth.o, and seagate.o
+ These two lines specify compilation flags for aha152x.o and gdth.o.
$(AFLAGS_$@) is a similar feature for source files in assembly
languages.
Example:
# arch/arm/kernel/Makefile
- AFLAGS_head-armv.o := -DTEXTADDR=$(TEXTADDR) -traditional
- AFLAGS_head-armo.o := -DTEXTADDR=$(TEXTADDR) -traditional
+ AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
+ AFLAGS_crunch-bits.o := -Wa,-mcpu=ep9312
+ AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
+
--- 3.9 Dependency tracking
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 1808f1157f30..ff9f1a855ab5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1812,6 +1812,8 @@ and is between 256 and 4096 characters. It is defined in the file
nousb [USB] Disable the USB subsystem
+ nowatchdog [KNL] Disable the lockup detector.
+
nowb [ARM]
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
@@ -1970,6 +1972,8 @@ and is between 256 and 4096 characters. It is defined in the file
norom [X86] Do not assign address space to
expansion ROMs that do not already have
BIOS assigned address ranges.
+ nobar [X86] Do not assign address space to the
+ BARs that weren't assigned by the BIOS.
irqmask=0xMMMM [X86] Set a bit mask of IRQs allowed to be
assigned automatically to PCI devices. You can
make the kernel exclude IRQs of your ISA cards
diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt
index aa60d1f627e5..c91ccc0720fa 100644
--- a/Documentation/mutex-design.txt
+++ b/Documentation/mutex-design.txt
@@ -66,14 +66,14 @@ of advantages of mutexes:
c0377ccb <mutex_lock>:
c0377ccb: f0 ff 08 lock decl (%eax)
- c0377cce: 78 0e js c0377cde <.text.lock.mutex>
+ c0377cce: 78 0e js c0377cde <.text..lock.mutex>
c0377cd0: c3 ret
the unlocking fastpath is equally tight:
c0377cd1 <mutex_unlock>:
c0377cd1: f0 ff 00 lock incl (%eax)
- c0377cd4: 7e 0f jle c0377ce5 <.text.lock.mutex+0x7>
+ c0377cd4: 7e 0f jle c0377ce5 <.text..lock.mutex+0x7>
c0377cd6: c3 ret
- 'struct mutex' semantics are well-defined and are enforced if
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index 61f516b135b4..d0914781830e 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -49,6 +49,7 @@ Table of Contents
3.3 Configuring Bonding Manually with Ifenslave
3.3.1 Configuring Multiple Bonds Manually
3.4 Configuring Bonding Manually via Sysfs
+3.5 Overriding Configuration for Special Cases
4. Querying Bonding Configuration
4.1 Bonding Configuration
@@ -1318,8 +1319,87 @@ echo 2000 > /sys/class/net/bond1/bonding/arp_interval
echo +eth2 > /sys/class/net/bond1/bonding/slaves
echo +eth3 > /sys/class/net/bond1/bonding/slaves
-
-4. Querying Bonding Configuration
+3.5 Overriding Configuration for Special Cases
+----------------------------------------------
+When using the bonding driver, the physical port which transmits a frame is
+typically selected by the bonding driver, and is not relevant to the user or
+system administrator. The output port is simply selected using the policies of
+the selected bonding mode. On occasion however, it is helpful to direct certain
+classes of traffic to certain physical interfaces on output to implement
+slightly more complex policies. For example, to reach a web server over a
+bonded interface in which eth0 connects to a private network, while eth1
+connects via a public network, it may be desirous to bias the bond to send said
+traffic over eth0 first, using eth1 only as a fall back, while all other traffic
+can safely be sent over either interface. Such configurations may be achieved
+using the traffic control utilities inherent in linux.
+
+By default the bonding driver is multiqueue aware and 16 queues are created
+when the driver initializes (see Documentation/networking/multiqueue.txt
+for details). If more or less queues are desired the module parameter
+tx_queues can be used to change this value. There is no sysfs parameter
+available as the allocation is done at module init time.
+
+The output of the file /proc/net/bonding/bondX has changed so the output Queue
+ID is now printed for each slave:
+
+Bonding Mode: fault-tolerance (active-backup)
+Primary Slave: None
+Currently Active Slave: eth0
+MII Status: up
+MII Polling Interval (ms): 0
+Up Delay (ms): 0
+Down Delay (ms): 0
+
+Slave Interface: eth0
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cb
+Slave queue ID: 0
+
+Slave Interface: eth1
+MII Status: up
+Link Failure Count: 0
+Permanent HW addr: 00:1a:a0:12:8f:cc
+Slave queue ID: 2
+
+The queue_id for a slave can be set using the command:
+
+# echo "eth1:2" > /sys/class/net/bond0/bonding/queue_id
+
+Any interface that needs a queue_id set should set it with multiple calls
+like the one above until proper priorities are set for all interfaces. On
+distributions that allow configuration via initscripts, multiple 'queue_id'
+arguments can be added to BONDING_OPTS to set all needed slave queues.
+
+These queue id's can be used in conjunction with the tc utility to configure
+a multiqueue qdisc and filters to bias certain traffic to transmit on certain
+slave devices. For instance, say we wanted, in the above configuration to
+force all traffic bound to 192.168.1.100 to use eth1 in the bond as its output
+device. The following commands would accomplish this:
+
+# tc qdisc add dev bond0 handle 1 root multiq
+
+# tc filter add dev bond0 protocol ip parent 1: prio 1 u32 match ip dst \
+ 192.168.1.100 action skbedit queue_mapping 2
+
+These commands tell the kernel to attach a multiqueue queue discipline to the
+bond0 interface and filter traffic enqueued to it, such that packets with a dst
+ip of 192.168.1.100 have their output queue mapping value overwritten to 2.
+This value is then passed into the driver, causing the normal output path
+selection policy to be overridden, selecting instead qid 2, which maps to eth1.
+
+Note that qid values begin at 1. Qid 0 is reserved to initiate to the driver
+that normal output policy selection should take place. One benefit to simply
+leaving the qid for a slave to 0 is the multiqueue awareness in the bonding
+driver that is now present. This awareness allows tc filters to be placed on
+slave devices as well as bond devices and the bonding driver will simply act as
+a pass-through for selecting output queues on the slave device rather than
+output port selection.
+
+This feature first appeared in bonding driver version 3.7.0 and support for
+output slave selection was limited to round-robin and active-backup modes.
+
+4 Querying Bonding Configuration
=================================
4.1 Bonding Configuration
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index d0536b5a4e01..f350c69b2bb4 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -903,7 +903,7 @@ arp_ignore - INTEGER
arp_notify - BOOLEAN
Define mode for notification of address and device changes.
0 - (default): do nothing
- 1 - Generate gratuitous arp replies when device is brought up
+ 1 - Generate gratuitous arp requests when device is brought up
or hardware address changes.
arp_accept - BOOLEAN
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index 98f71a5cef00..2546aa4dc232 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -493,6 +493,32 @@ The user can also use poll() to check if a buffer is available:
pfd.events = POLLOUT;
retval = poll(&pfd, 1, timeout);
+-------------------------------------------------------------------------------
++ PACKET_TIMESTAMP
+-------------------------------------------------------------------------------
+
+The PACKET_TIMESTAMP setting determines the source of the timestamp in
+the packet meta information. If your NIC is capable of timestamping
+packets in hardware, you can request those hardware timestamps to used.
+Note: you may need to enable the generation of hardware timestamps with
+SIOCSHWTSTAMP.
+
+PACKET_TIMESTAMP accepts the same integer bit field as
+SO_TIMESTAMPING. However, only the SOF_TIMESTAMPING_SYS_HARDWARE
+and SOF_TIMESTAMPING_RAW_HARDWARE values are recognized by
+PACKET_TIMESTAMP. SOF_TIMESTAMPING_SYS_HARDWARE takes precedence over
+SOF_TIMESTAMPING_RAW_HARDWARE if both bits are set.
+
+ int req = 0;
+ req |= SOF_TIMESTAMPING_SYS_HARDWARE;
+ setsockopt(fd, SOL_PACKET, PACKET_TIMESTAMP, (void *) &req, sizeof(req))
+
+If PACKET_TIMESTAMP is not set, a software timestamp generated inside
+the networking stack is used (the behavior before this setting was added).
+
+See include/linux/net_tstamp.h and Documentation/networking/timestamping
+for more information on hardware timestamps.
+
--------------------------------------------------------------------------------
+ THANKS
--------------------------------------------------------------------------------
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
index 8df0b782c4d7..33ed8007a845 100644
--- a/Documentation/rt-mutex-design.txt
+++ b/Documentation/rt-mutex-design.txt
@@ -364,7 +364,7 @@ process this is rather easy to know what needs to be adjusted.
The functions implementing the task adjustments are rt_mutex_adjust_prio,
__rt_mutex_adjust_prio (same as the former, but expects the task pi_lock
-to already be taken), rt_mutex_get_prio, and rt_mutex_setprio.
+to already be taken), rt_mutex_getprio, and rt_mutex_setprio.
rt_mutex_getprio and rt_mutex_setprio are only used in __rt_mutex_adjust_prio.
diff --git a/Documentation/timers/Makefile b/Documentation/timers/Makefile
index c85625f4ab25..73f75f8a87dc 100644
--- a/Documentation/timers/Makefile
+++ b/Documentation/timers/Makefile
@@ -2,7 +2,7 @@
obj- := dummy.o
# List of programs to build
-hostprogs-y := hpet_example
+hostprogs-$(CONFIG_X86) := hpet_example
# Tell kbuild to always build the programs
always := $(hostprogs-y)
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 070f2576707e..1387a69ae3aa 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -176,5 +176,6 @@
175 -> Leadtek Winfast DTV1000S [107d:6655]
176 -> Beholder BeholdTV 505 RDS [0000:5051]
177 -> Hawell HW-404M7
-179 -> Beholder BeholdTV H7 [5ace:7190]
-180 -> Beholder BeholdTV A7 [5ace:7090]
+178 -> Beholder BeholdTV H7 [5ace:7190]
+179 -> Beholder BeholdTV A7 [5ace:7090]
+180 -> Avermedia M733A [1461:4155,1461:4255]
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 8f3f5d33327c..f13eb036c439 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -290,6 +290,7 @@ sonixb 0c45:602e Genius VideoCam Messenger
sonixj 0c45:6040 Speed NVC 350K
sonixj 0c45:607c Sonix sn9c102p Hv7131R
sonixj 0c45:60c0 Sangha Sn535
+sonixj 0c45:60ce USB-PC-Camera-168 (TALK-5067)
sonixj 0c45:60ec SN9C105+MO4000
sonixj 0c45:60fb Surfer NoName
sonixj 0c45:60fc LG-LIC300
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index 66e9358e2144..ccd951fa94ee 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -694,7 +694,7 @@ static void usage(void)
#endif
" -l|--list Show page details in ranges\n"
" -L|--list-each Show page details one by one\n"
-" -N|--no-summary Don't show summay info\n"
+" -N|--no-summary Don't show summary info\n"
" -X|--hwpoison hwpoison pages\n"
" -x|--unpoison unpoison pages\n"
" -h|--help Show this usage message\n"
diff --git a/MAINTAINERS b/MAINTAINERS
index 13608bd2e791..7385f45bc02a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -948,8 +948,9 @@ ARM/SHMOBILE ARM ARCHITECTURE
M: Paul Mundt <lethal@linux-sh.org>
M: Magnus Damm <magnus.damm@gmail.com>
L: linux-sh@vger.kernel.org
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git
W: http://oss.renesas.com
+Q: http://patchwork.kernel.org/project/linux-sh/list/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/genesis-2.6.git
S: Supported
F: arch/arm/mach-shmobile/
F: drivers/sh/
@@ -1731,7 +1732,7 @@ S: Maintained
F: sound/pci/cs5535audio/
CX18 VIDEO4LINUX DRIVER
-M: Andy Walls <awalls@radix.net>
+M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -2978,7 +2979,6 @@ F: drivers/net/ixgb/
F: drivers/net/ixgbe/
INTEL PRO/WIRELESS 2100 NETWORK CONNECTION SUPPORT
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
@@ -2988,7 +2988,6 @@ F: Documentation/networking/README.ipw2100
F: drivers/net/wireless/ipw2x00/ipw2100.*
INTEL PRO/WIRELESS 2915ABG NETWORK CONNECTION SUPPORT
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
@@ -3019,8 +3018,8 @@ F: drivers/net/wimax/i2400m/
F: include/linux/wimax/i2400m.h
INTEL WIRELESS WIFI LINK (iwlwifi)
-M: Zhu Yi <yi.zhu@intel.com>
M: Reinette Chatre <reinette.chatre@intel.com>
+M: Wey-Yi Guy <wey-yi.w.guy@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
W: http://intellinuxwireless.org
@@ -3030,7 +3029,6 @@ F: drivers/net/wireless/iwlwifi/
INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi)
M: Samuel Ortiz <samuel.ortiz@intel.com>
-M: Zhu Yi <yi.zhu@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
@@ -3049,6 +3047,12 @@ L: linux-mips@linux-mips.org
S: Maintained
F: drivers/serial/ioc3_serial.c
+IOQ LIBRARY
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/ioq.h
+F: lib/ioq.c
+
IP MASQUERADING
M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
S: Maintained
@@ -3165,7 +3169,7 @@ F: Documentation/hwmon/it87
F: drivers/hwmon/it87.c
IVTV VIDEO4LINUX DRIVER
-M: Andy Walls <awalls@radix.net>
+M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
L: linux-media@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6.git
@@ -3242,7 +3246,7 @@ L: autofs@linux.kernel.org
S: Maintained
F: fs/autofs4/
-KERNEL BUILD
+KERNEL BUILD + files below scripts/ (unless maintained elsewhere)
M: Michal Marek <mmarek@suse.cz>
T: git git://repo.or.cz/linux-kbuild.git for-next
T: git git://repo.or.cz/linux-kbuild.git for-linus
@@ -3251,6 +3255,9 @@ S: Maintained
F: Documentation/kbuild/
F: Makefile
F: scripts/Makefile.*
+F: scripts/basic/
+F: scripts/mk*
+F: scripts/package/
KERNEL JANITORS
L: kernel-janitors@vger.kernel.org
@@ -3500,9 +3507,8 @@ F: arch/powerpc/platforms/83xx/
LINUX FOR POWERPC PA SEMI PWRFICIENT
M: Olof Johansson <olof@lixom.net>
-W: http://www.pasemi.com/
L: linuxppc-dev@ozlabs.org
-S: Supported
+S: Maintained
F: arch/powerpc/platforms/pasemi/
F: drivers/*/*pasemi*
F: drivers/*/*/*pasemi*
@@ -5119,6 +5125,12 @@ F: drivers/serial/serial_lh7a40x.c
F: drivers/usb/gadget/lh7a40*
F: drivers/usb/host/ohci-lh7a40*
+SHM-SIGNAL LIBRARY
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/shm_signal.h
+F: lib/shm_signal.c
+
SIMPLE FIRMWARE INTERFACE (SFI)
M: Len Brown <lenb@kernel.org>
L: sfi-devel@simplefirmware.org
@@ -5570,6 +5582,12 @@ F: include/linux/tipc*.h
F: include/net/tipc/
F: net/tipc/
+TILE ARCHITECTURE
+M: Chris Metcalf <cmetcalf@tilera.com>
+W: http://www.tilera.com/scm/
+S: Supported
+F: arch/tile/
+
TLAN NETWORK DRIVER
M: Samuel Chessman <chessman@tux.org>
L: tlan-devel@lists.sourceforge.net (subscribers-only)
@@ -6090,6 +6108,19 @@ S: Maintained
F: Documentation/fb/uvesafb.txt
F: drivers/video/uvesafb.*
+VBUS
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+F: include/linux/vbus*
+F: drivers/vbus/*
+
+VBUS ETHERNET DRIVER
+M: Gregory Haskins <ghaskins@novell.com>
+S: Maintained
+W: http://developer.novell.com/wiki/index.php/AlacrityVM
+F: include/linux/venet.h
+F: drivers/net/vbus-enet.c
+
VFAT/FAT/MSDOS FILESYSTEM
M: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
S: Maintained
diff --git a/Makefile b/Makefile
index 6e39ec701cbf..a670e7eeff3b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 35
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
NAME = Sheep on Meth
# *DOCUMENTATION*
@@ -183,11 +183,14 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
# CROSS_COMPILE can be set on the command line
# make CROSS_COMPILE=ia64-linux-
# Alternatively CROSS_COMPILE can be set in the environment.
+# A third alternative is to store a setting in .config so that plain
+# "make" in the configured kernel build directory always uses that.
# Default value for CROSS_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
+CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
@@ -523,7 +526,7 @@ endif # $(dot-config)
# The all: target is the default when no target is given on the
# command line.
# This allow a user to issue only 'make' to build a kernel including modules
-# Defaults vmlinux but it is usually overridden in the arch makefile
+# Defaults to vmlinux, but the arch makefile usually adds further targets
all: vmlinux
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
@@ -576,9 +579,6 @@ KBUILD_CFLAGS += $(call cc-option,-Wno-pointer-sign,)
# disable invalid "can't wrap" optimizations for signed / pointers
KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow)
-# revert to pre-gcc-4.4 behaviour of .eh_frame
-KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
-
# conserve stack if available
KBUILD_CFLAGS += $(call cc-option,-fconserve-stack)
@@ -882,9 +882,6 @@ $(sort $(vmlinux-init) $(vmlinux-main)) $(vmlinux-lds): $(vmlinux-dirs) ;
PHONY += $(vmlinux-dirs)
$(vmlinux-dirs): prepare scripts
$(Q)$(MAKE) $(build)=$@
-ifdef CONFIG_MODULES
- $(Q)$(MAKE) $(modbuiltin)=$@
-endif
# Build the kernel release string
#
@@ -907,14 +904,19 @@ endif
# $(localver)
# localversion* (files without backups, containing '~')
# $(CONFIG_LOCALVERSION) (from kernel config setting)
-# $(localver-auto) (only if CONFIG_LOCALVERSION_AUTO is set)
-# ./scripts/setlocalversion (SCM tag, if one exists)
-# $(LOCALVERSION) (from make command line if provided)
+# $(LOCALVERSION) (from make command line, if provided)
+# $(localver-extra)
+# $(scm-identifier) (unique SCM tag, if one exists)
+# ./scripts/setlocalversion (only with CONFIG_LOCALVERSION_AUTO)
+# .scmversion (only with CONFIG_LOCALVERSION_AUTO)
+# + (only without CONFIG_LOCALVERSION_AUTO
+# and without LOCALVERSION= and
+# repository is at non-tagged commit)
#
-# Note how the final $(localver-auto) string is included *only* if the
-# kernel config option CONFIG_LOCALVERSION_AUTO is selected. Also, at the
-# moment, only git is supported but other SCMs can edit the script
-# scripts/setlocalversion and add the appropriate checks as needed.
+# For kernels without CONFIG_LOCALVERSION_AUTO compiled from an SCM that has
+# been revised beyond a tagged commit, `+' is appended to the version string
+# when not overridden by using "make LOCALVERSION=". This indicates that the
+# kernel is not a vanilla release version and has been modified.
pattern = ".*/localversion[^~]*"
string = $(shell cat /dev/null \
@@ -923,26 +925,32 @@ string = $(shell cat /dev/null \
localver = $(subst $(space),, $(string) \
$(patsubst "%",%,$(CONFIG_LOCALVERSION)))
-# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
-# and if the SCM is know a tag from the SCM is appended.
-# The appended tag is determined by the SCM used.
+# scripts/setlocalversion is called to create a unique identifier if the source
+# is managed by a known SCM and the repository has been revised since the last
+# tagged (release) commit. The format of the identifier is determined by the
+# SCM's implementation.
#
# .scmversion is used when generating rpm packages so we do not loose
# the version information from the SCM when we do the build of the kernel
# from the copied source
-ifdef CONFIG_LOCALVERSION_AUTO
-
ifeq ($(wildcard .scmversion),)
- _localver-auto = $(shell $(CONFIG_SHELL) \
+ scm-identifier = $(shell $(CONFIG_SHELL) \
$(srctree)/scripts/setlocalversion $(srctree))
else
- _localver-auto = $(shell cat .scmversion 2> /dev/null)
+ scm-identifier = $(shell cat .scmversion 2> /dev/null)
endif
- localver-auto = $(LOCALVERSION)$(_localver-auto)
+ifdef CONFIG_LOCALVERSION_AUTO
+ localver-extra = $(scm-identifier)
+else
+ ifneq ($(scm-identifier),)
+ ifeq ($(LOCALVERSION),)
+ localver-extra = +
+ endif
+ endif
endif
-localver-full = $(localver)$(localver-auto)
+localver-full = $(localver)$(LOCALVERSION)$(localver-extra)
# Store (new) KERNELRELASE string in include/config/kernel.release
kernelrelease = $(KERNELVERSION)$(localver-full)
@@ -1089,11 +1097,16 @@ all: modules
PHONY += modules
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux)
$(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
- $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.builtin) > $(objtree)/modules.builtin
@$(kecho) ' Building modules, stage 2.';
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild
+modules.builtin: $(vmlinux-dirs:%=%/modules.builtin)
+ $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin
+
+%/modules.builtin: include/config/auto.conf
+ $(Q)$(MAKE) $(modbuiltin)=$*
+
# Target to prepare building external modules
PHONY += modules_prepare
@@ -1104,7 +1117,7 @@ PHONY += modules_install
modules_install: _modinst_ _modinst_post
PHONY += _modinst_
-_modinst_:
+_modinst_: modules.builtin
@if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \
echo "Warning: you may need to install module-init-tools"; \
echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\
@@ -1247,7 +1260,9 @@ help:
@echo ' firmware_install- Install all firmware to INSTALL_FW_PATH'
@echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)'
@echo ' dir/ - Build all files in dir and below'
- @echo ' dir/file.[ois] - Build specified target only'
+ @echo ' dir/file.[oisS] - Build specified target only'
+ @echo ' dir/file.lst - Build specified mixed source/assembly target only'
+ @echo ' (requires a recent binutils and recent build (System.map))'
@echo ' dir/file.ko - Build module including final link'
@echo ' modules_prepare - Set up for building external modules'
@echo ' tags/TAGS - Generate tags file for editors'
diff --git a/arch/Kconfig b/arch/Kconfig
index acda512da2e2..4877a8c8ee16 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -151,4 +151,11 @@ config HAVE_MIXED_BREAKPOINTS_REGS
config HAVE_USER_RETURN_NOTIFIER
bool
+config HAVE_PERF_EVENTS_NMI
+ bool
+ help
+ System hardware can generate an NMI using the perf event
+ subsystem. Also has support for calculating CPU cycle events
+ to determine how many clock cycles in a given period.
+
source "kernel/gcov/Kconfig"
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index a52a27c1d9be..6f80665f477e 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -951,8 +951,6 @@ static int sa1111_resume(struct platform_device *dev)
if (!save)
return 0;
- spin_lock_irqsave(&sachip->lock, flags);
-
/*
* Ensure that the SA1111 is still here.
* FIXME: shouldn't do this here.
@@ -969,6 +967,13 @@ static int sa1111_resume(struct platform_device *dev)
* First of all, wake up the chip.
*/
sa1111_wake(sachip);
+
+ /*
+ * Only lock for write ops. Also, sa1111_wake must be called with
+ * released spinlock!
+ */
+ spin_lock_irqsave(&sachip->lock, flags);
+
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN0);
sa1111_writel(0, sachip->base + SA1111_INTC + SA1111_INTEN1);
diff --git a/arch/arm/configs/ap4evb_defconfig b/arch/arm/configs/ap4evb_defconfig
index e14229be7676..57cb4b0ea83e 100644
--- a/arch/arm/configs/ap4evb_defconfig
+++ b/arch/arm/configs/ap4evb_defconfig
@@ -1,12 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc7
-# Mon Feb 8 12:25:36 2010
+# Linux kernel version: 2.6.35-rc1
+# Mon May 31 14:29:17 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
@@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
@@ -94,10 +94,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
#
# Kernel Performance Events And Counters
#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
@@ -172,8 +176,11 @@ CONFIG_MMU=y
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
@@ -182,7 +189,6 @@ CONFIG_MMU=y
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -199,6 +205,7 @@ CONFIG_MMU=y
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_MSM is not set
@@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
-# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_BCMRING is not set
-# CONFIG_ARCH_U8500 is not set
+# CONFIG_PLAT_SPEAR is not set
#
# SH-Mobile System Type
@@ -242,6 +253,8 @@ CONFIG_MEMORY_SIZE=0x10000000
# Timer and clock configuration
#
CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_TIMER_TMU=y
+CONFIG_SH_CLK_CPG=y
#
# Processor Type
@@ -269,6 +282,8 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_HAS_TLS_REG=y
CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
# CONFIG_ARM_ERRATA_430973 is not set
# CONFIG_ARM_ERRATA_458693 is not set
# CONFIG_ARM_ERRATA_460075 is not set
@@ -322,7 +337,8 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=sh-sci.0,115200"
+CONFIG_CMDLINE="console=ttySC0,115200"
+# CONFIG_CMDLINE_FORCE is not set
# CONFIG_XIP_KERNEL is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y
@@ -398,6 +414,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
# CONFIG_MTD_OOPS is not set
#
@@ -449,13 +466,19 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_NAND=y
-# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC=y
# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
+# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_SH_FLCTL is not set
# CONFIG_MTD_ONENAND is not set
#
@@ -476,6 +499,7 @@ CONFIG_HAVE_IDE=y
#
# SCSI device support
#
+CONFIG_SCSI_MOD=y
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
@@ -506,17 +530,56 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# Input Device Drivers
#
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+CONFIG_KEYBOARD_SH_KEYSC=y
+# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+CONFIG_TOUCHSCREEN_TSC2007=y
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_TOUCHSCREEN_TPS6507X is not set
# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
# CONFIG_GAMEPORT is not set
#
@@ -541,8 +604,12 @@ CONFIG_DEVKMEM=y
CONFIG_SERIAL_SH_SCI=y
CONFIG_SERIAL_SH_SCI_NR_UARTS=8
CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_SH_SCI_DMA=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -551,13 +618,81 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_R3964 is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
+# CONFIG_RAMOOPS is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_SH_MOBILE=y
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
# CONFIG_SPI is not set
#
# PPS support
#
# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
+
+#
+# MODULbus GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
@@ -569,25 +704,170 @@ CONFIG_SSB_POSSIBLE=y
# Sonics Silicon Backplane
#
# CONFIG_SSB is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_CORE is not set
+CONFIG_MFD_SUPPORT=y
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_SH_MOBILE_SDHI=y
+# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TPS6507X is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TC35892 is not set
# CONFIG_MFD_TMIO is not set
+CONFIG_TMIO_MMC_DMA=y
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_ABX500_CORE is not set
# CONFIG_REGULATOR is not set
-# CONFIG_MEDIA_SUPPORT is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+# CONFIG_IR_IMON is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_IR_I2C=y
+# CONFIG_VIDEO_SH_VOU is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=y
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
#
# Graphics support
#
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+CONFIG_FB_DEFERRED_IO=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_SH_MIPI_DSI=y
+CONFIG_SH_LCD_MIPI_DSI=y
+CONFIG_FB_SH_MOBILE_LCDC=y
+# CONFIG_FB_TMIO is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
@@ -600,22 +880,237 @@ CONFIG_SSB_POSSIBLE=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+
+#
+# SoC Audio support for SuperH
+#
+CONFIG_SND_SOC_SH4_FSI=y
+CONFIG_SND_FSI_AK4642=y
+CONFIG_SND_FSI_DA7210=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_AK4642=y
+CONFIG_SND_SOC_DA7210=y
+# CONFIG_SOUND_PRIME is not set
# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_MMC is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+CONFIG_USB_R8A66597_HCD=y
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_USB_ULPI is not set
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_TMIO=y
+CONFIG_MMC_SH_MMCIF=y
# CONFIG_MEMSTICK is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
-# CONFIG_DMADEVICES is not set
-# CONFIG_AUXDISPLAY is not set
-# CONFIG_UIO is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
#
-# TI VLYNQ
+# RTC interfaces
#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+CONFIG_RTC_DRV_RS5C372=y
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+CONFIG_SH_DMAE=y
+# CONFIG_TIMB_DMA is not set
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
# CONFIG_STAGING is not set
#
@@ -677,7 +1172,46 @@ CONFIG_TMPFS=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
#
# Kernel hacking
@@ -733,6 +1267,7 @@ CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
@@ -760,12 +1295,13 @@ CONFIG_DEFAULT_SECURITY=""
#
# Library routines
#
+CONFIG_BITREVERSE=y
CONFIG_GENERIC_FIND_LAST_BIT=y
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_T10DIF is not set
# CONFIG_CRC_ITU_T is not set
-# CONFIG_CRC32 is not set
+CONFIG_CRC32=y
# CONFIG_CRC7 is not set
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
diff --git a/arch/arm/configs/g3evm_defconfig b/arch/arm/configs/g3evm_defconfig
index 3c19031961db..549e46064a29 100644
--- a/arch/arm/configs/g3evm_defconfig
+++ b/arch/arm/configs/g3evm_defconfig
@@ -1,12 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc7
-# Mon Feb 8 12:20:01 2010
+# Linux kernel version: 2.6.34
+# Thu May 20 12:21:19 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
@@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
@@ -94,10 +94,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
#
# Kernel Performance Events And Counters
#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
@@ -172,8 +176,11 @@ CONFIG_MMU=y
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
@@ -182,7 +189,6 @@ CONFIG_MMU=y
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -199,6 +205,7 @@ CONFIG_MMU=y
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_MSM is not set
@@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_S5PV210 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_BCMRING is not set
-# CONFIG_ARCH_U8500 is not set
+# CONFIG_PLAT_SPEAR is not set
#
# SH-Mobile System Type
@@ -242,6 +253,7 @@ CONFIG_MEMORY_SIZE=0x08000000
# Timer and clock configuration
#
CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_TIMER_TMU=y
#
# Processor Type
@@ -267,6 +279,8 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
# CONFIG_ARM_ERRATA_411920 is not set
CONFIG_COMMON_CLKDEV=y
@@ -317,7 +331,7 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySC1,115200 earlyprintk=sh-sci.1,115200"
+CONFIG_CMDLINE="console=ttySC1,115200"
# CONFIG_XIP_KERNEL is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y
@@ -447,10 +461,12 @@ CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_SH_FLCTL=y
# CONFIG_MTD_ONENAND is not set
#
@@ -471,6 +487,7 @@ CONFIG_HAVE_IDE=y
#
# SCSI device support
#
+CONFIG_SCSI_MOD=y
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
@@ -538,6 +555,7 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -553,6 +571,31 @@ CONFIG_UNIX98_PTYS=y
# PPS support
#
# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
@@ -568,12 +611,16 @@ CONFIG_SSB_POSSIBLE=y
#
# Multifunction device drivers
#
-# CONFIG_MFD_CORE is not set
+CONFIG_MFD_CORE=y
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_SH_MOBILE_SDHI=y
+# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
# CONFIG_REGULATOR is not set
# CONFIG_MEDIA_SUPPORT is not set
@@ -728,6 +775,7 @@ CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
@@ -772,3 +820,4 @@ CONFIG_DECOMPRESS_LZO=y
CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/arm/configs/g4evm_defconfig b/arch/arm/configs/g4evm_defconfig
index 8ee79a537134..3841bc609d41 100644
--- a/arch/arm/configs/g4evm_defconfig
+++ b/arch/arm/configs/g4evm_defconfig
@@ -1,12 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.33-rc7
-# Mon Feb 8 12:21:35 2010
+# Linux kernel version: 2.6.34
+# Thu May 20 12:37:38 2010
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -17,6 +20,7 @@ CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -31,6 +35,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
CONFIG_HAVE_KERNEL_LZO=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
@@ -54,11 +59,6 @@ CONFIG_RCU_FANOUT=32
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=16
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
# CONFIG_SYSFS_DEPRECATED_V2 is not set
# CONFIG_RELAY is not set
@@ -94,10 +94,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
#
# Kernel Performance Events And Counters
#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
@@ -172,8 +176,11 @@ CONFIG_MMU=y
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
@@ -182,7 +189,6 @@ CONFIG_MMU=y
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -199,6 +205,7 @@ CONFIG_MMU=y
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_MSM is not set
@@ -207,14 +214,18 @@ CONFIG_ARCH_SHMOBILE=y
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_S5PV210 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_BCMRING is not set
-# CONFIG_ARCH_U8500 is not set
+# CONFIG_PLAT_SPEAR is not set
#
# SH-Mobile System Type
@@ -242,6 +253,7 @@ CONFIG_MEMORY_SIZE=0x08000000
# Timer and clock configuration
#
CONFIG_SH_TIMER_CMT=y
+CONFIG_SH_TIMER_TMU=y
#
# Processor Type
@@ -269,6 +281,8 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_HAS_TLS_REG=y
CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
# CONFIG_ARM_ERRATA_430973 is not set
# CONFIG_ARM_ERRATA_458693 is not set
# CONFIG_ARM_ERRATA_460075 is not set
@@ -322,7 +336,7 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySC4,115200 earlyprintk=sh-sci.4,115200"
+CONFIG_CMDLINE="console=ttySC4,115200"
# CONFIG_XIP_KERNEL is not set
CONFIG_KEXEC=y
CONFIG_ATAGS_PROC=y
@@ -452,10 +466,12 @@ CONFIG_MTD_NAND=y
# CONFIG_MTD_NAND_VERIFY_WRITE is not set
# CONFIG_MTD_NAND_ECC_SMC is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
+CONFIG_MTD_NAND_SH_FLCTL=y
# CONFIG_MTD_ONENAND is not set
#
@@ -476,6 +492,7 @@ CONFIG_HAVE_IDE=y
#
# SCSI device support
#
+CONFIG_SCSI_MOD=y
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
@@ -543,6 +560,7 @@ CONFIG_SERIAL_SH_SCI_NR_UARTS=8
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -558,6 +576,31 @@ CONFIG_UNIX98_PTYS=y
# PPS support
#
# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+
+#
+# AC97 GPIO expanders:
+#
# CONFIG_W1 is not set
# CONFIG_POWER_SUPPLY is not set
# CONFIG_HWMON is not set
@@ -573,12 +616,16 @@ CONFIG_SSB_POSSIBLE=y
#
# Multifunction device drivers
#
-# CONFIG_MFD_CORE is not set
+CONFIG_MFD_CORE=y
# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+CONFIG_MFD_SH_MOBILE_SDHI=y
+# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
# CONFIG_MFD_TMIO is not set
# CONFIG_MFD_T7L66XB is not set
# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
# CONFIG_REGULATOR is not set
# CONFIG_MEDIA_SUPPORT is not set
@@ -733,6 +780,7 @@ CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
# CONFIG_KGDB is not set
diff --git a/arch/arm/configs/mx25_defconfig b/arch/arm/configs/mx25_defconfig
new file mode 100644
index 000000000000..17d40ee5519b
--- /dev/null
+++ b/arch/arm/configs/mx25_defconfig
@@ -0,0 +1,1756 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.34
+# Mon May 31 10:57:45 2010
+#
+CONFIG_ARM=y
+CONFIG_HAVE_PWM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_FIQ=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
+# CONFIG_ARCH_S5PC100 is not set
+# CONFIG_ARCH_S5PV210 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_PLAT_SPEAR is not set
+
+#
+# Freescale MXC Implementations
+#
+# CONFIG_ARCH_MX1 is not set
+# CONFIG_ARCH_MX2 is not set
+CONFIG_ARCH_MX25=y
+# CONFIG_ARCH_MX3 is not set
+# CONFIG_ARCH_MXC91231 is not set
+# CONFIG_ARCH_MX5 is not set
+
+#
+# MX25 platforms:
+#
+CONFIG_MACH_MX25_3DS=y
+CONFIG_MXC_IRQ_PRIOR=y
+CONFIG_MXC_PWM=y
+CONFIG_ARCH_MXC_IOMUX_V3=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="noinitrd console=ttymxc0,115200 root=/dev/mtdblock2 rw ip=off"
+# CONFIG_CMDLINE_FORCE is not set
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+# CONFIG_FPE_NWFPE is not set
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_VFP=y
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+CONFIG_PM_DEBUG=y
+# CONFIG_PM_ADVANCED_DEBUG is not set
+# CONFIG_PM_VERBOSE is not set
+CONFIG_CAN_PM_TRACE=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+# CONFIG_MTD_PHYSMAP_COMPAT is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_MXC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+# CONFIG_BLK_DEV is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+CONFIG_SMSC_PHY=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_AX88796 is not set
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
+# CONFIG_ETHOC is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
+CONFIG_DNET=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
+# CONFIG_KS8851_MLL is not set
+CONFIG_FEC=y
+# CONFIG_FEC2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+CONFIG_WLAN=y
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+CONFIG_KEYBOARD_IMX=y
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+# CONFIG_I2C_GPIO is not set
+CONFIG_I2C_IMX=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_IMX=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_IT8761E is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX7300 is not set
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+CONFIG_W1=y
+
+#
+# 1-wire Bus Masters
+#
+# CONFIG_W1_MASTER_DS2490 is not set
+# CONFIG_W1_MASTER_DS2482 is not set
+CONFIG_W1_MASTER_MXC=y
+# CONFIG_W1_MASTER_DS1WM is not set
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+CONFIG_W1_SLAVE_THERM=y
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2431 is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_UCB1400_CORE is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
+CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_DUMMY is not set
+# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
+# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
+# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
+# CONFIG_REGULATOR_BQ24022 is not set
+# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
+# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_TPS65023 is not set
+# CONFIG_REGULATOR_TPS6507X is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+# CONFIG_IR_IMON is not set
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+CONFIG_VIDEO_IR_I2C=y
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+CONFIG_SOC_CAMERA=y
+CONFIG_SOC_CAMERA_MT9M001=y
+CONFIG_SOC_CAMERA_MT9M111=y
+CONFIG_SOC_CAMERA_MT9T031=y
+# CONFIG_SOC_CAMERA_MT9T112 is not set
+CONFIG_SOC_CAMERA_MT9V022=y
+# CONFIG_SOC_CAMERA_RJ54N1 is not set
+CONFIG_SOC_CAMERA_TW9910=y
+# CONFIG_SOC_CAMERA_PLATFORM is not set
+CONFIG_SOC_CAMERA_OV772X=y
+# CONFIG_SOC_CAMERA_OV9640 is not set
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_HAVE_FB_IMX=y
+CONFIG_FB_IMX=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_LOGO is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_ARM is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_IMX_SOC=y
+# CONFIG_SND_MXC_SOC_WM1133_EV1 is not set
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MXC=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+CONFIG_USB_ULPI=y
+# CONFIG_NOP_USB_XCEIV is not set
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+# CONFIG_MMC_MXC is not set
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+CONFIG_LEDS_REGULATOR=y
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_MXC is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
+
+#
+# DMA Devices
+#
+# CONFIG_TIMB_DMA is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_V4_1 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_ARM_UNWIND=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_RATIONAL=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/arm/configs/mx3_defconfig b/arch/arm/configs/mx3_defconfig
index 8a06bc64fe59..c45f9eccda34 100644
--- a/arch/arm/configs/mx3_defconfig
+++ b/arch/arm/configs/mx3_defconfig
@@ -1,14 +1,16 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.32-rc5
-# Sun Nov 1 22:56:24 2009
+# Linux kernel version: 2.6.34
+# Tue May 25 14:54:32 2010
#
CONFIG_ARM=y
CONFIG_HAVE_PWM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
CONFIG_GENERIC_GPIO=y
CONFIG_GENERIC_TIME=y
+# CONFIG_ARCH_USES_GETTIMEOFFSET is not set
CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_HAVE_PROC_CPU=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_HAVE_LATENCYTOP_SUPPORT=y
@@ -19,7 +21,8 @@ CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_MTD_XIP=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_FIQ=y
CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
CONFIG_VECTORS_BASE=0xffff0000
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -34,6 +37,13 @@ CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
CONFIG_SYSVIPC_SYSCTL=y
@@ -47,6 +57,7 @@ CONFIG_SYSVIPC_SYSCTL=y
#
CONFIG_TREE_RCU=y
# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
# CONFIG_RCU_TRACE is not set
CONFIG_RCU_FANOUT=32
# CONFIG_RCU_FANOUT_EXACT is not set
@@ -54,11 +65,6 @@ CONFIG_RCU_FANOUT=32
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-CONFIG_USER_SCHED=y
-# CONFIG_CGROUP_SCHED is not set
# CONFIG_CGROUPS is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
@@ -85,10 +91,14 @@ CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_USE_VMALLOC=y
#
# Kernel Performance Events And Counters
#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_COMPAT_BRK=y
CONFIG_SLAB=y
@@ -124,14 +134,41 @@ CONFIG_LBDAF=y
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
CONFIG_FREEZER=y
#
@@ -142,8 +179,11 @@ CONFIG_MMU=y
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_VEXPRESS is not set
# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_BCMRING is not set
# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CNS3XXX is not set
# CONFIG_ARCH_GEMINI is not set
# CONFIG_ARCH_EBSA110 is not set
# CONFIG_ARCH_EP93XX is not set
@@ -152,7 +192,6 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_STMP3XXX is not set
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_IOP13XX is not set
# CONFIG_ARCH_IOP32X is not set
# CONFIG_ARCH_IOP33X is not set
@@ -160,6 +199,7 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
# CONFIG_ARCH_KIRKWOOD is not set
# CONFIG_ARCH_LOKI is not set
# CONFIG_ARCH_MV78XX0 is not set
@@ -168,20 +208,27 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_KS8695 is not set
# CONFIG_ARCH_NS9XXX is not set
# CONFIG_ARCH_W90X900 is not set
+# CONFIG_ARCH_NUC93X is not set
# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_SHMOBILE is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
# CONFIG_ARCH_S3C2410 is not set
# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5P6440 is not set
+# CONFIG_ARCH_S5P6442 is not set
# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_S5PV210 is not set
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_U8500 is not set
+# CONFIG_ARCH_NOMADIK is not set
# CONFIG_ARCH_DAVINCI is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_BCMRING is not set
+# CONFIG_PLAT_SPEAR is not set
#
# Freescale MXC Implementations
@@ -191,6 +238,7 @@ CONFIG_ARCH_MXC=y
# CONFIG_ARCH_MX25 is not set
CONFIG_ARCH_MX3=y
# CONFIG_ARCH_MXC91231 is not set
+# CONFIG_ARCH_MX5 is not set
CONFIG_ARCH_MX31=y
CONFIG_ARCH_MX35=y
@@ -203,6 +251,7 @@ CONFIG_MACH_PCM037=y
CONFIG_MACH_PCM037_EET=y
CONFIG_MACH_MX31LITE=y
CONFIG_MACH_MX31_3DS=y
+# CONFIG_MACH_MX31_3DS_MXC_NAND_USE_BBT is not set
CONFIG_MACH_MX31MOBOARD=y
CONFIG_MACH_MX31LILLY=y
CONFIG_MACH_QONG=y
@@ -212,8 +261,10 @@ CONFIG_MACH_MX35_3DS=y
CONFIG_MACH_KZM_ARM11_01=y
CONFIG_MXC_IRQ_PRIOR=y
CONFIG_MXC_PWM=y
+CONFIG_MXC_ULPI=y
CONFIG_ARCH_HAS_RNGA=y
CONFIG_ARCH_MXC_IOMUX_V3=y
+CONFIG_ARCH_MXC_AUDMUX_V2=y
#
# Processor Type
@@ -239,8 +290,11 @@ CONFIG_ARM_THUMB=y
# CONFIG_CPU_DCACHE_DISABLE is not set
# CONFIG_CPU_BPREDICT_DISABLE is not set
CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
CONFIG_CACHE_L2X0=y
CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_ARM_DMA_MEM_BUFFERABLE=y
+CONFIG_CPU_HAS_PMU=y
# CONFIG_ARM_ERRATA_411920 is not set
CONFIG_COMMON_CLKDEV=y
@@ -282,8 +336,6 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_PHYS_ADDR_T_64BIT is not set
CONFIG_ZONE_DMA_FLAG=0
CONFIG_VIRT_TO_BUS=y
-CONFIG_HAVE_MLOCK=y
-CONFIG_HAVE_MLOCKED_PAGE_BIT=y
# CONFIG_KSM is not set
CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
CONFIG_ALIGNMENT_TRAP=y
@@ -328,13 +380,16 @@ CONFIG_HAVE_AOUT=y
#
CONFIG_PM=y
CONFIG_PM_DEBUG=y
+# CONFIG_PM_ADVANCED_DEBUG is not set
# CONFIG_PM_VERBOSE is not set
CONFIG_CAN_PM_TRACE=y
CONFIG_PM_SLEEP=y
CONFIG_SUSPEND=y
+# CONFIG_PM_TEST_SUSPEND is not set
CONFIG_SUSPEND_FREEZER=y
# CONFIG_APM_EMULATION is not set
# CONFIG_PM_RUNTIME is not set
+CONFIG_PM_OPS=y
CONFIG_ARCH_SUSPEND_POSSIBLE=y
CONFIG_NET=y
@@ -342,7 +397,6 @@ CONFIG_NET=y
# Networking options
#
CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
@@ -379,6 +433,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
# CONFIG_BRIDGE is not set
# CONFIG_NET_DSA is not set
# CONFIG_VLAN_8021Q is not set
@@ -404,12 +459,27 @@ CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_AF_RXRPC is not set
-# CONFIG_WIRELESS is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+
+#
+# Some wireless drivers require a rate control algorithm
+#
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
#
+# CAIF Support
+#
+# CONFIG_CAIF is not set
+
+#
# Device Drivers
#
@@ -446,6 +516,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
# CONFIG_SSFDC is not set
+# CONFIG_SM_FTL is not set
# CONFIG_MTD_OOPS is not set
#
@@ -485,6 +556,9 @@ CONFIG_MTD_PHYSMAP=y
#
# Self-contained MTD device drivers
#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SST25L is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
@@ -497,14 +571,18 @@ CONFIG_MTD_PHYSMAP=y
# CONFIG_MTD_DOC2001 is not set
# CONFIG_MTD_DOC2001PLUS is not set
CONFIG_MTD_NAND=y
-# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+CONFIG_MTD_NAND_ECC=y
# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_SM_COMMON is not set
# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR=0xFF108018
# CONFIG_MTD_NAND_GPIO is not set
CONFIG_MTD_NAND_IDS=y
# CONFIG_MTD_NAND_DISKONCHIP is not set
# CONFIG_MTD_NAND_NANDSIM is not set
# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
CONFIG_MTD_NAND_MXC=y
# CONFIG_MTD_ONENAND is not set
@@ -528,24 +606,31 @@ CONFIG_MTD_UBI_BEB_RESERVE=1
# CONFIG_PARPORT is not set
# CONFIG_BLK_DEV is not set
CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
# CONFIG_ICS932S401 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
# CONFIG_C2PORT is not set
#
# EEPROM support
#
CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_AT25 is not set
# CONFIG_EEPROM_LEGACY is not set
# CONFIG_EEPROM_MAX6875 is not set
# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_IWMC3200TOP is not set
CONFIG_HAVE_IDE=y
# CONFIG_IDE is not set
#
# SCSI device support
#
+CONFIG_SCSI_MOD=y
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
# CONFIG_SCSI_DMA is not set
@@ -577,6 +662,7 @@ CONFIG_SMSC_PHY=y
# CONFIG_NATIONAL_PHY is not set
# CONFIG_STE10XP is not set
# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_MICREL_PHY is not set
# CONFIG_FIXED_PHY is not set
# CONFIG_MDIO_BITBANG is not set
CONFIG_NET_ETHERNET=y
@@ -584,6 +670,7 @@ CONFIG_MII=y
# CONFIG_AX88796 is not set
# CONFIG_SMC91X is not set
# CONFIG_DM9000 is not set
+# CONFIG_ENC28J60 is not set
# CONFIG_ETHOC is not set
# CONFIG_SMC911X is not set
CONFIG_SMSC911X=y
@@ -598,18 +685,29 @@ CONFIG_DNET=y
# CONFIG_B44 is not set
# CONFIG_CS89x0 is not set
# CONFIG_KS8842 is not set
+# CONFIG_KS8851 is not set
# CONFIG_KS8851_MLL is not set
CONFIG_FEC=y
# CONFIG_FEC2 is not set
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
CONFIG_WLAN=y
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
#
# Enable WiMAX (Networking options) to see the WiMAX drivers
#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_USB_IPHETH is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -622,12 +720,80 @@ CONFIG_WLAN=y
#
# Input device support
#
-# CONFIG_INPUT is not set
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_GPIO is not set
+# CONFIG_KEYBOARD_TCA6416 is not set
+# CONFIG_KEYBOARD_MATRIX is not set
+# CONFIG_KEYBOARD_LM8323 is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_IMX is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_ADS7846 is not set
+# CONFIG_TOUCHSCREEN_AD7877 is not set
+# CONFIG_TOUCHSCREEN_AD7879_I2C is not set
+# CONFIG_TOUCHSCREEN_AD7879_SPI is not set
+# CONFIG_TOUCHSCREEN_AD7879 is not set
+# CONFIG_TOUCHSCREEN_DYNAPRO is not set
+# CONFIG_TOUCHSCREEN_HAMPSHIRE is not set
+# CONFIG_TOUCHSCREEN_EETI is not set
+# CONFIG_TOUCHSCREEN_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
+# CONFIG_TOUCHSCREEN_MCS5000 is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_WM97XX is not set
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+CONFIG_TOUCHSCREEN_MC13783=y
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
+# CONFIG_TOUCHSCREEN_W90X900 is not set
+# CONFIG_INPUT_MISC is not set
#
# Hardware I/O ports
#
-# CONFIG_SERIO is not set
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
# CONFIG_GAMEPORT is not set
#
@@ -636,6 +802,7 @@ CONFIG_WLAN=y
# CONFIG_VT is not set
CONFIG_DEVKMEM=y
# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_N_GSM is not set
#
# Serial drivers
@@ -652,10 +819,14 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
#
# Non-8250 serial port support
#
+# CONFIG_SERIAL_MAX3100 is not set
CONFIG_SERIAL_IMX=y
CONFIG_SERIAL_IMX_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_ALTERA_JTAGUART is not set
+# CONFIG_SERIAL_ALTERA_UART is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
# CONFIG_LEGACY_PTYS is not set
@@ -682,29 +853,40 @@ CONFIG_I2C_HELPER_AUTO=y
CONFIG_I2C_IMX=y
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
#
# External I2C/SMBus adapter drivers
#
# CONFIG_I2C_PARPORT_LIGHT is not set
# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
#
# Other I2C/SMBus bus drivers
#
# CONFIG_I2C_PCA_PLATFORM is not set
# CONFIG_I2C_STUB is not set
-
-#
-# Miscellaneous I2C Chip support
-#
-# CONFIG_DS1682 is not set
-# CONFIG_SENSORS_TSL2550 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-# CONFIG_SPI is not set
+CONFIG_SPI=y
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_IMX=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
#
# PPS support
@@ -717,13 +899,17 @@ CONFIG_GPIOLIB=y
#
# Memory mapped GPIO expanders:
#
+# CONFIG_GPIO_IT8761E is not set
#
# I2C GPIO expanders:
#
+# CONFIG_GPIO_MAX7300 is not set
# CONFIG_GPIO_MAX732X is not set
# CONFIG_GPIO_PCA953X is not set
# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_WM8350 is not set
+# CONFIG_GPIO_ADP5588 is not set
#
# PCI GPIO expanders:
@@ -732,6 +918,9 @@ CONFIG_GPIOLIB=y
#
# SPI GPIO expanders:
#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
#
# AC97 GPIO expanders:
@@ -741,6 +930,7 @@ CONFIG_W1=y
#
# 1-wire Bus Masters
#
+# CONFIG_W1_MASTER_DS2490 is not set
# CONFIG_W1_MASTER_DS2482 is not set
CONFIG_W1_MASTER_MXC=y
# CONFIG_W1_MASTER_DS1WM is not set
@@ -755,7 +945,15 @@ CONFIG_W1_SLAVE_THERM=y
# CONFIG_W1_SLAVE_DS2433 is not set
# CONFIG_W1_SLAVE_DS2760 is not set
# CONFIG_W1_SLAVE_BQ27000 is not set
-# CONFIG_POWER_SUPPLY is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_WM8350_POWER is not set
+# CONFIG_TEST_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_DS2782 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_BATTERY_MAX17040 is not set
# CONFIG_HWMON is not set
# CONFIG_THERMAL is not set
# CONFIG_WATCHDOG is not set
@@ -769,11 +967,14 @@ CONFIG_SSB_POSSIBLE=y
#
# Multifunction device drivers
#
-# CONFIG_MFD_CORE is not set
+CONFIG_MFD_CORE=y
+# CONFIG_MFD_88PM860X is not set
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_ASIC3 is not set
# CONFIG_HTC_EGPIO is not set
# CONFIG_HTC_PASIC3 is not set
+# CONFIG_HTC_I2CPLD is not set
+# CONFIG_UCB1400_CORE is not set
# CONFIG_TPS65010 is not set
# CONFIG_TWL4030_CORE is not set
# CONFIG_MFD_TMIO is not set
@@ -781,23 +982,33 @@ CONFIG_SSB_POSSIBLE=y
# CONFIG_MFD_TC6387XB is not set
# CONFIG_MFD_TC6393XB is not set
# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
# CONFIG_MFD_WM8400 is not set
# CONFIG_MFD_WM831X is not set
CONFIG_MFD_WM8350=y
CONFIG_MFD_WM8350_CONFIG_MODE_0=y
CONFIG_MFD_WM8352_CONFIG_MODE_0=y
CONFIG_MFD_WM8350_I2C=y
+# CONFIG_MFD_WM8994 is not set
# CONFIG_MFD_PCF50633 is not set
+CONFIG_MFD_MC13783=y
# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_AB4500_CORE is not set
CONFIG_REGULATOR=y
# CONFIG_REGULATOR_DEBUG is not set
+# CONFIG_REGULATOR_DUMMY is not set
# CONFIG_REGULATOR_FIXED_VOLTAGE is not set
# CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
# CONFIG_REGULATOR_USERSPACE_CONSUMER is not set
# CONFIG_REGULATOR_BQ24022 is not set
# CONFIG_REGULATOR_MAX1586 is not set
+# CONFIG_REGULATOR_MAX8649 is not set
+# CONFIG_REGULATOR_MAX8660 is not set
CONFIG_REGULATOR_WM8350=y
# CONFIG_REGULATOR_LP3971 is not set
+# CONFIG_REGULATOR_MC13783 is not set
# CONFIG_REGULATOR_TPS65023 is not set
# CONFIG_REGULATOR_TPS6507X is not set
CONFIG_MEDIA_SUPPORT=y
@@ -815,6 +1026,15 @@ CONFIG_VIDEO_MEDIA=y
#
# Multimedia drivers
#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+CONFIG_RC_MAP=y
+CONFIG_IR_NEC_DECODER=y
+CONFIG_IR_RC5_DECODER=y
+CONFIG_IR_RC6_DECODER=y
+CONFIG_IR_JVC_DECODER=y
+CONFIG_IR_SONY_DECODER=y
+# CONFIG_IR_IMON is not set
# CONFIG_MEDIA_ATTACH is not set
CONFIG_MEDIA_TUNER=y
# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
@@ -834,20 +1054,75 @@ CONFIG_VIDEO_CAPTURE_DRIVERS=y
# CONFIG_VIDEO_ADV_DEBUG is not set
# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_VIVI is not set
+CONFIG_VIDEO_IR_I2C=y
# CONFIG_VIDEO_SAA5246A is not set
# CONFIG_VIDEO_SAA5249 is not set
CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_MT9M001=y
CONFIG_SOC_CAMERA_MT9M111=y
CONFIG_SOC_CAMERA_MT9T031=y
+# CONFIG_SOC_CAMERA_MT9T112 is not set
CONFIG_SOC_CAMERA_MT9V022=y
+# CONFIG_SOC_CAMERA_RJ54N1 is not set
CONFIG_SOC_CAMERA_TW9910=y
# CONFIG_SOC_CAMERA_PLATFORM is not set
CONFIG_SOC_CAMERA_OV772X=y
+# CONFIG_SOC_CAMERA_OV9640 is not set
CONFIG_MX3_VIDEO=y
CONFIG_VIDEO_MX3=y
# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GSPCA_BENQ is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_CPIA1 is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_OV534_9 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SN9C2028 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+# CONFIG_V4L_MEM2MEM_DRIVERS is not set
# CONFIG_RADIO_ADAPTERS is not set
# CONFIG_DAB is not set
@@ -879,6 +1154,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
# Frame buffer hardware drivers
#
# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_TMIO is not set
# CONFIG_FB_VIRTUAL is not set
# CONFIG_FB_METRONOME is not set
# CONFIG_FB_MB862XX is not set
@@ -891,8 +1167,193 @@ CONFIG_FB_MX3=y
#
# CONFIG_DISPLAY_SUPPORT is not set
# CONFIG_LOGO is not set
-# CONFIG_SOUND is not set
-# CONFIG_USB_SUPPORT is not set
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+# CONFIG_SND_RAWMIDI_SEQ is not set
+# CONFIG_SND_OPL3_LIB_SEQ is not set
+# CONFIG_SND_OPL4_LIB_SEQ is not set
+# CONFIG_SND_SBAWE_SEQ is not set
+# CONFIG_SND_EMU10K1_SEQ is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_UA101 is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_SOC_AC97_BUS=y
+CONFIG_SND_IMX_SOC=y
+CONFIG_SND_MXC_SOC_SSI=y
+CONFIG_SND_MXC_SOC_WM1133_EV1=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_WM8350=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_3M_PCT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CANDO is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_PRODIKEYS is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DRAGONRISE is not set
+# CONFIG_HID_EGALAX is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_TWINHAN is not set
+# CONFIG_HID_KENSINGTON is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MOSART is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_ORTEK is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_PICOLCD is not set
+# CONFIG_HID_QUANTA is not set
+# CONFIG_HID_ROCCAT_KONE is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_STANTUM is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_HID_GREENASIA is not set
+# CONFIG_HID_SMARTJOYPLUS is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_HID_THRUSTMASTER is not set
+# CONFIG_HID_ZEROPLUS is not set
+# CONFIG_HID_ZYDACRON is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MXC=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+# CONFIG_USB_MUSB_HDRC is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+CONFIG_USB_ULPI=y
+# CONFIG_NOP_USB_XCEIV is not set
CONFIG_MMC=y
# CONFIG_MMC_DEBUG is not set
# CONFIG_MMC_UNSAFE_RESUME is not set
@@ -909,21 +1370,119 @@ CONFIG_MMC_BLOCK_BOUNCE=y
# MMC/SD/SDIO Host Controller Drivers
#
# CONFIG_MMC_SDHCI is not set
-# CONFIG_MMC_AT91 is not set
-# CONFIG_MMC_ATMELMCI is not set
CONFIG_MMC_MXC=y
+# CONFIG_MMC_SPI is not set
# CONFIG_MEMSTICK is not set
-# CONFIG_NEW_LEDS is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_WM8350 is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_PWM is not set
+CONFIG_LEDS_REGULATOR=y
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+CONFIG_LEDS_TRIGGERS=y
+
+#
+# LED Triggers
+#
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+# CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
# CONFIG_ACCESSIBILITY is not set
CONFIG_RTC_LIB=y
-# CONFIG_RTC_CLASS is not set
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+# CONFIG_RTC_DRV_PCF2123 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_MXC is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+# CONFIG_RTC_DRV_WM8350 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_MC13783=y
CONFIG_DMADEVICES=y
+# CONFIG_DMADEVICES_DEBUG is not set
#
# DMA Devices
#
CONFIG_MX3_IPU=y
CONFIG_MX3_IPU_IRQS=4
+# CONFIG_TIMB_DMA is not set
CONFIG_DMA_ENGINE=y
#
@@ -934,10 +1493,6 @@ CONFIG_DMA_ENGINE=y
# CONFIG_DMATEST is not set
# CONFIG_AUXDISPLAY is not set
# CONFIG_UIO is not set
-
-#
-# TI VLYNQ
-#
# CONFIG_STAGING is not set
#
@@ -1018,6 +1573,7 @@ CONFIG_UBIFS_FS=y
CONFIG_UBIFS_FS_LZO=y
CONFIG_UBIFS_FS_ZLIB=y
# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_LOGFS is not set
# CONFIG_CRAMFS is not set
# CONFIG_SQUASHFS is not set
# CONFIG_VXFS_FS is not set
@@ -1044,6 +1600,7 @@ CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
@@ -1054,13 +1611,52 @@ CONFIG_RPCSEC_GSS_KRB5=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-# CONFIG_NLS is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
# CONFIG_DLM is not set
#
# Kernel hacking
#
-# CONFIG_PRINTK_TIME is not set
+CONFIG_PRINTK_TIME=y
# CONFIG_ENABLE_WARN_DEPRECATED is not set
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_FRAME_WARN=1024
@@ -1070,7 +1666,7 @@ CONFIG_FRAME_WARN=1024
# CONFIG_DEBUG_FS is not set
# CONFIG_HEADERS_CHECK is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_MEMORY_INIT is not set
# CONFIG_RCU_CPU_STALL_DETECTOR is not set
# CONFIG_LATENCYTOP is not set
@@ -1078,10 +1674,12 @@ CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_TRACING_SUPPORT=y
# CONFIG_FTRACE is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
# CONFIG_SAMPLES is not set
CONFIG_HAVE_ARCH_KGDB=y
CONFIG_ARM_UNWIND=y
# CONFIG_DEBUG_USER is not set
+# CONFIG_OC_ETM is not set
#
# Security options
@@ -1089,7 +1687,11 @@ CONFIG_ARM_UNWIND=y
# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITYFS is not set
-# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
CONFIG_CRYPTO=y
#
@@ -1210,3 +1812,4 @@ CONFIG_HAS_IOMEM=y
CONFIG_HAS_IOPORT=y
CONFIG_HAS_DMA=y
CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 6072eaa5e66a..e1f3efedbcf1 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -25,6 +25,7 @@
#include <asm/mach/time.h>
#include <mach/kirkwood.h>
#include <mach/bridge-regs.h>
+#include <plat/audio.h>
#include <plat/cache-feroceon-l2.h>
#include <plat/ehci-orion.h>
#include <plat/mvsdio.h>
@@ -864,6 +865,42 @@ struct sys_timer kirkwood_timer = {
.init = kirkwood_timer_init,
};
+/*****************************************************************************
+ * Audio
+ ****************************************************************************/
+static struct resource kirkwood_i2s_resources[] = {
+ [0] = {
+ .start = AUDIO_PHYS_BASE,
+ .end = AUDIO_PHYS_BASE + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_KIRKWOOD_I2S,
+ .end = IRQ_KIRKWOOD_I2S,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
+ .dram = &kirkwood_mbus_dram_info,
+ .burst = 128,
+};
+
+static struct platform_device kirkwood_i2s_device = {
+ .name = "kirkwood-i2s",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(kirkwood_i2s_resources),
+ .resource = kirkwood_i2s_resources,
+ .dev = {
+ .platform_data = &kirkwood_i2s_data,
+ },
+};
+
+void __init kirkwood_audio_init(void)
+{
+ kirkwood_clk_ctrl |= CGC_AUDIO;
+ platform_device_register(&kirkwood_i2s_device);
+}
/*****************************************************************************
* General
@@ -923,6 +960,7 @@ void __init kirkwood_init(void)
kirkwood_spi_plat_data.tclk = kirkwood_tclk;
kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
+ kirkwood_i2s_data.tclk = kirkwood_tclk;
/*
* Disable propagation of mbus errors to the CPU local bus,
diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
index 05e8a8a5692e..c9ab1cb3b39f 100644
--- a/arch/arm/mach-kirkwood/common.h
+++ b/arch/arm/mach-kirkwood/common.h
@@ -17,6 +17,7 @@ struct mv_sata_platform_data;
struct mvsdio_platform_data;
struct mtd_partition;
struct mtd_info;
+struct kirkwood_asoc_platform_data;
/*
* Basic Kirkwood init functions used early by machine-setup.
@@ -43,6 +44,7 @@ void kirkwood_uart0_init(void);
void kirkwood_uart1_init(void);
void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
void kirkwood_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
+void kirkwood_audio_init(void);
extern int kirkwood_tclk;
extern struct sys_timer kirkwood_timer;
diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
index a15cf0ee22bd..838151d0744b 100644
--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
@@ -96,6 +96,9 @@
#define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000)
+#define AUDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
+#define AUDIO_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
+
/*
* Supported devices and revisions.
*/
diff --git a/arch/arm/mach-kirkwood/openrd-setup.c b/arch/arm/mach-kirkwood/openrd-setup.c
index ad3f1ec33796..e36067ad3aca 100644
--- a/arch/arm/mach-kirkwood/openrd-setup.c
+++ b/arch/arm/mach-kirkwood/openrd-setup.c
@@ -15,6 +15,7 @@
#include <linux/mtd/partitions.h>
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
+#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[] __initdata = {
0
};
+static struct i2c_board_info i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("cs42l51", 0x4a),
+ },
+};
+
static void __init openrd_init(void)
{
/*
@@ -80,6 +87,12 @@ static void __init openrd_init(void)
kirkwood_sdio_init(&openrd_mvsdio_data);
kirkwood_i2c_init();
+
+ if (machine_is_openrd_client()) {
+ i2c_register_board_info(0, i2c_board_info,
+ ARRAY_SIZE(i2c_board_info));
+ kirkwood_audio_init();
+ }
}
static int __init openrd_pci_init(void)
diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c
index af5e85b91d02..6ca42fd5ce2a 100644
--- a/arch/arm/mach-msm/acpuclock-arm11.c
+++ b/arch/arm/mach-msm/acpuclock-arm11.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
diff --git a/arch/arm/mach-msm/clock.c b/arch/arm/mach-msm/clock.c
index 9cb1276ab749..c57210f4f06a 100644
--- a/arch/arm/mach-msm/clock.c
+++ b/arch/arm/mach-msm/clock.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index d029d1f5f9e2..02cae5e2951c 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -17,6 +17,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/completion.h>
#include <mach/dma.h>
#define MSM_DMOV_CHANNEL_COUNT 16
diff --git a/arch/arm/mach-mx2/Kconfig b/arch/arm/mach-mx2/Kconfig
index 742fd4e6dcb9..3f756f4ad050 100644
--- a/arch/arm/mach-mx2/Kconfig
+++ b/arch/arm/mach-mx2/Kconfig
@@ -59,6 +59,7 @@ endchoice
config MACH_CPUIMX27
bool "Eukrea CPUIMX27 module"
depends on MACH_MX27
+ select MXC_ULPI if USB_ULPI
help
Include support for Eukrea CPUIMX27 platform. This includes
specific configurations for the module and its peripherals.
@@ -67,9 +68,16 @@ config MACH_EUKREA_CPUIMX27_USESDHC2
bool "CPUIMX27 integrates SDHC2 module"
depends on MACH_CPUIMX27
help
- This adds support for the internal SDHC2 used on CPUIMX27 used
+ This adds support for the internal SDHC2 used on CPUIMX27
for wifi or eMMC.
+config MACH_EUKREA_CPUIMX27_USEUART4
+ bool "CPUIMX27 integrates UART4 module"
+ depends on MACH_CPUIMX27
+ help
+ This adds support for the internal UART4 used on CPUIMX27
+ for bluetooth.
+
choice
prompt "Baseboard"
depends on MACH_CPUIMX27
diff --git a/arch/arm/mach-mx2/devices.c b/arch/arm/mach-mx2/devices.c
index a0aeb8a4adc1..4df2e340652c 100644
--- a/arch/arm/mach-mx2/devices.c
+++ b/arch/arm/mach-mx2/devices.c
@@ -501,3 +501,21 @@ struct platform_device mx21_usbhc_device = {
};
#endif
+static struct resource imx_kpp_resources[] = {
+ {
+ .start = MX2x_KPP_BASE_ADDR,
+ .end = MX2x_KPP_BASE_ADDR + 0xf,
+ .flags = IORESOURCE_MEM
+ }, {
+ .start = MX2x_INT_KPP,
+ .end = MX2x_INT_KPP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device imx_kpp_device = {
+ .name = "imx-keypad",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(imx_kpp_resources),
+ .resource = imx_kpp_resources,
+};
diff --git a/arch/arm/mach-mx2/devices.h b/arch/arm/mach-mx2/devices.h
index 84ed51380174..cd4977990bd4 100644
--- a/arch/arm/mach-mx2/devices.h
+++ b/arch/arm/mach-mx2/devices.h
@@ -40,3 +40,4 @@ extern struct platform_device mxc_spi_device2;
extern struct platform_device mx21_usbhc_device;
extern struct platform_device imx_ssi_device0;
extern struct platform_device imx_ssi_device1;
+extern struct platform_device imx_kpp_device;
diff --git a/arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c b/arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c
index f3b169d5245f..80f626803401 100644
--- a/arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c
+++ b/arch/arm/mach-mx2/eukrea_mbimx27-baseboard.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Eric Benard - eric@eukrea.com
+ * Copyright (C) 2009-2010 Eric Benard - eric@eukrea.com
*
* Based on pcm970-baseboard.c which is :
* Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
@@ -24,6 +24,9 @@
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
+#include <linux/backlight.h>
+#include <video/platform_lcd.h>
+#include <linux/input/matrix_keypad.h>
#include <asm/mach/arch.h>
@@ -33,6 +36,9 @@
#include <mach/hardware.h>
#include <mach/mmc.h>
#include <mach/imx-uart.h>
+#include <mach/spi.h>
+#include <mach/ssi.h>
+#include <mach/audmux.h>
#include "devices.h"
@@ -48,10 +54,12 @@ static int eukrea_mbimx27_pins[] = {
PE10_PF_UART3_CTS,
PE11_PF_UART3_RTS,
/* UART4 */
+#if !defined(MACH_EUKREA_CPUIMX27_USEUART4)
PB26_AF_UART4_RTS,
PB28_AF_UART4_TXD,
PB29_AF_UART4_CTS,
PB31_AF_UART4_RXD,
+#endif
/* SDHC1*/
PE18_PF_SD1_D0,
PE19_PF_SD1_D1,
@@ -84,10 +92,28 @@ static int eukrea_mbimx27_pins[] = {
PA30_PF_CONTRAST,
PA31_PF_OE_ACD,
/* SPI1 */
- PD28_PF_CSPI1_SS0,
PD29_PF_CSPI1_SCLK,
PD30_PF_CSPI1_MISO,
PD31_PF_CSPI1_MOSI,
+ /* SSI4 */
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
+ PC16_PF_SSI4_FS,
+ PC17_PF_SSI4_RXD | GPIO_PUEN,
+ PC18_PF_SSI4_TXD | GPIO_PUEN,
+ PC19_PF_SSI4_CLK,
+#endif
+};
+
+static const uint32_t eukrea_mbimx27_keymap[] = {
+ KEY(0, 0, KEY_UP),
+ KEY(0, 1, KEY_DOWN),
+ KEY(1, 0, KEY_RIGHT),
+ KEY(1, 1, KEY_LEFT),
+};
+
+static struct matrix_keymap_data eukrea_mbimx27_keymap_data = {
+ .keymap = eukrea_mbimx27_keymap,
+ .keymap_size = ARRAY_SIZE(eukrea_mbimx27_keymap),
};
static struct gpio_led gpio_leds[] = {
@@ -103,12 +129,6 @@ static struct gpio_led gpio_leds[] = {
.active_low = 1,
.gpio = GPIO_PORTF | 19,
},
- {
- .name = "backlight",
- .default_trigger = "backlight",
- .active_low = 0,
- .gpio = GPIO_PORTE | 5,
- },
};
static struct gpio_led_platform_data gpio_led_info = {
@@ -127,7 +147,7 @@ static struct platform_device leds_gpio = {
static struct imx_fb_videomode eukrea_mbimx27_modes[] = {
{
.mode = {
- .name = "CMO-QGVA",
+ .name = "CMO-QVGA",
.refresh = 60,
.xres = 320,
.yres = 240,
@@ -141,6 +161,38 @@ static struct imx_fb_videomode eukrea_mbimx27_modes[] = {
},
.pcr = 0xFAD08B80,
.bpp = 16,
+ }, {
+ .mode = {
+ .name = "DVI-VGA",
+ .refresh = 60,
+ .xres = 640,
+ .yres = 480,
+ .pixclock = 32000,
+ .hsync_len = 1,
+ .left_margin = 35,
+ .right_margin = 0,
+ .vsync_len = 1,
+ .upper_margin = 7,
+ .lower_margin = 0,
+ },
+ .pcr = 0xFA208B80,
+ .bpp = 16,
+ }, {
+ .mode = {
+ .name = "DVI-SVGA",
+ .refresh = 60,
+ .xres = 800,
+ .yres = 600,
+ .pixclock = 25000,
+ .hsync_len = 1,
+ .left_margin = 35,
+ .right_margin = 0,
+ .vsync_len = 1,
+ .upper_margin = 7,
+ .lower_margin = 0,
+ },
+ .pcr = 0xFA208B80,
+ .bpp = 16,
},
};
@@ -153,6 +205,47 @@ static struct imx_fb_platform_data eukrea_mbimx27_fb_data = {
.dmacr = 0x00040060,
};
+static void eukrea_mbimx27_bl_set_intensity(int intensity)
+{
+ if (intensity)
+ gpio_direction_output(GPIO_PORTE | 5, 1);
+ else
+ gpio_direction_output(GPIO_PORTE | 5, 0);
+}
+
+static struct generic_bl_info eukrea_mbimx27_bl_info = {
+ .name = "eukrea_mbimx27-bl",
+ .max_intensity = 0xff,
+ .default_intensity = 0xff,
+ .set_bl_intensity = eukrea_mbimx27_bl_set_intensity,
+};
+
+static struct platform_device eukrea_mbimx27_bl_dev = {
+ .name = "generic-bl",
+ .id = 1,
+ .dev = {
+ .platform_data = &eukrea_mbimx27_bl_info,
+ },
+};
+
+static void eukrea_mbimx27_lcd_power_set(struct plat_lcd_data *pd,
+ unsigned int power)
+{
+ if (power)
+ gpio_direction_output(GPIO_PORTA | 25, 1);
+ else
+ gpio_direction_output(GPIO_PORTA | 25, 0);
+}
+
+static struct plat_lcd_data eukrea_mbimx27_lcd_power_data = {
+ .set_power = eukrea_mbimx27_lcd_power_set,
+};
+
+static struct platform_device eukrea_mbimx27_lcd_powerdev = {
+ .name = "platform-lcd",
+ .dev.platform_data = &eukrea_mbimx27_lcd_power_data,
+};
+
static struct imxuart_platform_data uart_pdata[] = {
{
.flags = IMXUART_HAVE_RTSCTS,
@@ -160,9 +253,12 @@ static struct imxuart_platform_data uart_pdata[] = {
{
.flags = IMXUART_HAVE_RTSCTS,
},
+ {
+ .flags = IMXUART_HAVE_RTSCTS,
+ },
};
-#if defined(CONFIG_TOUCHSCREEN_ADS7846)
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
|| defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
#define ADS7846_PENDOWN (GPIO_PORTD | 25)
@@ -173,7 +269,6 @@ static void ads7846_dev_init(void)
printk(KERN_ERR "can't get ads746 pen down GPIO\n");
return;
}
-
gpio_direction_input(ADS7846_PENDOWN);
}
@@ -186,7 +281,9 @@ static struct ads7846_platform_data ads7846_config __initdata = {
.get_pendown_state = ads7846_get_pendown_state,
.keep_vref_on = 1,
};
+#endif
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
[0] = {
.modalias = "ads7846",
@@ -199,6 +296,12 @@ static struct spi_board_info eukrea_mbimx27_spi_board_info[] __initdata = {
},
};
+static struct i2c_board_info eukrea_mbimx27_i2c_devices[] = {
+ {
+ I2C_BOARD_INFO("tlv320aic23", 0x1a),
+ },
+};
+
static int eukrea_mbimx27_spi_cs[] = {GPIO_PORTD | 28};
static struct spi_imx_master eukrea_mbimx27_spi_0_data = {
@@ -211,6 +314,14 @@ static struct platform_device *platform_devices[] __initdata = {
&leds_gpio,
};
+static struct imxmmc_platform_data sdhc_pdata = {
+ .dat3_card_detect = 1,
+};
+
+struct imx_ssi_platform_data eukrea_mbimx27_ssi_pdata = {
+ .flags = IMX_SSI_DMA | IMX_SSI_USE_I2S_SLAVE,
+};
+
/*
* system init for baseboard usage. Will be called by cpuimx27 init.
*
@@ -222,21 +333,51 @@ void __init eukrea_mbimx27_baseboard_init(void)
mxc_gpio_setup_multiple_pins(eukrea_mbimx27_pins,
ARRAY_SIZE(eukrea_mbimx27_pins), "MBIMX27");
+#if defined(CONFIG_SND_SOC_EUKREA_TLV320)
+ /* SSI unit master I2S codec connected to SSI_PINS_4*/
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_TFSDIR |
+ MXC_AUDMUX_V1_PCR_TCLKDIR |
+ MXC_AUDMUX_V1_PCR_RFSDIR |
+ MXC_AUDMUX_V1_PCR_RCLKDIR |
+ MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+ MXC_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4)
+ );
+ mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4,
+ MXC_AUDMUX_V1_PCR_SYN |
+ MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0)
+ );
+#endif
+
mxc_register_device(&mxc_uart_device1, &uart_pdata[0]);
mxc_register_device(&mxc_uart_device2, &uart_pdata[1]);
+#if !defined(MACH_EUKREA_CPUIMX27_USEUART4)
+ mxc_register_device(&mxc_uart_device3, &uart_pdata[2]);
+#endif
mxc_register_device(&mxc_fb_device, &eukrea_mbimx27_fb_data);
- mxc_register_device(&mxc_sdhc_device0, NULL);
+ mxc_register_device(&mxc_sdhc_device0, &sdhc_pdata);
+
+ i2c_register_board_info(0, eukrea_mbimx27_i2c_devices,
+ ARRAY_SIZE(eukrea_mbimx27_i2c_devices));
+
+ mxc_register_device(&imx_ssi_device0, &eukrea_mbimx27_ssi_pdata);
-#if defined(CONFIG_TOUCHSCREEN_ADS7846)
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) \
|| defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- /* SPI and ADS7846 Touchscreen controler init */
- mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
+ /* ADS7846 Touchscreen controller init */
mxc_gpio_mode(GPIO_PORTD | 25 | GPIO_GPIO | GPIO_IN);
+ ads7846_dev_init();
+#endif
+
+#if defined(CONFIG_SPI_IMX) || defined(CONFIG_SPI_IMX_MODULE)
+ /* SPI_CS0 init */
+ mxc_gpio_mode(GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT);
mxc_register_device(&mxc_spi_device0, &eukrea_mbimx27_spi_0_data);
spi_register_board_info(eukrea_mbimx27_spi_board_info,
ARRAY_SIZE(eukrea_mbimx27_spi_board_info));
- ads7846_dev_init();
#endif
/* Leds configuration */
@@ -244,6 +385,14 @@ void __init eukrea_mbimx27_baseboard_init(void)
mxc_gpio_mode(GPIO_PORTF | 19 | GPIO_GPIO | GPIO_OUT);
/* Backlight */
mxc_gpio_mode(GPIO_PORTE | 5 | GPIO_GPIO | GPIO_OUT);
+ gpio_request(GPIO_PORTE | 5, "backlight");
+ platform_device_register(&eukrea_mbimx27_bl_dev);
+ /* LCD Reset */
+ mxc_gpio_mode(GPIO_PORTA | 25 | GPIO_GPIO | GPIO_OUT);
+ gpio_request(GPIO_PORTA | 25, "lcd_enable");
+ platform_device_register(&eukrea_mbimx27_lcd_powerdev);
+
+ mxc_register_device(&imx_kpp_device, &eukrea_mbimx27_keymap_data);
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
}
diff --git a/arch/arm/mach-mx2/mach-cpuimx27.c b/arch/arm/mach-mx2/mach-cpuimx27.c
index 1f616dcaabc9..dc2dca3ff9b7 100644
--- a/arch/arm/mach-mx2/mach-cpuimx27.c
+++ b/arch/arm/mach-mx2/mach-cpuimx27.c
@@ -26,6 +26,9 @@
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/serial_8250.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/ulpi.h>
+#include <linux/fsl_devices.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -39,6 +42,8 @@
#include <mach/iomux-mx27.h>
#include <mach/imx-uart.h>
#include <mach/mxc_nand.h>
+#include <mach/mxc_ehci.h>
+#include <mach/ulpi.h>
#include "devices.h"
@@ -49,10 +54,12 @@ static int eukrea_cpuimx27_pins[] = {
PE14_PF_UART1_CTS,
PE15_PF_UART1_RTS,
/* UART4 */
+#if defined(MACH_EUKREA_CPUIMX27_USEUART4)
PB26_AF_UART4_RTS,
PB28_AF_UART4_TXD,
PB29_AF_UART4_CTS,
PB31_AF_UART4_RXD,
+#endif
/* FEC */
PD0_AIN_FEC_TXD0,
PD1_AIN_FEC_TXD1,
@@ -76,19 +83,47 @@ static int eukrea_cpuimx27_pins[] = {
PD17_PF_I2C_DATA,
PD18_PF_I2C_CLK,
/* SDHC2 */
+#if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
PB4_PF_SD2_D0,
PB5_PF_SD2_D1,
PB6_PF_SD2_D2,
PB7_PF_SD2_D3,
PB8_PF_SD2_CMD,
PB9_PF_SD2_CLK,
+#endif
#if defined(CONFIG_SERIAL_8250) || defined(CONFIG_SERIAL_8250_MODULE)
/* Quad UART's IRQ */
- GPIO_PORTD | 22 | GPIO_GPIO | GPIO_IN,
- GPIO_PORTD | 23 | GPIO_GPIO | GPIO_IN,
- GPIO_PORTD | 27 | GPIO_GPIO | GPIO_IN,
- GPIO_PORTD | 30 | GPIO_GPIO | GPIO_IN,
+ GPIO_PORTB | 22 | GPIO_GPIO | GPIO_IN,
+ GPIO_PORTB | 23 | GPIO_GPIO | GPIO_IN,
+ GPIO_PORTB | 27 | GPIO_GPIO | GPIO_IN,
+ GPIO_PORTB | 30 | GPIO_GPIO | GPIO_IN,
#endif
+ /* OTG */
+ PC7_PF_USBOTG_DATA5,
+ PC8_PF_USBOTG_DATA6,
+ PC9_PF_USBOTG_DATA0,
+ PC10_PF_USBOTG_DATA2,
+ PC11_PF_USBOTG_DATA1,
+ PC12_PF_USBOTG_DATA4,
+ PC13_PF_USBOTG_DATA3,
+ PE0_PF_USBOTG_NXT,
+ PE1_PF_USBOTG_STP,
+ PE2_PF_USBOTG_DIR,
+ PE24_PF_USBOTG_CLK,
+ PE25_PF_USBOTG_DATA7,
+ /* USBH2 */
+ PA0_PF_USBH2_CLK,
+ PA1_PF_USBH2_DIR,
+ PA2_PF_USBH2_DATA7,
+ PA3_PF_USBH2_NXT,
+ PA4_PF_USBH2_STP,
+ PD19_AF_USBH2_DATA4,
+ PD20_AF_USBH2_DATA3,
+ PD21_AF_USBH2_DATA6,
+ PD22_AF_USBH2_DATA0,
+ PD23_AF_USBH2_DATA2,
+ PD24_AF_USBH2_DATA1,
+ PD26_AF_USBH2_DATA5,
};
static struct physmap_flash_data eukrea_cpuimx27_flash_data = {
@@ -127,6 +162,8 @@ static struct mxc_nand_platform_data eukrea_cpuimx27_nand_board_info = {
static struct platform_device *platform_devices[] __initdata = {
&eukrea_cpuimx27_nor_mtd_device,
&mxc_fec_device,
+ &mxc_wdt,
+ &mxc_w1_master_device,
};
static struct imxi2c_platform_data eukrea_cpuimx27_i2c_1_data = {
@@ -182,6 +219,36 @@ static struct platform_device serial_device = {
};
#endif
+static struct mxc_usbh_platform_data otg_pdata = {
+ .portsc = MXC_EHCI_MODE_ULPI,
+ .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+
+static struct mxc_usbh_platform_data usbh2_pdata = {
+ .portsc = MXC_EHCI_MODE_ULPI,
+ .flags = MXC_EHCI_INTERFACE_DIFF_UNI,
+};
+
+static struct fsl_usb2_platform_data otg_device_pdata = {
+ .operating_mode = FSL_USB2_DR_DEVICE,
+ .phy_mode = FSL_USB2_PHY_ULPI,
+};
+
+static int otg_mode_host;
+
+static int __init eukrea_cpuimx27_otg_mode(char *options)
+{
+ if (!strcmp(options, "host"))
+ otg_mode_host = 1;
+ else if (!strcmp(options, "device"))
+ otg_mode_host = 0;
+ else
+ pr_info("otg_mode neither \"host\" nor \"device\". "
+ "Defaulting to device\n");
+ return 0;
+}
+__setup("otg_mode=", eukrea_cpuimx27_otg_mode);
+
static void __init eukrea_cpuimx27_init(void)
{
mxc_gpio_setup_multiple_pins(eukrea_cpuimx27_pins,
@@ -202,6 +269,8 @@ static void __init eukrea_cpuimx27_init(void)
#if defined(CONFIG_MACH_EUKREA_CPUIMX27_USESDHC2)
/* SDHC2 can be used for Wifi */
mxc_register_device(&mxc_sdhc_device1, NULL);
+#endif
+#if defined(MACH_EUKREA_CPUIMX27_USEUART4)
/* in which case UART4 is also used for Bluetooth */
mxc_register_device(&mxc_uart_device3, &uart_pdata[1]);
#endif
@@ -210,6 +279,22 @@ static void __init eukrea_cpuimx27_init(void)
platform_device_register(&serial_device);
#endif
+#if defined(CONFIG_USB_ULPI)
+ if (otg_mode_host) {
+ otg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+ USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+ mxc_register_device(&mxc_otg_host, &otg_pdata);
+ }
+
+ usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+ USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+ mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+#endif
+ if (!otg_mode_host)
+ mxc_register_device(&mxc_otg_udc_device, &otg_device_pdata);
+
#ifdef CONFIG_MACH_EUKREA_MBIMX27_BASEBOARD
eukrea_mbimx27_baseboard_init();
#endif
diff --git a/arch/arm/mach-mx2/mach-pca100.c b/arch/arm/mach-mx2/mach-pca100.c
index a87422ed4ff5..7651d0ef4666 100644
--- a/arch/arm/mach-mx2/mach-pca100.c
+++ b/arch/arm/mach-mx2/mach-pca100.c
@@ -253,6 +253,7 @@ static struct imxmmc_platform_data sdhc_pdata = {
.exit = pca100_sdhc2_exit,
};
+#if defined(CONFIG_USB_ULPI)
static int otg_phy_init(struct platform_device *pdev)
{
gpio_set_value(OTG_PHY_CS_GPIO, 0);
@@ -276,6 +277,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
.portsc = MXC_EHCI_MODE_ULPI,
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+#endif
static struct fsl_usb2_platform_data otg_device_pdata = {
.operating_mode = FSL_USB2_DR_DEVICE,
diff --git a/arch/arm/mach-mx25/clock.c b/arch/arm/mach-mx25/clock.c
index 155014993b13..f44d65765b9a 100644
--- a/arch/arm/mach-mx25/clock.c
+++ b/arch/arm/mach-mx25/clock.c
@@ -217,7 +217,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
_REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)
_REGISTER_CLOCK("mxc_pwm.3", NULL, pwm4_clk)
- _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
+ _REGISTER_CLOCK("imx-keypad", NULL, kpp_clk)
_REGISTER_CLOCK("mx25-adc", NULL, tsc_clk)
_REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
_REGISTER_CLOCK("imx-i2c.1", NULL, i2c_clk)
diff --git a/arch/arm/mach-mx25/devices.c b/arch/arm/mach-mx25/devices.c
index 3a405fa400eb..fd331d04ea0d 100644
--- a/arch/arm/mach-mx25/devices.c
+++ b/arch/arm/mach-mx25/devices.c
@@ -515,3 +515,23 @@ struct platform_device mxc_wdt = {
.num_resources = ARRAY_SIZE(mxc_wdt_resources),
.resource = mxc_wdt_resources,
};
+
+static struct resource mx25_kpp_resources[] = {
+ {
+ .start = MX25_KPP_BASE_ADDR,
+ .end = MX25_KPP_BASE_ADDR + 0xf,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MX25_INT_KPP,
+ .end = MX25_INT_KPP,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mx25_kpp_device = {
+ .name = "imx-keypad",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(mx25_kpp_resources),
+ .resource = mx25_kpp_resources,
+};
diff --git a/arch/arm/mach-mx25/devices.h b/arch/arm/mach-mx25/devices.h
index cee12c0a0be6..8247fd451118 100644
--- a/arch/arm/mach-mx25/devices.h
+++ b/arch/arm/mach-mx25/devices.h
@@ -22,3 +22,4 @@ extern struct platform_device mxc_nand_device;
extern struct platform_device mx25_rtc_device;
extern struct platform_device mx25_fb_device;
extern struct platform_device mxc_wdt;
+extern struct platform_device mx25_kpp_device;
diff --git a/arch/arm/mach-mx25/mach-mx25pdk.c b/arch/arm/mach-mx25/mach-mx25pdk.c
index 83d74109e7d8..4a57f68860cb 100644
--- a/arch/arm/mach-mx25/mach-mx25pdk.c
+++ b/arch/arm/mach-mx25/mach-mx25pdk.c
@@ -24,6 +24,7 @@
#include <linux/gpio.h>
#include <linux/fec.h>
#include <linux/platform_device.h>
+#include <linux/input/matrix_keypad.h>
#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -80,6 +81,16 @@ static struct pad_desc mx25pdk_pads[] = {
MX25_PAD_LSCLK__LSCLK,
MX25_PAD_OE_ACD__OE_ACD,
MX25_PAD_CONTRAST__CONTRAST,
+
+ /* Keypad */
+ MX25_PAD_KPP_ROW0__KPP_ROW0,
+ MX25_PAD_KPP_ROW1__KPP_ROW1,
+ MX25_PAD_KPP_ROW2__KPP_ROW2,
+ MX25_PAD_KPP_ROW3__KPP_ROW3,
+ MX25_PAD_KPP_COL0__KPP_COL0,
+ MX25_PAD_KPP_COL1__KPP_COL1,
+ MX25_PAD_KPP_COL2__KPP_COL2,
+ MX25_PAD_KPP_COL3__KPP_COL3,
};
static struct fec_platform_data mx25_fec_pdata = {
@@ -137,6 +148,30 @@ static struct imx_fb_platform_data mx25pdk_fb_pdata = {
.dmacr = 0x00020010,
};
+static const uint32_t mx25pdk_keymap[] = {
+ KEY(0, 0, KEY_UP),
+ KEY(0, 1, KEY_DOWN),
+ KEY(0, 2, KEY_VOLUMEDOWN),
+ KEY(0, 3, KEY_HOME),
+ KEY(1, 0, KEY_RIGHT),
+ KEY(1, 1, KEY_LEFT),
+ KEY(1, 2, KEY_ENTER),
+ KEY(1, 3, KEY_VOLUMEUP),
+ KEY(2, 0, KEY_F6),
+ KEY(2, 1, KEY_F8),
+ KEY(2, 2, KEY_F9),
+ KEY(2, 3, KEY_F10),
+ KEY(3, 0, KEY_F1),
+ KEY(3, 1, KEY_F2),
+ KEY(3, 2, KEY_F3),
+ KEY(3, 3, KEY_POWER),
+};
+
+static struct matrix_keymap_data mx25pdk_keymap_data = {
+ .keymap = mx25pdk_keymap,
+ .keymap_size = ARRAY_SIZE(mx25pdk_keymap),
+};
+
static void __init mx25pdk_init(void)
{
mxc_iomux_v3_setup_multiple_pads(mx25pdk_pads,
@@ -150,6 +185,7 @@ static void __init mx25pdk_init(void)
mx25pdk_fec_reset();
mxc_register_device(&mx25_fec_device, &mx25_fec_pdata);
+ mxc_register_device(&mx25_kpp_device, &mx25pdk_keymap_data);
}
static void __init mx25pdk_timer_init(void)
diff --git a/arch/arm/mach-mx3/mach-mx31lilly.c b/arch/arm/mach-mx3/mach-mx31lilly.c
index d3d5877c750e..4b330844ccc5 100644
--- a/arch/arm/mach-mx3/mach-mx31lilly.c
+++ b/arch/arm/mach-mx3/mach-mx31lilly.c
@@ -115,6 +115,8 @@ static struct platform_device physmap_flash_device = {
/* USB */
+#if defined(CONFIG_USB_ULPI)
+
#define USB_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | \
PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU)
@@ -244,10 +246,20 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
.flags = MXC_EHCI_POWER_PINS_ENABLED,
};
-static struct platform_device *devices[] __initdata = {
- &smsc91x_device,
- &physmap_flash_device,
-};
+static void lilly1131_usb_init(void)
+{
+ usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+ USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+ usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
+ USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
+
+ mxc_register_device(&mxc_usbh1, &usbh1_pdata);
+ mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+}
+
+#else
+static inline void lilly1131_usb_init(void) {}
+#endif /* CONFIG_USB_ULPI */
/* SPI */
@@ -277,6 +289,12 @@ static struct spi_board_info mc13783_dev __initdata = {
.bus_num = 1,
.chip_select = 0,
.platform_data = &mc13783_pdata,
+ .irq = IOMUX_TO_IRQ(MX31_PIN_GPIO1_3),
+};
+
+static struct platform_device *devices[] __initdata = {
+ &smsc91x_device,
+ &physmap_flash_device,
};
static int mx31lilly_baseboard;
@@ -321,13 +339,7 @@ static void __init mx31lilly_board_init(void)
platform_add_devices(devices, ARRAY_SIZE(devices));
/* USB */
- usbotg_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
- usbh2_pdata.otg = otg_ulpi_create(&mxc_ulpi_access_ops,
- USB_OTG_DRV_VBUS | USB_OTG_DRV_VBUS_EXT);
-
- mxc_register_device(&mxc_usbh1, &usbh1_pdata);
- mxc_register_device(&mxc_usbh2, &usbh2_pdata);
+ lilly1131_usb_init();
}
static void __init mx31lilly_timer_init(void)
diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-mx3/mach-pcm037.c
index cce410662383..bb6c056854e9 100644
--- a/arch/arm/mach-mx3/mach-pcm037.c
+++ b/arch/arm/mach-mx3/mach-pcm037.c
@@ -545,6 +545,7 @@ static struct platform_device pcm970_sja1000 = {
.num_resources = ARRAY_SIZE(pcm970_sja1000_resources),
};
+#if defined(CONFIG_USB_ULPI)
static struct mxc_usbh_platform_data otg_pdata = {
.portsc = MXC_EHCI_MODE_ULPI,
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
@@ -554,6 +555,7 @@ static struct mxc_usbh_platform_data usbh2_pdata = {
.portsc = MXC_EHCI_MODE_ULPI,
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
};
+#endif
static struct fsl_usb2_platform_data otg_device_pdata = {
.operating_mode = FSL_USB2_DR_DEVICE,
@@ -581,7 +583,6 @@ __setup("otg_mode=", pcm037_otg_mode);
static void __init mxc_board_init(void)
{
int ret;
- u32 tmp;
mxc_iomux_set_gpr(MUX_PGP_UH2, 1);
diff --git a/arch/arm/mach-mx3/mach-pcm043.c b/arch/arm/mach-mx3/mach-pcm043.c
index 78d9185a9d4b..8071b7281c4b 100644
--- a/arch/arm/mach-mx3/mach-pcm043.c
+++ b/arch/arm/mach-mx3/mach-pcm043.c
@@ -309,6 +309,7 @@ static struct mxc_nand_platform_data pcm037_nand_board_info = {
.hw_ecc = 1,
};
+#if defined(CONFIG_USB_ULPI)
static struct mxc_usbh_platform_data otg_pdata = {
.portsc = MXC_EHCI_MODE_UTMI,
.flags = MXC_EHCI_INTERFACE_DIFF_UNI,
@@ -319,6 +320,7 @@ static struct mxc_usbh_platform_data usbh1_pdata = {
.flags = MXC_EHCI_INTERFACE_SINGLE_UNI | MXC_EHCI_INTERNAL_PHY |
MXC_EHCI_IPPUE_DOWN,
};
+#endif
static struct fsl_usb2_platform_data otg_device_pdata = {
.operating_mode = FSL_USB2_DR_DEVICE,
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index ed885f9d7b73..19cde6896302 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -12,6 +12,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/io.h>
@@ -21,6 +22,7 @@
#include <mach/hardware.h>
#include <mach/imx-uart.h>
#include <mach/iomux-mx51.h>
+#include <mach/i2c.h>
#include <mach/mxc_ehci.h>
#include <asm/irq.h>
@@ -64,6 +66,18 @@ static struct pad_desc mx51babbage_pads[] = {
MX51_PAD_EIM_D27__UART3_RTS,
MX51_PAD_EIM_D24__UART3_CTS,
+ /* I2C1 */
+ MX51_PAD_EIM_D16__I2C1_SDA,
+ MX51_PAD_EIM_D19__I2C1_SCL,
+
+ /* I2C2 */
+ MX51_PAD_KEY_COL4__I2C2_SCL,
+ MX51_PAD_KEY_COL5__I2C2_SDA,
+
+ /* HSI2C */
+ MX51_PAD_I2C1_CLK__HSI2C_CLK,
+ MX51_PAD_I2C1_DAT__HSI2C_DAT,
+
/* USB HOST1 */
MX51_PAD_USBH1_CLK__USBH1_CLK,
MX51_PAD_USBH1_DIR__USBH1_DIR,
@@ -99,6 +113,14 @@ static inline void mxc_init_imx_uart(void)
}
#endif /* SERIAL_IMX */
+static struct imxi2c_platform_data babbage_i2c_data = {
+ .bitrate = 100000,
+};
+
+static struct imxi2c_platform_data babbage_hsi2c_data = {
+ .bitrate = 400000,
+};
+
static int gpio_usbh1_active(void)
{
struct pad_desc usbh1stp_gpio = MX51_PAD_USBH1_STP__GPIO_1_27;
@@ -230,6 +252,10 @@ static void __init mxc_board_init(void)
mxc_init_imx_uart();
platform_add_devices(devices, ARRAY_SIZE(devices));
+ mxc_register_device(&mxc_i2c_device0, &babbage_i2c_data);
+ mxc_register_device(&mxc_i2c_device1, &babbage_i2c_data);
+ mxc_register_device(&mxc_hsi2c_device, &babbage_hsi2c_data);
+
if (otg_mode_host)
mxc_register_device(&mxc_usbdr_host_device, &dr_utmi_config);
else {
diff --git a/arch/arm/mach-mx5/clock-mx51.c b/arch/arm/mach-mx5/clock-mx51.c
index d9f612d3370e..fd24092154b5 100644
--- a/arch/arm/mach-mx5/clock-mx51.c
+++ b/arch/arm/mach-mx5/clock-mx51.c
@@ -798,6 +798,14 @@ DEFINE_CLOCK(gpt_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG9_OFFSET,
DEFINE_CLOCK(gpt_ipg_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG10_OFFSET,
NULL, NULL, &ipg_clk, NULL);
+/* I2C */
+DEFINE_CLOCK(i2c1_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG9_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(i2c2_clk, 1, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG10_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+DEFINE_CLOCK(hsi2c_clk, 0, MXC_CCM_CCGR1, MXC_CCM_CCGRx_CG11_OFFSET,
+ NULL, NULL, &ipg_clk, NULL);
+
/* FEC */
DEFINE_CLOCK(fec_clk, 0, MXC_CCM_CCGR2, MXC_CCM_CCGRx_CG12_OFFSET,
NULL, NULL, &ipg_clk, NULL);
@@ -815,6 +823,9 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
_REGISTER_CLOCK("fec.0", NULL, fec_clk)
+ _REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
+ _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
+ _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk)
_REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk)
_REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk)
_REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk)
diff --git a/arch/arm/mach-mx5/devices.c b/arch/arm/mach-mx5/devices.c
index 7130449aacdc..ede4fcbc7e80 100644
--- a/arch/arm/mach-mx5/devices.c
+++ b/arch/arm/mach-mx5/devices.c
@@ -93,6 +93,64 @@ struct platform_device mxc_fec_device = {
.resource = mxc_fec_resources,
};
+static struct resource mxc_i2c0_resources[] = {
+ {
+ .start = MX51_I2C1_BASE_ADDR,
+ .end = MX51_I2C1_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = MX51_MXC_INT_I2C1,
+ .end = MX51_MXC_INT_I2C1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_i2c_device0 = {
+ .name = "imx-i2c",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(mxc_i2c0_resources),
+ .resource = mxc_i2c0_resources,
+};
+
+static struct resource mxc_i2c1_resources[] = {
+ {
+ .start = MX51_I2C2_BASE_ADDR,
+ .end = MX51_I2C2_BASE_ADDR + SZ_4K - 1,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = MX51_MXC_INT_I2C2,
+ .end = MX51_MXC_INT_I2C2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_i2c_device1 = {
+ .name = "imx-i2c",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(mxc_i2c1_resources),
+ .resource = mxc_i2c1_resources,
+};
+
+static struct resource mxc_hsi2c_resources[] = {
+ {
+ .start = MX51_HSI2C_DMA_BASE_ADDR,
+ .end = MX51_HSI2C_DMA_BASE_ADDR + SZ_16K - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = MX51_MXC_INT_HS_I2C,
+ .end = MX51_MXC_INT_HS_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device mxc_hsi2c_device = {
+ .name = "imx-i2c",
+ .id = 2,
+ .num_resources = ARRAY_SIZE(mxc_hsi2c_resources),
+ .resource = mxc_hsi2c_resources
+};
+
static u64 usb_dma_mask = DMA_BIT_MASK(32);
static struct resource usbotg_resources[] = {
diff --git a/arch/arm/mach-mx5/devices.h b/arch/arm/mach-mx5/devices.h
index c879ae71cd5b..a853933682e7 100644
--- a/arch/arm/mach-mx5/devices.h
+++ b/arch/arm/mach-mx5/devices.h
@@ -6,3 +6,6 @@ extern struct platform_device mxc_usbdr_host_device;
extern struct platform_device mxc_usbh1_device;
extern struct platform_device mxc_usbdr_udc_device;
extern struct platform_device mxc_wdt;
+extern struct platform_device mxc_i2c_device0;
+extern struct platform_device mxc_i2c_device1;
+extern struct platform_device mxc_hsi2c_device;
diff --git a/arch/arm/mach-nomadik/clock.c b/arch/arm/mach-nomadik/clock.c
index 2c471fc451d7..f035f4185274 100644
--- a/arch/arm/mach-nomadik/clock.c
+++ b/arch/arm/mach-nomadik/clock.c
@@ -32,7 +32,10 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL(clk_disable);
-/* We have a fixed clock alone, for now */
+static struct clk clk_24 = {
+ .rate = 2400000,
+};
+
static struct clk clk_48 = {
.rate = 48 * 1000 * 1000,
};
@@ -50,6 +53,8 @@ static struct clk clk_default;
}
static struct clk_lookup lookups[] = {
+ CLK(&clk_24, "mtu0"),
+ CLK(&clk_24, "mtu1"),
CLK(&clk_48, "uart0"),
CLK(&clk_48, "uart1"),
CLK(&clk_default, "gpio.0"),
@@ -59,10 +64,8 @@ static struct clk_lookup lookups[] = {
CLK(&clk_default, "rng"),
};
-static int __init clk_init(void)
+int __init clk_init(void)
{
clkdev_add_table(lookups, ARRAY_SIZE(lookups));
return 0;
}
-
-arch_initcall(clk_init);
diff --git a/arch/arm/mach-nomadik/clock.h b/arch/arm/mach-nomadik/clock.h
index 5563985a2cc7..78da2e7c3985 100644
--- a/arch/arm/mach-nomadik/clock.h
+++ b/arch/arm/mach-nomadik/clock.h
@@ -11,3 +11,5 @@
struct clk {
unsigned long rate;
};
+
+int __init clk_init(void);
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 91c3c901b469..ac58e3b03b1a 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -31,6 +31,8 @@
#include <asm/cacheflush.h>
#include <asm/hardware/cache-l2x0.h>
+#include "clock.h"
+
#define __MEM_4K_RESOURCE(x) \
.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
@@ -143,6 +145,12 @@ void __init cpu8815_init_irq(void)
/* This modified VIC cell has two register blocks, at 0 and 0x20 */
vic_init(io_p2v(NOMADIK_IC_BASE + 0x00), IRQ_VIC_START + 0, ~0, 0);
vic_init(io_p2v(NOMADIK_IC_BASE + 0x20), IRQ_VIC_START + 32, ~0, 0);
+
+ /*
+ * Init clocks here so that they are available for system timer
+ * initialization.
+ */
+ clk_init();
}
/*
diff --git a/arch/arm/mach-omap2/board-omap3stalker.c b/arch/arm/mach-omap2/board-omap3stalker.c
index f848ba8dbc16..a04cffd691c5 100644
--- a/arch/arm/mach-omap2/board-omap3stalker.c
+++ b/arch/arm/mach-omap2/board-omap3stalker.c
@@ -538,9 +538,7 @@ static void ads7846_dev_init(void)
printk(KERN_ERR "can't get ads7846 pen down GPIO\n");
gpio_direction_input(OMAP3_STALKER_TS_GPIO);
-
- omap_set_gpio_debounce(OMAP3_STALKER_TS_GPIO, 1);
- omap_set_gpio_debounce_time(OMAP3_STALKER_TS_GPIO, 0xa);
+ gpio_set_debounce(OMAP3_STALKER_TS_GPIO, 310);
}
static int ads7846_get_pendown_state(void)
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 79ac41400c21..4ceeb56c414c 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -166,9 +166,26 @@ static struct platform_device overo_smsc911x_device = {
},
};
+static struct platform_device overo_smsc911x2_device = {
+ .name = "smsc911x",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(overo_smsc911x2_resources),
+ .resource = overo_smsc911x2_resources,
+ .dev = {
+ .platform_data = &overo_smsc911x_config,
+ },
+};
+
+static struct platform_device *smsc911x_devices[] = {
+ &overo_smsc911x_device,
+ &overo_smsc911x2_device,
+};
+
static inline void __init overo_init_smsc911x(void)
{
- unsigned long cs_mem_base;
+ unsigned long cs_mem_base, cs_mem_base2;
+
+ /* set up first smsc911x chip */
if (gpmc_cs_request(OVERO_SMSC911X_CS, SZ_16M, &cs_mem_base) < 0) {
printk(KERN_ERR "Failed request for GPMC mem for smsc911x\n");
@@ -189,7 +206,28 @@ static inline void __init overo_init_smsc911x(void)
overo_smsc911x_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X_GPIO);
overo_smsc911x_resources[1].end = 0;
- platform_device_register(&overo_smsc911x_device);
+ /* set up second smsc911x chip */
+
+ if (gpmc_cs_request(OVERO_SMSC911X2_CS, SZ_16M, &cs_mem_base2) < 0) {
+ printk(KERN_ERR "Failed request for GPMC mem for smsc911x2\n");
+ return;
+ }
+
+ overo_smsc911x2_resources[0].start = cs_mem_base2 + 0x0;
+ overo_smsc911x2_resources[0].end = cs_mem_base2 + 0xff;
+
+ if ((gpio_request(OVERO_SMSC911X2_GPIO, "SMSC911X2 IRQ") == 0) &&
+ (gpio_direction_input(OVERO_SMSC911X2_GPIO) == 0)) {
+ gpio_export(OVERO_SMSC911X2_GPIO, 0);
+ } else {
+ printk(KERN_ERR "could not obtain gpio for SMSC911X2 IRQ\n");
+ return;
+ }
+
+ overo_smsc911x2_resources[1].start = OMAP_GPIO_IRQ(OVERO_SMSC911X2_GPIO);
+ overo_smsc911x2_resources[1].end = 0;
+
+ platform_add_devices(smsc911x_devices, ARRAY_SIZE(smsc911x_devices));
}
#else
diff --git a/arch/arm/mach-omap2/mcbsp.c b/arch/arm/mach-omap2/mcbsp.c
index c29337074ad3..8fb5e5345557 100644
--- a/arch/arm/mach-omap2/mcbsp.c
+++ b/arch/arm/mach-omap2/mcbsp.c
@@ -133,7 +133,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP2_BASE,
@@ -143,7 +143,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x3FF,
+ .buffer_size = 0x500, /* The FIFO has 1024 + 256 locations */
},
{
.phys_base = OMAP34XX_MCBSP3_BASE,
@@ -153,7 +153,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP4_BASE,
@@ -162,7 +162,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
{
.phys_base = OMAP34XX_MCBSP5_BASE,
@@ -171,7 +171,7 @@ static struct omap_mcbsp_platform_data omap34xx_mcbsp_pdata[] = {
.rx_irq = INT_24XX_MCBSP5_IRQ_RX,
.tx_irq = INT_24XX_MCBSP5_IRQ_TX,
.ops = &omap2_mcbsp_ops,
- .buffer_size = 0x6F,
+ .buffer_size = 0x80, /* The FIFO has 128 locations */
},
};
#define OMAP34XX_MCBSP_PDATA_SZ ARRAY_SIZE(omap34xx_mcbsp_pdata)
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 2e967716cc3f..b88737fd6cfe 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -99,7 +99,7 @@ static void omap3_enable_io_chain(void)
/* Do a readback to assure write has been done */
prm_read_mod_reg(WKUP_MOD, PM_WKEN);
- while (!(prm_read_mod_reg(WKUP_MOD, PM_WKST) &
+ while (!(prm_read_mod_reg(WKUP_MOD, PM_WKEN) &
OMAP3430_ST_IO_CHAIN_MASK)) {
timeout++;
if (timeout > 1000) {
@@ -108,7 +108,7 @@ static void omap3_enable_io_chain(void)
return;
}
prm_set_mod_reg_bits(OMAP3430_ST_IO_CHAIN_MASK,
- WKUP_MOD, PM_WKST);
+ WKUP_MOD, PM_WKEN);
}
}
}
diff --git a/arch/arm/mach-omap2/usb-ehci.c b/arch/arm/mach-omap2/usb-ehci.c
index c68f799e83c5..d72d1ac30333 100644
--- a/arch/arm/mach-omap2/usb-ehci.c
+++ b/arch/arm/mach-omap2/usb-ehci.c
@@ -20,6 +20,8 @@
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+
#include <asm/io.h>
#include <plat/mux.h>
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index f2b88c5fe142..1de8d171c6e9 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -7,6 +7,7 @@ config ARCH_SH7367
select CPU_V6
select HAVE_CLK
select COMMON_CLKDEV
+ select SH_CLK_CPG
select GENERIC_CLOCKEVENTS
config ARCH_SH7377
@@ -14,6 +15,7 @@ config ARCH_SH7377
select CPU_V7
select HAVE_CLK
select COMMON_CLKDEV
+ select SH_CLK_CPG
select GENERIC_CLOCKEVENTS
config ARCH_SH7372
@@ -21,6 +23,7 @@ config ARCH_SH7372
select CPU_V7
select HAVE_CLK
select COMMON_CLKDEV
+ select SH_CLK_CPG
select GENERIC_CLOCKEVENTS
comment "SH-Mobile Board Type"
@@ -39,6 +42,7 @@ config MACH_AP4EVB
bool "AP4EVB board"
depends on ARCH_SH7372
select ARCH_REQUIRE_GPIOLIB
+ select SH_LCD_MIPI_DSI
comment "SH-Mobile System Configuration"
@@ -76,6 +80,15 @@ config SH_TIMER_CMT
help
This enables build of the CMT timer driver.
+config SH_TIMER_TMU
+ bool "TMU timer driver"
+ default y
+ help
+ This enables build of the TMU timer driver.
+
endmenu
+config SH_CLK_CPG
+ bool
+
endif
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 6d385d371c33..5e16b4c69222 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -3,12 +3,12 @@
#
# Common objects
-obj-y := timer.o console.o
+obj-y := timer.o console.o clock.o
# CPU objects
obj-$(CONFIG_ARCH_SH7367) += setup-sh7367.o clock-sh7367.o intc-sh7367.o
-obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7367.o intc-sh7377.o
-obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7367.o intc-sh7372.o
+obj-$(CONFIG_ARCH_SH7377) += setup-sh7377.o clock-sh7377.o intc-sh7377.o
+obj-$(CONFIG_ARCH_SH7372) += setup-sh7372.o clock-sh7372.o intc-sh7372.o
# Pinmux setup
pfc-$(CONFIG_ARCH_SH7367) := pfc-sh7367.o
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index 1c2ec96ce261..5d24d4ec93a7 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -17,25 +17,44 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/mmc/host.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
#include <linux/io.h>
#include <linux/smsc911x.h>
+#include <linux/sh_intc.h>
+#include <linux/sh_clk.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
+#include <linux/usb/r8a66597.h>
+
+#include <sound/sh_fsi.h>
+
+#include <video/sh_mobile_lcdc.h>
+#include <video/sh_mipi_dsi.h>
+
#include <mach/common.h>
+#include <mach/irqs.h>
#include <mach/sh7372.h>
+
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/mach/time.h>
/*
* Address Interface BusWidth note
@@ -80,12 +99,50 @@
*/
/*
- * KEYSC
+ * LCD / IRQ / KEYSC / IrDA
+ *
+ * IRQ = IRQ26 (TS), IRQ27 (VIO), IRQ28 (TouchScreen)
+ * LCD = 2nd LCDC
+ *
+ * | SW43 |
+ * SW3 | ON | OFF |
+ * -------------+-----------------------+---------------+
+ * ON | KEY / IrDA | LCD |
+ * OFF | KEY / IrDA / IRQ | IRQ |
+ */
+
+/*
+ * USB
+ *
+ * J7 : 1-2 MAX3355E VBUS
+ * 2-3 DC 5.0V
+ *
+ * S39: bit2: off
+ */
+
+/*
+ * FSI/FSMI
*
- * SW43 KEYSC
- * -------------------------
- * ON enable
- * OFF disable
+ * SW41 : ON : SH-Mobile AP4 Audio Mode
+ * : OFF : Bluetooth Audio Mode
+ */
+
+/*
+ * MMC0/SDHI1 (CN7)
+ *
+ * J22 : select card voltage
+ * 1-2 pin : 1.8v
+ * 2-3 pin : 3.3v
+ *
+ * SW1 | SW33
+ * | bit1 | bit2 | bit3 | bit4
+ * ------------+------+------+------+-------
+ * MMC0 OFF | OFF | ON | ON | X
+ * SDHI1 OFF | ON | X | OFF | ON
+ *
+ * voltage lebel
+ * CN7 : 1.8v
+ * CN12: 3.3v
*/
/* MTD */
@@ -148,7 +205,7 @@ static struct resource smc911x_resources[] = {
.end = 0x16000000 - 1,
.flags = IORESOURCE_MEM,
}, {
- .start = 6,
+ .start = evt2irq(0x02c0) /* IRQ6A */,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
},
};
@@ -191,7 +248,7 @@ static struct resource keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0x0be0), /* KEYSC_KEY */
.flags = IORESOURCE_IRQ,
},
};
@@ -206,7 +263,52 @@ static struct platform_device keysc_device = {
},
};
+/* SH_MMCIF */
+static struct resource sh_mmcif_resources[] = {
+ [0] = {
+ .name = "SH_MMCIF",
+ .start = 0xE6BD0000,
+ .end = 0xE6BD00FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* MMC ERR */
+ .start = evt2irq(0x1ac0),
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* MMC NOR */
+ .start = evt2irq(0x1ae0),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_plat = {
+ .sup_pclk = 0,
+ .ocr = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
+ .caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_8_BIT_DATA |
+ MMC_CAP_NEEDS_POLL,
+};
+
+static struct platform_device sh_mmcif_device = {
+ .name = "sh_mmcif",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL,
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &sh_mmcif_plat,
+ },
+ .num_resources = ARRAY_SIZE(sh_mmcif_resources),
+ .resource = sh_mmcif_resources,
+};
+
/* SDHI0 */
+static struct sh_mobile_sdhi_info sdhi0_info = {
+ .dma_slave_tx = SHDMA_SLAVE_SDHI0_TX,
+ .dma_slave_rx = SHDMA_SLAVE_SDHI0_RX,
+};
+
static struct resource sdhi0_resources[] = {
[0] = {
.name = "SDHI0",
@@ -215,7 +317,7 @@ static struct resource sdhi0_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 96,
+ .start = evt2irq(0x0e00) /* SDHI0 */,
.flags = IORESOURCE_IRQ,
},
};
@@ -225,6 +327,206 @@ static struct platform_device sdhi0_device = {
.num_resources = ARRAY_SIZE(sdhi0_resources),
.resource = sdhi0_resources,
.id = 0,
+ .dev = {
+ .platform_data = &sdhi0_info,
+ },
+};
+
+/* SDHI1 */
+static struct sh_mobile_sdhi_info sdhi1_info = {
+ .dma_slave_tx = SHDMA_SLAVE_SDHI1_TX,
+ .dma_slave_rx = SHDMA_SLAVE_SDHI1_RX,
+ .tmio_ocr_mask = MMC_VDD_165_195,
+};
+
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0xe6860000,
+ .end = 0xe68601ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x0e80),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+ .id = 1,
+ .dev = {
+ .platform_data = &sdhi1_info,
+ },
+};
+
+/* USB1 */
+static void usb1_host_port_power(int port, int power)
+{
+ if (!power) /* only power-on supported for now */
+ return;
+
+ /* set VBOUT/PWEN and EXTLP1 in DVSTCTR */
+ __raw_writew(__raw_readw(0xE68B0008) | 0x600, 0xE68B0008);
+}
+
+static struct r8a66597_platdata usb1_host_data = {
+ .on_chip = 1,
+ .port_power = usb1_host_port_power,
+};
+
+static struct resource usb1_host_resources[] = {
+ [0] = {
+ .name = "USBHS",
+ .start = 0xE68B0000,
+ .end = 0xE68B00E6 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x1ce0) /* USB1_USB1I0 */,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb1_host_device = {
+ .name = "r8a66597_hcd",
+ .id = 1,
+ .dev = {
+ .dma_mask = NULL, /* not use dma */
+ .coherent_dma_mask = 0xffffffff,
+ .platform_data = &usb1_host_data,
+ },
+ .num_resources = ARRAY_SIZE(usb1_host_resources),
+ .resource = usb1_host_resources,
+};
+
+static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = {
+ .clock_source = LCDC_CLK_PERIPHERAL, /* One of interface clocks */
+ .ch[0] = {
+ .chan = LCDC_CHAN_MAINLCD,
+ .bpp = 16,
+ .interface_type = RGB24,
+ .clock_divider = 1,
+ .flags = LCDC_FLAGS_DWPOL,
+ .lcd_cfg = {
+ .name = "R63302(QHD)",
+ .xres = 544,
+ .yres = 961,
+ .left_margin = 72,
+ .right_margin = 600,
+ .hsync_len = 16,
+ .upper_margin = 8,
+ .lower_margin = 8,
+ .vsync_len = 2,
+ .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
+ },
+ .lcd_size_cfg = {
+ .width = 44,
+ .height = 79,
+ },
+ }
+};
+
+static struct resource lcdc_resources[] = {
+ [0] = {
+ .name = "LCDC",
+ .start = 0xfe940000, /* P4-only space */
+ .end = 0xfe943fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0x580),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device lcdc_device = {
+ .name = "sh_mobile_lcdc_fb",
+ .num_resources = ARRAY_SIZE(lcdc_resources),
+ .resource = lcdc_resources,
+ .dev = {
+ .platform_data = &sh_mobile_lcdc_info,
+ .coherent_dma_mask = ~0,
+ },
+};
+
+static struct resource mipidsi0_resources[] = {
+ [0] = {
+ .start = 0xffc60000,
+ .end = 0xffc68fff,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
+static struct sh_mipi_dsi_info mipidsi0_info = {
+ .data_format = MIPI_RGB888,
+ .lcd_chan = &sh_mobile_lcdc_info.ch[0],
+};
+
+static struct platform_device mipidsi0_device = {
+ .name = "sh-mipi-dsi",
+ .num_resources = ARRAY_SIZE(mipidsi0_resources),
+ .resource = mipidsi0_resources,
+ .id = 0,
+ .dev = {
+ .platform_data = &mipidsi0_info,
+ },
+};
+
+/* FSI */
+#define IRQ_FSI evt2irq(0x1840)
+#define FSIACKCR 0xE6150018
+static void fsiackcr_init(struct clk *clk)
+{
+ u32 status = __raw_readl(clk->enable_reg);
+
+ /* use external clock */
+ status &= ~0x000000ff;
+ status |= 0x00000080;
+ __raw_writel(status, clk->enable_reg);
+}
+
+static struct clk_ops fsiackcr_clk_ops = {
+ .init = fsiackcr_init,
+};
+
+static struct clk fsiackcr_clk = {
+ .ops = &fsiackcr_clk_ops,
+ .enable_reg = (void __iomem *)FSIACKCR,
+ .rate = 0, /* unknown */
+};
+
+static struct sh_fsi_platform_info fsi_info = {
+ .porta_flags = SH_FSI_BRS_INV |
+ SH_FSI_OUT_SLAVE_MODE |
+ SH_FSI_IN_SLAVE_MODE |
+ SH_FSI_OFMT(PCM) |
+ SH_FSI_IFMT(PCM),
+};
+
+static struct resource fsi_resources[] = {
+ [0] = {
+ .name = "FSI",
+ .start = 0xFE3C0000,
+ .end = 0xFE3C0400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_FSI,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device fsi_device = {
+ .name = "sh_fsi2",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(fsi_resources),
+ .resource = fsi_resources,
+ .dev = {
+ .platform_data = &fsi_info,
+ },
};
static struct platform_device *ap4evb_devices[] __initdata = {
@@ -232,6 +534,38 @@ static struct platform_device *ap4evb_devices[] __initdata = {
&smc911x_device,
&keysc_device,
&sdhi0_device,
+ &sdhi1_device,
+ &usb1_host_device,
+ &lcdc_device,
+ &mipidsi0_device,
+ &fsi_device,
+ &sh_mmcif_device
+};
+
+/* TouchScreen (Needs SW3 set to OFF) */
+#define IRQ28 evt2irq(0x3380) /* IRQ28A */
+static struct tsc2007_platform_data tsc2007_info = {
+ .model = 2007,
+ .x_plate_ohms = 180,
+};
+
+/* I2C */
+static struct i2c_board_info i2c0_devices[] = {
+ {
+ I2C_BOARD_INFO("ak4643", 0x13),
+ },
+};
+
+static struct i2c_board_info i2c1_devices[] = {
+ {
+ I2C_BOARD_INFO("r2025sd", 0x32),
+ },
+ {
+ I2C_BOARD_INFO("tsc2007", 0x48),
+ .type = "tsc2007",
+ .platform_data = &tsc2007_info,
+ .irq = IRQ28,
+ },
};
static struct map_desc ap4evb_io_desc[] __initdata = {
@@ -250,14 +584,71 @@ static void __init ap4evb_map_io(void)
{
iotable_init(ap4evb_io_desc, ARRAY_SIZE(ap4evb_io_desc));
- /* setup early devices, clocks and console here as well */
+ /* setup early devices and console here as well */
sh7372_add_early_devices();
- sh7367_clock_init(); /* use g3 clocks for now */
shmobile_setup_console();
}
+/* This function will disappear when we switch to (runtime) PM */
+static int __init ap4evb_init_display_clk(void)
+{
+ struct clk *lcdc_clk;
+ struct clk *dsitx_clk;
+ int ret;
+
+ lcdc_clk = clk_get(&lcdc_device.dev, "sh_mobile_lcdc_fb.0");
+ if (IS_ERR(lcdc_clk))
+ return PTR_ERR(lcdc_clk);
+
+ dsitx_clk = clk_get(&mipidsi0_device.dev, "sh-mipi-dsi.0");
+ if (IS_ERR(dsitx_clk)) {
+ ret = PTR_ERR(dsitx_clk);
+ goto eclkdsitxget;
+ }
+
+ ret = clk_enable(lcdc_clk);
+ if (ret < 0)
+ goto eclklcdcon;
+
+ ret = clk_enable(dsitx_clk);
+ if (ret < 0)
+ goto eclkdsitxon;
+
+ return 0;
+
+eclkdsitxon:
+ clk_disable(lcdc_clk);
+eclklcdcon:
+ clk_put(dsitx_clk);
+eclkdsitxget:
+ clk_put(lcdc_clk);
+
+ return ret;
+}
+
+device_initcall(ap4evb_init_display_clk);
+
+/*
+ * FIXME !!
+ *
+ * gpio_no_direction is quick_hack.
+ *
+ * current gpio frame work doesn't have
+ * the method to control only pull up/down/free.
+ * this function should be replaced by correct gpio function
+ */
+static void __init gpio_no_direction(u32 addr)
+{
+ __raw_writeb(0x00, addr);
+}
+
+#define GPIO_PORT9CR 0xE6051009
+#define GPIO_PORT10CR 0xE605100A
+
static void __init ap4evb_init(void)
{
+ struct clk *clk;
+
sh7372_pinmux_init();
/* enable SCIFA0 */
@@ -318,16 +709,102 @@ static void __init ap4evb_init(void)
gpio_request(GPIO_FN_SDHID0_1, NULL);
gpio_request(GPIO_FN_SDHID0_0, NULL);
+ /* enable TouchScreen */
+ gpio_request(GPIO_FN_IRQ28_123, NULL);
+ set_irq_type(IRQ28, IRQ_TYPE_LEVEL_LOW);
+
+ /* MMCIF */
+ gpio_request(GPIO_FN_MMCD0_0, NULL);
+ gpio_request(GPIO_FN_MMCD0_1, NULL);
+ gpio_request(GPIO_FN_MMCD0_2, NULL);
+ gpio_request(GPIO_FN_MMCD0_3, NULL);
+ gpio_request(GPIO_FN_MMCD0_4, NULL);
+ gpio_request(GPIO_FN_MMCD0_5, NULL);
+ gpio_request(GPIO_FN_MMCD0_6, NULL);
+ gpio_request(GPIO_FN_MMCD0_7, NULL);
+ gpio_request(GPIO_FN_MMCCMD0, NULL);
+ gpio_request(GPIO_FN_MMCCLK0, NULL);
+
+ /* USB enable */
+ gpio_request(GPIO_FN_VBUS0_1, NULL);
+ gpio_request(GPIO_FN_IDIN_1_18, NULL);
+ gpio_request(GPIO_FN_PWEN_1_115, NULL);
+ gpio_request(GPIO_FN_OVCN_1_114, NULL);
+ gpio_request(GPIO_FN_EXTLP_1, NULL);
+ gpio_request(GPIO_FN_OVCN2_1, NULL);
+
+ /* setup USB phy */
+ __raw_writew(0x8a0a, 0xE6058130); /* USBCR2 */
+
+ /* enable FSI2 */
+ gpio_request(GPIO_FN_FSIAIBT, NULL);
+ gpio_request(GPIO_FN_FSIAILR, NULL);
+ gpio_request(GPIO_FN_FSIAISLD, NULL);
+ gpio_request(GPIO_FN_FSIAOSLD, NULL);
+ gpio_request(GPIO_PORT161, NULL);
+ gpio_direction_output(GPIO_PORT161, 0); /* slave */
+
+ gpio_request(GPIO_PORT9, NULL);
+ gpio_request(GPIO_PORT10, NULL);
+ gpio_no_direction(GPIO_PORT9CR); /* FSIAOBT needs no direction */
+ gpio_no_direction(GPIO_PORT10CR); /* FSIAOLR needs no direction */
+
+ /* set SPU2 clock to 119.6 MHz */
+ clk = clk_get(NULL, "spu_clk");
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, clk_round_rate(clk, 119600000));
+ clk_put(clk);
+ }
+
+ /* change parent of FSI A */
+ clk = clk_get(NULL, "fsia_clk");
+ if (!IS_ERR(clk)) {
+ clk_register(&fsiackcr_clk);
+ clk_set_parent(clk, &fsiackcr_clk);
+ clk_put(clk);
+ }
+
+ /*
+ * set irq priority, to avoid sound chopping
+ * when NFS rootfs is used
+ * FSI(3) > SMSC911X(2)
+ */
+ intc_set_priority(IRQ_FSI, 3);
+
+ i2c_register_board_info(0, i2c0_devices,
+ ARRAY_SIZE(i2c0_devices));
+
+ i2c_register_board_info(1, i2c1_devices,
+ ARRAY_SIZE(i2c1_devices));
+
+ /* SDHI1 */
+ gpio_request(GPIO_FN_SDHICMD1, NULL);
+ gpio_request(GPIO_FN_SDHICLK1, NULL);
+ gpio_request(GPIO_FN_SDHID1_3, NULL);
+ gpio_request(GPIO_FN_SDHID1_2, NULL);
+ gpio_request(GPIO_FN_SDHID1_1, NULL);
+ gpio_request(GPIO_FN_SDHID1_0, NULL);
+
sh7372_add_standard_devices();
platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices));
}
+static void __init ap4evb_timer_init(void)
+{
+ sh7372_clock_init();
+ shmobile_timer.init();
+}
+
+static struct sys_timer ap4evb_timer = {
+ .init = ap4evb_timer_init,
+};
+
MACHINE_START(AP4EVB, "ap4evb")
.phys_io = 0xe6000000,
.io_pg_offst = ((0xe6000000) >> 18) & 0xfffc,
.map_io = ap4evb_map_io,
.init_irq = sh7372_init_irq,
.init_machine = ap4evb_init,
- .timer = &shmobile_timer,
+ .timer = &ap4evb_timer,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-g3evm.c b/arch/arm/mach-shmobile/board-g3evm.c
index 9247503296c4..95ccb949d5d9 100644
--- a/arch/arm/mach-shmobile/board-g3evm.c
+++ b/arch/arm/mach-shmobile/board-g3evm.c
@@ -37,6 +37,15 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+/*
+ * IrDA
+ *
+ * S67: 5bit : ON power
+ * : 6bit : ON remote control
+ * OFF IrDA
+ */
static struct mtd_partition nor_flash_partitions[] = {
{
@@ -91,7 +100,7 @@ static struct platform_device nor_flash_device = {
};
/* USBHS */
-void usb_host_port_power(int port, int power)
+static void usb_host_port_power(int port, int power)
{
if (!power) /* only power-on supported for now */
return;
@@ -113,7 +122,7 @@ static struct resource usb_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
+ .start = evt2irq(0xa20), /* USBHS_USHI0 */
.flags = IORESOURCE_IRQ,
},
};
@@ -153,7 +162,7 @@ static struct resource keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0xbe0), /* KEYSC_KEY */
.flags = IORESOURCE_IRQ,
},
};
@@ -209,11 +218,30 @@ static struct platform_device nand_flash_device = {
},
};
+static struct resource irda_resources[] = {
+ [0] = {
+ .start = 0xE6D00000,
+ .end = 0xE6D01FD4 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x480), /* IRDA */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device irda_device = {
+ .name = "sh_irda",
+ .resource = irda_resources,
+ .num_resources = ARRAY_SIZE(irda_resources),
+};
+
static struct platform_device *g3evm_devices[] __initdata = {
&nor_flash_device,
&usb_host_device,
&keysc_device,
&nand_flash_device,
+ &irda_device,
};
static struct map_desc g3evm_io_desc[] __initdata = {
@@ -232,9 +260,8 @@ static void __init g3evm_map_io(void)
{
iotable_init(g3evm_io_desc, ARRAY_SIZE(g3evm_io_desc));
- /* setup early devices, clocks and console here as well */
+ /* setup early devices and console here as well */
sh7367_add_early_devices();
- sh7367_clock_init();
shmobile_setup_console();
}
@@ -271,9 +298,6 @@ static void __init g3evm_init(void)
gpio_request(GPIO_FN_EXTLP, NULL);
gpio_request(GPIO_FN_IDIN, NULL);
- /* enable clock in SYMSTPCR2 */
- __raw_writel(__raw_readl(0xe6158048) & ~(1 << 22), 0xe6158048);
-
/* setup USB phy */
__raw_writew(0x0300, 0xe605810a); /* USBCR1 */
__raw_writew(0x00e0, 0xe60581c0); /* CPFCH */
@@ -318,16 +342,32 @@ static void __init g3evm_init(void)
/* FOE, FCDE, FSC on dedicated pins */
__raw_writel(__raw_readl(0xe6158048) & ~(1 << 15), 0xe6158048);
+ /* IrDA */
+ gpio_request(GPIO_FN_IRDA_OUT, NULL);
+ gpio_request(GPIO_FN_IRDA_IN, NULL);
+ gpio_request(GPIO_FN_IRDA_FIRSEL, NULL);
+ set_irq_type(evt2irq(0x480), IRQ_TYPE_LEVEL_LOW);
+
sh7367_add_standard_devices();
platform_add_devices(g3evm_devices, ARRAY_SIZE(g3evm_devices));
}
+static void __init g3evm_timer_init(void)
+{
+ sh7367_clock_init();
+ shmobile_timer.init();
+}
+
+static struct sys_timer g3evm_timer = {
+ .init = g3evm_timer_init,
+};
+
MACHINE_START(G3EVM, "g3evm")
.phys_io = 0xe6000000,
.io_pg_offst = ((0xe6000000) >> 18) & 0xfffc,
.map_io = g3evm_map_io,
.init_irq = sh7367_init_irq,
.init_machine = g3evm_init,
- .timer = &shmobile_timer,
+ .timer = &g3evm_timer,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-g4evm.c b/arch/arm/mach-shmobile/board-g4evm.c
index 10673a90be52..2c3ff6f7f34c 100644
--- a/arch/arm/mach-shmobile/board-g4evm.c
+++ b/arch/arm/mach-shmobile/board-g4evm.c
@@ -30,12 +30,39 @@
#include <linux/io.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
+#include <linux/mfd/sh_mobile_sdhi.h>
#include <linux/gpio.h>
#include <mach/sh7377.h>
#include <mach/common.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
+#include <asm/mach/time.h>
+
+/*
+ * SDHI
+ *
+ * SDHI0 : card detection is possible
+ * SDHI1 : card detection is impossible
+ *
+ * [G4-MAIN-BOARD]
+ * JP74 : short # DBG_2V8A for SDHI0
+ * JP75 : NC # DBG_3V3A for SDHI0
+ * JP76 : NC # DBG_3V3A_SD for SDHI0
+ * JP77 : NC # 3V3A_SDIO for SDHI1
+ * JP78 : short # DBG_2V8A for SDHI1
+ * JP79 : NC # DBG_3V3A for SDHI1
+ * JP80 : NC # DBG_3V3A_SD for SDHI1
+ *
+ * [G4-CORE-BOARD]
+ * S32 : all off # to dissever from G3-CORE_DBG board
+ * S33 : all off # to dissever from G3-CORE_DBG board
+ *
+ * [G3-CORE_DBG-BOARD]
+ * S1 : all off # to dissever from G3-CORE_DBG board
+ * S3 : all off # to dissever from G3-CORE_DBG board
+ * S4 : all off # to dissever from G3-CORE_DBG board
+ */
static struct mtd_partition nor_flash_partitions[] = {
{
@@ -90,7 +117,7 @@ static struct platform_device nor_flash_device = {
};
/* USBHS */
-void usb_host_port_power(int port, int power)
+static void usb_host_port_power(int port, int power)
{
if (!power) /* only power-on supported for now */
return;
@@ -112,8 +139,7 @@ static struct resource usb_host_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 65,
- .end = 65,
+ .start = evt2irq(0x0a20), /* USBHS_USHI0 */
.flags = IORESOURCE_IRQ,
},
};
@@ -154,7 +180,7 @@ static struct resource keysc_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 79,
+ .start = evt2irq(0x0be0), /* KEYSC_KEY */
.flags = IORESOURCE_IRQ,
},
};
@@ -169,10 +195,53 @@ static struct platform_device keysc_device = {
},
};
+/* SDHI */
+static struct resource sdhi0_resources[] = {
+ [0] = {
+ .name = "SDHI0",
+ .start = 0xe6d50000,
+ .end = 0xe6d501ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x0e00), /* SDHI0 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi0_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi0_resources),
+ .resource = sdhi0_resources,
+ .id = 0,
+};
+
+static struct resource sdhi1_resources[] = {
+ [0] = {
+ .name = "SDHI1",
+ .start = 0xe6d60000,
+ .end = 0xe6d601ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x0e80), /* SDHI1 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device sdhi1_device = {
+ .name = "sh_mobile_sdhi",
+ .num_resources = ARRAY_SIZE(sdhi1_resources),
+ .resource = sdhi1_resources,
+ .id = 1,
+};
+
static struct platform_device *g4evm_devices[] __initdata = {
&nor_flash_device,
&usb_host_device,
&keysc_device,
+ &sdhi0_device,
+ &sdhi1_device,
};
static struct map_desc g4evm_io_desc[] __initdata = {
@@ -191,12 +260,41 @@ static void __init g4evm_map_io(void)
{
iotable_init(g4evm_io_desc, ARRAY_SIZE(g4evm_io_desc));
- /* setup early devices, clocks and console here as well */
+ /* setup early devices and console here as well */
sh7377_add_early_devices();
- sh7367_clock_init(); /* use g3 clocks for now */
shmobile_setup_console();
}
+#define GPIO_SDHID0_D0 0xe60520fc
+#define GPIO_SDHID0_D1 0xe60520fd
+#define GPIO_SDHID0_D2 0xe60520fe
+#define GPIO_SDHID0_D3 0xe60520ff
+#define GPIO_SDHICMD0 0xe6052100
+
+#define GPIO_SDHID1_D0 0xe6052103
+#define GPIO_SDHID1_D1 0xe6052104
+#define GPIO_SDHID1_D2 0xe6052105
+#define GPIO_SDHID1_D3 0xe6052106
+#define GPIO_SDHICMD1 0xe6052107
+
+/*
+ * FIXME !!
+ *
+ * gpio_pull_up is quick_hack.
+ *
+ * current gpio frame work doesn't have
+ * the method to control only pull up/down/free.
+ * this function should be replaced by correct gpio function
+ */
+static void __init gpio_pull_up(u32 addr)
+{
+ u8 data = __raw_readb(addr);
+
+ data &= 0x0F;
+ data |= 0xC0;
+ __raw_writeb(data, addr);
+}
+
static void __init g4evm_init(void)
{
sh7377_pinmux_init();
@@ -229,9 +327,6 @@ static void __init g4evm_init(void)
gpio_request(GPIO_FN_EXTLP, NULL);
gpio_request(GPIO_FN_IDIN, NULL);
- /* enable clock in SMSTPCR3 */
- __raw_writel(__raw_readl(0xe615013c) & ~(1 << 22), 0xe615013c);
-
/* setup USB phy */
__raw_writew(0x0200, 0xe605810a); /* USBCR1 */
__raw_writew(0x00e0, 0xe60581c0); /* CPFCH */
@@ -253,16 +348,54 @@ static void __init g4evm_init(void)
gpio_request(GPIO_FN_PORT71_KEYIN5_PU, NULL);
gpio_request(GPIO_FN_PORT72_KEYIN6_PU, NULL);
+ /* SDHI0 */
+ gpio_request(GPIO_FN_SDHICLK0, NULL);
+ gpio_request(GPIO_FN_SDHICD0, NULL);
+ gpio_request(GPIO_FN_SDHID0_0, NULL);
+ gpio_request(GPIO_FN_SDHID0_1, NULL);
+ gpio_request(GPIO_FN_SDHID0_2, NULL);
+ gpio_request(GPIO_FN_SDHID0_3, NULL);
+ gpio_request(GPIO_FN_SDHICMD0, NULL);
+ gpio_request(GPIO_FN_SDHIWP0, NULL);
+ gpio_pull_up(GPIO_SDHID0_D0);
+ gpio_pull_up(GPIO_SDHID0_D1);
+ gpio_pull_up(GPIO_SDHID0_D2);
+ gpio_pull_up(GPIO_SDHID0_D3);
+ gpio_pull_up(GPIO_SDHICMD0);
+
+ /* SDHI1 */
+ gpio_request(GPIO_FN_SDHICLK1, NULL);
+ gpio_request(GPIO_FN_SDHID1_0, NULL);
+ gpio_request(GPIO_FN_SDHID1_1, NULL);
+ gpio_request(GPIO_FN_SDHID1_2, NULL);
+ gpio_request(GPIO_FN_SDHID1_3, NULL);
+ gpio_request(GPIO_FN_SDHICMD1, NULL);
+ gpio_pull_up(GPIO_SDHID1_D0);
+ gpio_pull_up(GPIO_SDHID1_D1);
+ gpio_pull_up(GPIO_SDHID1_D2);
+ gpio_pull_up(GPIO_SDHID1_D3);
+ gpio_pull_up(GPIO_SDHICMD1);
+
sh7377_add_standard_devices();
platform_add_devices(g4evm_devices, ARRAY_SIZE(g4evm_devices));
}
+static void __init g4evm_timer_init(void)
+{
+ sh7377_clock_init();
+ shmobile_timer.init();
+}
+
+static struct sys_timer g4evm_timer = {
+ .init = g4evm_timer_init,
+};
+
MACHINE_START(G4EVM, "g4evm")
.phys_io = 0xe6000000,
.io_pg_offst = ((0xe6000000) >> 18) & 0xfffc,
.map_io = g4evm_map_io,
.init_irq = sh7377_init_irq,
.init_machine = g4evm_init,
- .timer = &shmobile_timer,
+ .timer = &g4evm_timer,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c
index bb940c6e4e6c..b6454c9f2abb 100644
--- a/arch/arm/mach-shmobile/clock-sh7367.c
+++ b/arch/arm/mach-shmobile/clock-sh7367.c
@@ -1,5 +1,5 @@
/*
- * Preliminary clock framework support for sh7367
+ * SH7367 clock framework support
*
* Copyright (C) 2010 Magnus Damm
*
@@ -17,87 +17,342 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <mach/common.h>
+#include <asm/clkdev.h>
+
+/* SH7367 registers */
+#define RTFRQCR 0xe6150000
+#define SYFRQCR 0xe6150004
+#define CMFRQCR 0xe61500E0
+#define VCLKCR1 0xe6150008
+#define VCLKCR2 0xe615000C
+#define VCLKCR3 0xe615001C
+#define SCLKACR 0xe6150010
+#define SCLKBCR 0xe6150014
+#define SUBUSBCKCR 0xe6158080
+#define SPUCKCR 0xe6150084
+#define MSUCKCR 0xe6150088
+#define MVI3CKCR 0xe6150090
+#define VOUCKCR 0xe6150094
+#define MFCK1CR 0xe6150098
+#define MFCK2CR 0xe615009C
+#define PLLC1CR 0xe6150028
+#define PLLC2CR 0xe615002C
+#define RTMSTPCR0 0xe6158030
+#define RTMSTPCR2 0xe6158038
+#define SYMSTPCR0 0xe6158040
+#define SYMSTPCR2 0xe6158048
+#define CMMSTPCR0 0xe615804c
-struct clk {
- const char *name;
- unsigned long rate;
+/* Fixed 32 KHz root clock from EXTALR pin */
+static struct clk r_clk = {
+ .rate = 32768,
};
-#include <asm/clkdev.h>
+/*
+ * 26MHz default rate for the EXTALB1 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7367_extalb1_clk = {
+ .rate = 26666666,
+};
-int __clk_get(struct clk *clk)
-{
- return 1;
-}
-EXPORT_SYMBOL(__clk_get);
+/*
+ * 48MHz default rate for the EXTAL2 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7367_extal2_clk = {
+ .rate = 48000000,
+};
-void __clk_put(struct clk *clk)
+/* A fixed divide-by-2 block */
+static unsigned long div2_recalc(struct clk *clk)
{
+ return clk->parent->rate / 2;
}
-EXPORT_SYMBOL(__clk_put);
+static struct clk_ops div2_clk_ops = {
+ .recalc = div2_recalc,
+};
+
+/* Divide extalb1 by two */
+static struct clk extalb1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7367_extalb1_clk,
+};
+
+/* Divide extal2 by two */
+static struct clk extal2_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7367_extal2_clk,
+};
-int clk_enable(struct clk *clk)
+/* PLLC1 */
+static unsigned long pllc1_recalc(struct clk *clk)
{
- return 0;
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC1CR) & (1 << 14))
+ mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
}
-EXPORT_SYMBOL(clk_enable);
-void clk_disable(struct clk *clk)
+static struct clk_ops pllc1_clk_ops = {
+ .recalc = pllc1_recalc,
+};
+
+static struct clk pllc1_clk = {
+ .ops = &pllc1_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extalb1_div2_clk,
+};
+
+/* Divide PLLC1 by two */
+static struct clk pllc1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &pllc1_clk,
+};
+
+/* PLLC2 */
+static unsigned long pllc2_recalc(struct clk *clk)
{
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC2CR) & (1 << 31))
+ mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
}
-EXPORT_SYMBOL(clk_disable);
-unsigned long clk_get_rate(struct clk *clk)
+static struct clk_ops pllc2_clk_ops = {
+ .recalc = pllc2_recalc,
+};
+
+static struct clk pllc2_clk = {
+ .ops = &pllc2_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extalb1_div2_clk,
+};
+
+static struct clk *main_clks[] = {
+ &r_clk,
+ &sh7367_extalb1_clk,
+ &sh7367_extal2_clk,
+ &extalb1_div2_clk,
+ &extal2_div2_clk,
+ &pllc1_clk,
+ &pllc1_div2_clk,
+ &pllc2_clk,
+};
+
+static void div4_kick(struct clk *clk)
{
- return clk ? clk->rate : 0;
+ unsigned long value;
+
+ /* set KICK bit in SYFRQCR to update hardware setting */
+ value = __raw_readl(SYFRQCR);
+ value |= (1 << 31);
+ __raw_writel(value, SYFRQCR);
}
-EXPORT_SYMBOL(clk_get_rate);
-/* a static peripheral clock for now - enough to get sh-sci working */
-static struct clk peripheral_clk = {
- .name = "peripheral_clk",
- .rate = 48000000,
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
+ 24, 32, 36, 48, 0, 72, 0, 0 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = divisors,
+ .nr_divisors = ARRAY_SIZE(divisors),
};
-/* a static rclk for now - enough to get sh_cmt working */
-static struct clk r_clk = {
- .name = "r_clk",
- .rate = 32768,
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+ .kick = div4_kick,
+};
+
+enum { DIV4_I, DIV4_G, DIV4_S, DIV4_B,
+ DIV4_ZX, DIV4_ZT, DIV4_Z, DIV4_ZD, DIV4_HP,
+ DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
+
+static struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_G] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_S] = DIV4(RTFRQCR, 12, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_ZX] = DIV4(SYFRQCR, 20, 0x6fff, 0),
+ [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0),
+ [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0),
+ [DIV4_ZD] = DIV4(SYFRQCR, 8, 0x6fff, 0),
+ [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0),
+ [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0),
+ [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0),
+ [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0),
+ [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0),
};
-/* a static usb0 for now - enough to get r8a66597 working */
-static struct clk usb0_clk = {
- .name = "usb0",
+enum { DIV6_SUB, DIV6_SIUA, DIV6_SIUB, DIV6_MSU, DIV6_SPU,
+ DIV6_MVI3, DIV6_MF1, DIV6_MF2,
+ DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_VOU,
+ DIV6_NR };
+
+static struct clk div6_clks[DIV6_NR] = {
+ [DIV6_SUB] = SH_CLK_DIV6(&sh7367_extal2_clk, SUBUSBCKCR, 0),
+ [DIV6_SIUA] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKACR, 0),
+ [DIV6_SIUB] = SH_CLK_DIV6(&pllc1_div2_clk, SCLKBCR, 0),
+ [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0),
+ [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
+ [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0),
+ [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0),
+ [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0),
+ [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
+ [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
+ [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
+ [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
};
-/* a static keysc0 clk for now - enough to get sh_keysc working */
-static struct clk keysc0_clk = {
- .name = "keysc0",
+enum { RTMSTP001,
+ RTMSTP231, RTMSTP230, RTMSTP229, RTMSTP228, RTMSTP226,
+ RTMSTP216, RTMSTP206, RTMSTP205, RTMSTP201,
+ SYMSTP023, SYMSTP007, SYMSTP006, SYMSTP004,
+ SYMSTP003, SYMSTP002, SYMSTP001, SYMSTP000,
+ SYMSTP231, SYMSTP229, SYMSTP225, SYMSTP223, SYMSTP222,
+ SYMSTP215, SYMSTP214, SYMSTP213, SYMSTP211,
+ CMMSTP003,
+ MSTP_NR };
+
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
+static struct clk mstp_clks[MSTP_NR] = {
+ [RTMSTP001] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR0, 1, 0), /* IIC2 */
+ [RTMSTP231] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 31, 0), /* VEU3 */
+ [RTMSTP230] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 30, 0), /* VEU2 */
+ [RTMSTP229] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 29, 0), /* VEU1 */
+ [RTMSTP228] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 28, 0), /* VEU0 */
+ [RTMSTP226] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 26, 0), /* VEU2H */
+ [RTMSTP216] = MSTP(&div6_clks[DIV6_SUB], RTMSTPCR2, 16, 0), /* IIC0 */
+ [RTMSTP206] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 6, 0), /* JPU */
+ [RTMSTP205] = MSTP(&div6_clks[DIV6_VOU], RTMSTPCR2, 5, 0), /* VOU */
+ [RTMSTP201] = MSTP(&div4_clks[DIV4_B], RTMSTPCR2, 1, 0), /* VPU */
+ [SYMSTP023] = MSTP(&div6_clks[DIV6_SPU], SYMSTPCR0, 23, 0), /* SPU1 */
+ [SYMSTP007] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 7, 0), /* SCIFA5 */
+ [SYMSTP006] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 6, 0), /* SCIFB */
+ [SYMSTP004] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 4, 0), /* SCIFA0 */
+ [SYMSTP003] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 3, 0), /* SCIFA1 */
+ [SYMSTP002] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 2, 0), /* SCIFA2 */
+ [SYMSTP001] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 1, 0), /* SCIFA3 */
+ [SYMSTP000] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR0, 0, 0), /* SCIFA4 */
+ [SYMSTP231] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 31, 0), /* SIU */
+ [SYMSTP229] = MSTP(&r_clk, SYMSTPCR2, 29, 0), /* CMT10 */
+ [SYMSTP225] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 25, 0), /* IRDA */
+ [SYMSTP223] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 23, 0), /* IIC1 */
+ [SYMSTP222] = MSTP(&div6_clks[DIV6_SUB], SYMSTPCR2, 22, 0), /* USBHS */
+ [SYMSTP215] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 15, 0), /* FLCTL */
+ [SYMSTP214] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 14, 0), /* SDHI0 */
+ [SYMSTP213] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 13, 0), /* SDHI1 */
+ [SYMSTP211] = MSTP(&div4_clks[DIV4_HP], SYMSTPCR2, 11, 0), /* SDHI2 */
+ [CMMSTP003] = MSTP(&r_clk, CMMSTPCR0, 3, 0), /* KEYSC */
};
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
+#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+
static struct clk_lookup lookups[] = {
- {
- .clk = &peripheral_clk,
- }, {
- .clk = &r_clk,
- }, {
- .clk = &usb0_clk,
- }, {
- .clk = &keysc0_clk,
- }
+ /* main clocks */
+ CLKDEV_CON_ID("r_clk", &r_clk),
+ CLKDEV_CON_ID("extalb1", &sh7367_extalb1_clk),
+ CLKDEV_CON_ID("extal2", &sh7367_extal2_clk),
+ CLKDEV_CON_ID("extalb1_div2_clk", &extalb1_div2_clk),
+ CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
+ CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
+ CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
+ CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("g_clk", &div4_clks[DIV4_G]),
+ CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]),
+ CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
+ CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]),
+ CLKDEV_CON_ID("zd_clk", &div4_clks[DIV4_ZD]),
+ CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
+ CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]),
+ CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
+ CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
+ CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
+
+ /* DIV6 clocks */
+ CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
+ CLKDEV_CON_ID("siua_clk", &div6_clks[DIV6_SIUA]),
+ CLKDEV_CON_ID("siub_clk", &div6_clks[DIV6_SIUB]),
+ CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]),
+ CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
+ CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]),
+ CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]),
+ CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]),
+ CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
+ CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
+ CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+ CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
+
+ /* MSTP32 clocks */
+ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[RTMSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[RTMSTP231]), /* VEU3 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[RTMSTP230]), /* VEU2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[RTMSTP229]), /* VEU1 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[RTMSTP228]), /* VEU0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[RTMSTP226]), /* VEU2H */
+ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[RTMSTP216]), /* IIC0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[RTMSTP206]), /* JPU */
+ CLKDEV_DEV_ID("sh-vou", &mstp_clks[RTMSTP205]), /* VOU */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[RTMSTP201]), /* VPU */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[SYMSTP023]), /* SPU1 */
+ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[SYMSTP007]), /* SCIFA5 */
+ CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[SYMSTP006]), /* SCIFB */
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[SYMSTP004]), /* SCIFA0 */
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[SYMSTP003]), /* SCIFA1 */
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[SYMSTP002]), /* SCIFA2 */
+ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */
+ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */
+ CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */
+ CLKDEV_CON_ID("cmt1", &mstp_clks[SYMSTP229]), /* CMT10 */
+ CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */
+ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */
+ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */
+ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[SYMSTP222]), /* USBHS */
+ CLKDEV_DEV_ID("sh_flctl", &mstp_clks[SYMSTP215]), /* FLCTL */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[SYMSTP214]), /* SDHI0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[SYMSTP213]), /* SDHI1 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[SYMSTP211]), /* SDHI2 */
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[CMMSTP003]), /* KEYSC */
};
void __init sh7367_clock_init(void)
{
- int i;
+ int k, ret = 0;
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+ if (!ret)
+ ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
- for (i = 0; i < ARRAY_SIZE(lookups); i++) {
- lookups[i].con_id = lookups[i].clk->name;
- clkdev_add(&lookups[i]);
- }
+ if (!ret)
+ clk_init();
+ else
+ panic("failed to setup sh7367 clocks\n");
}
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
new file mode 100644
index 000000000000..241caea32260
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -0,0 +1,399 @@
+/*
+ * SH7372 clock framework support
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <mach/common.h>
+#include <asm/clkdev.h>
+
+/* SH7372 registers */
+#define FRQCRA 0xe6150000
+#define FRQCRB 0xe6150004
+#define FRQCRC 0xe61500e0
+#define FRQCRD 0xe61500e4
+#define VCLKCR1 0xe6150008
+#define VCLKCR2 0xe615000c
+#define VCLKCR3 0xe615001c
+#define FMSICKCR 0xe6150010
+#define FMSOCKCR 0xe6150014
+#define FSIACKCR 0xe6150018
+#define FSIBCKCR 0xe6150090
+#define SUBCKCR 0xe6150080
+#define SPUCKCR 0xe6150084
+#define VOUCKCR 0xe6150088
+#define HDMICKCR 0xe6150094
+#define DSITCKCR 0xe6150060
+#define DSI0PCKCR 0xe6150064
+#define DSI1PCKCR 0xe6150098
+#define PLLC01CR 0xe6150028
+#define PLLC2CR 0xe615002c
+#define SMSTPCR0 0xe6150130
+#define SMSTPCR1 0xe6150134
+#define SMSTPCR2 0xe6150138
+#define SMSTPCR3 0xe615013c
+#define SMSTPCR4 0xe6150140
+
+/* Fixed 32 KHz root clock from EXTALR pin */
+static struct clk r_clk = {
+ .rate = 32768,
+};
+
+/*
+ * 26MHz default rate for the EXTAL1 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7372_extal1_clk = {
+ .rate = 26666666,
+};
+
+/*
+ * 48MHz default rate for the EXTAL2 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7372_extal2_clk = {
+ .rate = 48000000,
+};
+
+/* A fixed divide-by-2 block */
+static unsigned long div2_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 2;
+}
+
+static struct clk_ops div2_clk_ops = {
+ .recalc = div2_recalc,
+};
+
+/* Divide extal1 by two */
+static struct clk extal1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7372_extal1_clk,
+};
+
+/* Divide extal2 by two */
+static struct clk extal2_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7372_extal2_clk,
+};
+
+/* Divide extal2 by four */
+static struct clk extal2_div4_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &extal2_div2_clk,
+};
+
+/* PLLC0 and PLLC1 */
+static unsigned long pllc01_recalc(struct clk *clk)
+{
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC01CR) & (1 << 14))
+ mult = (((__raw_readl(clk->enable_reg) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
+}
+
+static struct clk_ops pllc01_clk_ops = {
+ .recalc = pllc01_recalc,
+};
+
+static struct clk pllc0_clk = {
+ .ops = &pllc01_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extal1_div2_clk,
+ .enable_reg = (void __iomem *)FRQCRC,
+};
+
+static struct clk pllc1_clk = {
+ .ops = &pllc01_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extal1_div2_clk,
+ .enable_reg = (void __iomem *)FRQCRA,
+};
+
+/* Divide PLLC1 by two */
+static struct clk pllc1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &pllc1_clk,
+};
+
+/* PLLC2 */
+static unsigned long pllc2_recalc(struct clk *clk)
+{
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC2CR) & (1 << 31))
+ mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
+}
+
+static struct clk_ops pllc2_clk_ops = {
+ .recalc = pllc2_recalc,
+};
+
+static struct clk pllc2_clk = {
+ .ops = &pllc2_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extal1_div2_clk,
+};
+
+static struct clk *main_clks[] = {
+ &r_clk,
+ &sh7372_extal1_clk,
+ &sh7372_extal2_clk,
+ &extal1_div2_clk,
+ &extal2_div2_clk,
+ &extal2_div4_clk,
+ &pllc0_clk,
+ &pllc1_clk,
+ &pllc1_div2_clk,
+ &pllc2_clk,
+};
+
+static void div4_kick(struct clk *clk)
+{
+ unsigned long value;
+
+ /* set KICK bit in FRQCRB to update hardware setting */
+ value = __raw_readl(FRQCRB);
+ value |= (1 << 31);
+ __raw_writel(value, FRQCRB);
+}
+
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
+ 24, 32, 36, 48, 0, 72, 96, 0 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = divisors,
+ .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+ .kick = div4_kick,
+};
+
+enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR,
+ DIV4_ZTR, DIV4_ZT, DIV4_ZX, DIV4_HP,
+ DIV4_ISPB, DIV4_S, DIV4_ZB, DIV4_ZB3, DIV4_CP,
+ DIV4_DDRP, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
+
+static struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(FRQCRA, 20, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_ZG] = DIV4(FRQCRA, 16, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(FRQCRA, 8, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_M1] = DIV4(FRQCRA, 4, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_CSIR] = DIV4(FRQCRA, 0, 0x6fff, 0),
+ [DIV4_ZTR] = DIV4(FRQCRB, 20, 0x6fff, 0),
+ [DIV4_ZT] = DIV4(FRQCRB, 16, 0x6fff, 0),
+ [DIV4_ZX] = DIV4(FRQCRB, 12, 0x6fff, 0),
+ [DIV4_HP] = DIV4(FRQCRB, 4, 0x6fff, 0),
+ [DIV4_ISPB] = DIV4(FRQCRC, 20, 0x6fff, 0),
+ [DIV4_S] = DIV4(FRQCRC, 12, 0x6fff, 0),
+ [DIV4_ZB] = DIV4(FRQCRC, 8, 0x6fff, 0),
+ [DIV4_ZB3] = DIV4(FRQCRC, 4, 0x6fff, 0),
+ [DIV4_CP] = DIV4(FRQCRC, 0, 0x6fff, 0),
+ [DIV4_DDRP] = DIV4(FRQCRD, 0, 0x677c, 0),
+};
+
+enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
+ DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU,
+ DIV6_VOU, DIV6_HDMI, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P,
+ DIV6_NR };
+
+static struct clk div6_clks[DIV6_NR] = {
+ [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
+ [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
+ [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
+ [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0),
+ [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0),
+ [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0),
+ [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0),
+ [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0),
+ [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
+ [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0),
+ [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
+ [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
+ [DIV6_DSI0P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI0PCKCR, 0),
+ [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0),
+};
+
+enum { MSTP001,
+ MSTP131, MSTP130,
+ MSTP129, MSTP128,
+ MSTP118, MSTP117, MSTP116,
+ MSTP106, MSTP101, MSTP100,
+ MSTP223,
+ MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+ MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
+ MSTP415, MSTP410, MSTP411, MSTP406, MSTP403,
+ MSTP_NR };
+
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
+static struct clk mstp_clks[MSTP_NR] = {
+ [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
+ [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
+ [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
+ [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
+ [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */
+ [MSTP118] = MSTP(&div6_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */
+ [MSTP117] = MSTP(&div6_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */
+ [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+ [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
+ [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
+ [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
+ [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
+ [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
+ [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
+ [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
+ [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
+ [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
+ [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
+ [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
+ [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+ [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, CLK_ENABLE_ON_INIT), /* FSIA */
+ [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
+ [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
+ [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
+ [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
+ [MSTP312] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 12, 0), /* MMC */
+ [MSTP415] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 15, 0), /* SDHI2 */
+ [MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
+ [MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
+ [MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
+ [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
+};
+
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
+#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+
+static struct clk_lookup lookups[] = {
+ /* main clocks */
+ CLKDEV_CON_ID("r_clk", &r_clk),
+ CLKDEV_CON_ID("extal1", &sh7372_extal1_clk),
+ CLKDEV_CON_ID("extal2", &sh7372_extal2_clk),
+ CLKDEV_CON_ID("extal1_div2_clk", &extal1_div2_clk),
+ CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
+ CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk),
+ CLKDEV_CON_ID("pllc0_clk", &pllc0_clk),
+ CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
+ CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
+ CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]),
+ CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]),
+ CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]),
+ CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]),
+ CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
+ CLKDEV_CON_ID("zx_clk", &div4_clks[DIV4_ZX]),
+ CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
+ CLKDEV_CON_ID("ispb_clk", &div4_clks[DIV4_ISPB]),
+ CLKDEV_CON_ID("s_clk", &div4_clks[DIV4_S]),
+ CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
+ CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
+ CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
+ CLKDEV_CON_ID("ddrp_clk", &div4_clks[DIV4_DDRP]),
+
+ /* DIV6 clocks */
+ CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
+ CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
+ CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+ CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
+ CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
+ CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]),
+ CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]),
+ CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
+ CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
+ CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]),
+ CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
+ CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
+ CLKDEV_CON_ID("dsi0p_clk", &div6_clks[DIV6_DSI0P]),
+ CLKDEV_CON_ID("dsi1p_clk", &div6_clks[DIV6_DSI1P]),
+
+ /* MSTP32 clocks */
+ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */
+ CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */
+ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */
+ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
+ CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
+ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
+ CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
+ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
+ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
+ CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
+ CLKDEV_DEV_ID("sh_fsi", &mstp_clks[MSTP328]), /* FSI */
+ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
+ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */
+ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP323]), /* USB0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
+ CLKDEV_DEV_ID("sh_mmcif.0", &mstp_clks[MSTP312]), /* MMC */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP415]), /* SDHI2 */
+ CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
+ CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
+ CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
+ CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
+};
+
+void __init sh7372_clock_init(void)
+{
+ int k, ret = 0;
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+ if (!ret)
+ ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ if (!ret)
+ clk_init();
+ else
+ panic("failed to setup sh7372 clocks\n");
+
+}
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c
new file mode 100644
index 000000000000..e007c28cf0a8
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock-sh7377.c
@@ -0,0 +1,369 @@
+/*
+ * SH7377 clock framework support
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/sh_clk.h>
+#include <mach/common.h>
+#include <asm/clkdev.h>
+
+/* SH7377 registers */
+#define RTFRQCR 0xe6150000
+#define SYFRQCR 0xe6150004
+#define CMFRQCR 0xe61500E0
+#define VCLKCR1 0xe6150008
+#define VCLKCR2 0xe615000C
+#define VCLKCR3 0xe615001C
+#define FMSICKCR 0xe6150010
+#define FMSOCKCR 0xe6150014
+#define FSICKCR 0xe6150018
+#define PLLC1CR 0xe6150028
+#define PLLC2CR 0xe615002C
+#define SUBUSBCKCR 0xe6150080
+#define SPUCKCR 0xe6150084
+#define MSUCKCR 0xe6150088
+#define MVI3CKCR 0xe6150090
+#define HDMICKCR 0xe6150094
+#define MFCK1CR 0xe6150098
+#define MFCK2CR 0xe615009C
+#define DSITCKCR 0xe6150060
+#define DSIPCKCR 0xe6150064
+#define SMSTPCR0 0xe6150130
+#define SMSTPCR1 0xe6150134
+#define SMSTPCR2 0xe6150138
+#define SMSTPCR3 0xe615013C
+#define SMSTPCR4 0xe6150140
+
+/* Fixed 32 KHz root clock from EXTALR pin */
+static struct clk r_clk = {
+ .rate = 32768,
+};
+
+/*
+ * 26MHz default rate for the EXTALC1 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7377_extalc1_clk = {
+ .rate = 26666666,
+};
+
+/*
+ * 48MHz default rate for the EXTAL2 root input clock.
+ * If needed, reset this with clk_set_rate() from the platform code.
+ */
+struct clk sh7377_extal2_clk = {
+ .rate = 48000000,
+};
+
+/* A fixed divide-by-2 block */
+static unsigned long div2_recalc(struct clk *clk)
+{
+ return clk->parent->rate / 2;
+}
+
+static struct clk_ops div2_clk_ops = {
+ .recalc = div2_recalc,
+};
+
+/* Divide extalc1 by two */
+static struct clk extalc1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7377_extalc1_clk,
+};
+
+/* Divide extal2 by two */
+static struct clk extal2_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &sh7377_extal2_clk,
+};
+
+/* Divide extal2 by four */
+static struct clk extal2_div4_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &extal2_div2_clk,
+};
+
+/* PLLC1 */
+static unsigned long pllc1_recalc(struct clk *clk)
+{
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC1CR) & (1 << 14))
+ mult = (((__raw_readl(RTFRQCR) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
+}
+
+static struct clk_ops pllc1_clk_ops = {
+ .recalc = pllc1_recalc,
+};
+
+static struct clk pllc1_clk = {
+ .ops = &pllc1_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extalc1_div2_clk,
+};
+
+/* Divide PLLC1 by two */
+static struct clk pllc1_div2_clk = {
+ .ops = &div2_clk_ops,
+ .parent = &pllc1_clk,
+};
+
+/* PLLC2 */
+static unsigned long pllc2_recalc(struct clk *clk)
+{
+ unsigned long mult = 1;
+
+ if (__raw_readl(PLLC2CR) & (1 << 31))
+ mult = (((__raw_readl(PLLC2CR) >> 24) & 0x3f) + 1) * 2;
+
+ return clk->parent->rate * mult;
+}
+
+static struct clk_ops pllc2_clk_ops = {
+ .recalc = pllc2_recalc,
+};
+
+static struct clk pllc2_clk = {
+ .ops = &pllc2_clk_ops,
+ .flags = CLK_ENABLE_ON_INIT,
+ .parent = &extalc1_div2_clk,
+};
+
+static struct clk *main_clks[] = {
+ &r_clk,
+ &sh7377_extalc1_clk,
+ &sh7377_extal2_clk,
+ &extalc1_div2_clk,
+ &extal2_div2_clk,
+ &extal2_div4_clk,
+ &pllc1_clk,
+ &pllc1_div2_clk,
+ &pllc2_clk,
+};
+
+static void div4_kick(struct clk *clk)
+{
+ unsigned long value;
+
+ /* set KICK bit in SYFRQCR to update hardware setting */
+ value = __raw_readl(SYFRQCR);
+ value |= (1 << 31);
+ __raw_writel(value, SYFRQCR);
+}
+
+static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18,
+ 24, 32, 36, 48, 0, 72, 96, 0 };
+
+static struct clk_div_mult_table div4_div_mult_table = {
+ .divisors = divisors,
+ .nr_divisors = ARRAY_SIZE(divisors),
+};
+
+static struct clk_div4_table div4_table = {
+ .div_mult_table = &div4_div_mult_table,
+ .kick = div4_kick,
+};
+
+enum { DIV4_I, DIV4_ZG, DIV4_B, DIV4_M1, DIV4_CSIR,
+ DIV4_ZTR, DIV4_ZT, DIV4_Z, DIV4_HP,
+ DIV4_ZS, DIV4_ZB, DIV4_ZB3, DIV4_CP, DIV4_NR };
+
+#define DIV4(_reg, _bit, _mask, _flags) \
+ SH_CLK_DIV4(&pllc1_clk, _reg, _bit, _mask, _flags)
+
+static struct clk div4_clks[DIV4_NR] = {
+ [DIV4_I] = DIV4(RTFRQCR, 20, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_ZG] = DIV4(RTFRQCR, 16, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_B] = DIV4(RTFRQCR, 8, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_M1] = DIV4(RTFRQCR, 4, 0x6fff, CLK_ENABLE_ON_INIT),
+ [DIV4_CSIR] = DIV4(RTFRQCR, 0, 0x6fff, 0),
+ [DIV4_ZTR] = DIV4(SYFRQCR, 20, 0x6fff, 0),
+ [DIV4_ZT] = DIV4(SYFRQCR, 16, 0x6fff, 0),
+ [DIV4_Z] = DIV4(SYFRQCR, 12, 0x6fff, 0),
+ [DIV4_HP] = DIV4(SYFRQCR, 4, 0x6fff, 0),
+ [DIV4_ZS] = DIV4(CMFRQCR, 12, 0x6fff, 0),
+ [DIV4_ZB] = DIV4(CMFRQCR, 8, 0x6fff, 0),
+ [DIV4_ZB3] = DIV4(CMFRQCR, 4, 0x6fff, 0),
+ [DIV4_CP] = DIV4(CMFRQCR, 0, 0x6fff, 0),
+};
+
+enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO,
+ DIV6_FSI, DIV6_SUB, DIV6_SPU, DIV6_MSU, DIV6_MVI3, DIV6_HDMI,
+ DIV6_MF1, DIV6_MF2, DIV6_DSIT, DIV6_DSIP,
+ DIV6_NR };
+
+static struct clk div6_clks[] = {
+ [DIV6_VCK1] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR1, 0),
+ [DIV6_VCK2] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR2, 0),
+ [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0),
+ [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0),
+ [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0),
+ [DIV6_FSI] = SH_CLK_DIV6(&pllc1_div2_clk, FSICKCR, 0),
+ [DIV6_SUB] = SH_CLK_DIV6(&sh7377_extal2_clk, SUBUSBCKCR, 0),
+ [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0),
+ [DIV6_MSU] = SH_CLK_DIV6(&pllc1_div2_clk, MSUCKCR, 0),
+ [DIV6_MVI3] = SH_CLK_DIV6(&pllc1_div2_clk, MVI3CKCR, 0),
+ [DIV6_HDMI] = SH_CLK_DIV6(&pllc1_div2_clk, HDMICKCR, 0),
+ [DIV6_MF1] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK1CR, 0),
+ [DIV6_MF2] = SH_CLK_DIV6(&pllc1_div2_clk, MFCK2CR, 0),
+ [DIV6_DSIT] = SH_CLK_DIV6(&pllc1_div2_clk, DSITCKCR, 0),
+ [DIV6_DSIP] = SH_CLK_DIV6(&pllc1_div2_clk, DSIPCKCR, 0),
+};
+
+enum { MSTP001,
+ MSTP131, MSTP130, MSTP129, MSTP128, MSTP116, MSTP106, MSTP101,
+ MSTP223, MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+ MSTP331, MSTP329, MSTP325, MSTP323, MSTP322,
+ MSTP315, MSTP314, MSTP313,
+ MSTP403,
+ MSTP_NR };
+
+#define MSTP(_parent, _reg, _bit, _flags) \
+ SH_CLK_MSTP32(_parent, _reg, _bit, _flags)
+
+static struct clk mstp_clks[] = {
+ [MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
+ [MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
+ [MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
+ [MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
+ [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */
+ [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */
+ [MSTP106] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 6, 0), /* JPU */
+ [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
+ [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
+ [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
+ [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
+ [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
+ [MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
+ [MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
+ [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
+ [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
+ [MSTP331] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 31, 0), /* SCIFA6 */
+ [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
+ [MSTP325] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 25, 0), /* IRDA */
+ [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
+ [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
+ [MSTP315] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 15, 0), /* FLCTL */
+ [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */
+ [MSTP313] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 13, 0), /* SDHI1 */
+ [MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
+};
+
+#define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk }
+#define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk }
+
+static struct clk_lookup lookups[] = {
+ /* main clocks */
+ CLKDEV_CON_ID("r_clk", &r_clk),
+ CLKDEV_CON_ID("extalc1", &sh7377_extalc1_clk),
+ CLKDEV_CON_ID("extal2", &sh7377_extal2_clk),
+ CLKDEV_CON_ID("extalc1_div2_clk", &extalc1_div2_clk),
+ CLKDEV_CON_ID("extal2_div2_clk", &extal2_div2_clk),
+ CLKDEV_CON_ID("extal2_div4_clk", &extal2_div4_clk),
+ CLKDEV_CON_ID("pllc1_clk", &pllc1_clk),
+ CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk),
+ CLKDEV_CON_ID("pllc2_clk", &pllc2_clk),
+
+ /* DIV4 clocks */
+ CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]),
+ CLKDEV_CON_ID("zg_clk", &div4_clks[DIV4_ZG]),
+ CLKDEV_CON_ID("b_clk", &div4_clks[DIV4_B]),
+ CLKDEV_CON_ID("m1_clk", &div4_clks[DIV4_M1]),
+ CLKDEV_CON_ID("csir_clk", &div4_clks[DIV4_CSIR]),
+ CLKDEV_CON_ID("ztr_clk", &div4_clks[DIV4_ZTR]),
+ CLKDEV_CON_ID("zt_clk", &div4_clks[DIV4_ZT]),
+ CLKDEV_CON_ID("z_clk", &div4_clks[DIV4_Z]),
+ CLKDEV_CON_ID("hp_clk", &div4_clks[DIV4_HP]),
+ CLKDEV_CON_ID("zs_clk", &div4_clks[DIV4_ZS]),
+ CLKDEV_CON_ID("zb_clk", &div4_clks[DIV4_ZB]),
+ CLKDEV_CON_ID("zb3_clk", &div4_clks[DIV4_ZB3]),
+ CLKDEV_CON_ID("cp_clk", &div4_clks[DIV4_CP]),
+
+ /* DIV6 clocks */
+ CLKDEV_CON_ID("vck1_clk", &div6_clks[DIV6_VCK1]),
+ CLKDEV_CON_ID("vck2_clk", &div6_clks[DIV6_VCK2]),
+ CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]),
+ CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]),
+ CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]),
+ CLKDEV_CON_ID("fsi_clk", &div6_clks[DIV6_FSI]),
+ CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]),
+ CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]),
+ CLKDEV_CON_ID("msu_clk", &div6_clks[DIV6_MSU]),
+ CLKDEV_CON_ID("mvi3_clk", &div6_clks[DIV6_MVI3]),
+ CLKDEV_CON_ID("hdmi_clk", &div6_clks[DIV6_HDMI]),
+ CLKDEV_CON_ID("mf1_clk", &div6_clks[DIV6_MF1]),
+ CLKDEV_CON_ID("mf2_clk", &div6_clks[DIV6_MF2]),
+ CLKDEV_CON_ID("dsit_clk", &div6_clks[DIV6_DSIT]),
+ CLKDEV_CON_ID("dsip_clk", &div6_clks[DIV6_DSIP]),
+
+ /* MSTP32 clocks */
+ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */
+ CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.5", &mstp_clks[MSTP106]), /* JPU */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.0", &mstp_clks[MSTP101]), /* VPU */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
+ CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
+ CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
+ CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP206]), /* SCIFB */
+ CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
+ CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
+ CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
+ CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
+ CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
+ CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */
+ CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */
+ CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */
+ CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
+ CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */
+ CLKDEV_DEV_ID("r8a66597_udc.0", &mstp_clks[MSTP322]), /* USBHS */
+ CLKDEV_DEV_ID("sh_flctl", &mstp_clks[MSTP315]), /* FLCTL */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]), /* SDHI0 */
+ CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP313]), /* SDHI1 */
+ CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
+};
+
+void __init sh7377_clock_init(void)
+{
+ int k, ret = 0;
+
+ for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
+ ret = clk_register(main_clks[k]);
+
+ if (!ret)
+ ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
+
+ if (!ret)
+ ret = sh_clk_div6_register(div6_clks, DIV6_NR);
+
+ if (!ret)
+ ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR);
+
+ clkdev_add_table(lookups, ARRAY_SIZE(lookups));
+
+ if (!ret)
+ clk_init();
+ else
+ panic("failed to setup sh7377 clocks\n");
+}
diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c
new file mode 100644
index 000000000000..b7c705a213a2
--- /dev/null
+++ b/arch/arm/mach-shmobile/clock.c
@@ -0,0 +1,44 @@
+/*
+ * SH-Mobile Timer
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sh_clk.h>
+
+int __init clk_init(void)
+{
+ /* Kick the child clocks.. */
+ recalculate_root_clocks();
+
+ /* Enable the necessary init clocks */
+ clk_enable_init_clocks();
+
+ return 0;
+}
+
+int __clk_get(struct clk *clk)
+{
+ return 1;
+}
+EXPORT_SYMBOL(__clk_get);
+
+void __clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(__clk_put);
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 57903605cc51..efeef778a875 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -3,21 +3,31 @@
extern struct sys_timer shmobile_timer;
extern void shmobile_setup_console(void);
+struct clk;
+extern int clk_init(void);
extern void sh7367_init_irq(void);
extern void sh7367_add_early_devices(void);
extern void sh7367_add_standard_devices(void);
extern void sh7367_clock_init(void);
extern void sh7367_pinmux_init(void);
+extern struct clk sh7367_extalb1_clk;
+extern struct clk sh7367_extal2_clk;
extern void sh7377_init_irq(void);
extern void sh7377_add_early_devices(void);
extern void sh7377_add_standard_devices(void);
+extern void sh7377_clock_init(void);
extern void sh7377_pinmux_init(void);
+extern struct clk sh7377_extalc1_clk;
+extern struct clk sh7377_extal2_clk;
extern void sh7372_init_irq(void);
extern void sh7372_add_early_devices(void);
extern void sh7372_add_standard_devices(void);
+extern void sh7372_clock_init(void);
extern void sh7372_pinmux_init(void);
+extern struct clk sh7372_extal1_clk;
+extern struct clk sh7372_extal2_clk;
#endif /* __ARCH_MACH_COMMON_H */
diff --git a/arch/arm/mach-shmobile/include/mach/irqs.h b/arch/arm/mach-shmobile/include/mach/irqs.h
index 5179b72e1ee3..e881797648a9 100644
--- a/arch/arm/mach-shmobile/include/mach/irqs.h
+++ b/arch/arm/mach-shmobile/include/mach/irqs.h
@@ -4,7 +4,13 @@
#define NR_IRQS 512
#define NR_IRQS_LEGACY 8
+/* INTCA */
#define evt2irq(evt) (((evt) >> 5) - 16)
#define irq2evt(irq) (((irq) + 16) << 5)
+/* INTCS */
+#define INTCS_VECT_BASE 0x2200
+#define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect))
+#define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt))
+
#endif /* __ASM_MACH_IRQS_H */
diff --git a/arch/arm/mach-shmobile/include/mach/memory.h b/arch/arm/mach-shmobile/include/mach/memory.h
index e188183f4dce..377584e57e03 100644
--- a/arch/arm/mach-shmobile/include/mach/memory.h
+++ b/arch/arm/mach-shmobile/include/mach/memory.h
@@ -4,4 +4,7 @@
#define PHYS_OFFSET UL(CONFIG_MEMORY_START)
#define MEM_SIZE UL(CONFIG_MEMORY_SIZE)
+/* DMA memory at 0xf6000000 - 0xffdfffff */
+#define CONSISTENT_DMA_SIZE (158 << 20)
+
#endif /* __ASM_MACH_MEMORY_H */
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index dc34f00c56b8..c2d2d811059c 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -431,4 +431,28 @@ enum {
GPIO_FN_SDENC_DV_CLKI,
};
+/* DMA slave IDs */
+enum {
+ SHDMA_SLAVE_SCIF0_TX,
+ SHDMA_SLAVE_SCIF0_RX,
+ SHDMA_SLAVE_SCIF1_TX,
+ SHDMA_SLAVE_SCIF1_RX,
+ SHDMA_SLAVE_SCIF2_TX,
+ SHDMA_SLAVE_SCIF2_RX,
+ SHDMA_SLAVE_SCIF3_TX,
+ SHDMA_SLAVE_SCIF3_RX,
+ SHDMA_SLAVE_SCIF4_TX,
+ SHDMA_SLAVE_SCIF4_RX,
+ SHDMA_SLAVE_SCIF5_TX,
+ SHDMA_SLAVE_SCIF5_RX,
+ SHDMA_SLAVE_SCIF6_TX,
+ SHDMA_SLAVE_SCIF6_RX,
+ SHDMA_SLAVE_SDHI0_RX,
+ SHDMA_SLAVE_SDHI0_TX,
+ SHDMA_SLAVE_SDHI1_RX,
+ SHDMA_SLAVE_SDHI1_TX,
+ SHDMA_SLAVE_SDHI2_RX,
+ SHDMA_SLAVE_SDHI2_TX,
+};
+
#endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/include/mach/vmalloc.h b/arch/arm/mach-shmobile/include/mach/vmalloc.h
index fb3c4f1ab252..4aecf6e3a859 100644
--- a/arch/arm/mach-shmobile/include/mach/vmalloc.h
+++ b/arch/arm/mach-shmobile/include/mach/vmalloc.h
@@ -1,6 +1,7 @@
#ifndef __ASM_MACH_VMALLOC_H
#define __ASM_MACH_VMALLOC_H
-#define VMALLOC_END (PAGE_OFFSET + 0x24000000)
+/* Vmalloc at ... - 0xe5ffffff */
+#define VMALLOC_END 0xe6000000
#endif /* __ASM_MACH_VMALLOC_H */
diff --git a/arch/arm/mach-shmobile/intc-sh7367.c b/arch/arm/mach-shmobile/intc-sh7367.c
index 5ff70cadfc32..1a20c489b20d 100644
--- a/arch/arm/mach-shmobile/intc-sh7367.c
+++ b/arch/arm/mach-shmobile/intc-sh7367.c
@@ -75,7 +75,7 @@ enum {
ETM11, ARM11, USBHS, FLCTL, IIC1
};
-static struct intc_vect intca_vectors[] = {
+static struct intc_vect intca_vectors[] __initdata = {
INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220),
INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260),
INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0),
@@ -162,7 +162,7 @@ static struct intc_group intca_groups[] __initdata = {
INTC_GROUP(IIC1, IIC1_ALI1, IIC1_TACKI1, IIC1_WAITI1, IIC1_DTEI1),
};
-static struct intc_mask_reg intca_mask_registers[] = {
+static struct intc_mask_reg intca_mask_registers[] __initdata = {
{ 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */
{ IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } },
{ 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */
@@ -211,7 +211,7 @@ static struct intc_mask_reg intca_mask_registers[] = {
MISTY, CMT3, RWDT1, RWDT0 } },
};
-static struct intc_prio_reg intca_prio_registers[] = {
+static struct intc_prio_reg intca_prio_registers[] __initdata = {
{ 0xe6900010, 0, 32, 4, /* INTPRI00A */
{ IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } },
{ 0xe6900014, 0, 32, 4, /* INTPRI10A */
@@ -263,8 +263,178 @@ static struct intc_desc intca_desc __initdata = {
intca_sense_registers, intca_ack_registers),
};
+enum {
+ UNUSED_INTCS = 0,
+
+ INTCS,
+
+ /* interrupt sources INTCS */
+ VIO2_VEU0, VIO2_VEU1, VIO2_VEU2, VIO2_VEU3,
+ VIO3_VOU,
+ RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3,
+ VIO1_CEU, VIO1_BEU0, VIO1_BEU1, VIO1_BEU2,
+ VPU,
+ SGX530,
+ _2DDMAC_2DDM0, _2DDMAC_2DDM1, _2DDMAC_2DDM2, _2DDMAC_2DDM3,
+ IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
+ IPMMU_IPMMUB, IPMMU_IPMMUS,
+ RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR,
+ MSIOF,
+ IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0,
+ TMU_TUNI0, TMU_TUNI1, TMU_TUNI2,
+ CMT,
+ TSIF,
+ IPMMUI,
+ MVI3,
+ ICB,
+ PEP,
+ ASA,
+ BEM,
+ VE2HO,
+ HQE,
+ JPEG,
+ LCDC,
+
+ /* interrupt groups INTCS */
+ _2DDMAC, RTDMAC_1, RTDMAC_2, VEU, BEU, IIC0, IPMMU, IIC2,
+};
+
+static struct intc_vect intcs_vectors[] = {
+ INTCS_VECT(VIO2_VEU0, 0x700), INTCS_VECT(VIO2_VEU1, 0x720),
+ INTCS_VECT(VIO2_VEU2, 0x740), INTCS_VECT(VIO2_VEU3, 0x760),
+ INTCS_VECT(VIO3_VOU, 0x780),
+ INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820),
+ INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860),
+ INTCS_VECT(VIO1_CEU, 0x880), INTCS_VECT(VIO1_BEU0, 0x8a0),
+ INTCS_VECT(VIO1_BEU1, 0x8c0), INTCS_VECT(VIO1_BEU2, 0x8e0),
+ INTCS_VECT(VPU, 0x980),
+ INTCS_VECT(SGX530, 0x9e0),
+ INTCS_VECT(_2DDMAC_2DDM0, 0xa00), INTCS_VECT(_2DDMAC_2DDM1, 0xa20),
+ INTCS_VECT(_2DDMAC_2DDM2, 0xa40), INTCS_VECT(_2DDMAC_2DDM3, 0xa60),
+ INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0),
+ INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0),
+ INTCS_VECT(IPMMU_IPMMUB, 0xb20), INTCS_VECT(IPMMU_IPMMUS, 0xb60),
+ INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0),
+ INTCS_VECT(RTDMAC_2_DADERR, 0xbc0),
+ INTCS_VECT(MSIOF, 0xd20),
+ INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20),
+ INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60),
+ INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0),
+ INTCS_VECT(TMU_TUNI2, 0xec0),
+ INTCS_VECT(CMT, 0xf00),
+ INTCS_VECT(TSIF, 0xf20),
+ INTCS_VECT(IPMMUI, 0xf60),
+ INTCS_VECT(MVI3, 0x420),
+ INTCS_VECT(ICB, 0x480),
+ INTCS_VECT(PEP, 0x4a0),
+ INTCS_VECT(ASA, 0x4c0),
+ INTCS_VECT(BEM, 0x4e0),
+ INTCS_VECT(VE2HO, 0x520),
+ INTCS_VECT(HQE, 0x540),
+ INTCS_VECT(JPEG, 0x560),
+ INTCS_VECT(LCDC, 0x580),
+
+ INTC_VECT(INTCS, 0xf80),
+};
+
+static struct intc_group intcs_groups[] __initdata = {
+ INTC_GROUP(_2DDMAC, _2DDMAC_2DDM0, _2DDMAC_2DDM1,
+ _2DDMAC_2DDM2, _2DDMAC_2DDM3),
+ INTC_GROUP(RTDMAC_1, RTDMAC_1_DEI0, RTDMAC_1_DEI1,
+ RTDMAC_1_DEI2, RTDMAC_1_DEI3),
+ INTC_GROUP(RTDMAC_2, RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR),
+ INTC_GROUP(VEU, VIO2_VEU0, VIO2_VEU1, VIO2_VEU2, VIO2_VEU3),
+ INTC_GROUP(BEU, VIO1_BEU0, VIO1_BEU1, VIO1_BEU2),
+ INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0),
+ INTC_GROUP(IPMMU, IPMMU_IPMMUS, IPMMU_IPMMUB),
+ INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2),
+};
+
+static struct intc_mask_reg intcs_mask_registers[] = {
+ { 0xffd20184, 0xffd201c4, 8, /* IMR1SA / IMCR1SA */
+ { VIO1_BEU2, VIO1_BEU1, VIO1_BEU0, VIO1_CEU,
+ VIO2_VEU3, VIO2_VEU2, VIO2_VEU1, VIO2_VEU0 } },
+ { 0xffd20188, 0xffd201c8, 8, /* IMR2SA / IMCR2SA */
+ { VIO3_VOU, 0, VE2HO, VPU,
+ 0, 0, 0, 0 } },
+ { 0xffd2018c, 0xffd201cc, 8, /* IMR3SA / IMCR3SA */
+ { _2DDMAC_2DDM3, _2DDMAC_2DDM2, _2DDMAC_2DDM1, _2DDMAC_2DDM0,
+ BEM, ASA, PEP, ICB } },
+ { 0xffd20190, 0xffd201d0, 8, /* IMR4SA / IMCR4SA */
+ { 0, 0, MVI3, 0,
+ JPEG, HQE, 0, LCDC } },
+ { 0xffd20194, 0xffd201d4, 8, /* IMR5SA / IMCR5SA */
+ { 0, RTDMAC_2_DADERR, RTDMAC_2_DEI5, RTDMAC_2_DEI4,
+ RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } },
+ { 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */
+ { 0, 0, MSIOF, 0,
+ SGX530, 0, 0, 0 } },
+ { 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */
+ { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0,
+ 0, 0, 0, 0 } },
+ { 0xffd201a4, 0xffd201e4, 8, /* IMR9SA / IMCR9SA */
+ { 0, 0, 0, CMT,
+ IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } },
+ { 0xffd201a8, 0xffd201e8, 8, /* IMR10SA / IMCR10SA */
+ { IPMMU_IPMMUS, 0, IPMMU_IPMMUB, 0,
+ 0, 0, 0, 0 } },
+ { 0xffd201ac, 0xffd201ec, 8, /* IMR11SA / IMCR11SA */
+ { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0,
+ 0, 0, IPMMUI, TSIF } },
+ { 0xffd20104, 0, 16, /* INTAMASK */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, INTCS } },
+};
+
+/* Priority is needed for INTCA to receive the INTCS interrupt */
+static struct intc_prio_reg intcs_prio_registers[] = {
+ { 0xffd20000, 0, 16, 4, /* IPRAS */ { 0, MVI3, _2DDMAC, ICB } },
+ { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPEG, LCDC, 0, 0 } },
+ { 0xffd20008, 0, 16, 4, /* IPRCS */ { BBIF2, 0, 0, 0 } },
+ { 0xffd20010, 0, 16, 4, /* IPRES */ { RTDMAC_1, VIO1_CEU, 0, VPU } },
+ { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0, RTDMAC_2, 0, CMT } },
+ { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU_TUNI0, TMU_TUNI1,
+ TMU_TUNI2, 0 } },
+ { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, VIO3_VOU, VEU, BEU } },
+ { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF, IIC0 } },
+ { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, SGX530, 0, 0 } },
+ { 0xffd20028, 0, 16, 4, /* IPRKS */ { BEM, ASA, IPMMUI, PEP } },
+ { 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, VE2HO, HQE } },
+ { 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } },
+};
+
+static struct resource intcs_resources[] __initdata = {
+ [0] = {
+ .start = 0xffd20000,
+ .end = 0xffd2ffff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct intc_desc intcs_desc __initdata = {
+ .name = "sh7367-intcs",
+ .resource = intcs_resources,
+ .num_resources = ARRAY_SIZE(intcs_resources),
+ .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
+ intcs_prio_registers, NULL, NULL),
+};
+
+static void intcs_demux(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *reg = (void *)get_irq_data(irq);
+ unsigned int evtcodeas = ioread32(reg);
+
+ generic_handle_irq(intcs_evt2irq(evtcodeas));
+}
+
void __init sh7367_init_irq(void)
{
- /* INTCA */
+ void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+
register_intc_controller(&intca_desc);
+ register_intc_controller(&intcs_desc);
+
+ /* demux using INTEVTSA */
+ set_irq_data(evt2irq(0xf80), (void *)intevtsa);
+ set_irq_chained_handler(evt2irq(0xf80), intcs_demux);
}
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 3ce9d9bd5899..e3551b56cd03 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -319,17 +319,17 @@ static struct intc_prio_reg intca_prio_registers[] __initdata = {
{ 0xe6950034, 0, 16, 4, /* IPRNA3 */ { AP_ARM2, 0, 0, 0 } },
{ 0xe6950038, 0, 16, 4, /* IPROA3 */ { MFIS2, CPORTR2S,
CMT14, CMT15 } },
- { 0xe694003c, 0, 16, 4, /* IPRPA3 */ { 0, 0,
+ { 0xe695003c, 0, 16, 4, /* IPRPA3 */ { 0, 0,
MMC_MMC_ERR, MMC_MMC_NOR } },
- { 0xe6940040, 0, 16, 4, /* IPRQA3 */ { IIC4_ALI4, IIC4_TACKI4,
+ { 0xe6950040, 0, 16, 4, /* IPRQA3 */ { IIC4_ALI4, IIC4_TACKI4,
IIC4_WAITI4, IIC4_DTEI4 } },
- { 0xe6940044, 0, 16, 4, /* IPRRA3 */ { IIC3_ALI3, IIC3_TACKI3,
+ { 0xe6950044, 0, 16, 4, /* IPRRA3 */ { IIC3_ALI3, IIC3_TACKI3,
IIC3_WAITI3, IIC3_DTEI3 } },
- { 0xe6940048, 0, 16, 4, /* IPRSA3 */ { 0/*ERI*/, 0/*RXI*/,
+ { 0xe6950048, 0, 16, 4, /* IPRSA3 */ { 0/*ERI*/, 0/*RXI*/,
0/*TXI*/, 0/*TEI*/} },
- { 0xe694004c, 0, 16, 4, /* IPRTA3 */ { USB0_USB0I1, USB0_USB0I0,
+ { 0xe695004c, 0, 16, 4, /* IPRTA3 */ { USB0_USB0I1, USB0_USB0I0,
USB1_USB1I1, USB1_USB1I0 } },
- { 0xe6940050, 0, 16, 4, /* IPRUA3 */ { USBHSDMAC1_USHDMI, 0, 0, 0 } },
+ { 0xe6950050, 0, 16, 4, /* IPRUA3 */ { USBHSDMAC1_USHDMI, 0, 0, 0 } },
};
static struct intc_sense_reg intca_sense_registers[] __initdata = {
@@ -363,7 +363,227 @@ static struct intc_desc intca_desc __initdata = {
intca_sense_registers, intca_ack_registers),
};
+enum {
+ UNUSED_INTCS = 0,
+
+ INTCS,
+
+ /* interrupt sources INTCS */
+ VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3,
+ RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3,
+ CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2,
+ VPU,
+ TSIF1,
+ _3DG_SGX530,
+ _2DDMAC,
+ IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
+ IPMMU_IPMMUR, IPMMU_IPMMUR2,
+ RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR,
+ MSIOF,
+ IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0,
+ TMU_TUNI0, TMU_TUNI1, TMU_TUNI2,
+ CMT0,
+ TSIF0,
+ LMB,
+ CTI,
+ ICB,
+ JPU_JPEG,
+ LCDC,
+ LCRC,
+ RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3,
+ RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR,
+ ISP,
+ LCDC1,
+ CSIRX,
+ DSITX_DSITX0,
+ DSITX_DSITX1,
+ TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2,
+ CMT4,
+ DSITX1_DSITX1_0,
+ DSITX1_DSITX1_1,
+ CPORTS2R,
+ JPU6E,
+
+ /* interrupt groups INTCS */
+ RTDMAC_1, RTDMAC_2, VEU, BEU, IIC0, IPMMU, IIC2,
+ RTDMAC2_1, RTDMAC2_2, TMU1, DSITX,
+};
+
+static struct intc_vect intcs_vectors[] = {
+ INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720),
+ INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760),
+ INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820),
+ INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860),
+ INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0),
+ INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0),
+ INTCS_VECT(VPU, 0x980),
+ INTCS_VECT(TSIF1, 0x9a0),
+ INTCS_VECT(_3DG_SGX530, 0x9e0),
+ INTCS_VECT(_2DDMAC, 0xa00),
+ INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0),
+ INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0),
+ INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20),
+ INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0),
+ INTCS_VECT(RTDMAC_2_DADERR, 0xbc0),
+ INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20),
+ INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60),
+ INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0),
+ INTCS_VECT(TMU_TUNI2, 0xec0),
+ INTCS_VECT(CMT0, 0xf00),
+ INTCS_VECT(TSIF0, 0xf20),
+ INTCS_VECT(LMB, 0xf60),
+ INTCS_VECT(CTI, 0x400),
+ INTCS_VECT(ICB, 0x480),
+ INTCS_VECT(JPU_JPEG, 0x560),
+ INTCS_VECT(LCDC, 0x580),
+ INTCS_VECT(LCRC, 0x5a0),
+ INTCS_VECT(RTDMAC2_1_DEI0, 0x1300), INTCS_VECT(RTDMAC2_1_DEI1, 0x1320),
+ INTCS_VECT(RTDMAC2_1_DEI2, 0x1340), INTCS_VECT(RTDMAC2_1_DEI3, 0x1360),
+ INTCS_VECT(RTDMAC2_2_DEI4, 0x1380), INTCS_VECT(RTDMAC2_2_DEI5, 0x13a0),
+ INTCS_VECT(RTDMAC2_2_DADERR, 0x13c0),
+ INTCS_VECT(ISP, 0x1720),
+ INTCS_VECT(LCDC1, 0x1780),
+ INTCS_VECT(CSIRX, 0x17a0),
+ INTCS_VECT(DSITX_DSITX0, 0x17c0),
+ INTCS_VECT(DSITX_DSITX1, 0x17e0),
+ INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920),
+ INTCS_VECT(TMU1_TUNI2, 0x1940),
+ INTCS_VECT(CMT4, 0x1980),
+ INTCS_VECT(DSITX1_DSITX1_0, 0x19a0),
+ INTCS_VECT(DSITX1_DSITX1_1, 0x19c0),
+ INTCS_VECT(CPORTS2R, 0x1a20),
+ INTCS_VECT(JPU6E, 0x1a80),
+
+ INTC_VECT(INTCS, 0xf80),
+};
+
+static struct intc_group intcs_groups[] __initdata = {
+ INTC_GROUP(RTDMAC_1, RTDMAC_1_DEI0, RTDMAC_1_DEI1,
+ RTDMAC_1_DEI2, RTDMAC_1_DEI3),
+ INTC_GROUP(RTDMAC_2, RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR),
+ INTC_GROUP(VEU, VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3),
+ INTC_GROUP(BEU, BEU_BEU0, BEU_BEU1, BEU_BEU2),
+ INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0),
+ INTC_GROUP(IPMMU, IPMMU_IPMMUR, IPMMU_IPMMUR2),
+ INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2),
+ INTC_GROUP(RTDMAC2_1, RTDMAC2_1_DEI0, RTDMAC2_1_DEI1,
+ RTDMAC2_1_DEI2, RTDMAC2_1_DEI3),
+ INTC_GROUP(RTDMAC2_2, RTDMAC2_2_DEI4,
+ RTDMAC2_2_DEI5, RTDMAC2_2_DADERR),
+ INTC_GROUP(TMU1, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0),
+ INTC_GROUP(DSITX, DSITX_DSITX0, DSITX_DSITX1),
+};
+
+static struct intc_mask_reg intcs_mask_registers[] = {
+ { 0xffd20184, 0xffd201c4, 8, /* IMR1SA / IMCR1SA */
+ { BEU_BEU2, BEU_BEU1, BEU_BEU0, CEU,
+ VEU_VEU3, VEU_VEU2, VEU_VEU1, VEU_VEU0 } },
+ { 0xffd20188, 0xffd201c8, 8, /* IMR2SA / IMCR2SA */
+ { 0, 0, 0, VPU,
+ 0, 0, 0, 0 } },
+ { 0xffd2018c, 0xffd201cc, 8, /* IMR3SA / IMCR3SA */
+ { 0, 0, 0, _2DDMAC,
+ 0, 0, 0, ICB } },
+ { 0xffd20190, 0xffd201d0, 8, /* IMR4SA / IMCR4SA */
+ { 0, 0, 0, CTI,
+ JPU_JPEG, 0, LCRC, LCDC } },
+ { 0xffd20194, 0xffd201d4, 8, /* IMR5SA / IMCR5SA */
+ { 0, RTDMAC_2_DADERR, RTDMAC_2_DEI5, RTDMAC_2_DEI4,
+ RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } },
+ { 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */
+ { 0, 0, MSIOF, 0,
+ _3DG_SGX530, 0, 0, 0 } },
+ { 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */
+ { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0,
+ 0, 0, 0, 0 } },
+ { 0xffd201a4, 0xffd201e4, 8, /* IMR9SA / IMCR9SA */
+ { 0, 0, 0, CMT0,
+ IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } },
+ { 0xffd201a8, 0xffd201e8, 8, /* IMR10SA / IMCR10SA */
+ { 0, 0, IPMMU_IPMMUR2, IPMMU_IPMMUR,
+ 0, 0, 0, 0 } },
+ { 0xffd201ac, 0xffd201ec, 8, /* IMR11SA / IMCR11SA */
+ { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0,
+ 0, TSIF1, LMB, TSIF0 } },
+ { 0xffd50180, 0xffd501c0, 8, /* IMR0SA3 / IMCR0SA3 */
+ { 0, RTDMAC2_2_DADERR, RTDMAC2_2_DEI5, RTDMAC2_2_DEI4,
+ RTDMAC2_1_DEI3, RTDMAC2_1_DEI2, RTDMAC2_1_DEI1, RTDMAC2_1_DEI0 } },
+ { 0xffd50190, 0xffd501d0, 8, /* IMR4SA3 / IMCR4SA3 */
+ { 0, ISP, 0, 0,
+ LCDC1, CSIRX, DSITX_DSITX0, DSITX_DSITX1 } },
+ { 0xffd50198, 0xffd501d8, 8, /* IMR6SA3 / IMCR6SA3 */
+ { 0, TMU1_TUNI2, TMU1_TUNI1, TMU1_TUNI0,
+ CMT4, DSITX1_DSITX1_0, DSITX1_DSITX1_1, 0 } },
+ { 0xffd5019c, 0xffd501dc, 8, /* IMR7SA3 / IMCR7SA3 */
+ { 0, CPORTS2R, 0, 0,
+ JPU6E, 0, 0, 0 } },
+ { 0xffd20104, 0, 16, /* INTAMASK */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, INTCS } },
+};
+
+/* Priority is needed for INTCA to receive the INTCS interrupt */
+static struct intc_prio_reg intcs_prio_registers[] = {
+ { 0xffd20000, 0, 16, 4, /* IPRAS */ { CTI, 0, _2DDMAC, ICB } },
+ { 0xffd20004, 0, 16, 4, /* IPRBS */ { JPU_JPEG, LCDC, 0, LCRC } },
+ { 0xffd20010, 0, 16, 4, /* IPRES */ { RTDMAC_1, CEU, 0, VPU } },
+ { 0xffd20014, 0, 16, 4, /* IPRFS */ { 0, RTDMAC_2, 0, CMT0 } },
+ { 0xffd20018, 0, 16, 4, /* IPRGS */ { TMU_TUNI0, TMU_TUNI1,
+ TMU_TUNI2, TSIF1 } },
+ { 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0, VEU, BEU } },
+ { 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF0, IIC0 } },
+ { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, _3DG_SGX530, 0, 0 } },
+ { 0xffd20028, 0, 16, 4, /* IPRKS */ { 0, 0, LMB, 0 } },
+ { 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, 0, 0 } },
+ { 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } },
+ { 0xffd50000, 0, 16, 4, /* IPRAS3 */ { RTDMAC2_1, 0, 0, 0 } },
+ { 0xffd50004, 0, 16, 4, /* IPRBS3 */ { RTDMAC2_2, 0, 0, 0 } },
+ { 0xffd50020, 0, 16, 4, /* IPRIS3 */ { 0, ISP, 0, 0 } },
+ { 0xffd50024, 0, 16, 4, /* IPRJS3 */ { LCDC1, CSIRX, DSITX, 0 } },
+ { 0xffd50030, 0, 16, 4, /* IPRMS3 */ { TMU1, 0, 0, 0 } },
+ { 0xffd50034, 0, 16, 4, /* IPRNS3 */ { CMT4, DSITX1_DSITX1_0,
+ DSITX1_DSITX1_1, 0 } },
+ { 0xffd50038, 0, 16, 4, /* IPROS3 */ { 0, CPORTS2R, 0, 0 } },
+ { 0xffd5003c, 0, 16, 4, /* IPRPS3 */ { JPU6E, 0, 0, 0 } },
+};
+
+static struct resource intcs_resources[] __initdata = {
+ [0] = {
+ .start = 0xffd20000,
+ .end = 0xffd201ff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0xffd50000,
+ .end = 0xffd501ff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct intc_desc intcs_desc __initdata = {
+ .name = "sh7372-intcs",
+ .resource = intcs_resources,
+ .num_resources = ARRAY_SIZE(intcs_resources),
+ .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
+ intcs_prio_registers, NULL, NULL),
+};
+
+static void intcs_demux(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *reg = (void *)get_irq_data(irq);
+ unsigned int evtcodeas = ioread32(reg);
+
+ generic_handle_irq(intcs_evt2irq(evtcodeas));
+}
+
void __init sh7372_init_irq(void)
{
+ void __iomem *intevtsa = ioremap_nocache(0xffd20100, PAGE_SIZE);
+
register_intc_controller(&intca_desc);
+ register_intc_controller(&intcs_desc);
+
+ /* demux using INTEVTSA */
+ set_irq_data(evt2irq(0xf80), (void *)intevtsa);
+ set_irq_chained_handler(evt2irq(0xf80), intcs_demux);
}
diff --git a/arch/arm/mach-shmobile/intc-sh7377.c b/arch/arm/mach-shmobile/intc-sh7377.c
index 5c781e2d1897..2cdeb8ccd821 100644
--- a/arch/arm/mach-shmobile/intc-sh7377.c
+++ b/arch/arm/mach-shmobile/intc-sh7377.c
@@ -90,7 +90,7 @@ enum {
ICUSB, ICUDMC
};
-static struct intc_vect intca_vectors[] = {
+static struct intc_vect intca_vectors[] __initdata = {
INTC_VECT(IRQ0A, 0x0200), INTC_VECT(IRQ1A, 0x0220),
INTC_VECT(IRQ2A, 0x0240), INTC_VECT(IRQ3A, 0x0260),
INTC_VECT(IRQ4A, 0x0280), INTC_VECT(IRQ5A, 0x02a0),
@@ -202,7 +202,7 @@ static struct intc_group intca_groups[] __initdata = {
INTC_GROUP(ICUDMC, ICUDMC_ICUDMC1, ICUDMC_ICUDMC2),
};
-static struct intc_mask_reg intca_mask_registers[] = {
+static struct intc_mask_reg intca_mask_registers[] __initdata = {
{ 0xe6900040, 0xe6900060, 8, /* INTMSK00A / INTMSKCLR00A */
{ IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } },
{ 0xe6900044, 0xe6900064, 8, /* INTMSK10A / INTMSKCLR10A */
@@ -272,7 +272,7 @@ static struct intc_mask_reg intca_mask_registers[] = {
SCIFA6, 0, 0, 0 } },
};
-static struct intc_prio_reg intca_prio_registers[] = {
+static struct intc_prio_reg intca_prio_registers[] __initdata = {
{ 0xe6900010, 0, 32, 4, /* INTPRI00A */
{ IRQ0A, IRQ1A, IRQ2A, IRQ3A, IRQ4A, IRQ5A, IRQ6A, IRQ7A } },
{ 0xe6900014, 0, 32, 4, /* INTPRI10A */
@@ -346,7 +346,301 @@ static struct intc_desc intca_desc __initdata = {
intca_sense_registers, intca_ack_registers),
};
+/* this macro ignore entry which is also in INTCA */
+#define __IGNORE(a...)
+#define __IGNORE0(a...) 0
+
+enum {
+ UNUSED_INTCS = 0,
+
+ INTCS,
+
+ /* interrupt sources INTCS */
+ VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3,
+ RTDMAC1_1_DEI0, RTDMAC1_1_DEI1, RTDMAC1_1_DEI2, RTDMAC1_1_DEI3,
+ CEU,
+ BEU_BEU0, BEU_BEU1, BEU_BEU2,
+ __IGNORE(MFI)
+ __IGNORE(BBIF2)
+ VPU,
+ TSIF1,
+ __IGNORE(SGX540)
+ _2DDMAC,
+ IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
+ IPMMU_IPMMUR, IPMMU_IPMMUR2,
+ RTDMAC1_2_DEI4, RTDMAC1_2_DEI5, RTDMAC1_2_DADERR,
+ __IGNORE(KEYSC)
+ __IGNORE(TTI20)
+ __IGNORE(MSIOF)
+ IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0,
+ TMU_TUNI0, TMU_TUNI1, TMU_TUNI2,
+ CMT0,
+ TSIF0,
+ __IGNORE(CMT2)
+ LMB,
+ __IGNORE(MSUG)
+ __IGNORE(MSU_MSU, MSU_MSU2)
+ __IGNORE(CTI)
+ MVI3,
+ __IGNORE(RWDT0)
+ __IGNORE(RWDT1)
+ ICB,
+ PEP,
+ ASA,
+ __IGNORE(_2DG)
+ HQE,
+ JPU,
+ LCDC0,
+ __IGNORE(LCRC)
+ RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3,
+ RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR,
+ FRC,
+ LCDC1,
+ CSIRX,
+ DSITX_DSITX0, DSITX_DSITX1,
+ __IGNORE(SPU2_SPU0, SPU2_SPU1)
+ __IGNORE(FSI)
+ __IGNORE(FMSI)
+ __IGNORE(SCUV)
+ TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12,
+ TSIF2,
+ CMT4,
+ __IGNORE(MFIS2)
+ CPORTS2R,
+
+ /* interrupt groups INTCS */
+ RTDMAC1_1, RTDMAC1_2, VEU, BEU, IIC0, __IGNORE(MSU) IPMMU,
+ IIC2, RTDMAC2_1, RTDMAC2_2, DSITX, __IGNORE(SPU2) TMU1,
+};
+
+#define INTCS_INTVECT 0x0F80
+static struct intc_vect intcs_vectors[] __initdata = {
+ INTCS_VECT(VEU_VEU0, 0x0700), INTCS_VECT(VEU_VEU1, 0x0720),
+ INTCS_VECT(VEU_VEU2, 0x0740), INTCS_VECT(VEU_VEU3, 0x0760),
+ INTCS_VECT(RTDMAC1_1_DEI0, 0x0800), INTCS_VECT(RTDMAC1_1_DEI1, 0x0820),
+ INTCS_VECT(RTDMAC1_1_DEI2, 0x0840), INTCS_VECT(RTDMAC1_1_DEI3, 0x0860),
+ INTCS_VECT(CEU, 0x0880),
+ INTCS_VECT(BEU_BEU0, 0x08A0),
+ INTCS_VECT(BEU_BEU1, 0x08C0),
+ INTCS_VECT(BEU_BEU2, 0x08E0),
+ __IGNORE(INTCS_VECT(MFI, 0x0900))
+ __IGNORE(INTCS_VECT(BBIF2, 0x0960))
+ INTCS_VECT(VPU, 0x0980),
+ INTCS_VECT(TSIF1, 0x09A0),
+ __IGNORE(INTCS_VECT(SGX540, 0x09E0))
+ INTCS_VECT(_2DDMAC, 0x0A00),
+ INTCS_VECT(IIC2_ALI2, 0x0A80), INTCS_VECT(IIC2_TACKI2, 0x0AA0),
+ INTCS_VECT(IIC2_WAITI2, 0x0AC0), INTCS_VECT(IIC2_DTEI2, 0x0AE0),
+ INTCS_VECT(IPMMU_IPMMUR, 0x0B00), INTCS_VECT(IPMMU_IPMMUR2, 0x0B20),
+ INTCS_VECT(RTDMAC1_2_DEI4, 0x0B80),
+ INTCS_VECT(RTDMAC1_2_DEI5, 0x0BA0),
+ INTCS_VECT(RTDMAC1_2_DADERR, 0x0BC0),
+ __IGNORE(INTCS_VECT(KEYSC 0x0BE0))
+ __IGNORE(INTCS_VECT(TTI20, 0x0C80))
+ __IGNORE(INTCS_VECT(MSIOF, 0x0D20))
+ INTCS_VECT(IIC0_ALI0, 0x0E00), INTCS_VECT(IIC0_TACKI0, 0x0E20),
+ INTCS_VECT(IIC0_WAITI0, 0x0E40), INTCS_VECT(IIC0_DTEI0, 0x0E60),
+ INTCS_VECT(TMU_TUNI0, 0x0E80),
+ INTCS_VECT(TMU_TUNI1, 0x0EA0),
+ INTCS_VECT(TMU_TUNI2, 0x0EC0),
+ INTCS_VECT(CMT0, 0x0F00),
+ INTCS_VECT(TSIF0, 0x0F20),
+ __IGNORE(INTCS_VECT(CMT2, 0x0F40))
+ INTCS_VECT(LMB, 0x0F60),
+ __IGNORE(INTCS_VECT(MSUG, 0x0F80))
+ __IGNORE(INTCS_VECT(MSU_MSU, 0x0FA0))
+ __IGNORE(INTCS_VECT(MSU_MSU2, 0x0FC0))
+ __IGNORE(INTCS_VECT(CTI, 0x0400))
+ INTCS_VECT(MVI3, 0x0420),
+ __IGNORE(INTCS_VECT(RWDT0, 0x0440))
+ __IGNORE(INTCS_VECT(RWDT1, 0x0460))
+ INTCS_VECT(ICB, 0x0480),
+ INTCS_VECT(PEP, 0x04A0),
+ INTCS_VECT(ASA, 0x04C0),
+ __IGNORE(INTCS_VECT(_2DG, 0x04E0))
+ INTCS_VECT(HQE, 0x0540),
+ INTCS_VECT(JPU, 0x0560),
+ INTCS_VECT(LCDC0, 0x0580),
+ __IGNORE(INTCS_VECT(LCRC, 0x05A0))
+ INTCS_VECT(RTDMAC2_1_DEI0, 0x1300), INTCS_VECT(RTDMAC2_1_DEI1, 0x1320),
+ INTCS_VECT(RTDMAC2_1_DEI2, 0x1340), INTCS_VECT(RTDMAC2_1_DEI3, 0x1360),
+ INTCS_VECT(RTDMAC2_2_DEI4, 0x1380), INTCS_VECT(RTDMAC2_2_DEI5, 0x13A0),
+ INTCS_VECT(RTDMAC2_2_DADERR, 0x13C0),
+ INTCS_VECT(FRC, 0x1700),
+ INTCS_VECT(LCDC1, 0x1780),
+ INTCS_VECT(CSIRX, 0x17A0),
+ INTCS_VECT(DSITX_DSITX0, 0x17C0), INTCS_VECT(DSITX_DSITX1, 0x17E0),
+ __IGNORE(INTCS_VECT(SPU2_SPU0, 0x1800))
+ __IGNORE(INTCS_VECT(SPU2_SPU1, 0x1820))
+ __IGNORE(INTCS_VECT(FSI, 0x1840))
+ __IGNORE(INTCS_VECT(FMSI, 0x1860))
+ __IGNORE(INTCS_VECT(SCUV, 0x1880))
+ INTCS_VECT(TMU1_TUNI10, 0x1900), INTCS_VECT(TMU1_TUNI11, 0x1920),
+ INTCS_VECT(TMU1_TUNI12, 0x1940),
+ INTCS_VECT(TSIF2, 0x1960),
+ INTCS_VECT(CMT4, 0x1980),
+ __IGNORE(INTCS_VECT(MFIS2, 0x1A00))
+ INTCS_VECT(CPORTS2R, 0x1A20),
+
+ INTC_VECT(INTCS, INTCS_INTVECT),
+};
+
+static struct intc_group intcs_groups[] __initdata = {
+ INTC_GROUP(RTDMAC1_1,
+ RTDMAC1_1_DEI0, RTDMAC1_1_DEI1,
+ RTDMAC1_1_DEI2, RTDMAC1_1_DEI3),
+ INTC_GROUP(RTDMAC1_2,
+ RTDMAC1_2_DEI4, RTDMAC1_2_DEI5, RTDMAC1_2_DADERR),
+ INTC_GROUP(VEU, VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3),
+ INTC_GROUP(BEU, BEU_BEU0, BEU_BEU1, BEU_BEU2),
+ INTC_GROUP(IIC0, IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0),
+ __IGNORE(INTC_GROUP(MSU, MSU_MSU, MSU_MSU2))
+ INTC_GROUP(IPMMU, IPMMU_IPMMUR, IPMMU_IPMMUR2),
+ INTC_GROUP(IIC2, IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2),
+ INTC_GROUP(RTDMAC2_1,
+ RTDMAC2_1_DEI0, RTDMAC2_1_DEI1,
+ RTDMAC2_1_DEI2, RTDMAC2_1_DEI3),
+ INTC_GROUP(RTDMAC2_2, RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR),
+ INTC_GROUP(DSITX, DSITX_DSITX0, DSITX_DSITX1),
+ __IGNORE(INTC_GROUP(SPU2, SPU2_SPU0, SPU2_SPU1))
+ INTC_GROUP(TMU1, TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12),
+};
+
+static struct intc_mask_reg intcs_mask_registers[] __initdata = {
+ { 0xE6940184, 0xE69401C4, 8, /* IMR1AS / IMCR1AS */
+ { BEU_BEU2, BEU_BEU1, BEU_BEU0, CEU,
+ VEU_VEU3, VEU_VEU2, VEU_VEU1, VEU_VEU0 } },
+ { 0xE6940188, 0xE69401C8, 8, /* IMR2AS / IMCR2AS */
+ { 0, 0, 0, VPU,
+ __IGNORE0(BBIF2), 0, 0, __IGNORE0(MFI) } },
+ { 0xE694018C, 0xE69401CC, 8, /* IMR3AS / IMCR3AS */
+ { 0, 0, 0, _2DDMAC,
+ __IGNORE0(_2DG), ASA, PEP, ICB } },
+ { 0xE6940190, 0xE69401D0, 8, /* IMR4AS / IMCR4AS */
+ { 0, 0, MVI3, __IGNORE0(CTI),
+ JPU, HQE, __IGNORE0(LCRC), LCDC0 } },
+ { 0xE6940194, 0xE69401D4, 8, /* IMR5AS / IMCR5AS */
+ { __IGNORE0(KEYSC), RTDMAC1_2_DADERR, RTDMAC1_2_DEI5, RTDMAC1_2_DEI4,
+ RTDMAC1_1_DEI3, RTDMAC1_1_DEI2, RTDMAC1_1_DEI1, RTDMAC1_1_DEI0 } },
+ __IGNORE({ 0xE6940198, 0xE69401D8, 8, /* IMR6AS / IMCR6AS */
+ { 0, 0, MSIOF, 0,
+ SGX540, 0, TTI20, 0 } })
+ { 0xE694019C, 0xE69401DC, 8, /* IMR7AS / IMCR7AS */
+ { 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0,
+ 0, 0, 0, 0 } },
+ __IGNORE({ 0xE69401A0, 0xE69401E0, 8, /* IMR8AS / IMCR8AS */
+ { 0, 0, 0, 0,
+ 0, MSU_MSU, MSU_MSU2, MSUG } })
+ { 0xE69401A4, 0xE69401E4, 8, /* IMR9AS / IMCR9AS */
+ { __IGNORE0(RWDT1), __IGNORE0(RWDT0), __IGNORE0(CMT2), CMT0,
+ IIC2_DTEI2, IIC2_WAITI2, IIC2_TACKI2, IIC2_ALI2 } },
+ { 0xE69401A8, 0xE69401E8, 8, /* IMR10AS / IMCR10AS */
+ { 0, 0, IPMMU_IPMMUR, IPMMU_IPMMUR2,
+ 0, 0, 0, 0 } },
+ { 0xE69401AC, 0xE69401EC, 8, /* IMR11AS / IMCR11AS */
+ { IIC0_DTEI0, IIC0_WAITI0, IIC0_TACKI0, IIC0_ALI0,
+ 0, TSIF1, LMB, TSIF0 } },
+ { 0xE6950180, 0xE69501C0, 8, /* IMR0AS3 / IMCR0AS3 */
+ { RTDMAC2_1_DEI0, RTDMAC2_1_DEI1, RTDMAC2_1_DEI2, RTDMAC2_1_DEI3,
+ RTDMAC2_2_DEI4, RTDMAC2_2_DEI5, RTDMAC2_2_DADERR, 0 } },
+ { 0xE6950190, 0xE69501D0, 8, /* IMR4AS3 / IMCR4AS3 */
+ { FRC, 0, 0, 0,
+ LCDC1, CSIRX, DSITX_DSITX0, DSITX_DSITX1 } },
+ __IGNORE({ 0xE6950194, 0xE69501D4, 8, /* IMR5AS3 / IMCR5AS3 */
+ {SPU2_SPU0, SPU2_SPU1, FSI, FMSI,
+ SCUV, 0, 0, 0 } })
+ { 0xE6950198, 0xE69501D8, 8, /* IMR6AS3 / IMCR6AS3 */
+ { TMU1_TUNI10, TMU1_TUNI11, TMU1_TUNI12, TSIF2,
+ CMT4, 0, 0, 0 } },
+ { 0xE695019C, 0xE69501DC, 8, /* IMR7AS3 / IMCR7AS3 */
+ { __IGNORE0(MFIS2), CPORTS2R, 0, 0,
+ 0, 0, 0, 0 } },
+ { 0xFFD20104, 0, 16, /* INTAMASK */
+ { 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, INTCS } }
+};
+
+static struct intc_prio_reg intcs_prio_registers[] __initdata = {
+ /* IPRAS */
+ { 0xFFD20000, 0, 16, 4, { __IGNORE0(CTI), MVI3, _2DDMAC, ICB } },
+ /* IPRBS */
+ { 0xFFD20004, 0, 16, 4, { JPU, LCDC0, 0, __IGNORE0(LCRC) } },
+ /* IPRCS */
+ __IGNORE({ 0xFFD20008, 0, 16, 4, { BBIF2, 0, 0, 0 } })
+ /* IPRES */
+ { 0xFFD20010, 0, 16, 4, { RTDMAC1_1, CEU, __IGNORE0(MFI), VPU } },
+ /* IPRFS */
+ { 0xFFD20014, 0, 16, 4,
+ { __IGNORE0(KEYSC), RTDMAC1_2, __IGNORE0(CMT2), CMT0 } },
+ /* IPRGS */
+ { 0xFFD20018, 0, 16, 4, { TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, TSIF1 } },
+ /* IPRHS */
+ { 0xFFD2001C, 0, 16, 4, { __IGNORE0(TTI20), 0, VEU, BEU } },
+ /* IPRIS */
+ { 0xFFD20020, 0, 16, 4, { 0, __IGNORE0(MSIOF), TSIF0, IIC0 } },
+ /* IPRJS */
+ __IGNORE({ 0xFFD20024, 0, 16, 4, { 0, SGX540, MSUG, MSU } })
+ /* IPRKS */
+ { 0xFFD20028, 0, 16, 4, { __IGNORE0(_2DG), ASA, LMB, PEP } },
+ /* IPRLS */
+ { 0xFFD2002C, 0, 16, 4, { IPMMU, 0, 0, HQE } },
+ /* IPRMS */
+ { 0xFFD20030, 0, 16, 4,
+ { IIC2, 0, __IGNORE0(RWDT1), __IGNORE0(RWDT0) } },
+ /* IPRAS3 */
+ { 0xFFD50000, 0, 16, 4, { RTDMAC2_1, 0, 0, 0 } },
+ /* IPRBS3 */
+ { 0xFFD50004, 0, 16, 4, { RTDMAC2_2, 0, 0, 0 } },
+ /* IPRIS3 */
+ { 0xFFD50020, 0, 16, 4, { FRC, 0, 0, 0 } },
+ /* IPRJS3 */
+ { 0xFFD50024, 0, 16, 4, { LCDC1, CSIRX, DSITX, 0 } },
+ /* IPRKS3 */
+ __IGNORE({ 0xFFD50028, 0, 16, 4, { SPU2, 0, FSI, FMSI } })
+ /* IPRLS3 */
+ __IGNORE({ 0xFFD5002C, 0, 16, 4, { SCUV, 0, 0, 0 } })
+ /* IPRMS3 */
+ { 0xFFD50030, 0, 16, 4, { TMU1, 0, 0, TSIF2 } },
+ /* IPRNS3 */
+ { 0xFFD50034, 0, 16, 4, { CMT4, 0, 0, 0 } },
+ /* IPROS3 */
+ { 0xFFD50038, 0, 16, 4, { __IGNORE0(MFIS2), CPORTS2R, 0, 0 } },
+};
+
+static struct resource intcs_resources[] __initdata = {
+ [0] = {
+ .start = 0xffd20000,
+ .end = 0xffd500ff,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct intc_desc intcs_desc __initdata = {
+ .name = "sh7377-intcs",
+ .resource = intcs_resources,
+ .num_resources = ARRAY_SIZE(intcs_resources),
+ .hw = INTC_HW_DESC(intcs_vectors, intcs_groups,
+ intcs_mask_registers, intcs_prio_registers,
+ NULL, NULL),
+};
+
+static void intcs_demux(unsigned int irq, struct irq_desc *desc)
+{
+ void __iomem *reg = (void *)get_irq_data(irq);
+ unsigned int evtcodeas = ioread32(reg);
+
+ generic_handle_irq(intcs_evt2irq(evtcodeas));
+}
+
+#define INTEVTSA 0xFFD20100
void __init sh7377_init_irq(void)
{
+ void __iomem *intevtsa = ioremap_nocache(INTEVTSA, PAGE_SIZE);
+
register_intc_controller(&intca_desc);
+ register_intc_controller(&intcs_desc);
+
+ /* demux using INTEVTSA */
+ set_irq_data(evt2irq(INTCS_INTVECT), (void *)intevtsa);
+ set_irq_chained_handler(evt2irq(INTCS_INTVECT), intcs_demux);
}
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c
index eca90716140e..3148c11a550e 100644
--- a/arch/arm/mach-shmobile/setup-sh7367.c
+++ b/arch/arm/mach-shmobile/setup-sh7367.c
@@ -31,11 +31,13 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+/* SCIFA0 */
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = { evt2irq(0xc00), evt2irq(0xc00),
+ evt2irq(0xc00), evt2irq(0xc00) },
};
static struct platform_device scif0_device = {
@@ -46,11 +48,13 @@ static struct platform_device scif0_device = {
},
};
+/* SCIFA1 */
static struct plat_sci_port scif1_platform_data = {
.mapbase = 0xe6c50000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = { evt2irq(0xc20), evt2irq(0xc20),
+ evt2irq(0xc20), evt2irq(0xc20) },
};
static struct platform_device scif1_device = {
@@ -61,11 +65,13 @@ static struct platform_device scif1_device = {
},
};
+/* SCIFA2 */
static struct plat_sci_port scif2_platform_data = {
.mapbase = 0xe6c60000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = { evt2irq(0xc40), evt2irq(0xc40),
+ evt2irq(0xc40), evt2irq(0xc40) },
};
static struct platform_device scif2_device = {
@@ -76,11 +82,13 @@ static struct platform_device scif2_device = {
},
};
+/* SCIFA3 */
static struct plat_sci_port scif3_platform_data = {
.mapbase = 0xe6c70000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 83, 83, 83, 83 },
+ .irqs = { evt2irq(0xc60), evt2irq(0xc60),
+ evt2irq(0xc60), evt2irq(0xc60) },
};
static struct platform_device scif3_device = {
@@ -91,11 +99,13 @@ static struct platform_device scif3_device = {
},
};
+/* SCIFA4 */
static struct plat_sci_port scif4_platform_data = {
.mapbase = 0xe6c80000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 89, 89, 89, 89 },
+ .irqs = { evt2irq(0xd20), evt2irq(0xd20),
+ evt2irq(0xd20), evt2irq(0xd20) },
};
static struct platform_device scif4_device = {
@@ -106,11 +116,13 @@ static struct platform_device scif4_device = {
},
};
+/* SCIFA5 */
static struct plat_sci_port scif5_platform_data = {
.mapbase = 0xe6cb0000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 90, 90, 90, 90 },
+ .irqs = { evt2irq(0xd40), evt2irq(0xd40),
+ evt2irq(0xd40), evt2irq(0xd40) },
};
static struct platform_device scif5_device = {
@@ -121,11 +133,13 @@ static struct platform_device scif5_device = {
},
};
+/* SCIFB */
static struct plat_sci_port scif6_platform_data = {
.mapbase = 0xe6c30000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 91, 91, 91, 91 },
+ .irqs = { evt2irq(0xd60), evt2irq(0xd60),
+ evt2irq(0xd60), evt2irq(0xd60) },
};
static struct platform_device scif6_device = {
@@ -153,7 +167,7 @@ static struct resource cmt10_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 72,
+ .start = evt2irq(0xb00), /* CMT1_CMT10 */
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 1d1153290f59..e26686c9d0b6 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -26,17 +26,21 @@
#include <linux/input.h>
#include <linux/io.h>
#include <linux/serial_sci.h>
+#include <linux/sh_dma.h>
#include <linux/sh_intc.h>
#include <linux/sh_timer.h>
#include <mach/hardware.h>
+#include <mach/sh7372.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+/* SCIFA0 */
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0c00), evt2irq(0x0c00),
+ evt2irq(0x0c00), evt2irq(0x0c00) },
};
static struct platform_device scif0_device = {
@@ -47,11 +51,13 @@ static struct platform_device scif0_device = {
},
};
+/* SCIFA1 */
static struct plat_sci_port scif1_platform_data = {
.mapbase = 0xe6c50000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0c20), evt2irq(0x0c20),
+ evt2irq(0x0c20), evt2irq(0x0c20) },
};
static struct platform_device scif1_device = {
@@ -62,11 +68,13 @@ static struct platform_device scif1_device = {
},
};
+/* SCIFA2 */
static struct plat_sci_port scif2_platform_data = {
.mapbase = 0xe6c60000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0c40), evt2irq(0x0c40),
+ evt2irq(0x0c40), evt2irq(0x0c40) },
};
static struct platform_device scif2_device = {
@@ -77,11 +85,13 @@ static struct platform_device scif2_device = {
},
};
+/* SCIFA3 */
static struct plat_sci_port scif3_platform_data = {
.mapbase = 0xe6c70000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 83, 83, 83, 83 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0c60), evt2irq(0x0c60),
+ evt2irq(0x0c60), evt2irq(0x0c60) },
};
static struct platform_device scif3_device = {
@@ -92,11 +102,13 @@ static struct platform_device scif3_device = {
},
};
+/* SCIFA4 */
static struct plat_sci_port scif4_platform_data = {
.mapbase = 0xe6c80000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 89, 89, 89, 89 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0d20), evt2irq(0x0d20),
+ evt2irq(0x0d20), evt2irq(0x0d20) },
};
static struct platform_device scif4_device = {
@@ -107,11 +119,13 @@ static struct platform_device scif4_device = {
},
};
+/* SCIFA5 */
static struct plat_sci_port scif5_platform_data = {
.mapbase = 0xe6cb0000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 90, 90, 90, 90 },
+ .type = PORT_SCIFA,
+ .irqs = { evt2irq(0x0d40), evt2irq(0x0d40),
+ evt2irq(0x0d40), evt2irq(0x0d40) },
};
static struct platform_device scif5_device = {
@@ -122,11 +136,13 @@ static struct platform_device scif5_device = {
},
};
+/* SCIFB */
static struct plat_sci_port scif6_platform_data = {
.mapbase = 0xe6c30000,
.flags = UPF_BOOT_AUTOCONF,
- .type = PORT_SCIF,
- .irqs = { 91, 91, 91, 91 },
+ .type = PORT_SCIFB,
+ .irqs = { evt2irq(0x0d60), evt2irq(0x0d60),
+ evt2irq(0x0d60), evt2irq(0x0d60) },
};
static struct platform_device scif6_device = {
@@ -137,11 +153,12 @@ static struct platform_device scif6_device = {
},
};
+/* CMT */
static struct sh_timer_config cmt10_platform_data = {
.name = "CMT10",
.channel_offset = 0x10,
.timer_bit = 0,
- .clk = "r_clk",
+ .clk = "cmt1",
.clockevent_rating = 125,
.clocksource_rating = 125,
};
@@ -154,7 +171,7 @@ static struct resource cmt10_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 72,
+ .start = evt2irq(0x0b00), /* CMT1_CMT10 */
.flags = IORESOURCE_IRQ,
},
};
@@ -169,6 +186,337 @@ static struct platform_device cmt10_device = {
.num_resources = ARRAY_SIZE(cmt10_resources),
};
+/* I2C */
+static struct resource iic0_resources[] = {
+ [0] = {
+ .name = "IIC0",
+ .start = 0xFFF20000,
+ .end = 0xFFF20425 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = intcs_evt2irq(0xe00), /* IIC0_ALI0 */
+ .end = intcs_evt2irq(0xe60), /* IIC0_DTEI0 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device iic0_device = {
+ .name = "i2c-sh_mobile",
+ .id = 0, /* "i2c0" clock */
+ .num_resources = ARRAY_SIZE(iic0_resources),
+ .resource = iic0_resources,
+};
+
+static struct resource iic1_resources[] = {
+ [0] = {
+ .name = "IIC1",
+ .start = 0xE6C20000,
+ .end = 0xE6C20425 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = evt2irq(0x780), /* IIC1_ALI1 */
+ .end = evt2irq(0x7e0), /* IIC1_DTEI1 */
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device iic1_device = {
+ .name = "i2c-sh_mobile",
+ .id = 1, /* "i2c1" clock */
+ .num_resources = ARRAY_SIZE(iic1_resources),
+ .resource = iic1_resources,
+};
+
+/* DMA */
+/* Transmit sizes and respective CHCR register values */
+enum {
+ XMIT_SZ_8BIT = 0,
+ XMIT_SZ_16BIT = 1,
+ XMIT_SZ_32BIT = 2,
+ XMIT_SZ_64BIT = 7,
+ XMIT_SZ_128BIT = 3,
+ XMIT_SZ_256BIT = 4,
+ XMIT_SZ_512BIT = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+#define TS_SHIFT { \
+ [XMIT_SZ_8BIT] = 0, \
+ [XMIT_SZ_16BIT] = 1, \
+ [XMIT_SZ_32BIT] = 2, \
+ [XMIT_SZ_64BIT] = 3, \
+ [XMIT_SZ_128BIT] = 4, \
+ [XMIT_SZ_256BIT] = 5, \
+ [XMIT_SZ_512BIT] = 6, \
+}
+
+#define TS_INDEX2VAL(i) ((((i) & 3) << 3) | \
+ (((i) & 0xc) << (20 - 2)))
+
+static const struct sh_dmae_slave_config sh7372_dmae_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_SCIF0_TX,
+ .addr = 0xe6c40020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x21,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF0_RX,
+ .addr = 0xe6c40024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x22,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF1_TX,
+ .addr = 0xe6c50020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x25,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF1_RX,
+ .addr = 0xe6c50024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x26,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF2_TX,
+ .addr = 0xe6c60020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x29,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF2_RX,
+ .addr = 0xe6c60024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x2a,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF3_TX,
+ .addr = 0xe6c70020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x2d,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF3_RX,
+ .addr = 0xe6c70024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x2e,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF4_TX,
+ .addr = 0xe6c80020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x39,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF4_RX,
+ .addr = 0xe6c80024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x3a,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF5_TX,
+ .addr = 0xe6cb0020,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x35,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF5_RX,
+ .addr = 0xe6cb0024,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x36,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF6_TX,
+ .addr = 0xe6c30040,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x3d,
+ }, {
+ .slave_id = SHDMA_SLAVE_SCIF6_RX,
+ .addr = 0xe6c30060,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_8BIT),
+ .mid_rid = 0x3e,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI0_TX,
+ .addr = 0xe6850030,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xc1,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI0_RX,
+ .addr = 0xe6850030,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xc2,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI1_TX,
+ .addr = 0xe6860030,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xc9,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI1_RX,
+ .addr = 0xe6860030,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xca,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI2_TX,
+ .addr = 0xe6870030,
+ .chcr = DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xcd,
+ }, {
+ .slave_id = SHDMA_SLAVE_SDHI2_RX,
+ .addr = 0xe6870030,
+ .chcr = DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL(XMIT_SZ_16BIT),
+ .mid_rid = 0xce,
+ },
+};
+
+static const struct sh_dmae_channel sh7372_dmae_channels[] = {
+ {
+ .offset = 0,
+ .dmars = 0,
+ .dmars_bit = 0,
+ }, {
+ .offset = 0x10,
+ .dmars = 0,
+ .dmars_bit = 8,
+ }, {
+ .offset = 0x20,
+ .dmars = 4,
+ .dmars_bit = 0,
+ }, {
+ .offset = 0x30,
+ .dmars = 4,
+ .dmars_bit = 8,
+ }, {
+ .offset = 0x50,
+ .dmars = 8,
+ .dmars_bit = 0,
+ }, {
+ .offset = 0x60,
+ .dmars = 8,
+ .dmars_bit = 8,
+ }
+};
+
+static const unsigned int ts_shift[] = TS_SHIFT;
+
+static struct sh_dmae_pdata dma_platform_data = {
+ .slave = sh7372_dmae_slaves,
+ .slave_num = ARRAY_SIZE(sh7372_dmae_slaves),
+ .channel = sh7372_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh7372_dmae_channels),
+ .ts_low_shift = 3,
+ .ts_low_mask = 0x18,
+ .ts_high_shift = (20 - 2), /* 2 bits for shifted low TS */
+ .ts_high_mask = 0x00300000,
+ .ts_shift = ts_shift,
+ .ts_shift_num = ARRAY_SIZE(ts_shift),
+ .dmaor_init = DMAOR_DME,
+};
+
+/* Resource order important! */
+static struct resource sh7372_dmae0_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xfe008020,
+ .end = 0xfe00808f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMARSx */
+ .start = 0xfe009000,
+ .end = 0xfe00900b,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMA error IRQ */
+ .start = 246,
+ .end = 246,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ /* IRQ for channels 0-5 */
+ .start = 240,
+ .end = 245,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* Resource order important! */
+static struct resource sh7372_dmae1_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xfe018020,
+ .end = 0xfe01808f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMARSx */
+ .start = 0xfe019000,
+ .end = 0xfe01900b,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMA error IRQ */
+ .start = 254,
+ .end = 254,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ /* IRQ for channels 0-5 */
+ .start = 248,
+ .end = 253,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+/* Resource order important! */
+static struct resource sh7372_dmae2_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xfe028020,
+ .end = 0xfe02808f,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMARSx */
+ .start = 0xfe029000,
+ .end = 0xfe02900b,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* DMA error IRQ */
+ .start = 262,
+ .end = 262,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ /* IRQ for channels 0-5 */
+ .start = 256,
+ .end = 261,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device dma0_device = {
+ .name = "sh-dma-engine",
+ .id = 0,
+ .resource = sh7372_dmae0_resources,
+ .num_resources = ARRAY_SIZE(sh7372_dmae0_resources),
+ .dev = {
+ .platform_data = &dma_platform_data,
+ },
+};
+
+static struct platform_device dma1_device = {
+ .name = "sh-dma-engine",
+ .id = 1,
+ .resource = sh7372_dmae1_resources,
+ .num_resources = ARRAY_SIZE(sh7372_dmae1_resources),
+ .dev = {
+ .platform_data = &dma_platform_data,
+ },
+};
+
+static struct platform_device dma2_device = {
+ .name = "sh-dma-engine",
+ .id = 2,
+ .resource = sh7372_dmae2_resources,
+ .num_resources = ARRAY_SIZE(sh7372_dmae2_resources),
+ .dev = {
+ .platform_data = &dma_platform_data,
+ },
+};
+
static struct platform_device *sh7372_early_devices[] __initdata = {
&scif0_device,
&scif1_device,
@@ -178,6 +526,11 @@ static struct platform_device *sh7372_early_devices[] __initdata = {
&scif5_device,
&scif6_device,
&cmt10_device,
+ &iic0_device,
+ &iic1_device,
+ &dma0_device,
+ &dma1_device,
+ &dma2_device,
};
void __init sh7372_add_standard_devices(void)
@@ -186,14 +539,8 @@ void __init sh7372_add_standard_devices(void)
ARRAY_SIZE(sh7372_early_devices));
}
-#define SMSTPCR3 0xe615013c
-#define SMSTPCR3_CMT1 (1 << 29)
-
void __init sh7372_add_early_devices(void)
{
- /* enable clock to CMT1 */
- __raw_writel(__raw_readl(SMSTPCR3) & ~SMSTPCR3_CMT1, SMSTPCR3);
-
early_platform_add_devices(sh7372_early_devices,
ARRAY_SIZE(sh7372_early_devices));
}
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c
index 60e37774c35c..bb4adf17dbf4 100644
--- a/arch/arm/mach-shmobile/setup-sh7377.c
+++ b/arch/arm/mach-shmobile/setup-sh7377.c
@@ -32,11 +32,13 @@
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+/* SCIFA0 */
static struct plat_sci_port scif0_platform_data = {
.mapbase = 0xe6c40000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 80, 80, 80, 80 },
+ .irqs = { evt2irq(0xc00), evt2irq(0xc00),
+ evt2irq(0xc00), evt2irq(0xc00) },
};
static struct platform_device scif0_device = {
@@ -47,11 +49,13 @@ static struct platform_device scif0_device = {
},
};
+/* SCIFA1 */
static struct plat_sci_port scif1_platform_data = {
.mapbase = 0xe6c50000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 81, 81, 81, 81 },
+ .irqs = { evt2irq(0xc20), evt2irq(0xc20),
+ evt2irq(0xc20), evt2irq(0xc20) },
};
static struct platform_device scif1_device = {
@@ -62,11 +66,13 @@ static struct platform_device scif1_device = {
},
};
+/* SCIFA2 */
static struct plat_sci_port scif2_platform_data = {
.mapbase = 0xe6c60000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 82, 82, 82, 82 },
+ .irqs = { evt2irq(0xc40), evt2irq(0xc40),
+ evt2irq(0xc40), evt2irq(0xc40) },
};
static struct platform_device scif2_device = {
@@ -77,11 +83,13 @@ static struct platform_device scif2_device = {
},
};
+/* SCIFA3 */
static struct plat_sci_port scif3_platform_data = {
.mapbase = 0xe6c70000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 83, 83, 83, 83 },
+ .irqs = { evt2irq(0xc60), evt2irq(0xc60),
+ evt2irq(0xc60), evt2irq(0xc60) },
};
static struct platform_device scif3_device = {
@@ -92,11 +100,13 @@ static struct platform_device scif3_device = {
},
};
+/* SCIFA4 */
static struct plat_sci_port scif4_platform_data = {
.mapbase = 0xe6c80000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 89, 89, 89, 89 },
+ .irqs = { evt2irq(0xd20), evt2irq(0xd20),
+ evt2irq(0xd20), evt2irq(0xd20) },
};
static struct platform_device scif4_device = {
@@ -107,11 +117,13 @@ static struct platform_device scif4_device = {
},
};
+/* SCIFA5 */
static struct plat_sci_port scif5_platform_data = {
.mapbase = 0xe6cb0000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 90, 90, 90, 90 },
+ .irqs = { evt2irq(0xd40), evt2irq(0xd40),
+ evt2irq(0xd40), evt2irq(0xd40) },
};
static struct platform_device scif5_device = {
@@ -122,11 +134,13 @@ static struct platform_device scif5_device = {
},
};
+/* SCIFA6 */
static struct plat_sci_port scif6_platform_data = {
.mapbase = 0xe6cc0000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 196, 196, 196, 196 },
+ .irqs = { intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80),
+ intcs_evt2irq(0x1a80), intcs_evt2irq(0x1a80) },
};
static struct platform_device scif6_device = {
@@ -137,11 +151,13 @@ static struct platform_device scif6_device = {
},
};
+/* SCIFB */
static struct plat_sci_port scif7_platform_data = {
.mapbase = 0xe6c30000,
.flags = UPF_BOOT_AUTOCONF,
.type = PORT_SCIF,
- .irqs = { 91, 91, 91, 91 },
+ .irqs = { evt2irq(0xd60), evt2irq(0xd60),
+ evt2irq(0xd60), evt2irq(0xd60) },
};
static struct platform_device scif7_device = {
@@ -169,7 +185,7 @@ static struct resource cmt10_resources[] = {
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = 72,
+ .start = evt2irq(0xb00), /* CMT1_CMT10 */
.flags = IORESOURCE_IRQ,
},
};
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 6544855af2f1..fe84b9021c7a 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -16,6 +16,7 @@
#include <asm/clkdev.h>
+#include <plat/mtu.h>
#include <mach/hardware.h>
#include "clock.h"
@@ -59,6 +60,9 @@
#define PRCM_DMACLK_MGT 0x074
#define PRCM_B2R2CLK_MGT 0x078
#define PRCM_TVCLK_MGT 0x07C
+#define PRCM_TCR 0x1C8
+#define PRCM_TCR_STOPPED (1 << 16)
+#define PRCM_TCR_DOZE_MODE (1 << 17)
#define PRCM_UNIPROCLK_MGT 0x278
#define PRCM_SSPCLK_MGT 0x280
#define PRCM_RNGCLK_MGT 0x284
@@ -120,10 +124,95 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL(clk_disable);
+/*
+ * The MTU has a separate, rather complex muxing setup
+ * with alternative parents (peripheral cluster or
+ * ULP or fixed 32768 Hz) depending on settings
+ */
+static unsigned long clk_mtu_get_rate(struct clk *clk)
+{
+ void __iomem *addr = __io_address(U8500_PRCMU_BASE)
+ + PRCM_TCR;
+ u32 tcr = readl(addr);
+ int mtu = (int) clk->data;
+ /*
+ * One of these is selected eventually
+ * TODO: Replace the constant with a reference
+ * to the ULP source once this is modeled.
+ */
+ unsigned long clk32k = 32768;
+ unsigned long mturate;
+ unsigned long retclk;
+
+ /* Get the rate from the parent as a default */
+ if (clk->parent_periph)
+ mturate = clk_get_rate(clk->parent_periph);
+ else if (clk->parent_cluster)
+ mturate = clk_get_rate(clk->parent_cluster);
+ else
+ /* We need to be connected SOMEWHERE */
+ BUG();
+
+ /*
+ * Are we in doze mode?
+ * In this mode the parent peripheral or the fixed 32768 Hz
+ * clock is fed into the block.
+ */
+ if (!(tcr & PRCM_TCR_DOZE_MODE)) {
+ /*
+ * Here we're using the clock input from the APE ULP
+ * clock domain. But first: are the timers stopped?
+ */
+ if (tcr & PRCM_TCR_STOPPED) {
+ clk32k = 0;
+ mturate = 0;
+ } else {
+ /* Else default mode: 0 and 2.4 MHz */
+ clk32k = 0;
+ if (cpu_is_u5500())
+ /* DB5500 divides by 8 */
+ mturate /= 8;
+ else if (cpu_is_u8500ed()) {
+ /*
+ * This clocking setting must not be used
+ * in the ED chip, it is simply not
+ * connected anywhere!
+ */
+ mturate = 0;
+ BUG();
+ } else
+ /*
+ * In this mode the ulp38m4 clock is divided
+ * by a factor 16, on the DB8500 typically
+ * 38400000 / 16 ~ 2.4 MHz.
+ * TODO: Replace the constant with a reference
+ * to the ULP source once this is modeled.
+ */
+ mturate = 38400000 / 16;
+ }
+ }
+
+ /* Return the clock selected for this MTU */
+ if (tcr & (1 << mtu))
+ retclk = clk32k;
+ else
+ retclk = mturate;
+
+ pr_info("MTU%d clock rate: %lu Hz\n", mtu, retclk);
+ return retclk;
+}
+
unsigned long clk_get_rate(struct clk *clk)
{
unsigned long rate;
+ /*
+ * If there is a custom getrate callback for this clock,
+ * it will take precedence.
+ */
+ if (clk->get_rate)
+ return clk->get_rate(clk);
+
if (clk->ops && clk->ops->get_rate)
return clk->ops->get_rate(clk);
@@ -341,8 +430,9 @@ static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
/* Peripheral Cluster #6 */
-static DEFINE_PRCC_CLK(6, mtu1_v1, 8, -1, NULL);
-static DEFINE_PRCC_CLK(6, mtu0_v1, 7, -1, NULL);
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
@@ -357,8 +447,9 @@ static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
/* Peripheral Cluster #7 */
static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
-static DEFINE_PRCC_CLK(7, mtu1_ed, 3, -1, NULL);
-static DEFINE_PRCC_CLK(7, mtu0_ed, 2, -1, NULL);
+/* MTU ID in data */
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
+static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
@@ -503,15 +594,17 @@ static struct clk_lookup u8500_v1_clks[] = {
CLK(uiccclk, "uicc", NULL),
};
-static int __init clk_init(void)
+int __init clk_init(void)
{
if (cpu_is_u8500ed()) {
clk_prcmu_ops.enable = clk_prcmu_ed_enable;
clk_prcmu_ops.disable = clk_prcmu_ed_disable;
+ clk_per6clk.rate = 100000000;
} else if (cpu_is_u5500()) {
/* Clock tree for U5500 not implemented yet */
clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
+ clk_per6clk.rate = 26000000;
}
clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
@@ -522,4 +615,3 @@ static int __init clk_init(void)
return 0;
}
-arch_initcall(clk_init);
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
index e4f99b65026f..a05802501527 100644
--- a/arch/arm/mach-ux500/clock.h
+++ b/arch/arm/mach-ux500/clock.h
@@ -28,6 +28,9 @@ struct clkops {
* @ops: pointer to clkops struct used to control this clock
* @name: name, for debugging
* @enabled: refcount. positive if enabled, zero if disabled
+ * @get_rate: custom callback for getting the clock rate
+ * @data: custom per-clock data for example for the get_rate
+ * callback
* @rate: fixed rate for clocks which don't implement
* ops->getrate
* @prcmu_cg_off: address offset of the combined enable/disable register
@@ -67,6 +70,8 @@ struct clk {
const struct clkops *ops;
const char *name;
unsigned int enabled;
+ unsigned long (*get_rate)(struct clk *);
+ void *data;
unsigned long rate;
struct list_head list;
@@ -117,9 +122,26 @@ struct clk clk_##_name = { \
.parent_periph = _kernclk \
}
+#define DEFINE_PRCC_CLK_CUSTOM(_pclust, _name, _bus_en, _kernel_en, _kernclk, _callback, _data) \
+struct clk clk_##_name = { \
+ .name = #_name, \
+ .ops = &clk_prcc_ops, \
+ .cluster = _pclust, \
+ .prcc_bus = _bus_en, \
+ .prcc_kernel = _kernel_en, \
+ .parent_cluster = &clk_per##_pclust##clk, \
+ .parent_periph = _kernclk, \
+ .get_rate = _callback, \
+ .data = (void *) _data \
+ }
+
+
#define CLK(_clk, _devname, _conname) \
{ \
.clk = &clk_##_clk, \
.dev_id = _devname, \
.con_id = _conname, \
}
+
+int __init clk_db8500_ed_fixup(void);
+int __init clk_init(void);
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index d81ad023963c..e0fd747e447a 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -62,6 +62,12 @@ void __init ux500_init_irq(void)
{
gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29);
gic_cpu_init(0, __io_address(UX500_GIC_CPU_BASE));
+
+ /*
+ * Init clocks here so that they are available for system timer
+ * initialization.
+ */
+ clk_init();
}
#ifdef CONFIG_CACHE_L2X0
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
index e6f73030d5f0..9b11eedba65f 100644
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ b/arch/arm/mach-vexpress/ct-ca9x4.c
@@ -2,6 +2,7 @@
* Versatile Express Core Tile Cortex A9x4 Support
*/
#include <linux/init.h>
+#include <linux/gfp.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 1ba6cf5a2c02..f6a999465323 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -678,10 +678,10 @@ void __init mem_init(void)
void free_initmem(void)
{
#ifdef CONFIG_HAVE_TCM
- extern char *__tcm_start, *__tcm_end;
+ extern char __tcm_start, __tcm_end;
- totalram_pages += free_area(__phys_to_pfn(__pa(__tcm_start)),
- __phys_to_pfn(__pa(__tcm_end)),
+ totalram_pages += free_area(__phys_to_pfn(__pa(&__tcm_start)),
+ __phys_to_pfn(__pa(&__tcm_end)),
"TCM link");
#endif
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index 323ff8ccc877..2ed3ab173add 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -52,13 +52,14 @@ static void __clk_disable(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
return;
-
- __clk_disable(clk->parent);
- __clk_disable(clk->secondary);
-
WARN_ON(!clk->usecount);
- if (!(--clk->usecount) && clk->disable)
- clk->disable(clk);
+
+ if (!(--clk->usecount)) {
+ if (clk->disable)
+ clk->disable(clk);
+ __clk_disable(clk->parent);
+ __clk_disable(clk->secondary);
+ }
}
static int __clk_enable(struct clk *clk)
@@ -66,12 +67,13 @@ static int __clk_enable(struct clk *clk)
if (clk == NULL || IS_ERR(clk))
return -EINVAL;
- __clk_enable(clk->parent);
- __clk_enable(clk->secondary);
-
- if (clk->usecount++ == 0 && clk->enable)
- clk->enable(clk);
+ if (clk->usecount++ == 0) {
+ __clk_enable(clk->parent);
+ __clk_enable(clk->secondary);
+ if (clk->enable)
+ clk->enable(clk);
+ }
return 0;
}
@@ -160,17 +162,28 @@ EXPORT_SYMBOL(clk_set_rate);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
int ret = -EINVAL;
+ struct clk *old;
if (clk == NULL || IS_ERR(clk) || parent == NULL ||
IS_ERR(parent) || clk->set_parent == NULL)
return ret;
+ if (clk->usecount)
+ clk_enable(parent);
+
mutex_lock(&clocks_mutex);
ret = clk->set_parent(clk, parent);
- if (ret == 0)
+ if (ret == 0) {
+ old = clk->parent;
clk->parent = parent;
+ } else {
+ old = parent;
+ }
mutex_unlock(&clocks_mutex);
+ if (clk->usecount)
+ clk_disable(old);
+
return ret;
}
EXPORT_SYMBOL(clk_set_parent);
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx25.h b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
index f39220d1b67a..e88d01a125a6 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx25.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx25.h
@@ -371,30 +371,33 @@
#define MX25_PAD_SD1_DATA3__FEC_CRS IOMUX_PAD(0x39c, 0x1a4, 0x10, 0x508, 2, NO_PAD_CTRL)
#define MX25_PAD_SD1_DATA3__GPIO_2_28 IOMUX_PAD(0x39c, 0x1a4, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, PAD_CTL_PKE)
+#define KPP_CTL_ROW (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
+#define KPP_CTL_COL (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP | PAD_CTL_ODE)
+
+#define MX25_PAD_KPP_ROW0__KPP_ROW0 IOMUX_PAD(0x3a0, 0x1a8, 0x10, 0, 0, KPP_CTL_ROW)
#define MX25_PAD_KPP_ROW0__GPIO_2_29 IOMUX_PAD(0x3a0, 0x1a8, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_ROW1__KPP_ROW1 IOMUX_PAD(0x3a4, 0x1ac, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW1__KPP_ROW1 IOMUX_PAD(0x3a4, 0x1ac, 0x10, 0, 0, KPP_CTL_ROW)
#define MX25_PAD_KPP_ROW1__GPIO_2_30 IOMUX_PAD(0x3a4, 0x1ac, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_ROW2__KPP_ROW2 IOMUX_PAD(0x3a8, 0x1b0, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW2__KPP_ROW2 IOMUX_PAD(0x3a8, 0x1b0, 0x10, 0, 0, KPP_CTL_ROW)
#define MX25_PAD_KPP_ROW2__CSI_D0 IOMUX_PAD(0x3a8, 0x1b0, 0x13, 0x488, 2, NO_PAD_CTRL)
#define MX25_PAD_KPP_ROW2__GPIO_2_31 IOMUX_PAD(0x3a8, 0x1b0, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_ROW3__KPP_ROW3 IOMUX_PAD(0x3ac, 0x1b4, 0x10, 0, 0, PAD_CTL_PKE)
+#define MX25_PAD_KPP_ROW3__KPP_ROW3 IOMUX_PAD(0x3ac, 0x1b4, 0x10, 0, 0, KPP_CTL_ROW)
#define MX25_PAD_KPP_ROW3__CSI_LD1 IOMUX_PAD(0x3ac, 0x1b4, 0x13, 0x48c, 2, NO_PAD_CTRL)
#define MX25_PAD_KPP_ROW3__GPIO_3_0 IOMUX_PAD(0x3ac, 0x1b4, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_COL0__KPP_COL0 IOMUX_PAD(0x3b0, 0x1b8, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL0__KPP_COL0 IOMUX_PAD(0x3b0, 0x1b8, 0x10, 0, 0, KPP_CTL_COL)
#define MX25_PAD_KPP_COL0__GPIO_3_1 IOMUX_PAD(0x3b0, 0x1b8, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_COL1__KPP_COL1 IOMUX_PAD(0x3b4, 0x1bc, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL1__KPP_COL1 IOMUX_PAD(0x3b4, 0x1bc, 0x10, 0, 0, KPP_CTL_COL)
#define MX25_PAD_KPP_COL1__GPIO_3_2 IOMUX_PAD(0x3b4, 0x1bc, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_COL2__KPP_COL2 IOMUX_PAD(0x3b8, 0x1c0, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL2__KPP_COL2 IOMUX_PAD(0x3b8, 0x1c0, 0x10, 0, 0, KPP_CTL_COL)
#define MX25_PAD_KPP_COL2__GPIO_3_3 IOMUX_PAD(0x3b8, 0x1c0, 0x15, 0, 0, NO_PAD_CTRL)
-#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, PAD_CTL_PKE | PAD_CTL_ODE)
+#define MX25_PAD_KPP_COL3__KPP_COL3 IOMUX_PAD(0x3bc, 0x1c4, 0x10, 0, 0, KPP_CTL_COL)
#define MX25_PAD_KPP_COL3__GPIO_3_4 IOMUX_PAD(0x3bc, 0x1c4, 0x15, 0, 0, NO_PAD_CTRL)
#define MX25_PAD_FEC_MDC__FEC_MDC IOMUX_PAD(0x3c0, 0x1c8, 0x10, 0, 0, NO_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/iomux-mx51.h b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
index ab0f95d953d0..38961c6a6f0d 100644
--- a/arch/arm/plat-mxc/include/mach/iomux-mx51.h
+++ b/arch/arm/plat-mxc/include/mach/iomux-mx51.h
@@ -38,6 +38,8 @@ typedef enum iomux_config {
PAD_CTL_SRE_FAST)
#define MX51_UART3_PAD_CTRL (PAD_CTL_PKE | PAD_CTL_DSE_HIGH | \
PAD_CTL_SRE_FAST)
+#define MX51_I2C_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_ODE | \
+ PAD_CTL_DSE_HIGH | PAD_CTL_PUS_100K_UP | PAD_CTL_HYS)
#define MX51_USBH1_PAD_CTRL (PAD_CTL_SRE_FAST | PAD_CTL_DSE_HIGH | \
PAD_CTL_PUS_100K_UP | PAD_CTL_PUE | \
PAD_CTL_PKE | PAD_CTL_HYS)
@@ -57,10 +59,12 @@ typedef enum iomux_config {
/* PAD MUX ALT INPSE PATH PADCTRL */
-#define MX51_PAD_GPIO_2_0__EIM_D16 IOMUX_PAD(0x3f0, 0x05c, 1, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D16__I2C1_SDA IOMUX_PAD(0x3f0, 0x05c, IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION, \
+ 0x09b4, 0, MX51_I2C_PAD_CTRL)
#define MX51_PAD_GPIO_2_1__EIM_D17 IOMUX_PAD(0x3f4, 0x060, 1, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_2_2__EIM_D18 IOMUX_PAD(0x3f8, 0x064, 1, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_2_3__EIM_D19 IOMUX_PAD(0x3fc, 0x068, 1, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_EIM_D19__I2C1_SCL IOMUX_PAD(0x3fc, 0x068, IOMUX_CONFIG_ALT4 | IOMUX_CONFIG_SION, \
+ 0x09b0, 0, MX51_I2C_PAD_CTRL)
#define MX51_PAD_GPIO_2_4__EIM_D20 IOMUX_PAD(0x400, 0x06c, 1, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_2_5__EIM_D21 IOMUX_PAD(0x404, 0x070, 1, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_EIM_D21__GPIO_2_5 IOMUX_PAD(0x404, 0x070, IOMUX_CONFIG_ALT1, 0x0, 0, MX51_GPIO_PAD_CTRL)
@@ -179,8 +183,8 @@ typedef enum iomux_config {
#define MX51_PAD_GPIO_4_14__CSI2_HSYNC IOMUX_PAD(0x5E0, 0x1F0, 3, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_4_15__CSI2_PIXCLK IOMUX_PAD(0x5E4, 0x1F4, 3, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_CSI2_PKE0__CSI2_PKE0 IOMUX_PAD(0x81C, 0x0, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_16__I2C1_CLK IOMUX_PAD(0x5E8, 0x1F8, 3, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_GPIO_4_17__I2C1_DAT IOMUX_PAD(0x5EC, 0x1FC, 3, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_CLK__HSI2C_CLK IOMUX_PAD(0x5E8, 0x1F8, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_I2C1_DAT__HSI2C_DAT IOMUX_PAD(0x5EC, 0x1FC, IOMUX_CONFIG_ALT0, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_4_18__AUD3_BB_TXD IOMUX_PAD(0x5F0, 0x200, 3, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_4_19__AUD3_BB_RXD IOMUX_PAD(0x5F4, 0x204, 3, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_GPIO_4_20__AUD3_BB_CK IOMUX_PAD(0x5F8, 0x208, 3, 0x0, 0, NO_PAD_CTRL)
@@ -213,8 +217,10 @@ typedef enum iomux_config {
#define MX51_PAD_KEY_COL1__KEY_COL1 IOMUX_PAD(0x650, 0x260, 0, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_KEY_COL2__KEY_COL2 IOMUX_PAD(0x654, 0x264, 0, 0x0, 0, NO_PAD_CTRL)
#define MX51_PAD_KEY_COL3__KEY_COL3 IOMUX_PAD(0x658, 0x268, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL4__KEY_COL4 IOMUX_PAD(0x65C, 0x26C, 0, 0x0, 0, NO_PAD_CTRL)
-#define MX51_PAD_KEY_COL5__KEY_COL5 IOMUX_PAD(0x660, 0x270, 0, 0x0, 0, NO_PAD_CTRL)
+#define MX51_PAD_KEY_COL4__I2C2_SCL IOMUX_PAD(0x65C, 0x26C, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION, \
+ 0x09b8, 1, MX51_I2C_PAD_CTRL)
+#define MX51_PAD_KEY_COL5__I2C2_SDA IOMUX_PAD(0x660, 0x270, IOMUX_CONFIG_ALT3 | IOMUX_CONFIG_SION, \
+ 0x09bc, 1, MX51_I2C_PAD_CTRL)
#define MX51_PAD_USBH1_CLK__USBH1_CLK IOMUX_PAD(0x678, 0x278, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
#define MX51_PAD_USBH1_DIR__USBH1_DIR IOMUX_PAD(0x67C, 0x27C, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
#define MX51_PAD_USBH1_STP__USBH1_STP IOMUX_PAD(0x680, 0x280, IOMUX_CONFIG_ALT0, 0x0, 0, MX51_USBH1_PAD_CTRL)
diff --git a/arch/arm/plat-mxc/include/mach/mmc.h b/arch/arm/plat-mxc/include/mach/mmc.h
index de2128dada5c..29115f405af9 100644
--- a/arch/arm/plat-mxc/include/mach/mmc.h
+++ b/arch/arm/plat-mxc/include/mach/mmc.h
@@ -31,6 +31,9 @@ struct imxmmc_platform_data {
/* adjust slot voltage */
void (*setpower)(struct device *, unsigned int vdd);
+
+ /* enable card detect using DAT3 */
+ int dat3_card_detect;
};
#endif
diff --git a/arch/arm/plat-mxc/include/mach/mx25.h b/arch/arm/plat-mxc/include/mach/mx25.h
index 4eb6e334bda5..35fb9f5e5d1c 100644
--- a/arch/arm/plat-mxc/include/mach/mx25.h
+++ b/arch/arm/plat-mxc/include/mach/mx25.h
@@ -34,11 +34,13 @@
#define MX25_NFC_BASE_ADDR 0xbb000000
#define MX25_DRYICE_BASE_ADDR 0x53ffc000
#define MX25_LCDC_BASE_ADDR 0x53fbc000
+#define MX25_KPP_BASE_ADDR 0x43fa8000
#define MX25_INT_DRYICE 25
#define MX25_INT_FEC 57
#define MX25_INT_NANDFC 33
#define MX25_INT_LCDC 39
+#define MX25_INT_KPP 24
#if defined(IMX_NEEDS_DEPRECATED_SYMBOLS)
#define UART1_BASE_ADDR MX25_UART1_BASE_ADDR
diff --git a/arch/arm/plat-mxc/include/mach/mxc_nand.h b/arch/arm/plat-mxc/include/mach/mxc_nand.h
index 5d2d21d414e0..2d74748c5db7 100644
--- a/arch/arm/plat-mxc/include/mach/mxc_nand.h
+++ b/arch/arm/plat-mxc/include/mach/mxc_nand.h
@@ -20,9 +20,13 @@
#ifndef __ASM_ARCH_NAND_H
#define __ASM_ARCH_NAND_H
+#include <linux/mtd/partitions.h>
+
struct mxc_nand_platform_data {
int width; /* data bus width in bytes */
int hw_ecc:1; /* 0 if supress hardware ECC */
int flash_bbt:1; /* set to 1 to use a flash based bbt */
+ struct mtd_partition *parts; /* partition table */
+ int nr_parts; /* size of parts */
};
#endif /* __ASM_ARCH_NAND_H */
diff --git a/arch/arm/plat-mxc/include/mach/ssi.h b/arch/arm/plat-mxc/include/mach/ssi.h
index c34ded523f10..63f3c2804239 100644
--- a/arch/arm/plat-mxc/include/mach/ssi.h
+++ b/arch/arm/plat-mxc/include/mach/ssi.h
@@ -10,6 +10,9 @@ struct imx_ssi_platform_data {
unsigned int flags;
#define IMX_SSI_DMA (1 << 0)
#define IMX_SSI_USE_AC97 (1 << 1)
+#define IMX_SSI_NET (1 << 2)
+#define IMX_SSI_SYN (1 << 3)
+#define IMX_SSI_USE_I2S_SLAVE (1 << 4)
void (*ac97_reset) (struct snd_ac97 *ac97);
void (*ac97_warm_reset)(struct snd_ac97 *ac97);
};
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index 0ff3798769ab..08aaa4a7f65f 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -13,7 +13,9 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/clockchips.h>
+#include <linux/clk.h>
#include <linux/jiffies.h>
+#include <linux/err.h>
#include <asm/mach/time.h>
#include <plat/mtu.h>
@@ -124,13 +126,25 @@ static struct irqaction nmdk_timer_irq = {
void __init nmdk_timer_init(void)
{
unsigned long rate;
- u32 cr = MTU_CRn_32BITS;;
+ struct clk *clk0;
+ struct clk *clk1;
+ u32 cr;
+
+ clk0 = clk_get_sys("mtu0", NULL);
+ BUG_ON(IS_ERR(clk0));
+
+ clk1 = clk_get_sys("mtu1", NULL);
+ BUG_ON(IS_ERR(clk1));
+
+ clk_enable(clk0);
+ clk_enable(clk1);
/*
* Tick rate is 2.4MHz for Nomadik and 110MHz for ux500:
* use a divide-by-16 counter if it's more than 16MHz
*/
- rate = CLOCK_TICK_RATE;
+ cr = MTU_CRn_32BITS;;
+ rate = clk_get_rate(clk0);
if (rate > 16 << 20) {
rate /= 16;
cr |= MTU_CRn_PRESCALE_16;
@@ -153,6 +167,14 @@ void __init nmdk_timer_init(void)
nmdk_clksrc.name);
/* Timer 1 is used for events, fix according to rate */
+ cr = MTU_CRn_32BITS;
+ rate = clk_get_rate(clk1);
+ if (rate > 16 << 20) {
+ rate /= 16;
+ cr |= MTU_CRn_PRESCALE_16;
+ } else {
+ cr |= MTU_CRn_PRESCALE_1;
+ }
writel(cr | MTU_CRn_ONESHOT, mtu_base + MTU_CR(1)); /* off, currently */
nmdk_clkevt.mult = div_sc(rate, NSEC_PER_SEC, nmdk_clkevt.shift);
nmdk_clkevt.max_delta_ns =
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index c64875f11fac..44bafdab2dce 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -541,11 +541,11 @@ void omap_dm_timer_stop(struct omap_dm_timer *timer)
* timer is stopped
*/
udelay(3500000 / clk_get_rate(timer->fclk) + 1);
- /* Ack possibly pending interrupt */
- omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
- OMAP_TIMER_INT_OVERFLOW);
#endif
}
+ /* Ack possibly pending interrupt */
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
+ OMAP_TIMER_INT_OVERFLOW);
}
EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 393e9219a5b6..9b7e3545f325 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -673,6 +673,7 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
if (cpu_is_omap34xx() || cpu_is_omap44xx())
clk_disable(bank->dbck);
}
+ bank->dbck_enable_mask = val;
__raw_writel(val, reg);
}
diff --git a/arch/arm/plat-omap/include/plat/mcbsp.h b/arch/arm/plat-omap/include/plat/mcbsp.h
index 975744f10a58..b4ff6a11a8f2 100644
--- a/arch/arm/plat-omap/include/plat/mcbsp.h
+++ b/arch/arm/plat-omap/include/plat/mcbsp.h
@@ -473,6 +473,7 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
+u16 omap_mcbsp_get_fifo_size(unsigned int id);
u16 omap_mcbsp_get_tx_delay(unsigned int id);
u16 omap_mcbsp_get_rx_delay(unsigned int id);
int omap_mcbsp_get_dma_op_mode(unsigned int id);
@@ -483,6 +484,7 @@ static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{ }
static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
+static inline u16 omap_mcbsp_get_fifo_size(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_tx_delay(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_rx_delay(unsigned int id) { return 0; }
static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
diff --git a/arch/arm/plat-omap/include/plat/uncompress.h b/arch/arm/plat-omap/include/plat/uncompress.h
index bbedd71943f6..ddf723be48dc 100644
--- a/arch/arm/plat-omap/include/plat/uncompress.h
+++ b/arch/arm/plat-omap/include/plat/uncompress.h
@@ -25,6 +25,8 @@
#include <plat/serial.h>
+#define MDR1_MODE_MASK 0x07
+
static volatile u8 *uart_base;
static int uart_shift;
@@ -42,6 +44,10 @@ static void putc(int c)
if (!uart_base)
return;
+ /* Check for UART 16x mode */
+ if ((uart_base[UART_OMAP_MDR1 << uart_shift] & MDR1_MODE_MASK) != 0)
+ return;
+
while (!(uart_base[UART_LSR << uart_shift] & UART_LSR_THRE))
barrier();
uart_base[UART_TX << uart_shift] = c;
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 7e669c9744d8..e31496e35b0f 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -481,9 +481,9 @@ int omap_st_is_enabled(unsigned int id)
EXPORT_SYMBOL(omap_st_is_enabled);
/*
- * omap_mcbsp_set_tx_threshold configures how to deal
- * with transmit threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the transmit threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH2 register.
*/
void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
{
@@ -498,14 +498,15 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
}
mcbsp = id_to_mcbsp_ptr(id);
- MCBSP_WRITE(mcbsp, THRSH2, threshold);
+ if (threshold && threshold <= mcbsp->max_tx_thres)
+ MCBSP_WRITE(mcbsp, THRSH2, threshold - 1);
}
EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
/*
- * omap_mcbsp_set_rx_threshold configures how to deal
- * with receive threshold. the threshold value and handler can be
- * configure in here.
+ * omap_mcbsp_set_rx_threshold configures the receive threshold in words.
+ * The threshold parameter is 1 based, and it is converted (threshold - 1)
+ * for the THRSH1 register.
*/
void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{
@@ -520,7 +521,8 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
}
mcbsp = id_to_mcbsp_ptr(id);
- MCBSP_WRITE(mcbsp, THRSH1, threshold);
+ if (threshold && threshold <= mcbsp->max_rx_thres)
+ MCBSP_WRITE(mcbsp, THRSH1, threshold - 1);
}
EXPORT_SYMBOL(omap_mcbsp_set_rx_threshold);
@@ -560,8 +562,20 @@ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
}
EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
-#define MCBSP2_FIFO_SIZE 0x500 /* 1024 + 256 locations */
-#define MCBSP1345_FIFO_SIZE 0x80 /* 128 locations */
+u16 omap_mcbsp_get_fifo_size(unsigned int id)
+{
+ struct omap_mcbsp *mcbsp;
+
+ if (!omap_mcbsp_check_valid_id(id)) {
+ printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+ return -ENODEV;
+ }
+ mcbsp = id_to_mcbsp_ptr(id);
+
+ return mcbsp->pdata->buffer_size;
+}
+EXPORT_SYMBOL(omap_mcbsp_get_fifo_size);
+
/*
* omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
*/
@@ -580,10 +594,7 @@ u16 omap_mcbsp_get_tx_delay(unsigned int id)
buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
/* Number of slots are different in McBSP ports */
- if (mcbsp->id == 2)
- return MCBSP2_FIFO_SIZE - buffstat;
- else
- return MCBSP1345_FIFO_SIZE - buffstat;
+ return mcbsp->pdata->buffer_size - buffstat;
}
EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
@@ -1683,8 +1694,16 @@ static inline void __devinit omap34xx_device_init(struct omap_mcbsp *mcbsp)
{
mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT;
if (cpu_is_omap34xx()) {
- mcbsp->max_tx_thres = max_thres(mcbsp);
- mcbsp->max_rx_thres = max_thres(mcbsp);
+ /*
+ * Initially configure the maximum thresholds to a safe value.
+ * The McBSP FIFO usage with these values should not go under
+ * 16 locations.
+ * If the whole FIFO without safety buffer is used, than there
+ * is a possibility that the DMA will be not able to push the
+ * new data on time, causing channel shifts in runtime.
+ */
+ mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10;
+ mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10;
/*
* REVISIT: Set dmap_op_mode to THRESHOLD as default
* for mcbsp2 instances.
diff --git a/arch/arm/plat-orion/include/plat/audio.h b/arch/arm/plat-orion/include/plat/audio.h
new file mode 100644
index 000000000000..9cf1f781329b
--- /dev/null
+++ b/arch/arm/plat-orion/include/plat/audio.h
@@ -0,0 +1,11 @@
+#ifndef __PLAT_AUDIO_H
+#define __PLAT_AUDIO_H
+
+#include <linux/mbus.h>
+
+struct kirkwood_asoc_platform_data {
+ u32 tclk;
+ struct mbus_dram_target_info *dram;
+ int burst;
+};
+#endif
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index 66dc2d03b7fc..d66cead97d28 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -277,7 +277,7 @@ ENTRY(vfp_put_double)
#ifdef CONFIG_VFPv3
@ d16 - d31 registers
.irp dr,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
-1: mcrr p11, 3, r1, r2, c\dr @ fmdrr r1, r2, d\dr
+1: mcrr p11, 3, r0, r1, c\dr @ fmdrr r0, r1, d\dr
mov pc, lr
.org 1b + 8
.endr
diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h
index 117713adea7f..e6c6812a9abd 100644
--- a/arch/blackfin/include/asm/elf.h
+++ b/arch/blackfin/include/asm/elf.h
@@ -119,6 +119,7 @@ do { \
#define ELF_CORE_COPY_REGS(pr_reg, regs) \
memcpy((char *) &pr_reg, (char *)regs, \
sizeof(struct pt_regs));
+#define ELF_CORE_COPY_FPREGS(...) 0 /* Blackfin has no FPU */
/* This yields a mask that user programs can use to figure out what
instruction set this cpu supports. */
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
index 8b18b5359210..620834097632 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
@@ -1738,85 +1738,4 @@
#define nAFEXIT 0x0
#define SECSTAT 0xe0 /* Secure Status */
-/* Bit masks for NFC_CTL */
-
-#define WR_DLY 0xf /* Write Strobe Delay */
-#define RD_DLY 0xf0 /* Read Strobe Delay */
-#define NWIDTH 0x100 /* NAND Data Width */
-#define nNWIDTH 0x0
-#define PG_SIZE 0x200 /* Page Size */
-#define nPG_SIZE 0x0
-
-/* Bit masks for NFC_STAT */
-
-#define NBUSY 0x1 /* Not Busy */
-#define nNBUSY 0x0
-#define WB_FULL 0x2 /* Write Buffer Full */
-#define nWB_FULL 0x0
-#define PG_WR_STAT 0x4 /* Page Write Pending */
-#define nPG_WR_STAT 0x0
-#define PG_RD_STAT 0x8 /* Page Read Pending */
-#define nPG_RD_STAT 0x0
-#define WB_EMPTY 0x10 /* Write Buffer Empty */
-#define nWB_EMPTY 0x0
-
-/* Bit masks for NFC_IRQSTAT */
-
-#define NBUSYIRQ 0x1 /* Not Busy IRQ */
-#define nNBUSYIRQ 0x0
-#define WB_OVF 0x2 /* Write Buffer Overflow */
-#define nWB_OVF 0x0
-#define WB_EDGE 0x4 /* Write Buffer Edge Detect */
-#define nWB_EDGE 0x0
-#define RD_RDY 0x8 /* Read Data Ready */
-#define nRD_RDY 0x0
-#define WR_DONE 0x10 /* Page Write Done */
-#define nWR_DONE 0x0
-
-/* Bit masks for NFC_IRQMASK */
-
-#define MASK_BUSYIRQ 0x1 /* Mask Not Busy IRQ */
-#define nMASK_BUSYIRQ 0x0
-#define MASK_WBOVF 0x2 /* Mask Write Buffer Overflow */
-#define nMASK_WBOVF 0x0
-#define MASK_WBEMPTY 0x4 /* Mask Write Buffer Empty */
-#define nMASK_WBEMPTY 0x0
-#define MASK_RDRDY 0x8 /* Mask Read Data Ready */
-#define nMASK_RDRDY 0x0
-#define MASK_WRDONE 0x10 /* Mask Write Done */
-#define nMASK_WRDONE 0x0
-
-/* Bit masks for NFC_RST */
-
-#define ECC_RST 0x1 /* ECC (and NFC counters) Reset */
-#define nECC_RST 0x0
-
-/* Bit masks for NFC_PGCTL */
-
-#define PG_RD_START 0x1 /* Page Read Start */
-#define nPG_RD_START 0x0
-#define PG_WR_START 0x2 /* Page Write Start */
-#define nPG_WR_START 0x0
-
-/* Bit masks for NFC_ECC0 */
-
-#define ECC0 0x7ff /* Parity Calculation Result0 */
-
-/* Bit masks for NFC_ECC1 */
-
-#define ECC1 0x7ff /* Parity Calculation Result1 */
-
-/* Bit masks for NFC_ECC2 */
-
-#define ECC2 0x7ff /* Parity Calculation Result2 */
-
-/* Bit masks for NFC_ECC3 */
-
-#define ECC3 0x7ff /* Parity Calculation Result3 */
-
-/* Bit masks for NFC_COUNT */
-
-#define ECCCNT 0x3ff /* Transfer Count */
-
-
#endif /* _DEF_BF52X_H */
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
index 0ed06c2366fe..54143441af5e 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
@@ -2044,66 +2044,6 @@
#define RESET_WDOG 0x4000 /* SW Reset Generated By Watchdog Timer */
#define RESET_SOFTWARE 0x8000 /* SW Reset Occurred Since Last Read Of SWRST */
-/* Bit masks for NFC_CTL */
-
-#define WR_DLY 0xf /* Write Strobe Delay */
-#define RD_DLY 0xf0 /* Read Strobe Delay */
-#define NWIDTH 0x100 /* NAND Data Width */
-#define PG_SIZE 0x200 /* Page Size */
-
-/* Bit masks for NFC_STAT */
-
-#define NBUSY 0x1 /* Not Busy */
-#define WB_FULL 0x2 /* Write Buffer Full */
-#define PG_WR_STAT 0x4 /* Page Write Pending */
-#define PG_RD_STAT 0x8 /* Page Read Pending */
-#define WB_EMPTY 0x10 /* Write Buffer Empty */
-
-/* Bit masks for NFC_IRQSTAT */
-
-#define NBUSYIRQ 0x1 /* Not Busy IRQ */
-#define WB_OVF 0x2 /* Write Buffer Overflow */
-#define WB_EDGE 0x4 /* Write Buffer Edge Detect */
-#define RD_RDY 0x8 /* Read Data Ready */
-#define WR_DONE 0x10 /* Page Write Done */
-
-/* Bit masks for NFC_IRQMASK */
-
-#define MASK_BUSYIRQ 0x1 /* Mask Not Busy IRQ */
-#define MASK_WBOVF 0x2 /* Mask Write Buffer Overflow */
-#define MASK_WBEMPTY 0x4 /* Mask Write Buffer Empty */
-#define MASK_RDRDY 0x8 /* Mask Read Data Ready */
-#define MASK_WRDONE 0x10 /* Mask Write Done */
-
-/* Bit masks for NFC_RST */
-
-#define ECC_RST 0x1 /* ECC (and NFC counters) Reset */
-
-/* Bit masks for NFC_PGCTL */
-
-#define PG_RD_START 0x1 /* Page Read Start */
-#define PG_WR_START 0x2 /* Page Write Start */
-
-/* Bit masks for NFC_ECC0 */
-
-#define ECC0 0x7ff /* Parity Calculation Result0 */
-
-/* Bit masks for NFC_ECC1 */
-
-#define ECC1 0x7ff /* Parity Calculation Result1 */
-
-/* Bit masks for NFC_ECC2 */
-
-#define ECC2 0x7ff /* Parity Calculation Result2 */
-
-/* Bit masks for NFC_ECC3 */
-
-#define ECC3 0x7ff /* Parity Calculation Result3 */
-
-/* Bit masks for NFC_COUNT */
-
-#define ECCCNT 0x3ff /* Transfer Count */
-
/* Bit masks for EPPIx_STATUS */
#define CFIFO_ERR 0x1 /* Chroma FIFO Error */
diff --git a/arch/cris/arch-v10/drivers/ds1302.c b/arch/cris/arch-v10/drivers/ds1302.c
index 77630df94343..884275629ef7 100644
--- a/arch/cris/arch-v10/drivers/ds1302.c
+++ b/arch/cris/arch-v10/drivers/ds1302.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
+#include <linux/smp_lock.h>
#include <linux/bcd.h>
#include <linux/capability.h>
@@ -238,9 +239,7 @@ static unsigned char days_in_mo[] =
/* ioctl that supports RTC_RD_TIME and RTC_SET_TIME (read and set time/date). */
-static int
-rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+static int rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
unsigned long flags;
@@ -354,6 +353,17 @@ rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
}
+static long rtc_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ ret = rtc_ioctl(file, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static void
print_rtc_status(void)
{
@@ -375,8 +385,8 @@ print_rtc_status(void)
/* The various file operations we support. */
static const struct file_operations rtc_fops = {
- .owner = THIS_MODULE,
- .ioctl = rtc_ioctl,
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = rtc_unlocked_ioctl,
};
/* Probe for the chip by writing something to its RAM and try reading it back. */
diff --git a/arch/cris/arch-v10/drivers/pcf8563.c b/arch/cris/arch-v10/drivers/pcf8563.c
index 1e90c1a9c849..7dcb1f85f42b 100644
--- a/arch/cris/arch-v10/drivers/pcf8563.c
+++ b/arch/cris/arch-v10/drivers/pcf8563.c
@@ -27,6 +27,7 @@
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/mutex.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -53,7 +54,7 @@ static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
static const unsigned char days_in_month[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+static long pcf8563_unlocked_ioctl(struct file *, unsigned int, unsigned long);
/* Cache VL bit value read at driver init since writing the RTC_SECOND
* register clears the VL status.
@@ -62,7 +63,7 @@ static int voltage_low;
static const struct file_operations pcf8563_fops = {
.owner = THIS_MODULE,
- .ioctl = pcf8563_ioctl,
+ .unlocked_ioctl = pcf8563_unlocked_ioctl,
};
unsigned char
@@ -212,8 +213,7 @@ pcf8563_exit(void)
* ioctl calls for this driver. Why return -ENOTTY upon error? Because
* POSIX says so!
*/
-int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
/* Some sanity checks. */
if (_IOC_TYPE(cmd) != RTC_MAGIC)
@@ -339,6 +339,17 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
+static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ return pcf8563_ioctl(filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static int __init pcf8563_register(void)
{
if (pcf8563_init() < 0) {
diff --git a/arch/cris/arch-v10/kernel/irq.c b/arch/cris/arch-v10/kernel/irq.c
index 1a61efc13982..a0c0df8be9c8 100644
--- a/arch/cris/arch-v10/kernel/irq.c
+++ b/arch/cris/arch-v10/kernel/irq.c
@@ -17,8 +17,8 @@
#include <linux/kernel.h>
#include <linux/init.h>
-#define mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
-#define unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
+#define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
+#define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
* global just so that the kernel gdb can use it.
@@ -116,12 +116,12 @@ static unsigned int startup_crisv10_irq(unsigned int irq)
static void enable_crisv10_irq(unsigned int irq)
{
- unmask_irq(irq);
+ crisv10_unmask_irq(irq);
}
static void disable_crisv10_irq(unsigned int irq)
{
- mask_irq(irq);
+ crisv10_mask_irq(irq);
}
static void ack_crisv10_irq(unsigned int irq)
diff --git a/arch/cris/arch-v10/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c
index e5fb44f505c5..49f5b8ca5b47 100644
--- a/arch/cris/arch-v10/lib/dmacopy.c
+++ b/arch/cris/arch-v10/lib/dmacopy.c
@@ -1,5 +1,4 @@
-/* $Id: dmacopy.c,v 1.1 2001/12/17 13:59:27 bjornw Exp $
- *
+/*
* memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax
*/
@@ -13,11 +12,11 @@ void *dma_memcpy(void *pdst,
unsigned int pn)
{
static etrax_dma_descr indma, outdma;
-
- D(printk("dma_memcpy %d bytes... ", pn));
+
+ D(printk(KERN_DEBUG "dma_memcpy %d bytes... ", pn));
#if 0
- *R_GEN_CONFIG = genconfig_shadow =
+ *R_GEN_CONFIG = genconfig_shadow =
(genconfig_shadow & ~0x3c0000) |
IO_STATE(R_GEN_CONFIG, dma6, intdma7) |
IO_STATE(R_GEN_CONFIG, dma7, intdma6);
@@ -32,11 +31,11 @@ void *dma_memcpy(void *pdst,
*R_DMA_CH7_FIRST = &outdma;
*R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start);
*R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start);
-
- while(*R_DMA_CH7_CMD == 1) /* wait for completion */ ;
- D(printk("done\n"));
+ while (*R_DMA_CH7_CMD == 1)
+ /* wait for completion */;
+ D(printk(KERN_DEBUG "done\n"));
}
diff --git a/arch/cris/arch-v10/lib/hw_settings.S b/arch/cris/arch-v10/lib/hw_settings.S
index 56905aaa7b6e..c09f19f478a5 100644
--- a/arch/cris/arch-v10/lib/hw_settings.S
+++ b/arch/cris/arch-v10/lib/hw_settings.S
@@ -1,13 +1,11 @@
/*
- * $Id: hw_settings.S,v 1.1 2001/12/17 13:59:27 bjornw Exp $
- *
* This table is used by some tools to extract hardware parameters.
* The table should be included in the kernel and the decompressor.
* Don't forget to update the tools if you change this table.
*
* Copyright (C) 2001 Axis Communications AB
*
- * Authors: Mikael Starvik (starvik@axis.com)
+ * Authors: Mikael Starvik (starvik@axis.com)
*/
#define PA_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PA_DIR << 8) | \
@@ -15,13 +13,13 @@
#define PB_SET_VALUE ((CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG << 16) | \
(CONFIG_ETRAX_DEF_R_PORT_PB_DIR << 8) | \
(CONFIG_ETRAX_DEF_R_PORT_PB_DATA))
-
+
.ascii "HW_PARAM_MAGIC" ; Magic number
.dword 0xc0004000 ; Kernel start address
; Debug port
#ifdef CONFIG_ETRAX_DEBUG_PORT0
- .dword 0
+ .dword 0
#elif defined(CONFIG_ETRAX_DEBUG_PORT1)
.dword 1
#elif defined(CONFIG_ETRAX_DEBUG_PORT2)
@@ -30,7 +28,7 @@
.dword 3
#else
.dword 4 ; No debug
-#endif
+#endif
; SDRAM or EDO DRAM?
#ifdef CONFIG_ETRAX_SDRAM
@@ -39,7 +37,7 @@
.dword 0
#endif
- ; Register values
+ ; Register values
.dword R_WAITSTATES
.dword CONFIG_ETRAX_DEF_R_WAITSTATES
.dword R_BUS_CONFIG
@@ -56,7 +54,7 @@
.dword CONFIG_ETRAX_DEF_R_DRAM_TIMING
#endif
.dword R_PORT_PA_SET
- .dword PA_SET_VALUE
+ .dword PA_SET_VALUE
.dword R_PORT_PB_SET
.dword PB_SET_VALUE
.dword 0 ; No more register values
diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig
index b9e328e688be..a2dd740c5907 100644
--- a/arch/cris/arch-v32/drivers/Kconfig
+++ b/arch/cris/arch-v32/drivers/Kconfig
@@ -360,24 +360,10 @@ config ETRAX_SER4_DSR_BIT
string "Ser 4 DSR bit (empty = not used)"
depends on ETRAX_SERIAL_PORT4
-config ETRAX_SER3_CD_BIT
+config ETRAX_SER4_CD_BIT
string "Ser 4 CD bit (empty = not used)"
depends on ETRAX_SERIAL_PORT4
-config ETRAX_RS485
- bool "RS-485 support"
- depends on ETRAXFS_SERIAL
- help
- Enables support for RS-485 serial communication. For a primer on
- RS-485, see <http://www.hw.cz/english/docs/rs485/rs485.html>.
-
-config ETRAX_RS485_DISABLE_RECEIVER
- bool "Disable serial receiver"
- depends on ETRAX_RS485
- help
- It is necessary to disable the serial receiver to avoid serial
- loopback. Not all products are able to do this in software only.
-
config ETRAX_SYNCHRONOUS_SERIAL
bool "Synchronous serial-port support"
depends on ETRAX_ARCH_V32
diff --git a/arch/cris/arch-v32/drivers/i2c.c b/arch/cris/arch-v32/drivers/i2c.c
index 506826399ae7..2fd6a740d895 100644
--- a/arch/cris/arch-v32/drivers/i2c.c
+++ b/arch/cris/arch-v32/drivers/i2c.c
@@ -649,10 +649,10 @@ i2c_release(struct inode *inode, struct file *filp)
/* Main device API. ioctl's to write or read to/from i2c registers.
*/
-static int
-i2c_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long
+i2c_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ int ret;
if(_IOC_TYPE(cmd) != ETRAXI2C_IOCTYPE) {
return -ENOTTY;
}
@@ -665,9 +665,13 @@ i2c_ioctl(struct inode *inode, struct file *file,
I2C_ARGREG(arg),
I2C_ARGVALUE(arg)));
- return i2c_writereg(I2C_ARGSLAVE(arg),
+ lock_kernel();
+ ret = i2c_writereg(I2C_ARGSLAVE(arg),
I2C_ARGREG(arg),
I2C_ARGVALUE(arg));
+ unlock_kernel();
+ return ret;
+
case I2C_READREG:
{
unsigned char val;
@@ -675,7 +679,9 @@ i2c_ioctl(struct inode *inode, struct file *file,
D(printk("i2cr %d %d ",
I2C_ARGSLAVE(arg),
I2C_ARGREG(arg)));
+ lock_kernel();
val = i2c_readreg(I2C_ARGSLAVE(arg), I2C_ARGREG(arg));
+ unlock_kernel();
D(printk("= %d\n", val));
return val;
}
@@ -688,10 +694,10 @@ i2c_ioctl(struct inode *inode, struct file *file,
}
static const struct file_operations i2c_fops = {
- .owner = THIS_MODULE,
- .ioctl = i2c_ioctl,
- .open = i2c_open,
- .release = i2c_release,
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = i2c_ioctl,
+ .open = i2c_open,
+ .release = i2c_release,
};
static int __init i2c_init(void)
diff --git a/arch/cris/arch-v32/drivers/pcf8563.c b/arch/cris/arch-v32/drivers/pcf8563.c
index f4478506e52c..bef6eb53b153 100644
--- a/arch/cris/arch-v32/drivers/pcf8563.c
+++ b/arch/cris/arch-v32/drivers/pcf8563.c
@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
+#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/mutex.h>
@@ -49,7 +50,7 @@ static DEFINE_MUTEX(rtc_lock); /* Protect state etc */
static const unsigned char days_in_month[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
/* Cache VL bit value read at driver init since writing the RTC_SECOND
* register clears the VL status.
@@ -57,8 +58,8 @@ int pcf8563_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
static int voltage_low;
static const struct file_operations pcf8563_fops = {
- .owner = THIS_MODULE,
- .ioctl = pcf8563_ioctl
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = pcf8563_unlocked_ioctl,
};
unsigned char
@@ -208,8 +209,7 @@ pcf8563_exit(void)
* ioctl calls for this driver. Why return -ENOTTY upon error? Because
* POSIX says so!
*/
-int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
- unsigned long arg)
+static int pcf8563_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
/* Some sanity checks. */
if (_IOC_TYPE(cmd) != RTC_MAGIC)
@@ -335,6 +335,17 @@ int pcf8563_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
return 0;
}
+static long pcf8563_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int ret;
+
+ lock_kernel();
+ return pcf8563_ioctl(filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+
static int __init pcf8563_register(void)
{
if (pcf8563_init() < 0) {
diff --git a/arch/cris/arch-v32/kernel/crisksyms.c b/arch/cris/arch-v32/kernel/crisksyms.c
index 64933e2c0f5b..bde8d1a10cad 100644
--- a/arch/cris/arch-v32/kernel/crisksyms.c
+++ b/arch/cris/arch-v32/kernel/crisksyms.c
@@ -24,5 +24,5 @@ EXPORT_SYMBOL(crisv32_io_get_name);
EXPORT_SYMBOL(crisv32_io_get);
/* Functions masking/unmasking interrupts */
-EXPORT_SYMBOL(mask_irq);
-EXPORT_SYMBOL(unmask_irq);
+EXPORT_SYMBOL(crisv32_mask_irq);
+EXPORT_SYMBOL(crisv32_unmask_irq);
diff --git a/arch/cris/arch-v32/kernel/irq.c b/arch/cris/arch-v32/kernel/irq.c
index b6241198fb98..0b1febe44aa3 100644
--- a/arch/cris/arch-v32/kernel/irq.c
+++ b/arch/cris/arch-v32/kernel/irq.c
@@ -280,8 +280,7 @@ out:
return cpu;
}
-void
-mask_irq(int irq)
+void crisv32_mask_irq(int irq)
{
int cpu;
@@ -289,8 +288,7 @@ mask_irq(int irq)
block_irq(irq, cpu);
}
-void
-unmask_irq(int irq)
+void crisv32_unmask_irq(int irq)
{
unblock_irq(irq, irq_cpu(irq));
}
@@ -298,23 +296,23 @@ unmask_irq(int irq)
static unsigned int startup_crisv32_irq(unsigned int irq)
{
- unmask_irq(irq);
+ crisv32_unmask_irq(irq);
return 0;
}
static void shutdown_crisv32_irq(unsigned int irq)
{
- mask_irq(irq);
+ crisv32_mask_irq(irq);
}
static void enable_crisv32_irq(unsigned int irq)
{
- unmask_irq(irq);
+ crisv32_unmask_irq(irq);
}
static void disable_crisv32_irq(unsigned int irq)
{
- mask_irq(irq);
+ crisv32_mask_irq(irq);
}
static void ack_crisv32_irq(unsigned int irq)
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 058adddf4e4b..84fed3b4b079 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -168,8 +168,8 @@ void __init smp_callin(void)
/* Enable IRQ and idle */
REG_WR(intr_vect, irq_regs[cpu], rw_mask, vect_mask);
- unmask_irq(IPI_INTR_VECT);
- unmask_irq(TIMER0_INTR_VECT);
+ crisv32_unmask_irq(IPI_INTR_VECT);
+ crisv32_unmask_irq(TIMER0_INTR_VECT);
preempt_disable();
notify_cpu_starting(cpu);
local_irq_enable();
diff --git a/arch/cris/include/arch-v10/arch/irq.h b/arch/cris/include/arch-v10/arch/irq.h
index 6248004eca1c..7d345947b3ee 100644
--- a/arch/cris/include/arch-v10/arch/irq.h
+++ b/arch/cris/include/arch-v10/arch/irq.h
@@ -93,15 +93,16 @@ void set_break_vector(int n, irqvectptr addr);
"push $r10\n\t" /* push orig_r10 */ \
"clear.d [$sp=$sp-4]\n\t" /* frametype - this is a normal stackframe */
- /* BLOCK_IRQ and UNBLOCK_IRQ do the same as mask_irq and unmask_irq */
+/* BLOCK_IRQ and UNBLOCK_IRQ do the same as
+ * crisv10_mask_irq and crisv10_unmask_irq */
#define BLOCK_IRQ(mask,nr) \
"move.d " #mask ",$r0\n\t" \
- "move.d $r0,[0xb00000d8]\n\t"
-
+ "move.d $r0,[0xb00000d8]\n\t"
+
#define UNBLOCK_IRQ(mask) \
"move.d " #mask ",$r0\n\t" \
- "move.d $r0,[0xb00000dc]\n\t"
+ "move.d $r0,[0xb00000dc]\n\t"
#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)
diff --git a/arch/cris/include/arch-v32/arch/irq.h b/arch/cris/include/arch-v32/arch/irq.h
index 9e4c9fbdfddf..b31e9984f849 100644
--- a/arch/cris/include/arch-v32/arch/irq.h
+++ b/arch/cris/include/arch-v32/arch/irq.h
@@ -23,8 +23,8 @@ struct etrax_interrupt_vector {
extern struct etrax_interrupt_vector *etrax_irv; /* head.S */
-void mask_irq(int irq);
-void unmask_irq(int irq);
+void crisv32_mask_irq(int irq);
+void crisv32_unmask_irq(int irq);
void set_exception_vector(int n, irqvectptr addr);
diff --git a/arch/cris/include/asm/param.h b/arch/cris/include/asm/param.h
index 0e47994e40be..484fcf8667c0 100644
--- a/arch/cris/include/asm/param.h
+++ b/arch/cris/include/asm/param.h
@@ -2,22 +2,9 @@
#define _ASMCRIS_PARAM_H
/* Currently we assume that HZ=100 is good for CRIS. */
-#ifdef __KERNEL__
-# define HZ CONFIG_HZ /* Internal kernel timer frequency */
-# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
-# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
-#endif
-
-#ifndef HZ
-#define HZ 100
-#endif
#define EXEC_PAGESIZE 8192
-#ifndef NOGROUP
-#define NOGROUP (-1)
-#endif
-
-#define MAXHOSTNAMELEN 64 /* max length of hostname */
+#include <asm-generic/param.h>
-#endif
+#endif /* _ASMCRIS_PARAM_H */
diff --git a/arch/frv/kernel/break.S b/arch/frv/kernel/break.S
index bd0bdf908d93..cbb6958a3147 100644
--- a/arch/frv/kernel/break.S
+++ b/arch/frv/kernel/break.S
@@ -21,7 +21,7 @@
#
# the break handler has its own stack
#
- .section .bss.stack
+ .section .bss..stack
.globl __break_user_context
.balign THREAD_SIZE
__break_stack:
@@ -63,7 +63,7 @@ __break_trace_through_exceptions:
# entry point for Break Exceptions/Interrupts
#
###############################################################################
- .section .text.break
+ .section .text..break
.balign 4
.globl __entry_break
__entry_break:
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 189397ec012a..63d579bf1c29 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -38,7 +38,7 @@
#define nr_syscalls ((syscall_table_size)/4)
- .section .text.entry
+ .section .text..entry
.balign 4
.macro LEDS val
diff --git a/arch/frv/kernel/head.S b/arch/frv/kernel/head.S
index b825ef3f2d54..e9a8cc63ac94 100644
--- a/arch/frv/kernel/head.S
+++ b/arch/frv/kernel/head.S
@@ -542,7 +542,7 @@ __head_end:
.size _boot, .-_boot
# provide a point for GDB to place a break
- .section .text.start,"ax"
+ .section .text..start,"ax"
.globl _start
.balign 4
_start:
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index cbe811fccfcc..8b973f3cc90e 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -57,10 +57,10 @@ SECTIONS
_text = .;
_stext = .;
.text : {
- *(.text.start)
- *(.text.entry)
- *(.text.break)
- *(.text.tlbmiss)
+ *(.text..start)
+ *(.text..entry)
+ *(.text..break)
+ *(.text..tlbmiss)
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
@@ -114,7 +114,7 @@ SECTIONS
.sbss : { *(.sbss .sbss.*) }
.bss : { *(.bss .bss.*) }
- .bss.stack : { *(.bss) }
+ .bss..stack : { *(.bss) }
__bss_stop = .;
_end = . ;
diff --git a/arch/frv/mm/fault.c b/arch/frv/mm/fault.c
index 30f5d100a81c..a325d57a83d5 100644
--- a/arch/frv/mm/fault.c
+++ b/arch/frv/mm/fault.c
@@ -257,10 +257,10 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
*/
out_of_memory:
up_read(&mm->mmap_sem);
- printk("VM: killing process %s\n", current->comm);
- if (user_mode(__frame))
- do_group_exit(SIGKILL);
- goto no_context;
+ if (!user_mode(__frame))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/frv/mm/tlb-miss.S b/arch/frv/mm/tlb-miss.S
index 7f392bc651a3..f3ac019bb18b 100644
--- a/arch/frv/mm/tlb-miss.S
+++ b/arch/frv/mm/tlb-miss.S
@@ -15,7 +15,7 @@
#include <asm/pgtable.h>
#include <asm/spr-regs.h>
- .section .text.tlbmiss
+ .section .text..tlbmiss
.balign 4
.globl __entry_insn_mmu_miss
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
index 985a81a2435a..10e9a2d1cc6c 100644
--- a/arch/h8300/boot/compressed/head.S
+++ b/arch/h8300/boot/compressed/head.S
@@ -9,7 +9,7 @@
#define SRAM_START 0xff4000
- .section .text.startup
+ .section .text..startup
.global startup
startup:
mov.l #SRAM_START+0x8000, sp
diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds
index 65e2a0d1ae39..a0a3a0ed54ef 100644
--- a/arch/h8300/boot/compressed/vmlinux.lds
+++ b/arch/h8300/boot/compressed/vmlinux.lds
@@ -4,7 +4,7 @@ SECTIONS
{
__stext = . ;
__text = .;
- *(.text.startup)
+ *(.text..startup)
*(.text)
__etext = . ;
}
diff --git a/arch/ia64/include/asm/asmmacro.h b/arch/ia64/include/asm/asmmacro.h
index c1642fd64029..3ab6d75aa3db 100644
--- a/arch/ia64/include/asm/asmmacro.h
+++ b/arch/ia64/include/asm/asmmacro.h
@@ -70,12 +70,12 @@ name:
* path (ivt.S - TLB miss processing) or in places where it might not be
* safe to use a "tpa" instruction (mca_asm.S - error recovery).
*/
- .section ".data.patch.vtop", "a" // declare section & section attributes
+ .section ".data..patch.vtop", "a" // declare section & section attributes
.previous
#define LOAD_PHYSICAL(pr, reg, obj) \
[1:](pr)movl reg = obj; \
- .xdata4 ".data.patch.vtop", 1b-.
+ .xdata4 ".data..patch.vtop", 1b-.
/*
* For now, we always put in the McKinley E9 workaround. On CPUs that don't need it,
@@ -84,11 +84,11 @@ name:
#define DO_MCKINLEY_E9_WORKAROUND
#ifdef DO_MCKINLEY_E9_WORKAROUND
- .section ".data.patch.mckinley_e9", "a"
+ .section ".data..patch.mckinley_e9", "a"
.previous
/* workaround for Itanium 2 Errata 9: */
# define FSYS_RETURN \
- .xdata4 ".data.patch.mckinley_e9", 1f-.; \
+ .xdata4 ".data..patch.mckinley_e9", 1f-.; \
1:{ .mib; \
nop.m 0; \
mov r16=ar.pfs; \
@@ -107,11 +107,11 @@ name:
* If physical stack register size is different from DEF_NUM_STACK_REG,
* dynamically patch the kernel for correct size.
*/
- .section ".data.patch.phys_stack_reg", "a"
+ .section ".data..patch.phys_stack_reg", "a"
.previous
#define LOAD_PHYS_STACK_REG_SIZE(reg) \
[1:] adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0; \
- .xdata4 ".data.patch.phys_stack_reg", 1b-.
+ .xdata4 ".data..patch.phys_stack_reg", 1b-.
/*
* Up until early 2004, use of .align within a function caused bad unwind info.
diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h
index e7482bd628ff..988254a7d349 100644
--- a/arch/ia64/include/asm/cache.h
+++ b/arch/ia64/include/asm/cache.h
@@ -24,6 +24,6 @@
# define SMP_CACHE_BYTES (1 << 3)
#endif
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#endif /* _ASM_IA64_CACHE_H */
diff --git a/arch/ia64/include/asm/percpu.h b/arch/ia64/include/asm/percpu.h
index 1bd408265694..14aa1c58912b 100644
--- a/arch/ia64/include/asm/percpu.h
+++ b/arch/ia64/include/asm/percpu.h
@@ -31,7 +31,7 @@ extern void *per_cpu_init(void);
#endif /* SMP */
-#define PER_CPU_BASE_SECTION ".data.percpu"
+#define PER_CPU_BASE_SECTION ".data..percpu"
/*
* Be extremely careful when taking the address of this variable! Due to virtual
diff --git a/arch/ia64/kernel/Makefile.gate b/arch/ia64/kernel/Makefile.gate
index ab9b03a9adcc..ceeffc509764 100644
--- a/arch/ia64/kernel/Makefile.gate
+++ b/arch/ia64/kernel/Makefile.gate
@@ -21,7 +21,7 @@ GATECFLAGS_gate-syms.o = -r
$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
$(call if_changed,gate)
-# gate-data.o contains the gate DSO image as data in section .data.gate.
+# gate-data.o contains the gate DSO image as data in section .data..gate.
# We must build gate.so before we can assemble it.
# Note: kbuild does not track this dependency due to usage of .incbin
$(obj)/gate-data.o: $(obj)/gate.so
diff --git a/arch/ia64/kernel/gate-data.S b/arch/ia64/kernel/gate-data.S
index 258c0a3238fb..b3ef1c72e132 100644
--- a/arch/ia64/kernel/gate-data.S
+++ b/arch/ia64/kernel/gate-data.S
@@ -1,3 +1,3 @@
- .section .data.gate, "aw"
+ .section .data..gate, "aw"
.incbin "arch/ia64/kernel/gate.so"
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index cf5e0a105e16..245d3e1ec7e1 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -21,18 +21,18 @@
* to targets outside the shared object) and to avoid multi-phase kernel builds, we
* simply create minimalistic "patch lists" in special ELF sections.
*/
- .section ".data.patch.fsyscall_table", "a"
+ .section ".data..patch.fsyscall_table", "a"
.previous
#define LOAD_FSYSCALL_TABLE(reg) \
[1:] movl reg=0; \
- .xdata4 ".data.patch.fsyscall_table", 1b-.
+ .xdata4 ".data..patch.fsyscall_table", 1b-.
- .section ".data.patch.brl_fsys_bubble_down", "a"
+ .section ".data..patch.brl_fsys_bubble_down", "a"
.previous
#define BRL_COND_FSYS_BUBBLE_DOWN(pr) \
[1:](pr)brl.cond.sptk 0; \
;; \
- .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-.
+ .xdata4 ".data..patch.brl_fsys_bubble_down", 1b-.
GLOBAL_ENTRY(__kernel_syscall_via_break)
.prologue
diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S
index 88c64ed47c36..d32b0855110a 100644
--- a/arch/ia64/kernel/gate.lds.S
+++ b/arch/ia64/kernel/gate.lds.S
@@ -33,21 +33,21 @@ SECTIONS
*/
. = GATE_ADDR + 0x600;
- .data.patch : {
+ .data..patch : {
__paravirt_start_gate_mckinley_e9_patchlist = .;
- *(.data.patch.mckinley_e9)
+ *(.data..patch.mckinley_e9)
__paravirt_end_gate_mckinley_e9_patchlist = .;
__paravirt_start_gate_vtop_patchlist = .;
- *(.data.patch.vtop)
+ *(.data..patch.vtop)
__paravirt_end_gate_vtop_patchlist = .;
__paravirt_start_gate_fsyscall_patchlist = .;
- *(.data.patch.fsyscall_table)
+ *(.data..patch.fsyscall_table)
__paravirt_end_gate_fsyscall_patchlist = .;
__paravirt_start_gate_brl_fsys_bubble_down_patchlist = .;
- *(.data.patch.brl_fsys_bubble_down)
+ *(.data..patch.brl_fsys_bubble_down)
__paravirt_end_gate_brl_fsys_bubble_down_patchlist = .;
} :readable
diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c
index e253ab8fcbc8..f9efe9739d3f 100644
--- a/arch/ia64/kernel/init_task.c
+++ b/arch/ia64/kernel/init_task.c
@@ -23,7 +23,7 @@ static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
* Initial task structure.
*
* We need to make sure that this is properly aligned due to the way process stacks are
- * handled. This is done by having a special ".data.init_task" section...
+ * handled. This is done by having a special ".data..init_task" section...
*/
#define init_thread_info init_task_mem.s.thread_info
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 179fd122e837..d93e396bf599 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -82,7 +82,7 @@
mov r19=n;; /* prepare to save predicates */ \
br.sptk.many dispatch_to_fault_handler
- .section .text.ivt,"ax"
+ .section .text..ivt,"ax"
.align 32768 // align on 32KB boundary
.global ia64_ivt
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index 292e214a3b84..d56753a11636 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -16,7 +16,7 @@
#define ACCOUNT_SYS_ENTER
#endif
-.section ".data.patch.rse", "a"
+.section ".data..patch.rse", "a"
.previous
/*
@@ -215,7 +215,7 @@
(pUStk) extr.u r17=r18,3,6; \
(pUStk) sub r16=r18,r22; \
[1:](pKStk) br.cond.sptk.many 1f; \
- .xdata4 ".data.patch.rse",1b-. \
+ .xdata4 ".data..patch.rse",1b-. \
;; \
cmp.ge p6,p7 = 33,r17; \
;; \
diff --git a/arch/ia64/kernel/paravirtentry.S b/arch/ia64/kernel/paravirtentry.S
index 6158560d7f17..92d880c4d3d1 100644
--- a/arch/ia64/kernel/paravirtentry.S
+++ b/arch/ia64/kernel/paravirtentry.S
@@ -28,7 +28,7 @@
#include "entry.h"
#define DATA8(sym, init_value) \
- .pushsection .data.read_mostly ; \
+ .pushsection .data..read_mostly ; \
.align 8 ; \
.global sym ; \
sym: ; \
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 1295ba327f6f..e07218a2577f 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -8,7 +8,7 @@
#define IVT_TEXT \
VMLINUX_SYMBOL(__start_ivt_text) = .; \
- *(.text.ivt) \
+ *(.text..ivt) \
VMLINUX_SYMBOL(__end_ivt_text) = .;
OUTPUT_FORMAT("elf64-ia64-little")
@@ -54,8 +54,8 @@ SECTIONS
.text2 : AT(ADDR(.text2) - LOAD_OFFSET)
{ *(.text2) }
#ifdef CONFIG_SMP
- .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET)
- { *(.text.lock) }
+ .text..lock : AT(ADDR(.text..lock) - LOAD_OFFSET)
+ { *(.text..lock) }
#endif
_etext = .;
@@ -75,10 +75,10 @@ SECTIONS
__stop___mca_table = .;
}
- .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET)
+ .data..patch.phys_stack_reg : AT(ADDR(.data..patch.phys_stack_reg) - LOAD_OFFSET)
{
__start___phys_stack_reg_patchlist = .;
- *(.data.patch.phys_stack_reg)
+ *(.data..patch.phys_stack_reg)
__end___phys_stack_reg_patchlist = .;
}
@@ -110,24 +110,24 @@ SECTIONS
INIT_TEXT_SECTION(PAGE_SIZE)
INIT_DATA_SECTION(16)
- .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
+ .data..patch.vtop : AT(ADDR(.data..patch.vtop) - LOAD_OFFSET)
{
__start___vtop_patchlist = .;
- *(.data.patch.vtop)
+ *(.data..patch.vtop)
__end___vtop_patchlist = .;
}
- .data.patch.rse : AT(ADDR(.data.patch.rse) - LOAD_OFFSET)
+ .data..patch.rse : AT(ADDR(.data..patch.rse) - LOAD_OFFSET)
{
__start___rse_patchlist = .;
- *(.data.patch.rse)
+ *(.data..patch.rse)
__end___rse_patchlist = .;
}
- .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET)
+ .data..patch.mckinley_e9 : AT(ADDR(.data..patch.mckinley_e9) - LOAD_OFFSET)
{
__start___mckinley_e9_bundles = .;
- *(.data.patch.mckinley_e9)
+ *(.data..patch.mckinley_e9)
__end___mckinley_e9_bundles = .;
}
@@ -175,17 +175,17 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__init_end = .;
- .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET)
+ .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET)
{
PAGE_ALIGNED_DATA(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
__start_gate_section = .;
- *(.data.gate)
+ *(.data..gate)
__stop_gate_section = .;
#ifdef CONFIG_XEN
. = ALIGN(PAGE_SIZE);
__xen_start_gate_section = .;
- *(.data.gate.xen)
+ *(.data..gate.xen)
__xen_stop_gate_section = .;
#endif
}
diff --git a/arch/ia64/kvm/vmm_ivt.S b/arch/ia64/kvm/vmm_ivt.S
index 40920c630649..24018484c6e9 100644
--- a/arch/ia64/kvm/vmm_ivt.S
+++ b/arch/ia64/kvm/vmm_ivt.S
@@ -104,7 +104,7 @@ GLOBAL_ENTRY(kvm_vmm_panic)
br.call.sptk.many b6=vmm_panic_handler;
END(kvm_vmm_panic)
- .section .text.ivt,"ax"
+ .section .text..ivt,"ax"
.align 32768 // align on 32KB boundary
.global kvm_ia64_ivt
diff --git a/arch/ia64/scripts/unwcheck.py b/arch/ia64/scripts/unwcheck.py
index c27849889e19..2bfd941ff7c7 100644
--- a/arch/ia64/scripts/unwcheck.py
+++ b/arch/ia64/scripts/unwcheck.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
#
# Usage: unwcheck.py FILE
#
diff --git a/arch/ia64/xen/gate-data.S b/arch/ia64/xen/gate-data.S
index 7d4830afc91d..6f95b6b32a4e 100644
--- a/arch/ia64/xen/gate-data.S
+++ b/arch/ia64/xen/gate-data.S
@@ -1,3 +1,3 @@
- .section .data.gate.xen, "aw"
+ .section .data..gate.xen, "aw"
.incbin "arch/ia64/xen/gate.so"
diff --git a/arch/ia64/xen/xensetup.S b/arch/ia64/xen/xensetup.S
index aff8346ea193..b820ed02ab9f 100644
--- a/arch/ia64/xen/xensetup.S
+++ b/arch/ia64/xen/xensetup.S
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <xen/interface/elfnote.h>
- .section .data.read_mostly
+ .section .data..read_mostly
.align 8
.global xen_domain_type
xen_domain_type:
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index 28ee389e5f5a..b8ec002aef8e 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -188,7 +188,6 @@ good_area:
if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC))
goto bad_area;
-survive:
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
@@ -271,15 +270,10 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (is_global_init(tsk)) {
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- printk("VM: killing process %s\n", tsk->comm);
- if (error_code & ACE_USERMODE)
- do_group_exit(SIGKILL);
- goto no_context;
+ if (!(error_code & ACE_USERMODE))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 1c16b1baf8db..c247de02bc7e 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -332,6 +332,15 @@ static struct mac_model mac_data_table[] = {
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
+ }, {
+ .ident = MAC_MODEL_CCLII,
+ .name = "Color Classic II",
+ .adb_type = MAC_ADB_CUDA,
+ .via_type = MAC_VIA_IIci,
+ .scsi_type = MAC_SCSI_OLD,
+ .scc_type = MAC_SCC_II,
+ .nubus_type = MAC_NUBUS,
+ .floppy_type = MAC_FLOPPY_SWIM_ADDR2,
},
/*
diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c
index 0f118ca156d9..e023fc6b37e5 100644
--- a/arch/m68k/mac/misc.c
+++ b/arch/m68k/mac/misc.c
@@ -91,7 +91,7 @@ static void cuda_write_pram(int offset, __u8 data)
#define cuda_write_pram NULL
#endif
-#if 0 /* def CONFIG_ADB_PMU68K */
+#ifdef CONFIG_ADB_PMU68K
static long pmu_read_time(void)
{
struct adb_request req;
@@ -102,8 +102,8 @@ static long pmu_read_time(void)
while (!req.complete)
pmu_poll();
- time = (req.reply[0] << 24) | (req.reply[1] << 16)
- | (req.reply[2] << 8) | req.reply[3];
+ time = (req.reply[1] << 24) | (req.reply[2] << 16)
+ | (req.reply[3] << 8) | req.reply[4];
return time - RTC_OFFSET;
}
diff --git a/arch/m68k/sun3/leds.c b/arch/m68k/sun3/leds.c
index a3e948463982..aad2e0a0682e 100644
--- a/arch/m68k/sun3/leds.c
+++ b/arch/m68k/sun3/leds.c
@@ -7,7 +7,7 @@ void sun3_leds(unsigned char byte)
unsigned char dfc;
GET_DFC(dfc);
- SET_DFC(FC_CONTROL);
- SET_CONTROL_BYTE(AC_LEDS,byte);
+ SET_DFC(FC_CONTROL);
+ SET_CONTROL_BYTE(AC_LEDS, byte);
SET_DFC(dfc);
}
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 9f1784f586b9..a91b2713451d 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -57,7 +57,7 @@ SECTIONS {
.romvec : {
__rom_start = . ;
_romvec = .;
- *(.data.initvect)
+ *(.data..initvect)
} > romvec
#endif
@@ -68,7 +68,7 @@ SECTIONS {
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
- *(.text.lock)
+ *(.text..lock)
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S
index 2ef06242398b..8eb94fb6b971 100644
--- a/arch/m68knommu/platform/68360/head-ram.S
+++ b/arch/m68knommu/platform/68360/head-ram.S
@@ -280,7 +280,7 @@ _dprbase:
* and then overwritten as needed.
*/
-.section ".data.initvect","awx"
+.section ".data..initvect","awx"
.long RAMEND /* Reset: Initial Stack Pointer - 0. */
.long _start /* Reset: Initial Program Counter - 1. */
.long buserr /* Bus Error - 2. */
diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S
index 62ecf4144b3b..97510e55b802 100644
--- a/arch/m68knommu/platform/68360/head-rom.S
+++ b/arch/m68knommu/platform/68360/head-rom.S
@@ -291,7 +291,7 @@ _dprbase:
* and then overwritten as needed.
*/
-.section ".data.initvect","awx"
+.section ".data..initvect","awx"
.long RAMEND /* Reset: Initial Stack Pointer - 0. */
.long _start /* Reset: Initial Program Counter - 1. */
.long buserr /* Bus Error - 2. */
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index 76818f926539..a8967ba103c0 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -75,6 +75,9 @@ config LOCKDEP_SUPPORT
config HAVE_LATENCYTOP_SUPPORT
def_bool y
+config NEED_SG_DMA_LENGTH
+ def_bool y
+
config DTC
def_bool y
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index a6edd356cd08..6764bef29a2f 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -60,7 +60,6 @@ void microblaze_cache_init(void);
#define invalidate_icache() mbc->iin();
#define invalidate_icache_range(start, end) mbc->iinr(start, end);
-
#define flush_icache_user_range(vma, pg, adr, len) flush_icache();
#define flush_icache_page(vma, pg) do { } while (0)
@@ -72,9 +71,15 @@ void microblaze_cache_init(void);
#define flush_dcache() mbc->dfl();
#define flush_dcache_range(start, end) mbc->dflr(start, end);
-#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
-/* D-cache aliasing problem can't happen - cache is between MMU and ram */
-#define flush_dcache_page(page) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+/* MS: We have to implement it because of rootfs-jffs2 issue on WB */
+#define flush_dcache_page(page) \
+do { \
+ unsigned long addr = (unsigned long) page_address(page); /* virtual */ \
+ addr = (u32)virt_to_phys((void *)addr); \
+ flush_dcache_range((unsigned) (addr), (unsigned) (addr) + PAGE_SIZE); \
+} while(0);
+
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index de493f86d28f..464ff32bee3d 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -34,6 +34,8 @@
/* MS be sure that SLAB allocates aligned objects */
#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
+#define ARCH_SLAB_MINALIGN L1_CACHE_BYTES
+
#define PAGE_UP(addr) (((addr)+((PAGE_SIZE)-1))&(~((PAGE_SIZE)-1)))
#define PAGE_DOWN(addr) ((addr)&(~((PAGE_SIZE)-1)))
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 26460d15b338..d840f4a2d3c9 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -359,7 +359,7 @@ extern long __user_bad(void);
__copy_tofrom_user((__force void __user *)(to), \
(void __user *)(from), (n))
#define __copy_from_user_inatomic(to, from, n) \
- copy_from_user((to), (from), (n))
+ __copy_from_user((to), (from), (n))
static inline long copy_from_user(void *to,
const void __user *from, unsigned long n)
@@ -373,7 +373,7 @@ static inline long copy_from_user(void *to,
#define __copy_to_user(to, from, n) \
__copy_tofrom_user((void __user *)(to), \
(__force const void __user *)(from), (n))
-#define __copy_to_user_inatomic(to, from, n) copy_to_user((to), (from), (n))
+#define __copy_to_user_inatomic(to, from, n) __copy_to_user((to), (from), (n))
static inline long copy_to_user(void __user *to,
const void *from, unsigned long n)
diff --git a/arch/microblaze/kernel/misc.S b/arch/microblaze/kernel/misc.S
index 0fb5fc6c1fc2..206da3da361f 100644
--- a/arch/microblaze/kernel/misc.S
+++ b/arch/microblaze/kernel/misc.S
@@ -76,7 +76,7 @@ early_console_reg_tlb_alloc:
* the UARTs nice and early. We use a 4k real==virtual mapping.
*/
ori r4, r0, MICROBLAZE_TLB_SIZE - 1
- mts rtlbx, r4 /* TLB slot 2 */
+ mts rtlbx, r4 /* TLB slot 63 */
or r4,r5,r0
andi r4,r4,0xfffff000
diff --git a/arch/microblaze/mm/fault.c b/arch/microblaze/mm/fault.c
index bab922993185..b224c650a18d 100644
--- a/arch/microblaze/mm/fault.c
+++ b/arch/microblaze/mm/fault.c
@@ -226,7 +226,6 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
-survive:
fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index cca3579d4268..573b97e7c14b 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -134,13 +134,8 @@ void __init setup_memory(void)
* for 4GB of memory, using 4kB pages), plus 1 page
* (in case the address isn't page-aligned).
*/
-#ifndef CONFIG_MMU
- map_size = init_bootmem_node(NODE_DATA(0), PFN_UP(TOPHYS((u32)klimit)),
- min_low_pfn, max_low_pfn);
-#else
- map_size = init_bootmem_node(&contig_page_data,
+ map_size = init_bootmem_node(NODE_DATA(0),
PFN_UP(TOPHYS((u32)klimit)), min_low_pfn, max_low_pfn);
-#endif
lmb_reserve(PFN_UP(TOPHYS((u32)klimit)) << PAGE_SHIFT, map_size);
/* free bootmem is whole main memory */
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild
new file mode 100644
index 000000000000..e322d65f33a4
--- /dev/null
+++ b/arch/mips/Kbuild
@@ -0,0 +1,15 @@
+# Fail on warnings - also for files referenced in subdirs
+# -Werror can be disabled for specific files using:
+# CFLAGS_<file.o> := -Wno-error
+subdir-ccflags-y := -Werror
+
+# platform specific definitions
+include arch/mips/Kbuild.platforms
+obj-y := $(platform-y)
+
+# mips object files
+# The object files are linked as core-y files would be linked
+
+obj-y += kernel/
+obj-y += mm/
+obj-y += math-emu/
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
new file mode 100644
index 000000000000..ea3b96cf2673
--- /dev/null
+++ b/arch/mips/Kbuild.platforms
@@ -0,0 +1,31 @@
+# All platforms listed in alphabetic order
+
+platforms += alchemy
+platforms += ar7
+platforms += bcm47xx
+platforms += bcm63xx
+platforms += cavium-octeon
+platforms += cobalt
+platforms += dec
+platforms += emma
+platforms += jazz
+platforms += lasat
+platforms += loongson
+platforms += mipssim
+platforms += mti-malta
+platforms += pmc-sierra
+platforms += pnx833x
+platforms += pnx8550
+platforms += powertv
+platforms += rb532
+platforms += sgi-ip22
+platforms += sgi-ip27
+platforms += sgi-ip32
+platforms += sibyte
+platforms += sni
+platforms += txx9
+platforms += vr41xx
+platforms += wrppmc
+
+# include the platform specific files
+include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms))
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 0b9c01add0a0..9296cbf3f1f5 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -130,26 +130,6 @@ cflags-$(CONFIG_CPU_R4300) += -march=r4300 -Wa,--trap
cflags-$(CONFIG_CPU_VR41XX) += -march=r4100 -Wa,--trap
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
-# only gcc >= 4.4 have the loongson-specific support
-cflags-$(CONFIG_CPU_LOONGSON2) += -Wa,--trap
-cflags-$(CONFIG_CPU_LOONGSON2E) += \
- $(call cc-option,-march=loongson2e,-march=r4600)
-cflags-$(CONFIG_CPU_LOONGSON2F) += \
- $(call cc-option,-march=loongson2f,-march=r4600)
-# enable the workarounds for loongson2f
-ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
- ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-nop,),)
- $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-nop)
- else
- cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-nop
- endif
- ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-jump,),)
- $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-jump)
- else
- cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-jump
- endif
-endif
-
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
-Wa,-mips32 -Wa,--trap
cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
@@ -209,455 +189,7 @@ endif
#
# Board-dependent options and extra files
#
-
-#
-# Texas Instruments AR7
-#
-core-$(CONFIG_AR7) += arch/mips/ar7/
-cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7
-load-$(CONFIG_AR7) += 0xffffffff94100000
-
-#
-# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
-#
-core-$(CONFIG_MACH_JAZZ) += arch/mips/jazz/
-cflags-$(CONFIG_MACH_JAZZ) += -I$(srctree)/arch/mips/include/asm/mach-jazz
-load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000
-
-#
-# Common Alchemy Au1x00 stuff
-#
-core-$(CONFIG_SOC_AU1X00) += arch/mips/alchemy/common/
-
-#
-# AMD Alchemy Pb1000 eval board
-#
-core-$(CONFIG_MIPS_PB1000) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1000) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1100 eval board
-#
-core-$(CONFIG_MIPS_PB1100) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1100) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1500 eval board
-#
-core-$(CONFIG_MIPS_PB1500) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1500) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1550 eval board
-#
-core-$(CONFIG_MIPS_PB1550) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1550) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000
-
-#
-# AMD Alchemy Pb1200 eval board
-#
-core-$(CONFIG_MIPS_PB1200) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_PB1200) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
-load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1000 eval board
-#
-core-$(CONFIG_MIPS_DB1000) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1100 eval board
-#
-core-$(CONFIG_MIPS_DB1100) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1100) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1500 eval board
-#
-core-$(CONFIG_MIPS_DB1500) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1500) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1550 eval board
-#
-core-$(CONFIG_MIPS_DB1550) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1550) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000
-
-#
-# AMD Alchemy Db1200 eval board
-#
-core-$(CONFIG_MIPS_DB1200) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
-
-#
-# AMD Alchemy Bosporus eval board
-#
-core-$(CONFIG_MIPS_BOSPORUS) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_BOSPORUS) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000
-
-#
-# AMD Alchemy Mirage eval board
-#
-core-$(CONFIG_MIPS_MIRAGE) += arch/mips/alchemy/devboards/
-cflags-$(CONFIG_MIPS_MIRAGE) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
-load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000
-
-#
-# 4G-Systems eval board
-#
-libs-$(CONFIG_MIPS_MTX1) += arch/mips/alchemy/mtx-1/
-load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000
-
-#
-# MyCable eval board
-#
-libs-$(CONFIG_MIPS_XXS1500) += arch/mips/alchemy/xxs1500/
-load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000
-
-# must be last for Alchemy systems for GPIO to work properly
-cflags-$(CONFIG_SOC_AU1X00) += -I$(srctree)/arch/mips/include/asm/mach-au1x00
-
-
-#
-# Cobalt Server
-#
-core-$(CONFIG_MIPS_COBALT) += arch/mips/cobalt/
-cflags-$(CONFIG_MIPS_COBALT) += -I$(srctree)/arch/mips/include/asm/mach-cobalt
-load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
-
-#
-# DECstation family
-#
-core-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/
-cflags-$(CONFIG_MACH_DECSTATION)+= -I$(srctree)/arch/mips/include/asm/mach-dec
-libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
-load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
-
-#
-# Wind River PPMC Board (4KC + GT64120)
-#
-core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/
-cflags-$(CONFIG_WR_PPMC) += -I$(srctree)/arch/mips/include/asm/mach-wrppmc
-load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
-
-#
-# Loongson family
-#
-core-$(CONFIG_MACH_LOONGSON) += arch/mips/loongson/
-cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson \
- -mno-branch-likely
-load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
-load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
-
-#
-# MIPS Malta board
-#
-core-$(CONFIG_MIPS_MALTA) += arch/mips/mti-malta/
-cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
-load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
-all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin
-
-#
-# MIPS SIM
-#
-core-$(CONFIG_MIPS_SIM) += arch/mips/mipssim/
-cflags-$(CONFIG_MIPS_SIM) += -I$(srctree)/arch/mips/include/asm/mach-mipssim
-load-$(CONFIG_MIPS_SIM) += 0x80100000
-
-#
-# PMC-Sierra MSP SOCs
-#
-core-$(CONFIG_PMC_MSP) += arch/mips/pmc-sierra/msp71xx/
-cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/pmc-sierra/msp71xx \
- -mno-branch-likely
-load-$(CONFIG_PMC_MSP) += 0xffffffff80100000
-
-#
-# PMC-Sierra Yosemite
-#
-core-$(CONFIG_PMC_YOSEMITE) += arch/mips/pmc-sierra/yosemite/
-cflags-$(CONFIG_PMC_YOSEMITE) += -I$(srctree)/arch/mips/include/asm/mach-yosemite
-load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000
-
-#
-# LASAT platforms
-#
-core-$(CONFIG_LASAT) += arch/mips/lasat/
-cflags-$(CONFIG_LASAT) += -I$(srctree)/arch/mips/include/asm/mach-lasat
-load-$(CONFIG_LASAT) += 0xffffffff80000000
-
-#
-# Common VR41xx
-#
-core-$(CONFIG_MACH_VR41XX) += arch/mips/vr41xx/common/
-cflags-$(CONFIG_MACH_VR41XX) += -I$(srctree)/arch/mips/include/asm/mach-vr41xx
-
-#
-# ZAO Networks Capcella (VR4131)
-#
-load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000
-
-#
-# Victor MP-C303/304 (VR4122)
-#
-load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000
-
-#
-# IBM WorkPad z50 (VR4121)
-#
-core-$(CONFIG_IBM_WORKPAD) += arch/mips/vr41xx/ibm-workpad/
-load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000
-
-#
-# CASIO CASSIPEIA E-55/65 (VR4111)
-#
-core-$(CONFIG_CASIO_E55) += arch/mips/vr41xx/casio-e55/
-load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
-
-#
-# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
-#
-load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
-
-# NXP STB225
-core-$(CONFIG_SOC_PNX833X) += arch/mips/nxp/pnx833x/common/
-cflags-$(CONFIG_SOC_PNX833X) += -Iarch/mips/include/asm/mach-pnx833x
-libs-$(CONFIG_NXP_STB220) += arch/mips/nxp/pnx833x/stb22x/
-load-$(CONFIG_NXP_STB220) += 0xffffffff80001000
-libs-$(CONFIG_NXP_STB225) += arch/mips/nxp/pnx833x/stb22x/
-load-$(CONFIG_NXP_STB225) += 0xffffffff80001000
-
-#
-# Common NXP PNX8550
-#
-core-$(CONFIG_SOC_PNX8550) += arch/mips/nxp/pnx8550/common/
-cflags-$(CONFIG_SOC_PNX8550) += -I$(srctree)/arch/mips/include/asm/mach-pnx8550
-
-#
-# NXP PNX8550 JBS board
-#
-libs-$(CONFIG_PNX8550_JBS) += arch/mips/nxp/pnx8550/jbs/
-#cflags-$(CONFIG_PNX8550_JBS) += -I$(srctree)/arch/mips/include/asm/mach-pnx8550
-load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
-
-# NXP PNX8550 STB810 board
-#
-libs-$(CONFIG_PNX8550_STB810) += arch/mips/nxp/pnx8550/stb810/
-load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
-
-#
-# Common NEC EMMAXXX
-#
-core-$(CONFIG_SOC_EMMA2RH) += arch/mips/emma/common/
-cflags-$(CONFIG_SOC_EMMA2RH) += -I$(srctree)/arch/mips/include/asm/mach-emma2rh
-
-#
-# NEC EMMA2RH Mark-eins
-#
-core-$(CONFIG_NEC_MARKEINS) += arch/mips/emma/markeins/
-load-$(CONFIG_NEC_MARKEINS) += 0xffffffff88100000
-
-#
-# Cisco PowerTV Platform
-#
-core-$(CONFIG_POWERTV) += arch/mips/powertv/
-cflags-$(CONFIG_POWERTV) += -I$(srctree)/arch/mips/include/asm/mach-powertv
-load-$(CONFIG_POWERTV) += 0xffffffff90800000
-
-#
-# SGI IP22 (Indy/Indigo2)
-#
-# Set the load address to >= 0xffffffff88069000 if you want to leave space for
-# symmon, 0xffffffff80002000 for production kernels. Note that the value must
-# be aligned to a multiple of the kernel stack size or the handling of the
-# current variable will break so for 64-bit kernels we have to raise the start
-# address by 8kb.
-#
-core-$(CONFIG_SGI_IP22) += arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP22) += -I$(srctree)/arch/mips/include/asm/mach-ip22
-ifdef CONFIG_32BIT
-load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
-endif
-ifdef CONFIG_64BIT
-load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
-endif
-
-#
-# SGI-IP27 (Origin200/2000)
-#
-# Set the load address to >= 0xc000000000300000 if you want to leave space for
-# symmon, 0xc00000000001c000 for production kernels. Note that the value must
-# be 16kb aligned or the handling of the current variable will break.
-#
-ifdef CONFIG_SGI_IP27
-core-$(CONFIG_SGI_IP27) += arch/mips/sgi-ip27/
-cflags-$(CONFIG_SGI_IP27) += -I$(srctree)/arch/mips/include/asm/mach-ip27
-ifdef CONFIG_MAPPED_KERNEL
-load-$(CONFIG_SGI_IP27) += 0xc00000004001c000
-OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000
-dataoffset-$(CONFIG_SGI_IP27) += 0x01000000
-else
-load-$(CONFIG_SGI_IP27) += 0xa80000000001c000
-OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000
-endif
-endif
-
-#
-# SGI IP28 (Indigo2 R10k)
-#
-# Set the load address to >= 0xa800000020080000 if you want to leave space for
-# symmon, 0xa800000020004000 for production kernels ? Note that the value must
-# be 16kb aligned or the handling of the current variable will break.
-# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
-#
-ifdef CONFIG_SGI_IP28
- ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
- $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
- endif
-endif
-core-$(CONFIG_SGI_IP28) += arch/mips/sgi-ip22/
-cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=store -I$(srctree)/arch/mips/include/asm/mach-ip28
-load-$(CONFIG_SGI_IP28) += 0xa800000020004000
-
-#
-# SGI-IP32 (O2)
-#
-# Set the load address to >= 80069000 if you want to leave space for symmon,
-# 0xffffffff80004000 for production kernels. Note that the value must be aligned to
-# a multiple of the kernel stack size or the handling of the current variable
-# will break.
-#
-core-$(CONFIG_SGI_IP32) += arch/mips/sgi-ip32/
-cflags-$(CONFIG_SGI_IP32) += -I$(srctree)/arch/mips/include/asm/mach-ip32
-load-$(CONFIG_SGI_IP32) += 0xffffffff80004000
-
-#
-# Sibyte SB1250/BCM1480 SOC
-#
-# This is a LIB so that it links at the end, and initcalls are later
-# the sequence; but it is built as an object so that modules don't get
-# removed (as happens, even if they have __initcall/module_init)
-#
-core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/sb1250/
-core-$(CONFIG_SIBYTE_BCM112X) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM112X) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
-
-core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/sb1250/
-core-$(CONFIG_SIBYTE_SB1250) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_SB1250) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
-
-core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/bcm1480/
-core-$(CONFIG_SIBYTE_BCM1x55) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x55) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
-
-core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/bcm1480/
-core-$(CONFIG_SIBYTE_BCM1x80) += arch/mips/sibyte/common/
-cflags-$(CONFIG_SIBYTE_BCM1x80) += -I$(srctree)/arch/mips/include/asm/mach-sibyte \
- -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
-
-#
-# Sibyte BCM91120x (Carmel) board
-# Sibyte BCM91120C (CRhine) board
-# Sibyte BCM91125C (CRhone) board
-# Sibyte BCM91125E (Rhone) board
-# Sibyte SWARM board
-# Sibyte BCM91x80 (BigSur) board
-#
-core-$(CONFIG_SIBYTE_CARMEL) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_CRHINE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_CRHONE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_RHONE) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_SENTOSA) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_SWARM) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
-core-$(CONFIG_SIBYTE_BIGSUR) += arch/mips/sibyte/swarm/
-load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
-
-#
-# Broadcom BCM47XX boards
-#
-core-$(CONFIG_BCM47XX) += arch/mips/bcm47xx/
-cflags-$(CONFIG_BCM47XX) += -I$(srctree)/arch/mips/include/asm/mach-bcm47xx
-load-$(CONFIG_BCM47XX) := 0xffffffff80001000
-
-#
-# Broadcom BCM63XX boards
-#
-core-$(CONFIG_BCM63XX) += arch/mips/bcm63xx/
-cflags-$(CONFIG_BCM63XX) += -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
-load-$(CONFIG_BCM63XX) := 0xffffffff80010000
-
-#
-# SNI RM
-#
-core-$(CONFIG_SNI_RM) += arch/mips/sni/
-cflags-$(CONFIG_SNI_RM) += -I$(srctree)/arch/mips/include/asm/mach-rm
-ifdef CONFIG_CPU_LITTLE_ENDIAN
-load-$(CONFIG_SNI_RM) += 0xffffffff80600000
-else
-load-$(CONFIG_SNI_RM) += 0xffffffff80030000
-endif
-all-$(CONFIG_SNI_RM) := $(COMPRESSION_FNAME).ecoff
-
-#
-# Common TXx9
-#
-core-$(CONFIG_MACH_TX39XX) += arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX39XX) += -I$(srctree)/arch/mips/include/asm/mach-tx39xx
-load-$(CONFIG_MACH_TX39XX) += 0xffffffff80050000
-core-$(CONFIG_MACH_TX49XX) += arch/mips/txx9/generic/
-cflags-$(CONFIG_MACH_TX49XX) += -I$(srctree)/arch/mips/include/asm/mach-tx49xx
-load-$(CONFIG_MACH_TX49XX) += 0xffffffff80100000
-
-#
-# Toshiba JMR-TX3927 board
-#
-core-$(CONFIG_TOSHIBA_JMR3927) += arch/mips/txx9/jmr3927/
-
-#
-# Routerboard 532 board
-#
-core-$(CONFIG_MIKROTIK_RB532) += arch/mips/rb532/
-cflags-$(CONFIG_MIKROTIK_RB532) += -I$(srctree)/arch/mips/include/asm/mach-rc32434
-load-$(CONFIG_MIKROTIK_RB532) += 0xffffffff80101000
-
-#
-# Toshiba RBTX49XX boards
-#
-core-$(CONFIG_TOSHIBA_RBTX4927) += arch/mips/txx9/rbtx4927/
-core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/txx9/rbtx4938/
-core-$(CONFIG_TOSHIBA_RBTX4939) += arch/mips/txx9/rbtx4939/
-
-#
-# Cavium Octeon
-#
-core-$(CONFIG_CPU_CAVIUM_OCTEON) += arch/mips/cavium-octeon/
-cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += -I$(srctree)/arch/mips/include/asm/mach-cavium-octeon
-core-$(CONFIG_CPU_CAVIUM_OCTEON) += arch/mips/cavium-octeon/executive/
-ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
-load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff84100000
-else
-load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
-endif
+include $(srctree)/arch/mips/Kbuild.platforms
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/
@@ -706,7 +238,8 @@ head-y := arch/mips/kernel/head.o arch/mips/kernel/init_task.o
libs-y += arch/mips/lib/
-core-y += arch/mips/kernel/ arch/mips/mm/ arch/mips/math-emu/
+# See arch/mips/Kbuild for content of core part of the kernel
+core-y += arch/mips/
drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
@@ -733,35 +266,19 @@ vmlinux.32: vmlinux
vmlinux.64: vmlinux
$(OBJCOPY) -O $(64bit-bfd) $(OBJCOPYFLAGS) $< $@
-makeboot =$(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) $(1)
-makezboot =$(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
- VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $(1)
-
all: $(all-y)
-vmlinuz: vmlinux FORCE
- +@$(call makezboot,$@)
+# boot
+vmlinux.bin vmlinux.ecoff vmlinux.srec: $(vmlinux-32) FORCE
+ $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) arch/mips/boot/$@
-vmlinuz.bin: vmlinux
- +@$(call makezboot,$@)
+# boot/compressed
+vmlinuz vmlinuz.bin vmlinuz.ecoff vmlinuz.srec: $(vmlinux-32) FORCE
+ $(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
+ VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $@
-vmlinuz.ecoff: vmlinux
- +@$(call makezboot,$@)
-vmlinuz.srec: vmlinux
- +@$(call makezboot,$@)
-
-vmlinux.bin: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-vmlinux.ecoff: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-vmlinux.srec: $(vmlinux-32)
- +@$(call makeboot,$@)
-
-CLEAN_FILES += vmlinux.ecoff \
- vmlinux.srec
+CLEAN_FILES += vmlinux.32 vmlinux.64
archprepare:
ifdef CONFIG_MIPS32_N32
@@ -780,9 +297,9 @@ install:
$(Q)install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE)
archclean:
- @$(MAKE) $(clean)=arch/mips/boot
- @$(MAKE) $(clean)=arch/mips/boot/compressed
- @$(MAKE) $(clean)=arch/mips/lasat
+ $(Q)$(MAKE) $(clean)=arch/mips/boot
+ $(Q)$(MAKE) $(clean)=arch/mips/boot/compressed
+ $(Q)$(MAKE) $(clean)=arch/mips/lasat
define archhelp
echo ' install - install kernel into $(INSTALL_PATH)'
@@ -796,11 +313,3 @@ define archhelp
echo
echo ' These will be default as apropriate for a configured platform.'
endef
-
-CLEAN_FILES += vmlinux.32 \
- vmlinux.64 \
- vmlinux.ecoff \
- vmlinuz \
- vmlinuz.ecoff \
- vmlinuz.bin \
- vmlinuz.srec
diff --git a/arch/mips/alchemy/Platform b/arch/mips/alchemy/Platform
new file mode 100644
index 000000000000..495cc9a2a3b1
--- /dev/null
+++ b/arch/mips/alchemy/Platform
@@ -0,0 +1,109 @@
+#
+# Core Alchemy code
+#
+platform-$(CONFIG_MACH_ALCHEMY) += alchemy/common/
+
+
+#
+# AMD Alchemy Pb1000 eval board
+#
+platform-$(CONFIG_MIPS_PB1000) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1000) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1000) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1100 eval board
+#
+platform-$(CONFIG_MIPS_PB1100) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1100) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1100) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1500 eval board
+#
+platform-$(CONFIG_MIPS_PB1500) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1500) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1500) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1550 eval board
+#
+platform-$(CONFIG_MIPS_PB1550) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1550) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1550) += 0xffffffff80100000
+
+#
+# AMD Alchemy Pb1200 eval board
+#
+platform-$(CONFIG_MIPS_PB1200) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_PB1200) += -I$(srctree)/arch/mips/include/asm/mach-pb1x00
+load-$(CONFIG_MIPS_PB1200) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1000 eval board
+#
+platform-$(CONFIG_MIPS_DB1000) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1000) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1000) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1100 eval board
+#
+platform-$(CONFIG_MIPS_DB1100) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1100) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1100) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1500 eval board
+#
+platform-$(CONFIG_MIPS_DB1500) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1500) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1500) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1550 eval board
+#
+platform-$(CONFIG_MIPS_DB1550) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1550) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1550) += 0xffffffff80100000
+
+#
+# AMD Alchemy Db1200 eval board
+#
+platform-$(CONFIG_MIPS_DB1200) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_DB1200) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_DB1200) += 0xffffffff80100000
+
+#
+# AMD Alchemy Bosporus eval board
+#
+platform-$(CONFIG_MIPS_BOSPORUS) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_BOSPORUS) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_BOSPORUS) += 0xffffffff80100000
+
+#
+# AMD Alchemy Mirage eval board
+#
+platform-$(CONFIG_MIPS_MIRAGE) += alchemy/devboards/
+cflags-$(CONFIG_MIPS_MIRAGE) += -I$(srctree)/arch/mips/include/asm/mach-db1x00
+load-$(CONFIG_MIPS_MIRAGE) += 0xffffffff80100000
+
+#
+# 4G-Systems eval board
+#
+platform-$(CONFIG_MIPS_MTX1) += alchemy/mtx-1/
+load-$(CONFIG_MIPS_MTX1) += 0xffffffff80100000
+
+#
+# MyCable eval board
+#
+platform-$(CONFIG_MIPS_XXS1500) += alchemy/xxs1500/
+load-$(CONFIG_MIPS_XXS1500) += 0xffffffff80100000
+
+
+# boards can specify their own <gpio.h> in one of their include dirs.
+# If they do, placing this line here at the end will make sure the
+# compiler picks the board one. If they don't, it will make sure
+# the alchemy generic gpio header is picked up.
+
+cflags-$(CONFIG_MACH_ALCHEMY) += -I$(srctree)/arch/mips/include/asm/mach-au1x00
diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile
index 06c0e65a54b5..27811fe341d6 100644
--- a/arch/mips/alchemy/common/Makefile
+++ b/arch/mips/alchemy/common/Makefile
@@ -18,5 +18,3 @@ ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),)
endif
obj-$(CONFIG_PCI) += pci.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/devboards/Makefile b/arch/mips/alchemy/devboards/Makefile
index ecbd37f9ee87..826449c817c3 100644
--- a/arch/mips/alchemy/devboards/Makefile
+++ b/arch/mips/alchemy/devboards/Makefile
@@ -16,5 +16,3 @@ obj-$(CONFIG_MIPS_DB1500) += db1x00/
obj-$(CONFIG_MIPS_DB1550) += db1x00/
obj-$(CONFIG_MIPS_BOSPORUS) += db1x00/
obj-$(CONFIG_MIPS_MIRAGE) += db1x00/
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/devboards/pb1200/Makefile b/arch/mips/alchemy/devboards/pb1200/Makefile
index 2ea9b02ef09f..18c1bd53e4c0 100644
--- a/arch/mips/alchemy/devboards/pb1200/Makefile
+++ b/arch/mips/alchemy/devboards/pb1200/Makefile
@@ -3,5 +3,3 @@
#
obj-y := board_setup.o platform.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/alchemy/mtx-1/Makefile b/arch/mips/alchemy/mtx-1/Makefile
index 4a53815b3c6c..81b540ceaf88 100644
--- a/arch/mips/alchemy/mtx-1/Makefile
+++ b/arch/mips/alchemy/mtx-1/Makefile
@@ -6,7 +6,4 @@
# Makefile for 4G Systems MTX-1 board.
#
-lib-y := init.o board_setup.o
-obj-y := platform.o
-
-EXTRA_CFLAGS += -Werror
+obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/alchemy/xxs1500/Makefile b/arch/mips/alchemy/xxs1500/Makefile
index 4dc81d794cb8..91defcf4f335 100644
--- a/arch/mips/alchemy/xxs1500/Makefile
+++ b/arch/mips/alchemy/xxs1500/Makefile
@@ -5,6 +5,4 @@
# Makefile for MyCable XXS1500 board.
#
-lib-y := init.o board_setup.o platform.o
-
-EXTRA_CFLAGS += -Werror
+obj-y += init.o board_setup.o platform.o
diff --git a/arch/mips/ar7/Makefile b/arch/mips/ar7/Makefile
index 26bc5da18997..7435e44b3964 100644
--- a/arch/mips/ar7/Makefile
+++ b/arch/mips/ar7/Makefile
@@ -8,4 +8,3 @@ obj-y := \
platform.o \
gpio.o \
clock.o
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/ar7/Platform b/arch/mips/ar7/Platform
new file mode 100644
index 000000000000..0bf85c416c6c
--- /dev/null
+++ b/arch/mips/ar7/Platform
@@ -0,0 +1,6 @@
+#
+# Texas Instruments AR7
+#
+platform-$(CONFIG_AR7) += ar7/
+cflags-$(CONFIG_AR7) += -I$(srctree)/arch/mips/include/asm/mach-ar7
+load-$(CONFIG_AR7) += 0xffffffff94100000
diff --git a/arch/mips/bcm47xx/Platform b/arch/mips/bcm47xx/Platform
new file mode 100644
index 000000000000..874b7ca4cd11
--- /dev/null
+++ b/arch/mips/bcm47xx/Platform
@@ -0,0 +1,7 @@
+#
+# Broadcom BCM47XX boards
+#
+platform-$(CONFIG_BCM47XX) += bcm47xx/
+cflags-$(CONFIG_BCM47XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-bcm47xx
+load-$(CONFIG_BCM47XX) := 0xffffffff80001000
diff --git a/arch/mips/bcm63xx/Makefile b/arch/mips/bcm63xx/Makefile
index 00064b660809..6dfdc69928ac 100644
--- a/arch/mips/bcm63xx/Makefile
+++ b/arch/mips/bcm63xx/Makefile
@@ -3,5 +3,3 @@ obj-y += clk.o cpu.o cs.o gpio.o irq.o prom.o setup.o timer.o \
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-y += boards/
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/bcm63xx/Platform b/arch/mips/bcm63xx/Platform
new file mode 100644
index 000000000000..5f86b2fff6de
--- /dev/null
+++ b/arch/mips/bcm63xx/Platform
@@ -0,0 +1,7 @@
+#
+# Broadcom BCM63XX boards
+#
+platform-$(CONFIG_BCM63XX) += bcm63xx/
+cflags-$(CONFIG_BCM63XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-bcm63xx/
+load-$(CONFIG_BCM63XX) := 0xffffffff80010000
diff --git a/arch/mips/boot/Makefile b/arch/mips/boot/Makefile
index e39a08edcaaa..85bcb5adc7cb 100644
--- a/arch/mips/boot/Makefile
+++ b/arch/mips/boot/Makefile
@@ -11,35 +11,32 @@
# Some DECstations need all possible sections of an ECOFF executable
#
ifdef CONFIG_MACH_DECSTATION
- E2EFLAGS = -a
-else
- E2EFLAGS =
+ e2eflag := -a
endif
#
# Drop some uninteresting sections in the kernel.
# This is only relevant for ELF kernels but doesn't hurt a.out
#
-drop-sections = .reginfo .mdebug .comment .note .pdr .options .MIPS.options
-strip-flags = $(addprefix --remove-section=,$(drop-sections))
-
-VMLINUX = vmlinux
-
-all: vmlinux.ecoff vmlinux.srec
-
-vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX)
- $(obj)/elf2ecoff $(VMLINUX) $(obj)/vmlinux.ecoff $(E2EFLAGS)
-
-$(obj)/elf2ecoff: $(obj)/elf2ecoff.c
- $(HOSTCC) -o $@ $^
-
-vmlinux.bin: $(VMLINUX)
- $(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $(obj)/vmlinux.bin
-
-vmlinux.srec: $(VMLINUX)
- $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $(obj)/vmlinux.srec
-
-clean-files += elf2ecoff \
- vmlinux.bin \
- vmlinux.ecoff \
- vmlinux.srec
+drop-sections := .reginfo .mdebug .comment .note .pdr .options .MIPS.options
+strip-flags := $(addprefix --remove-section=,$(drop-sections))
+
+hostprogs-y := elf2ecoff
+
+targets := vmlinux.ecoff
+quiet_cmd_ecoff = ECOFF $@
+ cmd_ecoff = $(obj)/elf2ecoff $(VMLINUX) $@ $(e2eflag)
+$(obj)/vmlinux.ecoff: $(obj)/elf2ecoff $(VMLINUX) FORCE
+ $(call if_changed,ecoff)
+
+targets += vmlinux.bin
+quiet_cmd_bin = OBJCOPY $@
+ cmd_bin = $(OBJCOPY) -O binary $(strip-flags) $(VMLINUX) $@
+$(obj)/vmlinux.bin: $(VMLINUX) FORCE
+ $(call if_changed,bin)
+
+targets += vmlinux.srec
+quiet_cmd_srec = OBJCOPY $@
+ cmd_srec = $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $@
+$(obj)/vmlinux.srec: $(VMLINUX) FORCE
+ $(call if_changed,srec)
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
index 790ddd397620..74a52d799346 100644
--- a/arch/mips/boot/compressed/Makefile
+++ b/arch/mips/boot/compressed/Makefile
@@ -33,15 +33,19 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
-DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ )
-obj-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
+
+# decompressor objects (linked with vmlinuz)
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
ifdef CONFIG_DEBUG_ZBOOT
-obj-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
-obj-$(CONFIG_MACH_ALCHEMY) += $(obj)/uart-alchemy.o
+vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
+vmlinuzobjs-$(CONFIG_MACH_ALCHEMY) += $(obj)/uart-alchemy.o
endif
+targets += vmlinux.bin
OBJCOPYFLAGS_vmlinux.bin := $(OBJCOPYFLAGS) -O binary -R .comment -S
-$(obj)/vmlinux.bin: $(KBUILD_IMAGE)
+$(obj)/vmlinux.bin: $(KBUILD_IMAGE) FORCE
$(call if_changed,objcopy)
suffix_$(CONFIG_KERNEL_GZIP) = gz
@@ -52,30 +56,31 @@ tool_$(CONFIG_KERNEL_GZIP) = gzip
tool_$(CONFIG_KERNEL_BZIP2) = bzip2
tool_$(CONFIG_KERNEL_LZMA) = lzma
tool_$(CONFIG_KERNEL_LZO) = lzo
-$(obj)/vmlinux.$(suffix_y): $(obj)/vmlinux.bin
+
+targets += vmlinux.gz vmlinux.bz2 vmlinux.lzma vmlinux.lzo
+$(obj)/vmlinux.$(suffix_y): $(obj)/vmlinux.bin FORCE
$(call if_changed,$(tool_y))
-$(obj)/piggy.o: $(obj)/vmlinux.$(suffix_y) $(obj)/dummy.o
- $(Q)$(OBJCOPY) $(OBJCOPYFLAGS) \
- --add-section=.image=$< \
- --set-section-flags=.image=contents,alloc,load,readonly,data \
- $(obj)/dummy.o $@
+targets += piggy.o
+OBJCOPYFLAGS_piggy.o := --add-section=.image=$(obj)/vmlinux.$(suffix_y) \
+ --set-section-flags=.image=contents,alloc,load,readonly,data
+$(obj)/piggy.o: $(obj)/dummy.o $(obj)/vmlinux.$(suffix_y) FORCE
+ $(call if_changed,objcopy)
LDFLAGS_vmlinuz := $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T
-vmlinuz: $(src)/ld.script $(obj-y) $(obj)/piggy.o
- $(call if_changed,ld)
+vmlinuz: $(src)/ld.script $(vmlinuzobjs-y) $(obj)/piggy.o
+ $(call cmd,ld)
$(Q)$(OBJCOPY) $(OBJCOPYFLAGS) $@
#
# Some DECstations need all possible sections of an ECOFF executable
#
ifdef CONFIG_MACH_DECSTATION
- E2EFLAGS = -a
-else
- E2EFLAGS =
+ e2eflag := -a
endif
# elf2ecoff can only handle 32bit image
+hostprogs-y := ../elf2ecoff
ifdef CONFIG_32BIT
VMLINUZ = vmlinuz
@@ -83,23 +88,22 @@ else
VMLINUZ = vmlinuz.32
endif
+quiet_cmd_32 = OBJCOPY $@
+ cmd_32 = $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
vmlinuz.32: vmlinuz
- $(Q)$(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
+ $(call cmd,32)
+quiet_cmd_ecoff = ECOFF $@
+ cmd_ecoff = $< $(VMLINUZ) $@ $(e2eflag)
vmlinuz.ecoff: $(obj)/../elf2ecoff $(VMLINUZ)
- $(Q)$(obj)/../elf2ecoff $(VMLINUZ) vmlinuz.ecoff $(E2EFLAGS)
-
-$(obj)/../elf2ecoff: $(src)/../elf2ecoff.c
- $(Q)$(HOSTCC) -o $@ $^
+ $(call cmd,ecoff)
OBJCOPYFLAGS_vmlinuz.bin := $(OBJCOPYFLAGS) -O binary
vmlinuz.bin: vmlinuz
- $(call if_changed,objcopy)
+ $(call cmd,objcopy)
OBJCOPYFLAGS_vmlinuz.srec := $(OBJCOPYFLAGS) -S -O srec
vmlinuz.srec: vmlinuz
- $(call if_changed,objcopy)
+ $(call cmd,objcopy)
-clean:
-clean-files += *.o \
- vmlinu*
+clean-files := $(objtree)/vmlinuz.*
diff --git a/arch/mips/cavium-octeon/Makefile b/arch/mips/cavium-octeon/Makefile
index 3e9876317e61..19eb0434269f 100644
--- a/arch/mips/cavium-octeon/Makefile
+++ b/arch/mips/cavium-octeon/Makefile
@@ -12,7 +12,6 @@
obj-y := cpu.o setup.o serial.o octeon-platform.o octeon-irq.o csrc-octeon.o
obj-y += dma-octeon.o flash_setup.o
obj-y += octeon-memcpy.o
+obj-y += executive/
obj-$(CONFIG_SMP) += smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/cavium-octeon/Platform b/arch/mips/cavium-octeon/Platform
new file mode 100644
index 000000000000..1e43ccf1a792
--- /dev/null
+++ b/arch/mips/cavium-octeon/Platform
@@ -0,0 +1,11 @@
+#
+# Cavium Octeon
+#
+platform-$(CONFIG_CPU_CAVIUM_OCTEON) += cavium-octeon/
+cflags-$(CONFIG_CPU_CAVIUM_OCTEON) += \
+ -I$(srctree)/arch/mips/include/asm/mach-cavium-octeon
+ifdef CONFIG_CAVIUM_OCTEON_2ND_KERNEL
+load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff84100000
+else
+load-$(CONFIG_CPU_CAVIUM_OCTEON) += 0xffffffff81100000
+endif
diff --git a/arch/mips/cobalt/Makefile b/arch/mips/cobalt/Makefile
index 237926288d6d..61a334ac43ac 100644
--- a/arch/mips/cobalt/Makefile
+++ b/arch/mips/cobalt/Makefile
@@ -7,5 +7,3 @@ obj-y := buttons.o irq.o lcd.o led.o reset.o rtc.o serial.o setup.o time.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_EARLY_PRINTK) += console.o
obj-$(CONFIG_MTD_PHYSMAP) += mtd.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/cobalt/Platform b/arch/mips/cobalt/Platform
new file mode 100644
index 000000000000..34123efd6dfe
--- /dev/null
+++ b/arch/mips/cobalt/Platform
@@ -0,0 +1,6 @@
+#
+# Cobalt Server
+#
+platform-$(CONFIG_MIPS_COBALT) += cobalt/
+cflags-$(CONFIG_MIPS_COBALT) += -I$(srctree)/arch/mips/include/asm/mach-cobalt
+load-$(CONFIG_MIPS_COBALT) += 0xffffffff80080000
diff --git a/arch/mips/dec/Makefile b/arch/mips/dec/Makefile
index c530208ee154..9eb2f9c036aa 100644
--- a/arch/mips/dec/Makefile
+++ b/arch/mips/dec/Makefile
@@ -8,5 +8,3 @@ obj-y := ecc-berr.o int-handler.o ioasic-irq.o kn01-berr.o \
obj-$(CONFIG_PROM_CONSOLE) += promcon.o
obj-$(CONFIG_TC) += tc.o
obj-$(CONFIG_CPU_HAS_WB) += wbflush.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/dec/Platform b/arch/mips/dec/Platform
new file mode 100644
index 000000000000..3adbcbd95db1
--- /dev/null
+++ b/arch/mips/dec/Platform
@@ -0,0 +1,8 @@
+#
+# DECstation family
+#
+platform-$(CONFIG_MACH_DECSTATION) = dec/
+cflags-$(CONFIG_MACH_DECSTATION) += \
+ -I$(srctree)/arch/mips/include/asm/mach-dec
+libs-$(CONFIG_MACH_DECSTATION) += arch/mips/dec/prom/
+load-$(CONFIG_MACH_DECSTATION) += 0xffffffff80040000
diff --git a/arch/mips/dec/promcon.c b/arch/mips/dec/promcon.c
index 9f0972f5a702..c239c25b79ff 100644
--- a/arch/mips/dec/promcon.c
+++ b/arch/mips/dec/promcon.c
@@ -33,8 +33,7 @@ static int __init prom_console_setup(struct console *co, char *options)
return 0;
}
-static struct console sercons =
-{
+static struct console sercons = {
.name = "ttyS",
.write = prom_console_write,
.setup = prom_console_setup,
diff --git a/arch/mips/emma/Makefile b/arch/mips/emma/Makefile
new file mode 100644
index 000000000000..4254a31edb09
--- /dev/null
+++ b/arch/mips/emma/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_SOC_EMMA2RH) += common/
+
+#
+# NEC EMMA2RH Mark-eins
+#
+obj-$(CONFIG_NEC_MARKEINS) += markeins/
diff --git a/arch/mips/emma/Platform b/arch/mips/emma/Platform
new file mode 100644
index 000000000000..0282f7f99b88
--- /dev/null
+++ b/arch/mips/emma/Platform
@@ -0,0 +1,4 @@
+platform-$(CONFIG_SOC_EMMA2RH) += emma/
+cflags-$(CONFIG_SOC_EMMA2RH) += \
+ -I$(srctree)/arch/mips/include/asm/mach-emma2rh
+load-$(CONFIG_NEC_MARKEINS) += 0xffffffff88100000
diff --git a/arch/mips/include/asm/mach-powertv/asic_reg_map.h b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
index 6f26cb09828e..20348e817b09 100644
--- a/arch/mips/include/asm/mach-powertv/asic_reg_map.h
+++ b/arch/mips/include/asm/mach-powertv/asic_reg_map.h
@@ -64,7 +64,7 @@ REGISTER_MAP_ELEMENT(int_level_0_1)
REGISTER_MAP_ELEMENT(int_level_0_0)
REGISTER_MAP_ELEMENT(int_docsis_en)
REGISTER_MAP_ELEMENT(mips_pll_setup)
-REGISTER_MAP_ELEMENT(usb_fs)
+REGISTER_MAP_ELEMENT(fs432x4b4_usb_ctl)
REGISTER_MAP_ELEMENT(test_bus)
REGISTER_MAP_ELEMENT(crt_spare)
REGISTER_MAP_ELEMENT(usb2_ohci_int_mask)
diff --git a/arch/mips/include/asm/mach-powertv/dma-coherence.h b/arch/mips/include/asm/mach-powertv/dma-coherence.h
index 5b8d5ebeb838..f76029c2406e 100644
--- a/arch/mips/include/asm/mach-powertv/dma-coherence.h
+++ b/arch/mips/include/asm/mach-powertv/dma-coherence.h
@@ -65,21 +65,21 @@ static inline dma_addr_t plat_map_dma_mem(struct device *dev, void *addr,
size_t size)
{
if (is_kseg2(addr))
- return phys_to_bus(virt_to_phys_from_pte(addr));
+ return phys_to_dma(virt_to_phys_from_pte(addr));
else
- return phys_to_bus(virt_to_phys(addr));
+ return phys_to_dma(virt_to_phys(addr));
}
static inline dma_addr_t plat_map_dma_mem_page(struct device *dev,
struct page *page)
{
- return phys_to_bus(page_to_phys(page));
+ return phys_to_dma(page_to_phys(page));
}
static inline unsigned long plat_dma_addr_to_phys(struct device *dev,
dma_addr_t dma_addr)
{
- return bus_to_phys(dma_addr);
+ return dma_to_phys(dma_addr);
}
static inline void plat_unmap_dma_mem(struct device *dev, dma_addr_t dma_addr,
diff --git a/arch/mips/include/asm/mach-powertv/ioremap.h b/arch/mips/include/asm/mach-powertv/ioremap.h
index e6276d5146e8..076f2eeaa575 100644
--- a/arch/mips/include/asm/mach-powertv/ioremap.h
+++ b/arch/mips/include/asm/mach-powertv/ioremap.h
@@ -10,64 +10,101 @@
#define __ASM_MACH_POWERTV_IOREMAP_H
#include <linux/types.h>
+#include <linux/log2.h>
+#include <linux/compiler.h>
-#define LOW_MEM_BOUNDARY_PHYS 0x20000000
-#define LOW_MEM_BOUNDARY_MASK (~(LOW_MEM_BOUNDARY_PHYS - 1))
+#include <asm/pgtable-bits.h>
+#include <asm/addrspace.h>
+
+/* We're going to mess with bits, so get sizes */
+#define IOR_BPC 8 /* Bits per char */
+#define IOR_PHYS_BITS (IOR_BPC * sizeof(phys_addr_t))
+#define IOR_DMA_BITS (IOR_BPC * sizeof(dma_addr_t))
/*
- * The bus addresses are different than the physical addresses that
- * the processor sees by an offset. This offset varies by ASIC
- * version. Define a variable to hold the offset and some macros to
- * make the conversion simpler. */
-extern unsigned long phys_to_bus_offset;
-
-#ifdef CONFIG_HIGHMEM
-#define MEM_GAP_PHYS 0x60000000
+ * Define the granularity of physical/DMA mapping in terms of the number
+ * of bits that defines the offset within a grain. These will be the
+ * least significant bits of the address. The rest of a physical or DMA
+ * address will be used to index into an appropriate table to find the
+ * offset to add to the address to yield the corresponding DMA or physical
+ * address, respectively.
+ */
+#define IOR_LSBITS 22 /* Bits in a grain */
+
/*
- * TODO: We will use the hard code for conversion between physical and
- * bus until the bootloader releases their device tree to us.
+ * Compute the number of most significant address bits after removing those
+ * used for the offset within a grain and then compute the number of table
+ * entries for the conversion.
*/
-#define phys_to_bus(x) (((x) < LOW_MEM_BOUNDARY_PHYS) ? \
- ((x) + phys_to_bus_offset) : (x))
-#define bus_to_phys(x) (((x) < MEM_GAP_PHYS_ADDR) ? \
- ((x) - phys_to_bus_offset) : (x))
-#else
-#define phys_to_bus(x) ((x) + phys_to_bus_offset)
-#define bus_to_phys(x) ((x) - phys_to_bus_offset)
-#endif
+#define IOR_PHYS_MSBITS (IOR_PHYS_BITS - IOR_LSBITS)
+#define IOR_NUM_PHYS_TO_DMA ((phys_addr_t) 1 << IOR_PHYS_MSBITS)
+
+#define IOR_DMA_MSBITS (IOR_DMA_BITS - IOR_LSBITS)
+#define IOR_NUM_DMA_TO_PHYS ((dma_addr_t) 1 << IOR_DMA_MSBITS)
/*
- * Determine whether the address we are given is for an ASIC device
- * Params: addr Address to check
- * Returns: Zero if the address is not for ASIC devices, non-zero
- * if it is.
+ * Define data structures used as elements in the arrays for the conversion
+ * between physical and DMA addresses. We do some slightly fancy math to
+ * compute the width of the offset element of the conversion tables so
+ * that we can have the smallest conversion tables. Next, round up the
+ * sizes to the next higher power of two, i.e. the offset element will have
+ * 8, 16, 32, 64, etc. bits. This eliminates the need to mask off any
+ * bits. Finally, we compute a shift value that puts the most significant
+ * bits of the offset into the most significant bits of the offset element.
+ * This makes it more efficient on processors without barrel shifters and
+ * easier to see the values if the conversion table is dumped in binary.
*/
-static inline int asic_is_device_addr(phys_t addr)
+#define _IOR_OFFSET_WIDTH(n) (1 << order_base_2(n))
+#define IOR_OFFSET_WIDTH(n) \
+ (_IOR_OFFSET_WIDTH(n) < 8 ? 8 : _IOR_OFFSET_WIDTH(n))
+
+#define IOR_PHYS_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_PHYS_MSBITS)
+#define IOR_PHYS_SHIFT (IOR_PHYS_BITS - IOR_PHYS_OFFSET_BITS)
+
+#define IOR_DMA_OFFSET_BITS IOR_OFFSET_WIDTH(IOR_DMA_MSBITS)
+#define IOR_DMA_SHIFT (IOR_DMA_BITS - IOR_DMA_OFFSET_BITS)
+
+struct ior_phys_to_dma {
+ dma_addr_t offset:IOR_DMA_OFFSET_BITS __packed
+ __aligned((IOR_DMA_OFFSET_BITS / IOR_BPC));
+};
+
+struct ior_dma_to_phys {
+ dma_addr_t offset:IOR_PHYS_OFFSET_BITS __packed
+ __aligned((IOR_PHYS_OFFSET_BITS / IOR_BPC));
+};
+
+extern struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA];
+extern struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS];
+
+static inline dma_addr_t _phys_to_dma_offset_raw(phys_addr_t phys)
{
- return !((phys_t)addr & (phys_t) LOW_MEM_BOUNDARY_MASK);
+ return (dma_addr_t)_ior_phys_to_dma[phys >> IOR_LSBITS].offset;
}
-/*
- * Determine whether the address we are given is external RAM mappable
- * into KSEG1.
- * Params: addr Address to check
- * Returns: Zero if the address is not for external RAM and
- */
-static inline int asic_is_lowmem_ram_addr(phys_t addr)
+static inline dma_addr_t _dma_to_phys_offset_raw(dma_addr_t dma)
{
- /*
- * The RAM always starts at the following address in the processor's
- * physical address space
- */
- static const phys_t phys_ram_base = 0x10000000;
- phys_t bus_ram_base;
+ return (dma_addr_t)_ior_dma_to_phys[dma >> IOR_LSBITS].offset;
+}
- bus_ram_base = phys_to_bus_offset + phys_ram_base;
+/* These are not portable and should not be used in drivers. Drivers should
+ * be using ioremap() and friends to map physical addreses to virtual
+ * addresses and dma_map*() and friends to map virtual addresses into DMA
+ * addresses and back.
+ */
+static inline dma_addr_t phys_to_dma(phys_addr_t phys)
+{
+ return phys + (_phys_to_dma_offset_raw(phys) << IOR_PHYS_SHIFT);
+}
- return addr >= bus_ram_base &&
- addr < (bus_ram_base + (LOW_MEM_BOUNDARY_PHYS - phys_ram_base));
+static inline phys_addr_t dma_to_phys(dma_addr_t dma)
+{
+ return dma + (_dma_to_phys_offset_raw(dma) << IOR_DMA_SHIFT);
}
+extern void ioremap_add_map(dma_addr_t phys, phys_addr_t alias,
+ dma_addr_t size);
+
/*
* Allow physical addresses to be fixed up to help peripherals located
* outside the low 32-bit range -- generic pass-through version.
@@ -77,10 +114,50 @@ static inline phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size)
return phys_addr;
}
-static inline void __iomem *plat_ioremap(phys_t offset, unsigned long size,
+/*
+ * Handle the special case of addresses the area aliased into the first
+ * 512 MiB of the processor's physical address space. These turn into either
+ * kseg0 or kseg1 addresses, depending on flags.
+ */
+static inline void __iomem *plat_ioremap(phys_t start, unsigned long size,
unsigned long flags)
{
- return NULL;
+ phys_addr_t start_offset;
+ void __iomem *result = NULL;
+
+ /* Start by checking to see whether this is an aliased address */
+ start_offset = _dma_to_phys_offset_raw(start);
+
+ /*
+ * If:
+ * o the memory is aliased into the first 512 MiB, and
+ * o the start and end are in the same RAM bank, and
+ * o we don't have a zero size or wrap around, and
+ * o we are supposed to create an uncached mapping,
+ * handle this is a kseg0 or kseg1 address
+ */
+ if (start_offset != 0) {
+ phys_addr_t last;
+ dma_addr_t dma_to_phys_offset;
+
+ last = start + size - 1;
+ dma_to_phys_offset =
+ _dma_to_phys_offset_raw(last) << IOR_DMA_SHIFT;
+
+ if (dma_to_phys_offset == start_offset &&
+ size != 0 && start <= last) {
+ phys_t adjusted_start;
+ adjusted_start = start + start_offset;
+ if (flags == _CACHE_UNCACHED)
+ result = (void __iomem *) (unsigned long)
+ CKSEG1ADDR(adjusted_start);
+ else
+ result = (void __iomem *) (unsigned long)
+ CKSEG0ADDR(adjusted_start);
+ }
+ }
+
+ return result;
}
static inline int plat_iounmap(const volatile void __iomem *addr)
diff --git a/arch/mips/jazz/Makefile b/arch/mips/jazz/Makefile
index 5aee0c266d18..dd9d99bfcf7a 100644
--- a/arch/mips/jazz/Makefile
+++ b/arch/mips/jazz/Makefile
@@ -3,5 +3,3 @@
#
obj-y := irq.o jazzdma.o reset.o setup.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/jazz/Platform b/arch/mips/jazz/Platform
new file mode 100644
index 000000000000..3373788acca1
--- /dev/null
+++ b/arch/mips/jazz/Platform
@@ -0,0 +1,6 @@
+#
+# Acer PICA 61, Mips Magnum 4000 and Olivetti M700.
+#
+platform-$(CONFIG_MACH_JAZZ) += jazz/
+cflags-$(CONFIG_MACH_JAZZ) += -I$(srctree)/arch/mips/include/asm/mach-jazz
+load-$(CONFIG_MACH_JAZZ) += 0xffffffff80080000
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 7a6ac501cbb5..ff5ec2e0184e 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -101,6 +101,4 @@ obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
-EXTRA_CFLAGS += -Werror
-
CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/lasat/Makefile b/arch/mips/lasat/Makefile
index 33791609fe99..9cc4e4db8b99 100644
--- a/arch/mips/lasat/Makefile
+++ b/arch/mips/lasat/Makefile
@@ -12,5 +12,3 @@ obj-$(CONFIG_PICVUE_PROC) += picvue_proc.o
clean:
make -C image clean
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/lasat/Platform b/arch/mips/lasat/Platform
new file mode 100644
index 000000000000..760252828bf1
--- /dev/null
+++ b/arch/mips/lasat/Platform
@@ -0,0 +1,7 @@
+#
+# LASAT platforms
+#
+platform-$(CONFIG_LASAT) += lasat/
+cflags-$(CONFIG_LASAT) += \
+ -I$(srctree)/arch/mips/include/asm/mach-lasat
+load-$(CONFIG_LASAT) += 0xffffffff80000000
diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S
index efb95f2609c2..e0ecda92c40a 100644
--- a/arch/mips/lasat/image/head.S
+++ b/arch/mips/lasat/image/head.S
@@ -1,7 +1,7 @@
#include <asm/lasat/head.h>
.text
- .section .text.start, "ax"
+ .section .text..start, "ax"
.set noreorder
.set mips3
diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal
index 988f8ad189cb..0864c963e188 100644
--- a/arch/mips/lasat/image/romscript.normal
+++ b/arch/mips/lasat/image/romscript.normal
@@ -4,7 +4,7 @@ SECTIONS
{
.text :
{
- *(.text.start)
+ *(.text..start)
}
/* Data in ROM */
diff --git a/arch/mips/loongson/Platform b/arch/mips/loongson/Platform
new file mode 100644
index 000000000000..29692e5433b1
--- /dev/null
+++ b/arch/mips/loongson/Platform
@@ -0,0 +1,32 @@
+#
+# Loongson Processors' Support
+#
+
+# Only gcc >= 4.4 have Loongson specific support
+cflags-$(CONFIG_CPU_LOONGSON2) += -Wa,--trap
+cflags-$(CONFIG_CPU_LOONGSON2E) += \
+ $(call cc-option,-march=loongson2e,-march=r4600)
+cflags-$(CONFIG_CPU_LOONGSON2F) += \
+ $(call cc-option,-march=loongson2f,-march=r4600)
+# Enable the workarounds for Loongson2f
+ifdef CONFIG_CPU_LOONGSON2F_WORKAROUNDS
+ ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-nop,),)
+ $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-nop)
+ else
+ cflags-$(CONFIG_CPU_NOP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-nop
+ endif
+ ifeq ($(call as-option,-Wa$(comma)-mfix-loongson2f-jump,),)
+ $(error only binutils >= 2.20.2 have needed option -mfix-loongson2f-jump)
+ else
+ cflags-$(CONFIG_CPU_JUMP_WORKAROUNDS) += -Wa$(comma)-mfix-loongson2f-jump
+ endif
+endif
+
+#
+# Loongson Machines' Support
+#
+
+platform-$(CONFIG_MACH_LOONGSON) += loongson/
+cflags-$(CONFIG_MACH_LOONGSON) += -I$(srctree)/arch/mips/include/asm/mach-loongson -mno-branch-likely
+load-$(CONFIG_LEMOTE_FULOONG2E) += 0xffffffff80100000
+load-$(CONFIG_LEMOTE_MACH2F) += 0xffffffff80200000
diff --git a/arch/mips/loongson/common/cs5536/Makefile b/arch/mips/loongson/common/cs5536/Makefile
index 510d4cdc2378..f12e64007347 100644
--- a/arch/mips/loongson/common/cs5536/Makefile
+++ b/arch/mips/loongson/common/cs5536/Makefile
@@ -9,5 +9,3 @@ obj-$(CONFIG_CS5536) += cs5536_pci.o cs5536_ide.o cs5536_acc.o cs5536_ohci.o \
# Enable cs5536 mfgpt Timer
#
obj-$(CONFIG_CS5536_MFGPT) += cs5536_mfgpt.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/loongson/fuloong-2e/Makefile b/arch/mips/loongson/fuloong-2e/Makefile
index 3aba5fcc09dc..b7622720c1ad 100644
--- a/arch/mips/loongson/fuloong-2e/Makefile
+++ b/arch/mips/loongson/fuloong-2e/Makefile
@@ -3,5 +3,3 @@
#
obj-y += irq.o reset.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile
index d547efdeedc2..96607230d9ea 100644
--- a/arch/mips/math-emu/Makefile
+++ b/arch/mips/math-emu/Makefile
@@ -10,4 +10,3 @@ obj-y := cp1emu.o ieee754m.o ieee754d.o ieee754dp.o ieee754sp.o ieee754.o \
sp_scalb.o sp_simple.o sp_tint.o sp_fint.o sp_tlong.o sp_flong.o \
dp_sqrt.o sp_sqrt.o kernel_linkage.o dsemul.o
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/math-emu/dp_modf.c b/arch/mips/math-emu/dp_modf.c
index 25861a42c36f..a8570e5c3efc 100644
--- a/arch/mips/math-emu/dp_modf.c
+++ b/arch/mips/math-emu/dp_modf.c
@@ -29,7 +29,7 @@
/* modf function is always exact for a finite number
*/
-ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp * ip)
+ieee754dp ieee754dp_modf(ieee754dp x, ieee754dp *ip)
{
COMPXDP;
diff --git a/arch/mips/math-emu/dp_tint.c b/arch/mips/math-emu/dp_tint.c
index 77b2b7ccf28a..24478623c117 100644
--- a/arch/mips/math-emu/dp_tint.c
+++ b/arch/mips/math-emu/dp_tint.c
@@ -69,8 +69,7 @@ int ieee754dp_tint(ieee754dp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
residue = xm << (64 - DP_MBITS + xe);
round = (residue >> 63) != 0;
sticky = (residue << 1) != 0;
diff --git a/arch/mips/math-emu/dp_tlong.c b/arch/mips/math-emu/dp_tlong.c
index d71113e07164..0f07ec2be3f9 100644
--- a/arch/mips/math-emu/dp_tlong.c
+++ b/arch/mips/math-emu/dp_tlong.c
@@ -71,8 +71,7 @@ s64 ieee754dp_tlong(ieee754dp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
/* Shifting a u64 64 times does not work,
* so we do it in two steps. Be aware that xe
* may be -1 */
diff --git a/arch/mips/math-emu/sp_modf.c b/arch/mips/math-emu/sp_modf.c
index 4b1dbac796f8..76568946b4c0 100644
--- a/arch/mips/math-emu/sp_modf.c
+++ b/arch/mips/math-emu/sp_modf.c
@@ -29,7 +29,7 @@
/* modf function is always exact for a finite number
*/
-ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp * ip)
+ieee754sp ieee754sp_modf(ieee754sp x, ieee754sp *ip)
{
COMPXSP;
diff --git a/arch/mips/math-emu/sp_tint.c b/arch/mips/math-emu/sp_tint.c
index 1d73d2abe0b5..352dc3a5f1af 100644
--- a/arch/mips/math-emu/sp_tint.c
+++ b/arch/mips/math-emu/sp_tint.c
@@ -72,8 +72,7 @@ int ieee754sp_tint(ieee754sp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
/* Shifting a u32 32 times does not work,
* so we do it in two steps. Be aware that xe
* may be -1 */
diff --git a/arch/mips/math-emu/sp_tlong.c b/arch/mips/math-emu/sp_tlong.c
index 4be21aa81fbf..92cd9c511a10 100644
--- a/arch/mips/math-emu/sp_tlong.c
+++ b/arch/mips/math-emu/sp_tlong.c
@@ -71,8 +71,7 @@ s64 ieee754sp_tlong(ieee754sp x)
round = 0;
sticky = residue != 0;
xm = 0;
- }
- else {
+ } else {
residue = xm << (32 - SP_MBITS + xe);
round = (residue >> 31) != 0;
sticky = (residue << 1) != 0;
diff --git a/arch/mips/mipssim/Makefile b/arch/mips/mipssim/Makefile
index 41b96571315e..01410a3f1729 100644
--- a/arch/mips/mipssim/Makefile
+++ b/arch/mips/mipssim/Makefile
@@ -21,5 +21,3 @@ obj-y := sim_platform.o sim_setup.o sim_mem.o sim_time.o sim_int.o
obj-$(CONFIG_EARLY_PRINTK) += sim_console.o
obj-$(CONFIG_MIPS_MT_SMTC) += sim_smtc.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mipssim/Platform b/arch/mips/mipssim/Platform
new file mode 100644
index 000000000000..3df60b8a12ef
--- /dev/null
+++ b/arch/mips/mipssim/Platform
@@ -0,0 +1,6 @@
+#
+# MIPS SIM
+#
+platform-$(CONFIG_MIPS_SIM) += mipssim/
+cflags-$(CONFIG_MIPS_SIM) += -I$(srctree)/arch/mips/include/asm/mach-mipssim
+load-$(CONFIG_MIPS_SIM) += 0x80100000
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index f0e435599707..d679c772d082 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -34,5 +34,3 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index b78f7d913ca4..b4aac424b2e9 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -16,7 +16,6 @@
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/smp.h>
-#include <linux/vt_kern.h> /* For unblank_screen() */
#include <linux/module.h>
#include <asm/branch.h>
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile
index 32e847808df1..6079ef33b5f0 100644
--- a/arch/mips/mti-malta/Makefile
+++ b/arch/mips/mti-malta/Makefile
@@ -15,5 +15,3 @@ obj-$(CONFIG_PCI) += malta-pci.o
# FIXME FIXME FIXME
obj-$(CONFIG_MIPS_MT_SMTC) += malta-smtc.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/mti-malta/Platform b/arch/mips/mti-malta/Platform
new file mode 100644
index 000000000000..5b548b5a4fcf
--- /dev/null
+++ b/arch/mips/mti-malta/Platform
@@ -0,0 +1,7 @@
+#
+# MIPS Malta board
+#
+platform-$(CONFIG_MIPS_MALTA) += mti-malta/
+cflags-$(CONFIG_MIPS_MALTA) += -I$(srctree)/arch/mips/include/asm/mach-malta
+load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
+all-$(CONFIG_MIPS_MALTA) := $(COMPRESSION_FNAME).bin
diff --git a/arch/mips/nxp/pnx833x/stb22x/Makefile b/arch/mips/nxp/pnx833x/stb22x/Makefile
deleted file mode 100644
index f81c5801f455..000000000000
--- a/arch/mips/nxp/pnx833x/stb22x/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-lib-y := board.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx8550/jbs/Makefile b/arch/mips/nxp/pnx8550/jbs/Makefile
deleted file mode 100644
index ad6a8ca7d8ce..000000000000
--- a/arch/mips/nxp/pnx8550/jbs/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# Makefile for the NXP JBS Board.
-
-lib-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/stb810/Makefile b/arch/mips/nxp/pnx8550/stb810/Makefile
deleted file mode 100644
index ab91d72c5664..000000000000
--- a/arch/mips/nxp/pnx8550/stb810/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-
-# Makefile for the NXP STB810 Board.
-
-lib-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/pci/ops-titan-ht.c b/arch/mips/pci/ops-titan-ht.c
index 749c1922d420..57d54adc9e20 100644
--- a/arch/mips/pci/ops-titan-ht.c
+++ b/arch/mips/pci/ops-titan-ht.c
@@ -32,7 +32,7 @@
#include <asm/titan_dep.h>
static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn,
- int offset, u32 * val)
+ int offset, u32 *val)
{
volatile uint32_t address;
int busno;
@@ -64,7 +64,7 @@ static int titan_ht_config_read_dword(struct pci_bus *bus, unsigned int devfn,
}
static int titan_ht_config_read(struct pci_bus *bus, unsigned int devfn,
- int offset, int size, u32 * val)
+ int offset, int size, u32 *val)
{
uint32_t dword;
diff --git a/arch/mips/pmc-sierra/Platform b/arch/mips/pmc-sierra/Platform
new file mode 100644
index 000000000000..f092f2524c5f
--- /dev/null
+++ b/arch/mips/pmc-sierra/Platform
@@ -0,0 +1,14 @@
+#
+# PMC-Sierra MSP SOCs
+#
+platform-$(CONFIG_PMC_MSP) += pmc-sierra/msp71xx/
+cflags-$(CONFIG_PMC_MSP) += -I$(srctree)/arch/mips/include/asm/pmc-sierra/msp71xx \
+ -mno-branch-likely
+load-$(CONFIG_PMC_MSP) += 0xffffffff80100000
+
+#
+# PMC-Sierra Yosemite
+#
+platform-$(CONFIG_PMC_YOSEMITE) += pmc-sierra/yosemite/
+cflags-$(CONFIG_PMC_YOSEMITE) += -I$(srctree)/arch/mips/include/asm/mach-yosemite
+load-$(CONFIG_PMC_YOSEMITE) += 0xffffffff80100000
diff --git a/arch/mips/pmc-sierra/yosemite/ht-irq.c b/arch/mips/pmc-sierra/yosemite/ht-irq.c
index 5aec4057314e..86b98e98fb4f 100644
--- a/arch/mips/pmc-sierra/yosemite/ht-irq.c
+++ b/arch/mips/pmc-sierra/yosemite/ht-irq.c
@@ -35,18 +35,17 @@
*/
void __init titan_ht_pcibios_fixup_bus(struct pci_bus *bus)
{
- struct pci_bus *current_bus = bus;
- struct pci_dev *devices;
- struct list_head *devices_link;
+ struct pci_bus *current_bus = bus;
+ struct pci_dev *devices;
+ struct list_head *devices_link;
list_for_each(devices_link, &(current_bus->devices)) {
- devices = pci_dev_b(devices_link);
- if (devices == NULL)
- continue;
+ devices = pci_dev_b(devices_link);
+ if (devices == NULL)
+ continue;
}
/*
* PLX and SPKT related changes go here
*/
-
}
diff --git a/arch/mips/pnx833x/Makefile b/arch/mips/pnx833x/Makefile
new file mode 100644
index 000000000000..02c4698cab05
--- /dev/null
+++ b/arch/mips/pnx833x/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SOC_PNX833X) += common/
+obj-$(CONFIG_NXP_STB220) += stb22x/
+obj-$(CONFIG_NXP_STB225) += stb22x/
diff --git a/arch/mips/pnx833x/Platform b/arch/mips/pnx833x/Platform
new file mode 100644
index 000000000000..7e6ec4dbc8dd
--- /dev/null
+++ b/arch/mips/pnx833x/Platform
@@ -0,0 +1,5 @@
+# NXP STB225
+platform-$(CONFIG_SOC_PNX833X) += pnx833x/
+cflags-$(CONFIG_SOC_PNX833X) += -Iarch/mips/include/asm/mach-pnx833x
+load-$(CONFIG_NXP_STB220) += 0xffffffff80001000
+load-$(CONFIG_NXP_STB225) += 0xffffffff80001000
diff --git a/arch/mips/nxp/pnx833x/common/Makefile b/arch/mips/pnx833x/common/Makefile
index 4a16f3b503b5..1a46dd291b16 100644
--- a/arch/mips/nxp/pnx833x/common/Makefile
+++ b/arch/mips/pnx833x/common/Makefile
@@ -1,3 +1 @@
obj-y := interrupts.o platform.o prom.o setup.o reset.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx833x/common/interrupts.c b/arch/mips/pnx833x/common/interrupts.c
index 941916f8aaff..941916f8aaff 100644
--- a/arch/mips/nxp/pnx833x/common/interrupts.c
+++ b/arch/mips/pnx833x/common/interrupts.c
diff --git a/arch/mips/nxp/pnx833x/common/platform.c b/arch/mips/pnx833x/common/platform.c
index 01f8345a2069..01f8345a2069 100644
--- a/arch/mips/nxp/pnx833x/common/platform.c
+++ b/arch/mips/pnx833x/common/platform.c
diff --git a/arch/mips/nxp/pnx833x/common/prom.c b/arch/mips/pnx833x/common/prom.c
index 29969f90a6b0..29969f90a6b0 100644
--- a/arch/mips/nxp/pnx833x/common/prom.c
+++ b/arch/mips/pnx833x/common/prom.c
diff --git a/arch/mips/nxp/pnx833x/common/reset.c b/arch/mips/pnx833x/common/reset.c
index e0ea96d29fde..e0ea96d29fde 100644
--- a/arch/mips/nxp/pnx833x/common/reset.c
+++ b/arch/mips/pnx833x/common/reset.c
diff --git a/arch/mips/nxp/pnx833x/common/setup.c b/arch/mips/pnx833x/common/setup.c
index e51fbc4b644d..e51fbc4b644d 100644
--- a/arch/mips/nxp/pnx833x/common/setup.c
+++ b/arch/mips/pnx833x/common/setup.c
diff --git a/arch/mips/pnx833x/stb22x/Makefile b/arch/mips/pnx833x/stb22x/Makefile
new file mode 100644
index 000000000000..7b580060de50
--- /dev/null
+++ b/arch/mips/pnx833x/stb22x/Makefile
@@ -0,0 +1 @@
+obj-y := board.o
diff --git a/arch/mips/nxp/pnx833x/stb22x/board.c b/arch/mips/pnx833x/stb22x/board.c
index 644eb7c3210f..644eb7c3210f 100644
--- a/arch/mips/nxp/pnx833x/stb22x/board.c
+++ b/arch/mips/pnx833x/stb22x/board.c
diff --git a/arch/mips/pnx8550/Makefile b/arch/mips/pnx8550/Makefile
new file mode 100644
index 000000000000..3f7e8561437b
--- /dev/null
+++ b/arch/mips/pnx8550/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_SOC_PNX8550) += common/
+obj-$(CONFIG_PNX8550_JBS) += jbs/
+obj-$(CONFIG_PNX8550_STB810) += stb810/
diff --git a/arch/mips/pnx8550/Platform b/arch/mips/pnx8550/Platform
new file mode 100644
index 000000000000..0e7fbde768d5
--- /dev/null
+++ b/arch/mips/pnx8550/Platform
@@ -0,0 +1,7 @@
+platform-$(CONFIG_SOC_PNX8550) += pnx8550/
+
+cflags-$(CONFIG_SOC_PNX8550) += \
+ -I$(srctree)/arch/mips/include/asm/mach-pnx8550
+
+load-$(CONFIG_PNX8550_JBS) += 0xffffffff80060000
+load-$(CONFIG_PNX8550_STB810) += 0xffffffff80060000
diff --git a/arch/mips/nxp/pnx8550/common/Makefile b/arch/mips/pnx8550/common/Makefile
index dd9e7b1f7fd3..f8ce695dc54f 100644
--- a/arch/mips/nxp/pnx8550/common/Makefile
+++ b/arch/mips/pnx8550/common/Makefile
@@ -24,5 +24,3 @@
obj-y := setup.o prom.o int.o reset.o time.o proc.o platform.o
obj-$(CONFIG_PCI) += pci.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/nxp/pnx8550/common/int.c b/arch/mips/pnx8550/common/int.c
index cfed5051dc6d..cfed5051dc6d 100644
--- a/arch/mips/nxp/pnx8550/common/int.c
+++ b/arch/mips/pnx8550/common/int.c
diff --git a/arch/mips/nxp/pnx8550/common/pci.c b/arch/mips/pnx8550/common/pci.c
index eee4f3dfc410..eee4f3dfc410 100644
--- a/arch/mips/nxp/pnx8550/common/pci.c
+++ b/arch/mips/pnx8550/common/pci.c
diff --git a/arch/mips/nxp/pnx8550/common/platform.c b/arch/mips/pnx8550/common/platform.c
index 5264cc09a27b..5264cc09a27b 100644
--- a/arch/mips/nxp/pnx8550/common/platform.c
+++ b/arch/mips/pnx8550/common/platform.c
diff --git a/arch/mips/nxp/pnx8550/common/proc.c b/arch/mips/pnx8550/common/proc.c
index 3bba5ec828e8..3bba5ec828e8 100644
--- a/arch/mips/nxp/pnx8550/common/proc.c
+++ b/arch/mips/pnx8550/common/proc.c
diff --git a/arch/mips/nxp/pnx8550/common/prom.c b/arch/mips/pnx8550/common/prom.c
index 32f70097c3c7..32f70097c3c7 100644
--- a/arch/mips/nxp/pnx8550/common/prom.c
+++ b/arch/mips/pnx8550/common/prom.c
diff --git a/arch/mips/nxp/pnx8550/common/reset.c b/arch/mips/pnx8550/common/reset.c
index fadd8744a6bc..fadd8744a6bc 100644
--- a/arch/mips/nxp/pnx8550/common/reset.c
+++ b/arch/mips/pnx8550/common/reset.c
diff --git a/arch/mips/nxp/pnx8550/common/setup.c b/arch/mips/pnx8550/common/setup.c
index 2aed50fef10f..2aed50fef10f 100644
--- a/arch/mips/nxp/pnx8550/common/setup.c
+++ b/arch/mips/pnx8550/common/setup.c
diff --git a/arch/mips/nxp/pnx8550/common/time.c b/arch/mips/pnx8550/common/time.c
index 8836c6203df0..8836c6203df0 100644
--- a/arch/mips/nxp/pnx8550/common/time.c
+++ b/arch/mips/pnx8550/common/time.c
diff --git a/arch/mips/pnx8550/jbs/Makefile b/arch/mips/pnx8550/jbs/Makefile
new file mode 100644
index 000000000000..c4dc3d53eb5c
--- /dev/null
+++ b/arch/mips/pnx8550/jbs/Makefile
@@ -0,0 +1,4 @@
+
+# Makefile for the NXP JBS Board.
+
+obj-y := init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/jbs/board_setup.c b/arch/mips/pnx8550/jbs/board_setup.c
index 57dd903ca408..57dd903ca408 100644
--- a/arch/mips/nxp/pnx8550/jbs/board_setup.c
+++ b/arch/mips/pnx8550/jbs/board_setup.c
diff --git a/arch/mips/nxp/pnx8550/jbs/init.c b/arch/mips/pnx8550/jbs/init.c
index d59b4a4e5e8b..d59b4a4e5e8b 100644
--- a/arch/mips/nxp/pnx8550/jbs/init.c
+++ b/arch/mips/pnx8550/jbs/init.c
diff --git a/arch/mips/nxp/pnx8550/jbs/irqmap.c b/arch/mips/pnx8550/jbs/irqmap.c
index 7fc89842002c..7fc89842002c 100644
--- a/arch/mips/nxp/pnx8550/jbs/irqmap.c
+++ b/arch/mips/pnx8550/jbs/irqmap.c
diff --git a/arch/mips/pnx8550/stb810/Makefile b/arch/mips/pnx8550/stb810/Makefile
new file mode 100644
index 000000000000..cb4ff022f1fb
--- /dev/null
+++ b/arch/mips/pnx8550/stb810/Makefile
@@ -0,0 +1,4 @@
+
+# Makefile for the NXP STB810 Board.
+
+obj-y := prom_init.o board_setup.o irqmap.o
diff --git a/arch/mips/nxp/pnx8550/stb810/board_setup.c b/arch/mips/pnx8550/stb810/board_setup.c
index af2a55e0b4e9..af2a55e0b4e9 100644
--- a/arch/mips/nxp/pnx8550/stb810/board_setup.c
+++ b/arch/mips/pnx8550/stb810/board_setup.c
diff --git a/arch/mips/nxp/pnx8550/stb810/irqmap.c b/arch/mips/pnx8550/stb810/irqmap.c
index 8c034963ddcd..8c034963ddcd 100644
--- a/arch/mips/nxp/pnx8550/stb810/irqmap.c
+++ b/arch/mips/pnx8550/stb810/irqmap.c
diff --git a/arch/mips/nxp/pnx8550/stb810/prom_init.c b/arch/mips/pnx8550/stb810/prom_init.c
index ca7f4ada0640..ca7f4ada0640 100644
--- a/arch/mips/nxp/pnx8550/stb810/prom_init.c
+++ b/arch/mips/pnx8550/stb810/prom_init.c
diff --git a/arch/mips/powertv/Makefile b/arch/mips/powertv/Makefile
index 0a0d73c0564f..506c4ca9d44a 100644
--- a/arch/mips/powertv/Makefile
+++ b/arch/mips/powertv/Makefile
@@ -23,6 +23,7 @@
# under Linux.
#
-obj-y += init.o memory.o reset.o time.o powertv_setup.o asic/ pci/
+obj-y += init.o ioremap.o memory.o powertv_setup.o reset.o time.o \
+ asic/ pci/
-EXTRA_CFLAGS += -Wall -Werror
+EXTRA_CFLAGS += -Wall
diff --git a/arch/mips/powertv/Platform b/arch/mips/powertv/Platform
new file mode 100644
index 000000000000..4eb5af1d8eea
--- /dev/null
+++ b/arch/mips/powertv/Platform
@@ -0,0 +1,7 @@
+#
+# Cisco PowerTV Platform
+#
+platform-$(CONFIG_POWERTV) += powertv/
+cflags-$(CONFIG_POWERTV) += \
+ -I$(srctree)/arch/mips/include/asm/mach-powertv
+load-$(CONFIG_POWERTV) += 0xffffffff90800000
diff --git a/arch/mips/powertv/asic/asic-calliope.c b/arch/mips/powertv/asic/asic-calliope.c
index 1ae6623444b2..0a170e0ffeaa 100644
--- a/arch/mips/powertv/asic/asic-calliope.c
+++ b/arch/mips/powertv/asic/asic-calliope.c
@@ -77,7 +77,7 @@ const struct register_map calliope_register_map __initdata = {
.int_docsis_en = {.phys = CALLIOPE_ADDR(0xA028F4)},
.mips_pll_setup = {.phys = CALLIOPE_ADDR(0x980000)},
- .usb_fs = {.phys = CALLIOPE_ADDR(0x980030)},
+ .fs432x4b4_usb_ctl = {.phys = CALLIOPE_ADDR(0x980030)},
.test_bus = {.phys = CALLIOPE_ADDR(0x9800CC)},
.crt_spare = {.phys = CALLIOPE_ADDR(0x9800d4)},
.usb2_ohci_int_mask = {.phys = CALLIOPE_ADDR(0x9A000c)},
diff --git a/arch/mips/powertv/asic/asic-cronus.c b/arch/mips/powertv/asic/asic-cronus.c
index 5bb64bfb508b..bbc0c122be5e 100644
--- a/arch/mips/powertv/asic/asic-cronus.c
+++ b/arch/mips/powertv/asic/asic-cronus.c
@@ -77,13 +77,13 @@ const struct register_map cronus_register_map __initdata = {
.int_docsis_en = {.phys = CRONUS_ADDR(0x2A28F4)},
.mips_pll_setup = {.phys = CRONUS_ADDR(0x1C0000)},
- .usb_fs = {.phys = CRONUS_ADDR(0x1C0018)},
+ .fs432x4b4_usb_ctl = {.phys = CRONUS_ADDR(0x1C0028)},
.test_bus = {.phys = CRONUS_ADDR(0x1C00CC)},
.crt_spare = {.phys = CRONUS_ADDR(0x1c00d4)},
.usb2_ohci_int_mask = {.phys = CRONUS_ADDR(0x20000C)},
.usb2_strap = {.phys = CRONUS_ADDR(0x200014)},
.ehci_hcapbase = {.phys = CRONUS_ADDR(0x21FE00)},
- .ohci_hc_revision = {.phys = CRONUS_ADDR(0x1E0000)},
+ .ohci_hc_revision = {.phys = CRONUS_ADDR(0x21fc00)},
.bcm1_bs_lmi_steer = {.phys = CRONUS_ADDR(0x2E0008)},
.usb2_control = {.phys = CRONUS_ADDR(0x2E004C)},
.usb2_stbus_obc = {.phys = CRONUS_ADDR(0x21FF00)},
diff --git a/arch/mips/powertv/asic/asic-zeus.c b/arch/mips/powertv/asic/asic-zeus.c
index 095cbe10ebb9..4a05bb096476 100644
--- a/arch/mips/powertv/asic/asic-zeus.c
+++ b/arch/mips/powertv/asic/asic-zeus.c
@@ -77,7 +77,7 @@ const struct register_map zeus_register_map __initdata = {
.int_docsis_en = {.phys = ZEUS_ADDR(0x2828F4)},
.mips_pll_setup = {.phys = ZEUS_ADDR(0x1a0000)},
- .usb_fs = {.phys = ZEUS_ADDR(0x1a0018)},
+ .fs432x4b4_usb_ctl = {.phys = ZEUS_ADDR(0x1a0018)},
.test_bus = {.phys = ZEUS_ADDR(0x1a0238)},
.crt_spare = {.phys = ZEUS_ADDR(0x1a0090)},
.usb2_ohci_int_mask = {.phys = ZEUS_ADDR(0x1e000c)},
diff --git a/arch/mips/powertv/asic/asic_devices.c b/arch/mips/powertv/asic/asic_devices.c
index 8ee77887306a..2276c18eb73b 100644
--- a/arch/mips/powertv/asic/asic_devices.c
+++ b/arch/mips/powertv/asic/asic_devices.c
@@ -80,8 +80,8 @@ static bool usb_configured;
* Don't recommend to use it directly, it is usually used by kernel internally.
* Portable code should be using interfaces such as ioremp, dma_map_single, etc.
*/
-unsigned long phys_to_bus_offset;
-EXPORT_SYMBOL(phys_to_bus_offset);
+unsigned long phys_to_dma_offset;
+EXPORT_SYMBOL(phys_to_dma_offset);
/*
*
@@ -180,9 +180,9 @@ static void __init fs_update(int pe, int md, int sdiv, int disable_div_by_3)
val = ((sdiv << 29) | (md << 24) | (pe<<8) | (sout<<3) | (byp<<2) |
(nsb<<1) | (disable_div_by_3<<5));
- asic_write(val, usb_fs);
- asic_write(val | (en_prg<<4), usb_fs);
- asic_write(val | (en_prg<<4) | pwr, usb_fs);
+ asic_write(val, fs432x4b4_usb_ctl);
+ asic_write(val | (en_prg<<4), fs432x4b4_usb_ctl);
+ asic_write(val | (en_prg<<4) | pwr, fs432x4b4_usb_ctl);
}
/*
@@ -532,10 +532,10 @@ void __init configure_platform(void)
switch (asic) {
case ASIC_ZEUS:
- phys_to_bus_offset = 0x30000000;
+ phys_to_dma_offset = 0x30000000;
break;
case ASIC_CALLIOPE:
- phys_to_bus_offset = 0x10000000;
+ phys_to_dma_offset = 0x10000000;
break;
case ASIC_CRONUSLITE:
/* Fall through */
@@ -545,10 +545,10 @@ void __init configure_platform(void)
* 0x2XXXXXXX. If 0x10000000 aliases into 0x60000000-
* 0x6XXXXXXX, the offset should be 0x50000000, not 0x10000000.
*/
- phys_to_bus_offset = 0x10000000;
+ phys_to_dma_offset = 0x10000000;
break;
default:
- phys_to_bus_offset = 0x00000000;
+ phys_to_dma_offset = 0x00000000;
break;
}
}
@@ -602,7 +602,7 @@ void __init platform_alloc_bootmem(void)
int size = gp_resources[i].end - gp_resources[i].start + 1;
if ((gp_resources[i].start != 0) &&
((gp_resources[i].flags & IORESOURCE_MEM) != 0)) {
- reserve_bootmem(bus_to_phys(gp_resources[i].start),
+ reserve_bootmem(dma_to_phys(gp_resources[i].start),
size, 0);
total += gp_resources[i].end -
gp_resources[i].start + 1;
@@ -626,7 +626,7 @@ void __init platform_alloc_bootmem(void)
else {
gp_resources[i].start =
- phys_to_bus(virt_to_phys(mem));
+ phys_to_dma(virt_to_phys(mem));
gp_resources[i].end =
gp_resources[i].start + size - 1;
total += size;
@@ -690,7 +690,7 @@ static void __init pmem_setup_resource(void)
if (resource && pmemaddr && pmemlen) {
/* The address provided by bootloader is in kseg0. Convert to
* a bus address. */
- resource->start = phys_to_bus(pmemaddr - 0x80000000);
+ resource->start = phys_to_dma(pmemaddr - 0x80000000);
resource->end = resource->start + pmemlen - 1;
pr_info("persistent memory: start=0x%x end=0x%x\n",
diff --git a/arch/mips/powertv/ioremap.c b/arch/mips/powertv/ioremap.c
new file mode 100644
index 000000000000..a77c6f62fe23
--- /dev/null
+++ b/arch/mips/powertv/ioremap.c
@@ -0,0 +1,136 @@
+/*
+ * ioremap.c
+ *
+ * Support for mapping between dma_addr_t values a phys_addr_t values.
+ *
+ * Copyright (C) 2005-2009 Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: David VomLehn <dvomlehn@cisco.com>
+ *
+ * Description: Defines the platform resources for the SA settop.
+ *
+ * NOTE: The bootloader allocates persistent memory at an address which is
+ * 16 MiB below the end of the highest address in KSEG0. All fixed
+ * address memory reservations must avoid this region.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <asm/mach-powertv/ioremap.h>
+
+/*
+ * Define the sizes of and masks for grains in physical and DMA space. The
+ * values are the same but the types are not.
+ */
+#define IOR_PHYS_GRAIN ((phys_addr_t) 1 << IOR_LSBITS)
+#define IOR_PHYS_GRAIN_MASK (IOR_PHYS_GRAIN - 1)
+
+#define IOR_DMA_GRAIN ((dma_addr_t) 1 << IOR_LSBITS)
+#define IOR_DMA_GRAIN_MASK (IOR_DMA_GRAIN - 1)
+
+/*
+ * Values that, when accessed by an index derived from a phys_addr_t and
+ * added to phys_addr_t value, yield a DMA address
+ */
+struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA];
+EXPORT_SYMBOL(_ior_phys_to_dma);
+
+/*
+ * Values that, when accessed by an index derived from a dma_addr_t and
+ * added to that dma_addr_t value, yield a physical address
+ */
+struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS];
+EXPORT_SYMBOL(_ior_dma_to_phys);
+
+/**
+ * setup_dma_to_phys - set up conversion from DMA to physical addresses
+ * @dma_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index
+ * into the array _dma_to_phys.
+ * @delta: Value that, when added to the DMA address, will yield the
+ * physical address
+ * @s: Number of bytes in the section of memory with the given delta
+ * between DMA and physical addresses.
+ */
+static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s)
+{
+ int dma_idx, first_idx, last_idx;
+ phys_addr_t first, last;
+
+ /*
+ * Calculate the first and last indices, rounding the first up and
+ * the second down.
+ */
+ first = dma & ~IOR_DMA_GRAIN_MASK;
+ last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK;
+ first_idx = first >> IOR_LSBITS; /* Convert to indices */
+ last_idx = last >> IOR_LSBITS;
+
+ for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++)
+ _ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT;
+}
+
+/**
+ * setup_phys_to_dma - set up conversion from DMA to physical addresses
+ * @phys_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index
+ * into the array _phys_to_dma.
+ * @delta: Value that, when added to the DMA address, will yield the
+ * physical address
+ * @s: Number of bytes in the section of memory with the given delta
+ * between DMA and physical addresses.
+ */
+static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s)
+{
+ int phys_idx, first_idx, last_idx;
+ phys_addr_t first, last;
+
+ /*
+ * Calculate the first and last indices, rounding the first up and
+ * the second down.
+ */
+ first = phys & ~IOR_PHYS_GRAIN_MASK;
+ last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK;
+ first_idx = first >> IOR_LSBITS; /* Convert to indices */
+ last_idx = last >> IOR_LSBITS;
+
+ for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++)
+ _ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT;
+}
+
+/**
+ * ioremap_add_map - add to the physical and DMA address conversion arrays
+ * @phys: Process's view of the address of the start of the memory chunk
+ * @dma: DMA address of the start of the memory chunk
+ * @size: Size, in bytes, of the chunk of memory
+ *
+ * NOTE: It might be obvious, but the assumption is that all @size bytes have
+ * the same offset between the physical address and the DMA address.
+ */
+void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size)
+{
+ if (size == 0)
+ return;
+
+ if ((dma & IOR_DMA_GRAIN_MASK) != 0 ||
+ (phys & IOR_PHYS_GRAIN_MASK) != 0 ||
+ (size & IOR_PHYS_GRAIN_MASK) != 0)
+ pr_crit("Memory allocation must be in chunks of 0x%x bytes\n",
+ IOR_PHYS_GRAIN);
+
+ setup_dma_to_phys(dma, phys - dma, size);
+ setup_phys_to_dma(phys, dma - phys, size);
+}
diff --git a/arch/mips/powertv/memory.c b/arch/mips/powertv/memory.c
index f49eb3d0358b..c463cd39c713 100644
--- a/arch/mips/powertv/memory.c
+++ b/arch/mips/powertv/memory.c
@@ -30,28 +30,140 @@
#include <asm/sections.h>
#include <asm/mips-boards/prom.h>
+#include <asm/mach-powertv/asic.h>
+#include <asm/mach-powertv/ioremap.h>
#include "init.h"
/* Memory constants */
#define KIBIBYTE(n) ((n) * 1024) /* Number of kibibytes */
#define MEBIBYTE(n) ((n) * KIBIBYTE(1024)) /* Number of mebibytes */
-#define DEFAULT_MEMSIZE MEBIBYTE(256) /* If no memsize provided */
-#define LOW_MEM_MAX MEBIBYTE(252) /* Max usable low mem */
-#define RES_BOOTLDR_MEMSIZE MEBIBYTE(1) /* Memory reserved for bldr */
-#define BOOT_MEM_SIZE KIBIBYTE(256) /* Memory reserved for bldr */
-#define PHYS_MEM_START 0x10000000 /* Start of physical memory */
+#define DEFAULT_MEMSIZE MEBIBYTE(128) /* If no memsize provided */
-char __initdata cmdline[COMMAND_LINE_SIZE];
+#define BLDR_SIZE KIBIBYTE(256) /* Memory reserved for bldr */
+#define RV_SIZE MEBIBYTE(4) /* Size of reset vector */
-void __init prom_meminit(void)
+#define LOW_MEM_END 0x20000000 /* Highest low memory address */
+#define BLDR_ALIAS 0x10000000 /* Bootloader address */
+#define RV_PHYS 0x1fc00000 /* Reset vector address */
+#define LOW_RAM_END RV_PHYS /* End of real RAM in low mem */
+
+/*
+ * Very low-level conversion from processor physical address to device
+ * DMA address for the first bank of memory.
+ */
+#define PHYS_TO_DMA(paddr) ((paddr) + (CONFIG_LOW_RAM_DMA - LOW_RAM_ALIAS))
+
+unsigned long ptv_memsize;
+
+/*
+ * struct low_mem_reserved - Items in low memmory that are reserved
+ * @start: Physical address of item
+ * @size: Size, in bytes, of this item
+ * @is_aliased: True if this is RAM aliased from another location. If false,
+ * it is something other than aliased RAM and the RAM in the
+ * unaliased address is still visible outside of low memory.
+ */
+struct low_mem_reserved {
+ phys_addr_t start;
+ phys_addr_t size;
+ bool is_aliased;
+};
+
+/*
+ * Must be in ascending address order
+ */
+struct low_mem_reserved low_mem_reserved[] = {
+ {BLDR_ALIAS, BLDR_SIZE, true}, /* Bootloader RAM */
+ {RV_PHYS, RV_SIZE, false}, /* Reset vector */
+};
+
+/*
+ * struct mem_layout - layout of a piece of the system RAM
+ * @phys: Physical address of the start of this piece of RAM. This is the
+ * address at which both the processor and I/O devices see the
+ * RAM.
+ * @alias: Alias of this piece of memory in order to make it appear in
+ * the low memory part of the processor's address space. I/O
+ * devices don't see anything here.
+ * @size: Size, in bytes, of this piece of RAM
+ */
+struct mem_layout {
+ phys_addr_t phys;
+ phys_addr_t alias;
+ phys_addr_t size;
+};
+
+/*
+ * struct mem_layout_list - list descriptor for layouts of system RAM pieces
+ * @family: Specifies the family being described
+ * @n: Number of &struct mem_layout elements
+ * @layout: Pointer to the list of &mem_layout structures
+ */
+struct mem_layout_list {
+ enum family_type family;
+ size_t n;
+ struct mem_layout *layout;
+};
+
+static struct mem_layout f1500_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(256)},
+};
+
+static struct mem_layout f4500_layout[] = {
+ {0x40000000, 0x10000000, MEBIBYTE(256)},
+ {0x20000000, 0x20000000, MEBIBYTE(32)},
+};
+
+static struct mem_layout f8500_layout[] = {
+ {0x40000000, 0x10000000, MEBIBYTE(256)},
+ {0x20000000, 0x20000000, MEBIBYTE(32)},
+ {0x30000000, 0x30000000, MEBIBYTE(32)},
+};
+
+static struct mem_layout fx600_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(256)},
+ {0x60000000, 0x60000000, MEBIBYTE(128)},
+};
+
+static struct mem_layout_list layout_list[] = {
+ {FAMILY_1500, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_1500VZE, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_1500VZF, ARRAY_SIZE(f1500_layout), f1500_layout},
+ {FAMILY_4500, ARRAY_SIZE(f4500_layout), f4500_layout},
+ {FAMILY_8500, ARRAY_SIZE(f8500_layout), f8500_layout},
+ {FAMILY_8500RNG, ARRAY_SIZE(f8500_layout), f8500_layout},
+ {FAMILY_4600, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_4600VZA, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_8600, ARRAY_SIZE(fx600_layout), fx600_layout},
+ {FAMILY_8600VZB, ARRAY_SIZE(fx600_layout), fx600_layout},
+};
+
+/* If we can't determine the layout, use this */
+static struct mem_layout default_layout[] = {
+ {0x20000000, 0x10000000, MEBIBYTE(128)},
+};
+
+/**
+ * register_non_ram - register low memory not available for RAM usage
+ */
+static __init void register_non_ram(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(low_mem_reserved); i++)
+ add_memory_region(low_mem_reserved[i].start,
+ low_mem_reserved[i].size, BOOT_MEM_RESERVED);
+}
+
+/**
+ * get_memsize - get the size of memory as a single bank
+ */
+static phys_addr_t get_memsize(void)
{
+ phys_addr_t memsize = 0;
char *memsize_str;
- unsigned long memsize = 0;
- unsigned int physend;
- char *ptr;
- int low_mem;
- int high_mem;
+ char cmdline[COMMAND_LINE_SIZE], *ptr;
/* Check the command line first for a memsize directive */
strcpy(cmdline, arcs_cmdline);
@@ -73,96 +185,156 @@ void __init prom_meminit(void)
if (memsize == 0) {
if (_prom_memsize != 0) {
memsize = _prom_memsize;
- pr_info("_prom_memsize = 0x%lx\n", memsize);
+ pr_info("_prom_memsize = 0x%x\n", memsize);
/* add in memory that the bootloader doesn't
* report */
- memsize += BOOT_MEM_SIZE;
+ memsize += BLDR_SIZE;
} else {
memsize = DEFAULT_MEMSIZE;
pr_info("Memsize not passed by bootloader, "
- "defaulting to 0x%lx\n", memsize);
+ "defaulting to 0x%x\n", memsize);
}
}
}
- physend = PFN_ALIGN(&_end) - 0x80000000;
- if (memsize > LOW_MEM_MAX) {
- low_mem = LOW_MEM_MAX;
- high_mem = memsize - low_mem;
- } else {
- low_mem = memsize;
- high_mem = 0;
+ return memsize;
+}
+
+/**
+ * register_low_ram - register an aliased section of RAM
+ * @p: Alias address of memory
+ * @n: Number of bytes in this section of memory
+ *
+ * Returns the number of bytes registered
+ *
+ */
+static __init phys_addr_t register_low_ram(phys_addr_t p, phys_addr_t n)
+{
+ phys_addr_t s;
+ int i;
+ phys_addr_t orig_n;
+
+ orig_n = n;
+
+ BUG_ON(p + n > RV_PHYS);
+
+ for (i = 0; n != 0 && i < ARRAY_SIZE(low_mem_reserved); i++) {
+ phys_addr_t start;
+ phys_addr_t size;
+
+ start = low_mem_reserved[i].start;
+ size = low_mem_reserved[i].size;
+
+ /* Handle memory before this low memory section */
+ if (p < start) {
+ phys_addr_t s;
+ s = min(n, start - p);
+ add_memory_region(p, s, BOOT_MEM_RAM);
+ p += s;
+ n -= s;
+ }
+
+ /* Handle the low memory section itself. If it's aliased,
+ * we reduce the number of byes left, but if not, the RAM
+ * is available elsewhere and we don't reduce the number of
+ * bytes remaining. */
+ if (p == start) {
+ if (low_mem_reserved[i].is_aliased) {
+ s = min(n, size);
+ n -= s;
+ p += s;
+ } else
+ p += n;
+ }
}
+ return orig_n - n;
+}
+
/*
- * TODO: We will use the hard code for memory configuration until
- * the bootloader releases their device tree to us.
+ * register_ram - register real RAM
+ * @p: Address of memory as seen by devices
+ * @alias: If the memory is seen at an additional address by the processor,
+ * this will be the address, otherwise it is the same as @p.
+ * @n: Number of bytes in this section of memory
*/
+static __init void register_ram(phys_addr_t p, phys_addr_t alias,
+ phys_addr_t n)
+{
/*
- * Add the memory reserved for use by the bootloader to the
- * memory map.
- */
- add_memory_region(PHYS_MEM_START, RES_BOOTLDR_MEMSIZE,
- BOOT_MEM_RESERVED);
-#ifdef CONFIG_HIGHMEM_256_128
- /*
- * Add memory in low for general use by the kernel and its friends
- * (like drivers, applications, etc).
- */
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- LOW_MEM_MAX - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
- /*
- * Add the memory reserved for reset vector.
- */
- add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED);
- /*
- * Add the memory reserved.
- */
- add_memory_region(0x20000000, MEBIBYTE(1024 + 75), BOOT_MEM_RESERVED);
- /*
- * Add memory in high for general use by the kernel and its friends
- * (like drivers, applications, etc).
- *
- * 75MB is reserved for devices which are using the memory in high.
- */
- add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75),
- BOOT_MEM_RAM);
-#elif defined CONFIG_HIGHMEM_128_128
- /*
- * Add memory in low for general use by the kernel and its friends
- * (like drivers, applications, etc).
- */
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- MEBIBYTE(128) - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
- /*
- * Add the memory reserved.
- */
- add_memory_region(PHYS_MEM_START + MEBIBYTE(128),
- MEBIBYTE(128 + 1024 + 75), BOOT_MEM_RESERVED);
- /*
- * Add memory in high for general use by the kernel and its friends
- * (like drivers, applications, etc).
- *
- * 75MB is reserved for devices which are using the memory in high.
- */
- add_memory_region(0x60000000 + MEBIBYTE(75), MEBIBYTE(128 - 75),
- BOOT_MEM_RAM);
-#else
- /* Add low memory regions for either:
- * - no-highmemory configuration case -OR-
- * - highmemory "HIGHMEM_LOWBANK_ONLY" case
- */
- /*
- * Add memory for general use by the kernel and its friends
- * (like drivers, applications, etc).
+ * If some or all of this memory has an alias, break it into the
+ * aliased and non-aliased portion.
*/
- add_memory_region(PHYS_MEM_START + RES_BOOTLDR_MEMSIZE,
- low_mem - RES_BOOTLDR_MEMSIZE, BOOT_MEM_RAM);
+ if (p != alias) {
+ phys_addr_t alias_size;
+ phys_addr_t registered;
+
+ alias_size = min(n, LOW_RAM_END - alias);
+ registered = register_low_ram(alias, alias_size);
+ ioremap_add_map(alias, p, n);
+ n -= registered;
+ p += registered;
+ }
+
+#ifdef CONFIG_HIGHMEM
+ if (n != 0) {
+ add_memory_region(p, n, BOOT_MEM_RAM);
+ ioremap_add_map(p, p, n);
+ }
+#endif
+}
+
+/**
+ * register_address_space - register things in the address space
+ * @memsize: Number of bytes of RAM installed
+ *
+ * Takes the given number of bytes of RAM and registers as many of the regions,
+ * or partial regions, as it can. So, the default configuration might have
+ * two regions with 256 MiB each. If the memsize passed in on the command line
+ * is 384 MiB, it will register the first region with 256 MiB and the second
+ * with 128 MiB.
+ */
+static __init void register_address_space(phys_addr_t memsize)
+{
+ int i;
+ phys_addr_t size;
+ size_t n;
+ struct mem_layout *layout;
+ enum family_type family;
+
/*
- * Add the memory reserved for reset vector.
+ * Register all of the things that aren't available to the kernel as
+ * memory.
*/
- add_memory_region(0x1fc00000, MEBIBYTE(4), BOOT_MEM_RESERVED);
-#endif
+ register_non_ram();
+
+ /* Find the appropriate memory description */
+ family = platform_get_family();
+
+ for (i = 0; i < ARRAY_SIZE(layout_list); i++) {
+ if (layout_list[i].family == family)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(layout_list)) {
+ n = ARRAY_SIZE(default_layout);
+ layout = default_layout;
+ } else {
+ n = layout_list[i].n;
+ layout = layout_list[i].layout;
+ }
+
+ for (i = 0; memsize != 0 && i < n; i++) {
+ size = min(memsize, layout[i].size);
+ register_ram(layout[i].phys, layout[i].alias, size);
+ memsize -= size;
+ }
+}
+
+void __init prom_meminit(void)
+{
+ ptv_memsize = get_memsize();
+ register_address_space(ptv_memsize);
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/rb532/Makefile b/arch/mips/rb532/Makefile
index 8f0b6b6a1625..efdecdb6e3ea 100644
--- a/arch/mips/rb532/Makefile
+++ b/arch/mips/rb532/Makefile
@@ -3,5 +3,3 @@
#
obj-y += irq.o time.o setup.o serial.o prom.o gpio.o devices.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/rb532/Platform b/arch/mips/rb532/Platform
new file mode 100644
index 000000000000..aeec45a7cbb3
--- /dev/null
+++ b/arch/mips/rb532/Platform
@@ -0,0 +1,7 @@
+#
+# Routerboard 532
+#
+platform-$(CONFIG_MIKROTIK_RB532) += rb532/
+cflags-$(CONFIG_MIKROTIK_RB532) += \
+ -I$(srctree)/arch/mips/include/asm/mach-rc32434
+load-$(CONFIG_MIKROTIK_RB532) += 0xffffffff80101000
diff --git a/arch/mips/sgi-ip22/Makefile b/arch/mips/sgi-ip22/Makefile
index 416b18f9fa72..cc538493cae1 100644
--- a/arch/mips/sgi-ip22/Makefile
+++ b/arch/mips/sgi-ip22/Makefile
@@ -9,5 +9,3 @@ obj-y += ip22-mc.o ip22-hpc.o ip22-int.o ip22-time.o ip22-nvram.o \
obj-$(CONFIG_SGI_IP22) += ip22-berr.o
obj-$(CONFIG_SGI_IP28) += ip28-berr.o
obj-$(CONFIG_EISA) += ip22-eisa.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip22/Platform b/arch/mips/sgi-ip22/Platform
new file mode 100644
index 000000000000..d29cbe863ffe
--- /dev/null
+++ b/arch/mips/sgi-ip22/Platform
@@ -0,0 +1,34 @@
+#
+# SGI IP22 (Indy/Indigo2)
+#
+# Set the load address to >= 0xffffffff88069000 if you want to leave space for
+# symmon, 0xffffffff80002000 for production kernels. Note that the value must
+# be aligned to a multiple of the kernel stack size or the handling of the
+# current variable will break so for 64-bit kernels we have to raise the start
+# address by 8kb.
+#
+patform-$(CONFIG_SGI_IP22) += sgi-ip22/
+cflags-$(CONFIG_SGI_IP22) += -I$(srctree)/arch/mips/include/asm/mach-ip22
+ifdef CONFIG_32BIT
+load-$(CONFIG_SGI_IP22) += 0xffffffff88002000
+endif
+ifdef CONFIG_64BIT
+load-$(CONFIG_SGI_IP22) += 0xffffffff88004000
+endif
+
+#
+# SGI IP28 (Indigo2 R10k)
+#
+# Set the load address to >= 0xa800000020080000 if you want to leave space for
+# symmon, 0xa800000020004000 for production kernels ? Note that the value must
+# be 16kb aligned or the handling of the current variable will break.
+# Simplified: what IP22 does at 128MB+ in ksegN, IP28 does at 512MB+ in xkphys
+#
+ifdef CONFIG_SGI_IP28
+ ifeq ($(call cc-option-yn,-mr10k-cache-barrier=store), n)
+ $(error gcc doesn't support needed option -mr10k-cache-barrier=store)
+ endif
+endif
+platform-$(CONFIG_SGI_IP28) += sgi-ip22/
+cflags-$(CONFIG_SGI_IP28) += -mr10k-cache-barrier=store -I$(srctree)/arch/mips/include/asm/mach-ip28
+load-$(CONFIG_SGI_IP28) += 0xa800000020004000
diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile
index 31f4931b8484..1f29e761d691 100644
--- a/arch/mips/sgi-ip27/Makefile
+++ b/arch/mips/sgi-ip27/Makefile
@@ -8,5 +8,3 @@ obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o
obj-$(CONFIG_SMP) += ip27-smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip27/Platform b/arch/mips/sgi-ip27/Platform
new file mode 100644
index 000000000000..1fb9c2ea7c8f
--- /dev/null
+++ b/arch/mips/sgi-ip27/Platform
@@ -0,0 +1,19 @@
+#
+# SGI-IP27 (Origin200/2000)
+#
+# Set the load address to >= 0xc000000000300000 if you want to leave space for
+# symmon, 0xc00000000001c000 for production kernels. Note that the value must
+# be 16kb aligned or the handling of the current variable will break.
+#
+ifdef CONFIG_SGI_IP27
+platform-$(CONFIG_SGI_IP27) += sgi-ip27/
+cflags-$(CONFIG_SGI_IP27) += -I$(srctree)/arch/mips/include/asm/mach-ip27
+ifdef CONFIG_MAPPED_KERNEL
+load-$(CONFIG_SGI_IP27) += 0xc00000004001c000
+OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000
+dataoffset-$(CONFIG_SGI_IP27) += 0x01000000
+else
+load-$(CONFIG_SGI_IP27) += 0xa80000000001c000
+OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000
+endif
+endif
diff --git a/arch/mips/sgi-ip27/ip27-klconfig.c b/arch/mips/sgi-ip27/ip27-klconfig.c
index dd830b3670d1..7afe14688003 100644
--- a/arch/mips/sgi-ip27/ip27-klconfig.c
+++ b/arch/mips/sgi-ip27/ip27-klconfig.c
@@ -48,7 +48,7 @@ klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type)
return find_component(brd, (klinfo_t *)NULL, struct_type);
}
-lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
+lboard_t *find_lboard(lboard_t *start, unsigned char brd_type)
{
/* Search all boards stored on this node. */
while (start) {
@@ -60,7 +60,7 @@ lboard_t * find_lboard(lboard_t *start, unsigned char brd_type)
return (lboard_t *)NULL;
}
-lboard_t * find_lboard_class(lboard_t *start, unsigned char brd_type)
+lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_type)
{
/* Search all boards stored on this node. */
while (start) {
@@ -78,7 +78,7 @@ cnodeid_t get_cpu_cnode(cpuid_t cpu)
return CPUID_TO_COMPACT_NODEID(cpu);
}
-klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
+klcpu_t *nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
{
lboard_t *brd;
klcpu_t *acpu;
@@ -97,7 +97,7 @@ klcpu_t * nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
return (klcpu_t *)NULL;
}
-klcpu_t * sn_get_cpuinfo(cpuid_t cpu)
+klcpu_t *sn_get_cpuinfo(cpuid_t cpu)
{
nasid_t nasid;
int slice;
diff --git a/arch/mips/sgi-ip32/Makefile b/arch/mips/sgi-ip32/Makefile
index 31c9aa1bcb40..60f0227425e7 100644
--- a/arch/mips/sgi-ip32/Makefile
+++ b/arch/mips/sgi-ip32/Makefile
@@ -5,5 +5,3 @@
obj-y += ip32-berr.o ip32-irq.o ip32-platform.o ip32-setup.o ip32-reset.o \
crime.o ip32-memory.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sgi-ip32/Platform b/arch/mips/sgi-ip32/Platform
new file mode 100644
index 000000000000..0fea556f3641
--- /dev/null
+++ b/arch/mips/sgi-ip32/Platform
@@ -0,0 +1,11 @@
+#
+# SGI-IP32 (O2)
+#
+# Set the load address to >= 80069000 if you want to leave space for symmon,
+# 0xffffffff80004000 for production kernels. Note that the value must be aligned to
+# a multiple of the kernel stack size or the handling of the current variable
+# will break.
+#
+platform-$(CONFIG_SGI_IP32) += sgi-ip32/
+cflags-$(CONFIG_SGI_IP32) += -I$(srctree)/arch/mips/include/asm/mach-ip32
+load-$(CONFIG_SGI_IP32) += 0xffffffff80004000
diff --git a/arch/mips/sibyte/Makefile b/arch/mips/sibyte/Makefile
new file mode 100644
index 000000000000..d9df7b1f753e
--- /dev/null
+++ b/arch/mips/sibyte/Makefile
@@ -0,0 +1,27 @@
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+core-$(CONFIG_SIBYTE_BCM112X) += sb1250/
+core-$(CONFIG_SIBYTE_BCM112X) += common/
+core-$(CONFIG_SIBYTE_SB1250) += sb1250/
+core-$(CONFIG_SIBYTE_SB1250) += common/
+core-$(CONFIG_SIBYTE_BCM1x55) += bcm1480/
+core-$(CONFIG_SIBYTE_BCM1x55) += common/
+core-$(CONFIG_SIBYTE_BCM1x80) += bcm1480/
+core-$(CONFIG_SIBYTE_BCM1x80) += common/
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte SWARM board
+# Sibyte BCM91x80 (BigSur) board
+#
+core-$(CONFIG_SIBYTE_CARMEL) += swarm/
+core-$(CONFIG_SIBYTE_CRHINE) += swarm/
+core-$(CONFIG_SIBYTE_CRHONE) += swarm/
+core-$(CONFIG_SIBYTE_RHONE) += swarm/
+core-$(CONFIG_SIBYTE_SENTOSA) += swarm/
+core-$(CONFIG_SIBYTE_SWARM) += swarm/
+core-$(CONFIG_SIBYTE_BIGSUR) += swarm/
diff --git a/arch/mips/sibyte/Platform b/arch/mips/sibyte/Platform
new file mode 100644
index 000000000000..911dfe39c631
--- /dev/null
+++ b/arch/mips/sibyte/Platform
@@ -0,0 +1,43 @@
+#
+# These are all rather similar so we consider them a single platform
+#
+platform-$(CONFIG_SIBYTE_BCM112X) += sibyte/
+platform-$(CONFIG_SIBYTE_SB1250) += sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x55) += sibyte/
+platform-$(CONFIG_SIBYTE_BCM1x80) += sibyte/
+
+#
+# Sibyte SB1250 / BCM1480 family of SOCs
+#
+cflags-$(CONFIG_SIBYTE_BCM112X) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+platform-$(CONFIG_SIBYTE_SB1250) += sibyte/
+cflags-$(CONFIG_SIBYTE_SB1250) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1250_112x_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x55) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+cflags-$(CONFIG_SIBYTE_BCM1x80) += \
+ -I$(srctree)/arch/mips/include/asm/mach-sibyte \
+ -DSIBYTE_HDR_FEATURES=SIBYTE_HDR_FMASK_1480_ALL
+
+#
+# Sibyte BCM91120x (Carmel) board
+# Sibyte BCM91120C (CRhine) board
+# Sibyte BCM91125C (CRhone) board
+# Sibyte BCM91125E (Rhone) board
+# Sibyte SWARM board
+# Sibyte BCM91x80 (BigSur) board
+#
+load-$(CONFIG_SIBYTE_CARMEL) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHINE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_CRHONE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_RHONE) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SENTOSA) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_SWARM) := 0xffffffff80100000
+load-$(CONFIG_SIBYTE_BIGSUR) := 0xffffffff80100000
diff --git a/arch/mips/sibyte/bcm1480/Makefile b/arch/mips/sibyte/bcm1480/Makefile
index f292f7df0cfb..cdc4c56c3e29 100644
--- a/arch/mips/sibyte/bcm1480/Makefile
+++ b/arch/mips/sibyte/bcm1480/Makefile
@@ -1,5 +1,3 @@
obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sibyte/common/Makefile b/arch/mips/sibyte/common/Makefile
index 4f659837c7c6..36aa700cc40c 100644
--- a/arch/mips/sibyte/common/Makefile
+++ b/arch/mips/sibyte/common/Makefile
@@ -1,5 +1,3 @@
obj-y := cfe.o
obj-$(CONFIG_SIBYTE_CFE_CONSOLE) += cfe_console.o
obj-$(CONFIG_SIBYTE_TBPROF) += sb_tbprof.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sibyte/sb1250/Makefile b/arch/mips/sibyte/sb1250/Makefile
index 1896f4e77a30..d3d969de407b 100644
--- a/arch/mips/sibyte/sb1250/Makefile
+++ b/arch/mips/sibyte/sb1250/Makefile
@@ -2,5 +2,3 @@ obj-y := setup.o irq.o time.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SIBYTE_BUS_WATCHER) += bus_watcher.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sni/Makefile b/arch/mips/sni/Makefile
index a7dbeebe7fe6..9d3bad3200ce 100644
--- a/arch/mips/sni/Makefile
+++ b/arch/mips/sni/Makefile
@@ -4,5 +4,3 @@
obj-y += irq.o reset.o setup.o a20r.o rm200.o pcimt.o pcit.o time.o
obj-$(CONFIG_EISA) += eisa.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/sni/Platform b/arch/mips/sni/Platform
new file mode 100644
index 000000000000..2644a9d63c0f
--- /dev/null
+++ b/arch/mips/sni/Platform
@@ -0,0 +1,11 @@
+#
+# SNI RM
+#
+platform-$(CONFIG_SNI_RM) += sni/
+cflags-$(CONFIG_SNI_RM) += -I$(srctree)/arch/mips/include/asm/mach-rm
+ifdef CONFIG_CPU_LITTLE_ENDIAN
+load-$(CONFIG_SNI_RM) += 0xffffffff80600000
+else
+load-$(CONFIG_SNI_RM) += 0xffffffff80030000
+endif
+all-$(CONFIG_SNI_RM) := $(COMPRESSION_FNAME).ecoff
diff --git a/arch/mips/txx9/Makefile b/arch/mips/txx9/Makefile
new file mode 100644
index 000000000000..9beb320689b9
--- /dev/null
+++ b/arch/mips/txx9/Makefile
@@ -0,0 +1,17 @@
+#
+# Common TXx9
+#
+core-$(CONFIG_MACH_TX39XX) += arch/mips/txx9/generic/
+core-$(CONFIG_MACH_TX49XX) += arch/mips/txx9/generic/
+
+#
+# Toshiba JMR-TX3927 board
+#
+lib-$(CONFIG_TOSHIBA_JMR3927) += jmr3927/
+
+#
+# Toshiba RBTX49XX boards
+#
+lib-$(CONFIG_TOSHIBA_RBTX4927) += rbtx4927/
+lib-$(CONFIG_TOSHIBA_RBTX4938) += rbtx4938/
+lib-$(CONFIG_TOSHIBA_RBTX4939) += rbtx4939/
diff --git a/arch/mips/txx9/Platform b/arch/mips/txx9/Platform
new file mode 100644
index 000000000000..a801abbe138b
--- /dev/null
+++ b/arch/mips/txx9/Platform
@@ -0,0 +1,10 @@
+platform-$(CONFIG_MACH_TX39XX) += txx9/
+platform-$(CONFIG_MACH_TX49XX) += txx9/
+
+cflags-$(CONFIG_MACH_TX39XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-tx39xx
+cflags-$(CONFIG_MACH_TX49XX) += \
+ -I$(srctree)/arch/mips/include/asm/mach-tx49xx
+
+load-$(CONFIG_MACH_TX39XX) += 0xffffffff80050000
+load-$(CONFIG_MACH_TX49XX) += 0xffffffff80100000
diff --git a/arch/mips/txx9/generic/Makefile b/arch/mips/txx9/generic/Makefile
index f2579ce054a1..1863c167e66e 100644
--- a/arch/mips/txx9/generic/Makefile
+++ b/arch/mips/txx9/generic/Makefile
@@ -11,5 +11,3 @@ obj-$(CONFIG_SOC_TX4939) += setup_tx4939.o irq_tx4939.o
obj-$(CONFIG_TOSHIBA_FPCIB0) += smsc_fdc37m81x.o
obj-$(CONFIG_SPI) += spi_eeprom.o
obj-$(CONFIG_TXX9_7SEGLED) += 7segled.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/jmr3927/Makefile b/arch/mips/txx9/jmr3927/Makefile
index 20d61ac543e5..9f5d5b623839 100644
--- a/arch/mips/txx9/jmr3927/Makefile
+++ b/arch/mips/txx9/jmr3927/Makefile
@@ -3,5 +3,3 @@
#
obj-y += prom.o irq.o setup.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4927/Makefile b/arch/mips/txx9/rbtx4927/Makefile
index f3e1f597b4f1..60b24c8f7e63 100644
--- a/arch/mips/txx9/rbtx4927/Makefile
+++ b/arch/mips/txx9/rbtx4927/Makefile
@@ -1,3 +1 @@
obj-y += prom.o setup.o irq.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4938/Makefile b/arch/mips/txx9/rbtx4938/Makefile
index f3e1f597b4f1..60b24c8f7e63 100644
--- a/arch/mips/txx9/rbtx4938/Makefile
+++ b/arch/mips/txx9/rbtx4938/Makefile
@@ -1,3 +1 @@
obj-y += prom.o setup.o irq.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/txx9/rbtx4939/Makefile b/arch/mips/txx9/rbtx4939/Makefile
index 3232cd03a7d6..5c84625a3f1c 100644
--- a/arch/mips/txx9/rbtx4939/Makefile
+++ b/arch/mips/txx9/rbtx4939/Makefile
@@ -1,3 +1 @@
obj-y += irq.o setup.o prom.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/vr41xx/Platform b/arch/mips/vr41xx/Platform
new file mode 100644
index 000000000000..b6c8d5c08ddb
--- /dev/null
+++ b/arch/mips/vr41xx/Platform
@@ -0,0 +1,32 @@
+#
+# NEC VR4100 series based machines
+#
+platform-$(CONFIG_MACH_VR41XX) += vr41xx/common/
+cflags-$(CONFIG_MACH_VR41XX) += -I$(srctree)/arch/mips/include/asm/mach-vr41xx
+
+#
+# CASIO CASSIPEIA E-55/65 (VR4111)
+#
+platform-$(CONFIG_CASIO_E55) += vr41xx/casio-e55/
+load-$(CONFIG_CASIO_E55) += 0xffffffff80004000
+
+#
+# IBM WorkPad z50 (VR4121)
+#
+platform-$(CONFIG_IBM_WORKPAD) += vr41xx/ibm-workpad/
+load-$(CONFIG_IBM_WORKPAD) += 0xffffffff80004000
+
+#
+# TANBAC VR4131 multichip module(TB0225) and TANBAC VR4131DIMM(TB0229) (VR4131)
+#
+load-$(CONFIG_TANBAC_TB022X) += 0xffffffff80000000
+
+#
+# Victor MP-C303/304 (VR4122)
+#
+load-$(CONFIG_VICTOR_MPC30X) += 0xffffffff80001000
+
+#
+# ZAO Networks Capcella (VR4131)
+#
+load-$(CONFIG_ZAO_CAPCELLA) += 0xffffffff80000000
diff --git a/arch/mips/vr41xx/common/Makefile b/arch/mips/vr41xx/common/Makefile
index 7d5d83b8c582..d0d84ec8d63d 100644
--- a/arch/mips/vr41xx/common/Makefile
+++ b/arch/mips/vr41xx/common/Makefile
@@ -3,5 +3,3 @@
#
obj-y += bcu.o cmu.o giu.o icu.o init.o irq.o pmu.o rtc.o siu.o type.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/gt64120/wrppmc/Makefile b/arch/mips/wrppmc/Makefile
index b49d282bee8a..307cc6920ce6 100644
--- a/arch/mips/gt64120/wrppmc/Makefile
+++ b/arch/mips/wrppmc/Makefile
@@ -6,9 +6,7 @@
# Copyright 2006 Wind River System, Inc.
# Author: Rongkai.Zhan <rongkai.zhan@windriver.com>
#
-# Makefile for the Wind River MIPS 4KC PPMC Eval Board
+# Makefile for the Wind River MIPS 4Kc PPMC Eval Board
#
obj-y += irq.o pci.o reset.o serial.o setup.o time.o
-
-EXTRA_CFLAGS += -Werror
diff --git a/arch/mips/wrppmc/Platform b/arch/mips/wrppmc/Platform
new file mode 100644
index 000000000000..e758645e9681
--- /dev/null
+++ b/arch/mips/wrppmc/Platform
@@ -0,0 +1,7 @@
+#
+# Wind River PPMC Board (4KC + GT64120)
+#
+platform-$(CONFIG_WR_PPMC) += wrppmc/
+cflags-$(CONFIG_WR_PPMC) += \
+ -I$(srctree)/arch/mips/include/asm/mach-wrppmc
+load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/wrppmc/irq.c
index c6e706274db4..c6e706274db4 100644
--- a/arch/mips/gt64120/wrppmc/irq.c
+++ b/arch/mips/wrppmc/irq.c
diff --git a/arch/mips/gt64120/wrppmc/pci.c b/arch/mips/wrppmc/pci.c
index d06192faeb7c..d06192faeb7c 100644
--- a/arch/mips/gt64120/wrppmc/pci.c
+++ b/arch/mips/wrppmc/pci.c
diff --git a/arch/mips/gt64120/wrppmc/reset.c b/arch/mips/wrppmc/reset.c
index cc5474b24f06..cc5474b24f06 100644
--- a/arch/mips/gt64120/wrppmc/reset.c
+++ b/arch/mips/wrppmc/reset.c
diff --git a/arch/mips/gt64120/wrppmc/serial.c b/arch/mips/wrppmc/serial.c
index 6f9d0858f596..6f9d0858f596 100644
--- a/arch/mips/gt64120/wrppmc/serial.c
+++ b/arch/mips/wrppmc/serial.c
diff --git a/arch/mips/gt64120/wrppmc/setup.c b/arch/mips/wrppmc/setup.c
index ca65c84031a7..ca65c84031a7 100644
--- a/arch/mips/gt64120/wrppmc/setup.c
+++ b/arch/mips/wrppmc/setup.c
diff --git a/arch/mips/gt64120/wrppmc/time.c b/arch/mips/wrppmc/time.c
index 668dbd5f12c5..668dbd5f12c5 100644
--- a/arch/mips/gt64120/wrppmc/time.c
+++ b/arch/mips/wrppmc/time.c
diff --git a/arch/mn10300/mm/fault.c b/arch/mn10300/mm/fault.c
index 53bb17d0f068..81f153fa51b4 100644
--- a/arch/mn10300/mm/fault.c
+++ b/arch/mn10300/mm/fault.c
@@ -338,11 +338,10 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- monitor_signal(regs);
- printk(KERN_ALERT "VM: killing process %s\n", tsk->comm);
- if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
- do_exit(SIGKILL);
- goto no_context;
+ if ((fault_code & MMUFCR_xFC_ACCESS) != MMUFCR_xFC_ACCESS_USR)
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
do_sigbus:
up_read(&mm->mmap_sem);
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
index 32c2cca74345..45effe6978fa 100644
--- a/arch/parisc/include/asm/cache.h
+++ b/arch/parisc/include/asm/cache.h
@@ -28,7 +28,7 @@
#define SMP_CACHE_BYTES L1_CACHE_BYTES
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
void parisc_cache_init(void); /* initializes cache-flushing */
void disable_sr_hashing_asm(int); /* low level support for above */
diff --git a/arch/parisc/include/asm/system.h b/arch/parisc/include/asm/system.h
index 4653c77bf9d1..2ab4af58ecb9 100644
--- a/arch/parisc/include/asm/system.h
+++ b/arch/parisc/include/asm/system.h
@@ -174,7 +174,7 @@ static inline void set_eiem(unsigned long val)
})
#ifdef CONFIG_SMP
-# define __lock_aligned __attribute__((__section__(".data.lock_aligned")))
+# define __lock_aligned __attribute__((__section__(".data..lock_aligned")))
#endif
#define arch_align_stack(x) (x)
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 0e3d9f9b9e33..4dbdf0ed6fa0 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -345,7 +345,7 @@ smp_slave_stext:
ENDPROC(stext)
#ifndef CONFIG_64BIT
- .section .data.read_mostly
+ .section .data..read_mostly
.align 4
.export $global$,data
diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c
index d020eae6525c..4a91e433416f 100644
--- a/arch/parisc/kernel/init_task.c
+++ b/arch/parisc/kernel/init_task.c
@@ -53,11 +53,11 @@ union thread_union init_thread_union __init_task_data
* guarantee that global objects will be laid out in memory in the same order
* as the order of declaration, so put these in different sections and use
* the linker script to order them. */
-pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data.vm0.pmd"), aligned(PAGE_SIZE)));
+pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data..vm0.pmd"), aligned(PAGE_SIZE)));
#endif
-pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data.vm0.pgd"), aligned(PAGE_SIZE)));
-pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data.vm0.pte"), aligned(PAGE_SIZE)));
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data..vm0.pgd"), aligned(PAGE_SIZE)));
+pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data..vm0.pte"), aligned(PAGE_SIZE)));
/*
* Initial task structure.
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 9dab4a4e09f7..d64a6bbec2aa 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -94,8 +94,8 @@ SECTIONS
/* PA-RISC locks requires 16-byte alignment */
. = ALIGN(16);
- .data.lock_aligned : {
- *(.data.lock_aligned)
+ .data..lock_aligned : {
+ *(.data..lock_aligned)
}
/* End of data section */
@@ -105,10 +105,10 @@ SECTIONS
__bss_start = .;
/* page table entries need to be PAGE_SIZE aligned */
. = ALIGN(PAGE_SIZE);
- .data.vmpages : {
- *(.data.vm0.pmd)
- *(.data.vm0.pgd)
- *(.data.vm0.pte)
+ .data..vmpages : {
+ *(.data..vm0.pmd)
+ *(.data..vm0.pgd)
+ *(.data..vm0.pte)
}
.bss : {
*(.bss)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 66a315e06dce..328774bd41ee 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -351,7 +351,7 @@ config ARCH_ENABLE_MEMORY_HOTREMOVE
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
- depends on PPC_BOOK3S && EXPERIMENTAL
+ depends on (PPC_BOOK3S || (FSL_BOOKE && !SMP)) && EXPERIMENTAL
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 1a54a3b3a3fa..42dcd3f4ad7b 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -112,6 +112,11 @@ KBUILD_CFLAGS += $(call cc-option,-mspe=no)
# kernel considerably.
KBUILD_CFLAGS += $(call cc-option,-funit-at-a-time)
+# FIXME: the module load should be taught about the additional relocs
+# generated by this.
+# revert to pre-gcc-4.4 behaviour of .eh_frame
+KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
+
# Never use string load/store instructions as they are
# often slow when they are implemented at all
KBUILD_CFLAGS += -mno-string
diff --git a/arch/powerpc/boot/4xx.c b/arch/powerpc/boot/4xx.c
index 27db8938827a..9d3bd4c45a24 100644
--- a/arch/powerpc/boot/4xx.c
+++ b/arch/powerpc/boot/4xx.c
@@ -519,7 +519,7 @@ void ibm440ep_fixup_clocks(unsigned int sys_clk,
{
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 0);
- /* serial clocks beed fixup based on int/ext */
+ /* serial clocks need fixup based on int/ext */
eplike_fixup_uart_clk(0, "/plb/opb/serial@ef600300", ser_clk, plb_clk);
eplike_fixup_uart_clk(1, "/plb/opb/serial@ef600400", ser_clk, plb_clk);
eplike_fixup_uart_clk(2, "/plb/opb/serial@ef600500", ser_clk, plb_clk);
@@ -532,7 +532,7 @@ void ibm440gx_fixup_clocks(unsigned int sys_clk,
{
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
- /* serial clocks beed fixup based on int/ext */
+ /* serial clocks need fixup based on int/ext */
eplike_fixup_uart_clk(0, "/plb/opb/serial@40000200", ser_clk, plb_clk);
eplike_fixup_uart_clk(1, "/plb/opb/serial@40000300", ser_clk, plb_clk);
}
@@ -543,10 +543,10 @@ void ibm440spe_fixup_clocks(unsigned int sys_clk,
{
unsigned int plb_clk = __ibm440eplike_fixup_clocks(sys_clk, tmr_clk, 1);
- /* serial clocks beed fixup based on int/ext */
- eplike_fixup_uart_clk(0, "/plb/opb/serial@10000200", ser_clk, plb_clk);
- eplike_fixup_uart_clk(1, "/plb/opb/serial@10000300", ser_clk, plb_clk);
- eplike_fixup_uart_clk(2, "/plb/opb/serial@10000600", ser_clk, plb_clk);
+ /* serial clocks need fixup based on int/ext */
+ eplike_fixup_uart_clk(0, "/plb/opb/serial@f0000200", ser_clk, plb_clk);
+ eplike_fixup_uart_clk(1, "/plb/opb/serial@f0000300", ser_clk, plb_clk);
+ eplike_fixup_uart_clk(2, "/plb/opb/serial@f0000600", ser_clk, plb_clk);
}
void ibm405gp_fixup_clocks(unsigned int sys_clk, unsigned int ser_clk)
diff --git a/arch/powerpc/boot/dts/icon.dts b/arch/powerpc/boot/dts/icon.dts
new file mode 100644
index 000000000000..abcd0caeccae
--- /dev/null
+++ b/arch/powerpc/boot/dts/icon.dts
@@ -0,0 +1,447 @@
+/*
+ * Device Tree Source for Mosaix Technologies, Inc. ICON board
+ *
+ * Copyright 2010 DENX Software Engineering, Stefan Roese <sr@denx.de>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without
+ * any warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ model = "mosaixtech,icon";
+ compatible = "mosaixtech,icon";
+ dcr-parent = <&{/cpus/cpu@0}>;
+
+ aliases {
+ ethernet0 = &EMAC0;
+ serial0 = &UART0;
+ serial1 = &UART1;
+ serial2 = &UART2;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,440SPe";
+ reg = <0x00000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ dcr-controller;
+ dcr-access-method = "native";
+ reset-type = <2>; /* Use chip-reset */
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x00000000 0x0 0x00000000>; /* Filled in by U-Boot */
+ };
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-440spe","ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0x0c0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-440spe","ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0x0d0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-440spe","ibm,uic";
+ interrupt-controller;
+ cell-index = <2>;
+ dcr-reg = <0x0e0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC3: interrupt-controller3 {
+ compatible = "ibm,uic-440spe","ibm,uic";
+ interrupt-controller;
+ cell-index = <3>;
+ dcr-reg = <0x0f0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ SDR0: sdr {
+ compatible = "ibm,sdr-440spe";
+ dcr-reg = <0x00e 0x002>;
+ };
+
+ CPR0: cpr {
+ compatible = "ibm,cpr-440spe";
+ dcr-reg = <0x00c 0x002>;
+ };
+
+ MQ0: mq {
+ compatible = "ibm,mq-440spe";
+ dcr-reg = <0x040 0x020>;
+ };
+
+ plb {
+ compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* addr-child addr-parent size */
+ ranges = <0x4 0x00100000 0x4 0x00100000 0x00001000
+ 0x4 0x00200000 0x4 0x00200000 0x00000400
+ 0x4 0xe0000000 0x4 0xe0000000 0x20000000
+ 0xc 0x00000000 0xc 0x00000000 0x20000000
+ 0xd 0x00000000 0xd 0x00000000 0x80000000
+ 0xd 0x80000000 0xd 0x80000000 0x80000000
+ 0xe 0x00000000 0xe 0x00000000 0x80000000
+ 0xe 0x80000000 0xe 0x80000000 0x80000000
+ 0xf 0x00000000 0xf 0x00000000 0x80000000
+ 0xf 0x80000000 0xf 0x80000000 0x80000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ SDRAM0: sdram {
+ compatible = "ibm,sdram-440spe", "ibm,sdram-405gp";
+ dcr-reg = <0x010 0x002>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-440spe", "ibm,mcmal2";
+ dcr-reg = <0x180 0x062>;
+ num-tx-chans = <2>;
+ num-rx-chans = <1>;
+ interrupt-parent = <&MAL0>;
+ interrupts = <0x0 0x1 0x2 0x3 0x4>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*TXEOB*/ 0x0 &UIC1 0x6 0x4
+ /*RXEOB*/ 0x1 &UIC1 0x7 0x4
+ /*SERR*/ 0x2 &UIC1 0x1 0x4
+ /*TXDE*/ 0x3 &UIC1 0x2 0x4
+ /*RXDE*/ 0x4 &UIC1 0x3 0x4>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-440spe", "ibm,opb-440gp", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xe0000000 0x00000004 0xe0000000 0x20000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-440spe", "ibm,ebc-440gp", "ibm,ebc";
+ dcr-reg = <0x012 0x002>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
+ interrupts = <0x5 0x1>;
+ interrupt-parent = <&UIC1>;
+
+ nor_flash@0,0 {
+ compatible = "cfi-flash";
+ bank-width = <2>;
+ reg = <0x00000000 0x00000000 0x01000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "kernel";
+ reg = <0x00000000 0x001e0000>;
+ };
+ partition@1e0000 {
+ label = "dtb";
+ reg = <0x001e0000 0x00020000>;
+ };
+ partition@200000 {
+ label = "root";
+ reg = <0x00200000 0x00200000>;
+ };
+ partition@400000 {
+ label = "user";
+ reg = <0x00400000 0x00b60000>;
+ };
+ partition@f60000 {
+ label = "env";
+ reg = <0x00f60000 0x00040000>;
+ };
+ partition@fa0000 {
+ label = "u-boot";
+ reg = <0x00fa0000 0x00060000>;
+ };
+ };
+
+ SysACE_CompactFlash: sysace@1,0 {
+ compatible = "xlnx,sysace";
+ interrupt-parent = <&UIC2>;
+ interrupts = <24 0x4>;
+ reg = <0x00000001 0x00000000 0x10000>;
+ };
+ };
+
+ UART0: serial@f0000200 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xf0000200 0x00000008>;
+ virtual-reg = <0xa0000200>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <115200>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x0 0x4>;
+ };
+
+ UART1: serial@f0000300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xf0000300 0x00000008>;
+ virtual-reg = <0xa0000300>;
+ clock-frequency = <0>;
+ current-speed = <0>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x1 0x4>;
+ };
+
+
+ UART2: serial@f0000600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xf0000600 0x00000008>;
+ virtual-reg = <0xa0000600>;
+ clock-frequency = <0>;
+ current-speed = <0>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x5 0x4>;
+ };
+
+ IIC0: i2c@f0000400 {
+ compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic";
+ reg = <0xf0000400 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x2 0x4>;
+ };
+
+ IIC1: i2c@f0000500 {
+ compatible = "ibm,iic-440spe", "ibm,iic-440gp", "ibm,iic";
+ reg = <0xf0000500 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x3 0x4>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@68 {
+ compatible = "stm,m41t00";
+ reg = <0x68>;
+ };
+ };
+
+ EMAC0: ethernet@f0000800 {
+ linux,network-index = <0x0>;
+ device_type = "network";
+ compatible = "ibm,emac-440spe", "ibm,emac4";
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x1c 0x4 0x1d 0x4>;
+ reg = <0xf0000800 0x00000074>;
+ local-mac-address = [000000000000];
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "gmii";
+ phy-map = <0x00000000>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+ };
+
+ PCIX0: pci@c0ec00000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pcix-440spe", "ibm,plb-pcix";
+ primary;
+ large-inbound-windows;
+ enable-msi-hole;
+ reg = <0x0000000c 0x0ec00000 0x00000008 /* Config space access */
+ 0x00000000 0x00000000 0x00000000 /* no IACK cycles */
+ 0x0000000c 0x0ed00000 0x00000004 /* Special cycles */
+ 0x0000000c 0x0ec80000 0x00000100 /* Internal registers */
+ 0x0000000c 0x0ec80100 0x000000fc>; /* Internal messaging registers */
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>;
+
+ /* Inbound 4GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+ /* This drives busses 0 to 0xf */
+ bus-range = <0x0 0xf>;
+
+ /* PCI-X interrupt (SM502) is routed to extIRQ10 (UIC1, 19) */
+ interrupt-map-mask = <0x0 0x0 0x0 0x0>;
+ interrupt-map = <0x0 0x0 0x0 0x0 &UIC1 19 0x8>;
+ };
+
+ PCIE0: pciex@d00000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
+ primary;
+ port = <0x0>; /* port number */
+ reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
+ 0x0000000c 0x10000000 0x00001000>; /* Registers */
+ dcr-reg = <0x100 0x020>;
+ sdr-base = <0x300>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+ /* Inbound 4GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+ /* This drives busses 0x10 to 0x1f */
+ bus-range = <0x10 0x1f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x0 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x1 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0x2 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0x3 0x4 /* swizzled int D */>;
+ };
+
+ PCIE1: pciex@d20000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
+ primary;
+ port = <0x1>; /* port number */
+ reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */
+ 0x0000000c 0x10001000 0x00001000>; /* Registers */
+ dcr-reg = <0x120 0x020>;
+ sdr-base = <0x340>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
+
+ /* Inbound 4GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>;
+
+ /* This drives busses 0x20 to 0x2f */
+ bus-range = <0x20 0x2f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x4 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x5 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0x6 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0x7 0x4 /* swizzled int D */>;
+ };
+
+ I2O: i2o@400100000 {
+ compatible = "ibm,i2o-440spe";
+ reg = <0x00000004 0x00100000 0x100>;
+ dcr-reg = <0x060 0x020>;
+ };
+
+ DMA0: dma0@400100100 {
+ compatible = "ibm,dma-440spe";
+ cell-index = <0>;
+ reg = <0x00000004 0x00100100 0x100>;
+ dcr-reg = <0x060 0x020>;
+ interrupt-parent = <&DMA0>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <
+ 0 &UIC0 0x14 4
+ 1 &UIC1 0x16 4>;
+ };
+
+ DMA1: dma1@400100200 {
+ compatible = "ibm,dma-440spe";
+ cell-index = <1>;
+ reg = <0x00000004 0x00100200 0x100>;
+ dcr-reg = <0x060 0x020>;
+ interrupt-parent = <&DMA1>;
+ interrupts = <0 1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = <
+ 0 &UIC0 0x16 4
+ 1 &UIC1 0x16 4>;
+ };
+
+ xor-accel@400200000 {
+ compatible = "amcc,xor-accelerator";
+ reg = <0x00000004 0x00200000 0x400>;
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x1f 4>;
+ };
+ };
+
+ chosen {
+ linux,stdout-path = "/plb/opb/serial@f0000200";
+ };
+};
diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts
index 8cf2c0c88c05..7c3be5e45748 100644
--- a/arch/powerpc/boot/dts/katmai.dts
+++ b/arch/powerpc/boot/dts/katmai.dts
@@ -44,6 +44,7 @@
d-cache-size = <32768>;
dcr-controller;
dcr-access-method = "native";
+ reset-type = <2>; /* Use chip-reset */
};
};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
index 4173af387c63..0f5262452682 100644
--- a/arch/powerpc/boot/dts/mpc8548cds.dts
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -20,10 +20,8 @@
aliases {
ethernet0 = &enet0;
ethernet1 = &enet1;
-/*
ethernet2 = &enet2;
ethernet3 = &enet3;
-*/
serial0 = &serial0;
serial1 = &serial1;
pci0 = &pci0;
@@ -254,7 +252,6 @@
};
};
-/* eTSEC 3/4 are currently broken
enet2: ethernet@26000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -310,7 +307,6 @@
};
};
};
- */
serial0: serial@4500 {
cell-index = <0>;
diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
index 5bd1011fde96..3375c2ab0c32 100644
--- a/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
+++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core0.dts
@@ -215,6 +215,18 @@
clock-frequency = <0>;
};
+ msi@41600 {
+ compatible = "fsl,mpc8572-msi", "fsl,mpic-msi";
+ reg = <0x41600 0x80>;
+ msi-available-ranges = <0 0x80>;
+ interrupts = <
+ 0xe0 0
+ 0xe1 0
+ 0xe2 0
+ 0xe3 0>;
+ interrupt-parent = <&mpic>;
+ };
+
global-utilities@e0000 { //global utilities block
compatible = "fsl,mpc8572-guts";
reg = <0xe0000 0x1000>;
@@ -243,8 +255,7 @@
protected-sources = <
31 32 33 37 38 39 /* enet2 enet3 */
76 77 78 79 26 42 /* dma2 pci2 serial*/
- 0xe0 0xe1 0xe2 0xe3 /* msi */
- 0xe4 0xe5 0xe6 0xe7
+ 0xe4 0xe5 0xe6 0xe7 /* msi */
>;
};
};
diff --git a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
index 0efc3456e297..e7b477f6a3fe 100644
--- a/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
+++ b/arch/powerpc/boot/dts/mpc8572ds_camp_core1.dts
@@ -154,12 +154,8 @@
msi@41600 {
compatible = "fsl,mpc8572-msi", "fsl,mpic-msi";
reg = <0x41600 0x80>;
- msi-available-ranges = <0 0x100>;
+ msi-available-ranges = <0x80 0x80>;
interrupts = <
- 0xe0 0
- 0xe1 0
- 0xe2 0
- 0xe3 0
0xe4 0
0xe5 0
0xe6 0
@@ -190,6 +186,7 @@
0x1 0x2 0x3 0x4 /* pci slot */
0x9 0xa 0xb 0xc /* usb */
0x6 0x7 0xe 0x5 /* Audio elgacy SATA */
+ 0xe0 0xe1 0xe2 0xe3 /* msi */
>;
};
};
diff --git a/arch/powerpc/boot/dts/p1021mds.dts b/arch/powerpc/boot/dts/p1021mds.dts
new file mode 100644
index 000000000000..7fad2df25981
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1021mds.dts
@@ -0,0 +1,698 @@
+/*
+ * P1021 MDS Device Tree Source
+ *
+ * Copyright 2010 Freescale Semiconductor Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/dts-v1/;
+/ {
+ model = "fsl,P1021";
+ compatible = "fsl,P1021MDS";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ ethernet2 = &enet2;
+ ethernet3 = &enet3;
+ ethernet4 = &enet4;
+ pci0 = &pci0;
+ pci1 = &pci1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,P1021@0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ next-level-cache = <&L2>;
+ };
+
+ PowerPC,P1021@1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ };
+
+ localbus@ffe05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,p1021-elbc", "fsl,elbc", "simple-bus";
+ reg = <0 0xffe05000 0 0x1000>;
+ interrupts = <19 2>;
+ interrupt-parent = <&mpic>;
+
+ /* NAND Flash, BCSR, PMC0/1*/
+ ranges = <0x0 0x0 0x0 0xfc000000 0x02000000
+ 0x1 0x0 0x0 0xf8000000 0x00008000
+ 0x2 0x0 0x0 0xf8010000 0x00020000
+ 0x3 0x0 0x0 0xf8020000 0x00020000>;
+
+ nand@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,p1021-fcm-nand",
+ "fsl,elbc-fcm-nand";
+ reg = <0x0 0x0 0x40000>;
+
+ partition@0 {
+ /* This location must not be altered */
+ /* 1MB for u-boot Bootloader Image */
+ reg = <0x0 0x00100000>;
+ label = "NAND (RO) U-Boot Image";
+ read-only;
+ };
+
+ partition@100000 {
+ /* 1MB for DTB Image */
+ reg = <0x00100000 0x00100000>;
+ label = "NAND (RO) DTB Image";
+ read-only;
+ };
+
+ partition@200000 {
+ /* 4MB for Linux Kernel Image */
+ reg = <0x00200000 0x00400000>;
+ label = "NAND (RO) Linux Kernel Image";
+ read-only;
+ };
+
+ partition@600000 {
+ /* 5MB for Compressed Root file System Image */
+ reg = <0x00600000 0x00500000>;
+ label = "NAND (RO) Compressed RFS Image";
+ read-only;
+ };
+
+ partition@b00000 {
+ /* 6MB for JFFS2 based Root file System */
+ reg = <0x00a00000 0x00600000>;
+ label = "NAND (RW) JFFS2 Root File System";
+ };
+
+ partition@1100000 {
+ /* 14MB for JFFS2 based Root file System */
+ reg = <0x01100000 0x00e00000>;
+ label = "NAND (RW) Writable User area";
+ };
+
+ partition@1f00000 {
+ /* 1MB for microcode */
+ reg = <0x01f00000 0x00100000>;
+ label = "NAND (RO) QE Ucode";
+ read-only;
+ };
+ };
+
+ bcsr@1,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,p1021mds-bcsr";
+ reg = <1 0 0x8000>;
+ ranges = <0 1 0 0x8000>;
+ };
+
+ pib@2,0 {
+ compatible = "fsl,p1021mds-pib";
+ reg = <2 0 0x10000>;
+ };
+
+ pib@3,0 {
+ compatible = "fsl,p1021mds-pib";
+ reg = <3 0 0x10000>;
+ };
+ };
+
+ soc@ffe00000 {
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ compatible = "fsl,p1021-immr", "simple-bus";
+ ranges = <0x0 0x0 0xffe00000 0x100000>;
+ bus-frequency = <0>; // Filled out by uboot.
+
+ ecm-law@0 {
+ compatible = "fsl,ecm-law";
+ reg = <0x0 0x1000>;
+ fsl,num-laws = <12>;
+ };
+
+ ecm@1000 {
+ compatible = "fsl,p1021-ecm", "fsl,ecm";
+ reg = <0x1000 0x1000>;
+ interrupts = <16 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ memory-controller@2000 {
+ compatible = "fsl,p1021-memory-controller";
+ reg = <0x2000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+
+ i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ rtc@68 {
+ compatible = "dallas,ds1374";
+ reg = <0x68>;
+ };
+ };
+
+ i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cell-index = <1>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <43 2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <42 2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ spi@7000 {
+ cell-index = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,espi";
+ reg = <0x7000 0x1000>;
+ interrupts = <59 0x2>;
+ interrupt-parent = <&mpic>;
+ espi,num-ss-bits = <4>;
+ mode = "cpu";
+
+ fsl_m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,espi-flash";
+ reg = <0>;
+ linux,modalias = "fsl_m25p80";
+ spi-max-frequency = <40000000>; /* input clock */
+ partition@u-boot {
+ label = "u-boot-spi";
+ reg = <0x00000000 0x00100000>;
+ read-only;
+ };
+ partition@kernel {
+ label = "kernel-spi";
+ reg = <0x00100000 0x00500000>;
+ read-only;
+ };
+ partition@dtb {
+ label = "dtb-spi";
+ reg = <0x00600000 0x00100000>;
+ read-only;
+ };
+ partition@fs {
+ label = "file system-spi";
+ reg = <0x00700000 0x00900000>;
+ };
+ };
+ };
+
+ gpio: gpio-controller@f000 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8572-gpio";
+ reg = <0xf000 0x100>;
+ interrupts = <47 0x2>;
+ interrupt-parent = <&mpic>;
+ gpio-controller;
+ };
+
+ L2: l2-cache-controller@20000 {
+ compatible = "fsl,p1021-l2-cache-controller";
+ reg = <0x20000 0x1000>;
+ cache-line-size = <32>; // 32 bytes
+ cache-size = <0x40000>; // L2,256K
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ usb@22000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-usb2-dr";
+ reg = <0x22000 0x1000>;
+ interrupt-parent = <&mpic>;
+ interrupts = <28 0x2>;
+ phy_type = "ulpi";
+ };
+
+ mdio@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-mdio";
+ reg = <0x24000 0x1000 0xb0030 0x4>;
+
+ phy0: ethernet-phy@0 {
+ interrupt-parent = <&mpic>;
+ interrupts = <1 1>;
+ reg = <0x0>;
+ };
+ phy1: ethernet-phy@1 {
+ interrupt-parent = <&mpic>;
+ interrupts = <2 1>;
+ reg = <0x1>;
+ };
+ phy4: ethernet-phy@4 {
+ interrupt-parent = <&mpic>;
+ reg = <0x4>;
+ };
+ };
+
+ mdio@25000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,etsec2-tbi";
+ reg = <0x25000 0x1000 0xb1030 0x4>;
+ tbi0: tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet0: ethernet@B0000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "fsl,etsec2";
+ fsl,num_rx_queues = <0x8>;
+ fsl,num_tx_queues = <0x8>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy0>;
+ phy-connection-type = "rgmii-id";
+ queue-group@0{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB0000 0x1000>;
+ interrupts = <29 2 30 2 34 2>;
+ };
+ queue-group@1{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB4000 0x1000>;
+ interrupts = <17 2 18 2 24 2>;
+ };
+ };
+
+ enet1: ethernet@B1000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "fsl,etsec2";
+ fsl,num_rx_queues = <0x8>;
+ fsl,num_tx_queues = <0x8>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy4>;
+ tbi-handle = <&tbi0>;
+ phy-connection-type = "sgmii";
+ queue-group@0{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB1000 0x1000>;
+ interrupts = <35 2 36 2 40 2>;
+ };
+ queue-group@1{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB5000 0x1000>;
+ interrupts = <51 2 52 2 67 2>;
+ };
+ };
+
+ enet2: ethernet@B2000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ cell-index = <0>;
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "fsl,etsec2";
+ fsl,num_rx_queues = <0x8>;
+ fsl,num_tx_queues = <0x8>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy1>;
+ phy-connection-type = "rgmii-id";
+ queue-group@0{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB2000 0x1000>;
+ interrupts = <31 2 32 2 33 2>;
+ };
+ queue-group@1{
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xB6000 0x1000>;
+ interrupts = <25 2 26 2 27 2>;
+ };
+ };
+
+ sdhci@2e000 {
+ compatible = "fsl,p1021-esdhc", "fsl,esdhc";
+ reg = <0x2e000 0x1000>;
+ interrupts = <72 0x2>;
+ interrupt-parent = <&mpic>;
+ /* Filled in by U-Boot */
+ clock-frequency = <0>;
+ };
+
+ crypto@30000 {
+ compatible = "fsl,sec3.3", "fsl,sec3.1",
+ "fsl,sec3.0", "fsl,sec2.4",
+ "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
+ reg = <0x30000 0x10000>;
+ interrupts = <45 2 58 2>;
+ interrupt-parent = <&mpic>;
+ fsl,num-channels = <4>;
+ fsl,channel-fifo-len = <24>;
+ fsl,exec-units-mask = <0x97c>;
+ fsl,descriptor-types-mask = <0x3a30abf>;
+ };
+
+ mpic: pic@40000 {
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+
+ msi@41600 {
+ compatible = "fsl,p1021-msi", "fsl,mpic-msi";
+ reg = <0x41600 0x80>;
+ msi-available-ranges = <0 0x100>;
+ interrupts = <
+ 0xe0 0
+ 0xe1 0
+ 0xe2 0
+ 0xe3 0
+ 0xe4 0
+ 0xe5 0
+ 0xe6 0
+ 0xe7 0>;
+ interrupt-parent = <&mpic>;
+ };
+
+ global-utilities@e0000 { //global utilities block
+ compatible = "fsl,p1021-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+
+ par_io@e0100 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xe0100 0x60>;
+ ranges = <0x0 0xe0100 0x60>;
+ device_type = "par_io";
+ num-ports = <3>;
+ pio1: ucc_pin@01 {
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */
+ 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */
+ 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */
+ 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9
+*/
+ 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */
+ 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */
+ 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */
+ 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */
+ 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */
+ 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */
+ 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */
+ 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */
+ 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */
+ 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */
+ 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */
+ 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */
+ 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */
+ 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */
+ };
+
+ pio2: ucc_pin@02 {
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */
+ 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */
+ 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */
+ 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */
+ 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */
+ 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */
+ 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */
+ 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */
+ 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */
+ 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */
+ };
+ };
+ };
+
+ pci0: pcie@ffe09000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe09000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 4 1
+ 0000 0 0 2 &mpic 5 1
+ 0000 0 0 3 &mpic 6 1
+ 0000 0 0 4 &mpic 7 1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xa0000000
+ 0x2000000 0x0 0xa0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ pci1: pcie@ffe0a000 {
+ compatible = "fsl,mpc8548-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0 0xffe0a000 0 0x1000>;
+ bus-range = <0 255>;
+ ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000
+ 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <16 2>;
+ interrupt-map-mask = <0xf800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0 */
+ 0000 0 0 1 &mpic 0 1
+ 0000 0 0 2 &mpic 1 1
+ 0000 0 0 3 &mpic 2 1
+ 0000 0 0 4 &mpic 3 1
+ >;
+ pcie@0 {
+ reg = <0x0 0x0 0x0 0x0 0x0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x2000000 0x0 0xc0000000
+ 0x2000000 0x0 0xc0000000
+ 0x0 0x20000000
+
+ 0x1000000 0x0 0x0
+ 0x1000000 0x0 0x0
+ 0x0 0x100000>;
+ };
+ };
+
+ qe@ffe80000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "qe";
+ compatible = "fsl,qe";
+ ranges = <0x0 0x0 0xffe80000 0x40000>;
+ reg = <0 0xffe80000 0 0x480>;
+ brg-frequency = <0>;
+ bus-frequency = <0>;
+ fsl,qe-num-riscs = <1>;
+ fsl,qe-num-snums = <28>;
+
+ qeic: interrupt-controller@80 {
+ interrupt-controller;
+ compatible = "fsl,qe-ic";
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <0x80 0x80>;
+ interrupts = <63 2 60 2>; //high:47 low:44
+ interrupt-parent = <&mpic>;
+ };
+
+ enet3: ucc@2000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ cell-index = <1>;
+ reg = <0x2000 0x200>;
+ interrupts = <32>;
+ interrupt-parent = <&qeic>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ rx-clock-name = "clk12";
+ tx-clock-name = "clk9";
+ pio-handle = <&pio1>;
+ phy-handle = <&qe_phy0>;
+ phy-connection-type = "mii";
+ };
+
+ mdio@2120 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x2120 0x18>;
+ compatible = "fsl,ucc-mdio";
+
+ qe_phy0: ethernet-phy@0 {
+ interrupt-parent = <&mpic>;
+ interrupts = <4 1>;
+ reg = <0x0>;
+ device_type = "ethernet-phy";
+ };
+ qe_phy1: ethernet-phy@03 {
+ interrupt-parent = <&mpic>;
+ interrupts = <5 1>;
+ reg = <0x3>;
+ device_type = "ethernet-phy";
+ };
+ tbi-phy@11 {
+ reg = <0x11>;
+ device_type = "tbi-phy";
+ };
+ };
+
+ enet4: ucc@2400 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ cell-index = <5>;
+ reg = <0x2400 0x200>;
+ interrupts = <40>;
+ interrupt-parent = <&qeic>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ rx-clock-name = "none";
+ tx-clock-name = "clk13";
+ pio-handle = <&pio2>;
+ phy-handle = <&qe_phy1>;
+ phy-connection-type = "rmii";
+ };
+
+ muram@10000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,qe-muram", "fsl,cpm-muram";
+ ranges = <0x0 0x10000 0x6000>;
+
+ data-only@0 {
+ compatible = "fsl,qe-muram-data",
+ "fsl,cpm-muram-data";
+ reg = <0x0 0x6000>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts
index d2af32e2bf7a..81636c01d906 100644
--- a/arch/powerpc/boot/dts/redwood.dts
+++ b/arch/powerpc/boot/dts/redwood.dts
@@ -234,10 +234,132 @@
has-inverted-stacr-oc;
has-new-stacr-staopc;
};
+ };
+ PCIE0: pciex@d00000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex";
+ primary;
+ port = <0x0>; /* port number */
+ reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */
+ 0x0000000c 0x10000000 0x00001000>; /* Registers */
+ dcr-reg = <0x100 0x020>;
+ sdr-base = <0x300>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+ /* This drives busses 10 to 0x1f */
+ bus-range = <0x10 0x1f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x0 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x1 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0x2 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0x3 0x4 /* swizzled int D */>;
+ };
+
+ PCIE1: pciex@d20000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex";
+ primary;
+ port = <0x1>; /* port number */
+ reg = <0x0000000d 0x20000000 0x20000000 /* Config space access */
+ 0x0000000c 0x10001000 0x00001000>; /* Registers */
+ dcr-reg = <0x120 0x020>;
+ sdr-base = <0x340>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 10 to 0x1f */
+ bus-range = <0x20 0x2f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x4 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x5 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0x6 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0x7 0x4 /* swizzled int D */>;
+ };
+
+ PCIE2: pciex@d40000000 {
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "ibm,plb-pciex-460sx", "ibm,plb-pciex";
+ primary;
+ port = <0x2>; /* port number */
+ reg = <0x0000000d 0x40000000 0x20000000 /* Config space access */
+ 0x0000000c 0x10002000 0x00001000>; /* Registers */
+ dcr-reg = <0x140 0x020>;
+ sdr-base = <0x370>;
+
+ /* Outbound ranges, one memory and one IO,
+ * later cannot be changed
+ */
+ ranges = <0x02000000 0x00000000 0x80000000 0x0000000f 0x00000000 0x00000000 0x80000000
+ 0x01000000 0x00000000 0x00000000 0x0000000f 0x80020000 0x00000000 0x00010000>;
+
+ /* Inbound 2GB range starting at 0 */
+ dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>;
+
+ /* This drives busses 10 to 0x1f */
+ bus-range = <0x30 0x3f>;
+
+ /* Legacy interrupts (note the weird polarity, the bridge seems
+ * to invert PCIe legacy interrupts).
+ * We are de-swizzling here because the numbers are actually for
+ * port of the root complex virtual P2P bridge. But I want
+ * to avoid putting a node for it in the tree, so the numbers
+ * below are basically de-swizzled numbers.
+ * The real slot is on idsel 0, so the swizzling is 1:1
+ */
+ interrupt-map-mask = <0x0 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0 0x0 0x0 0x1 &UIC3 0x8 0x4 /* swizzled int A */
+ 0x0 0x0 0x0 0x2 &UIC3 0x9 0x4 /* swizzled int B */
+ 0x0 0x0 0x0 0x3 &UIC3 0xa 0x4 /* swizzled int C */
+ 0x0 0x0 0x0 0x4 &UIC3 0xb 0x4 /* swizzled int D */>;
};
};
+
chosen {
linux,stdout-path = "/plb/opb/serial@ef600200";
};
diff --git a/arch/powerpc/configs/44x/icon_defconfig b/arch/powerpc/configs/44x/icon_defconfig
new file mode 100644
index 000000000000..277f88c2750f
--- /dev/null
+++ b/arch/powerpc/configs/44x/icon_defconfig
@@ -0,0 +1,1451 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.34-rc7
+# Fri May 21 17:40:22 2010
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_PPC_BOOK3S_32 is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+CONFIG_PPC_MMU_NOHASH=y
+CONFIG_PPC_MMU_NOHASH_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_NR_IRQS=512
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_PPC_ADV_DEBUG_REGS=y
+CONFIG_PPC_ADV_DEBUG_IACS=4
+CONFIG_PPC_ADV_DEBUG_DACS=2
+CONFIG_PPC_ADV_DEBUG_DVCS=2
+CONFIG_PPC_ADV_DEBUG_DAC_RANGE=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+# CONFIG_LOGBUFFER is not set
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+CONFIG_PPC4xx_PCI_EXPRESS=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
+# CONFIG_EBONY is not set
+# CONFIG_SAM440EP is not set
+# CONFIG_SEQUOIA is not set
+# CONFIG_TAISHAN is not set
+# CONFIG_KATMAI is not set
+# CONFIG_RAINIER is not set
+# CONFIG_WARP is not set
+# CONFIG_ARCHES is not set
+# CONFIG_CANYONLANDS is not set
+# CONFIG_GLACIER is not set
+# CONFIG_REDWOOD is not set
+# CONFIG_EIGER is not set
+# CONFIG_YOSEMITE is not set
+CONFIG_ICON=y
+# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
+CONFIG_PPC44x_SIMPLE=y
+# CONFIG_PPC4xx_GPIO is not set
+CONFIG_440SPe=y
+CONFIG_STDBINUTILS=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_MAX_ACTIVE_REGIONS=32
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_ARCH_HAS_NMI_WATCHDOG is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_4xx_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIE_ECRC is not set
+# CONFIG_PCIEAER_INJECT is not set
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+# CONFIG_LIB80211 is not set
+
+#
+# CFG80211 needs to be enabled for MAC80211
+#
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_DYNAMIC=y
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_DRBD is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=35000
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_XILINX_SYSACE=y
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=y
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+# CONFIG_SCSI_LOWLEVEL is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+CONFIG_FUSION=y
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+CONFIG_FUSION_SAS=y
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_CTL=y
+CONFIG_FUSION_LOGGING=y
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# The newer stack is recommended.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=128
+CONFIG_IBM_NEW_EMAC_TXB=64
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+CONFIG_IBM_NEW_EMAC_EMAC4=y
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_ATL2 is not set
+# CONFIG_XILINX_EMACLITE is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_PS2_ALPS is not set
+# CONFIG_MOUSE_PS2_LOGIPS2PP is not set
+# CONFIG_MOUSE_PS2_SYNAPTICS is not set
+# CONFIG_MOUSE_PS2_TRACKPOINT is not set
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_BOOTCOUNT is not set
+# CONFIG_DISPLAY_PDSP1880 is not set
+# CONFIG_MUCMC52_IO is not set
+# CONFIG_UC101_IO is not set
+# CONFIG_SRAM is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_IBM_IIC=y
+# CONFIG_I2C_MPC is not set
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+CONFIG_MFD_SM501=y
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+CONFIG_VGA_ARB=y
+CONFIG_VGA_ARB_MAX_GPUS=16
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_OF is not set
+# CONFIG_FB_CT65550 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+CONFIG_FB_SM501=y
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+# CONFIG_HID_PID is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+CONFIG_RTC_DRV_DS1307=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_LOGFS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=y
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_PPC4XX is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 725634fc18c6..4b509411ad8a 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -42,7 +42,7 @@ extern struct ppc64_caches ppc64_caches;
#endif /* __powerpc64__ && ! __ASSEMBLY__ */
#if !defined(__ASSEMBLY__)
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#endif
#endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index e3cba4e1eb34..b0b21134f61a 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -70,6 +70,7 @@ struct pt_regs;
extern int machine_check_generic(struct pt_regs *regs);
extern int machine_check_4xx(struct pt_regs *regs);
extern int machine_check_440A(struct pt_regs *regs);
+extern int machine_check_e500mc(struct pt_regs *regs);
extern int machine_check_e500(struct pt_regs *regs);
extern int machine_check_e200(struct pt_regs *regs);
extern int machine_check_47x(struct pt_regs *regs);
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index a6ca6da1430b..2a9cd74a841e 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -2,6 +2,18 @@
#define _ASM_POWERPC_KEXEC_H
#ifdef __KERNEL__
+#ifdef CONFIG_FSL_BOOKE
+
+/*
+ * On FSL-BookE we setup a 1:1 mapping which covers the first 2GiB of memory
+ * and therefore we can only deal with memory within this range
+ */
+#define KEXEC_SOURCE_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
+#define KEXEC_DESTINATION_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
+#define KEXEC_CONTROL_MEMORY_LIMIT (2 * 1024 * 1024 * 1024UL)
+
+#else
+
/*
* Maximum page that is mapped directly into kernel memory.
* XXX: Since we copy virt we can use any page we allocate
@@ -21,6 +33,7 @@
/* TASK_SIZE, probably left over from use_mm ?? */
#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
#endif
+#endif
#define KEXEC_CONTROL_PAGE_SIZE 4096
diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h
index 19a661b4cb98..675e159b5ef4 100644
--- a/arch/powerpc/include/asm/macio.h
+++ b/arch/powerpc/include/asm/macio.h
@@ -123,10 +123,6 @@ static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev)
*/
struct macio_driver
{
- char *name;
- struct of_device_id *match_table;
- struct module *owner;
-
int (*probe)(struct macio_dev* dev, const struct of_device_id *match);
int (*remove)(struct macio_dev* dev);
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index bfc4e027e2ad..358ff14ea25e 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -162,14 +162,6 @@ do { \
#endif /* !CONFIG_HUGETLB_PAGE */
-#ifdef MODULE
-#define __page_aligned __attribute__((__aligned__(PAGE_SIZE)))
-#else
-#define __page_aligned \
- __attribute__((__aligned__(PAGE_SIZE), \
- __section__(".data.page_aligned")))
-#endif
-
#define VM_DATA_DEFAULT_FLAGS \
(test_thread_flag(TIF_32BIT) ? \
VM_DATA_DEFAULT_FLAGS32 : VM_DATA_DEFAULT_FLAGS64)
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index 5304a37ba425..2360317179a9 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -4,6 +4,12 @@
* are not true Book E PowerPCs, they borrowed a number of features
* before Book E was finalized, and are included here as well. Unfortunatly,
* they sometimes used different locations than true Book E CPUs did.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * Copyright 2009-2010 Freescale Semiconductor, Inc.
*/
#ifdef __KERNEL__
#ifndef __ASM_POWERPC_REG_BOOKE_H__
@@ -88,6 +94,7 @@
#define SPRN_IVOR35 0x213 /* Interrupt Vector Offset Register 35 */
#define SPRN_IVOR36 0x214 /* Interrupt Vector Offset Register 36 */
#define SPRN_IVOR37 0x215 /* Interrupt Vector Offset Register 37 */
+#define SPRN_MCARU 0x239 /* Machine Check Address Register Upper */
#define SPRN_MCSRR0 0x23A /* Machine Check Save and Restore Register 0 */
#define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */
#define SPRN_MCSR 0x23C /* Machine Check Status Register */
@@ -196,8 +203,11 @@
#define PPC47x_MCSR_IPR 0x00400000 /* Imprecise Machine Check Exception */
#ifdef CONFIG_E500
+/* All e500 */
#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */
#define MCSR_ICPERR 0x40000000UL /* I-Cache Parity Error */
+
+/* e500v1/v2 */
#define MCSR_DCP_PERR 0x20000000UL /* D-Cache Push Parity Error */
#define MCSR_DCPERR 0x10000000UL /* D-Cache Parity Error */
#define MCSR_BUS_IAERR 0x00000080UL /* Instruction Address Error */
@@ -209,12 +219,20 @@
#define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */
#define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */
-/* e500 parts may set unused bits in MCSR; mask these off */
-#define MCSR_MASK (MCSR_MCP | MCSR_ICPERR | MCSR_DCP_PERR | \
- MCSR_DCPERR | MCSR_BUS_IAERR | MCSR_BUS_RAERR | \
- MCSR_BUS_WAERR | MCSR_BUS_IBERR | MCSR_BUS_RBERR | \
- MCSR_BUS_WBERR | MCSR_BUS_IPERR | MCSR_BUS_RPERR)
+/* e500mc */
+#define MCSR_DCPERR_MC 0x20000000UL /* D-Cache Parity Error */
+#define MCSR_L2MMU_MHIT 0x04000000UL /* Hit on multiple TLB entries */
+#define MCSR_NMI 0x00100000UL /* Non-Maskable Interrupt */
+#define MCSR_MAV 0x00080000UL /* MCAR address valid */
+#define MCSR_MEA 0x00040000UL /* MCAR is effective address */
+#define MCSR_IF 0x00010000UL /* Instruction Fetch */
+#define MCSR_LD 0x00008000UL /* Load */
+#define MCSR_ST 0x00004000UL /* Store */
+#define MCSR_LDG 0x00002000UL /* Guarded Load */
+#define MCSR_TLBSYNC 0x00000002UL /* Multiple tlbsyncs detected */
+#define MCSR_BSL2_ERR 0x00000001UL /* Backside L2 cache error */
#endif
+
#ifdef CONFIG_E200
#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */
#define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */
@@ -225,11 +243,6 @@
#define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */
#define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered
store or cache line push */
-
-/* e200 parts may set unused bits in MCSR; mask these off */
-#define MCSR_MASK (MCSR_MCP | MCSR_CP_PERR | MCSR_CPERR | \
- MCSR_EXCP_ERR | MCSR_BUS_IRERR | MCSR_BUS_DRERR | \
- MCSR_BUS_WRERR)
#endif
/* Bit definitions for the DBSR. */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 877326320e74..58d0572de6f9 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -57,8 +57,12 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_E500) += idle_e500.o
obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
obj-$(CONFIG_TAU) += tau_6xx.o
-obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \
- swsusp_$(CONFIG_WORD_SIZE).o
+obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o
+ifeq ($(CONFIG_FSL_BOOKE),y)
+obj-$(CONFIG_HIBERNATION) += swsusp_booke.o
+else
+obj-$(CONFIG_HIBERNATION) += swsusp_$(CONFIG_WORD_SIZE).o
+endif
obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o
obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_44x) += cpu_setup_44x.o
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 9556be903e96..87aa0f3c6047 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -1840,7 +1840,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.oprofile_cpu_type = "ppc/e500mc",
.oprofile_type = PPC_OPROFILE_FSL_EMB,
.cpu_setup = __setup_cpu_e500mc,
- .machine_check = machine_check_e500,
+ .machine_check = machine_check_e500mc,
.platform = "ppce500mc",
},
{ /* default match */
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c
index 8c066d6a8e4b..b46f2e09bd81 100644
--- a/arch/powerpc/kernel/crash.c
+++ b/arch/powerpc/kernel/crash.c
@@ -163,6 +163,7 @@ static void crash_kexec_prepare_cpus(int cpu)
}
/* wait for all the CPUs to hit real mode but timeout if they don't come in */
+#ifdef CONFIG_PPC_STD_MMU_64
static void crash_kexec_wait_realmode(int cpu)
{
unsigned int msecs;
@@ -187,6 +188,7 @@ static void crash_kexec_wait_realmode(int cpu)
}
mb();
}
+#endif
/*
* This function will be called by secondary cpus or by kexec cpu
@@ -445,7 +447,9 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
crash_kexec_prepare_cpus(crashing_cpu);
cpu_set(crashing_cpu, cpus_in_crash);
crash_kexec_stop_spus();
+#ifdef CONFIG_PPC_STD_MMU_64
crash_kexec_wait_realmode(crashing_cpu);
+#endif
if (ppc_md.kexec_cpu_down)
ppc_md.kexec_cpu_down(1, 0);
}
diff --git a/arch/powerpc/kernel/fsl_booke_entry_mapping.S b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
new file mode 100644
index 000000000000..beb4d78a2304
--- /dev/null
+++ b/arch/powerpc/kernel/fsl_booke_entry_mapping.S
@@ -0,0 +1,237 @@
+
+/* 1. Find the index of the entry we're executing in */
+ bl invstr /* Find our address */
+invstr: mflr r6 /* Make it accessible */
+ mfmsr r7
+ rlwinm r4,r7,27,31,31 /* extract MSR[IS] */
+ mfspr r7, SPRN_PID0
+ slwi r7,r7,16
+ or r7,r7,r4
+ mtspr SPRN_MAS6,r7
+ tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */
+ mfspr r7,SPRN_MAS1
+ andis. r7,r7,MAS1_VALID@h
+ bne match_TLB
+
+ mfspr r7,SPRN_MMUCFG
+ rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */
+ cmpwi r7,3
+ bne match_TLB /* skip if NPIDS != 3 */
+
+ mfspr r7,SPRN_PID1
+ slwi r7,r7,16
+ or r7,r7,r4
+ mtspr SPRN_MAS6,r7
+ tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */
+ mfspr r7,SPRN_MAS1
+ andis. r7,r7,MAS1_VALID@h
+ bne match_TLB
+ mfspr r7, SPRN_PID2
+ slwi r7,r7,16
+ or r7,r7,r4
+ mtspr SPRN_MAS6,r7
+ tlbsx 0,r6 /* Fall through, we had to match */
+
+match_TLB:
+ mfspr r7,SPRN_MAS0
+ rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */
+
+ mfspr r7,SPRN_MAS1 /* Insure IPROT set */
+ oris r7,r7,MAS1_IPROT@h
+ mtspr SPRN_MAS1,r7
+ tlbwe
+
+/* 2. Invalidate all entries except the entry we're executing in */
+ mfspr r9,SPRN_TLB1CFG
+ andi. r9,r9,0xfff
+ li r6,0 /* Set Entry counter to 0 */
+1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
+ rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */
+ mtspr SPRN_MAS0,r7
+ tlbre
+ mfspr r7,SPRN_MAS1
+ rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */
+ cmpw r3,r6
+ beq skpinv /* Dont update the current execution TLB */
+ mtspr SPRN_MAS1,r7
+ tlbwe
+ isync
+skpinv: addi r6,r6,1 /* Increment */
+ cmpw r6,r9 /* Are we done? */
+ bne 1b /* If not, repeat */
+
+ /* Invalidate TLB0 */
+ li r6,0x04
+ tlbivax 0,r6
+ TLBSYNC
+ /* Invalidate TLB1 */
+ li r6,0x0c
+ tlbivax 0,r6
+ TLBSYNC
+
+/* 3. Setup a temp mapping and jump to it */
+ andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */
+ addi r5, r5, 0x1
+ lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
+ rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */
+ mtspr SPRN_MAS0,r7
+ tlbre
+
+ /* grab and fixup the RPN */
+ mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */
+ rlwinm r6,r6,25,27,31
+ li r8,-1
+ addi r6,r6,10
+ slw r6,r8,r6 /* convert to mask */
+
+ bl 1f /* Find our address */
+1: mflr r7
+
+ mfspr r8,SPRN_MAS3
+#ifdef CONFIG_PHYS_64BIT
+ mfspr r23,SPRN_MAS7
+#endif
+ and r8,r6,r8
+ subfic r9,r6,-4096
+ and r9,r9,r7
+
+ or r25,r8,r9
+ ori r8,r25,(MAS3_SX|MAS3_SW|MAS3_SR)
+
+ /* Just modify the entry ID and EPN for the temp mapping */
+ lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
+ rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */
+ mtspr SPRN_MAS0,r7
+ xori r6,r4,1 /* Setup TMP mapping in the other Address space */
+ slwi r6,r6,12
+ oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h
+ ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l
+ mtspr SPRN_MAS1,r6
+ mfspr r6,SPRN_MAS2
+ li r7,0 /* temp EPN = 0 */
+ rlwimi r7,r6,0,20,31
+ mtspr SPRN_MAS2,r7
+ mtspr SPRN_MAS3,r8
+ tlbwe
+
+ xori r6,r4,1
+ slwi r6,r6,5 /* setup new context with other address space */
+ bl 1f /* Find our address */
+1: mflr r9
+ rlwimi r7,r9,0,20,31
+ addi r7,r7,(2f - 1b)
+ mtspr SPRN_SRR0,r7
+ mtspr SPRN_SRR1,r6
+ rfi
+2:
+/* 4. Clear out PIDs & Search info */
+ li r6,0
+ mtspr SPRN_MAS6,r6
+ mtspr SPRN_PID0,r6
+
+ mfspr r7,SPRN_MMUCFG
+ rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */
+ cmpwi r7,3
+ bne 2f /* skip if NPIDS != 3 */
+
+ mtspr SPRN_PID1,r6
+ mtspr SPRN_PID2,r6
+
+/* 5. Invalidate mapping we started in */
+2:
+ lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
+ rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */
+ mtspr SPRN_MAS0,r7
+ tlbre
+ mfspr r6,SPRN_MAS1
+ rlwinm r6,r6,0,2,0 /* clear IPROT */
+ mtspr SPRN_MAS1,r6
+ tlbwe
+ /* Invalidate TLB1 */
+ li r9,0x0c
+ tlbivax 0,r9
+ TLBSYNC
+
+/* The mapping only needs to be cache-coherent on SMP */
+#ifdef CONFIG_SMP
+#define M_IF_SMP MAS2_M
+#else
+#define M_IF_SMP 0
+#endif
+
+#if defined(ENTRY_MAPPING_BOOT_SETUP)
+
+/* 6. Setup KERNELBASE mapping in TLB1[0] */
+ lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
+ mtspr SPRN_MAS0,r6
+ lis r6,(MAS1_VALID|MAS1_IPROT)@h
+ ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l
+ mtspr SPRN_MAS1,r6
+ lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h
+ ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l
+ mtspr SPRN_MAS2,r6
+ mtspr SPRN_MAS3,r8
+ tlbwe
+
+/* 7. Jump to KERNELBASE mapping */
+ lis r6,(KERNELBASE & ~0xfff)@h
+ ori r6,r6,(KERNELBASE & ~0xfff)@l
+
+#elif defined(ENTRY_MAPPING_KEXEC_SETUP)
+/*
+ * 6. Setup a 1:1 mapping in TLB1. Esel 0 is unsued, 1 or 2 contains the tmp
+ * mapping so we start at 3. We setup 8 mappings, each 256MiB in size. This
+ * will cover the first 2GiB of memory.
+ */
+
+ lis r10, (MAS1_VALID|MAS1_IPROT)@h
+ ori r10,r10, (MAS1_TSIZE(BOOK3E_PAGESZ_256M))@l
+ li r11, 0
+ li r0, 8
+ mtctr r0
+
+next_tlb_setup:
+ addi r0, r11, 3
+ rlwinm r0, r0, 16, 4, 15 // Compute esel
+ rlwinm r9, r11, 28, 0, 3 // Compute [ER]PN
+ oris r0, r0, (MAS0_TLBSEL(1))@h
+ mtspr SPRN_MAS0,r0
+ mtspr SPRN_MAS1,r10
+ mtspr SPRN_MAS2,r9
+ ori r9, r9, (MAS3_SX|MAS3_SW|MAS3_SR)
+ mtspr SPRN_MAS3,r9
+ tlbwe
+ addi r11, r11, 1
+ bdnz+ next_tlb_setup
+
+/* 7. Jump to our 1:1 mapping */
+ li r6, 0
+
+#else
+ #error You need to specify the mapping or not use this at all.
+#endif
+
+ lis r7,MSR_KERNEL@h
+ ori r7,r7,MSR_KERNEL@l
+ bl 1f /* Find our address */
+1: mflr r9
+ rlwimi r6,r9,0,20,31
+ addi r6,r6,(2f - 1b)
+ add r6, r6, r25
+ mtspr SPRN_SRR0,r6
+ mtspr SPRN_SRR1,r7
+ rfi /* start execution out of TLB1[0] entry */
+
+/* 8. Clear out the temp mapping */
+2: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
+ rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */
+ mtspr SPRN_MAS0,r7
+ tlbre
+ mfspr r8,SPRN_MAS1
+ rlwinm r8,r8,0,2,0 /* clear IPROT */
+ mtspr SPRN_MAS1,r8
+ tlbwe
+ /* Invalidate TLB1 */
+ li r9,0x0c
+ tlbivax 0,r9
+ TLBSYNC
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index edd4a57fd29e..4faeba247854 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -94,204 +94,10 @@ _ENTRY(_start);
*/
_ENTRY(__early_start)
-/* 1. Find the index of the entry we're executing in */
- bl invstr /* Find our address */
-invstr: mflr r6 /* Make it accessible */
- mfmsr r7
- rlwinm r4,r7,27,31,31 /* extract MSR[IS] */
- mfspr r7, SPRN_PID0
- slwi r7,r7,16
- or r7,r7,r4
- mtspr SPRN_MAS6,r7
- tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */
- mfspr r7,SPRN_MAS1
- andis. r7,r7,MAS1_VALID@h
- bne match_TLB
-
- mfspr r7,SPRN_MMUCFG
- rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */
- cmpwi r7,3
- bne match_TLB /* skip if NPIDS != 3 */
-
- mfspr r7,SPRN_PID1
- slwi r7,r7,16
- or r7,r7,r4
- mtspr SPRN_MAS6,r7
- tlbsx 0,r6 /* search MSR[IS], SPID=PID1 */
- mfspr r7,SPRN_MAS1
- andis. r7,r7,MAS1_VALID@h
- bne match_TLB
- mfspr r7, SPRN_PID2
- slwi r7,r7,16
- or r7,r7,r4
- mtspr SPRN_MAS6,r7
- tlbsx 0,r6 /* Fall through, we had to match */
-
-match_TLB:
- mfspr r7,SPRN_MAS0
- rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */
-
- mfspr r7,SPRN_MAS1 /* Insure IPROT set */
- oris r7,r7,MAS1_IPROT@h
- mtspr SPRN_MAS1,r7
- tlbwe
-
-/* 2. Invalidate all entries except the entry we're executing in */
- mfspr r9,SPRN_TLB1CFG
- andi. r9,r9,0xfff
- li r6,0 /* Set Entry counter to 0 */
-1: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
- rlwimi r7,r6,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r6) */
- mtspr SPRN_MAS0,r7
- tlbre
- mfspr r7,SPRN_MAS1
- rlwinm r7,r7,0,2,31 /* Clear MAS1 Valid and IPROT */
- cmpw r3,r6
- beq skpinv /* Dont update the current execution TLB */
- mtspr SPRN_MAS1,r7
- tlbwe
- isync
-skpinv: addi r6,r6,1 /* Increment */
- cmpw r6,r9 /* Are we done? */
- bne 1b /* If not, repeat */
-
- /* Invalidate TLB0 */
- li r6,0x04
- tlbivax 0,r6
- TLBSYNC
- /* Invalidate TLB1 */
- li r6,0x0c
- tlbivax 0,r6
- TLBSYNC
-
-/* 3. Setup a temp mapping and jump to it */
- andi. r5, r3, 0x1 /* Find an entry not used and is non-zero */
- addi r5, r5, 0x1
- lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
- rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */
- mtspr SPRN_MAS0,r7
- tlbre
-
- /* grab and fixup the RPN */
- mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */
- rlwinm r6,r6,25,27,31
- li r8,-1
- addi r6,r6,10
- slw r6,r8,r6 /* convert to mask */
-
- bl 1f /* Find our address */
-1: mflr r7
-
- mfspr r8,SPRN_MAS3
-#ifdef CONFIG_PHYS_64BIT
- mfspr r23,SPRN_MAS7
-#endif
- and r8,r6,r8
- subfic r9,r6,-4096
- and r9,r9,r7
-
- or r25,r8,r9
- ori r8,r25,(MAS3_SX|MAS3_SW|MAS3_SR)
-
- /* Just modify the entry ID and EPN for the temp mapping */
- lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
- rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */
- mtspr SPRN_MAS0,r7
- xori r6,r4,1 /* Setup TMP mapping in the other Address space */
- slwi r6,r6,12
- oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h
- ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l
- mtspr SPRN_MAS1,r6
- mfspr r6,SPRN_MAS2
- li r7,0 /* temp EPN = 0 */
- rlwimi r7,r6,0,20,31
- mtspr SPRN_MAS2,r7
- mtspr SPRN_MAS3,r8
- tlbwe
-
- xori r6,r4,1
- slwi r6,r6,5 /* setup new context with other address space */
- bl 1f /* Find our address */
-1: mflr r9
- rlwimi r7,r9,0,20,31
- addi r7,r7,(2f - 1b)
- mtspr SPRN_SRR0,r7
- mtspr SPRN_SRR1,r6
- rfi
-2:
-/* 4. Clear out PIDs & Search info */
- li r6,0
- mtspr SPRN_MAS6,r6
- mtspr SPRN_PID0,r6
-
- mfspr r7,SPRN_MMUCFG
- rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */
- cmpwi r7,3
- bne 2f /* skip if NPIDS != 3 */
- mtspr SPRN_PID1,r6
- mtspr SPRN_PID2,r6
-
-/* 5. Invalidate mapping we started in */
-2:
- lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
- rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */
- mtspr SPRN_MAS0,r7
- tlbre
- mfspr r6,SPRN_MAS1
- rlwinm r6,r6,0,2,0 /* clear IPROT */
- mtspr SPRN_MAS1,r6
- tlbwe
- /* Invalidate TLB1 */
- li r9,0x0c
- tlbivax 0,r9
- TLBSYNC
-
-/* The mapping only needs to be cache-coherent on SMP */
-#ifdef CONFIG_SMP
-#define M_IF_SMP MAS2_M
-#else
-#define M_IF_SMP 0
-#endif
-
-/* 6. Setup KERNELBASE mapping in TLB1[0] */
- lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */
- mtspr SPRN_MAS0,r6
- lis r6,(MAS1_VALID|MAS1_IPROT)@h
- ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l
- mtspr SPRN_MAS1,r6
- lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h
- ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l
- mtspr SPRN_MAS2,r6
- mtspr SPRN_MAS3,r8
- tlbwe
-
-/* 7. Jump to KERNELBASE mapping */
- lis r6,(KERNELBASE & ~0xfff)@h
- ori r6,r6,(KERNELBASE & ~0xfff)@l
- lis r7,MSR_KERNEL@h
- ori r7,r7,MSR_KERNEL@l
- bl 1f /* Find our address */
-1: mflr r9
- rlwimi r6,r9,0,20,31
- addi r6,r6,(2f - 1b)
- mtspr SPRN_SRR0,r6
- mtspr SPRN_SRR1,r7
- rfi /* start execution out of TLB1[0] entry */
-
-/* 8. Clear out the temp mapping */
-2: lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */
- rlwimi r7,r5,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r5) */
- mtspr SPRN_MAS0,r7
- tlbre
- mfspr r8,SPRN_MAS1
- rlwinm r8,r8,0,2,0 /* clear IPROT */
- mtspr SPRN_MAS1,r8
- tlbwe
- /* Invalidate TLB1 */
- li r9,0x0c
- tlbivax 0,r9
- TLBSYNC
+#define ENTRY_MAPPING_BOOT_SETUP
+#include "fsl_booke_entry_mapping.S"
+#undef ENTRY_MAPPING_BOOT_SETUP
/* Establish the interrupt vector offsets */
SET_IVOR(0, CriticalInput);
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index c533525ca56a..bc47352deb1f 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -378,17 +378,6 @@ static int __kprobes trampoline_probe_handler(struct kprobe *p,
* single-stepped a copy of the instruction. The address of this
* copy is p->ainsn.insn.
*/
-static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
-{
- int ret;
- unsigned int insn = *p->ainsn.insn;
-
- regs->nip = (unsigned long)p->addr;
- ret = emulate_step(regs, insn);
- if (ret == 0)
- regs->nip = (unsigned long)p->addr + 4;
-}
-
static int __kprobes post_kprobe_handler(struct pt_regs *regs)
{
struct kprobe *cur = kprobe_running();
@@ -406,7 +395,8 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs)
cur->post_handler(cur, regs, 0);
}
- resume_execution(cur, regs);
+ /* Adjust nip to after the single-stepped instruction */
+ regs->nip = (unsigned long)cur->addr + 4;
regs->msr |= kcb->kprobe_saved_msr;
/*Restore back the original saved kprobes variables and continue. */
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 8043d1b73cf0..dc66d52dcff5 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -711,6 +711,22 @@ relocate_new_kernel:
/* r4 = reboot_code_buffer */
/* r5 = start_address */
+#ifdef CONFIG_FSL_BOOKE
+
+ mr r29, r3
+ mr r30, r4
+ mr r31, r5
+
+#define ENTRY_MAPPING_KEXEC_SETUP
+#include "fsl_booke_entry_mapping.S"
+#undef ENTRY_MAPPING_KEXEC_SETUP
+
+ mr r3, r29
+ mr r4, r30
+ mr r5, r31
+
+ li r0, 0
+#else
li r0, 0
/*
@@ -727,6 +743,7 @@ relocate_new_kernel:
rfi
1:
+#endif
/* from this point address translation is turned off */
/* and interrupts are disabled */
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index bc9f39d2598b..3b4dcc82a4c1 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -101,7 +101,7 @@ EXPORT_SYMBOL(pci_dram_offset);
EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(kernel_thread);
-#ifndef CONFIG_BOOKE
+#ifdef CONFIG_PPC_FPU
EXPORT_SYMBOL_GPL(cvt_df);
EXPORT_SYMBOL_GPL(cvt_fd);
#endif
diff --git a/arch/powerpc/kernel/swsusp_booke.S b/arch/powerpc/kernel/swsusp_booke.S
new file mode 100644
index 000000000000..11a39307dd71
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_booke.S
@@ -0,0 +1,193 @@
+/*
+ * Based on swsusp_32.S, modified for FSL BookE by
+ * Anton Vorontsov <avorontsov@ru.mvista.com>
+ * Copyright (c) 2009-2010 MontaVista Software, LLC.
+ */
+
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/mmu.h>
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_SP 0
+#define SL_PC 4
+#define SL_MSR 8
+#define SL_TCR 0xc
+#define SL_SPRG0 0x10
+#define SL_SPRG1 0x14
+#define SL_SPRG2 0x18
+#define SL_SPRG3 0x1c
+#define SL_SPRG4 0x20
+#define SL_SPRG5 0x24
+#define SL_SPRG6 0x28
+#define SL_SPRG7 0x2c
+#define SL_TBU 0x30
+#define SL_TBL 0x34
+#define SL_R2 0x38
+#define SL_CR 0x3c
+#define SL_LR 0x40
+#define SL_R12 0x44 /* r12 to r31 */
+#define SL_SIZE (SL_R12 + 80)
+
+ .section .data
+ .align 5
+
+_GLOBAL(swsusp_save_area)
+ .space SL_SIZE
+
+
+ .section .text
+ .align 5
+
+_GLOBAL(swsusp_arch_suspend)
+ lis r11,swsusp_save_area@h
+ ori r11,r11,swsusp_save_area@l
+
+ mflr r0
+ stw r0,SL_LR(r11)
+ mfcr r0
+ stw r0,SL_CR(r11)
+ stw r1,SL_SP(r11)
+ stw r2,SL_R2(r11)
+ stmw r12,SL_R12(r11)
+
+ /* Save MSR & TCR */
+ mfmsr r4
+ stw r4,SL_MSR(r11)
+ mfspr r4,SPRN_TCR
+ stw r4,SL_TCR(r11)
+
+ /* Get a stable timebase and save it */
+1: mfspr r4,SPRN_TBRU
+ stw r4,SL_TBU(r11)
+ mfspr r5,SPRN_TBRL
+ stw r5,SL_TBL(r11)
+ mfspr r3,SPRN_TBRU
+ cmpw r3,r4
+ bne 1b
+
+ /* Save SPRGs */
+ mfsprg r4,0
+ stw r4,SL_SPRG0(r11)
+ mfsprg r4,1
+ stw r4,SL_SPRG1(r11)
+ mfsprg r4,2
+ stw r4,SL_SPRG2(r11)
+ mfsprg r4,3
+ stw r4,SL_SPRG3(r11)
+ mfsprg r4,4
+ stw r4,SL_SPRG4(r11)
+ mfsprg r4,5
+ stw r4,SL_SPRG5(r11)
+ mfsprg r4,6
+ stw r4,SL_SPRG6(r11)
+ mfsprg r4,7
+ stw r4,SL_SPRG7(r11)
+
+ /* Call the low level suspend stuff (we should probably have made
+ * a stackframe...
+ */
+ bl swsusp_save
+
+ /* Restore LR from the save area */
+ lis r11,swsusp_save_area@h
+ ori r11,r11,swsusp_save_area@l
+ lwz r0,SL_LR(r11)
+ mtlr r0
+
+ blr
+
+_GLOBAL(swsusp_arch_resume)
+ sync
+
+ /* Load ptr the list of pages to copy in r3 */
+ lis r11,(restore_pblist)@h
+ ori r11,r11,restore_pblist@l
+ lwz r3,0(r11)
+
+ /* Copy the pages. This is a very basic implementation, to
+ * be replaced by something more cache efficient */
+1:
+ li r0,256
+ mtctr r0
+ lwz r5,pbe_address(r3) /* source */
+ lwz r6,pbe_orig_address(r3) /* destination */
+2:
+ lwz r8,0(r5)
+ lwz r9,4(r5)
+ lwz r10,8(r5)
+ lwz r11,12(r5)
+ addi r5,r5,16
+ stw r8,0(r6)
+ stw r9,4(r6)
+ stw r10,8(r6)
+ stw r11,12(r6)
+ addi r6,r6,16
+ bdnz 2b
+ lwz r3,pbe_next(r3)
+ cmpwi 0,r3,0
+ bne 1b
+
+ bl flush_dcache_L1
+ bl flush_instruction_cache
+
+ lis r11,swsusp_save_area@h
+ ori r11,r11,swsusp_save_area@l
+
+ lwz r4,SL_SPRG0(r11)
+ mtsprg 0,r4
+ lwz r4,SL_SPRG1(r11)
+ mtsprg 1,r4
+ lwz r4,SL_SPRG2(r11)
+ mtsprg 2,r4
+ lwz r4,SL_SPRG3(r11)
+ mtsprg 3,r4
+ lwz r4,SL_SPRG4(r11)
+ mtsprg 4,r4
+ lwz r4,SL_SPRG5(r11)
+ mtsprg 5,r4
+ lwz r4,SL_SPRG6(r11)
+ mtsprg 6,r4
+ lwz r4,SL_SPRG7(r11)
+ mtsprg 7,r4
+
+ /* restore the MSR */
+ lwz r3,SL_MSR(r11)
+ mtmsr r3
+
+ /* Restore TB */
+ li r3,0
+ mtspr SPRN_TBWL,r3
+ lwz r3,SL_TBU(r11)
+ lwz r4,SL_TBL(r11)
+ mtspr SPRN_TBWU,r3
+ mtspr SPRN_TBWL,r4
+
+ /* Restore TCR and clear any pending bits in TSR. */
+ lwz r4,SL_TCR(r11)
+ mtspr SPRN_TCR,r4
+ lis r4, (TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS)@h
+ mtspr SPRN_TSR,r4
+
+ /* Kick decrementer */
+ li r0,1
+ mtdec r0
+
+ /* Restore the callee-saved registers and return */
+ lwz r0,SL_CR(r11)
+ mtcr r0
+ lwz r2,SL_R2(r11)
+ lmw r12,SL_R12(r11)
+ lwz r1,SL_SP(r11)
+ lwz r0,SL_LR(r11)
+ mtlr r0
+
+ li r3,0
+ blr
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 3031fc712ad0..25fc33984c2b 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ * Copyright 2007-2010 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -305,7 +306,7 @@ static inline int check_io_access(struct pt_regs *regs)
#ifndef CONFIG_FSL_BOOKE
#define get_mc_reason(regs) ((regs)->dsisr)
#else
-#define get_mc_reason(regs) (mfspr(SPRN_MCSR) & MCSR_MASK)
+#define get_mc_reason(regs) (mfspr(SPRN_MCSR))
#endif
#define REASON_FP ESR_FP
#define REASON_ILLEGAL (ESR_PIL | ESR_PUO)
@@ -421,6 +422,91 @@ int machine_check_47x(struct pt_regs *regs)
return 0;
}
#elif defined(CONFIG_E500)
+int machine_check_e500mc(struct pt_regs *regs)
+{
+ unsigned long mcsr = mfspr(SPRN_MCSR);
+ unsigned long reason = mcsr;
+ int recoverable = 1;
+
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from MCSR=%lx): ", reason);
+
+ if (reason & MCSR_MCP)
+ printk("Machine Check Signal\n");
+
+ if (reason & MCSR_ICPERR) {
+ printk("Instruction Cache Parity Error\n");
+
+ /*
+ * This is recoverable by invalidating the i-cache.
+ */
+ mtspr(SPRN_L1CSR1, mfspr(SPRN_L1CSR1) | L1CSR1_ICFI);
+ while (mfspr(SPRN_L1CSR1) & L1CSR1_ICFI)
+ ;
+
+ /*
+ * This will generally be accompanied by an instruction
+ * fetch error report -- only treat MCSR_IF as fatal
+ * if it wasn't due to an L1 parity error.
+ */
+ reason &= ~MCSR_IF;
+ }
+
+ if (reason & MCSR_DCPERR_MC) {
+ printk("Data Cache Parity Error\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_L2MMU_MHIT) {
+ printk("Hit on multiple TLB entries\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_NMI)
+ printk("Non-maskable interrupt\n");
+
+ if (reason & MCSR_IF) {
+ printk("Instruction Fetch Error Report\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_LD) {
+ printk("Load Error Report\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_ST) {
+ printk("Store Error Report\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_LDG) {
+ printk("Guarded Load Error Report\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_TLBSYNC)
+ printk("Simultaneous tlbsync operations\n");
+
+ if (reason & MCSR_BSL2_ERR) {
+ printk("Level 2 Cache Error\n");
+ recoverable = 0;
+ }
+
+ if (reason & MCSR_MAV) {
+ u64 addr;
+
+ addr = mfspr(SPRN_MCAR);
+ addr |= (u64)mfspr(SPRN_MCARU) << 32;
+
+ printk("Machine Check %s Address: %#llx\n",
+ reason & MCSR_MEA ? "Effective" : "Physical", addr);
+ }
+
+ mtspr(SPRN_MCSR, mcsr);
+ return mfspr(SPRN_MCSR) == 0 && recoverable;
+}
+
int machine_check_e500(struct pt_regs *regs)
{
unsigned long reason = get_mc_reason(regs);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index dcd01c82e701..8a0deefac08d 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -223,19 +223,17 @@ SECTIONS
#endif
/* The initial task and kernel stack */
- .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
- INIT_TASK_DATA(THREAD_SIZE)
- }
+ INIT_TASK_DATA_SECTION(THREAD_SIZE)
- .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+ .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) {
PAGE_ALIGNED_DATA(PAGE_SIZE)
}
- .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+ .data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET) {
CACHELINE_ALIGNED_DATA(L1_CACHE_BYTES)
}
- .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+ .data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET) {
READ_MOSTLY_DATA(L1_CACHE_BYTES)
}
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index bc2b4004eb26..e8a00b0c4449 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -164,7 +164,7 @@ static int __init kvmppc_e500_init(void)
return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
}
-static void __init kvmppc_e500_exit(void)
+static void __exit kvmppc_e500_exit(void)
{
kvmppc_booke_exit();
}
diff --git a/arch/powerpc/oprofile/op_model_cell.c b/arch/powerpc/oprofile/op_model_cell.c
index 2c9e52267292..7fd90d02d8c6 100644
--- a/arch/powerpc/oprofile/op_model_cell.c
+++ b/arch/powerpc/oprofile/op_model_cell.c
@@ -1077,7 +1077,7 @@ static int calculate_lfsr(int n)
index = ENTRIES-1;
/* make sure index is valid */
- if ((index > ENTRIES) || (index < 0))
+ if ((index >= ENTRIES) || (index < 0))
index = ENTRIES-1;
return initial_lfsr[index];
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index eeba0a70e466..69d668c072ae 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -171,6 +171,17 @@ config ISS4xx
help
This option enables support for the IBM ISS simulation environment
+config ICON
+ bool "Icon"
+ depends on 44x
+ default n
+ select PPC44x_SIMPLE
+ select 440SPe
+ select PCI
+ select PPC4xx_PCI_EXPRESS
+ help
+ This option enables support for the AMCC PPC440SPe evaluation board.
+
#config LUAN
# bool "Luan"
# depends on 44x
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
index e8c23ccaa1fc..5f7a29d7f590 100644
--- a/arch/powerpc/platforms/44x/ppc44x_simple.c
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -61,7 +61,8 @@ static char *board[] __initdata = {
"amcc,redwood",
"amcc,sequoia",
"amcc,taishan",
- "amcc,yosemite"
+ "amcc,yosemite",
+ "mosaixtech,icon"
};
static int __init ppc44x_probe(void)
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0525a4..e9dca280a4d2 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -1,29 +1,24 @@
config PPC_MPC512x
- bool
+ bool "512x-based boards"
+ depends on 6xx
select FSL_SOC
select IPIC
select PPC_CLOCK
select PPC_PCI_CHOICE
select FSL_PCI if PCI
-config PPC_MPC5121
- bool
- select PPC_MPC512x
-
config MPC5121_ADS
bool "Freescale MPC5121E ADS"
- depends on 6xx
+ depends on PPC_MPC512x
select DEFAULT_UIMAGE
- select PPC_MPC5121
select MPC5121_ADS_CPLD
help
This option enables support for the MPC5121E ADS board.
config MPC5121_GENERIC
bool "Generic support for simple MPC5121 based boards"
- depends on 6xx
+ depends on PPC_MPC512x
select DEFAULT_UIMAGE
- select PPC_MPC5121
help
This option enables support for simple MPC5121 based boards
which do not need custom platform specific setup.
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index f0684c8ac960..8fe87fc61485 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) Freescale Semicondutor, Inc. 2006-2007. All rights reserved.
+ * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved.
*
* Author: Andy Fleming <afleming@freescale.com>
*
@@ -154,6 +154,10 @@ static int mpc8568_mds_phy_fixups(struct phy_device *phydev)
* Setup the architecture
*
*/
+#ifdef CONFIG_SMP
+extern void __init mpc85xx_smp_init(void);
+#endif
+
static void __init mpc85xx_mds_setup_arch(void)
{
struct device_node *np;
@@ -194,6 +198,10 @@ static void __init mpc85xx_mds_setup_arch(void)
}
#endif
+#ifdef CONFIG_SMP
+ mpc85xx_smp_init();
+#endif
+
#ifdef CONFIG_QUICC_ENGINE
np = of_find_compatible_node(NULL, NULL, "fsl,qe");
if (!np) {
@@ -271,9 +279,49 @@ static void __init mpc85xx_mds_setup_arch(void)
BCSR_UCC_RGMII, BCSR_UCC_RTBI);
}
+ } else if (machine_is(p1021_mds)) {
+#define BCSR11_ENET_MICRST (0x1 << 5)
+ /* Reset Micrel PHY */
+ clrbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
+ setbits8(&bcsr_regs[11], BCSR11_ENET_MICRST);
}
+
iounmap(bcsr_regs);
}
+
+ if (machine_is(p1021_mds)) {
+#define MPC85xx_PMUXCR_OFFSET 0x60
+#define MPC85xx_PMUXCR_QE0 0x00008000
+#define MPC85xx_PMUXCR_QE3 0x00001000
+#define MPC85xx_PMUXCR_QE9 0x00000040
+#define MPC85xx_PMUXCR_QE12 0x00000008
+ static __be32 __iomem *pmuxcr;
+
+ np = of_find_node_by_name(NULL, "global-utilities");
+
+ if (np) {
+ pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET;
+
+ if (!pmuxcr)
+ printk(KERN_EMERG "Error: Alternate function"
+ " signal multiplex control register not"
+ " mapped!\n");
+ else
+ /* P1021 has pins muxed for QE and other functions. To
+ * enable QE UEC mode, we need to set bit QE0 for UCC1
+ * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
+ * and QE12 for QE MII management singals in PMUXCR
+ * register.
+ */
+ setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 |
+ MPC85xx_PMUXCR_QE3 |
+ MPC85xx_PMUXCR_QE9 |
+ MPC85xx_PMUXCR_QE12);
+
+ of_node_put(np);
+ }
+
+ }
#endif /* CONFIG_QUICC_ENGINE */
#ifdef CONFIG_SWIOTLB
@@ -330,6 +378,16 @@ static struct of_device_id mpc85xx_ids[] = {
{},
};
+static struct of_device_id p1021_ids[] = {
+ { .type = "soc", },
+ { .compatible = "soc", },
+ { .compatible = "simple-bus", },
+ { .type = "qe", },
+ { .compatible = "fsl,qe", },
+ { .compatible = "gianfar", },
+ {},
+};
+
static int __init mpc85xx_publish_devices(void)
{
if (machine_is(mpc8568_mds))
@@ -342,11 +400,22 @@ static int __init mpc85xx_publish_devices(void)
return 0;
}
+
+static int __init p1021_publish_devices(void)
+{
+ /* Publish the QE devices */
+ of_platform_bus_probe(NULL, p1021_ids, NULL);
+
+ return 0;
+}
+
machine_device_initcall(mpc8568_mds, mpc85xx_publish_devices);
machine_device_initcall(mpc8569_mds, mpc85xx_publish_devices);
+machine_device_initcall(p1021_mds, p1021_publish_devices);
machine_arch_initcall(mpc8568_mds, swiotlb_setup_bus_notifier);
machine_arch_initcall(mpc8569_mds, swiotlb_setup_bus_notifier);
+machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier);
static void __init mpc85xx_mds_pic_init(void)
{
@@ -366,7 +435,7 @@ static void __init mpc85xx_mds_pic_init(void)
mpic = mpic_alloc(np, r.start,
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN |
- MPIC_BROKEN_FRR_NIRQS,
+ MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU,
0, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
of_node_put(np);
@@ -380,7 +449,11 @@ static void __init mpc85xx_mds_pic_init(void)
if (!np)
return;
}
- qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
+ if (machine_is(p1021_mds))
+ qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+ qe_ic_cascade_high_mpic);
+ else
+ qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
of_node_put(np);
#endif /* CONFIG_QUICC_ENGINE */
}
@@ -426,3 +499,26 @@ define_machine(mpc8569_mds) {
.pcibios_fixup_bus = fsl_pcibios_fixup_bus,
#endif
};
+
+static int __init p1021_mds_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ return of_flat_dt_is_compatible(root, "fsl,P1021MDS");
+
+}
+
+define_machine(p1021_mds) {
+ .name = "P1021 MDS",
+ .probe = p1021_mds_probe,
+ .setup_arch = mpc85xx_mds_setup_arch,
+ .init_IRQ = mpc85xx_mds_pic_init,
+ .get_irq = mpic_get_irq,
+ .restart = fsl_rstcr_restart,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+#ifdef CONFIG_PCI
+ .pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+#endif
+};
+
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 22667a09d40e..4326b737d913 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -1066,7 +1066,7 @@ static int __init cell_iommu_fixed_mapping_init(void)
fbase = _ALIGN_UP(fbase, 1 << IO_SEGMENT_SHIFT);
fsize = lmb_phys_mem_size();
- if ((fbase + fsize) <= 0x800000000)
+ if ((fbase + fsize) <= 0x800000000ul)
hbase = 0; /* use the device tree window */
else {
/* If we're over 32 GB we need to cheat. We can't map all of
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index e5e5f823d687..32625f366fb5 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -110,7 +110,9 @@ spufs_setattr(struct dentry *dentry, struct iattr *attr)
if ((attr->ia_valid & ATTR_SIZE) &&
(attr->ia_size != inode->i_size))
return -EINVAL;
- return inode_setattr(inode, attr);
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index a7be144f5874..962c2d8dd8d9 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007-2008 Freescale Semiconductor, Inc. All rights reserved.
+ * Copyright (C) 2007-2010 Freescale Semiconductor, Inc.
*
* Author: Tony Li <tony.li@freescale.com>
* Jason Jin <Jason.jin@freescale.com>
@@ -22,14 +22,20 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
+#include <asm/mpic.h>
#include "fsl_msi.h"
+LIST_HEAD(msi_head);
+
struct fsl_msi_feature {
u32 fsl_pic_ip;
u32 msiir_offset;
};
-static struct fsl_msi *fsl_msi;
+struct fsl_msi_cascade_data {
+ struct fsl_msi *msi_data;
+ int index;
+};
static inline u32 fsl_msi_read(u32 __iomem *base, unsigned int reg)
{
@@ -54,10 +60,12 @@ static struct irq_chip fsl_msi_chip = {
static int fsl_msi_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
+ struct fsl_msi *msi_data = h->host_data;
struct irq_chip *chip = &fsl_msi_chip;
irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING;
+ set_irq_chip_data(virq, msi_data);
set_irq_chip_and_handler(virq, chip, handle_edge_irq);
return 0;
@@ -96,11 +104,12 @@ static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
if (entry->irq == NO_IRQ)
continue;
+ msi_data = get_irq_data(entry->irq);
set_irq_msi(entry->irq, NULL);
msi_bitmap_free_hwirqs(&msi_data->bitmap,
virq_to_hw(entry->irq), 1);
@@ -111,9 +120,10 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
}
static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
- struct msi_msg *msg)
+ struct msi_msg *msg,
+ struct fsl_msi *fsl_msi_data)
{
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data = fsl_msi_data;
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
u32 base = 0;
@@ -130,14 +140,19 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
- int rc, hwirq;
+ int rc, hwirq = -ENOMEM;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
list_for_each_entry(entry, &pdev->msi_list, list) {
- hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ list_for_each_entry(msi_data, &msi_head, list) {
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
+ if (hwirq >= 0)
+ break;
+ }
+
if (hwirq < 0) {
rc = hwirq;
pr_debug("%s: fail allocating msi interrupt\n",
@@ -154,25 +169,31 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
rc = -ENOSPC;
goto out_free;
}
+ set_irq_data(virq, msi_data);
set_irq_msi(virq, entry);
- fsl_compose_msi_msg(pdev, hwirq, &msg);
+ fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
write_msi_msg(virq, &msg);
}
return 0;
out_free:
+ /* free by the caller of this function */
return rc;
}
static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
{
unsigned int cascade_irq;
- struct fsl_msi *msi_data = fsl_msi;
+ struct fsl_msi *msi_data;
int msir_index = -1;
u32 msir_value = 0;
u32 intr_index;
u32 have_shift = 0;
+ struct fsl_msi_cascade_data *cascade_data;
+
+ cascade_data = (struct fsl_msi_cascade_data *)get_irq_data(irq);
+ msi_data = cascade_data->msi_data;
raw_spin_lock(&desc->lock);
if ((msi_data->feature & FSL_PIC_IP_MASK) == FSL_PIC_IP_IPIC) {
@@ -187,13 +208,13 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
if (unlikely(desc->status & IRQ_INPROGRESS))
goto unlock;
- msir_index = (int)desc->handler_data;
+ msir_index = cascade_data->index;
if (msir_index >= NR_MSI_REG)
cascade_irq = NO_IRQ;
desc->status |= IRQ_INPROGRESS;
- switch (fsl_msi->feature & FSL_PIC_IP_MASK) {
+ switch (msi_data->feature & FSL_PIC_IP_MASK) {
case FSL_PIC_IP_MPIC:
msir_value = fsl_msi_read(msi_data->msi_regs,
msir_index * 0x10);
@@ -229,6 +250,30 @@ unlock:
raw_spin_unlock(&desc->lock);
}
+static int fsl_of_msi_remove(struct of_device *ofdev)
+{
+ struct fsl_msi *msi = ofdev->dev.platform_data;
+ int virq, i;
+ struct fsl_msi_cascade_data *cascade_data;
+
+ if (msi->list.prev != NULL)
+ list_del(&msi->list);
+ for (i = 0; i < NR_MSI_REG; i++) {
+ virq = msi->msi_virqs[i];
+ if (virq != NO_IRQ) {
+ cascade_data = get_irq_data(virq);
+ kfree(cascade_data);
+ irq_dispose_mapping(virq);
+ }
+ }
+ if (msi->bitmap.bitmap)
+ msi_bitmap_free(&msi->bitmap);
+ iounmap(msi->msi_regs);
+ kfree(msi);
+
+ return 0;
+}
+
static int __devinit fsl_of_msi_probe(struct of_device *dev,
const struct of_device_id *match)
{
@@ -239,15 +284,18 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
int virt_msir;
const u32 *p;
struct fsl_msi_feature *features = match->data;
+ struct fsl_msi_cascade_data *cascade_data = NULL;
+ int len;
+ u32 offset;
printk(KERN_DEBUG "Setting up Freescale MSI support\n");
msi = kzalloc(sizeof(struct fsl_msi), GFP_KERNEL);
if (!msi) {
dev_err(&dev->dev, "No memory for MSI structure\n");
- err = -ENOMEM;
- goto error_out;
+ return -ENOMEM;
}
+ dev->dev.platform_data = msi;
msi->irqhost = irq_alloc_host(dev->dev.of_node, IRQ_HOST_MAP_LINEAR,
NR_MSI_IRQS, &fsl_msi_host_ops, 0);
@@ -298,27 +346,47 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
err = -EINVAL;
goto error_out;
}
+ offset = 0;
+ p = of_get_property(dev->dev.of_node, "msi-available-ranges", &len);
+ if (p)
+ offset = *p / IRQS_PER_MSI_REG;
count /= sizeof(u32);
- for (i = 0; i < count / 2; i++) {
- if (i > NR_MSI_REG)
- break;
+ for (i = 0; i < min(count / 2, NR_MSI_REG); i++) {
virt_msir = irq_of_parse_and_map(dev->dev.of_node, i);
if (virt_msir != NO_IRQ) {
- set_irq_data(virt_msir, (void *)i);
+ cascade_data = kzalloc(
+ sizeof(struct fsl_msi_cascade_data),
+ GFP_KERNEL);
+ if (!cascade_data) {
+ dev_err(&dev->dev,
+ "No memory for MSI cascade data\n");
+ err = -ENOMEM;
+ goto error_out;
+ }
+ msi->msi_virqs[i] = virt_msir;
+ cascade_data->index = i + offset;
+ cascade_data->msi_data = msi;
+ set_irq_data(virt_msir, (void *)cascade_data);
set_irq_chained_handler(virt_msir, fsl_msi_cascade);
}
}
- fsl_msi = msi;
+ list_add_tail(&msi->list, &msi_head);
- WARN_ON(ppc_md.setup_msi_irqs);
- ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
- ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
- ppc_md.msi_check_device = fsl_msi_check_device;
+ /* The multiple setting ppc_md.setup_msi_irqs will not harm things */
+ if (!ppc_md.setup_msi_irqs) {
+ ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
+ ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
+ ppc_md.msi_check_device = fsl_msi_check_device;
+ } else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
+ dev_err(&dev->dev, "Different MSI driver already installed!\n");
+ err = -ENODEV;
+ goto error_out;
+ }
return 0;
error_out:
- kfree(msi);
+ fsl_of_msi_remove(dev);
return err;
}
@@ -351,6 +419,7 @@ static struct of_platform_driver fsl_of_msi_driver = {
.of_match_table = fsl_of_msi_ids,
},
.probe = fsl_of_msi_probe,
+ .remove = fsl_of_msi_remove,
};
static __init int fsl_of_msi_init(void)
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index 331c7e7025b7..624580c252d7 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -32,8 +32,11 @@ struct fsl_msi {
u32 msi_addr_hi;
void __iomem *msi_regs;
u32 feature;
+ int msi_virqs[NR_MSI_REG];
struct msi_bitmap bitmap;
+
+ struct list_head list; /* support multiple MSI banks */
};
#endif /* _POWERPC_SYSDEV_FSL_MSI_H */
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index cd37e49e7034..30e1626b2e85 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -1426,7 +1426,7 @@ int fsl_rio_setup(struct of_device *dev)
port->iores.flags = IORESOURCE_MEM;
port->iores.name = "rio_io_win";
- priv->pwirq = irq_of_parse_and_map(dev->node, 0);
+ priv->pwirq = irq_of_parse_and_map(dev->dev.of_node, 0);
priv->bellirq = irq_of_parse_and_map(dev->dev.of_node, 2);
priv->txirq = irq_of_parse_and_map(dev->dev.of_node, 3);
priv->rxirq = irq_of_parse_and_map(dev->dev.of_node, 4);
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index 106d767bf65b..156aa7d36258 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -974,6 +974,123 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata =
.setup_utl = ppc460ex_pciex_init_utl,
};
+static int __init ppc460sx_pciex_core_init(struct device_node *np)
+{
+ /* HSS drive amplitude */
+ mtdcri(SDR0, PESDR0_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL3DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL4DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL5DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL6DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR0_460SX_HSSL7DAMP, 0xB9843211);
+
+ mtdcri(SDR0, PESDR1_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR1_460SX_HSSL3DAMP, 0xB9843211);
+
+ mtdcri(SDR0, PESDR2_460SX_HSSL0DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL2DAMP, 0xB9843211);
+ mtdcri(SDR0, PESDR2_460SX_HSSL3DAMP, 0xB9843211);
+
+ /* HSS TX pre-emphasis */
+ mtdcri(SDR0, PESDR0_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL3COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL4COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL5COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL6COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR0_460SX_HSSL7COEFA, 0xDCB98987);
+
+ mtdcri(SDR0, PESDR1_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR1_460SX_HSSL3COEFA, 0xDCB98987);
+
+ mtdcri(SDR0, PESDR2_460SX_HSSL0COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL2COEFA, 0xDCB98987);
+ mtdcri(SDR0, PESDR2_460SX_HSSL3COEFA, 0xDCB98987);
+
+ /* HSS TX calibration control */
+ mtdcri(SDR0, PESDR0_460SX_HSSL1CALDRV, 0x22222222);
+ mtdcri(SDR0, PESDR1_460SX_HSSL1CALDRV, 0x22220000);
+ mtdcri(SDR0, PESDR2_460SX_HSSL1CALDRV, 0x22220000);
+
+ /* HSS TX slew control */
+ mtdcri(SDR0, PESDR0_460SX_HSSSLEW, 0xFFFFFFFF);
+ mtdcri(SDR0, PESDR1_460SX_HSSSLEW, 0xFFFF0000);
+ mtdcri(SDR0, PESDR2_460SX_HSSSLEW, 0xFFFF0000);
+
+ udelay(100);
+
+ /* De-assert PLLRESET */
+ dcri_clrset(SDR0, PESDR0_PLLLCT2, 0x00000100, 0);
+
+ /* Reset DL, UTL, GPL before configuration */
+ mtdcri(SDR0, PESDR0_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+ mtdcri(SDR0, PESDR1_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+ mtdcri(SDR0, PESDR2_460SX_RCSSET,
+ PESDRx_RCSSET_RSTDL | PESDRx_RCSSET_RSTGU);
+
+ udelay(100);
+
+ /*
+ * If bifurcation is not enabled, u-boot would have disabled the
+ * third PCIe port
+ */
+ if (((mfdcri(SDR0, PESDR1_460SX_HSSCTLSET) & 0x00000001) ==
+ 0x00000001)) {
+ printk(KERN_INFO "PCI: PCIE bifurcation setup successfully.\n");
+ printk(KERN_INFO "PCI: Total 3 PCIE ports are present\n");
+ return 3;
+ }
+
+ printk(KERN_INFO "PCI: Total 2 PCIE ports are present\n");
+ return 2;
+}
+
+static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+
+ if (port->endpoint)
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
+ 0x01000000, 0);
+ else
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_UTLSET2,
+ 0, 0x01000000);
+
+ /*Gen-1*/
+ mtdcri(SDR0, port->sdr_base + PESDRn_460SX_RCEI, 0x08000000);
+
+ dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET,
+ (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL),
+ PESDRx_RCSSET_RSTPYN);
+
+ port->has_ibpre = 1;
+
+ return 0;
+}
+
+static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port)
+{
+ /* Max 128 Bytes */
+ out_be32 (port->utl_base + PEUTL_PBBSZ, 0x00000000);
+ return 0;
+}
+
+static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = {
+ .core_init = ppc460sx_pciex_core_init,
+ .port_init_hw = ppc460sx_pciex_init_port_hw,
+ .setup_utl = ppc460sx_pciex_init_utl,
+};
+
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
@@ -1089,6 +1206,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np)
}
if (of_device_is_compatible(np, "ibm,plb-pciex-460ex"))
ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops;
+ if (of_device_is_compatible(np, "ibm,plb-pciex-460sx"))
+ ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops;
#endif /* CONFIG_44x */
#ifdef CONFIG_40x
if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h
index d04e40b306fb..56d9e5deccbf 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.h
+++ b/arch/powerpc/sysdev/ppc4xx_pci.h
@@ -324,6 +324,64 @@
#define PESDR0_460EX_IHS2 0x036D
/*
+ * 460SX addtional DCRs
+ */
+#define PESDRn_460SX_RCEI 0x02
+
+#define PESDR0_460SX_HSSL0DAMP 0x320
+#define PESDR0_460SX_HSSL1DAMP 0x321
+#define PESDR0_460SX_HSSL2DAMP 0x322
+#define PESDR0_460SX_HSSL3DAMP 0x323
+#define PESDR0_460SX_HSSL4DAMP 0x324
+#define PESDR0_460SX_HSSL5DAMP 0x325
+#define PESDR0_460SX_HSSL6DAMP 0x326
+#define PESDR0_460SX_HSSL7DAMP 0x327
+
+#define PESDR1_460SX_HSSL0DAMP 0x354
+#define PESDR1_460SX_HSSL1DAMP 0x355
+#define PESDR1_460SX_HSSL2DAMP 0x356
+#define PESDR1_460SX_HSSL3DAMP 0x357
+
+#define PESDR2_460SX_HSSL0DAMP 0x384
+#define PESDR2_460SX_HSSL1DAMP 0x385
+#define PESDR2_460SX_HSSL2DAMP 0x386
+#define PESDR2_460SX_HSSL3DAMP 0x387
+
+#define PESDR0_460SX_HSSL0COEFA 0x328
+#define PESDR0_460SX_HSSL1COEFA 0x329
+#define PESDR0_460SX_HSSL2COEFA 0x32A
+#define PESDR0_460SX_HSSL3COEFA 0x32B
+#define PESDR0_460SX_HSSL4COEFA 0x32C
+#define PESDR0_460SX_HSSL5COEFA 0x32D
+#define PESDR0_460SX_HSSL6COEFA 0x32E
+#define PESDR0_460SX_HSSL7COEFA 0x32F
+
+#define PESDR1_460SX_HSSL0COEFA 0x358
+#define PESDR1_460SX_HSSL1COEFA 0x359
+#define PESDR1_460SX_HSSL2COEFA 0x35A
+#define PESDR1_460SX_HSSL3COEFA 0x35B
+
+#define PESDR2_460SX_HSSL0COEFA 0x388
+#define PESDR2_460SX_HSSL1COEFA 0x389
+#define PESDR2_460SX_HSSL2COEFA 0x38A
+#define PESDR2_460SX_HSSL3COEFA 0x38B
+
+#define PESDR0_460SX_HSSL1CALDRV 0x339
+#define PESDR1_460SX_HSSL1CALDRV 0x361
+#define PESDR2_460SX_HSSL1CALDRV 0x391
+
+#define PESDR0_460SX_HSSSLEW 0x338
+#define PESDR1_460SX_HSSSLEW 0x360
+#define PESDR2_460SX_HSSSLEW 0x390
+
+#define PESDR0_460SX_HSSCTLSET 0x31E
+#define PESDR1_460SX_HSSCTLSET 0x352
+#define PESDR2_460SX_HSSCTLSET 0x382
+
+#define PESDR0_460SX_RCSSET 0x304
+#define PESDR1_460SX_RCSSET 0x344
+#define PESDR2_460SX_RCSSET 0x374
+/*
* Of the above, some are common offsets from the base
*/
#define PESDRn_UTLSET1 0x00
diff --git a/arch/s390/appldata/appldata_os.c b/arch/s390/appldata/appldata_os.c
index 55c80ffd42b9..92f1cb745d69 100644
--- a/arch/s390/appldata/appldata_os.c
+++ b/arch/s390/appldata/appldata_os.c
@@ -181,7 +181,7 @@ static int __init appldata_os_init(void)
goto out;
}
- appldata_os_data = kzalloc(max_size, GFP_DMA);
+ appldata_os_data = kzalloc(max_size, GFP_KERNEL | GFP_DMA);
if (appldata_os_data == NULL) {
rc = -ENOMEM;
goto out;
diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile
index 6a1157fa4f98..1cf81d77c5a5 100644
--- a/arch/s390/crypto/Makefile
+++ b/arch/s390/crypto/Makefile
@@ -5,6 +5,6 @@
obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o
obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o
obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o
-obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
+obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o
obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
obj-$(CONFIG_S390_PRNG) += prng.o
diff --git a/arch/s390/crypto/crypto_des.h b/arch/s390/crypto/crypto_des.h
index c964b64111dd..6210457ceebb 100644
--- a/arch/s390/crypto/crypto_des.h
+++ b/arch/s390/crypto/crypto_des.h
@@ -15,4 +15,4 @@
extern int crypto_des_check_key(const u8*, unsigned int, u32*);
-#endif //__CRYPTO_DES_H__
+#endif /*__CRYPTO_DES_H__*/
diff --git a/arch/s390/crypto/des_s390.c b/arch/s390/crypto/des_s390.c
index 2bc479ab3a66..cc5420118393 100644
--- a/arch/s390/crypto/des_s390.c
+++ b/arch/s390/crypto/des_s390.c
@@ -14,32 +14,21 @@
*
*/
-#include <crypto/algapi.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+#include <crypto/des.h>
#include "crypt_s390.h"
-#include "crypto_des.h"
-
-#define DES_BLOCK_SIZE 8
-#define DES_KEY_SIZE 8
-
-#define DES3_128_KEY_SIZE (2 * DES_KEY_SIZE)
-#define DES3_128_BLOCK_SIZE DES_BLOCK_SIZE
#define DES3_192_KEY_SIZE (3 * DES_KEY_SIZE)
-#define DES3_192_BLOCK_SIZE DES_BLOCK_SIZE
struct crypt_s390_des_ctx {
u8 iv[DES_BLOCK_SIZE];
u8 key[DES_KEY_SIZE];
};
-struct crypt_s390_des3_128_ctx {
- u8 iv[DES_BLOCK_SIZE];
- u8 key[DES3_128_KEY_SIZE];
-};
-
struct crypt_s390_des3_192_ctx {
u8 iv[DES_BLOCK_SIZE];
u8 key[DES3_192_KEY_SIZE];
@@ -50,13 +39,16 @@ static int des_setkey(struct crypto_tfm *tfm, const u8 *key,
{
struct crypt_s390_des_ctx *dctx = crypto_tfm_ctx(tfm);
u32 *flags = &tfm->crt_flags;
- int ret;
+ u32 tmp[DES_EXPKEY_WORDS];
- /* test if key is valid (not a weak key) */
- ret = crypto_des_check_key(key, keylen, flags);
- if (ret == 0)
- memcpy(dctx->key, key, keylen);
- return ret;
+ /* check for weak keys */
+ if (!des_ekey(tmp, key) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ return -EINVAL;
+ }
+
+ memcpy(dctx->key, key, keylen);
+ return 0;
}
static void des_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
@@ -237,165 +229,6 @@ static struct crypto_alg cbc_des_alg = {
* complementation keys. Any weakness is obviated by the use of
* multiple keys.
*
- * However, if the two independent 64-bit keys are equal,
- * then the DES3 operation is simply the same as DES.
- * Implementers MUST reject keys that exhibit this property.
- *
- */
-static int des3_128_setkey(struct crypto_tfm *tfm, const u8 *key,
- unsigned int keylen)
-{
- int i, ret;
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
- const u8 *temp_key = key;
- u32 *flags = &tfm->crt_flags;
-
- if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE)) &&
- (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
- *flags |= CRYPTO_TFM_RES_WEAK_KEY;
- return -EINVAL;
- }
- for (i = 0; i < 2; i++, temp_key += DES_KEY_SIZE) {
- ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
- if (ret < 0)
- return ret;
- }
- memcpy(dctx->key, key, keylen);
- return 0;
-}
-
-static void des3_128_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
- crypt_s390_km(KM_TDEA_128_ENCRYPT, dctx->key, dst, (void*)src,
- DES3_128_BLOCK_SIZE);
-}
-
-static void des3_128_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
-{
- struct crypt_s390_des3_128_ctx *dctx = crypto_tfm_ctx(tfm);
-
- crypt_s390_km(KM_TDEA_128_DECRYPT, dctx->key, dst, (void*)src,
- DES3_128_BLOCK_SIZE);
-}
-
-static struct crypto_alg des3_128_alg = {
- .cra_name = "des3_ede128",
- .cra_driver_name = "des3_ede128-s390",
- .cra_priority = CRYPT_S390_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(des3_128_alg.cra_list),
- .cra_u = {
- .cipher = {
- .cia_min_keysize = DES3_128_KEY_SIZE,
- .cia_max_keysize = DES3_128_KEY_SIZE,
- .cia_setkey = des3_128_setkey,
- .cia_encrypt = des3_128_encrypt,
- .cia_decrypt = des3_128_decrypt,
- }
- }
-};
-
-static int ecb_des3_128_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_128_ENCRYPT, sctx->key, &walk);
-}
-
-static int ecb_des3_128_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return ecb_desall_crypt(desc, KM_TDEA_128_DECRYPT, sctx->key, &walk);
-}
-
-static struct crypto_alg ecb_des3_128_alg = {
- .cra_name = "ecb(des3_ede128)",
- .cra_driver_name = "ecb-des3_ede128-s390",
- .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(
- ecb_des3_128_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_128_KEY_SIZE,
- .max_keysize = DES3_128_KEY_SIZE,
- .setkey = des3_128_setkey,
- .encrypt = ecb_des3_128_encrypt,
- .decrypt = ecb_des3_128_decrypt,
- }
- }
-};
-
-static int cbc_des3_128_encrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_128_ENCRYPT, sctx->iv, &walk);
-}
-
-static int cbc_des3_128_decrypt(struct blkcipher_desc *desc,
- struct scatterlist *dst,
- struct scatterlist *src, unsigned int nbytes)
-{
- struct crypt_s390_des3_128_ctx *sctx = crypto_blkcipher_ctx(desc->tfm);
- struct blkcipher_walk walk;
-
- blkcipher_walk_init(&walk, dst, src, nbytes);
- return cbc_desall_crypt(desc, KMC_TDEA_128_DECRYPT, sctx->iv, &walk);
-}
-
-static struct crypto_alg cbc_des3_128_alg = {
- .cra_name = "cbc(des3_ede128)",
- .cra_driver_name = "cbc-des3_ede128-s390",
- .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
- .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_128_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct crypt_s390_des3_128_ctx),
- .cra_type = &crypto_blkcipher_type,
- .cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(
- cbc_des3_128_alg.cra_list),
- .cra_u = {
- .blkcipher = {
- .min_keysize = DES3_128_KEY_SIZE,
- .max_keysize = DES3_128_KEY_SIZE,
- .ivsize = DES3_128_BLOCK_SIZE,
- .setkey = des3_128_setkey,
- .encrypt = cbc_des3_128_encrypt,
- .decrypt = cbc_des3_128_decrypt,
- }
- }
-};
-
-/*
- * RFC2451:
- *
- * For DES-EDE3, there is no known need to reject weak or
- * complementation keys. Any weakness is obviated by the use of
- * multiple keys.
- *
* However, if the first two or last two independent 64-bit keys are
* equal (k1 == k2 or k2 == k3), then the DES3 operation is simply the
* same as DES. Implementers MUST reject keys that exhibit this
@@ -405,9 +238,7 @@ static struct crypto_alg cbc_des3_128_alg = {
static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
unsigned int keylen)
{
- int i, ret;
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
- const u8 *temp_key = key;
u32 *flags = &tfm->crt_flags;
if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
@@ -417,11 +248,6 @@ static int des3_192_setkey(struct crypto_tfm *tfm, const u8 *key,
*flags |= CRYPTO_TFM_RES_WEAK_KEY;
return -EINVAL;
}
- for (i = 0; i < 3; i++, temp_key += DES_KEY_SIZE) {
- ret = crypto_des_check_key(temp_key, DES_KEY_SIZE, flags);
- if (ret < 0)
- return ret;
- }
memcpy(dctx->key, key, keylen);
return 0;
}
@@ -431,7 +257,7 @@ static void des3_192_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
crypt_s390_km(KM_TDEA_192_ENCRYPT, dctx->key, dst, (void*)src,
- DES3_192_BLOCK_SIZE);
+ DES_BLOCK_SIZE);
}
static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
@@ -439,7 +265,7 @@ static void des3_192_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
struct crypt_s390_des3_192_ctx *dctx = crypto_tfm_ctx(tfm);
crypt_s390_km(KM_TDEA_192_DECRYPT, dctx->key, dst, (void*)src,
- DES3_192_BLOCK_SIZE);
+ DES_BLOCK_SIZE);
}
static struct crypto_alg des3_192_alg = {
@@ -447,7 +273,7 @@ static struct crypto_alg des3_192_alg = {
.cra_driver_name = "des3_ede-s390",
.cra_priority = CRYPT_S390_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(des3_192_alg.cra_list),
@@ -489,7 +315,7 @@ static struct crypto_alg ecb_des3_192_alg = {
.cra_driver_name = "ecb-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
@@ -533,7 +359,7 @@ static struct crypto_alg cbc_des3_192_alg = {
.cra_driver_name = "cbc-des3_ede-s390",
.cra_priority = CRYPT_S390_COMPOSITE_PRIORITY,
.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
- .cra_blocksize = DES3_192_BLOCK_SIZE,
+ .cra_blocksize = DES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypt_s390_des3_192_ctx),
.cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
@@ -543,7 +369,7 @@ static struct crypto_alg cbc_des3_192_alg = {
.blkcipher = {
.min_keysize = DES3_192_KEY_SIZE,
.max_keysize = DES3_192_KEY_SIZE,
- .ivsize = DES3_192_BLOCK_SIZE,
+ .ivsize = DES_BLOCK_SIZE,
.setkey = des3_192_setkey,
.encrypt = cbc_des3_192_encrypt,
.decrypt = cbc_des3_192_decrypt,
@@ -553,10 +379,9 @@ static struct crypto_alg cbc_des3_192_alg = {
static int des_s390_init(void)
{
- int ret = 0;
+ int ret;
if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
- !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
!crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
return -EOPNOTSUPP;
@@ -569,17 +394,6 @@ static int des_s390_init(void)
ret = crypto_register_alg(&cbc_des_alg);
if (ret)
goto cbc_des_err;
-
- ret = crypto_register_alg(&des3_128_alg);
- if (ret)
- goto des3_128_err;
- ret = crypto_register_alg(&ecb_des3_128_alg);
- if (ret)
- goto ecb_des3_128_err;
- ret = crypto_register_alg(&cbc_des3_128_alg);
- if (ret)
- goto cbc_des3_128_err;
-
ret = crypto_register_alg(&des3_192_alg);
if (ret)
goto des3_192_err;
@@ -589,7 +403,6 @@ static int des_s390_init(void)
ret = crypto_register_alg(&cbc_des3_192_alg);
if (ret)
goto cbc_des3_192_err;
-
out:
return ret;
@@ -598,12 +411,6 @@ cbc_des3_192_err:
ecb_des3_192_err:
crypto_unregister_alg(&des3_192_alg);
des3_192_err:
- crypto_unregister_alg(&cbc_des3_128_alg);
-cbc_des3_128_err:
- crypto_unregister_alg(&ecb_des3_128_alg);
-ecb_des3_128_err:
- crypto_unregister_alg(&des3_128_alg);
-des3_128_err:
crypto_unregister_alg(&cbc_des_alg);
cbc_des_err:
crypto_unregister_alg(&ecb_des_alg);
@@ -613,21 +420,18 @@ des_err:
goto out;
}
-static void __exit des_s390_fini(void)
+static void __exit des_s390_exit(void)
{
crypto_unregister_alg(&cbc_des3_192_alg);
crypto_unregister_alg(&ecb_des3_192_alg);
crypto_unregister_alg(&des3_192_alg);
- crypto_unregister_alg(&cbc_des3_128_alg);
- crypto_unregister_alg(&ecb_des3_128_alg);
- crypto_unregister_alg(&des3_128_alg);
crypto_unregister_alg(&cbc_des_alg);
crypto_unregister_alg(&ecb_des_alg);
crypto_unregister_alg(&des_alg);
}
module_init(des_s390_init);
-module_exit(des_s390_fini);
+module_exit(des_s390_exit);
MODULE_ALIAS("des");
MODULE_ALIAS("des3_ede");
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index bcd6884985ad..253f158db668 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.34-rc3
-# Fri Apr 9 09:57:10 2010
+# Linux kernel version: 2.6.35-rc1
+# Fri Jun 4 11:32:40 2010
#
CONFIG_SCHED_MC=y
CONFIG_MMU=y
@@ -35,11 +35,13 @@ CONFIG_CONSTRUCTORS=y
CONFIG_EXPERIMENTAL=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_CROSS_COMPILE=""
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_HAVE_KERNEL_GZIP=y
CONFIG_HAVE_KERNEL_BZIP2=y
CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
CONFIG_KERNEL_GZIP=y
# CONFIG_KERNEL_BZIP2 is not set
# CONFIG_KERNEL_LZMA is not set
@@ -77,6 +79,7 @@ CONFIG_CGROUP_NS=y
# CONFIG_CGROUP_CPUACCT is not set
# CONFIG_RESOURCE_COUNTERS is not set
# CONFIG_CGROUP_SCHED is not set
+# CONFIG_BLK_CGROUP is not set
CONFIG_SYSFS_DEPRECATED=y
CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_RELAY is not set
@@ -157,7 +160,6 @@ CONFIG_STOP_MACHINE=y
CONFIG_BLOCK=y
CONFIG_BLK_DEV_BSG=y
# CONFIG_BLK_DEV_INTEGRITY is not set
-# CONFIG_BLK_CGROUP is not set
CONFIG_BLOCK_COMPAT=y
#
@@ -166,7 +168,6 @@ CONFIG_BLOCK_COMPAT=y
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
-# CONFIG_CFQ_GROUP_IOSCHED is not set
CONFIG_DEFAULT_DEADLINE=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
@@ -247,7 +248,6 @@ CONFIG_64BIT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=32
CONFIG_HOTPLUG_CPU=y
-# CONFIG_SCHED_BOOK is not set
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
CONFIG_AUDIT_ARCH=y
@@ -320,7 +320,6 @@ CONFIG_COMPAT_BINFMT_ELF=y
# CONFIG_HAVE_AOUT is not set
CONFIG_BINFMT_MISC=m
CONFIG_FORCE_MAX_ZONEORDER=9
-# CONFIG_PROCESS_DEBUG is not set
CONFIG_PFAULT=y
# CONFIG_SHARED_KERNEL is not set
# CONFIG_CMM is not set
@@ -457,6 +456,7 @@ CONFIG_NF_CONNTRACK=m
# CONFIG_IP6_NF_IPTABLES is not set
# CONFIG_IP_DCCP is not set
CONFIG_IP_SCTP=m
+# CONFIG_NET_SCTPPROBE is not set
# CONFIG_SCTP_DBG_MSG is not set
# CONFIG_SCTP_DBG_OBJCNT is not set
# CONFIG_SCTP_HMAC_NONE is not set
@@ -465,6 +465,7 @@ CONFIG_SCTP_HMAC_MD5=y
# CONFIG_RDS is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
+# CONFIG_L2TP is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
# CONFIG_DECNET is not set
@@ -525,6 +526,7 @@ CONFIG_NET_ACT_NAT=m
# CONFIG_NET_CLS_IND is not set
CONFIG_NET_SCH_FIFO=y
# CONFIG_DCB is not set
+CONFIG_RPS=y
#
# Network testing
@@ -546,6 +548,7 @@ CONFIG_CAN_VCAN=m
# CONFIG_WIMAX is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
+# CONFIG_CAIF is not set
# CONFIG_PCMCIA is not set
CONFIG_CCW=y
@@ -728,6 +731,7 @@ CONFIG_VIRTIO_NET=m
# Character devices
#
CONFIG_DEVKMEM=y
+# CONFIG_N_GSM is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
CONFIG_LEGACY_PTYS=y
@@ -775,6 +779,7 @@ CONFIG_S390_TAPE_34XX=m
# CONFIG_MONREADER is not set
CONFIG_MONWRITER=m
CONFIG_S390_VMUR=m
+# CONFIG_RAMOOPS is not set
#
# PPS support
@@ -788,10 +793,6 @@ CONFIG_S390_VMUR=m
# CONFIG_NEW_LEDS is not set
CONFIG_ACCESSIBILITY=y
# CONFIG_AUXDISPLAY is not set
-
-#
-# TI VLYNQ
-#
# CONFIG_STAGING is not set
#
@@ -976,6 +977,7 @@ CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
# CONFIG_LKDTM is not set
+# CONFIG_CPU_NOTIFIER_ERROR_INJECT is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_LATENCYTOP is not set
CONFIG_SYSCTL_SYSCALL_CHECK=y
@@ -1010,6 +1012,7 @@ CONFIG_BRANCH_PROFILE_NONE=y
CONFIG_KPROBE_EVENT=y
# CONFIG_RING_BUFFER_BENCHMARK is not set
# CONFIG_DYNAMIC_DEBUG is not set
+# CONFIG_ATOMIC64_SELFTEST is not set
CONFIG_SAMPLES=y
# CONFIG_SAMPLE_TRACEPOINTS is not set
# CONFIG_SAMPLE_TRACE_EVENTS is not set
diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h
index 9b866816863c..24aafa68b643 100644
--- a/arch/s390/include/asm/cache.h
+++ b/arch/s390/include/asm/cache.h
@@ -14,6 +14,6 @@
#define L1_CACHE_BYTES 256
#define L1_CACHE_SHIFT 8
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#endif
diff --git a/arch/s390/include/asm/ccwdev.h b/arch/s390/include/asm/ccwdev.h
index 1c0030f9b890..f3ba0fa98de6 100644
--- a/arch/s390/include/asm/ccwdev.h
+++ b/arch/s390/include/asm/ccwdev.h
@@ -208,6 +208,8 @@ extern void ccw_device_get_id(struct ccw_device *, struct ccw_dev_id *);
extern struct ccw_device *ccw_device_probe_console(void);
extern int ccw_device_force_console(void);
+int ccw_device_siosl(struct ccw_device *);
+
// FIXME: these have to go
extern int _ccw_device_get_subchannel_number(struct ccw_device *);
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index 639380a0c45c..22cfd634c355 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -55,8 +55,10 @@ void *module_alloc(unsigned long size)
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
- vfree(mod->arch.syminfo);
- mod->arch.syminfo = NULL;
+ if (mod) {
+ vfree(mod->arch.syminfo);
+ mod->arch.syminfo = NULL;
+ }
vfree(module_region);
}
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index c56d3f56d020..1f066e46e83e 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -264,7 +264,7 @@ restore_registers:
lghi %r2,0
br %r14
- .section .data.nosave,"aw",@progbits
+ .section .data..nosave,"aw",@progbits
.align 8
.Ldisabled_wait_31:
.long 0x000a0000,0x00000000
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 8093e6f47f49..ae3705816878 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -761,7 +761,7 @@ static int __init kvm_s390_init(void)
* to hold the maximum amount of facilites. On the other hand, we
* only set facilities that are known to work in KVM.
*/
- facilities = (unsigned long long *) get_zeroed_page(GFP_DMA);
+ facilities = (unsigned long long *) get_zeroed_page(GFP_KERNEL|GFP_DMA);
if (!facilities) {
kvm_exit();
return -ENOMEM;
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index eff3c5989b46..702276f5e2fa 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -113,7 +113,7 @@ static int __inject_sigp_stop(struct kvm_s390_local_interrupt *li, int action)
{
struct kvm_s390_interrupt_info *inti;
- inti = kzalloc(sizeof(*inti), GFP_KERNEL);
+ inti = kzalloc(sizeof(*inti), GFP_ATOMIC);
if (!inti)
return -ENOMEM;
inti->type = KVM_S390_SIGP_STOP;
diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c
index eb6a2ef5f82e..a9550dca3e4b 100644
--- a/arch/s390/mm/cmm.c
+++ b/arch/s390/mm/cmm.c
@@ -427,7 +427,7 @@ static struct notifier_block cmm_power_notifier = {
.notifier_call = cmm_power_event,
};
-static int cmm_init(void)
+static int __init cmm_init(void)
{
int rc = -ENOMEM;
@@ -435,6 +435,13 @@ static int cmm_init(void)
if (!cmm_sysctl_header)
goto out_sysctl;
#ifdef CONFIG_CMM_IUCV
+ /* convert sender to uppercase characters */
+ if (sender) {
+ int len = strlen(sender);
+ while (len--)
+ sender[len] = toupper(sender[len]);
+ }
+
rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
if (rc < 0)
goto out_smsg;
@@ -467,7 +474,7 @@ out_sysctl:
}
module_init(cmm_init);
-static void cmm_exit(void)
+static void __exit cmm_exit(void)
{
unregister_sysctl_table(cmm_sysctl_header);
#ifdef CONFIG_CMM_IUCV
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 6409fd57eb04..3cc95dd0a3a6 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -105,7 +105,7 @@ static int
dcss_set_subcodes(void)
{
#ifdef CONFIG_64BIT
- char *name = kmalloc(8 * sizeof(char), GFP_DMA);
+ char *name = kmalloc(8 * sizeof(char), GFP_KERNEL | GFP_DMA);
unsigned long rx, ry;
int rc;
@@ -252,12 +252,13 @@ dcss_diag_translate_rc (int vm_rc) {
static int
query_segment_type (struct dcss_segment *seg)
{
- struct qin64 *qin = kmalloc (sizeof(struct qin64), GFP_DMA);
- struct qout64 *qout = kmalloc (sizeof(struct qout64), GFP_DMA);
-
- int diag_cc, rc, i;
unsigned long dummy, vmrc;
+ int diag_cc, rc, i;
+ struct qout64 *qout;
+ struct qin64 *qin;
+ qin = kmalloc(sizeof(*qin), GFP_KERNEL | GFP_DMA);
+ qout = kmalloc(sizeof(*qout), GFP_KERNEL | GFP_DMA);
if ((qin == NULL) || (qout == NULL)) {
rc = -ENOMEM;
goto out_free;
@@ -286,7 +287,7 @@ query_segment_type (struct dcss_segment *seg)
copy data for the new format. */
if (segext_scode == DCSS_SEGEXT) {
struct qout64_old *qout_old;
- qout_old = kzalloc(sizeof(struct qout64_old), GFP_DMA);
+ qout_old = kzalloc(sizeof(*qout_old), GFP_KERNEL | GFP_DMA);
if (qout_old == NULL) {
rc = -ENOMEM;
goto out_free;
@@ -407,11 +408,11 @@ segment_overlaps_others (struct dcss_segment *seg)
static int
__segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
{
- struct dcss_segment *seg = kmalloc(sizeof(struct dcss_segment),
- GFP_DMA);
- int rc, diag_cc;
unsigned long start_addr, end_addr, dummy;
+ struct dcss_segment *seg;
+ int rc, diag_cc;
+ seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
if (seg == NULL) {
rc = -ENOMEM;
goto out;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index c5ee4ce60b57..573fca1fbd9b 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -9,7 +9,7 @@ config SUPERH
def_bool y
select EMBEDDED
select HAVE_CLK
- select HAVE_IDE
+ select HAVE_IDE if HAS_IOPORT
select HAVE_LMB
select HAVE_OPROFILE
select HAVE_GENERIC_DMA_COHERENT
@@ -174,6 +174,9 @@ config ARCH_HAS_DEFAULT_IDLE
config ARCH_HAS_CPU_IDLE_WAIT
def_bool y
+config NO_IOPORT
+ bool
+
config IO_TRAPPED
bool
@@ -776,6 +779,17 @@ config ENTRY_OFFSET
default "0x00010000" if PAGE_SIZE_64KB
default "0x00000000"
+config ROMIMAGE_MMCIF
+ bool "Include MMCIF loader in romImage (EXPERIMENTAL)"
+ depends on CPU_SUBTYPE_SH7724 && EXPERIMENTAL
+ help
+ Say Y here to include experimental MMCIF loading code in
+ romImage. With this enabled it is possible to write the romImage
+ kernel image to an MMC card and boot the kernel straight from
+ the reset vector. At reset the processor Mask ROM will load the
+ first part of the romImage which in turn loads the rest the kernel
+ image to RAM using the MMCIF hardware block.
+
choice
prompt "Kernel command line"
optional
diff --git a/arch/sh/boards/Kconfig b/arch/sh/boards/Kconfig
index 938e87d51482..07b35ca2f644 100644
--- a/arch/sh/boards/Kconfig
+++ b/arch/sh/boards/Kconfig
@@ -154,6 +154,7 @@ config SH_SDK7786
bool "SDK7786"
depends on CPU_SUBTYPE_SH7786
select SYS_SUPPORTS_PCI
+ select NO_IOPORT if !PCI
help
Select SDK7786 if configuring for a Renesas Technology Europe
SH7786-65nm board.
@@ -190,6 +191,7 @@ config SH_URQUELL
depends on CPU_SUBTYPE_SH7786
select ARCH_REQUIRE_GPIOLIB
select SYS_SUPPORTS_PCI
+ select NO_IOPORT if !PCI
config SH_MIGOR
bool "Migo-R"
@@ -286,6 +288,7 @@ config SH_LBOX_RE2
config SH_X3PROTO
bool "SH-X3 Prototype board"
depends on CPU_SUBTYPE_SHX3
+ select NO_IOPORT if !PCI
config SH_MAGIC_PANEL_R2
bool "Magic Panel R2"
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 57e37e284208..3a170bd3f3d0 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -328,7 +328,7 @@ static struct soc_camera_platform_info camera_info = {
.set_capture = camera_set_capture,
};
-struct soc_camera_link camera_link = {
+static struct soc_camera_link camera_link = {
.bus_id = 0,
.add_device = ap325rxa_camera_add,
.del_device = ap325rxa_camera_del,
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 49714258732e..1d7b495a7db4 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -12,6 +12,8 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/mfd/sh_mobile_sdhi.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
#include <linux/mtd/physmap.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
@@ -23,10 +25,8 @@
#include <linux/spi/spi.h>
#include <linux/spi/sh_msiof.h>
#include <linux/spi/mmc_spi.h>
-#include <linux/mmc/host.h>
#include <linux/input.h>
#include <linux/input/sh_keysc.h>
-#include <linux/mfd/sh_mobile_sdhi.h>
#include <video/sh_mobile_lcdc.h>
#include <sound/sh_fsi.h>
#include <media/sh_mobile_ceu.h>
@@ -139,7 +139,7 @@ static struct resource sh_eth_resources[] = {
},
};
-struct sh_eth_plat_data sh_eth_plat = {
+static struct sh_eth_plat_data sh_eth_plat = {
.phy = 0x1f, /* SMSC LAN8700 */
.edmac_endian = EDMAC_LITTLE_ENDIAN,
.ether_link_active_low = 1
@@ -159,7 +159,7 @@ static struct platform_device sh_eth_device = {
};
/* USB0 host */
-void usb0_port_power(int port, int power)
+static void usb0_port_power(int port, int power)
{
gpio_set_value(GPIO_PTB4, power);
}
@@ -195,7 +195,7 @@ static struct platform_device usb0_host_device = {
};
/* USB1 host/function */
-void usb1_port_power(int port, int power)
+static void usb1_port_power(int port, int power)
{
gpio_set_value(GPIO_PTB5, power);
}
@@ -421,7 +421,7 @@ static int ts_init(void)
return 0;
}
-struct tsc2007_platform_data tsc2007_info = {
+static struct tsc2007_platform_data tsc2007_info = {
.model = 2007,
.x_plate_ohms = 180,
.get_pendown_state = ts_get_pendown_state,
@@ -436,7 +436,7 @@ static struct i2c_board_info ts_i2c_clients = {
};
#ifdef CONFIG_MFD_SH_MOBILE_SDHI
-/* SHDI0 */
+/* SDHI0 */
static void sdhi0_set_pwr(struct platform_device *pdev, int state)
{
gpio_set_value(GPIO_PTB6, state);
@@ -474,7 +474,8 @@ static struct platform_device sdhi0_device = {
},
};
-/* SHDI1 */
+#if !defined(CONFIG_MMC_SH_MMCIF)
+/* SDHI1 */
static void sdhi1_set_pwr(struct platform_device *pdev, int state)
{
gpio_set_value(GPIO_PTB7, state);
@@ -511,6 +512,7 @@ static struct platform_device sdhi1_device = {
.hwblk_id = HWBLK_SDHI1,
},
};
+#endif /* CONFIG_MMC_SH_MMCIF */
#else
@@ -720,7 +722,7 @@ static struct clk fsimckb_clk = {
.rate = 0, /* unknown */
};
-struct sh_fsi_platform_info fsi_info = {
+static struct sh_fsi_platform_info fsi_info = {
.portb_flags = SH_FSI_BRS_INV |
SH_FSI_OUT_SLAVE_MODE |
SH_FSI_IN_SLAVE_MODE |
@@ -777,7 +779,7 @@ static struct platform_device irda_device = {
#include <media/ak881x.h>
#include <media/sh_vou.h>
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
.flags = AK881X_IF_MODE_SLAVE,
};
@@ -786,7 +788,7 @@ static struct i2c_board_info ak8813 = {
.platform_data = &ak881x_pdata,
};
-struct sh_vou_pdata sh_vou_pdata = {
+static struct sh_vou_pdata sh_vou_pdata = {
.bus_fmt = SH_VOU_BUS_8BIT,
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
@@ -819,6 +821,58 @@ static struct platform_device vou_device = {
},
};
+#if defined(CONFIG_MMC_SH_MMCIF)
+/* SH_MMCIF */
+static void mmcif_set_pwr(struct platform_device *pdev, int state)
+{
+ gpio_set_value(GPIO_PTB7, state);
+}
+
+static void mmcif_down_pwr(struct platform_device *pdev)
+{
+ gpio_set_value(GPIO_PTB7, 0);
+}
+
+static struct resource sh_mmcif_resources[] = {
+ [0] = {
+ .name = "SH_MMCIF",
+ .start = 0xA4CA0000,
+ .end = 0xA4CA00FF,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /* MMC2I */
+ .start = 29,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* MMC3I */
+ .start = 30,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_plat = {
+ .set_pwr = mmcif_set_pwr,
+ .down_pwr = mmcif_down_pwr,
+ .sup_pclk = 0, /* SH7724: Max Pclk/2 */
+ .caps = MMC_CAP_4_BIT_DATA |
+ MMC_CAP_8_BIT_DATA |
+ MMC_CAP_NEEDS_POLL,
+ .ocr = MMC_VDD_32_33 | MMC_VDD_33_34,
+};
+
+static struct platform_device sh_mmcif_device = {
+ .name = "sh_mmcif",
+ .id = 0,
+ .dev = {
+ .platform_data = &sh_mmcif_plat,
+ },
+ .num_resources = ARRAY_SIZE(sh_mmcif_resources),
+ .resource = sh_mmcif_resources,
+};
+#endif
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
@@ -831,7 +885,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
&keysc_device,
#ifdef CONFIG_MFD_SH_MOBILE_SDHI
&sdhi0_device,
+#if !defined(CONFIG_MMC_SH_MMCIF)
&sdhi1_device,
+#endif
#else
&msiof0_device,
#endif
@@ -841,6 +897,9 @@ static struct platform_device *ecovec_devices[] __initdata = {
&fsi_device,
&irda_device,
&vou_device,
+#if defined(CONFIG_MMC_SH_MMCIF)
+ &sh_mmcif_device,
+#endif
};
#ifdef CONFIG_I2C
@@ -1134,6 +1193,7 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTB6, NULL);
gpio_direction_output(GPIO_PTB6, 0);
+#if !defined(CONFIG_MMC_SH_MMCIF)
/* enable SDHI1 on CN12 (needs DS2.6,7 set to ON,OFF) */
gpio_request(GPIO_FN_SDHI1CD, NULL);
gpio_request(GPIO_FN_SDHI1WP, NULL);
@@ -1148,6 +1208,7 @@ static int __init arch_setup(void)
/* I/O buffer drive ability is high for SDHI1 */
__raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+#endif /* CONFIG_MMC_SH_MMCIF */
#else
/* enable MSIOF0 on CN11 (needs DS2.4 set to OFF) */
gpio_request(GPIO_FN_MSIOF0_TXD, NULL);
@@ -1223,6 +1284,25 @@ static int __init arch_setup(void)
gpio_request(GPIO_PTU5, NULL);
gpio_direction_output(GPIO_PTU5, 0);
+#if defined(CONFIG_MMC_SH_MMCIF)
+ /* enable MMCIF (needs DS2.6,7 set to OFF,ON) */
+ gpio_request(GPIO_FN_MMC_D7, NULL);
+ gpio_request(GPIO_FN_MMC_D6, NULL);
+ gpio_request(GPIO_FN_MMC_D5, NULL);
+ gpio_request(GPIO_FN_MMC_D4, NULL);
+ gpio_request(GPIO_FN_MMC_D3, NULL);
+ gpio_request(GPIO_FN_MMC_D2, NULL);
+ gpio_request(GPIO_FN_MMC_D1, NULL);
+ gpio_request(GPIO_FN_MMC_D0, NULL);
+ gpio_request(GPIO_FN_MMC_CLK, NULL);
+ gpio_request(GPIO_FN_MMC_CMD, NULL);
+ gpio_request(GPIO_PTB7, NULL);
+ gpio_direction_output(GPIO_PTB7, 0);
+
+ /* I/O buffer drive ability is high for MMCIF */
+ __raw_writew((__raw_readw(IODRIVEA) & ~0x3000) | 0x2000 , IODRIVEA);
+#endif
+
/* enable I2C device */
i2c_register_board_info(0, i2c0_devices,
ARRAY_SIZE(i2c0_devices));
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 87185de20446..662debe4ead2 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -181,7 +181,7 @@ static int migor_nand_flash_ready(struct mtd_info *mtd)
return gpio_get_value(GPIO_PTA1); /* NAND_RBn */
}
-struct platform_nand_data migor_nand_flash_data = {
+static struct platform_nand_data migor_nand_flash_data = {
.chip = {
.nr_chips = 1,
.partitions = migor_nand_flash_partitions,
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index f9b82546c2df..552ebd9ba82b 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -283,7 +283,7 @@ static struct clk fsimcka_clk = {
};
/* change J20, J21, J22 pin to 1-2 connection to use slave mode */
-struct sh_fsi_platform_info fsi_info = {
+static struct sh_fsi_platform_info fsi_info = {
.porta_flags = SH_FSI_BRS_INV |
SH_FSI_OUT_SLAVE_MODE |
SH_FSI_IN_SLAVE_MODE |
@@ -371,7 +371,7 @@ static struct resource sh_eth_resources[] = {
},
};
-struct sh_eth_plat_data sh_eth_plat = {
+static struct sh_eth_plat_data sh_eth_plat = {
.phy = 0x1f, /* SMSC LAN8187 */
.edmac_endian = EDMAC_LITTLE_ENDIAN,
};
@@ -535,7 +535,7 @@ static struct platform_device irda_device = {
#include <media/ak881x.h>
#include <media/sh_vou.h>
-struct ak881x_pdata ak881x_pdata = {
+static struct ak881x_pdata ak881x_pdata = {
.flags = AK881X_IF_MODE_SLAVE,
};
@@ -545,7 +545,7 @@ static struct i2c_board_info ak8813 = {
.platform_data = &ak881x_pdata,
};
-struct sh_vou_pdata sh_vou_pdata = {
+static struct sh_vou_pdata sh_vou_pdata = {
.bus_fmt = SH_VOU_BUS_8BIT,
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
diff --git a/arch/sh/boot/compressed/vmlinux.scr b/arch/sh/boot/compressed/vmlinux.scr
index f02382ae5c48..862d74808236 100644
--- a/arch/sh/boot/compressed/vmlinux.scr
+++ b/arch/sh/boot/compressed/vmlinux.scr
@@ -1,6 +1,6 @@
SECTIONS
{
- .rodata.compressed : {
+ .rodata..compressed : {
input_len = .;
LONG(input_data_end - input_data) input_data = .;
*(.data)
diff --git a/arch/sh/boot/romimage/Makefile b/arch/sh/boot/romimage/Makefile
index f473a24a2d92..2216ee57f251 100644
--- a/arch/sh/boot/romimage/Makefile
+++ b/arch/sh/boot/romimage/Makefile
@@ -1,16 +1,21 @@
#
# linux/arch/sh/boot/romimage/Makefile
#
-# create an image suitable for burning to flash from zImage
+# create an romImage file suitable for burning to flash/mmc from zImage
#
targets := vmlinux head.o zeropage.bin piggy.o
+load-y := 0
-OBJECTS = $(obj)/head.o
-LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext 0 -e romstart \
+mmcif-load-$(CONFIG_CPU_SUBTYPE_SH7724) := 0xe5200000 # ILRAM
+mmcif-obj-$(CONFIG_CPU_SUBTYPE_SH7724) := $(obj)/mmcif-sh7724.o
+load-$(CONFIG_ROMIMAGE_MMCIF) := $(mmcif-load-y)
+obj-$(CONFIG_ROMIMAGE_MMCIF) := $(mmcif-obj-y)
+
+LDFLAGS_vmlinux := --oformat $(ld-bfd) -Ttext $(load-y) -e romstart \
-T $(obj)/../../kernel/vmlinux.lds
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+$(obj)/vmlinux: $(obj)/head.o $(obj-y) $(obj)/piggy.o FORCE
$(call if_changed,ld)
@:
diff --git a/arch/sh/boot/romimage/head.S b/arch/sh/boot/romimage/head.S
index 93e779a405ec..4671d1b82150 100644
--- a/arch/sh/boot/romimage/head.S
+++ b/arch/sh/boot/romimage/head.S
@@ -12,8 +12,40 @@ romstart:
/* include board specific setup code */
#include <mach/romimage.h>
+#ifdef CONFIG_ROMIMAGE_MMCIF
+ /* load the romImage to above the empty zero page */
+ mov.l empty_zero_page_dst, r4
+ mov.l empty_zero_page_dst_adj, r5
+ add r5, r4
+ mov.l bytes_to_load, r5
+ mov.l loader_function, r7
+ jsr @r7
+ mov r4, r15
+
+ mov.l empty_zero_page_dst, r4
+ mov.l empty_zero_page_dst_adj, r5
+ add r5, r4
+ mov.l loaded_code_offs, r5
+ add r5, r4
+ jmp @r4
+ nop
+
+ .balign 4
+empty_zero_page_dst_adj:
+ .long PAGE_SIZE
+bytes_to_load:
+ .long end_data - romstart
+loader_function:
+ .long mmcif_loader
+loaded_code_offs:
+ .long loaded_code - romstart
+loaded_code:
+#endif /* CONFIG_ROMIMAGE_MMCIF */
+
/* copy the empty_zero_page contents to where vmlinux expects it */
- mova empty_zero_page_src, r0
+ mova extra_data_pos, r0
+ mov.l extra_data_size, r1
+ add r1, r0
mov.l empty_zero_page_dst, r1
mov #(PAGE_SHIFT - 4), r4
mov #1, r3
@@ -37,7 +69,9 @@ romstart:
mov #PAGE_SHIFT, r4
mov #1, r1
shld r4, r1
- mova empty_zero_page_src, r0
+ mova extra_data_pos, r0
+ add r1, r0
+ mov.l extra_data_size, r1
add r1, r0
jmp @r0
nop
@@ -45,4 +79,6 @@ romstart:
.align 2
empty_zero_page_dst:
.long _text
-empty_zero_page_src:
+extra_data_pos:
+extra_data_size:
+ .long zero_page_pos - extra_data_pos
diff --git a/arch/sh/boot/romimage/mmcif-sh7724.c b/arch/sh/boot/romimage/mmcif-sh7724.c
new file mode 100644
index 000000000000..14863d7292cb
--- /dev/null
+++ b/arch/sh/boot/romimage/mmcif-sh7724.c
@@ -0,0 +1,72 @@
+/*
+ * sh7724 MMCIF loader
+ *
+ * Copyright (C) 2010 Magnus Damm
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/mmc/sh_mmcif.h>
+#include <mach/romimage.h>
+
+#define MMCIF_BASE (void __iomem *)0xa4ca0000
+
+#define MSTPCR2 0xa4150038
+#define PTWCR 0xa4050146
+#define PTXCR 0xa4050148
+#define PSELA 0xa405014e
+#define PSELE 0xa4050156
+#define HIZCRC 0xa405015c
+#define DRVCRA 0xa405018a
+
+enum { MMCIF_PROGRESS_ENTER, MMCIF_PROGRESS_INIT,
+ MMCIF_PROGRESS_LOAD, MMCIF_PROGRESS_DONE };
+
+/* SH7724 specific MMCIF loader
+ *
+ * loads the romImage from an MMC card starting from block 512
+ * use the following line to write the romImage to an MMC card
+ * # dd if=arch/sh/boot/romImage of=/dev/sdx bs=512 seek=512
+ */
+asmlinkage void mmcif_loader(unsigned char *buf, unsigned long no_bytes)
+{
+ mmcif_update_progress(MMCIF_PROGRESS_ENTER);
+
+ /* enable clock to the MMCIF hardware block */
+ __raw_writel(__raw_readl(MSTPCR2) & ~0x20000000, MSTPCR2);
+
+ /* setup pins D7-D0 */
+ __raw_writew(0x0000, PTWCR);
+
+ /* setup pins MMC_CLK, MMC_CMD */
+ __raw_writew(__raw_readw(PTXCR) & ~0x000f, PTXCR);
+
+ /* select D3-D0 pin function */
+ __raw_writew(__raw_readw(PSELA) & ~0x2000, PSELA);
+
+ /* select D7-D4 pin function */
+ __raw_writew(__raw_readw(PSELE) & ~0x3000, PSELE);
+
+ /* disable Hi-Z for the MMC pins */
+ __raw_writew(__raw_readw(HIZCRC) & ~0x0620, HIZCRC);
+
+ /* high drive capability for MMC pins */
+ __raw_writew(__raw_readw(DRVCRA) | 0x3000, DRVCRA);
+
+ mmcif_update_progress(MMCIF_PROGRESS_INIT);
+
+ /* setup MMCIF hardware */
+ sh_mmcif_boot_init(MMCIF_BASE);
+
+ mmcif_update_progress(MMCIF_PROGRESS_LOAD);
+
+ /* load kernel via MMCIF interface */
+ sh_mmcif_boot_slurp(MMCIF_BASE, buf, no_bytes);
+
+ /* disable clock to the MMCIF hardware block */
+ __raw_writel(__raw_readl(MSTPCR2) | 0x20000000, MSTPCR2);
+
+ mmcif_update_progress(MMCIF_PROGRESS_DONE);
+}
diff --git a/arch/sh/boot/romimage/vmlinux.scr b/arch/sh/boot/romimage/vmlinux.scr
index 287c08f8b4bb..590394e2f5f2 100644
--- a/arch/sh/boot/romimage/vmlinux.scr
+++ b/arch/sh/boot/romimage/vmlinux.scr
@@ -1,6 +1,8 @@
SECTIONS
{
.text : {
+ zero_page_pos = .;
*(.data)
+ end_data = .;
}
}
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 953af139e230..1e9598d2bbf4 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -139,8 +139,6 @@ static void pcibios_fixup_device_resources(struct pci_dev *dev,
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (!dev->resource[i].start)
continue;
- if (dev->resource[i].flags & IORESOURCE_PCI_FIXED)
- continue;
if (dev->resource[i].flags & IORESOURCE_IO)
offset = hose->io_offset;
else if (dev->resource[i].flags & IORESOURCE_MEM)
diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h
index e461d67f03c3..ef9e555aafba 100644
--- a/arch/sh/include/asm/cache.h
+++ b/arch/sh/include/asm/cache.h
@@ -14,7 +14,7 @@
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#ifndef __ASSEMBLY__
struct cache_info {
diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h
index f689554e17c1..b237d525d592 100644
--- a/arch/sh/include/asm/io.h
+++ b/arch/sh/include/asm/io.h
@@ -39,6 +39,8 @@
#include <asm/io_generic.h>
#include <asm/io_trapped.h>
+#ifdef CONFIG_HAS_IOPORT
+
#define inb(p) sh_mv.mv_inb((p))
#define inw(p) sh_mv.mv_inw((p))
#define inl(p) sh_mv.mv_inl((p))
@@ -60,6 +62,8 @@
#define outsw(p,b,c) sh_mv.mv_outsw((p), (b), (c))
#define outsl(p,b,c) sh_mv.mv_outsl((p), (b), (c))
+#endif
+
#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile u8 __force *)(a) = (v))
#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v))
#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v))
@@ -240,6 +244,8 @@ __BUILD_MEMORY_STRING(q, u64)
#define IO_SPACE_LIMIT 0xffffffff
+#ifdef CONFIG_HAS_IOPORT
+
/*
* This function provides a method for the generic case where a
* board-specific ioport_map simply needs to return the port + some
@@ -255,6 +261,8 @@ static inline void __set_io_port_base(unsigned long pbase)
#define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n))
+#endif
+
/* We really want to try and get these to memcpy etc */
void memcpy_fromio(void *, const volatile void __iomem *, unsigned long);
void memcpy_toio(volatile void __iomem *, const void *, unsigned long);
diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h
index bc0218cb72e1..a0b0cf79cf8a 100644
--- a/arch/sh/include/asm/machvec.h
+++ b/arch/sh/include/asm/machvec.h
@@ -19,6 +19,10 @@ struct sh_machine_vector {
const char *mv_name;
int mv_nr_irqs;
+ int (*mv_irq_demux)(int irq);
+ void (*mv_init_irq)(void);
+
+#ifdef CONFIG_HAS_IOPORT
u8 (*mv_inb)(unsigned long);
u16 (*mv_inw)(unsigned long);
u32 (*mv_inl)(unsigned long);
@@ -40,12 +44,9 @@ struct sh_machine_vector {
void (*mv_outsw)(unsigned long, const void *src, unsigned long count);
void (*mv_outsl)(unsigned long, const void *src, unsigned long count);
- int (*mv_irq_demux)(int irq);
-
- void (*mv_init_irq)(void);
-
void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
void (*mv_ioport_unmap)(void __iomem *);
+#endif
int (*mv_clk_init)(void);
int (*mv_mode_pins)(void);
diff --git a/arch/sh/include/cpu-sh4/cpu/sh7724.h b/arch/sh/include/cpu-sh4/cpu/sh7724.h
index fbbf550cc529..4c27b68789b3 100644
--- a/arch/sh/include/cpu-sh4/cpu/sh7724.h
+++ b/arch/sh/include/cpu-sh4/cpu/sh7724.h
@@ -9,6 +9,7 @@
* MD3: BSC - Area0 Bus Width (16/32-bit) [CS0BCR.9,10]
* MD5: BSC - Endian Mode (L: Big, H: Little) [CMNCR.3]
* MD8: Test Mode
+ * BOOT: FBR - Boot Mode (L: MMCIF, H: Area0)
*/
/* Pin Function Controller:
diff --git a/arch/sh/include/mach-common/mach/romimage.h b/arch/sh/include/mach-common/mach/romimage.h
index 267e24112d82..08fb42269ecd 100644
--- a/arch/sh/include/mach-common/mach/romimage.h
+++ b/arch/sh/include/mach-common/mach/romimage.h
@@ -1 +1,11 @@
+#ifdef __ASSEMBLY__
+
/* do nothing here by default */
+
+#else /* __ASSEMBLY__ */
+
+extern inline void mmcif_update_progress(int nr)
+{
+}
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sh/include/mach-ecovec24/mach/romimage.h b/arch/sh/include/mach-ecovec24/mach/romimage.h
index 1c8787ecb1c1..1dcf5e6c8d83 100644
--- a/arch/sh/include/mach-ecovec24/mach/romimage.h
+++ b/arch/sh/include/mach-ecovec24/mach/romimage.h
@@ -1,3 +1,5 @@
+#ifdef __ASSEMBLY__
+
/* EcoVec board specific boot code:
* converts the "partner-jet-script.txt" script into assembly
* the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,28 @@
.align 2
1 : .long 0xa8000000
2 :
+
+#else /* __ASSEMBLY__ */
+
+/* Ecovec board specific information:
+ *
+ * Set the following to enable MMCIF boot from the MMC card in CN12:
+ *
+ * DS1.5 = OFF (SH BOOT pin set to L)
+ * DS2.6 = OFF (Select MMCIF on CN12 instead of SDHI1)
+ * DS2.7 = ON (Select MMCIF on CN12 instead of SDHI1)
+ *
+ */
+#define HIZCRA 0xa4050158
+#define PGDR 0xa405012c
+
+extern inline void mmcif_update_progress(int nr)
+{
+ /* disable Hi-Z for LED pins */
+ __raw_writew(__raw_readw(HIZCRA) & ~(1 << 1), HIZCRA);
+
+ /* update progress on LED4, LED5, LED6 and LED7 */
+ __raw_writeb(1 << (nr - 1), PGDR);
+}
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sh/include/mach-kfr2r09/mach/romimage.h b/arch/sh/include/mach-kfr2r09/mach/romimage.h
index a110823f2bde..976256a323f2 100644
--- a/arch/sh/include/mach-kfr2r09/mach/romimage.h
+++ b/arch/sh/include/mach-kfr2r09/mach/romimage.h
@@ -1,3 +1,5 @@
+#ifdef __ASSEMBLY__
+
/* kfr2r09 board specific boot code:
* converts the "partner-jet-script.txt" script into assembly
* the assembly code is the first code to be executed in the romImage
@@ -18,3 +20,11 @@
.align 2
1: .long 0xa8000000
2:
+
+#else /* __ASSEMBLY__ */
+
+extern inline void mmcif_update_progress(int nr)
+{
+}
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index 650b92f00ee5..e25f3c69525d 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -12,7 +12,7 @@ endif
CFLAGS_REMOVE_return_address.o = -pg
obj-y := clkdev.o debugtraps.o dma-nommu.o dumpstack.o \
- idle.o io.o io_generic.o irq.o \
+ idle.o io.o irq.o \
irq_$(BITS).o machvec.o nmi_debug.o process.o \
process_$(BITS).o ptrace_$(BITS).o \
reboot.o return_address.o \
@@ -39,6 +39,7 @@ obj-$(CONFIG_DUMP_CODE) += disassemble.o
obj-$(CONFIG_HIBERNATION) += swsusp.o
obj-$(CONFIG_DWARF_UNWINDER) += dwarf.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_callchain.o
+obj-$(CONFIG_HAS_IOPORT) += io_generic.o
obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) += localtimer.o
diff --git a/arch/sh/kernel/dwarf.c b/arch/sh/kernel/dwarf.c
index 886d7d83ace3..49c09c7d5b77 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -49,6 +49,8 @@ static DEFINE_SPINLOCK(dwarf_fde_lock);
static struct dwarf_cie *cached_cie;
+static unsigned int dwarf_unwinder_ready;
+
/**
* dwarf_frame_alloc_reg - allocate memory for a DWARF register
* @frame: the DWARF frame whose list of registers we insert on
@@ -582,6 +584,13 @@ struct dwarf_frame *dwarf_unwind_stack(unsigned long pc,
unsigned long addr;
/*
+ * If we've been called in to before initialization has
+ * completed, bail out immediately.
+ */
+ if (!dwarf_unwinder_ready)
+ return NULL;
+
+ /*
* If we're starting at the top of the stack we need get the
* contents of a physical register to get the CFA in order to
* begin the virtual unwinding of the stack.
@@ -1167,7 +1176,7 @@ void module_dwarf_cleanup(struct module *mod)
*/
static int __init dwarf_unwinder_init(void)
{
- int err;
+ int err = -ENOMEM;
dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
sizeof(struct dwarf_frame), 0,
@@ -1181,11 +1190,15 @@ static int __init dwarf_unwinder_init(void)
mempool_alloc_slab,
mempool_free_slab,
dwarf_frame_cachep);
+ if (!dwarf_frame_pool)
+ goto out;
dwarf_reg_pool = mempool_create(DWARF_REG_MIN_REQ,
mempool_alloc_slab,
mempool_free_slab,
dwarf_reg_cachep);
+ if (!dwarf_reg_pool)
+ goto out;
err = dwarf_parse_section(__start_eh_frame, __stop_eh_frame, NULL);
if (err)
@@ -1195,11 +1208,13 @@ static int __init dwarf_unwinder_init(void)
if (err)
goto out;
+ dwarf_unwinder_ready = 1;
+
return 0;
out:
printk(KERN_ERR "Failed to initialise DWARF unwinder: %d\n", err);
dwarf_unwinder_cleanup();
- return -EINVAL;
+ return err;
}
early_initcall(dwarf_unwinder_init);
diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
index 4770c241c679..5c51b794ba2a 100644
--- a/arch/sh/kernel/io.c
+++ b/arch/sh/kernel/io.c
@@ -112,25 +112,3 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
}
}
EXPORT_SYMBOL(memset_io);
-
-#ifndef CONFIG_GENERIC_IOMAP
-
-void __iomem *ioport_map(unsigned long port, unsigned int nr)
-{
- void __iomem *ret;
-
- ret = __ioport_map_trapped(port, nr);
- if (ret)
- return ret;
-
- return __ioport_map(port, nr);
-}
-EXPORT_SYMBOL(ioport_map);
-
-void ioport_unmap(void __iomem *addr)
-{
- sh_mv.mv_ioport_unmap(addr);
-}
-EXPORT_SYMBOL(ioport_unmap);
-
-#endif /* CONFIG_GENERIC_IOMAP */
diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c
index e1e1dbd19557..447d78f666f9 100644
--- a/arch/sh/kernel/io_generic.c
+++ b/arch/sh/kernel/io_generic.c
@@ -158,3 +158,23 @@ void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
void generic_ioport_unmap(void __iomem *addr)
{
}
+
+#ifndef CONFIG_GENERIC_IOMAP
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+ void __iomem *ret;
+
+ ret = __ioport_map_trapped(port, nr);
+ if (ret)
+ return ret;
+
+ return __ioport_map(port, nr);
+}
+EXPORT_SYMBOL(ioport_map);
+
+void ioport_unmap(void __iomem *addr)
+{
+ sh_mv.mv_ioport_unmap(addr);
+}
+EXPORT_SYMBOL(ioport_unmap);
+#endif /* CONFIG_GENERIC_IOMAP */
diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c
index 4a8bb4eeb8ad..2947d2bd1291 100644
--- a/arch/sh/kernel/io_trapped.c
+++ b/arch/sh/kernel/io_trapped.c
@@ -91,10 +91,14 @@ int register_trapped_io(struct trapped_io *tiop)
tiop->magic = IO_TRAPPED_MAGIC;
INIT_LIST_HEAD(&tiop->list);
spin_lock_irq(&trapped_lock);
+#ifdef CONFIG_HAS_IOPORT
if (flags & IORESOURCE_IO)
list_add(&tiop->list, &trapped_io);
+#endif
+#ifdef CONFIG_HAS_IOMEM
if (flags & IORESOURCE_MEM)
list_add(&tiop->list, &trapped_mem);
+#endif
spin_unlock_irq(&trapped_lock);
return 0;
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
index 85cfaf916fdc..9f9bb63616ad 100644
--- a/arch/sh/kernel/machvec.c
+++ b/arch/sh/kernel/machvec.c
@@ -118,6 +118,14 @@ void __init sh_mv_setup(void)
sh_mv.mv_##elem = generic_##elem; \
} while (0)
+#ifdef CONFIG_HAS_IOPORT
+
+#ifdef P2SEG
+ __set_io_port_base(P2SEG);
+#else
+ __set_io_port_base(0);
+#endif
+
mv_set(inb); mv_set(inw); mv_set(inl);
mv_set(outb); mv_set(outw); mv_set(outl);
@@ -129,16 +137,13 @@ void __init sh_mv_setup(void)
mv_set(ioport_map);
mv_set(ioport_unmap);
+
+#endif
+
mv_set(irq_demux);
mv_set(mode_pins);
mv_set(mem_init);
if (!sh_mv.mv_nr_irqs)
sh_mv.mv_nr_irqs = NR_IRQS;
-
-#ifdef P2SEG
- __set_io_port_base(P2SEG);
-#else
- __set_io_port_base(0);
-#endif
}
diff --git a/arch/sh/kernel/return_address.c b/arch/sh/kernel/return_address.c
index cbf1dd5372b2..5124aeb28c3f 100644
--- a/arch/sh/kernel/return_address.c
+++ b/arch/sh/kernel/return_address.c
@@ -24,6 +24,8 @@ void *return_address(unsigned int depth)
struct dwarf_frame *tmp;
tmp = dwarf_unwind_stack(ra, frame);
+ if (!tmp)
+ return NULL;
if (frame)
dwarf_free_frame(frame);
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c
index bbf91b9c3d39..e7f2940bd270 100644
--- a/arch/sparc/boot/btfixupprep.c
+++ b/arch/sparc/boot/btfixupprep.c
@@ -325,7 +325,7 @@ main1:
(*rr)->next = NULL;
}
printf("! Generated by btfixupprep. Do not edit.\n\n");
- printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n");
+ printf("\t.section\t\".data..init\",#alloc,#write\n\t.align\t4\n\n");
printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n");
for (i = 0; i < last; i++) {
f = array + i;
diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h
index 78b07009f60a..0588b8c7faa2 100644
--- a/arch/sparc/include/asm/cache.h
+++ b/arch/sparc/include/asm/cache.h
@@ -21,7 +21,7 @@
#define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT)
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#ifdef CONFIG_SPARC32
#include <asm/asi.h>
diff --git a/arch/tile/Kbuild b/arch/tile/Kbuild
new file mode 100644
index 000000000000..a9b922716092
--- /dev/null
+++ b/arch/tile/Kbuild
@@ -0,0 +1,3 @@
+
+obj-y += kernel/
+obj-y += mm/
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
new file mode 100644
index 000000000000..290ef4161939
--- /dev/null
+++ b/arch/tile/Kconfig
@@ -0,0 +1,352 @@
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+
+config MMU
+ def_bool y
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_HARDIRQS
+ def_bool y
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ def_bool y
+
+config GENERIC_IRQ_PROBE
+ def_bool y
+
+config GENERIC_PENDING_IRQ
+ def_bool y
+ depends on GENERIC_HARDIRQS && SMP
+
+config SEMAPHORE_SLEEPERS
+ def_bool y
+
+config HAVE_ARCH_ALLOC_REMAP
+ def_bool y
+
+config HAVE_SETUP_PER_CPU_AREA
+ def_bool y
+
+config NEED_PER_CPU_PAGE_FIRST_CHUNK
+ def_bool y
+
+config SYS_SUPPORTS_HUGETLBFS
+ def_bool y
+
+config GENERIC_TIME
+ def_bool y
+
+config GENERIC_CLOCKEVENTS
+ def_bool y
+
+# FIXME: tilegx can implement a more efficent rwsem.
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+# We have a very flat architecture from a migration point of view,
+# so save boot time by presetting this (particularly useful on tile-sim).
+config DEFAULT_MIGRATION_COST
+ int
+ default "10000000"
+
+# We only support gcc 4.4 and above, so this should work.
+config ARCH_SUPPORTS_OPTIMIZED_INLINING
+ def_bool y
+
+config ARCH_PHYS_ADDR_T_64BIT
+ def_bool y
+
+config LOCKDEP_SUPPORT
+ def_bool y
+
+config STACKTRACE_SUPPORT
+ def_bool y
+ select STACKTRACE
+
+# We use discontigmem for now; at some point we may want to switch
+# to sparsemem (Tilera bug 7996).
+config ARCH_DISCONTIGMEM_ENABLE
+ def_bool y
+
+config ARCH_DISCONTIGMEM_DEFAULT
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+config STRICT_DEVMEM
+ def_bool y
+
+# SMP is required for Tilera Linux.
+config SMP
+ def_bool y
+
+# Allow checking for compile-time determined overflow errors in
+# copy_from_user(). There are still unprovable places in the
+# generic code as of 2.6.34, so this option is not really compatible
+# with -Werror, which is more useful in general.
+config DEBUG_COPY_FROM_USER
+ def_bool n
+
+config HVC_TILE
+ select HVC_DRIVER
+ def_bool y
+
+config TILE
+ def_bool y
+ select GENERIC_FIND_FIRST_BIT
+ select GENERIC_FIND_NEXT_BIT
+ select USE_GENERIC_SMP_HELPERS
+ select CC_OPTIMIZE_FOR_SIZE
+
+# FIXME: investigate whether we need/want these options.
+# select HAVE_IOREMAP_PROT
+# select HAVE_OPTPROBES
+# select HAVE_REGS_AND_STACK_ACCESS_API
+# select HAVE_HW_BREAKPOINT
+# select PERF_EVENTS
+# select HAVE_USER_RETURN_NOTIFIER
+# config NO_BOOTMEM
+# config ARCH_SUPPORTS_DEBUG_PAGEALLOC
+# config HUGETLB_PAGE_SIZE_VARIABLE
+
+
+mainmenu "Linux/TILE Kernel Configuration"
+
+# Please note: TILE-Gx support is not yet finalized; this is
+# the preliminary support. TILE-Gx drivers are only provided
+# with the alpha or beta test versions for Tilera customers.
+config TILEGX
+ depends on EXPERIMENTAL
+ bool "Building with TILE-Gx (64-bit) compiler and toolchain"
+
+config 64BIT
+ depends on TILEGX
+ def_bool y
+
+config ARCH_DEFCONFIG
+ string
+ default "arch/tile/configs/tile_defconfig" if !TILEGX
+ default "arch/tile/configs/tilegx_defconfig" if TILEGX
+
+source "init/Kconfig"
+
+menu "Tilera-specific configuration"
+
+config NR_CPUS
+ int "Maximum number of tiles (2-255)"
+ range 2 255
+ depends on SMP
+ default "64"
+ ---help---
+ Building with 64 is the recommended value, but a slightly
+ smaller kernel memory footprint results from using a smaller
+ value on chips with fewer tiles.
+
+source "kernel/time/Kconfig"
+
+source "kernel/Kconfig.hz"
+
+config KEXEC
+ bool "kexec system call"
+ ---help---
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is independent of the system firmware. It is used
+ to implement the "mboot" Tilera booter.
+
+ The name comes from the similarity to the exec system call.
+
+config COMPAT
+ bool "Support 32-bit TILE-Gx binaries in addition to 64-bit"
+ depends on TILEGX
+ select COMPAT_BINFMT_ELF
+ default y
+ ---help---
+ If enabled, the kernel will support running TILE-Gx binaries
+ that were built with the -m32 option.
+
+config SYSVIPC_COMPAT
+ def_bool y
+ depends on COMPAT && SYSVIPC
+
+# We do not currently support disabling HIGHMEM on tile64 and tilepro.
+config HIGHMEM
+ bool # "Support for more than 512 MB of RAM"
+ default !TILEGX
+ ---help---
+ Linux can use the full amount of RAM in the system by
+ default. However, the address space of TILE processors is
+ only 4 Gigabytes large. That means that, if you have a large
+ amount of physical memory, not all of it can be "permanently
+ mapped" by the kernel. The physical memory that's not
+ permanently mapped is called "high memory".
+
+ If you are compiling a kernel which will never run on a
+ machine with more than 512 MB total physical RAM, answer
+ "false" here. This will result in the kernel mapping all of
+ physical memory into the top 1 GB of virtual memory space.
+
+ If unsure, say "true".
+
+# We do not currently support disabling NUMA.
+config NUMA
+ bool # "NUMA Memory Allocation and Scheduler Support"
+ depends on SMP && DISCONTIGMEM
+ default y
+ ---help---
+ NUMA memory allocation is required for TILE processors
+ unless booting with memory striping enabled in the
+ hypervisor, or with only a single memory controller.
+ It is recommended that this option always be enabled.
+
+config NODES_SHIFT
+ int "Log base 2 of the max number of memory controllers"
+ default 2
+ depends on NEED_MULTIPLE_NODES
+ ---help---
+ By default, 2, i.e. 2^2 == 4 DDR2 controllers.
+ In a system with more controllers, this value should be raised.
+
+# Need 16MB areas to enable hugetlb
+# See build-time check in arch/tile/mm/init.c.
+config FORCE_MAX_ZONEORDER
+ int
+ default 9
+
+choice
+ depends on !TILEGX
+ prompt "Memory split" if EMBEDDED
+ default VMSPLIT_3G
+ ---help---
+ Select the desired split between kernel and user memory.
+
+ If the address range available to the kernel is less than the
+ physical memory installed, the remaining memory will be available
+ as "high memory". Accessing high memory is a little more costly
+ than low memory, as it needs to be mapped into the kernel first.
+ Note that increasing the kernel address space limits the range
+ available to user programs, making the address space there
+ tighter. Selecting anything other than the default 3G/1G split
+ will also likely make your kernel incompatible with binary-only
+ kernel modules.
+
+ If you are not absolutely sure what you are doing, leave this
+ option alone!
+
+ config VMSPLIT_375G
+ bool "3.75G/0.25G user/kernel split (no kernel networking)"
+ config VMSPLIT_35G
+ bool "3.5G/0.5G user/kernel split"
+ config VMSPLIT_3G
+ bool "3G/1G user/kernel split"
+ config VMSPLIT_3G_OPT
+ bool "3G/1G user/kernel split (for full 1G low memory)"
+ config VMSPLIT_2G
+ bool "2G/2G user/kernel split"
+ config VMSPLIT_1G
+ bool "1G/3G user/kernel split"
+endchoice
+
+config PAGE_OFFSET
+ hex
+ default 0xF0000000 if VMSPLIT_375G
+ default 0xE0000000 if VMSPLIT_35G
+ default 0xB0000000 if VMSPLIT_3G_OPT
+ default 0x80000000 if VMSPLIT_2G
+ default 0x40000000 if VMSPLIT_1G
+ default 0xC0000000
+
+source "mm/Kconfig"
+
+config CMDLINE_BOOL
+ bool "Built-in kernel command line"
+ default n
+ ---help---
+ Allow for specifying boot arguments to the kernel at
+ build time. On some systems (e.g. embedded ones), it is
+ necessary or convenient to provide some or all of the
+ kernel boot arguments with the kernel itself (that is,
+ to not rely on the boot loader to provide them.)
+
+ To compile command line arguments into the kernel,
+ set this option to 'Y', then fill in the
+ the boot arguments in CONFIG_CMDLINE.
+
+ Systems with fully functional boot loaders (e.g. mboot, or
+ if booting over PCI) should leave this option set to 'N'.
+
+config CMDLINE
+ string "Built-in kernel command string"
+ depends on CMDLINE_BOOL
+ default ""
+ ---help---
+ Enter arguments here that should be compiled into the kernel
+ image and used at boot time. If the boot loader provides a
+ command line at boot time, it is appended to this string to
+ form the full kernel command line, when the system boots.
+
+ However, you can use the CONFIG_CMDLINE_OVERRIDE option to
+ change this behavior.
+
+ In most cases, the command line (whether built-in or provided
+ by the boot loader) should specify the device for the root
+ file system.
+
+config CMDLINE_OVERRIDE
+ bool "Built-in command line overrides boot loader arguments"
+ default n
+ depends on CMDLINE_BOOL
+ ---help---
+ Set this option to 'Y' to have the kernel ignore the boot loader
+ command line, and use ONLY the built-in command line.
+
+ This is used to work around broken boot loaders. This should
+ be set to 'N' under normal conditions.
+
+config VMALLOC_RESERVE
+ hex
+ default 0x1000000
+
+endmenu # Tilera-specific configuration
+
+menu "Bus options"
+
+config NO_IOMEM
+ def_bool !PCI
+
+config NO_IOPORT
+ def_bool !PCI
+
+source "drivers/pci/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Executable file formats"
+
+# only elf supported
+config KCORE_ELF
+ def_bool y
+ depends on PROC_FS
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/tile/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug
new file mode 100644
index 000000000000..a81f0fbf7e60
--- /dev/null
+++ b/arch/tile/Kconfig.debug
@@ -0,0 +1,43 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+config EARLY_PRINTK
+ bool "Early printk" if EMBEDDED && DEBUG_KERNEL
+ default y
+ help
+ Write kernel log output directly via the hypervisor console.
+
+ This is useful for kernel debugging when your machine crashes very
+ early before the console code is initialized. For normal operation
+ it is not recommended because it looks ugly and doesn't cooperate
+ with klogd/syslogd. You should normally N here,
+ unless you want to debug such a crash.
+
+config DEBUG_STACKOVERFLOW
+ bool "Check for stack overflows"
+ depends on DEBUG_KERNEL
+ help
+ This option will cause messages to be printed if free stack space
+ drops below a certain limit.
+
+config DEBUG_STACK_USAGE
+ bool "Stack utilization instrumentation"
+ depends on DEBUG_KERNEL
+ help
+ Enables the display of the minimum amount of free stack which each
+ task has ever had available in the sysrq-T and sysrq-P debug output.
+
+ This option will slow down process creation somewhat.
+
+config DEBUG_EXTRA_FLAGS
+ string "Additional compiler arguments when building with '-g'"
+ depends on DEBUG_INFO
+ default ""
+ help
+ Debug info can be large, and flags like
+ `-femit-struct-debug-baseonly' can reduce the kernel file
+ size and build time noticeably. Such flags are often
+ helpful if the main use of debug info is line number info.
+
+endmenu
diff --git a/arch/tile/Makefile b/arch/tile/Makefile
new file mode 100644
index 000000000000..07c4318c0629
--- /dev/null
+++ b/arch/tile/Makefile
@@ -0,0 +1,52 @@
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+
+ifeq ($(CROSS_COMPILE),)
+# If building with TILERA_ROOT set (i.e. using the Tilera Multicore
+# Development Environment) we can set CROSS_COMPILE based on that.
+ifdef TILERA_ROOT
+CROSS_COMPILE = $(TILERA_ROOT)/bin/tile-
+endif
+endif
+
+# If we're not cross-compiling, make sure we're on the right architecture.
+ifeq ($(CROSS_COMPILE),)
+HOST_ARCH = $(shell uname -m)
+ifneq ($(HOST_ARCH),$(ARCH))
+$(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH))
+endif
+endif
+
+
+KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS)
+
+LIBGCC_PATH := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+
+# Provide the path to use for "make defconfig".
+KBUILD_DEFCONFIG := $(ARCH)_defconfig
+
+# Used as a file extension when useful, e.g. head_$(BITS).o
+# Not needed for (e.g.) "$(CC) -m32" since the compiler automatically
+# uses the right default anyway.
+export BITS
+ifeq ($(CONFIG_TILEGX),y)
+BITS := 64
+else
+BITS := 32
+endif
+
+head-y := arch/tile/kernel/head_$(BITS).o
+
+libs-y += arch/tile/lib/
+libs-y += $(LIBGCC_PATH)
+
+
+# See arch/tile/Kbuild for content of core part of the kernel
+core-y += arch/tile/
diff --git a/arch/tile/configs/tile_defconfig b/arch/tile/configs/tile_defconfig
new file mode 100644
index 000000000000..74a5be39e8f2
--- /dev/null
+++ b/arch/tile/configs/tile_defconfig
@@ -0,0 +1,1289 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.34
+# Fri May 28 17:51:43 2010
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_CSUM=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_ZONE_DMA=y
+CONFIG_SEMAPHORE_SLEEPERS=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_HAVE_ARCH_ALLOC_REMAP=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK=y
+CONFIG_SYS_SUPPORTS_HUGETLBFS=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_CLOCKSOURCE_WATCHDOG=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_DEFAULT_MIGRATION_COST=10000000
+CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING=y
+CONFIG_ARCH_PHYS_ADDR_T_64BIT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_STRICT_DEVMEM=y
+CONFIG_SMP=y
+CONFIG_WERROR=y
+# CONFIG_DEBUG_COPY_FROM_USER is not set
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_HVC_TILE=y
+CONFIG_TILE=y
+# CONFIG_TILEGX is not set
+CONFIG_ARCH_DEFCONFIG="arch/tile/configs/tile_defconfig"
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_RCU_FAST_NO_HZ is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="usr/contents.txt"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_INITRAMFS_COMPRESSION_NONE=y
+# CONFIG_INITRAMFS_COMPRESSION_GZIP is not set
+# CONFIG_INITRAMFS_COMPRESSION_BZIP2 is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZMA is not set
+# CONFIG_INITRAMFS_COMPRESSION_LZO is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+
+#
+# Tilera-specific configuration
+#
+CONFIG_NR_CPUS=64
+CONFIG_HOMECACHE=y
+CONFIG_DATAPLANE=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+# CONFIG_KEXEC is not set
+CONFIG_HIGHMEM=y
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=2
+CONFIG_FORCE_MAX_ZONEORDER=9
+# CONFIG_VMSPLIT_375G is not set
+# CONFIG_VMSPLIT_35G is not set
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_3G_OPT is not set
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM_MANUAL=y
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_DISCONTIGMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_FEEDBACK_COLLECT is not set
+CONFIG_FEEDBACK_USE=""
+# CONFIG_HUGEVMAP is not set
+CONFIG_VMALLOC_RESERVE=0x1000000
+CONFIG_HARDWALL=y
+CONFIG_MEMPROF=y
+CONFIG_XGBE_MAIN=y
+CONFIG_NET_TILE=y
+CONFIG_PSEUDO_NAPI=y
+CONFIG_TILEPCI_ENDP=y
+CONFIG_TILE_IDE_GPIO=y
+CONFIG_TILE_SOFTUART=y
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCI_IOV is not set
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+# CONFIG_IPV6_SIT_6RD is not set
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_CB710_CORE is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+CONFIG_SCSI_MOD=y
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_BNX2_ISCSI is not set
+# CONFIG_BE2ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_HPSA is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_3W_SAS is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_MPT2SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_PMCRAID is not set
+# CONFIG_SCSI_PM8001 is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_BFA_FC is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_ATA_VERBOSE_ERROR=y
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SIL24=y
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATP867X is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_LEGACY is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RDC is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_TOSHIBA is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# You can enable one or both FireWire driver stacks.
+#
+
+#
+# The newer stack is recommended.
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=y
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+CONFIG_E1000E=y
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_IGBVF is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_CNIC is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_VMXNET3 is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_TIMBERDALE is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_HVC_DRIVER=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_XILINX is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_88PM860X is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_MAX8925 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_WM8994 is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_LPC_SCH is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGA_ARB is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+# CONFIG_RTC_INTF_SYSFS is not set
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+CONFIG_DNOTIFY=y
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=y
+# CONFIG_CUSE is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_LOGFS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CEPH_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+CONFIG_DEBUG_SPINLOCK_SLEEP=y
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_VM=y
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_RING_BUFFER=y
+CONFIG_RING_BUFFER_ALLOW_SWAP=y
+CONFIG_TRACING_SUPPORT=y
+CONFIG_FTRACE=y
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_ENABLE_DEFAULT_TRACERS is not set
+# CONFIG_BOOT_TRACER is not set
+CONFIG_BRANCH_PROFILE_NONE=y
+# CONFIG_PROFILE_ANNOTATED_BRANCHES is not set
+# CONFIG_PROFILE_ALL_BRANCHES is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_RING_BUFFER_BENCHMARK is not set
+# CONFIG_SAMPLES is not set
+CONFIG_EARLY_PRINTK=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+CONFIG_DEBUG_EXTRA_FLAGS="-femit-struct-debug-baseonly"
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_RNG=m
+CONFIG_CRYPTO_RNG2=m
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_PCRYPT is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=m
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_FIRST_BIT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_NLATTR=y
diff --git a/arch/tile/include/arch/abi.h b/arch/tile/include/arch/abi.h
new file mode 100644
index 000000000000..7cdc47b3e02a
--- /dev/null
+++ b/arch/tile/include/arch/abi.h
@@ -0,0 +1,93 @@
+// Copyright 2010 Tilera Corporation. All Rights Reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation, version 2.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+// NON INFRINGEMENT. See the GNU General Public License for
+// more details.
+
+//! @file
+//!
+//! ABI-related register definitions helpful when writing assembly code.
+//!
+
+#ifndef __ARCH_ABI_H__
+#define __ARCH_ABI_H__
+
+#include <arch/chip.h>
+
+// Registers 0 - 55 are "normal", but some perform special roles.
+
+#define TREG_FP 52 /**< Frame pointer. */
+#define TREG_TP 53 /**< Thread pointer. */
+#define TREG_SP 54 /**< Stack pointer. */
+#define TREG_LR 55 /**< Link to calling function PC. */
+
+/** Index of last normal general-purpose register. */
+#define TREG_LAST_GPR 55
+
+// Registers 56 - 62 are "special" network registers.
+
+#define TREG_SN 56 /**< Static network access. */
+#define TREG_IDN0 57 /**< IDN demux 0 access. */
+#define TREG_IDN1 58 /**< IDN demux 1 access. */
+#define TREG_UDN0 59 /**< UDN demux 0 access. */
+#define TREG_UDN1 60 /**< UDN demux 1 access. */
+#define TREG_UDN2 61 /**< UDN demux 2 access. */
+#define TREG_UDN3 62 /**< UDN demux 3 access. */
+
+// Register 63 is the "special" zero register.
+
+#define TREG_ZERO 63 /**< "Zero" register; always reads as "0". */
+
+
+/** By convention, this register is used to hold the syscall number. */
+#define TREG_SYSCALL_NR 10
+
+/** Name of register that holds the syscall number, for use in assembly. */
+#define TREG_SYSCALL_NR_NAME r10
+
+
+//! The ABI requires callers to allocate a caller state save area of
+//! this many bytes at the bottom of each stack frame.
+//!
+#ifdef __tile__
+#define C_ABI_SAVE_AREA_SIZE (2 * __SIZEOF_POINTER__)
+#endif
+
+//! The operand to an 'info' opcode directing the backtracer to not
+//! try to find the calling frame.
+//!
+#define INFO_OP_CANNOT_BACKTRACE 2
+
+#ifndef __ASSEMBLER__
+#if CHIP_WORD_SIZE() > 32
+
+//! Unsigned type that can hold a register.
+typedef unsigned long long uint_reg_t;
+
+//! Signed type that can hold a register.
+typedef long long int_reg_t;
+
+//! String prefix to use for printf().
+#define INT_REG_FMT "ll"
+
+#elif !defined(__LP64__) /* avoid confusion with LP64 cross-build tools */
+
+//! Unsigned type that can hold a register.
+typedef unsigned long uint_reg_t;
+
+//! Signed type that can hold a register.
+typedef long int_reg_t;
+
+//! String prefix to use for printf().
+#define INT_REG_FMT "l"
+
+#endif
+#endif /* __ASSEMBLER__ */
+
+#endif // !__ARCH_ABI_H__
diff --git a/arch/tile/include/arch/chip.h b/arch/tile/include/arch/chip.h
new file mode 100644
index 000000000000..926d3db0e91e
--- /dev/null
+++ b/arch/tile/include/arch/chip.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#if __tile_chip__ == 0
+#include <arch/chip_tile64.h>
+#elif __tile_chip__ == 1
+#include <arch/chip_tilepro.h>
+#elif defined(__tilegx__)
+#include <arch/chip_tilegx.h>
+#else
+#error Unexpected Tilera chip type
+#endif
diff --git a/arch/tile/include/arch/chip_tile64.h b/arch/tile/include/arch/chip_tile64.h
new file mode 100644
index 000000000000..18b5bc8e563f
--- /dev/null
+++ b/arch/tile/include/arch/chip_tile64.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/*
+ * @file
+ * Global header file.
+ * This header file specifies defines for TILE64.
+ */
+
+#ifndef __ARCH_CHIP_H__
+#define __ARCH_CHIP_H__
+
+/** Specify chip version.
+ * When possible, prefer the CHIP_xxx symbols below for future-proofing.
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip__ symbol.
+ */
+#define TILE_CHIP 0
+
+/** Specify chip revision.
+ * This provides for the case of a respin of a particular chip type;
+ * the normal value for this symbol is "0".
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip_rev__ symbol.
+ */
+#define TILE_CHIP_REV 0
+
+/** The name of this architecture. */
+#define CHIP_ARCH_NAME "tile64"
+
+/** The ELF e_machine type for binaries for this chip. */
+#define CHIP_ELF_TYPE() EM_TILE64
+
+/** The alternate ELF e_machine type for binaries for this chip. */
+#define CHIP_COMPAT_ELF_TYPE() 0x2506
+
+/** What is the native word size of the machine? */
+#define CHIP_WORD_SIZE() 32
+
+/** How many bits of a virtual address are used. Extra bits must be
+ * the sign extension of the low bits.
+ */
+#define CHIP_VA_WIDTH() 32
+
+/** How many bits are in a physical address? */
+#define CHIP_PA_WIDTH() 36
+
+/** Size of the L2 cache, in bytes. */
+#define CHIP_L2_CACHE_SIZE() 65536
+
+/** Log size of an L2 cache line in bytes. */
+#define CHIP_L2_LOG_LINE_SIZE() 6
+
+/** Size of an L2 cache line, in bytes. */
+#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE())
+
+/** Associativity of the L2 cache. */
+#define CHIP_L2_ASSOC() 2
+
+/** Size of the L1 data cache, in bytes. */
+#define CHIP_L1D_CACHE_SIZE() 8192
+
+/** Log size of an L1 data cache line in bytes. */
+#define CHIP_L1D_LOG_LINE_SIZE() 4
+
+/** Size of an L1 data cache line, in bytes. */
+#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE())
+
+/** Associativity of the L1 data cache. */
+#define CHIP_L1D_ASSOC() 2
+
+/** Size of the L1 instruction cache, in bytes. */
+#define CHIP_L1I_CACHE_SIZE() 8192
+
+/** Log size of an L1 instruction cache line in bytes. */
+#define CHIP_L1I_LOG_LINE_SIZE() 6
+
+/** Size of an L1 instruction cache line, in bytes. */
+#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE())
+
+/** Associativity of the L1 instruction cache. */
+#define CHIP_L1I_ASSOC() 1
+
+/** Stride with which flush instructions must be issued. */
+#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which inv instructions must be issued. */
+#define CHIP_INV_STRIDE() CHIP_L1D_LINE_SIZE()
+
+/** Stride with which finv instructions must be issued. */
+#define CHIP_FINV_STRIDE() CHIP_L1D_LINE_SIZE()
+
+/** Can the local cache coherently cache data that is homed elsewhere? */
+#define CHIP_HAS_COHERENT_LOCAL_CACHE() 0
+
+/** How many simultaneous outstanding victims can the L2 cache have? */
+#define CHIP_MAX_OUTSTANDING_VICTIMS() 2
+
+/** Does the TLB support the NC and NOALLOC bits? */
+#define CHIP_HAS_NC_AND_NOALLOC_BITS() 0
+
+/** Does the chip support hash-for-home caching? */
+#define CHIP_HAS_CBOX_HOME_MAP() 0
+
+/** Number of entries in the chip's home map tables. */
+/* #define CHIP_CBOX_HOME_MAP_SIZE() -- does not apply to chip 0 */
+
+/** Do uncacheable requests miss in the cache regardless of whether
+ * there is matching data? */
+#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 0
+
+/** Does the mf instruction wait for victims? */
+#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 1
+
+/** Does the chip have an "inv" instruction that doesn't also flush? */
+#define CHIP_HAS_INV() 0
+
+/** Does the chip have a "wh64" instruction? */
+#define CHIP_HAS_WH64() 0
+
+/** Does this chip have a 'dword_align' instruction? */
+#define CHIP_HAS_DWORD_ALIGN() 0
+
+/** Number of performance counters. */
+#define CHIP_PERFORMANCE_COUNTERS() 2
+
+/** Does this chip have auxiliary performance counters? */
+#define CHIP_HAS_AUX_PERF_COUNTERS() 0
+
+/** Is the CBOX_MSR1 SPR supported? */
+#define CHIP_HAS_CBOX_MSR1() 0
+
+/** Is the TILE_RTF_HWM SPR supported? */
+#define CHIP_HAS_TILE_RTF_HWM() 0
+
+/** Is the TILE_WRITE_PENDING SPR supported? */
+#define CHIP_HAS_TILE_WRITE_PENDING() 0
+
+/** Is the PROC_STATUS SPR supported? */
+#define CHIP_HAS_PROC_STATUS_SPR() 0
+
+/** Log of the number of mshims we have. */
+#define CHIP_LOG_NUM_MSHIMS() 2
+
+/** Are the bases of the interrupt vector areas fixed? */
+#define CHIP_HAS_FIXED_INTVEC_BASE() 1
+
+/** Are the interrupt masks split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_INTR_MASK() 1
+
+/** Is the cycle count split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_CYCLE() 1
+
+/** Does the chip have a static network? */
+#define CHIP_HAS_SN() 1
+
+/** Does the chip have a static network processor? */
+#define CHIP_HAS_SN_PROC() 1
+
+/** Size of the L1 static network processor instruction cache, in bytes. */
+#define CHIP_L1SNI_CACHE_SIZE() 2048
+
+/** Does the chip have DMA support in each tile? */
+#define CHIP_HAS_TILE_DMA() 1
+
+/** Does the chip have the second revision of the directly accessible
+ * dynamic networks? This encapsulates a number of characteristics,
+ * including the absence of the catch-all, the absence of inline message
+ * tags, the absence of support for network context-switching, and so on.
+ */
+#define CHIP_HAS_REV1_XDN() 0
+
+/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */
+#define CHIP_HAS_CMPEXCH() 0
+
+/** Does the chip have memory-mapped I/O support? */
+#define CHIP_HAS_MMIO() 0
+
+/** Does the chip have post-completion interrupts? */
+#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 0
+
+/** Does the chip have native single step support? */
+#define CHIP_HAS_SINGLE_STEP() 0
+
+#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */
+
+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 8
+
+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 16
+
+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 16
+
+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 1
+
+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 0
+
+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 0
+
+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 0
+
+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 0
+
+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 0
+
+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 0
+
+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 0
+
+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0
+
+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 0
+
+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 0
+
+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 0
+
+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0
+
+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 0
+
+#endif /* !__OPEN_SOURCE__ */
+#endif /* __ARCH_CHIP_H__ */
diff --git a/arch/tile/include/arch/chip_tilepro.h b/arch/tile/include/arch/chip_tilepro.h
new file mode 100644
index 000000000000..9852af163862
--- /dev/null
+++ b/arch/tile/include/arch/chip_tilepro.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/*
+ * @file
+ * Global header file.
+ * This header file specifies defines for TILEPro.
+ */
+
+#ifndef __ARCH_CHIP_H__
+#define __ARCH_CHIP_H__
+
+/** Specify chip version.
+ * When possible, prefer the CHIP_xxx symbols below for future-proofing.
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip__ symbol.
+ */
+#define TILE_CHIP 1
+
+/** Specify chip revision.
+ * This provides for the case of a respin of a particular chip type;
+ * the normal value for this symbol is "0".
+ * This is intended for cross-compiling; native compilation should
+ * use the predefined __tile_chip_rev__ symbol.
+ */
+#define TILE_CHIP_REV 0
+
+/** The name of this architecture. */
+#define CHIP_ARCH_NAME "tilepro"
+
+/** The ELF e_machine type for binaries for this chip. */
+#define CHIP_ELF_TYPE() EM_TILEPRO
+
+/** The alternate ELF e_machine type for binaries for this chip. */
+#define CHIP_COMPAT_ELF_TYPE() 0x2507
+
+/** What is the native word size of the machine? */
+#define CHIP_WORD_SIZE() 32
+
+/** How many bits of a virtual address are used. Extra bits must be
+ * the sign extension of the low bits.
+ */
+#define CHIP_VA_WIDTH() 32
+
+/** How many bits are in a physical address? */
+#define CHIP_PA_WIDTH() 36
+
+/** Size of the L2 cache, in bytes. */
+#define CHIP_L2_CACHE_SIZE() 65536
+
+/** Log size of an L2 cache line in bytes. */
+#define CHIP_L2_LOG_LINE_SIZE() 6
+
+/** Size of an L2 cache line, in bytes. */
+#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE())
+
+/** Associativity of the L2 cache. */
+#define CHIP_L2_ASSOC() 4
+
+/** Size of the L1 data cache, in bytes. */
+#define CHIP_L1D_CACHE_SIZE() 8192
+
+/** Log size of an L1 data cache line in bytes. */
+#define CHIP_L1D_LOG_LINE_SIZE() 4
+
+/** Size of an L1 data cache line, in bytes. */
+#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE())
+
+/** Associativity of the L1 data cache. */
+#define CHIP_L1D_ASSOC() 2
+
+/** Size of the L1 instruction cache, in bytes. */
+#define CHIP_L1I_CACHE_SIZE() 16384
+
+/** Log size of an L1 instruction cache line in bytes. */
+#define CHIP_L1I_LOG_LINE_SIZE() 6
+
+/** Size of an L1 instruction cache line, in bytes. */
+#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE())
+
+/** Associativity of the L1 instruction cache. */
+#define CHIP_L1I_ASSOC() 1
+
+/** Stride with which flush instructions must be issued. */
+#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which inv instructions must be issued. */
+#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Stride with which finv instructions must be issued. */
+#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE()
+
+/** Can the local cache coherently cache data that is homed elsewhere? */
+#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1
+
+/** How many simultaneous outstanding victims can the L2 cache have? */
+#define CHIP_MAX_OUTSTANDING_VICTIMS() 4
+
+/** Does the TLB support the NC and NOALLOC bits? */
+#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1
+
+/** Does the chip support hash-for-home caching? */
+#define CHIP_HAS_CBOX_HOME_MAP() 1
+
+/** Number of entries in the chip's home map tables. */
+#define CHIP_CBOX_HOME_MAP_SIZE() 64
+
+/** Do uncacheable requests miss in the cache regardless of whether
+ * there is matching data? */
+#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1
+
+/** Does the mf instruction wait for victims? */
+#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0
+
+/** Does the chip have an "inv" instruction that doesn't also flush? */
+#define CHIP_HAS_INV() 1
+
+/** Does the chip have a "wh64" instruction? */
+#define CHIP_HAS_WH64() 1
+
+/** Does this chip have a 'dword_align' instruction? */
+#define CHIP_HAS_DWORD_ALIGN() 1
+
+/** Number of performance counters. */
+#define CHIP_PERFORMANCE_COUNTERS() 4
+
+/** Does this chip have auxiliary performance counters? */
+#define CHIP_HAS_AUX_PERF_COUNTERS() 1
+
+/** Is the CBOX_MSR1 SPR supported? */
+#define CHIP_HAS_CBOX_MSR1() 1
+
+/** Is the TILE_RTF_HWM SPR supported? */
+#define CHIP_HAS_TILE_RTF_HWM() 1
+
+/** Is the TILE_WRITE_PENDING SPR supported? */
+#define CHIP_HAS_TILE_WRITE_PENDING() 1
+
+/** Is the PROC_STATUS SPR supported? */
+#define CHIP_HAS_PROC_STATUS_SPR() 1
+
+/** Log of the number of mshims we have. */
+#define CHIP_LOG_NUM_MSHIMS() 2
+
+/** Are the bases of the interrupt vector areas fixed? */
+#define CHIP_HAS_FIXED_INTVEC_BASE() 1
+
+/** Are the interrupt masks split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_INTR_MASK() 1
+
+/** Is the cycle count split up into 2 SPRs? */
+#define CHIP_HAS_SPLIT_CYCLE() 1
+
+/** Does the chip have a static network? */
+#define CHIP_HAS_SN() 1
+
+/** Does the chip have a static network processor? */
+#define CHIP_HAS_SN_PROC() 0
+
+/** Size of the L1 static network processor instruction cache, in bytes. */
+/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 1 */
+
+/** Does the chip have DMA support in each tile? */
+#define CHIP_HAS_TILE_DMA() 1
+
+/** Does the chip have the second revision of the directly accessible
+ * dynamic networks? This encapsulates a number of characteristics,
+ * including the absence of the catch-all, the absence of inline message
+ * tags, the absence of support for network context-switching, and so on.
+ */
+#define CHIP_HAS_REV1_XDN() 0
+
+/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */
+#define CHIP_HAS_CMPEXCH() 0
+
+/** Does the chip have memory-mapped I/O support? */
+#define CHIP_HAS_MMIO() 0
+
+/** Does the chip have post-completion interrupts? */
+#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 0
+
+/** Does the chip have native single step support? */
+#define CHIP_HAS_SINGLE_STEP() 0
+
+#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */
+
+/** How many entries are present in the instruction TLB? */
+#define CHIP_ITLB_ENTRIES() 16
+
+/** How many entries are present in the data TLB? */
+#define CHIP_DTLB_ENTRIES() 16
+
+/** How many MAF entries does the XAUI shim have? */
+#define CHIP_XAUI_MAF_ENTRIES() 32
+
+/** Does the memory shim have a source-id table? */
+#define CHIP_HAS_MSHIM_SRCID_TABLE() 0
+
+/** Does the L1 instruction cache clear on reset? */
+#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1
+
+/** Does the chip come out of reset with valid coordinates on all tiles?
+ * Note that if defined, this also implies that the upper left is 1,1.
+ */
+#define CHIP_HAS_VALID_TILE_COORD_RESET() 1
+
+/** Does the chip have unified packet formats? */
+#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1
+
+/** Does the chip support write reordering? */
+#define CHIP_HAS_WRITE_REORDERING() 1
+
+/** Does the chip support Y-X routing as well as X-Y? */
+#define CHIP_HAS_Y_X_ROUTING() 1
+
+/** Is INTCTRL_3 managed with the correct MPL? */
+#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1
+
+/** Is it possible to configure the chip to be big-endian? */
+#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1
+
+/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */
+#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 1
+
+/** Is the DIAG_TRACE_WAY SPR supported? */
+#define CHIP_HAS_DIAG_TRACE_WAY() 1
+
+/** Is the MEM_STRIPE_CONFIG SPR supported? */
+#define CHIP_HAS_MEM_STRIPE_CONFIG() 1
+
+/** Are the TLB_PERF SPRs supported? */
+#define CHIP_HAS_TLB_PERF() 1
+
+/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */
+#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 1
+
+/** Does the chip support rev1 DMA packets? */
+#define CHIP_HAS_REV1_DMA_PACKETS() 1
+
+#endif /* !__OPEN_SOURCE__ */
+#endif /* __ARCH_CHIP_H__ */
diff --git a/arch/tile/include/arch/interrupts.h b/arch/tile/include/arch/interrupts.h
new file mode 100644
index 000000000000..20f8f07d2de9
--- /dev/null
+++ b/arch/tile/include/arch/interrupts.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifdef __tilegx__
+#include <arch/interrupts_64.h>
+#else
+#include <arch/interrupts_32.h>
+#endif
diff --git a/arch/tile/include/arch/interrupts_32.h b/arch/tile/include/arch/interrupts_32.h
new file mode 100644
index 000000000000..feffada705f0
--- /dev/null
+++ b/arch/tile/include/arch/interrupts_32.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __ARCH_INTERRUPTS_H__
+#define __ARCH_INTERRUPTS_H__
+
+/** Mask for an interrupt. */
+#ifdef __ASSEMBLER__
+/* Note: must handle breaking interrupts into high and low words manually. */
+#define INT_MASK(intno) (1 << (intno))
+#else
+#define INT_MASK(intno) (1ULL << (intno))
+#endif
+
+
+/** Where a given interrupt executes */
+#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8))
+
+/** Where to store a vector for a given interrupt. */
+#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0)
+
+/** The base address of user-level interrupts. */
+#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0)
+
+
+/** Additional synthetic interrupt. */
+#define INT_BREAKPOINT (63)
+
+#define INT_ITLB_MISS 0
+#define INT_MEM_ERROR 1
+#define INT_ILL 2
+#define INT_GPV 3
+#define INT_SN_ACCESS 4
+#define INT_IDN_ACCESS 5
+#define INT_UDN_ACCESS 6
+#define INT_IDN_REFILL 7
+#define INT_UDN_REFILL 8
+#define INT_IDN_COMPLETE 9
+#define INT_UDN_COMPLETE 10
+#define INT_SWINT_3 11
+#define INT_SWINT_2 12
+#define INT_SWINT_1 13
+#define INT_SWINT_0 14
+#define INT_UNALIGN_DATA 15
+#define INT_DTLB_MISS 16
+#define INT_DTLB_ACCESS 17
+#define INT_DMATLB_MISS 18
+#define INT_DMATLB_ACCESS 19
+#define INT_SNITLB_MISS 20
+#define INT_SN_NOTIFY 21
+#define INT_SN_FIREWALL 22
+#define INT_IDN_FIREWALL 23
+#define INT_UDN_FIREWALL 24
+#define INT_TILE_TIMER 25
+#define INT_IDN_TIMER 26
+#define INT_UDN_TIMER 27
+#define INT_DMA_NOTIFY 28
+#define INT_IDN_CA 29
+#define INT_UDN_CA 30
+#define INT_IDN_AVAIL 31
+#define INT_UDN_AVAIL 32
+#define INT_PERF_COUNT 33
+#define INT_INTCTRL_3 34
+#define INT_INTCTRL_2 35
+#define INT_INTCTRL_1 36
+#define INT_INTCTRL_0 37
+#define INT_BOOT_ACCESS 38
+#define INT_WORLD_ACCESS 39
+#define INT_I_ASID 40
+#define INT_D_ASID 41
+#define INT_DMA_ASID 42
+#define INT_SNI_ASID 43
+#define INT_DMA_CPL 44
+#define INT_SN_CPL 45
+#define INT_DOUBLE_FAULT 46
+#define INT_SN_STATIC_ACCESS 47
+#define INT_AUX_PERF_COUNT 48
+
+#define NUM_INTERRUPTS 49
+
+#define QUEUED_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_DMATLB_MISS) | \
+ INT_MASK(INT_DMATLB_ACCESS) | \
+ INT_MASK(INT_SNITLB_MISS) | \
+ INT_MASK(INT_SN_NOTIFY) | \
+ INT_MASK(INT_SN_FIREWALL) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_DMA_NOTIFY) | \
+ INT_MASK(INT_IDN_CA) | \
+ INT_MASK(INT_UDN_CA) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DMA_ASID) | \
+ INT_MASK(INT_SNI_ASID) | \
+ INT_MASK(INT_DMA_CPL) | \
+ INT_MASK(INT_SN_CPL) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ 0)
+#define NONQUEUED_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_SN_ACCESS) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_IDN_REFILL) | \
+ INT_MASK(INT_UDN_REFILL) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_SN_STATIC_ACCESS) | \
+ 0)
+#define CRITICAL_MASKED_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_DMATLB_MISS) | \
+ INT_MASK(INT_DMATLB_ACCESS) | \
+ INT_MASK(INT_SNITLB_MISS) | \
+ INT_MASK(INT_SN_NOTIFY) | \
+ INT_MASK(INT_SN_FIREWALL) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_DMA_NOTIFY) | \
+ INT_MASK(INT_IDN_CA) | \
+ INT_MASK(INT_UDN_CA) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ 0)
+#define CRITICAL_UNMASKED_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_SN_ACCESS) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_IDN_REFILL) | \
+ INT_MASK(INT_UDN_REFILL) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DMA_ASID) | \
+ INT_MASK(INT_SNI_ASID) | \
+ INT_MASK(INT_DMA_CPL) | \
+ INT_MASK(INT_SN_CPL) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ INT_MASK(INT_SN_STATIC_ACCESS) | \
+ 0)
+#define MASKABLE_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_IDN_REFILL) | \
+ INT_MASK(INT_UDN_REFILL) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_DMATLB_MISS) | \
+ INT_MASK(INT_DMATLB_ACCESS) | \
+ INT_MASK(INT_SNITLB_MISS) | \
+ INT_MASK(INT_SN_NOTIFY) | \
+ INT_MASK(INT_SN_FIREWALL) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_DMA_NOTIFY) | \
+ INT_MASK(INT_IDN_CA) | \
+ INT_MASK(INT_UDN_CA) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ 0)
+#define UNMASKABLE_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_SN_ACCESS) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DMA_ASID) | \
+ INT_MASK(INT_SNI_ASID) | \
+ INT_MASK(INT_DMA_CPL) | \
+ INT_MASK(INT_SN_CPL) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ INT_MASK(INT_SN_STATIC_ACCESS) | \
+ 0)
+#define SYNC_INTERRUPTS ( \
+ INT_MASK(INT_ITLB_MISS) | \
+ INT_MASK(INT_ILL) | \
+ INT_MASK(INT_GPV) | \
+ INT_MASK(INT_SN_ACCESS) | \
+ INT_MASK(INT_IDN_ACCESS) | \
+ INT_MASK(INT_UDN_ACCESS) | \
+ INT_MASK(INT_IDN_REFILL) | \
+ INT_MASK(INT_UDN_REFILL) | \
+ INT_MASK(INT_IDN_COMPLETE) | \
+ INT_MASK(INT_UDN_COMPLETE) | \
+ INT_MASK(INT_SWINT_3) | \
+ INT_MASK(INT_SWINT_2) | \
+ INT_MASK(INT_SWINT_1) | \
+ INT_MASK(INT_SWINT_0) | \
+ INT_MASK(INT_UNALIGN_DATA) | \
+ INT_MASK(INT_DTLB_MISS) | \
+ INT_MASK(INT_DTLB_ACCESS) | \
+ INT_MASK(INT_SN_STATIC_ACCESS) | \
+ 0)
+#define NON_SYNC_INTERRUPTS ( \
+ INT_MASK(INT_MEM_ERROR) | \
+ INT_MASK(INT_DMATLB_MISS) | \
+ INT_MASK(INT_DMATLB_ACCESS) | \
+ INT_MASK(INT_SNITLB_MISS) | \
+ INT_MASK(INT_SN_NOTIFY) | \
+ INT_MASK(INT_SN_FIREWALL) | \
+ INT_MASK(INT_IDN_FIREWALL) | \
+ INT_MASK(INT_UDN_FIREWALL) | \
+ INT_MASK(INT_TILE_TIMER) | \
+ INT_MASK(INT_IDN_TIMER) | \
+ INT_MASK(INT_UDN_TIMER) | \
+ INT_MASK(INT_DMA_NOTIFY) | \
+ INT_MASK(INT_IDN_CA) | \
+ INT_MASK(INT_UDN_CA) | \
+ INT_MASK(INT_IDN_AVAIL) | \
+ INT_MASK(INT_UDN_AVAIL) | \
+ INT_MASK(INT_PERF_COUNT) | \
+ INT_MASK(INT_INTCTRL_3) | \
+ INT_MASK(INT_INTCTRL_2) | \
+ INT_MASK(INT_INTCTRL_1) | \
+ INT_MASK(INT_INTCTRL_0) | \
+ INT_MASK(INT_BOOT_ACCESS) | \
+ INT_MASK(INT_WORLD_ACCESS) | \
+ INT_MASK(INT_I_ASID) | \
+ INT_MASK(INT_D_ASID) | \
+ INT_MASK(INT_DMA_ASID) | \
+ INT_MASK(INT_SNI_ASID) | \
+ INT_MASK(INT_DMA_CPL) | \
+ INT_MASK(INT_SN_CPL) | \
+ INT_MASK(INT_DOUBLE_FAULT) | \
+ INT_MASK(INT_AUX_PERF_COUNT) | \
+ 0)
+#endif // !__ARCH_INTERRUPTS_H__
diff --git a/arch/tile/include/arch/sim_def.h b/arch/tile/include/arch/sim_def.h
new file mode 100644
index 000000000000..6418fbde063e
--- /dev/null
+++ b/arch/tile/include/arch/sim_def.h
@@ -0,0 +1,512 @@
+// Copyright 2010 Tilera Corporation. All Rights Reserved.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation, version 2.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+// NON INFRINGEMENT. See the GNU General Public License for
+// more details.
+
+//! @file
+//!
+//! Some low-level simulator definitions.
+//!
+
+#ifndef __ARCH_SIM_DEF_H__
+#define __ARCH_SIM_DEF_H__
+
+
+//! Internal: the low bits of the SIM_CONTROL_* SPR values specify
+//! the operation to perform, and the remaining bits are
+//! an operation-specific parameter (often unused).
+//!
+#define _SIM_CONTROL_OPERATOR_BITS 8
+
+
+//== Values which can be written to SPR_SIM_CONTROL.
+
+//! If written to SPR_SIM_CONTROL, stops profiling.
+//!
+#define SIM_CONTROL_PROFILER_DISABLE 0
+
+//! If written to SPR_SIM_CONTROL, starts profiling.
+//!
+#define SIM_CONTROL_PROFILER_ENABLE 1
+
+//! If written to SPR_SIM_CONTROL, clears profiling counters.
+//!
+#define SIM_CONTROL_PROFILER_CLEAR 2
+
+//! If written to SPR_SIM_CONTROL, checkpoints the simulator.
+//!
+#define SIM_CONTROL_CHECKPOINT 3
+
+//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+//! sets the tracing mask to the given mask. See "sim_set_tracing()".
+//!
+#define SIM_CONTROL_SET_TRACING 4
+
+//! If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8),
+//! dumps the requested items of machine state to the log.
+//!
+#define SIM_CONTROL_DUMP 5
+
+//! If written to SPR_SIM_CONTROL, clears chip-level profiling counters.
+//!
+#define SIM_CONTROL_PROFILER_CHIP_CLEAR 6
+
+//! If written to SPR_SIM_CONTROL, disables chip-level profiling.
+//!
+#define SIM_CONTROL_PROFILER_CHIP_DISABLE 7
+
+//! If written to SPR_SIM_CONTROL, enables chip-level profiling.
+//!
+#define SIM_CONTROL_PROFILER_CHIP_ENABLE 8
+
+//! If written to SPR_SIM_CONTROL, enables chip-level functional mode
+//!
+#define SIM_CONTROL_ENABLE_FUNCTIONAL 9
+
+//! If written to SPR_SIM_CONTROL, disables chip-level functional mode.
+//!
+#define SIM_CONTROL_DISABLE_FUNCTIONAL 10
+
+//! If written to SPR_SIM_CONTROL, enables chip-level functional mode.
+//! All tiles must perform this write for functional mode to be enabled.
+//! Ignored in naked boot mode unless --functional is specified.
+//! WARNING: Only the hypervisor startup code should use this!
+//!
+#define SIM_CONTROL_ENABLE_FUNCTIONAL_BARRIER 11
+
+//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+//! writes a string directly to the simulator output. Written to once for
+//! each character in the string, plus a final NUL. Instead of NUL,
+//! you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY".
+//!
+// ISSUE: Document the meaning of "newline", and the handling of NUL.
+//
+#define SIM_CONTROL_PUTC 12
+
+//! If written to SPR_SIM_CONTROL, clears the --grind-coherence state for
+//! this core. This is intended to be used before a loop that will
+//! invalidate the cache by loading new data and evicting all current data.
+//! Generally speaking, this API should only be used by system code.
+//!
+#define SIM_CONTROL_GRINDER_CLEAR 13
+
+//! If written to SPR_SIM_CONTROL, shuts down the simulator.
+//!
+#define SIM_CONTROL_SHUTDOWN 14
+
+//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+//! indicates that a fork syscall just created the given process.
+//!
+#define SIM_CONTROL_OS_FORK 15
+
+//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+//! indicates that an exit syscall was just executed by the given process.
+//!
+#define SIM_CONTROL_OS_EXIT 16
+
+//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+//! indicates that the OS just switched to the given process.
+//!
+#define SIM_CONTROL_OS_SWITCH 17
+
+//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+//! indicates that an exec syscall was just executed. Written to once for
+//! each character in the executable name, plus a final NUL.
+//!
+#define SIM_CONTROL_OS_EXEC 18
+
+//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+//! indicates that an interpreter (PT_INTERP) was loaded. Written to once
+//! for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a
+//! hex load address starting with "0x", and "PATH" is the executable name.
+//!
+#define SIM_CONTROL_OS_INTERP 19
+
+//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+//! indicates that a dll was loaded. Written to once for each character
+//! in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load
+//! address starting with "0x", and "PATH" is the executable name.
+//!
+#define SIM_CONTROL_DLOPEN 20
+
+//! If written to SPR_SIM_CONTROL, combined with a character (shifted by 8),
+//! indicates that a dll was unloaded. Written to once for each character
+//! in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load
+//! address starting with "0x".
+//!
+#define SIM_CONTROL_DLCLOSE 21
+
+//! If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8),
+//! indicates whether to allow data reads to remotely-cached
+//! dirty cache lines to be cached locally without grinder warnings or
+//! assertions (used by Linux kernel fast memcpy).
+//!
+#define SIM_CONTROL_ALLOW_MULTIPLE_CACHING 22
+
+//! If written to SPR_SIM_CONTROL, enables memory tracing.
+//!
+#define SIM_CONTROL_ENABLE_MEM_LOGGING 23
+
+//! If written to SPR_SIM_CONTROL, disables memory tracing.
+//!
+#define SIM_CONTROL_DISABLE_MEM_LOGGING 24
+
+//! If written to SPR_SIM_CONTROL, changes the shaping parameters of one of
+//! the gbe or xgbe shims. Must specify the shim id, the type, the units, and
+//! the rate, as defined in SIM_SHAPING_SPR_ARG.
+//!
+#define SIM_CONTROL_SHAPING 25
+
+//! If written to SPR_SIM_CONTROL, combined with character (shifted by 8),
+//! requests that a simulator command be executed. Written to once for each
+//! character in the command, plus a final NUL.
+//!
+#define SIM_CONTROL_COMMAND 26
+
+//! If written to SPR_SIM_CONTROL, indicates that the simulated system
+//! is panicking, to allow debugging via --debug-on-panic.
+//!
+#define SIM_CONTROL_PANIC 27
+
+//! If written to SPR_SIM_CONTROL, triggers a simulator syscall.
+//! See "sim_syscall()" for more info.
+//!
+#define SIM_CONTROL_SYSCALL 32
+
+//! If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8),
+//! provides the pid that subsequent SIM_CONTROL_OS_FORK writes should
+//! use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH.
+//!
+#define SIM_CONTROL_OS_FORK_PARENT 33
+
+//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+//! (shifted by 8), clears the pending magic data section. The cleared
+//! pending magic data section and any subsequently appended magic bytes
+//! will only take effect when the classifier blast programmer is run.
+#define SIM_CONTROL_CLEAR_MPIPE_MAGIC_BYTES 34
+
+//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+//! (shifted by 8) and a byte of data (shifted by 16), appends that byte
+//! to the shim's pending magic data section. The pending magic data
+//! section takes effect when the classifier blast programmer is run.
+#define SIM_CONTROL_APPEND_MPIPE_MAGIC_BYTE 35
+
+//! If written to SPR_SIM_CONTROL, combined with a mPIPE shim number
+//! (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a
+//! mask of links (shifted by 32), enable or disable the corresponding
+//! mPIPE links.
+#define SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE 36
+
+//== Syscall numbers for use with "sim_syscall()".
+
+//! Syscall number for sim_add_watchpoint().
+//!
+#define SIM_SYSCALL_ADD_WATCHPOINT 2
+
+//! Syscall number for sim_remove_watchpoint().
+//!
+#define SIM_SYSCALL_REMOVE_WATCHPOINT 3
+
+//! Syscall number for sim_query_watchpoint().
+//!
+#define SIM_SYSCALL_QUERY_WATCHPOINT 4
+
+//! Syscall number that asserts that the cache lines whose 64-bit PA
+//! is passed as the second argument to sim_syscall(), and over a
+//! range passed as the third argument, are no longer in cache.
+//! The simulator raises an error if this is not the case.
+//!
+#define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5
+
+
+//== Bit masks which can be shifted by 8, combined with
+//== SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL.
+
+//! @addtogroup arch_sim
+//! @{
+
+//! Enable --trace-cycle when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_CYCLES 0x01
+
+//! Enable --trace-router when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_ROUTER 0x02
+
+//! Enable --trace-register-writes when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_REGISTER_WRITES 0x04
+
+//! Enable --trace-disasm when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_DISASM 0x08
+
+//! Enable --trace-stall-info when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_STALL_INFO 0x10
+
+//! Enable --trace-memory-controller when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_MEMORY_CONTROLLER 0x20
+
+//! Enable --trace-l2 when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_L2_CACHE 0x40
+
+//! Enable --trace-lines when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_LINES 0x80
+
+//! Turn off all tracing when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_NONE 0
+
+//! Turn on all tracing when passed to simulator_set_tracing().
+//!
+#define SIM_TRACE_ALL (-1)
+
+//! @}
+
+//! Computes the value to write to SPR_SIM_CONTROL to set tracing flags.
+//!
+#define SIM_TRACE_SPR_ARG(mask) \
+ (SIM_CONTROL_SET_TRACING | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
+
+
+//== Bit masks which can be shifted by 8, combined with
+//== SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL.
+
+//! @addtogroup arch_sim
+//! @{
+
+//! Dump the general-purpose registers.
+//!
+#define SIM_DUMP_REGS 0x001
+
+//! Dump the SPRs.
+//!
+#define SIM_DUMP_SPRS 0x002
+
+//! Dump the ITLB.
+//!
+#define SIM_DUMP_ITLB 0x004
+
+//! Dump the DTLB.
+//!
+#define SIM_DUMP_DTLB 0x008
+
+//! Dump the L1 I-cache.
+//!
+#define SIM_DUMP_L1I 0x010
+
+//! Dump the L1 D-cache.
+//!
+#define SIM_DUMP_L1D 0x020
+
+//! Dump the L2 cache.
+//!
+#define SIM_DUMP_L2 0x040
+
+//! Dump the switch registers.
+//!
+#define SIM_DUMP_SNREGS 0x080
+
+//! Dump the switch ITLB.
+//!
+#define SIM_DUMP_SNITLB 0x100
+
+//! Dump the switch L1 I-cache.
+//!
+#define SIM_DUMP_SNL1I 0x200
+
+//! Dump the current backtrace.
+//!
+#define SIM_DUMP_BACKTRACE 0x400
+
+//! Only dump valid lines in caches.
+//!
+#define SIM_DUMP_VALID_LINES 0x800
+
+//! Dump everything that is dumpable.
+//!
+#define SIM_DUMP_ALL (-1 & ~SIM_DUMP_VALID_LINES)
+
+// @}
+
+//! Computes the value to write to SPR_SIM_CONTROL to dump machine state.
+//!
+#define SIM_DUMP_SPR_ARG(mask) \
+ (SIM_CONTROL_DUMP | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
+
+
+//== Bit masks which can be shifted by 8, combined with
+//== SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL.
+
+//! @addtogroup arch_sim
+//! @{
+
+//! Use with with SIM_PROFILER_CHIP_xxx to control the memory controllers.
+//!
+#define SIM_CHIP_MEMCTL 0x001
+
+//! Use with with SIM_PROFILER_CHIP_xxx to control the XAUI interface.
+//!
+#define SIM_CHIP_XAUI 0x002
+
+//! Use with with SIM_PROFILER_CHIP_xxx to control the PCIe interface.
+//!
+#define SIM_CHIP_PCIE 0x004
+
+//! Use with with SIM_PROFILER_CHIP_xxx to control the MPIPE interface.
+//!
+#define SIM_CHIP_MPIPE 0x008
+
+//! Reference all chip devices.
+//!
+#define SIM_CHIP_ALL (-1)
+
+//! @}
+
+//! Computes the value to write to SPR_SIM_CONTROL to clear chip statistics.
+//!
+#define SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask) \
+ (SIM_CONTROL_PROFILER_CHIP_CLEAR | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
+
+//! Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.
+//!
+#define SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask) \
+ (SIM_CONTROL_PROFILER_CHIP_DISABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
+
+//! Computes the value to write to SPR_SIM_CONTROL to enable chip statistics.
+//!
+#define SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask) \
+ (SIM_CONTROL_PROFILER_CHIP_ENABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS))
+
+
+
+// Shim bitrate controls.
+
+//! The number of bits used to store the shim id.
+//!
+#define SIM_CONTROL_SHAPING_SHIM_ID_BITS 3
+
+//! @addtogroup arch_sim
+//! @{
+
+//! Change the gbe 0 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_GBE_0 0x0
+
+//! Change the gbe 1 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_GBE_1 0x1
+
+//! Change the gbe 2 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_GBE_2 0x2
+
+//! Change the gbe 3 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_GBE_3 0x3
+
+//! Change the xgbe 0 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_XGBE_0 0x4
+
+//! Change the xgbe 1 bitrate.
+//!
+#define SIM_CONTROL_SHAPING_XGBE_1 0x5
+
+//! The type of shaping to do.
+//!
+#define SIM_CONTROL_SHAPING_TYPE_BITS 2
+
+//! Control the multiplier.
+//!
+#define SIM_CONTROL_SHAPING_MULTIPLIER 0
+
+//! Control the PPS.
+//!
+#define SIM_CONTROL_SHAPING_PPS 1
+
+//! Control the BPS.
+//!
+#define SIM_CONTROL_SHAPING_BPS 2
+
+//! The number of bits for the units for the shaping parameter.
+//!
+#define SIM_CONTROL_SHAPING_UNITS_BITS 2
+
+//! Provide a number in single units.
+//!
+#define SIM_CONTROL_SHAPING_UNITS_SINGLE 0
+
+//! Provide a number in kilo units.
+//!
+#define SIM_CONTROL_SHAPING_UNITS_KILO 1
+
+//! Provide a number in mega units.
+//!
+#define SIM_CONTROL_SHAPING_UNITS_MEGA 2
+
+//! Provide a number in giga units.
+//!
+#define SIM_CONTROL_SHAPING_UNITS_GIGA 3
+
+// @}
+
+//! How many bits are available for the rate.
+//!
+#define SIM_CONTROL_SHAPING_RATE_BITS \
+ (32 - (_SIM_CONTROL_OPERATOR_BITS + \
+ SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
+ SIM_CONTROL_SHAPING_TYPE_BITS + \
+ SIM_CONTROL_SHAPING_UNITS_BITS))
+
+//! Computes the value to write to SPR_SIM_CONTROL to change a bitrate.
+//!
+#define SIM_SHAPING_SPR_ARG(shim, type, units, rate) \
+ (SIM_CONTROL_SHAPING | \
+ ((shim) | \
+ ((type) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS)) | \
+ ((units) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
+ SIM_CONTROL_SHAPING_TYPE_BITS)) | \
+ ((rate) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS + \
+ SIM_CONTROL_SHAPING_TYPE_BITS + \
+ SIM_CONTROL_SHAPING_UNITS_BITS))) << _SIM_CONTROL_OPERATOR_BITS)
+
+
+//== Values returned when reading SPR_SIM_CONTROL.
+// ISSUE: These names should share a longer common prefix.
+
+//! When reading SPR_SIM_CONTROL, the mask of simulator tracing bits
+//! (SIM_TRACE_xxx values).
+//!
+#define SIM_TRACE_FLAG_MASK 0xFFFF
+
+//! When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled.
+//!
+#define SIM_PROFILER_ENABLED_MASK 0x10000
+
+
+//== Special arguments for "SIM_CONTROL_PUTC".
+
+//! Flag value for forcing a PUTC string-flush, including
+//! coordinate/cycle prefix and newline.
+//!
+#define SIM_PUTC_FLUSH_STRING 0x100
+
+//! Flag value for forcing a PUTC binary-data-flush, which skips the
+//! prefix and does not append a newline.
+//!
+#define SIM_PUTC_FLUSH_BINARY 0x101
+
+
+#endif //__ARCH_SIM_DEF_H__
diff --git a/arch/tile/include/arch/spr_def.h b/arch/tile/include/arch/spr_def.h
new file mode 100644
index 000000000000..c8fdbd9a45e6
--- /dev/null
+++ b/arch/tile/include/arch/spr_def.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifdef __tilegx__
+#include <arch/spr_def_64.h>
+#else
+#include <arch/spr_def_32.h>
+#endif
diff --git a/arch/tile/include/arch/spr_def_32.h b/arch/tile/include/arch/spr_def_32.h
new file mode 100644
index 000000000000..b4fc06864df6
--- /dev/null
+++ b/arch/tile/include/arch/spr_def_32.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __DOXYGEN__
+
+#ifndef __ARCH_SPR_DEF_H__
+#define __ARCH_SPR_DEF_H__
+
+#define SPR_AUX_PERF_COUNT_0 0x6005
+#define SPR_AUX_PERF_COUNT_1 0x6006
+#define SPR_AUX_PERF_COUNT_CTL 0x6007
+#define SPR_AUX_PERF_COUNT_STS 0x6008
+#define SPR_CYCLE_HIGH 0x4e06
+#define SPR_CYCLE_LOW 0x4e07
+#define SPR_DMA_BYTE 0x3900
+#define SPR_DMA_CHUNK_SIZE 0x3901
+#define SPR_DMA_CTR 0x3902
+#define SPR_DMA_CTR__REQUEST_MASK 0x1
+#define SPR_DMA_CTR__SUSPEND_MASK 0x2
+#define SPR_DMA_DST_ADDR 0x3903
+#define SPR_DMA_DST_CHUNK_ADDR 0x3904
+#define SPR_DMA_SRC_ADDR 0x3905
+#define SPR_DMA_SRC_CHUNK_ADDR 0x3906
+#define SPR_DMA_STATUS__DONE_MASK 0x1
+#define SPR_DMA_STATUS__BUSY_MASK 0x2
+#define SPR_DMA_STATUS__RUNNING_MASK 0x10
+#define SPR_DMA_STRIDE 0x3907
+#define SPR_DMA_USER_STATUS 0x3908
+#define SPR_DONE 0x4e08
+#define SPR_EVENT_BEGIN 0x4e0d
+#define SPR_EVENT_END 0x4e0e
+#define SPR_EX_CONTEXT_0_0 0x4a05
+#define SPR_EX_CONTEXT_0_1 0x4a06
+#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_0_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_0_1__ICS_MASK 0x4
+#define SPR_EX_CONTEXT_1_0 0x4805
+#define SPR_EX_CONTEXT_1_1 0x4806
+#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0
+#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3
+#define SPR_EX_CONTEXT_1_1__PL_MASK 0x3
+#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2
+#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1
+#define SPR_EX_CONTEXT_1_1__ICS_MASK 0x4
+#define SPR_FAIL 0x4e09
+#define SPR_INTCTRL_0_STATUS 0x4a07
+#define SPR_INTCTRL_1_STATUS 0x4807
+#define SPR_INTERRUPT_CRITICAL_SECTION 0x4e0a
+#define SPR_INTERRUPT_MASK_0_0 0x4a08
+#define SPR_INTERRUPT_MASK_0_1 0x4a09
+#define SPR_INTERRUPT_MASK_1_0 0x4809
+#define SPR_INTERRUPT_MASK_1_1 0x480a
+#define SPR_INTERRUPT_MASK_RESET_0_0 0x4a0a
+#define SPR_INTERRUPT_MASK_RESET_0_1 0x4a0b
+#define SPR_INTERRUPT_MASK_RESET_1_0 0x480b
+#define SPR_INTERRUPT_MASK_RESET_1_1 0x480c
+#define SPR_INTERRUPT_MASK_SET_0_0 0x4a0c
+#define SPR_INTERRUPT_MASK_SET_0_1 0x4a0d
+#define SPR_INTERRUPT_MASK_SET_1_0 0x480d
+#define SPR_INTERRUPT_MASK_SET_1_1 0x480e
+#define SPR_MPL_DMA_CPL_SET_0 0x5800
+#define SPR_MPL_DMA_CPL_SET_1 0x5801
+#define SPR_MPL_DMA_NOTIFY_SET_0 0x3800
+#define SPR_MPL_DMA_NOTIFY_SET_1 0x3801
+#define SPR_MPL_INTCTRL_0_SET_0 0x4a00
+#define SPR_MPL_INTCTRL_0_SET_1 0x4a01
+#define SPR_MPL_INTCTRL_1_SET_0 0x4800
+#define SPR_MPL_INTCTRL_1_SET_1 0x4801
+#define SPR_MPL_SN_ACCESS_SET_0 0x0800
+#define SPR_MPL_SN_ACCESS_SET_1 0x0801
+#define SPR_MPL_SN_CPL_SET_0 0x5a00
+#define SPR_MPL_SN_CPL_SET_1 0x5a01
+#define SPR_MPL_SN_FIREWALL_SET_0 0x2c00
+#define SPR_MPL_SN_FIREWALL_SET_1 0x2c01
+#define SPR_MPL_SN_NOTIFY_SET_0 0x2a00
+#define SPR_MPL_SN_NOTIFY_SET_1 0x2a01
+#define SPR_MPL_UDN_ACCESS_SET_0 0x0c00
+#define SPR_MPL_UDN_ACCESS_SET_1 0x0c01
+#define SPR_MPL_UDN_AVAIL_SET_0 0x4000
+#define SPR_MPL_UDN_AVAIL_SET_1 0x4001
+#define SPR_MPL_UDN_CA_SET_0 0x3c00
+#define SPR_MPL_UDN_CA_SET_1 0x3c01
+#define SPR_MPL_UDN_COMPLETE_SET_0 0x1400
+#define SPR_MPL_UDN_COMPLETE_SET_1 0x1401
+#define SPR_MPL_UDN_FIREWALL_SET_0 0x3000
+#define SPR_MPL_UDN_FIREWALL_SET_1 0x3001
+#define SPR_MPL_UDN_REFILL_SET_0 0x1000
+#define SPR_MPL_UDN_REFILL_SET_1 0x1001
+#define SPR_MPL_UDN_TIMER_SET_0 0x3600
+#define SPR_MPL_UDN_TIMER_SET_1 0x3601
+#define SPR_MPL_WORLD_ACCESS_SET_0 0x4e00
+#define SPR_MPL_WORLD_ACCESS_SET_1 0x4e01
+#define SPR_PASS 0x4e0b
+#define SPR_PERF_COUNT_0 0x4205
+#define SPR_PERF_COUNT_1 0x4206
+#define SPR_PERF_COUNT_CTL 0x4207
+#define SPR_PERF_COUNT_STS 0x4208
+#define SPR_PROC_STATUS 0x4f00
+#define SPR_SIM_CONTROL 0x4e0c
+#define SPR_SNCTL 0x0805
+#define SPR_SNCTL__FRZFABRIC_MASK 0x1
+#define SPR_SNCTL__FRZPROC_MASK 0x2
+#define SPR_SNPC 0x080b
+#define SPR_SNSTATIC 0x080c
+#define SPR_SYSTEM_SAVE_0_0 0x4b00
+#define SPR_SYSTEM_SAVE_0_1 0x4b01
+#define SPR_SYSTEM_SAVE_0_2 0x4b02
+#define SPR_SYSTEM_SAVE_0_3 0x4b03
+#define SPR_SYSTEM_SAVE_1_0 0x4900
+#define SPR_SYSTEM_SAVE_1_1 0x4901
+#define SPR_SYSTEM_SAVE_1_2 0x4902
+#define SPR_SYSTEM_SAVE_1_3 0x4903
+#define SPR_TILE_COORD 0x4c17
+#define SPR_TILE_RTF_HWM 0x4e10
+#define SPR_TILE_TIMER_CONTROL 0x3205
+#define SPR_TILE_WRITE_PENDING 0x4e0f
+#define SPR_UDN_AVAIL_EN 0x4005
+#define SPR_UDN_CA_DATA 0x0d00
+#define SPR_UDN_DATA_AVAIL 0x0d03
+#define SPR_UDN_DEADLOCK_TIMEOUT 0x3606
+#define SPR_UDN_DEMUX_CA_COUNT 0x0c05
+#define SPR_UDN_DEMUX_COUNT_0 0x0c06
+#define SPR_UDN_DEMUX_COUNT_1 0x0c07
+#define SPR_UDN_DEMUX_COUNT_2 0x0c08
+#define SPR_UDN_DEMUX_COUNT_3 0x0c09
+#define SPR_UDN_DEMUX_CTL 0x0c0a
+#define SPR_UDN_DEMUX_QUEUE_SEL 0x0c0c
+#define SPR_UDN_DEMUX_STATUS 0x0c0d
+#define SPR_UDN_DEMUX_WRITE_FIFO 0x0c0e
+#define SPR_UDN_DIRECTION_PROTECT 0x3005
+#define SPR_UDN_REFILL_EN 0x1005
+#define SPR_UDN_SP_FIFO_DATA 0x0c11
+#define SPR_UDN_SP_FIFO_SEL 0x0c12
+#define SPR_UDN_SP_FREEZE 0x0c13
+#define SPR_UDN_SP_FREEZE__SP_FRZ_MASK 0x1
+#define SPR_UDN_SP_FREEZE__DEMUX_FRZ_MASK 0x2
+#define SPR_UDN_SP_FREEZE__NON_DEST_EXT_MASK 0x4
+#define SPR_UDN_SP_STATE 0x0c14
+#define SPR_UDN_TAG_0 0x0c15
+#define SPR_UDN_TAG_1 0x0c16
+#define SPR_UDN_TAG_2 0x0c17
+#define SPR_UDN_TAG_3 0x0c18
+#define SPR_UDN_TAG_VALID 0x0c19
+#define SPR_UDN_TILE_COORD 0x0c1a
+
+#endif /* !defined(__ARCH_SPR_DEF_H__) */
+
+#endif /* !defined(__DOXYGEN__) */
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
new file mode 100644
index 000000000000..3b8f55b82dee
--- /dev/null
+++ b/arch/tile/include/asm/Kbuild
@@ -0,0 +1,3 @@
+include include/asm-generic/Kbuild.asm
+
+header-y += ucontext.h
diff --git a/arch/tile/include/asm/asm-offsets.h b/arch/tile/include/asm/asm-offsets.h
new file mode 100644
index 000000000000..d370ee36a182
--- /dev/null
+++ b/arch/tile/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h
new file mode 100644
index 000000000000..b8c49f98a44c
--- /dev/null
+++ b/arch/tile/include/asm/atomic.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Atomic primitives.
+ */
+
+#ifndef _ASM_TILE_ATOMIC_H
+#define _ASM_TILE_ATOMIC_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/compiler.h>
+#include <asm/system.h>
+
+#define ATOMIC_INIT(i) { (i) }
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.
+ */
+static inline int atomic_read(const atomic_t *v)
+{
+ return v->counter;
+}
+
+/**
+ * atomic_sub_return - subtract integer and return
+ * @v: pointer of type atomic_t
+ * @i: integer value to subtract
+ *
+ * Atomically subtracts @i from @v and returns @v - @i
+ */
+#define atomic_sub_return(i, v) atomic_add_return((int)(-(i)), (v))
+
+/**
+ * atomic_sub - subtract integer from atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+#define atomic_sub(i, v) atomic_add((int)(-(i)), (v))
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns true if the result is
+ * zero, or false for all other cases.
+ */
+#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
+
+/**
+ * atomic_inc_return - increment memory and return
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1 and returns the new value.
+ */
+#define atomic_inc_return(v) atomic_add_return(1, (v))
+
+/**
+ * atomic_dec_return - decrement memory and return
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and returns the new value.
+ */
+#define atomic_dec_return(v) atomic_sub_return(1, (v))
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc(v) atomic_add(1, (v))
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec(v) atomic_sub(1, (v))
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and returns true if the result is 0.
+ */
+#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
+
+/**
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1 and returns true if the result is 0.
+ */
+#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true if the result is
+ * negative, or false when result is greater than or equal to zero.
+ */
+#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0)
+
+/**
+ * atomic_inc_not_zero - increment unless the number is zero
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1, so long as @v is non-zero.
+ * Returns non-zero if @v was non-zero, and zero otherwise.
+ */
+#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
+
+
+/*
+ * We define xchg() and cmpxchg() in the included headers.
+ * Note that we do not define __HAVE_ARCH_CMPXCHG, since that would imply
+ * that cmpxchg() is an efficient operation, which is not particularly true.
+ */
+
+/* Nonexistent functions intended to cause link errors. */
+extern unsigned long __xchg_called_with_bad_pointer(void);
+extern unsigned long __cmpxchg_called_with_bad_pointer(void);
+
+#define tas(ptr) (xchg((ptr), 1))
+
+#endif /* __ASSEMBLY__ */
+
+#ifndef __tilegx__
+#include <asm/atomic_32.h>
+#else
+#include <asm/atomic_64.h>
+#endif
+
+/* Provide the appropriate atomic_long_t definitions. */
+#ifndef __ASSEMBLY__
+#include <asm-generic/atomic-long.h>
+#endif
+
+#endif /* _ASM_TILE_ATOMIC_H */
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
new file mode 100644
index 000000000000..e4f8b4f04895
--- /dev/null
+++ b/arch/tile/include/asm/atomic_32.h
@@ -0,0 +1,353 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Do not include directly; use <asm/atomic.h>.
+ */
+
+#ifndef _ASM_TILE_ATOMIC_32_H
+#define _ASM_TILE_ATOMIC_32_H
+
+#include <arch/chip.h>
+
+#ifndef __ASSEMBLY__
+
+/* Tile-specific routines to support <asm/atomic.h>. */
+int _atomic_xchg(atomic_t *v, int n);
+int _atomic_xchg_add(atomic_t *v, int i);
+int _atomic_xchg_add_unless(atomic_t *v, int a, int u);
+int _atomic_cmpxchg(atomic_t *v, int o, int n);
+
+/**
+ * atomic_xchg - atomically exchange contents of memory with a new value
+ * @v: pointer of type atomic_t
+ * @i: integer value to store in memory
+ *
+ * Atomically sets @v to @i and returns old @v
+ */
+static inline int atomic_xchg(atomic_t *v, int n)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic_xchg(v, n);
+}
+
+/**
+ * atomic_cmpxchg - atomically exchange contents of memory if it matches
+ * @v: pointer of type atomic_t
+ * @o: old value that memory should have
+ * @n: new value to write to memory if it matches
+ *
+ * Atomically checks if @v holds @o and replaces it with @n if so.
+ * Returns the old value at @v.
+ */
+static inline int atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic_cmpxchg(v, o, n);
+}
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+static inline void atomic_add(int i, atomic_t *v)
+{
+ _atomic_xchg_add(v, i);
+}
+
+/**
+ * atomic_add_return - add integer and return
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns @i + @v
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic_xchg_add(v, i) + i;
+}
+
+/**
+ * atomic_add_unless - add unless the number is already a given value
+ * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as @v was not already @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static inline int atomic_add_unless(atomic_t *v, int a, int u)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic_xchg_add_unless(v, a, u) != u;
+}
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ *
+ * atomic_set() can't be just a raw store, since it would be lost if it
+ * fell between the load and store of one of the other atomic ops.
+ */
+static inline void atomic_set(atomic_t *v, int n)
+{
+ _atomic_xchg(v, n);
+}
+
+#define xchg(ptr, x) ((typeof(*(ptr))) \
+ ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
+ atomic_xchg((atomic_t *)(ptr), (long)(x)) : \
+ __xchg_called_with_bad_pointer()))
+
+#define cmpxchg(ptr, o, n) ((typeof(*(ptr))) \
+ ((sizeof(*(ptr)) == sizeof(atomic_t)) ? \
+ atomic_cmpxchg((atomic_t *)(ptr), (long)(o), (long)(n)) : \
+ __cmpxchg_called_with_bad_pointer()))
+
+/* A 64bit atomic type */
+
+typedef struct {
+ u64 __aligned(8) counter;
+} atomic64_t;
+
+#define ATOMIC64_INIT(val) { (val) }
+
+u64 _atomic64_xchg(atomic64_t *v, u64 n);
+u64 _atomic64_xchg_add(atomic64_t *v, u64 i);
+u64 _atomic64_xchg_add_unless(atomic64_t *v, u64 a, u64 u);
+u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n);
+
+/**
+ * atomic64_read - read atomic variable
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically reads the value of @v.
+ */
+static inline u64 atomic64_read(const atomic64_t *v)
+{
+ /*
+ * Requires an atomic op to read both 32-bit parts consistently.
+ * Casting away const is safe since the atomic support routines
+ * do not write to memory if the value has not been modified.
+ */
+ return _atomic64_xchg_add((atomic64_t *)v, 0);
+}
+
+/**
+ * atomic64_xchg - atomically exchange contents of memory with a new value
+ * @v: pointer of type atomic64_t
+ * @i: integer value to store in memory
+ *
+ * Atomically sets @v to @i and returns old @v
+ */
+static inline u64 atomic64_xchg(atomic64_t *v, u64 n)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic64_xchg(v, n);
+}
+
+/**
+ * atomic64_cmpxchg - atomically exchange contents of memory if it matches
+ * @v: pointer of type atomic64_t
+ * @o: old value that memory should have
+ * @n: new value to write to memory if it matches
+ *
+ * Atomically checks if @v holds @o and replaces it with @n if so.
+ * Returns the old value at @v.
+ */
+static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic64_cmpxchg(v, o, n);
+}
+
+/**
+ * atomic64_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic64_t
+ *
+ * Atomically adds @i to @v.
+ */
+static inline void atomic64_add(u64 i, atomic64_t *v)
+{
+ _atomic64_xchg_add(v, i);
+}
+
+/**
+ * atomic64_add_return - add integer and return
+ * @v: pointer of type atomic64_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns @i + @v
+ */
+static inline u64 atomic64_add_return(u64 i, atomic64_t *v)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic64_xchg_add(v, i) + i;
+}
+
+/**
+ * atomic64_add_unless - add unless the number is already a given value
+ * @v: pointer of type atomic64_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
+ *
+ * Atomically adds @a to @v, so long as @v was not already @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
+ */
+static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u)
+{
+ smp_mb(); /* barrier for proper semantics */
+ return _atomic64_xchg_add_unless(v, a, u) != u;
+}
+
+/**
+ * atomic64_set - set atomic variable
+ * @v: pointer of type atomic64_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ *
+ * atomic64_set() can't be just a raw store, since it would be lost if it
+ * fell between the load and store of one of the other atomic ops.
+ */
+static inline void atomic64_set(atomic64_t *v, u64 n)
+{
+ _atomic64_xchg(v, n);
+}
+
+#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
+#define atomic64_inc(v) atomic64_add(1LL, (v))
+#define atomic64_inc_return(v) atomic64_add_return(1LL, (v))
+#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
+#define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v))
+#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0)
+#define atomic64_sub(i, v) atomic64_add(-(i), (v))
+#define atomic64_dec(v) atomic64_sub(1LL, (v))
+#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v))
+#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0)
+#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL)
+
+/*
+ * We need to barrier before modifying the word, since the _atomic_xxx()
+ * routines just tns the lock and then read/modify/write of the word.
+ * But after the word is updated, the routine issues an "mf" before returning,
+ * and since it's a function call, we don't even need a compiler barrier.
+ */
+#define smp_mb__before_atomic_dec() smp_mb()
+#define smp_mb__before_atomic_inc() smp_mb()
+#define smp_mb__after_atomic_dec() do { } while (0)
+#define smp_mb__after_atomic_inc() do { } while (0)
+
+
+/*
+ * Support "tns" atomic integers. These are atomic integers that can
+ * hold any value but "1". They are more efficient than regular atomic
+ * operations because the "lock" (aka acquire) step is a single "tns"
+ * in the uncontended case, and the "unlock" (aka release) step is a
+ * single "store" without an mf. (However, note that on tilepro the
+ * "tns" will evict the local cache line, so it's not all upside.)
+ *
+ * Note that you can ONLY observe the value stored in the pointer
+ * using these operations; a direct read of the value may confusingly
+ * return the special value "1".
+ */
+
+int __tns_atomic_acquire(atomic_t *);
+void __tns_atomic_release(atomic_t *p, int v);
+
+static inline void tns_atomic_set(atomic_t *v, int i)
+{
+ __tns_atomic_acquire(v);
+ __tns_atomic_release(v, i);
+}
+
+static inline int tns_atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+ int ret = __tns_atomic_acquire(v);
+ __tns_atomic_release(v, (ret == o) ? n : ret);
+ return ret;
+}
+
+static inline int tns_atomic_xchg(atomic_t *v, int n)
+{
+ int ret = __tns_atomic_acquire(v);
+ __tns_atomic_release(v, n);
+ return ret;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Internal definitions only beyond this point.
+ */
+
+#define ATOMIC_LOCKS_FOUND_VIA_TABLE() \
+ (!CHIP_HAS_CBOX_HOME_MAP() && defined(CONFIG_SMP))
+
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+
+/* Number of entries in atomic_lock_ptr[]. */
+#define ATOMIC_HASH_L1_SHIFT 6
+#define ATOMIC_HASH_L1_SIZE (1 << ATOMIC_HASH_L1_SHIFT)
+
+/* Number of locks in each struct pointed to by atomic_lock_ptr[]. */
+#define ATOMIC_HASH_L2_SHIFT (CHIP_L2_LOG_LINE_SIZE() - 2)
+#define ATOMIC_HASH_L2_SIZE (1 << ATOMIC_HASH_L2_SHIFT)
+
+#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+/*
+ * Number of atomic locks in atomic_locks[]. Must be a power of two.
+ * There is no reason for more than PAGE_SIZE / 8 entries, since that
+ * is the maximum number of pointer bits we can use to index this.
+ * And we cannot have more than PAGE_SIZE / 4, since this has to
+ * fit on a single page and each entry takes 4 bytes.
+ */
+#define ATOMIC_HASH_SHIFT (PAGE_SHIFT - 3)
+#define ATOMIC_HASH_SIZE (1 << ATOMIC_HASH_SHIFT)
+
+#ifndef __ASSEMBLY__
+extern int atomic_locks[];
+#endif
+
+#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+/*
+ * All the code that may fault while holding an atomic lock must
+ * place the pointer to the lock in ATOMIC_LOCK_REG so the fault code
+ * can correctly release and reacquire the lock. Note that we
+ * mention the register number in a comment in "lib/atomic_asm.S" to help
+ * assembly coders from using this register by mistake, so if it
+ * is changed here, change that comment as well.
+ */
+#define ATOMIC_LOCK_REG 20
+#define ATOMIC_LOCK_REG_NAME r20
+
+#ifndef __ASSEMBLY__
+/* Called from setup to initialize a hash table to point to per_cpu locks. */
+void __init_atomic_per_cpu(void);
+
+#ifdef CONFIG_SMP
+/* Support releasing the atomic lock in do_page_fault_ics(). */
+void __atomic_fault_unlock(int *lock_ptr);
+#endif
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_ATOMIC_32_H */
diff --git a/arch/tile/include/asm/auxvec.h b/arch/tile/include/asm/auxvec.h
new file mode 100644
index 000000000000..1d393edb0641
--- /dev/null
+++ b/arch/tile/include/asm/auxvec.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_AUXVEC_H
+#define _ASM_TILE_AUXVEC_H
+
+/* No extensions to auxvec */
+
+#endif /* _ASM_TILE_AUXVEC_H */
diff --git a/arch/tile/include/asm/backtrace.h b/arch/tile/include/asm/backtrace.h
new file mode 100644
index 000000000000..6970bfcad549
--- /dev/null
+++ b/arch/tile/include/asm/backtrace.h
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _TILE_BACKTRACE_H
+#define _TILE_BACKTRACE_H
+
+
+
+#include <linux/types.h>
+
+#include <arch/chip.h>
+
+#if CHIP_VA_WIDTH() > 32
+typedef unsigned long long VirtualAddress;
+#else
+typedef unsigned int VirtualAddress;
+#endif
+
+
+/** Reads 'size' bytes from 'address' and writes the data to 'result'.
+ * Returns true if successful, else false (e.g. memory not readable).
+ */
+typedef bool (*BacktraceMemoryReader)(void *result,
+ VirtualAddress address,
+ unsigned int size,
+ void *extra);
+
+typedef struct {
+ /** Current PC. */
+ VirtualAddress pc;
+
+ /** Current stack pointer value. */
+ VirtualAddress sp;
+
+ /** Current frame pointer value (i.e. caller's stack pointer) */
+ VirtualAddress fp;
+
+ /** Internal use only: caller's PC for first frame. */
+ VirtualAddress initial_frame_caller_pc;
+
+ /** Internal use only: callback to read memory. */
+ BacktraceMemoryReader read_memory_func;
+
+ /** Internal use only: arbitrary argument to read_memory_func. */
+ void *read_memory_func_extra;
+
+} BacktraceIterator;
+
+
+/** Initializes a backtracer to start from the given location.
+ *
+ * If the frame pointer cannot be determined it is set to -1.
+ *
+ * @param state The state to be filled in.
+ * @param read_memory_func A callback that reads memory. If NULL, a default
+ * value is provided.
+ * @param read_memory_func_extra An arbitrary argument to read_memory_func.
+ * @param pc The current PC.
+ * @param lr The current value of the 'lr' register.
+ * @param sp The current value of the 'sp' register.
+ * @param r52 The current value of the 'r52' register.
+ */
+extern void backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ VirtualAddress pc, VirtualAddress lr,
+ VirtualAddress sp, VirtualAddress r52);
+
+
+/** Advances the backtracing state to the calling frame, returning
+ * true iff successful.
+ */
+extern bool backtrace_next(BacktraceIterator *state);
+
+
+typedef enum {
+
+ /* We have no idea what the caller's pc is. */
+ PC_LOC_UNKNOWN,
+
+ /* The caller's pc is currently in lr. */
+ PC_LOC_IN_LR,
+
+ /* The caller's pc can be found by dereferencing the caller's sp. */
+ PC_LOC_ON_STACK
+
+} CallerPCLocation;
+
+
+typedef enum {
+
+ /* We have no idea what the caller's sp is. */
+ SP_LOC_UNKNOWN,
+
+ /* The caller's sp is currently in r52. */
+ SP_LOC_IN_R52,
+
+ /* The caller's sp can be found by adding a certain constant
+ * to the current value of sp.
+ */
+ SP_LOC_OFFSET
+
+} CallerSPLocation;
+
+
+/* Bit values ORed into CALLER_* values for info ops. */
+enum {
+ /* Setting the low bit on any of these values means the info op
+ * applies only to one bundle ago.
+ */
+ ONE_BUNDLE_AGO_FLAG = 1,
+
+ /* Setting this bit on a CALLER_SP_* value means the PC is in LR.
+ * If not set, PC is on the stack.
+ */
+ PC_IN_LR_FLAG = 2,
+
+ /* This many of the low bits of a CALLER_SP_* value are for the
+ * flag bits above.
+ */
+ NUM_INFO_OP_FLAGS = 2,
+
+ /* We cannot have one in the memory pipe so this is the maximum. */
+ MAX_INFO_OPS_PER_BUNDLE = 2
+};
+
+
+/** Internal constants used to define 'info' operands. */
+enum {
+ /* 0 and 1 are reserved, as are all negative numbers. */
+
+ CALLER_UNKNOWN_BASE = 2,
+
+ CALLER_SP_IN_R52_BASE = 4,
+
+ CALLER_SP_OFFSET_BASE = 8
+};
+
+
+/** Current backtracer state describing where it thinks the caller is. */
+typedef struct {
+ /*
+ * Public fields
+ */
+
+ /* How do we find the caller's PC? */
+ CallerPCLocation pc_location : 8;
+
+ /* How do we find the caller's SP? */
+ CallerSPLocation sp_location : 8;
+
+ /* If sp_location == SP_LOC_OFFSET, then caller_sp == sp +
+ * loc->sp_offset. Else this field is undefined.
+ */
+ uint16_t sp_offset;
+
+ /* In the most recently visited bundle a terminating bundle? */
+ bool at_terminating_bundle;
+
+ /*
+ * Private fields
+ */
+
+ /* Will the forward scanner see someone clobbering sp
+ * (i.e. changing it with something other than addi sp, sp, N?)
+ */
+ bool sp_clobber_follows;
+
+ /* Operand to next "visible" info op (no more than one bundle past
+ * the next terminating bundle), or -32768 if none.
+ */
+ int16_t next_info_operand;
+
+ /* Is the info of in next_info_op in the very next bundle? */
+ bool is_next_info_operand_adjacent;
+
+} CallerLocation;
+
+
+
+
+#endif /* _TILE_BACKTRACE_H */
diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h
new file mode 100644
index 000000000000..84600f3514da
--- /dev/null
+++ b/arch/tile/include/asm/bitops.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1992, Linus Torvalds.
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_BITOPS_H
+#define _ASM_TILE_BITOPS_H
+
+#include <linux/types.h>
+
+#ifndef _LINUX_BITOPS_H
+#error only <linux/bitops.h> can be included directly
+#endif
+
+#ifdef __tilegx__
+#include <asm/bitops_64.h>
+#else
+#include <asm/bitops_32.h>
+#endif
+
+/**
+ * __ffs - find first set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __ffs(unsigned long word)
+{
+ return __builtin_ctzl(word);
+}
+
+/**
+ * ffz - find first zero bit in word
+ * @word: The word to search
+ *
+ * Undefined if no zero exists, so code should check against ~0UL first.
+ */
+static inline unsigned long ffz(unsigned long word)
+{
+ return __builtin_ctzl(~word);
+}
+
+/**
+ * __fls - find last set bit in word
+ * @word: The word to search
+ *
+ * Undefined if no set bit exists, so code should check against 0 first.
+ */
+static inline unsigned long __fls(unsigned long word)
+{
+ return (sizeof(word) * 8) - 1 - __builtin_clzl(word);
+}
+
+/**
+ * ffs - find first set bit in word
+ * @x: the word to search
+ *
+ * This is defined the same way as the libc and compiler builtin ffs
+ * routines, therefore differs in spirit from the other bitops.
+ *
+ * ffs(value) returns 0 if value is 0 or the position of the first
+ * set bit if value is nonzero. The first (least significant) bit
+ * is at position 1.
+ */
+static inline int ffs(int x)
+{
+ return __builtin_ffs(x);
+}
+
+/**
+ * fls - find last set bit in word
+ * @x: the word to search
+ *
+ * This is defined in a similar way as the libc and compiler builtin
+ * ffs, but returns the position of the most significant set bit.
+ *
+ * fls(value) returns 0 if value is 0 or the position of the last
+ * set bit if value is nonzero. The last (most significant) bit is
+ * at position 32.
+ */
+static inline int fls(int x)
+{
+ return (sizeof(int) * 8) - __builtin_clz(x);
+}
+
+static inline int fls64(__u64 w)
+{
+ return (sizeof(__u64) * 8) - __builtin_clzll(w);
+}
+
+static inline unsigned int hweight32(unsigned int w)
+{
+ return __builtin_popcount(w);
+}
+
+static inline unsigned int hweight16(unsigned int w)
+{
+ return __builtin_popcount(w & 0xffff);
+}
+
+static inline unsigned int hweight8(unsigned int w)
+{
+ return __builtin_popcount(w & 0xff);
+}
+
+static inline unsigned long hweight64(__u64 w)
+{
+ return __builtin_popcountll(w);
+}
+
+#include <asm-generic/bitops/lock.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/ext2-non-atomic.h>
+#include <asm-generic/bitops/minix.h>
+
+#endif /* _ASM_TILE_BITOPS_H */
diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h
new file mode 100644
index 000000000000..7a93c001ac19
--- /dev/null
+++ b/arch/tile/include/asm/bitops_32.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_BITOPS_32_H
+#define _ASM_TILE_BITOPS_32_H
+
+#include <linux/compiler.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/* Tile-specific routines to support <asm/bitops.h>. */
+unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask);
+unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask);
+unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask);
+
+/**
+ * set_bit - Atomically set a bit in memory
+ * @nr: the bit to set
+ * @addr: the address to start counting from
+ *
+ * This function is atomic and may not be reordered.
+ * See __set_bit() if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void set_bit(unsigned nr, volatile unsigned long *addr)
+{
+ _atomic_or(addr + BIT_WORD(nr), BIT_MASK(nr));
+}
+
+/**
+ * clear_bit - Clears a bit in memory
+ * @nr: Bit to clear
+ * @addr: Address to start counting from
+ *
+ * clear_bit() is atomic and may not be reordered.
+ * See __clear_bit() if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ *
+ * clear_bit() may not contain a memory barrier, so if it is used for
+ * locking purposes, you should call smp_mb__before_clear_bit() and/or
+ * smp_mb__after_clear_bit() to ensure changes are visible on other cpus.
+ */
+static inline void clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+ _atomic_andn(addr + BIT_WORD(nr), BIT_MASK(nr));
+}
+
+/**
+ * change_bit - Toggle a bit in memory
+ * @nr: Bit to change
+ * @addr: Address to start counting from
+ *
+ * change_bit() is atomic and may not be reordered.
+ * See __change_bit() if you do not require the atomic guarantees.
+ * Note that @nr may be almost arbitrarily large; this function is not
+ * restricted to acting on a single-word quantity.
+ */
+static inline void change_bit(unsigned nr, volatile unsigned long *addr)
+{
+ _atomic_xor(addr + BIT_WORD(nr), BIT_MASK(nr));
+}
+
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ addr += BIT_WORD(nr);
+ smp_mb(); /* barrier for proper semantics */
+ return (_atomic_or(addr, mask) & mask) != 0;
+}
+
+/**
+ * test_and_clear_bit - Clear a bit and return its old value
+ * @nr: Bit to clear
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ addr += BIT_WORD(nr);
+ smp_mb(); /* barrier for proper semantics */
+ return (_atomic_andn(addr, mask) & mask) != 0;
+}
+
+/**
+ * test_and_change_bit - Change a bit and return its old value
+ * @nr: Bit to change
+ * @addr: Address to count from
+ *
+ * This operation is atomic and cannot be reordered.
+ * It also implies a memory barrier.
+ */
+static inline int test_and_change_bit(unsigned nr,
+ volatile unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ addr += BIT_WORD(nr);
+ smp_mb(); /* barrier for proper semantics */
+ return (_atomic_xor(addr, mask) & mask) != 0;
+}
+
+/* See discussion at smp_mb__before_atomic_dec() in <asm/atomic.h>. */
+#define smp_mb__before_clear_bit() smp_mb()
+#define smp_mb__after_clear_bit() do {} while (0)
+
+#include <asm-generic/bitops/non-atomic.h>
+#include <asm-generic/bitops/ext2-atomic.h>
+
+#endif /* _ASM_TILE_BITOPS_32_H */
diff --git a/arch/tile/include/asm/bitsperlong.h b/arch/tile/include/asm/bitsperlong.h
new file mode 100644
index 000000000000..58c771f2af2f
--- /dev/null
+++ b/arch/tile/include/asm/bitsperlong.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_BITSPERLONG_H
+#define _ASM_TILE_BITSPERLONG_H
+
+#ifdef __LP64__
+# define __BITS_PER_LONG 64
+#else
+# define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* _ASM_TILE_BITSPERLONG_H */
diff --git a/arch/tile/include/asm/bug.h b/arch/tile/include/asm/bug.h
new file mode 100644
index 000000000000..b12fd89e42e9
--- /dev/null
+++ b/arch/tile/include/asm/bug.h
@@ -0,0 +1 @@
+#include <asm-generic/bug.h>
diff --git a/arch/tile/include/asm/bugs.h b/arch/tile/include/asm/bugs.h
new file mode 100644
index 000000000000..61791e1ad9f5
--- /dev/null
+++ b/arch/tile/include/asm/bugs.h
@@ -0,0 +1 @@
+#include <asm-generic/bugs.h>
diff --git a/arch/tile/include/asm/byteorder.h b/arch/tile/include/asm/byteorder.h
new file mode 100644
index 000000000000..9558416d578b
--- /dev/null
+++ b/arch/tile/include/asm/byteorder.h
@@ -0,0 +1 @@
+#include <linux/byteorder/little_endian.h>
diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h
new file mode 100644
index 000000000000..c2b7dcfe5327
--- /dev/null
+++ b/arch/tile/include/asm/cache.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_CACHE_H
+#define _ASM_TILE_CACHE_H
+
+#include <arch/chip.h>
+
+/* bytes per L1 data cache line */
+#define L1_CACHE_SHIFT CHIP_L1D_LOG_LINE_SIZE()
+#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
+#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1)) & -L1_CACHE_BYTES)
+
+/* bytes per L1 instruction cache line */
+#define L1I_CACHE_SHIFT CHIP_L1I_LOG_LINE_SIZE()
+#define L1I_CACHE_BYTES (1 << L1I_CACHE_SHIFT)
+#define L1I_CACHE_ALIGN(x) (((x)+(L1I_CACHE_BYTES-1)) & -L1I_CACHE_BYTES)
+
+/* bytes per L2 cache line */
+#define L2_CACHE_SHIFT CHIP_L2_LOG_LINE_SIZE()
+#define L2_CACHE_BYTES (1 << L2_CACHE_SHIFT)
+#define L2_CACHE_ALIGN(x) (((x)+(L2_CACHE_BYTES-1)) & -L2_CACHE_BYTES)
+
+/* use the cache line size for the L2, which is where it counts */
+#define SMP_CACHE_BYTES_SHIFT L2_CACHE_SHIFT
+#define SMP_CACHE_BYTES L2_CACHE_BYTES
+#define INTERNODE_CACHE_SHIFT L2_CACHE_SHIFT
+#define INTERNODE_CACHE_BYTES L2_CACHE_BYTES
+
+/* Group together read-mostly things to avoid cache false sharing */
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+
+/*
+ * Attribute for data that is kept read/write coherent until the end of
+ * initialization, then bumped to read/only incoherent for performance.
+ */
+#define __write_once __attribute__((__section__(".w1data")))
+
+#endif /* _ASM_TILE_CACHE_H */
diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h
new file mode 100644
index 000000000000..7e2096a4ef7d
--- /dev/null
+++ b/arch/tile/include/asm/cacheflush.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_CACHEFLUSH_H
+#define _ASM_TILE_CACHEFLUSH_H
+
+#include <arch/chip.h>
+
+/* Keep includes the same across arches. */
+#include <linux/mm.h>
+#include <linux/cache.h>
+#include <asm/system.h>
+
+/* Caches are physically-indexed and so don't need special treatment */
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+#define flush_cache_dup_mm(mm) do { } while (0)
+#define flush_cache_range(vma, start, end) do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+#define flush_dcache_page(page) do { } while (0)
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vunmap(start, end) do { } while (0)
+#define flush_icache_page(vma, pg) do { } while (0)
+#define flush_icache_user_range(vma, pg, adr, len) do { } while (0)
+
+/* See "arch/tile/lib/__invalidate_icache.S". */
+extern void __invalidate_icache(unsigned long start, unsigned long size);
+
+/* Flush the icache just on this cpu */
+static inline void __flush_icache_range(unsigned long start, unsigned long end)
+{
+ __invalidate_icache(start, end - start);
+}
+
+/* Flush the entire icache on this cpu. */
+#define __flush_icache() __flush_icache_range(0, CHIP_L1I_CACHE_SIZE())
+
+#ifdef CONFIG_SMP
+/*
+ * When the kernel writes to its own text we need to do an SMP
+ * broadcast to make the L1I coherent everywhere. This includes
+ * module load and single step.
+ */
+extern void flush_icache_range(unsigned long start, unsigned long end);
+#else
+#define flush_icache_range __flush_icache_range
+#endif
+
+/*
+ * An update to an executable user page requires icache flushing.
+ * We could carefully update only tiles that are running this process,
+ * and rely on the fact that we flush the icache on every context
+ * switch to avoid doing extra work here. But for now, I'll be
+ * conservative and just do a global icache flush.
+ */
+static inline void copy_to_user_page(struct vm_area_struct *vma,
+ struct page *page, unsigned long vaddr,
+ void *dst, void *src, int len)
+{
+ memcpy(dst, src, len);
+ if (vma->vm_flags & VM_EXEC) {
+ flush_icache_range((unsigned long) dst,
+ (unsigned long) dst + len);
+ }
+}
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+ memcpy((dst), (src), (len))
+
+/*
+ * Invalidate a VA range; pads to L2 cacheline boundaries.
+ *
+ * Note that on TILE64, __inv_buffer() actually flushes modified
+ * cache lines in addition to invalidating them, i.e., it's the
+ * same as __finv_buffer().
+ */
+static inline void __inv_buffer(void *buffer, size_t size)
+{
+ char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
+ char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
+ while (next < finish) {
+ __insn_inv(next);
+ next += CHIP_INV_STRIDE();
+ }
+}
+
+/* Flush a VA range; pads to L2 cacheline boundaries. */
+static inline void __flush_buffer(void *buffer, size_t size)
+{
+ char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
+ char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
+ while (next < finish) {
+ __insn_flush(next);
+ next += CHIP_FLUSH_STRIDE();
+ }
+}
+
+/* Flush & invalidate a VA range; pads to L2 cacheline boundaries. */
+static inline void __finv_buffer(void *buffer, size_t size)
+{
+ char *next = (char *)((long)buffer & -L2_CACHE_BYTES);
+ char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size);
+ while (next < finish) {
+ __insn_finv(next);
+ next += CHIP_FINV_STRIDE();
+ }
+}
+
+
+/* Invalidate a VA range, then memory fence. */
+static inline void inv_buffer(void *buffer, size_t size)
+{
+ __inv_buffer(buffer, size);
+ mb_incoherent();
+}
+
+/* Flush a VA range, then memory fence. */
+static inline void flush_buffer(void *buffer, size_t size)
+{
+ __flush_buffer(buffer, size);
+ mb_incoherent();
+}
+
+/* Flush & invalidate a VA range, then memory fence. */
+static inline void finv_buffer(void *buffer, size_t size)
+{
+ __finv_buffer(buffer, size);
+ mb_incoherent();
+}
+
+#endif /* _ASM_TILE_CACHEFLUSH_H */
diff --git a/arch/tile/include/asm/checksum.h b/arch/tile/include/asm/checksum.h
new file mode 100644
index 000000000000..a120766c7264
--- /dev/null
+++ b/arch/tile/include/asm/checksum.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_CHECKSUM_H
+#define _ASM_TILE_CHECKSUM_H
+
+#include <asm-generic/checksum.h>
+
+/* Allow us to provide a more optimized do_csum(). */
+__wsum do_csum(const unsigned char *buff, int len);
+#define do_csum do_csum
+
+#endif /* _ASM_TILE_CHECKSUM_H */
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
new file mode 100644
index 000000000000..e133c53f6c4f
--- /dev/null
+++ b/arch/tile/include/asm/compat.h
@@ -0,0 +1,308 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_COMPAT_H
+#define _ASM_TILE_COMPAT_H
+
+/*
+ * Architecture specific compatibility types
+ */
+#include <linux/types.h>
+#include <linux/sched.h>
+
+#define COMPAT_USER_HZ 100
+
+/* "long" and pointer-based types are different. */
+typedef s32 compat_long_t;
+typedef u32 compat_ulong_t;
+typedef u32 compat_size_t;
+typedef s32 compat_ssize_t;
+typedef s32 compat_off_t;
+typedef s32 compat_time_t;
+typedef s32 compat_clock_t;
+typedef u32 compat_ino_t;
+typedef u32 compat_caddr_t;
+typedef u32 compat_uptr_t;
+
+/* Many types are "int" or otherwise the same. */
+typedef __kernel_pid_t compat_pid_t;
+typedef __kernel_uid_t __compat_uid_t;
+typedef __kernel_gid_t __compat_gid_t;
+typedef __kernel_uid32_t __compat_uid32_t;
+typedef __kernel_uid32_t __compat_gid32_t;
+typedef __kernel_mode_t compat_mode_t;
+typedef __kernel_dev_t compat_dev_t;
+typedef __kernel_loff_t compat_loff_t;
+typedef __kernel_nlink_t compat_nlink_t;
+typedef __kernel_ipc_pid_t compat_ipc_pid_t;
+typedef __kernel_daddr_t compat_daddr_t;
+typedef __kernel_fsid_t compat_fsid_t;
+typedef __kernel_timer_t compat_timer_t;
+typedef __kernel_key_t compat_key_t;
+typedef int compat_int_t;
+typedef s64 compat_s64;
+typedef uint compat_uint_t;
+typedef u64 compat_u64;
+
+/* We use the same register dump format in 32-bit images. */
+typedef unsigned long compat_elf_greg_t;
+#define COMPAT_ELF_NGREG (sizeof(struct pt_regs) / sizeof(compat_elf_greg_t))
+typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
+
+struct compat_timespec {
+ compat_time_t tv_sec;
+ s32 tv_nsec;
+};
+
+struct compat_timeval {
+ compat_time_t tv_sec;
+ s32 tv_usec;
+};
+
+struct compat_stat {
+ unsigned int st_dev;
+ unsigned int st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_rdev;
+ unsigned int __pad1;
+ int st_size;
+ int st_blksize;
+ int __pad2;
+ int st_blocks;
+ int st_atime;
+ unsigned int st_atime_nsec;
+ int st_mtime;
+ unsigned int st_mtime_nsec;
+ int st_ctime;
+ unsigned int st_ctime_nsec;
+ unsigned int __unused[2];
+};
+
+struct compat_stat64 {
+ unsigned long st_dev;
+ unsigned long st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned long st_rdev;
+ long st_size;
+ unsigned int st_blksize;
+ unsigned long st_blocks __attribute__((packed));
+ unsigned int st_atime;
+ unsigned int st_atime_nsec;
+ unsigned int st_mtime;
+ unsigned int st_mtime_nsec;
+ unsigned int st_ctime;
+ unsigned int st_ctime_nsec;
+ unsigned int __unused8;
+};
+
+#define compat_statfs statfs
+
+struct compat_sysctl {
+ unsigned int name;
+ int nlen;
+ unsigned int oldval;
+ unsigned int oldlenp;
+ unsigned int newval;
+ unsigned int newlen;
+ unsigned int __unused[4];
+};
+
+
+struct compat_flock {
+ short l_type;
+ short l_whence;
+ compat_off_t l_start;
+ compat_off_t l_len;
+ compat_pid_t l_pid;
+};
+
+#define F_GETLK64 12 /* using 'struct flock64' */
+#define F_SETLK64 13
+#define F_SETLKW64 14
+
+struct compat_flock64 {
+ short l_type;
+ short l_whence;
+ compat_loff_t l_start;
+ compat_loff_t l_len;
+ compat_pid_t l_pid;
+};
+
+#define COMPAT_RLIM_INFINITY 0xffffffff
+
+#define _COMPAT_NSIG 64
+#define _COMPAT_NSIG_BPW 32
+
+typedef u32 compat_sigset_word;
+
+#define COMPAT_OFF_T_MAX 0x7fffffff
+#define COMPAT_LOFF_T_MAX 0x7fffffffffffffffL
+
+struct compat_ipc64_perm {
+ compat_key_t key;
+ __compat_uid32_t uid;
+ __compat_gid32_t gid;
+ __compat_uid32_t cuid;
+ __compat_gid32_t cgid;
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short seq;
+ unsigned short __pad2;
+ compat_ulong_t unused1;
+ compat_ulong_t unused2;
+};
+
+struct compat_semid64_ds {
+ struct compat_ipc64_perm sem_perm;
+ compat_time_t sem_otime;
+ compat_ulong_t __unused1;
+ compat_time_t sem_ctime;
+ compat_ulong_t __unused2;
+ compat_ulong_t sem_nsems;
+ compat_ulong_t __unused3;
+ compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+ struct compat_ipc64_perm msg_perm;
+ compat_time_t msg_stime;
+ compat_ulong_t __unused1;
+ compat_time_t msg_rtime;
+ compat_ulong_t __unused2;
+ compat_time_t msg_ctime;
+ compat_ulong_t __unused3;
+ compat_ulong_t msg_cbytes;
+ compat_ulong_t msg_qnum;
+ compat_ulong_t msg_qbytes;
+ compat_pid_t msg_lspid;
+ compat_pid_t msg_lrpid;
+ compat_ulong_t __unused4;
+ compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+ struct compat_ipc64_perm shm_perm;
+ compat_size_t shm_segsz;
+ compat_time_t shm_atime;
+ compat_ulong_t __unused1;
+ compat_time_t shm_dtime;
+ compat_ulong_t __unused2;
+ compat_time_t shm_ctime;
+ compat_ulong_t __unused3;
+ compat_pid_t shm_cpid;
+ compat_pid_t shm_lpid;
+ compat_ulong_t shm_nattch;
+ compat_ulong_t __unused4;
+ compat_ulong_t __unused5;
+};
+
+/*
+ * A pointer passed in from user mode. This should not
+ * be used for syscall parameters, just declare them
+ * as pointers because the syscall entry code will have
+ * appropriately converted them already.
+ */
+
+static inline void __user *compat_ptr(compat_uptr_t uptr)
+{
+ return (void __user *)(unsigned long)uptr;
+}
+
+static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+{
+ return (u32)(unsigned long)uptr;
+}
+
+/* Sign-extend when storing a kernel pointer to a user's ptregs. */
+static inline unsigned long ptr_to_compat_reg(void __user *uptr)
+{
+ return (long)(int)(long)uptr;
+}
+
+static inline void __user *compat_alloc_user_space(long len)
+{
+ struct pt_regs *regs = task_pt_regs(current);
+ return (void __user *)regs->sp - len;
+}
+
+static inline int is_compat_task(void)
+{
+ return current_thread_info()->status & TS_COMPAT;
+}
+
+extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka,
+ siginfo_t *info, sigset_t *set,
+ struct pt_regs *regs);
+
+/* Compat syscalls. */
+struct compat_sigaction;
+struct compat_siginfo;
+struct compat_sigaltstack;
+long compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp);
+long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
+ struct compat_sigaction __user *oact,
+ size_t sigsetsize);
+long compat_sys_rt_sigqueueinfo(int pid, int sig,
+ struct compat_siginfo __user *uinfo);
+long compat_sys_rt_sigreturn(void);
+long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr);
+long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
+long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
+long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high);
+long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high);
+long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len);
+long compat_sys_sync_file_range2(int fd, unsigned int flags,
+ u32 offset_lo, u32 offset_hi,
+ u32 nbytes_lo, u32 nbytes_hi);
+long compat_sys_fallocate(int fd, int mode,
+ u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi);
+long compat_sys_stat64(char __user *filename,
+ struct compat_stat64 __user *statbuf);
+long compat_sys_lstat64(char __user *filename,
+ struct compat_stat64 __user *statbuf);
+long compat_sys_fstat64(unsigned int fd, struct compat_stat64 __user *statbuf);
+long compat_sys_fstatat64(int dfd, char __user *filename,
+ struct compat_stat64 __user *statbuf, int flag);
+long compat_sys_sched_rr_get_interval(compat_pid_t pid,
+ struct compat_timespec __user *interval);
+ssize_t compat_sys_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
+ size_t count);
+
+/* Versions of compat functions that differ from generic Linux. */
+struct compat_msgbuf;
+long tile_compat_sys_msgsnd(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, int msgflg);
+long tile_compat_sys_msgrcv(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, long msgtyp, int msgflg);
+long tile_compat_sys_ptrace(compat_long_t request, compat_long_t pid,
+ compat_long_t addr, compat_long_t data);
+
+/* Tilera Linux syscalls that don't have "compat" versions. */
+#define compat_sys_raise_fpe sys_raise_fpe
+#define compat_sys_flush_cache sys_flush_cache
+
+#endif /* _ASM_TILE_COMPAT_H */
diff --git a/arch/tile/include/asm/cputime.h b/arch/tile/include/asm/cputime.h
new file mode 100644
index 000000000000..6d68ad7e0ea3
--- /dev/null
+++ b/arch/tile/include/asm/cputime.h
@@ -0,0 +1 @@
+#include <asm-generic/cputime.h>
diff --git a/arch/tile/include/asm/current.h b/arch/tile/include/asm/current.h
new file mode 100644
index 000000000000..da21acf020d3
--- /dev/null
+++ b/arch/tile/include/asm/current.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_CURRENT_H
+#define _ASM_TILE_CURRENT_H
+
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void)
+{
+ return current_thread_info()->task;
+}
+#define current get_current()
+
+/* Return a usable "task_struct" pointer even if the real one is corrupt. */
+struct task_struct *validate_current(void);
+
+#endif /* _ASM_TILE_CURRENT_H */
diff --git a/arch/tile/include/asm/delay.h b/arch/tile/include/asm/delay.h
new file mode 100644
index 000000000000..97b0e69e704e
--- /dev/null
+++ b/arch/tile/include/asm/delay.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_DELAY_H
+#define _ASM_TILE_DELAY_H
+
+/* Undefined functions to get compile-time errors. */
+extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
+
+extern void __udelay(unsigned long usecs);
+extern void __ndelay(unsigned long nsecs);
+extern void __delay(unsigned long loops);
+
+#define udelay(n) (__builtin_constant_p(n) ? \
+ ((n) > 20000 ? __bad_udelay() : __ndelay((n) * 1000)) : \
+ __udelay(n))
+
+#define ndelay(n) (__builtin_constant_p(n) ? \
+ ((n) > 20000 ? __bad_ndelay() : __ndelay(n)) : \
+ __ndelay(n))
+
+#endif /* _ASM_TILE_DELAY_H */
diff --git a/arch/tile/include/asm/device.h b/arch/tile/include/asm/device.h
new file mode 100644
index 000000000000..f0a4c256403b
--- /dev/null
+++ b/arch/tile/include/asm/device.h
@@ -0,0 +1 @@
+#include <asm-generic/device.h>
diff --git a/arch/tile/include/asm/div64.h b/arch/tile/include/asm/div64.h
new file mode 100644
index 000000000000..6cd978cefb28
--- /dev/null
+++ b/arch/tile/include/asm/div64.h
@@ -0,0 +1 @@
+#include <asm-generic/div64.h>
diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h
new file mode 100644
index 000000000000..cf466b39aa13
--- /dev/null
+++ b/arch/tile/include/asm/dma-mapping.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_DMA_MAPPING_H
+#define _ASM_TILE_DMA_MAPPING_H
+
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/cache.h>
+#include <linux/io.h>
+
+/*
+ * Note that on x86 and powerpc, there is a "struct dma_mapping_ops"
+ * that is used for all the DMA operations. For now, we don't have an
+ * equivalent on tile, because we only have a single way of doing DMA.
+ * (Tilera bug 7994 to use dma_mapping_ops.)
+ */
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+extern dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction);
+extern void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction);
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction);
+extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction);
+
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
+extern void dma_sync_single_for_cpu(struct device *, dma_addr_t, size_t,
+ enum dma_data_direction);
+extern void dma_sync_single_for_device(struct device *, dma_addr_t,
+ size_t, enum dma_data_direction);
+extern void dma_sync_single_range_for_cpu(struct device *, dma_addr_t,
+ unsigned long offset, size_t,
+ enum dma_data_direction);
+extern void dma_sync_single_range_for_device(struct device *, dma_addr_t,
+ unsigned long offset, size_t,
+ enum dma_data_direction);
+extern void dma_cache_sync(void *vaddr, size_t, enum dma_data_direction);
+
+static inline int
+dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+ return 1;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 mask)
+{
+ if (!dev->dma_mask || !dma_supported(dev, mask))
+ return -EIO;
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
+
+static inline int
+dma_get_cache_alignment(void)
+{
+ return L2_CACHE_BYTES;
+}
+
+#define dma_is_consistent(d, h) (1)
+
+
+#endif /* _ASM_TILE_DMA_MAPPING_H */
diff --git a/arch/tile/include/asm/dma.h b/arch/tile/include/asm/dma.h
new file mode 100644
index 000000000000..12a7ca16d164
--- /dev/null
+++ b/arch/tile/include/asm/dma.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_DMA_H
+#define _ASM_TILE_DMA_H
+
+#include <asm-generic/dma.h>
+
+/* Needed by drivers/pci/quirks.c */
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#endif
+
+#endif /* _ASM_TILE_DMA_H */
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h
new file mode 100644
index 000000000000..1bca0debdb0f
--- /dev/null
+++ b/arch/tile/include/asm/elf.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_ELF_H
+#define _ASM_TILE_ELF_H
+
+/*
+ * ELF register definitions.
+ */
+
+#include <arch/chip.h>
+
+#include <linux/ptrace.h>
+#include <asm/byteorder.h>
+#include <asm/page.h>
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+#define EM_TILE64 187
+#define EM_TILEPRO 188
+#define EM_TILEGX 191
+
+/* Provide a nominal data structure. */
+#define ELF_NFPREG 0
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#ifdef __tilegx__
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+#define ELF_DATA ELFDATA2LSB
+
+/*
+ * There seems to be a bug in how compat_binfmt_elf.c works: it
+ * #undefs ELF_ARCH, but it is then used in binfmt_elf.c for fill_note_info().
+ * Hack around this by providing an enum value of ELF_ARCH.
+ */
+enum { ELF_ARCH = CHIP_ELF_TYPE() };
+#define ELF_ARCH ELF_ARCH
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) \
+ ((x)->e_ident[EI_CLASS] == ELF_CLASS && \
+ ((x)->e_machine == CHIP_ELF_TYPE() || \
+ (x)->e_machine == CHIP_COMPAT_ELF_TYPE()))
+
+/* The module loader only handles a few relocation types. */
+#ifndef __tilegx__
+#define R_TILE_32 1
+#define R_TILE_JOFFLONG_X1 15
+#define R_TILE_IMM16_X0_LO 25
+#define R_TILE_IMM16_X1_LO 26
+#define R_TILE_IMM16_X0_HA 29
+#define R_TILE_IMM16_X1_HA 30
+#else
+#define R_TILEGX_64 1
+#define R_TILEGX_JUMPOFF_X1 21
+#define R_TILEGX_IMM16_X0_HW0 36
+#define R_TILEGX_IMM16_X1_HW0 37
+#define R_TILEGX_IMM16_X0_HW1 38
+#define R_TILEGX_IMM16_X1_HW1 39
+#define R_TILEGX_IMM16_X0_HW2_LAST 48
+#define R_TILEGX_IMM16_X1_HW2_LAST 49
+#endif
+
+/* Use standard page size for core dumps. */
+#define ELF_EXEC_PAGESIZE PAGE_SIZE
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader. We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
+
+#define ELF_CORE_COPY_REGS(_dest, _regs) \
+ memcpy((char *) &_dest, (char *) _regs, \
+ sizeof(struct pt_regs));
+
+/* No additional FP registers to copy. */
+#define ELF_CORE_COPY_FPREGS(t, fpu) 0
+
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports. This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+#define ELF_HWCAP (0)
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization. This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ */
+#define ELF_PLATFORM (NULL)
+
+extern void elf_plat_init(struct pt_regs *regs, unsigned long load_addr);
+
+#define ELF_PLAT_INIT(_r, load_addr) elf_plat_init(_r, load_addr)
+
+extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+
+/* Tilera Linux has no personalities currently, so no need to do anything. */
+#define SET_PERSONALITY(ex) do { } while (0)
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+/* Support auto-mapping of the user interrupt vectors. */
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack);
+#ifdef CONFIG_COMPAT
+
+#define COMPAT_ELF_PLATFORM "tilegx-m32"
+
+/*
+ * "Compat" binaries have the same machine type, but 32-bit class,
+ * since they're not a separate machine type, but just a 32-bit
+ * variant of the standard 64-bit architecture.
+ */
+#define compat_elf_check_arch(x) \
+ ((x)->e_ident[EI_CLASS] == ELFCLASS32 && \
+ ((x)->e_machine == CHIP_ELF_TYPE() || \
+ (x)->e_machine == CHIP_COMPAT_ELF_TYPE()))
+
+#define compat_start_thread(regs, ip, usp) do { \
+ regs->pc = ptr_to_compat_reg((void *)(ip)); \
+ regs->sp = ptr_to_compat_reg((void *)(usp)); \
+ } while (0)
+
+/*
+ * Use SET_PERSONALITY to indicate compatibility via TS_COMPAT.
+ */
+#undef SET_PERSONALITY
+#define SET_PERSONALITY(ex) \
+do { \
+ current->personality = PER_LINUX; \
+ current_thread_info()->status &= ~TS_COMPAT; \
+} while (0)
+#define COMPAT_SET_PERSONALITY(ex) \
+do { \
+ current->personality = PER_LINUX_32BIT; \
+ current_thread_info()->status |= TS_COMPAT; \
+} while (0)
+
+#define COMPAT_ELF_ET_DYN_BASE (0xffffffff / 3 * 2)
+
+#endif /* CONFIG_COMPAT */
+
+#endif /* _ASM_TILE_ELF_H */
diff --git a/arch/tile/include/asm/emergency-restart.h b/arch/tile/include/asm/emergency-restart.h
new file mode 100644
index 000000000000..3711bd9d50bd
--- /dev/null
+++ b/arch/tile/include/asm/emergency-restart.h
@@ -0,0 +1 @@
+#include <asm-generic/emergency-restart.h>
diff --git a/arch/tile/include/asm/errno.h b/arch/tile/include/asm/errno.h
new file mode 100644
index 000000000000..4c82b503d92f
--- /dev/null
+++ b/arch/tile/include/asm/errno.h
@@ -0,0 +1 @@
+#include <asm-generic/errno.h>
diff --git a/arch/tile/include/asm/fcntl.h b/arch/tile/include/asm/fcntl.h
new file mode 100644
index 000000000000..46ab12db5739
--- /dev/null
+++ b/arch/tile/include/asm/fcntl.h
@@ -0,0 +1 @@
+#include <asm-generic/fcntl.h>
diff --git a/arch/tile/include/asm/fixmap.h b/arch/tile/include/asm/fixmap.h
new file mode 100644
index 000000000000..51537ff9265a
--- /dev/null
+++ b/arch/tile/include/asm/fixmap.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 1998 Ingo Molnar
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_FIXMAP_H
+#define _ASM_TILE_FIXMAP_H
+
+#include <asm/page.h>
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#ifdef CONFIG_HIGHMEM
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#endif
+
+#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT))
+#define __virt_to_fix(x) ((FIXADDR_TOP - ((x)&PAGE_MASK)) >> PAGE_SHIFT)
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process. We allocate these special addresses
+ * from the end of supervisor virtual memory backwards.
+ * Also this lets us do fail-safe vmalloc(), we
+ * can guarantee that these special addresses and
+ * vmalloc()-ed addresses never overlap.
+ *
+ * these 'compile-time allocated' memory buffers are
+ * fixed-size 4k pages. (or larger if used with an increment
+ * higher than 1) use fixmap_set(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ * TLB entries of such buffers will not be flushed across
+ * task switches.
+ *
+ * We don't bother with a FIX_HOLE since above the fixmaps
+ * is unmapped memory in any case.
+ */
+enum fixed_addresses {
+#ifdef CONFIG_HIGHMEM
+ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
+ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
+#endif
+ __end_of_permanent_fixed_addresses,
+
+ /*
+ * Temporary boot-time mappings, used before ioremap() is functional.
+ * Not currently needed by the Tile architecture.
+ */
+#define NR_FIX_BTMAPS 0
+#if NR_FIX_BTMAPS
+ FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+ FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1,
+ __end_of_fixed_addresses
+#else
+ __end_of_fixed_addresses = __end_of_permanent_fixed_addresses
+#endif
+};
+
+extern void __set_fixmap(enum fixed_addresses idx,
+ unsigned long phys, pgprot_t flags);
+
+#define set_fixmap(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL)
+/*
+ * Some hardware wants to get fixmapped without caching.
+ */
+#define set_fixmap_nocache(idx, phys) \
+ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE)
+
+#define clear_fixmap(idx) \
+ __set_fixmap(idx, 0, __pgprot(0))
+
+#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
+#define __FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_SIZE)
+#define FIXADDR_BOOT_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_BOOT_SIZE)
+
+extern void __this_fixmap_does_not_exist(void);
+
+/*
+ * 'index to address' translation. If anyone tries to use the idx
+ * directly without tranlation, we catch the bug with a NULL-deference
+ * kernel oops. Illegal ranges of incoming indices are caught too.
+ */
+static __always_inline unsigned long fix_to_virt(const unsigned int idx)
+{
+ /*
+ * this branch gets completely eliminated after inlining,
+ * except when someone tries to use fixaddr indices in an
+ * illegal way. (such as mixing up address types or using
+ * out-of-range indices).
+ *
+ * If it doesn't get removed, the linker will complain
+ * loudly with a reasonably clear error message..
+ */
+ if (idx >= __end_of_fixed_addresses)
+ __this_fixmap_does_not_exist();
+
+ return __fix_to_virt(idx);
+}
+
+static inline unsigned long virt_to_fix(const unsigned long vaddr)
+{
+ BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+ return __virt_to_fix(vaddr);
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_FIXMAP_H */
diff --git a/arch/tile/include/asm/ftrace.h b/arch/tile/include/asm/ftrace.h
new file mode 100644
index 000000000000..461459b06d98
--- /dev/null
+++ b/arch/tile/include/asm/ftrace.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_FTRACE_H
+#define _ASM_TILE_FTRACE_H
+
+/* empty */
+
+#endif /* _ASM_TILE_FTRACE_H */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
new file mode 100644
index 000000000000..9eaeb3c08786
--- /dev/null
+++ b/arch/tile/include/asm/futex.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * These routines make two important assumptions:
+ *
+ * 1. atomic_t is really an int and can be freely cast back and forth
+ * (validated in __init_atomic_per_cpu).
+ *
+ * 2. userspace uses sys_cmpxchg() for all atomic operations, thus using
+ * the same locking convention that all the kernel atomic routines use.
+ */
+
+#ifndef _ASM_TILE_FUTEX_H
+#define _ASM_TILE_FUTEX_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <linux/errno.h>
+
+extern struct __get_user futex_set(int *v, int i);
+extern struct __get_user futex_add(int *v, int n);
+extern struct __get_user futex_or(int *v, int n);
+extern struct __get_user futex_andn(int *v, int n);
+extern struct __get_user futex_cmpxchg(int *v, int o, int n);
+
+#ifndef __tilegx__
+extern struct __get_user futex_xor(int *v, int n);
+#else
+static inline struct __get_user futex_xor(int __user *uaddr, int n)
+{
+ struct __get_user asm_ret = __get_user_4(uaddr);
+ if (!asm_ret.err) {
+ int oldval, newval;
+ do {
+ oldval = asm_ret.val;
+ newval = oldval ^ n;
+ asm_ret = futex_cmpxchg(uaddr, oldval, newval);
+ } while (asm_ret.err == 0 && oldval != asm_ret.val);
+ }
+ return asm_ret;
+}
+#endif
+
+static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int ret;
+ struct __get_user asm_ret;
+
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ pagefault_disable();
+ switch (op) {
+ case FUTEX_OP_SET:
+ asm_ret = futex_set(uaddr, oparg);
+ break;
+ case FUTEX_OP_ADD:
+ asm_ret = futex_add(uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ asm_ret = futex_or(uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ asm_ret = futex_andn(uaddr, oparg);
+ break;
+ case FUTEX_OP_XOR:
+ asm_ret = futex_xor(uaddr, oparg);
+ break;
+ default:
+ asm_ret.err = -ENOSYS;
+ }
+ pagefault_enable();
+
+ ret = asm_ret.err;
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ:
+ ret = (asm_ret.val == cmparg);
+ break;
+ case FUTEX_OP_CMP_NE:
+ ret = (asm_ret.val != cmparg);
+ break;
+ case FUTEX_OP_CMP_LT:
+ ret = (asm_ret.val < cmparg);
+ break;
+ case FUTEX_OP_CMP_GE:
+ ret = (asm_ret.val >= cmparg);
+ break;
+ case FUTEX_OP_CMP_LE:
+ ret = (asm_ret.val <= cmparg);
+ break;
+ case FUTEX_OP_CMP_GT:
+ ret = (asm_ret.val > cmparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval,
+ int newval)
+{
+ struct __get_user asm_ret;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ asm_ret = futex_cmpxchg(uaddr, oldval, newval);
+ return asm_ret.err ? asm_ret.err : asm_ret.val;
+}
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_FUTEX_H */
diff --git a/arch/tile/include/asm/hardirq.h b/arch/tile/include/asm/hardirq.h
new file mode 100644
index 000000000000..822390f9a154
--- /dev/null
+++ b/arch/tile/include/asm/hardirq.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_HARDIRQ_H
+#define _ASM_TILE_HARDIRQ_H
+
+#include <linux/threads.h>
+#include <linux/cache.h>
+
+#include <asm/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ long idle_timestamp;
+
+ /* Hard interrupt statistics. */
+ unsigned int irq_timer_count;
+ unsigned int irq_syscall_count;
+ unsigned int irq_resched_count;
+ unsigned int irq_hv_flush_count;
+ unsigned int irq_call_count;
+ unsigned int irq_hv_msg_count;
+ unsigned int irq_dev_intr_count;
+
+} ____cacheline_aligned irq_cpustat_t;
+
+DECLARE_PER_CPU(irq_cpustat_t, irq_stat);
+
+#define __ARCH_IRQ_STAT
+#define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member)
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+#define HARDIRQ_BITS 8
+
+#endif /* _ASM_TILE_HARDIRQ_H */
diff --git a/arch/tile/include/asm/highmem.h b/arch/tile/include/asm/highmem.h
new file mode 100644
index 000000000000..efdd12e91020
--- /dev/null
+++ b/arch/tile/include/asm/highmem.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 1999 Gerhard Wichert, Siemens AG
+ * Gerhard.Wichert@pdb.siemens.de
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Used in CONFIG_HIGHMEM systems for memory pages which
+ * are not addressable by direct kernel virtual addresses.
+ *
+ */
+
+#ifndef _ASM_TILE_HIGHMEM_H
+#define _ASM_TILE_HIGHMEM_H
+
+#include <linux/interrupt.h>
+#include <linux/threads.h>
+#include <asm/kmap_types.h>
+#include <asm/tlbflush.h>
+#include <asm/homecache.h>
+
+/* declarations for highmem.c */
+extern unsigned long highstart_pfn, highend_pfn;
+
+extern pte_t *pkmap_page_table;
+
+/*
+ * Ordering is:
+ *
+ * FIXADDR_TOP
+ * fixed_addresses
+ * FIXADDR_START
+ * temp fixed addresses
+ * FIXADDR_BOOT_START
+ * Persistent kmap area
+ * PKMAP_BASE
+ * VMALLOC_END
+ * Vmalloc area
+ * VMALLOC_START
+ * high_memory
+ */
+#define LAST_PKMAP_MASK (LAST_PKMAP-1)
+#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
+#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))
+
+void *kmap_high(struct page *page);
+void kunmap_high(struct page *page);
+void *kmap(struct page *page);
+void kunmap(struct page *page);
+void *kmap_fix_kpte(struct page *page, int finished);
+
+/* This macro is used only in map_new_virtual() to map "page". */
+#define kmap_prot page_to_kpgprot(page)
+
+void kunmap_atomic(void *kvaddr, enum km_type type);
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
+struct page *kmap_atomic_to_page(void *ptr);
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot);
+void *kmap_atomic(struct page *page, enum km_type type);
+void kmap_atomic_fix_kpte(struct page *page, int finished);
+
+#define flush_cache_kmaps() do { } while (0)
+
+#endif /* _ASM_TILE_HIGHMEM_H */
diff --git a/arch/tile/include/asm/homecache.h b/arch/tile/include/asm/homecache.h
new file mode 100644
index 000000000000..a8243865d49e
--- /dev/null
+++ b/arch/tile/include/asm/homecache.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Handle issues around the Tile "home cache" model of coherence.
+ */
+
+#ifndef _ASM_TILE_HOMECACHE_H
+#define _ASM_TILE_HOMECACHE_H
+
+#include <asm/page.h>
+#include <linux/cpumask.h>
+
+struct page;
+struct task_struct;
+struct vm_area_struct;
+struct zone;
+
+/*
+ * Coherence point for the page is its memory controller.
+ * It is not present in any cache (L1 or L2).
+ */
+#define PAGE_HOME_UNCACHED -1
+
+/*
+ * Is this page immutable (unwritable) and thus able to be cached more
+ * widely than would otherwise be possible? On tile64 this means we
+ * mark the PTE to cache locally; on tilepro it means we have "nc" set.
+ */
+#define PAGE_HOME_IMMUTABLE -2
+
+/*
+ * Each cpu considers its own cache to be the home for the page,
+ * which makes it incoherent.
+ */
+#define PAGE_HOME_INCOHERENT -3
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+/* Home for the page is distributed via hash-for-home. */
+#define PAGE_HOME_HASH -4
+#endif
+
+/* Homing is unknown or unspecified. Not valid for page_home(). */
+#define PAGE_HOME_UNKNOWN -5
+
+/* Home on the current cpu. Not valid for page_home(). */
+#define PAGE_HOME_HERE -6
+
+/* Support wrapper to use instead of explicit hv_flush_remote(). */
+extern void flush_remote(unsigned long cache_pfn, unsigned long cache_length,
+ const struct cpumask *cache_cpumask,
+ HV_VirtAddr tlb_va, unsigned long tlb_length,
+ unsigned long tlb_pgsize,
+ const struct cpumask *tlb_cpumask,
+ HV_Remote_ASID *asids, int asidcount);
+
+/* Set homing-related bits in a PTE (can also pass a pgprot_t). */
+extern pte_t pte_set_home(pte_t pte, int home);
+
+/* Do a cache eviction on the specified cpus. */
+extern void homecache_evict(const struct cpumask *mask);
+
+/*
+ * Change a kernel page's homecache. It must not be mapped in user space.
+ * If !CONFIG_HOMECACHE, only usable on LOWMEM, and can only be called when
+ * no other cpu can reference the page, and causes a full-chip cache/TLB flush.
+ */
+extern void homecache_change_page_home(struct page *, int order, int home);
+
+/*
+ * Flush a page out of whatever cache(s) it is in.
+ * This is more than just finv, since it properly handles waiting
+ * for the data to reach memory on tilepro, but it can be quite
+ * heavyweight, particularly on hash-for-home memory.
+ */
+extern void homecache_flush_cache(struct page *, int order);
+
+/*
+ * Allocate a page with the given GFP flags, home, and optionally
+ * node. These routines are actually just wrappers around the normal
+ * alloc_pages() / alloc_pages_node() functions, which set and clear
+ * a per-cpu variable to communicate with homecache_new_kernel_page().
+ * If !CONFIG_HOMECACHE, uses homecache_change_page_home().
+ */
+extern struct page *homecache_alloc_pages(gfp_t gfp_mask,
+ unsigned int order, int home);
+extern struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask,
+ unsigned int order, int home);
+#define homecache_alloc_page(gfp_mask, home) \
+ homecache_alloc_pages(gfp_mask, 0, home)
+
+/*
+ * These routines are just pass-throughs to free_pages() when
+ * we support full homecaching. If !CONFIG_HOMECACHE, then these
+ * routines use homecache_change_page_home() to reset the home
+ * back to the default before returning the page to the allocator.
+ */
+void homecache_free_pages(unsigned long addr, unsigned int order);
+#define homecache_free_page(page) \
+ homecache_free_pages((page), 0)
+
+
+
+/*
+ * Report the page home for LOWMEM pages by examining their kernel PTE,
+ * or for highmem pages as the default home.
+ */
+extern int page_home(struct page *);
+
+#define homecache_migrate_kthread() do {} while (0)
+
+#define homecache_kpte_lock() 0
+#define homecache_kpte_unlock(flags) do {} while (0)
+
+
+#endif /* _ASM_TILE_HOMECACHE_H */
diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h
new file mode 100644
index 000000000000..0521c277bbde
--- /dev/null
+++ b/arch/tile/include/asm/hugetlb.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_HUGETLB_H
+#define _ASM_TILE_HUGETLB_H
+
+#include <asm/page.h>
+
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len) {
+ return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(struct file *file,
+ unsigned long addr, unsigned long len)
+{
+ struct hstate *h = hstate_file(file);
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (addr & ~huge_page_mask(h))
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm)
+{
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ set_pte_order(ptep, pte, HUGETLB_PAGE_ORDER);
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ return ptep_get_and_clear(mm, addr, ptep);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_clear_flush(vma, addr, ptep);
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ ptep_set_wrprotect(mm, addr, ptep);
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline int arch_prepare_hugepage(struct page *page)
+{
+ return 0;
+}
+
+static inline void arch_release_hugepage(struct page *page)
+{
+}
+
+#endif /* _ASM_TILE_HUGETLB_H */
diff --git a/arch/tile/include/asm/hv_driver.h b/arch/tile/include/asm/hv_driver.h
new file mode 100644
index 000000000000..ad614de899b3
--- /dev/null
+++ b/arch/tile/include/asm/hv_driver.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This header defines a wrapper interface for managing hypervisor
+ * device calls that will result in an interrupt at some later time.
+ * In particular, this provides wrappers for hv_preada() and
+ * hv_pwritea().
+ */
+
+#ifndef _ASM_TILE_HV_DRIVER_H
+#define _ASM_TILE_HV_DRIVER_H
+
+#include <hv/hypervisor.h>
+
+struct hv_driver_cb;
+
+/* A callback to be invoked when an operation completes. */
+typedef void hv_driver_callback_t(struct hv_driver_cb *cb, __hv32 result);
+
+/*
+ * A structure to hold information about an outstanding call.
+ * The driver must allocate a separate structure for each call.
+ */
+struct hv_driver_cb {
+ hv_driver_callback_t *callback; /* Function to call on interrupt. */
+ void *dev; /* Driver-specific state variable. */
+};
+
+/* Wrapper for invoking hv_dev_preada(). */
+static inline int
+tile_hv_dev_preada(int devhdl, __hv32 flags, __hv32 sgl_len,
+ HV_SGL sgl[/* sgl_len */], __hv64 offset,
+ struct hv_driver_cb *callback)
+{
+ return hv_dev_preada(devhdl, flags, sgl_len, sgl,
+ offset, (HV_IntArg)callback);
+}
+
+/* Wrapper for invoking hv_dev_pwritea(). */
+static inline int
+tile_hv_dev_pwritea(int devhdl, __hv32 flags, __hv32 sgl_len,
+ HV_SGL sgl[/* sgl_len */], __hv64 offset,
+ struct hv_driver_cb *callback)
+{
+ return hv_dev_pwritea(devhdl, flags, sgl_len, sgl,
+ offset, (HV_IntArg)callback);
+}
+
+
+#endif /* _ASM_TILE_HV_DRIVER_H */
diff --git a/arch/tile/include/asm/hw_irq.h b/arch/tile/include/asm/hw_irq.h
new file mode 100644
index 000000000000..4fac5fbf333e
--- /dev/null
+++ b/arch/tile/include/asm/hw_irq.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_HW_IRQ_H
+#define _ASM_TILE_HW_IRQ_H
+
+#endif /* _ASM_TILE_HW_IRQ_H */
diff --git a/arch/tile/include/asm/ide.h b/arch/tile/include/asm/ide.h
new file mode 100644
index 000000000000..3c6f2ed894ce
--- /dev/null
+++ b/arch/tile/include/asm/ide.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_IDE_H
+#define _ASM_TILE_IDE_H
+
+/* For IDE on PCI */
+#define MAX_HWIFS 10
+
+#define ide_default_io_ctl(base) (0)
+
+#include <asm-generic/ide_iops.h>
+
+#endif /* _ASM_TILE_IDE_H */
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
new file mode 100644
index 000000000000..8c95bef3fa45
--- /dev/null
+++ b/arch/tile/include/asm/io.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_IO_H
+#define _ASM_TILE_IO_H
+
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <asm/page.h>
+
+#define IO_SPACE_LIMIT 0xfffffffful
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access.
+ */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer.
+ */
+#define xlate_dev_kmem_ptr(p) p
+
+/*
+ * Change "struct page" to physical address.
+ */
+#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
+
+/*
+ * Some places try to pass in an loff_t for PHYSADDR (?!), so we cast it to
+ * long before casting it to a pointer to avoid compiler warnings.
+ */
+#if CHIP_HAS_MMIO()
+extern void __iomem *ioremap(resource_size_t offset, unsigned long size);
+extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
+ pgprot_t pgprot);
+extern void iounmap(volatile void __iomem *addr);
+#else
+#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr))
+#define iounmap(addr) ((void)0)
+#endif
+
+#define ioremap_nocache(physaddr, size) ioremap(physaddr, size)
+#define ioremap_writethrough(physaddr, size) ioremap(physaddr, size)
+#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size)
+
+void __iomem *ioport_map(unsigned long port, unsigned int len);
+extern inline void ioport_unmap(void __iomem *addr) {}
+
+#define mmiowb()
+
+/* Conversion between virtual and physical mappings. */
+#define mm_ptov(addr) ((void *)phys_to_virt(addr))
+#define mm_vtop(addr) ((unsigned long)virt_to_phys(addr))
+
+#ifdef CONFIG_PCI
+
+extern u8 _tile_readb(unsigned long addr);
+extern u16 _tile_readw(unsigned long addr);
+extern u32 _tile_readl(unsigned long addr);
+extern u64 _tile_readq(unsigned long addr);
+extern void _tile_writeb(u8 val, unsigned long addr);
+extern void _tile_writew(u16 val, unsigned long addr);
+extern void _tile_writel(u32 val, unsigned long addr);
+extern void _tile_writeq(u64 val, unsigned long addr);
+
+#else
+
+/*
+ * The Tile architecture does not support IOMEM unless PCI is enabled.
+ * Unfortunately we can't yet simply not declare these methods,
+ * since some generic code that compiles into the kernel, but
+ * we never run, uses them unconditionally.
+ */
+
+static inline int iomem_panic(void)
+{
+ panic("readb/writeb and friends do not exist on tile without PCI");
+ return 0;
+}
+
+static inline u8 _tile_readb(unsigned long addr)
+{
+ return iomem_panic();
+}
+
+static inline u16 _tile_readw(unsigned long addr)
+{
+ return iomem_panic();
+}
+
+static inline u32 _tile_readl(unsigned long addr)
+{
+ return iomem_panic();
+}
+
+static inline u64 _tile_readq(unsigned long addr)
+{
+ return iomem_panic();
+}
+
+static inline void _tile_writeb(u8 val, unsigned long addr)
+{
+ iomem_panic();
+}
+
+static inline void _tile_writew(u16 val, unsigned long addr)
+{
+ iomem_panic();
+}
+
+static inline void _tile_writel(u32 val, unsigned long addr)
+{
+ iomem_panic();
+}
+
+static inline void _tile_writeq(u64 val, unsigned long addr)
+{
+ iomem_panic();
+}
+
+#endif
+
+#define readb(addr) _tile_readb((unsigned long)addr)
+#define readw(addr) _tile_readw((unsigned long)addr)
+#define readl(addr) _tile_readl((unsigned long)addr)
+#define readq(addr) _tile_readq((unsigned long)addr)
+#define writeb(val, addr) _tile_writeb(val, (unsigned long)addr)
+#define writew(val, addr) _tile_writew(val, (unsigned long)addr)
+#define writel(val, addr) _tile_writel(val, (unsigned long)addr)
+#define writeq(val, addr) _tile_writeq(val, (unsigned long)addr)
+
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
+#define __raw_readq readq
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
+#define __raw_writeq writeq
+
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
+#define readq_relaxed readq
+
+#define ioread8 readb
+#define ioread16 readw
+#define ioread32 readl
+#define ioread64 readq
+#define iowrite8 writeb
+#define iowrite16 writew
+#define iowrite32 writel
+#define iowrite64 writeq
+
+static inline void *memcpy_fromio(void *dst, void *src, int len)
+{
+ int x;
+ BUG_ON((unsigned long)src & 0x3);
+ for (x = 0; x < len; x += 4)
+ *(u32 *)(dst + x) = readl(src + x);
+ return dst;
+}
+
+static inline void *memcpy_toio(void *dst, void *src, int len)
+{
+ int x;
+ BUG_ON((unsigned long)dst & 0x3);
+ for (x = 0; x < len; x += 4)
+ writel(*(u32 *)(src + x), dst + x);
+ return dst;
+}
+
+/*
+ * The Tile architecture does not support IOPORT, even with PCI.
+ * Unfortunately we can't yet simply not declare these methods,
+ * since some generic code that compiles into the kernel, but
+ * we never run, uses them unconditionally.
+ */
+
+static inline int ioport_panic(void)
+{
+ panic("inb/outb and friends do not exist on tile");
+ return 0;
+}
+
+static inline u8 inb(unsigned long addr)
+{
+ return ioport_panic();
+}
+
+static inline u16 inw(unsigned long addr)
+{
+ return ioport_panic();
+}
+
+static inline u32 inl(unsigned long addr)
+{
+ return ioport_panic();
+}
+
+static inline void outb(u8 b, unsigned long addr)
+{
+ ioport_panic();
+}
+
+static inline void outw(u16 b, unsigned long addr)
+{
+ ioport_panic();
+}
+
+static inline void outl(u32 b, unsigned long addr)
+{
+ ioport_panic();
+}
+
+#define inb_p(addr) inb(addr)
+#define inw_p(addr) inw(addr)
+#define inl_p(addr) inl(addr)
+#define outb_p(x, addr) outb((x), (addr))
+#define outw_p(x, addr) outw((x), (addr))
+#define outl_p(x, addr) outl((x), (addr))
+
+static inline void insb(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}
+
+static inline void insw(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}
+
+static inline void insl(unsigned long addr, void *buffer, int count)
+{
+ ioport_panic();
+}
+
+static inline void outsb(unsigned long addr, const void *buffer, int count)
+{
+ ioport_panic();
+}
+
+static inline void outsw(unsigned long addr, const void *buffer, int count)
+{
+ ioport_panic();
+}
+
+static inline void outsl(unsigned long addr, const void *buffer, int count)
+{
+ ioport_panic();
+}
+
+#define ioread8_rep(p, dst, count) \
+ insb((unsigned long) (p), (dst), (count))
+#define ioread16_rep(p, dst, count) \
+ insw((unsigned long) (p), (dst), (count))
+#define ioread32_rep(p, dst, count) \
+ insl((unsigned long) (p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) \
+ outsb((unsigned long) (p), (src), (count))
+#define iowrite16_rep(p, src, count) \
+ outsw((unsigned long) (p), (src), (count))
+#define iowrite32_rep(p, src, count) \
+ outsl((unsigned long) (p), (src), (count))
+
+#endif /* _ASM_TILE_IO_H */
diff --git a/arch/tile/include/asm/ioctl.h b/arch/tile/include/asm/ioctl.h
new file mode 100644
index 000000000000..b279fe06dfe5
--- /dev/null
+++ b/arch/tile/include/asm/ioctl.h
@@ -0,0 +1 @@
+#include <asm-generic/ioctl.h>
diff --git a/arch/tile/include/asm/ioctls.h b/arch/tile/include/asm/ioctls.h
new file mode 100644
index 000000000000..ec34c760665e
--- /dev/null
+++ b/arch/tile/include/asm/ioctls.h
@@ -0,0 +1 @@
+#include <asm-generic/ioctls.h>
diff --git a/arch/tile/include/asm/ipc.h b/arch/tile/include/asm/ipc.h
new file mode 100644
index 000000000000..a46e3d9c2a3f
--- /dev/null
+++ b/arch/tile/include/asm/ipc.h
@@ -0,0 +1 @@
+#include <asm-generic/ipc.h>
diff --git a/arch/tile/include/asm/ipcbuf.h b/arch/tile/include/asm/ipcbuf.h
new file mode 100644
index 000000000000..84c7e51cb6d0
--- /dev/null
+++ b/arch/tile/include/asm/ipcbuf.h
@@ -0,0 +1 @@
+#include <asm-generic/ipcbuf.h>
diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h
new file mode 100644
index 000000000000..9be1f849fac9
--- /dev/null
+++ b/arch/tile/include/asm/irq.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_IRQ_H
+#define _ASM_TILE_IRQ_H
+
+#include <linux/hardirq.h>
+
+/* The hypervisor interface provides 32 IRQs. */
+#define NR_IRQS 32
+
+/* IRQ numbers used for linux IPIs. */
+#define IRQ_RESCHEDULE 1
+
+/* The HV interrupt state object. */
+DECLARE_PER_CPU(HV_IntrState, dev_intr_state);
+
+void ack_bad_irq(unsigned int irq);
+
+/*
+ * Paravirtualized drivers should call this when their init calls
+ * discover a valid HV IRQ.
+ */
+void tile_irq_activate(unsigned int irq);
+
+#endif /* _ASM_TILE_IRQ_H */
diff --git a/arch/tile/include/asm/irq_regs.h b/arch/tile/include/asm/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/arch/tile/include/asm/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
new file mode 100644
index 000000000000..cf5bffd00fef
--- /dev/null
+++ b/arch/tile/include/asm/irqflags.h
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_IRQFLAGS_H
+#define _ASM_TILE_IRQFLAGS_H
+
+#include <asm/processor.h>
+#include <arch/interrupts.h>
+#include <arch/chip.h>
+
+/*
+ * The set of interrupts we want to allow when interrupts are nominally
+ * disabled. The remainder are effectively "NMI" interrupts from
+ * the point of view of the generic Linux code. Note that synchronous
+ * interrupts (aka "non-queued") are not blocked by the mask in any case.
+ */
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+#define LINUX_MASKABLE_INTERRUPTS \
+ (~(INT_MASK(INT_PERF_COUNT) | INT_MASK(INT_AUX_PERF_COUNT)))
+#else
+#define LINUX_MASKABLE_INTERRUPTS \
+ (~(INT_MASK(INT_PERF_COUNT)))
+#endif
+
+#ifndef __ASSEMBLY__
+
+/* NOTE: we can't include <linux/percpu.h> due to #include dependencies. */
+#include <asm/percpu.h>
+#include <arch/spr_def.h>
+
+/* Set and clear kernel interrupt masks. */
+#if CHIP_HAS_SPLIT_INTR_MASK()
+#if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 || INT_MEM_ERROR >= 32
+# error Fix assumptions about which word various interrupts are in
+#endif
+#define interrupt_mask_set(n) do { \
+ int __n = (n); \
+ int __mask = 1 << (__n & 0x1f); \
+ if (__n < 32) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, __mask); \
+ else \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, __mask); \
+} while (0)
+#define interrupt_mask_reset(n) do { \
+ int __n = (n); \
+ int __mask = 1 << (__n & 0x1f); \
+ if (__n < 32) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, __mask); \
+ else \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, __mask); \
+} while (0)
+#define interrupt_mask_check(n) ({ \
+ int __n = (n); \
+ (((__n < 32) ? \
+ __insn_mfspr(SPR_INTERRUPT_MASK_1_0) : \
+ __insn_mfspr(SPR_INTERRUPT_MASK_1_1)) \
+ >> (__n & 0x1f)) & 1; \
+})
+#define interrupt_mask_set_mask(mask) do { \
+ unsigned long long __m = (mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_0, (unsigned long)(__m)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1_1, (unsigned long)(__m>>32)); \
+} while (0)
+#define interrupt_mask_reset_mask(mask) do { \
+ unsigned long long __m = (mask); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_0, (unsigned long)(__m)); \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1_1, (unsigned long)(__m>>32)); \
+} while (0)
+#else
+#define interrupt_mask_set(n) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (1UL << (n)))
+#define interrupt_mask_reset(n) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (1UL << (n)))
+#define interrupt_mask_check(n) \
+ ((__insn_mfspr(SPR_INTERRUPT_MASK_1) >> (n)) & 1)
+#define interrupt_mask_set_mask(mask) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_SET_1, (mask))
+#define interrupt_mask_reset_mask(mask) \
+ __insn_mtspr(SPR_INTERRUPT_MASK_RESET_1, (mask))
+#endif
+
+/*
+ * The set of interrupts we want active if irqs are enabled.
+ * Note that in particular, the tile timer interrupt comes and goes
+ * from this set, since we have no other way to turn off the timer.
+ * Likewise, INTCTRL_1 is removed and re-added during device
+ * interrupts, as is the the hardwall UDN_FIREWALL interrupt.
+ * We use a low bit (MEM_ERROR) as our sentinel value and make sure it
+ * is always claimed as an "active interrupt" so we can query that bit
+ * to know our current state.
+ */
+DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
+#define INITIAL_INTERRUPTS_ENABLED INT_MASK(INT_MEM_ERROR)
+
+/* Disable interrupts. */
+#define raw_local_irq_disable() \
+ interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS)
+
+/* Disable all interrupts, including NMIs. */
+#define raw_local_irq_disable_all() \
+ interrupt_mask_set_mask(-1UL)
+
+/* Re-enable all maskable interrupts. */
+#define raw_local_irq_enable() \
+ interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask))
+
+/* Disable or enable interrupts based on flag argument. */
+#define raw_local_irq_restore(disabled) do { \
+ if (disabled) \
+ raw_local_irq_disable(); \
+ else \
+ raw_local_irq_enable(); \
+} while (0)
+
+/* Return true if "flags" argument means interrupts are disabled. */
+#define raw_irqs_disabled_flags(flags) ((flags) != 0)
+
+/* Return true if interrupts are currently disabled. */
+#define raw_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR)
+
+/* Save whether interrupts are currently disabled. */
+#define raw_local_save_flags(flags) ((flags) = raw_irqs_disabled())
+
+/* Save whether interrupts are currently disabled, then disable them. */
+#define raw_local_irq_save(flags) \
+ do { raw_local_save_flags(flags); raw_local_irq_disable(); } while (0)
+
+/* Prevent the given interrupt from being enabled next time we enable irqs. */
+#define raw_local_irq_mask(interrupt) \
+ (__get_cpu_var(interrupts_enabled_mask) &= ~INT_MASK(interrupt))
+
+/* Prevent the given interrupt from being enabled immediately. */
+#define raw_local_irq_mask_now(interrupt) do { \
+ raw_local_irq_mask(interrupt); \
+ interrupt_mask_set(interrupt); \
+} while (0)
+
+/* Allow the given interrupt to be enabled next time we enable irqs. */
+#define raw_local_irq_unmask(interrupt) \
+ (__get_cpu_var(interrupts_enabled_mask) |= INT_MASK(interrupt))
+
+/* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */
+#define raw_local_irq_unmask_now(interrupt) do { \
+ raw_local_irq_unmask(interrupt); \
+ if (!irqs_disabled()) \
+ interrupt_mask_reset(interrupt); \
+} while (0)
+
+#else /* __ASSEMBLY__ */
+
+/* We provide a somewhat more restricted set for assembly. */
+
+#ifdef __tilegx__
+
+#if INT_MEM_ERROR != 0
+# error Fix IRQ_DISABLED() macro
+#endif
+
+/* Return 0 or 1 to indicate whether interrupts are currently disabled. */
+#define IRQS_DISABLED(tmp) \
+ mfspr tmp, INTERRUPT_MASK_1; \
+ andi tmp, tmp, 1
+
+/* Load up a pointer to &interrupts_enabled_mask. */
+#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
+ moveli reg, hw2_last(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw1(interrupts_enabled_mask); \
+ shl16insli reg, reg, hw0(interrupts_enabled_mask); \
+ add reg, reg, tp
+
+/* Disable interrupts. */
+#define IRQ_DISABLE(tmp0, tmp1) \
+ moveli tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS); \
+ shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS); \
+ shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS); \
+ mtspr INTERRUPT_MASK_SET_1, tmp0
+
+/* Disable ALL synchronous interrupts (used by NMI entry). */
+#define IRQ_DISABLE_ALL(tmp) \
+ movei tmp, -1; \
+ mtspr INTERRUPT_MASK_SET_1, tmp
+
+/* Enable interrupts. */
+#define IRQ_ENABLE(tmp0, tmp1) \
+ GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
+ ld tmp0, tmp0; \
+ mtspr INTERRUPT_MASK_RESET_1, tmp0
+
+#else /* !__tilegx__ */
+
+/*
+ * Return 0 or 1 to indicate whether interrupts are currently disabled.
+ * Note that it's important that we use a bit from the "low" mask word,
+ * since when we are enabling, that is the word we write first, so if we
+ * are interrupted after only writing half of the mask, the interrupt
+ * handler will correctly observe that we have interrupts enabled, and
+ * will enable interrupts itself on return from the interrupt handler
+ * (making the original code's write of the "high" mask word idempotent).
+ */
+#define IRQS_DISABLED(tmp) \
+ mfspr tmp, INTERRUPT_MASK_1_0; \
+ shri tmp, tmp, INT_MEM_ERROR; \
+ andi tmp, tmp, 1
+
+/* Load up a pointer to &interrupts_enabled_mask. */
+#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \
+ moveli reg, lo16(interrupts_enabled_mask); \
+ auli reg, reg, ha16(interrupts_enabled_mask);\
+ add reg, reg, tp
+
+/* Disable interrupts. */
+#define IRQ_DISABLE(tmp0, tmp1) \
+ { \
+ movei tmp0, -1; \
+ moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS) \
+ }; \
+ { \
+ mtspr INTERRUPT_MASK_SET_1_0, tmp0; \
+ auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS) \
+ }; \
+ mtspr INTERRUPT_MASK_SET_1_1, tmp1
+
+/* Disable ALL synchronous interrupts (used by NMI entry). */
+#define IRQ_DISABLE_ALL(tmp) \
+ movei tmp, -1; \
+ mtspr INTERRUPT_MASK_SET_1_0, tmp; \
+ mtspr INTERRUPT_MASK_SET_1_1, tmp
+
+/* Enable interrupts. */
+#define IRQ_ENABLE(tmp0, tmp1) \
+ GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \
+ { \
+ lw tmp0, tmp0; \
+ addi tmp1, tmp0, 4 \
+ }; \
+ lw tmp1, tmp1; \
+ mtspr INTERRUPT_MASK_RESET_1_0, tmp0; \
+ mtspr INTERRUPT_MASK_RESET_1_1, tmp1
+#endif
+
+/*
+ * Do the CPU's IRQ-state tracing from assembly code. We call a
+ * C function, but almost everywhere we do, we don't mind clobbering
+ * all the caller-saved registers.
+ */
+#ifdef CONFIG_TRACE_IRQFLAGS
+# define TRACE_IRQS_ON jal trace_hardirqs_on
+# define TRACE_IRQS_OFF jal trace_hardirqs_off
+#else
+# define TRACE_IRQS_ON
+# define TRACE_IRQS_OFF
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_IRQFLAGS_H */
diff --git a/arch/tile/include/asm/kdebug.h b/arch/tile/include/asm/kdebug.h
new file mode 100644
index 000000000000..6ece1b037665
--- /dev/null
+++ b/arch/tile/include/asm/kdebug.h
@@ -0,0 +1 @@
+#include <asm-generic/kdebug.h>
diff --git a/arch/tile/include/asm/kexec.h b/arch/tile/include/asm/kexec.h
new file mode 100644
index 000000000000..c11a6cc73bb8
--- /dev/null
+++ b/arch/tile/include/asm/kexec.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * based on kexec.h from other architectures in linux-2.6.18
+ */
+
+#ifndef _ASM_TILE_KEXEC_H
+#define _ASM_TILE_KEXEC_H
+
+#include <asm/page.h>
+
+/* Maximum physical address we can use pages from. */
+#define KEXEC_SOURCE_MEMORY_LIMIT TASK_SIZE
+/* Maximum address we can reach in physical address mode. */
+#define KEXEC_DESTINATION_MEMORY_LIMIT TASK_SIZE
+/* Maximum address we can use for the control code buffer. */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE
+
+/*
+ * We don't bother to provide a unique identifier, since we can only
+ * reboot with a single type of kernel image anyway.
+ */
+#define KEXEC_ARCH KEXEC_ARCH_DEFAULT
+
+/* Use the tile override for the page allocator. */
+struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order);
+#define kimage_alloc_pages_arch kimage_alloc_pages_arch
+
+#define MAX_NOTE_BYTES 1024
+
+/* Defined in arch/tile/kernel/relocate_kernel.S */
+extern const unsigned char relocate_new_kernel[];
+extern const unsigned long relocate_new_kernel_size;
+extern void relocate_new_kernel_end(void);
+
+/* Provide a dummy definition to avoid build failures. */
+static inline void crash_setup_regs(struct pt_regs *n, struct pt_regs *o)
+{
+}
+
+#endif /* _ASM_TILE_KEXEC_H */
diff --git a/arch/tile/include/asm/kmap_types.h b/arch/tile/include/asm/kmap_types.h
new file mode 100644
index 000000000000..1480106d1c05
--- /dev/null
+++ b/arch/tile/include/asm/kmap_types.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_KMAP_TYPES_H
+#define _ASM_TILE_KMAP_TYPES_H
+
+/*
+ * In TILE Linux each set of four of these uses another 16MB chunk of
+ * address space, given 64 tiles and 64KB pages, so we only enable
+ * ones that are required by the kernel configuration.
+ */
+enum km_type {
+ KM_BOUNCE_READ,
+ KM_SKB_SUNRPC_DATA,
+ KM_SKB_DATA_SOFTIRQ,
+ KM_USER0,
+ KM_USER1,
+ KM_BIO_SRC_IRQ,
+ KM_IRQ0,
+ KM_IRQ1,
+ KM_SOFTIRQ0,
+ KM_SOFTIRQ1,
+ KM_MEMCPY0,
+ KM_MEMCPY1,
+#if defined(CONFIG_HIGHPTE)
+ KM_PTE0,
+ KM_PTE1,
+#endif
+ KM_TYPE_NR
+};
+
+#endif /* _ASM_TILE_KMAP_TYPES_H */
diff --git a/arch/tile/include/asm/linkage.h b/arch/tile/include/asm/linkage.h
new file mode 100644
index 000000000000..e121c39751a7
--- /dev/null
+++ b/arch/tile/include/asm/linkage.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_LINKAGE_H
+#define _ASM_TILE_LINKAGE_H
+
+#include <feedback.h>
+
+#define __ALIGN .align 8
+
+/*
+ * The STD_ENTRY and STD_ENDPROC macros put the function in a
+ * self-named .text.foo section, and if linker feedback collection
+ * is enabled, add a suitable call to the feedback collection code.
+ * STD_ENTRY_SECTION lets you specify a non-standard section name.
+ */
+
+#define STD_ENTRY(name) \
+ .pushsection .text.##name, "ax"; \
+ ENTRY(name); \
+ FEEDBACK_ENTER(name)
+
+#define STD_ENTRY_SECTION(name, section) \
+ .pushsection section, "ax"; \
+ ENTRY(name); \
+ FEEDBACK_ENTER_EXPLICIT(name, section, .Lend_##name - name)
+
+#define STD_ENDPROC(name) \
+ ENDPROC(name); \
+ .Lend_##name:; \
+ .popsection
+
+/* Create a file-static function entry set up for feedback gathering. */
+#define STD_ENTRY_LOCAL(name) \
+ .pushsection .text.##name, "ax"; \
+ ALIGN; \
+ name:; \
+ FEEDBACK_ENTER(name)
+
+#endif /* _ASM_TILE_LINKAGE_H */
diff --git a/arch/tile/include/asm/local.h b/arch/tile/include/asm/local.h
new file mode 100644
index 000000000000..c11c530f74d0
--- /dev/null
+++ b/arch/tile/include/asm/local.h
@@ -0,0 +1 @@
+#include <asm-generic/local.h>
diff --git a/arch/tile/include/asm/memprof.h b/arch/tile/include/asm/memprof.h
new file mode 100644
index 000000000000..359949be28c1
--- /dev/null
+++ b/arch/tile/include/asm/memprof.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * The hypervisor's memory controller profiling infrastructure allows
+ * the programmer to find out what fraction of the available memory
+ * bandwidth is being consumed at each memory controller. The
+ * profiler provides start, stop, and clear operations to allows
+ * profiling over a specific time window, as well as an interface for
+ * reading the most recent profile values.
+ *
+ * This header declares IOCTL codes necessary to control memprof.
+ */
+#ifndef _ASM_TILE_MEMPROF_H
+#define _ASM_TILE_MEMPROF_H
+
+#include <linux/ioctl.h>
+
+#define MEMPROF_IOCTL_TYPE 0xB4
+#define MEMPROF_IOCTL_START _IO(MEMPROF_IOCTL_TYPE, 0)
+#define MEMPROF_IOCTL_STOP _IO(MEMPROF_IOCTL_TYPE, 1)
+#define MEMPROF_IOCTL_CLEAR _IO(MEMPROF_IOCTL_TYPE, 2)
+
+#endif /* _ASM_TILE_MEMPROF_H */
diff --git a/arch/tile/include/asm/mman.h b/arch/tile/include/asm/mman.h
new file mode 100644
index 000000000000..4c6811e3e8dc
--- /dev/null
+++ b/arch/tile/include/asm/mman.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_MMAN_H
+#define _ASM_TILE_MMAN_H
+
+#include <asm-generic/mman-common.h>
+#include <arch/chip.h>
+
+/* Standard Linux flags */
+
+#define MAP_POPULATE 0x0040 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x0080 /* do not block on IO */
+#define MAP_GROWSDOWN 0x0100 /* stack-like segment */
+#define MAP_LOCKED 0x0200 /* pages are locked */
+#define MAP_NORESERVE 0x0400 /* don't check for reservations */
+#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
+#define MAP_HUGETLB 0x4000 /* create a huge page mapping */
+
+
+/*
+ * Flags for mlockall
+ */
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
+
+#endif /* _ASM_TILE_MMAN_H */
diff --git a/arch/tile/include/asm/mmu.h b/arch/tile/include/asm/mmu.h
new file mode 100644
index 000000000000..92f94c77b6e4
--- /dev/null
+++ b/arch/tile/include/asm/mmu.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_MMU_H
+#define _ASM_TILE_MMU_H
+
+/* Capture any arch- and mm-specific information. */
+struct mm_context {
+ /*
+ * Written under the mmap_sem semaphore; read without the
+ * semaphore but atomically, but it is conservatively set.
+ */
+ unsigned int priority_cached;
+};
+
+typedef struct mm_context mm_context_t;
+
+void leave_mm(int cpu);
+
+#endif /* _ASM_TILE_MMU_H */
diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h
new file mode 100644
index 000000000000..9bc0d0725c28
--- /dev/null
+++ b/arch/tile/include/asm/mmu_context.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_MMU_CONTEXT_H
+#define _ASM_TILE_MMU_CONTEXT_H
+
+#include <linux/smp.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+#include <asm/homecache.h>
+#include <asm-generic/mm_hooks.h>
+
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ return 0;
+}
+
+/* Note that arch/tile/kernel/head.S also calls hv_install_context() */
+static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot)
+{
+ /* FIXME: DIRECTIO should not always be set. FIXME. */
+ int rc = hv_install_context(__pa(pgdir), prot, asid, HV_CTX_DIRECTIO);
+ if (rc < 0)
+ panic("hv_install_context failed: %d", rc);
+}
+
+static inline void install_page_table(pgd_t *pgdir, int asid)
+{
+ pte_t *ptep = virt_to_pte(NULL, (unsigned long)pgdir);
+ __install_page_table(pgdir, asid, *ptep);
+}
+
+/*
+ * "Lazy" TLB mode is entered when we are switching to a kernel task,
+ * which borrows the mm of the previous task. The goal of this
+ * optimization is to avoid having to install a new page table. On
+ * early x86 machines (where the concept originated) you couldn't do
+ * anything short of a full page table install for invalidation, so
+ * handling a remote TLB invalidate required doing a page table
+ * re-install. Someone clearly decided that it was silly to keep
+ * doing this while in "lazy" TLB mode, so the optimization involves
+ * installing the swapper page table instead the first time one
+ * occurs, and clearing the cpu out of cpu_vm_mask, so the cpu running
+ * the kernel task doesn't need to take any more interrupts. At that
+ * point it's then necessary to explicitly reinstall it when context
+ * switching back to the original mm.
+ *
+ * On Tile, we have to do a page-table install whenever DMA is enabled,
+ * so in that case lazy mode doesn't help anyway. And more generally,
+ * we have efficient per-page TLB shootdown, and don't expect to spend
+ * that much time in kernel tasks in general, so just leaving the
+ * kernel task borrowing the old page table, but handling TLB
+ * shootdowns, is a reasonable thing to do. And importantly, this
+ * lets us use the hypervisor's internal APIs for TLB shootdown, which
+ * means we don't have to worry about having TLB shootdowns blocked
+ * when Linux is disabling interrupts; see the page migration code for
+ * an example of where it's important for TLB shootdowns to complete
+ * even when interrupts are disabled at the Linux level.
+ */
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *t)
+{
+#if CHIP_HAS_TILE_DMA()
+ /*
+ * We have to do an "identity" page table switch in order to
+ * clear any pending DMA interrupts.
+ */
+ if (current->thread.tile_dma_state.enabled)
+ install_page_table(mm->pgd, __get_cpu_var(current_asid));
+#endif
+}
+
+static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ if (likely(prev != next)) {
+
+ int cpu = smp_processor_id();
+
+ /* Pick new ASID. */
+ int asid = __get_cpu_var(current_asid) + 1;
+ if (asid > max_asid) {
+ asid = min_asid;
+ local_flush_tlb();
+ }
+ __get_cpu_var(current_asid) = asid;
+
+ /* Clear cpu from the old mm, and set it in the new one. */
+ cpumask_clear_cpu(cpu, &prev->cpu_vm_mask);
+ cpumask_set_cpu(cpu, &next->cpu_vm_mask);
+
+ /* Re-load page tables */
+ install_page_table(next->pgd, asid);
+
+ /* See how we should set the red/black cache info */
+ check_mm_caching(prev, next);
+
+ /*
+ * Since we're changing to a new mm, we have to flush
+ * the icache in case some physical page now being mapped
+ * has subsequently been repurposed and has new code.
+ */
+ __flush_icache();
+
+ }
+}
+
+static inline void activate_mm(struct mm_struct *prev_mm,
+ struct mm_struct *next_mm)
+{
+ switch_mm(prev_mm, next_mm, NULL);
+}
+
+#define destroy_context(mm) do { } while (0)
+#define deactivate_mm(tsk, mm) do { } while (0)
+
+#endif /* _ASM_TILE_MMU_CONTEXT_H */
diff --git a/arch/tile/include/asm/mmzone.h b/arch/tile/include/asm/mmzone.h
new file mode 100644
index 000000000000..c6344c4f32ac
--- /dev/null
+++ b/arch/tile/include/asm/mmzone.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_MMZONE_H
+#define _ASM_TILE_MMZONE_H
+
+extern struct pglist_data node_data[];
+#define NODE_DATA(nid) (&node_data[nid])
+
+extern void get_memcfg_numa(void);
+
+#ifdef CONFIG_DISCONTIGMEM
+
+#include <asm/page.h>
+
+/*
+ * Generally, memory ranges are always doled out by the hypervisor in
+ * fixed-size, power-of-two increments. That would make computing the node
+ * very easy. We could just take a couple high bits of the PA, which
+ * denote the memory shim, and we'd be done. However, when we're doing
+ * memory striping, this may not be true; PAs with different high bit
+ * values might be in the same node. Thus, we keep a lookup table to
+ * translate the high bits of the PFN to the node number.
+ */
+extern int highbits_to_node[];
+
+static inline int pfn_to_nid(unsigned long pfn)
+{
+ return highbits_to_node[__pfn_to_highbits(pfn)];
+}
+
+/*
+ * Following are macros that each numa implmentation must define.
+ */
+
+#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn)
+#define node_end_pfn(nid) \
+({ \
+ pg_data_t *__pgdat = NODE_DATA(nid); \
+ __pgdat->node_start_pfn + __pgdat->node_spanned_pages; \
+})
+
+#define kern_addr_valid(kaddr) virt_addr_valid((void *)kaddr)
+
+static inline int pfn_valid(int pfn)
+{
+ int nid = pfn_to_nid(pfn);
+
+ if (nid >= 0)
+ return (pfn < node_end_pfn(nid));
+ return 0;
+}
+
+/* Information on the NUMA nodes that we compute early */
+extern unsigned long node_start_pfn[];
+extern unsigned long node_end_pfn[];
+extern unsigned long node_memmap_pfn[];
+extern unsigned long node_percpu_pfn[];
+extern unsigned long node_free_pfn[];
+#ifdef CONFIG_HIGHMEM
+extern unsigned long node_lowmem_end_pfn[];
+#endif
+#ifdef CONFIG_PCI
+extern unsigned long pci_reserve_start_pfn;
+extern unsigned long pci_reserve_end_pfn;
+#endif
+
+#endif /* CONFIG_DISCONTIGMEM */
+
+#endif /* _ASM_TILE_MMZONE_H */
diff --git a/arch/tile/include/asm/module.h b/arch/tile/include/asm/module.h
new file mode 100644
index 000000000000..1e4b79fe8584
--- /dev/null
+++ b/arch/tile/include/asm/module.h
@@ -0,0 +1 @@
+#include <asm-generic/module.h>
diff --git a/arch/tile/include/asm/msgbuf.h b/arch/tile/include/asm/msgbuf.h
new file mode 100644
index 000000000000..809134c644a6
--- /dev/null
+++ b/arch/tile/include/asm/msgbuf.h
@@ -0,0 +1 @@
+#include <asm-generic/msgbuf.h>
diff --git a/arch/tile/include/asm/mutex.h b/arch/tile/include/asm/mutex.h
new file mode 100644
index 000000000000..ff6101aa2c71
--- /dev/null
+++ b/arch/tile/include/asm/mutex.h
@@ -0,0 +1 @@
+#include <asm-generic/mutex-dec.h>
diff --git a/arch/tile/include/asm/opcode-tile.h b/arch/tile/include/asm/opcode-tile.h
new file mode 100644
index 000000000000..ba38959137d7
--- /dev/null
+++ b/arch/tile/include/asm/opcode-tile.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_OPCODE_TILE_H
+#define _ASM_TILE_OPCODE_TILE_H
+
+#include <arch/chip.h>
+
+#if CHIP_WORD_SIZE() == 64
+#include <asm/opcode-tile_64.h>
+#else
+#include <asm/opcode-tile_32.h>
+#endif
+
+/* These definitions are not correct for TILE64, so just avoid them. */
+#undef TILE_ELF_MACHINE_CODE
+#undef TILE_ELF_NAME
+
+#endif /* _ASM_TILE_OPCODE_TILE_H */
diff --git a/arch/tile/include/asm/opcode-tile_32.h b/arch/tile/include/asm/opcode-tile_32.h
new file mode 100644
index 000000000000..90f8dd372531
--- /dev/null
+++ b/arch/tile/include/asm/opcode-tile_32.h
@@ -0,0 +1,1597 @@
+/* tile.h -- Header file for TILE opcode table
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Tilera Corp. */
+
+#ifndef opcode_tile_h
+#define opcode_tile_h
+
+typedef unsigned long long tile_bundle_bits;
+
+
+enum
+{
+ TILE_MAX_OPERANDS = 5 /* mm */
+};
+
+typedef enum
+{
+ TILE_OPC_BPT,
+ TILE_OPC_INFO,
+ TILE_OPC_INFOL,
+ TILE_OPC_J,
+ TILE_OPC_JAL,
+ TILE_OPC_MOVE,
+ TILE_OPC_MOVE_SN,
+ TILE_OPC_MOVEI,
+ TILE_OPC_MOVEI_SN,
+ TILE_OPC_MOVELI,
+ TILE_OPC_MOVELI_SN,
+ TILE_OPC_MOVELIS,
+ TILE_OPC_PREFETCH,
+ TILE_OPC_ADD,
+ TILE_OPC_ADD_SN,
+ TILE_OPC_ADDB,
+ TILE_OPC_ADDB_SN,
+ TILE_OPC_ADDBS_U,
+ TILE_OPC_ADDBS_U_SN,
+ TILE_OPC_ADDH,
+ TILE_OPC_ADDH_SN,
+ TILE_OPC_ADDHS,
+ TILE_OPC_ADDHS_SN,
+ TILE_OPC_ADDI,
+ TILE_OPC_ADDI_SN,
+ TILE_OPC_ADDIB,
+ TILE_OPC_ADDIB_SN,
+ TILE_OPC_ADDIH,
+ TILE_OPC_ADDIH_SN,
+ TILE_OPC_ADDLI,
+ TILE_OPC_ADDLI_SN,
+ TILE_OPC_ADDLIS,
+ TILE_OPC_ADDS,
+ TILE_OPC_ADDS_SN,
+ TILE_OPC_ADIFFB_U,
+ TILE_OPC_ADIFFB_U_SN,
+ TILE_OPC_ADIFFH,
+ TILE_OPC_ADIFFH_SN,
+ TILE_OPC_AND,
+ TILE_OPC_AND_SN,
+ TILE_OPC_ANDI,
+ TILE_OPC_ANDI_SN,
+ TILE_OPC_AULI,
+ TILE_OPC_AVGB_U,
+ TILE_OPC_AVGB_U_SN,
+ TILE_OPC_AVGH,
+ TILE_OPC_AVGH_SN,
+ TILE_OPC_BBNS,
+ TILE_OPC_BBNS_SN,
+ TILE_OPC_BBNST,
+ TILE_OPC_BBNST_SN,
+ TILE_OPC_BBS,
+ TILE_OPC_BBS_SN,
+ TILE_OPC_BBST,
+ TILE_OPC_BBST_SN,
+ TILE_OPC_BGEZ,
+ TILE_OPC_BGEZ_SN,
+ TILE_OPC_BGEZT,
+ TILE_OPC_BGEZT_SN,
+ TILE_OPC_BGZ,
+ TILE_OPC_BGZ_SN,
+ TILE_OPC_BGZT,
+ TILE_OPC_BGZT_SN,
+ TILE_OPC_BITX,
+ TILE_OPC_BITX_SN,
+ TILE_OPC_BLEZ,
+ TILE_OPC_BLEZ_SN,
+ TILE_OPC_BLEZT,
+ TILE_OPC_BLEZT_SN,
+ TILE_OPC_BLZ,
+ TILE_OPC_BLZ_SN,
+ TILE_OPC_BLZT,
+ TILE_OPC_BLZT_SN,
+ TILE_OPC_BNZ,
+ TILE_OPC_BNZ_SN,
+ TILE_OPC_BNZT,
+ TILE_OPC_BNZT_SN,
+ TILE_OPC_BYTEX,
+ TILE_OPC_BYTEX_SN,
+ TILE_OPC_BZ,
+ TILE_OPC_BZ_SN,
+ TILE_OPC_BZT,
+ TILE_OPC_BZT_SN,
+ TILE_OPC_CLZ,
+ TILE_OPC_CLZ_SN,
+ TILE_OPC_CRC32_32,
+ TILE_OPC_CRC32_32_SN,
+ TILE_OPC_CRC32_8,
+ TILE_OPC_CRC32_8_SN,
+ TILE_OPC_CTZ,
+ TILE_OPC_CTZ_SN,
+ TILE_OPC_DRAIN,
+ TILE_OPC_DTLBPR,
+ TILE_OPC_DWORD_ALIGN,
+ TILE_OPC_DWORD_ALIGN_SN,
+ TILE_OPC_FINV,
+ TILE_OPC_FLUSH,
+ TILE_OPC_FNOP,
+ TILE_OPC_ICOH,
+ TILE_OPC_ILL,
+ TILE_OPC_INTHB,
+ TILE_OPC_INTHB_SN,
+ TILE_OPC_INTHH,
+ TILE_OPC_INTHH_SN,
+ TILE_OPC_INTLB,
+ TILE_OPC_INTLB_SN,
+ TILE_OPC_INTLH,
+ TILE_OPC_INTLH_SN,
+ TILE_OPC_INV,
+ TILE_OPC_IRET,
+ TILE_OPC_JALB,
+ TILE_OPC_JALF,
+ TILE_OPC_JALR,
+ TILE_OPC_JALRP,
+ TILE_OPC_JB,
+ TILE_OPC_JF,
+ TILE_OPC_JR,
+ TILE_OPC_JRP,
+ TILE_OPC_LB,
+ TILE_OPC_LB_SN,
+ TILE_OPC_LB_U,
+ TILE_OPC_LB_U_SN,
+ TILE_OPC_LBADD,
+ TILE_OPC_LBADD_SN,
+ TILE_OPC_LBADD_U,
+ TILE_OPC_LBADD_U_SN,
+ TILE_OPC_LH,
+ TILE_OPC_LH_SN,
+ TILE_OPC_LH_U,
+ TILE_OPC_LH_U_SN,
+ TILE_OPC_LHADD,
+ TILE_OPC_LHADD_SN,
+ TILE_OPC_LHADD_U,
+ TILE_OPC_LHADD_U_SN,
+ TILE_OPC_LNK,
+ TILE_OPC_LNK_SN,
+ TILE_OPC_LW,
+ TILE_OPC_LW_SN,
+ TILE_OPC_LW_NA,
+ TILE_OPC_LW_NA_SN,
+ TILE_OPC_LWADD,
+ TILE_OPC_LWADD_SN,
+ TILE_OPC_LWADD_NA,
+ TILE_OPC_LWADD_NA_SN,
+ TILE_OPC_MAXB_U,
+ TILE_OPC_MAXB_U_SN,
+ TILE_OPC_MAXH,
+ TILE_OPC_MAXH_SN,
+ TILE_OPC_MAXIB_U,
+ TILE_OPC_MAXIB_U_SN,
+ TILE_OPC_MAXIH,
+ TILE_OPC_MAXIH_SN,
+ TILE_OPC_MF,
+ TILE_OPC_MFSPR,
+ TILE_OPC_MINB_U,
+ TILE_OPC_MINB_U_SN,
+ TILE_OPC_MINH,
+ TILE_OPC_MINH_SN,
+ TILE_OPC_MINIB_U,
+ TILE_OPC_MINIB_U_SN,
+ TILE_OPC_MINIH,
+ TILE_OPC_MINIH_SN,
+ TILE_OPC_MM,
+ TILE_OPC_MNZ,
+ TILE_OPC_MNZ_SN,
+ TILE_OPC_MNZB,
+ TILE_OPC_MNZB_SN,
+ TILE_OPC_MNZH,
+ TILE_OPC_MNZH_SN,
+ TILE_OPC_MTSPR,
+ TILE_OPC_MULHH_SS,
+ TILE_OPC_MULHH_SS_SN,
+ TILE_OPC_MULHH_SU,
+ TILE_OPC_MULHH_SU_SN,
+ TILE_OPC_MULHH_UU,
+ TILE_OPC_MULHH_UU_SN,
+ TILE_OPC_MULHHA_SS,
+ TILE_OPC_MULHHA_SS_SN,
+ TILE_OPC_MULHHA_SU,
+ TILE_OPC_MULHHA_SU_SN,
+ TILE_OPC_MULHHA_UU,
+ TILE_OPC_MULHHA_UU_SN,
+ TILE_OPC_MULHHSA_UU,
+ TILE_OPC_MULHHSA_UU_SN,
+ TILE_OPC_MULHL_SS,
+ TILE_OPC_MULHL_SS_SN,
+ TILE_OPC_MULHL_SU,
+ TILE_OPC_MULHL_SU_SN,
+ TILE_OPC_MULHL_US,
+ TILE_OPC_MULHL_US_SN,
+ TILE_OPC_MULHL_UU,
+ TILE_OPC_MULHL_UU_SN,
+ TILE_OPC_MULHLA_SS,
+ TILE_OPC_MULHLA_SS_SN,
+ TILE_OPC_MULHLA_SU,
+ TILE_OPC_MULHLA_SU_SN,
+ TILE_OPC_MULHLA_US,
+ TILE_OPC_MULHLA_US_SN,
+ TILE_OPC_MULHLA_UU,
+ TILE_OPC_MULHLA_UU_SN,
+ TILE_OPC_MULHLSA_UU,
+ TILE_OPC_MULHLSA_UU_SN,
+ TILE_OPC_MULLL_SS,
+ TILE_OPC_MULLL_SS_SN,
+ TILE_OPC_MULLL_SU,
+ TILE_OPC_MULLL_SU_SN,
+ TILE_OPC_MULLL_UU,
+ TILE_OPC_MULLL_UU_SN,
+ TILE_OPC_MULLLA_SS,
+ TILE_OPC_MULLLA_SS_SN,
+ TILE_OPC_MULLLA_SU,
+ TILE_OPC_MULLLA_SU_SN,
+ TILE_OPC_MULLLA_UU,
+ TILE_OPC_MULLLA_UU_SN,
+ TILE_OPC_MULLLSA_UU,
+ TILE_OPC_MULLLSA_UU_SN,
+ TILE_OPC_MVNZ,
+ TILE_OPC_MVNZ_SN,
+ TILE_OPC_MVZ,
+ TILE_OPC_MVZ_SN,
+ TILE_OPC_MZ,
+ TILE_OPC_MZ_SN,
+ TILE_OPC_MZB,
+ TILE_OPC_MZB_SN,
+ TILE_OPC_MZH,
+ TILE_OPC_MZH_SN,
+ TILE_OPC_NAP,
+ TILE_OPC_NOP,
+ TILE_OPC_NOR,
+ TILE_OPC_NOR_SN,
+ TILE_OPC_OR,
+ TILE_OPC_OR_SN,
+ TILE_OPC_ORI,
+ TILE_OPC_ORI_SN,
+ TILE_OPC_PACKBS_U,
+ TILE_OPC_PACKBS_U_SN,
+ TILE_OPC_PACKHB,
+ TILE_OPC_PACKHB_SN,
+ TILE_OPC_PACKHS,
+ TILE_OPC_PACKHS_SN,
+ TILE_OPC_PACKLB,
+ TILE_OPC_PACKLB_SN,
+ TILE_OPC_PCNT,
+ TILE_OPC_PCNT_SN,
+ TILE_OPC_RL,
+ TILE_OPC_RL_SN,
+ TILE_OPC_RLI,
+ TILE_OPC_RLI_SN,
+ TILE_OPC_S1A,
+ TILE_OPC_S1A_SN,
+ TILE_OPC_S2A,
+ TILE_OPC_S2A_SN,
+ TILE_OPC_S3A,
+ TILE_OPC_S3A_SN,
+ TILE_OPC_SADAB_U,
+ TILE_OPC_SADAB_U_SN,
+ TILE_OPC_SADAH,
+ TILE_OPC_SADAH_SN,
+ TILE_OPC_SADAH_U,
+ TILE_OPC_SADAH_U_SN,
+ TILE_OPC_SADB_U,
+ TILE_OPC_SADB_U_SN,
+ TILE_OPC_SADH,
+ TILE_OPC_SADH_SN,
+ TILE_OPC_SADH_U,
+ TILE_OPC_SADH_U_SN,
+ TILE_OPC_SB,
+ TILE_OPC_SBADD,
+ TILE_OPC_SEQ,
+ TILE_OPC_SEQ_SN,
+ TILE_OPC_SEQB,
+ TILE_OPC_SEQB_SN,
+ TILE_OPC_SEQH,
+ TILE_OPC_SEQH_SN,
+ TILE_OPC_SEQI,
+ TILE_OPC_SEQI_SN,
+ TILE_OPC_SEQIB,
+ TILE_OPC_SEQIB_SN,
+ TILE_OPC_SEQIH,
+ TILE_OPC_SEQIH_SN,
+ TILE_OPC_SH,
+ TILE_OPC_SHADD,
+ TILE_OPC_SHL,
+ TILE_OPC_SHL_SN,
+ TILE_OPC_SHLB,
+ TILE_OPC_SHLB_SN,
+ TILE_OPC_SHLH,
+ TILE_OPC_SHLH_SN,
+ TILE_OPC_SHLI,
+ TILE_OPC_SHLI_SN,
+ TILE_OPC_SHLIB,
+ TILE_OPC_SHLIB_SN,
+ TILE_OPC_SHLIH,
+ TILE_OPC_SHLIH_SN,
+ TILE_OPC_SHR,
+ TILE_OPC_SHR_SN,
+ TILE_OPC_SHRB,
+ TILE_OPC_SHRB_SN,
+ TILE_OPC_SHRH,
+ TILE_OPC_SHRH_SN,
+ TILE_OPC_SHRI,
+ TILE_OPC_SHRI_SN,
+ TILE_OPC_SHRIB,
+ TILE_OPC_SHRIB_SN,
+ TILE_OPC_SHRIH,
+ TILE_OPC_SHRIH_SN,
+ TILE_OPC_SLT,
+ TILE_OPC_SLT_SN,
+ TILE_OPC_SLT_U,
+ TILE_OPC_SLT_U_SN,
+ TILE_OPC_SLTB,
+ TILE_OPC_SLTB_SN,
+ TILE_OPC_SLTB_U,
+ TILE_OPC_SLTB_U_SN,
+ TILE_OPC_SLTE,
+ TILE_OPC_SLTE_SN,
+ TILE_OPC_SLTE_U,
+ TILE_OPC_SLTE_U_SN,
+ TILE_OPC_SLTEB,
+ TILE_OPC_SLTEB_SN,
+ TILE_OPC_SLTEB_U,
+ TILE_OPC_SLTEB_U_SN,
+ TILE_OPC_SLTEH,
+ TILE_OPC_SLTEH_SN,
+ TILE_OPC_SLTEH_U,
+ TILE_OPC_SLTEH_U_SN,
+ TILE_OPC_SLTH,
+ TILE_OPC_SLTH_SN,
+ TILE_OPC_SLTH_U,
+ TILE_OPC_SLTH_U_SN,
+ TILE_OPC_SLTI,
+ TILE_OPC_SLTI_SN,
+ TILE_OPC_SLTI_U,
+ TILE_OPC_SLTI_U_SN,
+ TILE_OPC_SLTIB,
+ TILE_OPC_SLTIB_SN,
+ TILE_OPC_SLTIB_U,
+ TILE_OPC_SLTIB_U_SN,
+ TILE_OPC_SLTIH,
+ TILE_OPC_SLTIH_SN,
+ TILE_OPC_SLTIH_U,
+ TILE_OPC_SLTIH_U_SN,
+ TILE_OPC_SNE,
+ TILE_OPC_SNE_SN,
+ TILE_OPC_SNEB,
+ TILE_OPC_SNEB_SN,
+ TILE_OPC_SNEH,
+ TILE_OPC_SNEH_SN,
+ TILE_OPC_SRA,
+ TILE_OPC_SRA_SN,
+ TILE_OPC_SRAB,
+ TILE_OPC_SRAB_SN,
+ TILE_OPC_SRAH,
+ TILE_OPC_SRAH_SN,
+ TILE_OPC_SRAI,
+ TILE_OPC_SRAI_SN,
+ TILE_OPC_SRAIB,
+ TILE_OPC_SRAIB_SN,
+ TILE_OPC_SRAIH,
+ TILE_OPC_SRAIH_SN,
+ TILE_OPC_SUB,
+ TILE_OPC_SUB_SN,
+ TILE_OPC_SUBB,
+ TILE_OPC_SUBB_SN,
+ TILE_OPC_SUBBS_U,
+ TILE_OPC_SUBBS_U_SN,
+ TILE_OPC_SUBH,
+ TILE_OPC_SUBH_SN,
+ TILE_OPC_SUBHS,
+ TILE_OPC_SUBHS_SN,
+ TILE_OPC_SUBS,
+ TILE_OPC_SUBS_SN,
+ TILE_OPC_SW,
+ TILE_OPC_SWADD,
+ TILE_OPC_SWINT0,
+ TILE_OPC_SWINT1,
+ TILE_OPC_SWINT2,
+ TILE_OPC_SWINT3,
+ TILE_OPC_TBLIDXB0,
+ TILE_OPC_TBLIDXB0_SN,
+ TILE_OPC_TBLIDXB1,
+ TILE_OPC_TBLIDXB1_SN,
+ TILE_OPC_TBLIDXB2,
+ TILE_OPC_TBLIDXB2_SN,
+ TILE_OPC_TBLIDXB3,
+ TILE_OPC_TBLIDXB3_SN,
+ TILE_OPC_TNS,
+ TILE_OPC_TNS_SN,
+ TILE_OPC_WH64,
+ TILE_OPC_XOR,
+ TILE_OPC_XOR_SN,
+ TILE_OPC_XORI,
+ TILE_OPC_XORI_SN,
+ TILE_OPC_NONE
+} tile_mnemonic;
+
+/* 64-bit pattern for a { bpt ; nop } bundle. */
+#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL
+
+
+#define TILE_ELF_MACHINE_CODE EM_TILEPRO
+
+#define TILE_ELF_NAME "elf32-tilepro"
+
+enum
+{
+ TILE_SN_MAX_OPERANDS = 6 /* route */
+};
+
+typedef enum
+{
+ TILE_SN_OPC_BZ,
+ TILE_SN_OPC_BNZ,
+ TILE_SN_OPC_JRR,
+ TILE_SN_OPC_FNOP,
+ TILE_SN_OPC_BLZ,
+ TILE_SN_OPC_NOP,
+ TILE_SN_OPC_MOVEI,
+ TILE_SN_OPC_MOVE,
+ TILE_SN_OPC_BGEZ,
+ TILE_SN_OPC_JR,
+ TILE_SN_OPC_BLEZ,
+ TILE_SN_OPC_BBNS,
+ TILE_SN_OPC_JALRR,
+ TILE_SN_OPC_BPT,
+ TILE_SN_OPC_JALR,
+ TILE_SN_OPC_SHR1,
+ TILE_SN_OPC_BGZ,
+ TILE_SN_OPC_BBS,
+ TILE_SN_OPC_SHL8II,
+ TILE_SN_OPC_ADDI,
+ TILE_SN_OPC_HALT,
+ TILE_SN_OPC_ROUTE,
+ TILE_SN_OPC_NONE
+} tile_sn_mnemonic;
+
+extern const unsigned char tile_sn_route_encode[6 * 6 * 6];
+extern const signed char tile_sn_route_decode[256][3];
+extern const char tile_sn_direction_names[6][5];
+extern const signed char tile_sn_dest_map[6][6];
+
+
+static __inline unsigned int
+get_BrOff_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_BrOff_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000);
+}
+
+static __inline unsigned int
+get_BrType_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0xf);
+}
+
+static __inline unsigned int
+get_Dest_Imm8_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x0000003f) |
+ (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 2)) & 0x3);
+}
+
+static __inline unsigned int
+get_Dest_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Imm16_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm16_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm8_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_ImmOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 20)) & 0x7f);
+}
+
+static __inline unsigned int
+get_ImmOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 51)) & 0x7f);
+}
+
+static __inline unsigned int
+get_ImmRROpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 8)) & 0x3);
+}
+
+static __inline unsigned int
+get_JOffLong_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000) |
+ (((unsigned int)(n >> 14)) & 0x001e0000) |
+ (((unsigned int)(n >> 16)) & 0x07e00000) |
+ (((unsigned int)(n >> 31)) & 0x18000000);
+}
+
+static __inline unsigned int
+get_JOff_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000) |
+ (((unsigned int)(n >> 14)) & 0x001e0000) |
+ (((unsigned int)(n >> 16)) & 0x07e00000) |
+ (((unsigned int)(n >> 31)) & 0x08000000);
+}
+
+static __inline unsigned int
+get_MF_Imm15_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x00003fff) |
+ (((unsigned int)(n >> 44)) & 0x00004000);
+}
+
+static __inline unsigned int
+get_MMEnd_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMEnd_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMStart_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 23)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMStart_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 54)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MT_Imm15_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x0000003f) |
+ (((unsigned int)(n >> 37)) & 0x00003fc0) |
+ (((unsigned int)(n >> 44)) & 0x00004000);
+}
+
+static __inline unsigned int
+get_Mode(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 63)) & 0x1);
+}
+
+static __inline unsigned int
+get_NoRegOpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 10)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Opcode_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 28)) & 0x7);
+}
+
+static __inline unsigned int
+get_Opcode_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 59)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 27)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 59)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y2(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 56)) & 0x7);
+}
+
+static __inline unsigned int
+get_RROpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 4)) & 0xf);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x1ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x1ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x3);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x3);
+}
+
+static __inline unsigned int
+get_RouteOpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_S_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 27)) & 0x1);
+}
+
+static __inline unsigned int
+get_S_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 58)) & 0x1);
+}
+
+static __inline unsigned int
+get_ShAmt_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_SrcA_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y2(tile_bundle_bits n)
+{
+ return (((n >> 26)) & 0x00000001) |
+ (((unsigned int)(n >> 50)) & 0x0000003e);
+}
+
+static __inline unsigned int
+get_SrcBDest_Y2(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 20)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Src_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 17)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 48)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 17)) & 0x7);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 48)) & 0x7);
+}
+
+
+static __inline int
+sign_extend(int n, int num_bits)
+{
+ int shift = (int)(sizeof(int) * 8 - num_bits);
+ return (n << shift) >> shift;
+}
+
+
+
+static __inline tile_bundle_bits
+create_BrOff_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_BrOff_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20);
+}
+
+static __inline tile_bundle_bits
+create_BrType_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Imm8_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tile_bundle_bits)(n & 0x000000c0)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Dest_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 2);
+}
+
+static __inline tile_bundle_bits
+create_Dest_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Dest_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Imm16_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xffff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm16_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xffff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_ImmOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7f) << 20);
+}
+
+static __inline tile_bundle_bits
+create_ImmOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7f)) << 51);
+}
+
+static __inline tile_bundle_bits
+create_ImmRROpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 8);
+}
+
+static __inline tile_bundle_bits
+create_JOffLong_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20) |
+ (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
+ (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
+ (((tile_bundle_bits)(n & 0x18000000)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_JOff_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20) |
+ (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
+ (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
+ (((tile_bundle_bits)(n & 0x08000000)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_MF_Imm15_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00003fff)) << 37) |
+ (((tile_bundle_bits)(n & 0x00004000)) << 44);
+}
+
+static __inline tile_bundle_bits
+create_MMEnd_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 18);
+}
+
+static __inline tile_bundle_bits
+create_MMEnd_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_MMStart_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 23);
+}
+
+static __inline tile_bundle_bits
+create_MMStart_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tile_bundle_bits
+create_MT_Imm15_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tile_bundle_bits)(n & 0x00003fc0)) << 37) |
+ (((tile_bundle_bits)(n & 0x00004000)) << 44);
+}
+
+static __inline tile_bundle_bits
+create_Mode(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1)) << 63);
+}
+
+static __inline tile_bundle_bits
+create_NoRegOpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 10);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7) << 28);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 59);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 27);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 59);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7)) << 56);
+}
+
+static __inline tile_bundle_bits
+create_RROpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 4);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1ff) << 18);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1ff)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 18);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_RouteOpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_S_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1) << 27);
+}
+
+static __inline tile_bundle_bits
+create_S_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1)) << 58);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 6);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 6);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x00000001) << 26) |
+ (((tile_bundle_bits)(n & 0x0000003e)) << 50);
+}
+
+static __inline tile_bundle_bits
+create_SrcBDest_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 20);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Src_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 0);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 17);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3ff)) << 48);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7) << 17);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7)) << 48);
+}
+
+
+typedef unsigned short tile_sn_instruction_bits;
+
+
+typedef enum
+{
+ TILE_PIPELINE_X0,
+ TILE_PIPELINE_X1,
+ TILE_PIPELINE_Y0,
+ TILE_PIPELINE_Y1,
+ TILE_PIPELINE_Y2,
+} tile_pipeline;
+
+#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1)
+
+typedef enum
+{
+ TILE_OP_TYPE_REGISTER,
+ TILE_OP_TYPE_IMMEDIATE,
+ TILE_OP_TYPE_ADDRESS,
+ TILE_OP_TYPE_SPR
+} tile_operand_type;
+
+/* This is the bit that determines if a bundle is in the Y encoding. */
+#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63)
+
+enum
+{
+ /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
+ TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+
+ /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
+ TILE_NUM_PIPELINE_ENCODINGS = 5,
+
+ /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */
+ TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+
+ /* Instructions take this many bytes. */
+ TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES,
+
+ /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+
+ /* Bundles should be aligned modulo this number of bytes. */
+ TILE_BUNDLE_ALIGNMENT_IN_BYTES =
+ (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
+
+ /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */
+ TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1,
+
+ /* Static network instructions take this many bytes. */
+ TILE_SN_INSTRUCTION_SIZE_IN_BYTES =
+ (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES),
+
+ /* Number of registers (some are magic, such as network I/O). */
+ TILE_NUM_REGISTERS = 64,
+
+ /* Number of static network registers. */
+ TILE_NUM_SN_REGISTERS = 4
+};
+
+
+struct tile_operand
+{
+ /* Is this operand a register, immediate or address? */
+ tile_operand_type type;
+
+ /* The default relocation type for this operand. */
+ signed int default_reloc : 16;
+
+ /* How many bits is this value? (used for range checking) */
+ unsigned int num_bits : 5;
+
+ /* Is the value signed? (used for range checking) */
+ unsigned int is_signed : 1;
+
+ /* Is this operand a source register? */
+ unsigned int is_src_reg : 1;
+
+ /* Is this operand written? (i.e. is it a destination register) */
+ unsigned int is_dest_reg : 1;
+
+ /* Is this operand PC-relative? */
+ unsigned int is_pc_relative : 1;
+
+ /* By how many bits do we right shift the value before inserting? */
+ unsigned int rightshift : 2;
+
+ /* Return the bits for this operand to be ORed into an existing bundle. */
+ tile_bundle_bits (*insert) (int op);
+
+ /* Extract this operand and return it. */
+ unsigned int (*extract) (tile_bundle_bits bundle);
+};
+
+
+extern const struct tile_operand tile_operands[];
+
+/* One finite-state machine per pipe for rapid instruction decoding. */
+extern const unsigned short * const
+tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS];
+
+
+struct tile_opcode
+{
+ /* The opcode mnemonic, e.g. "add" */
+ const char *name;
+
+ /* The enum value for this mnemonic. */
+ tile_mnemonic mnemonic;
+
+ /* A bit mask of which of the five pipes this instruction
+ is compatible with:
+ X0 0x01
+ X1 0x02
+ Y0 0x04
+ Y1 0x08
+ Y2 0x10 */
+ unsigned char pipes;
+
+ /* How many operands are there? */
+ unsigned char num_operands;
+
+ /* Which register does this write implicitly, or TREG_ZERO if none? */
+ unsigned char implicitly_written_register;
+
+ /* Can this be bundled with other instructions (almost always true). */
+ unsigned char can_bundle;
+
+ /* The description of the operands. Each of these is an
+ * index into the tile_operands[] table. */
+ unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS];
+
+ /* A mask of which bits have predefined values for each pipeline.
+ * This is useful for disassembly. */
+ tile_bundle_bits fixed_bit_masks[TILE_NUM_PIPELINE_ENCODINGS];
+
+ /* For each bit set in fixed_bit_masks, what the value is for this
+ * instruction. */
+ tile_bundle_bits fixed_bit_values[TILE_NUM_PIPELINE_ENCODINGS];
+};
+
+extern const struct tile_opcode tile_opcodes[];
+
+struct tile_sn_opcode
+{
+ /* The opcode mnemonic, e.g. "add" */
+ const char *name;
+
+ /* The enum value for this mnemonic. */
+ tile_sn_mnemonic mnemonic;
+
+ /* How many operands are there? */
+ unsigned char num_operands;
+
+ /* The description of the operands. Each of these is an
+ * index into the tile_operands[] table. */
+ unsigned char operands[TILE_SN_MAX_OPERANDS];
+
+ /* A mask of which bits have predefined values.
+ * This is useful for disassembly. */
+ tile_sn_instruction_bits fixed_bit_mask;
+
+ /* For each bit set in fixed_bit_masks, what its value is. */
+ tile_sn_instruction_bits fixed_bit_values;
+};
+
+extern const struct tile_sn_opcode tile_sn_opcodes[];
+
+/* Used for non-textual disassembly into structs. */
+struct tile_decoded_instruction
+{
+ const struct tile_opcode *opcode;
+ const struct tile_operand *operands[TILE_MAX_OPERANDS];
+ int operand_values[TILE_MAX_OPERANDS];
+};
+
+
+/* Disassemble a bundle into a struct for machine processing. */
+extern int parse_insn_tile(tile_bundle_bits bits,
+ unsigned int pc,
+ struct tile_decoded_instruction
+ decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+
+
+/* Canonical names of all the registers. */
+/* ISSUE: This table lives in "tile-dis.c" */
+extern const char * const tile_register_names[];
+
+/* Descriptor for a special-purpose register. */
+struct tile_spr
+{
+ /* The number */
+ int number;
+
+ /* The name */
+ const char *name;
+};
+
+/* List of all the SPRs; ordered by increasing number. */
+extern const struct tile_spr tile_sprs[];
+
+/* Number of special-purpose registers. */
+extern const int tile_num_sprs;
+
+extern const char *
+get_tile_spr_name (int num);
+
+#endif /* opcode_tile_h */
diff --git a/arch/tile/include/asm/opcode-tile_64.h b/arch/tile/include/asm/opcode-tile_64.h
new file mode 100644
index 000000000000..90f8dd372531
--- /dev/null
+++ b/arch/tile/include/asm/opcode-tile_64.h
@@ -0,0 +1,1597 @@
+/* tile.h -- Header file for TILE opcode table
+ Copyright (C) 2005 Free Software Foundation, Inc.
+ Contributed by Tilera Corp. */
+
+#ifndef opcode_tile_h
+#define opcode_tile_h
+
+typedef unsigned long long tile_bundle_bits;
+
+
+enum
+{
+ TILE_MAX_OPERANDS = 5 /* mm */
+};
+
+typedef enum
+{
+ TILE_OPC_BPT,
+ TILE_OPC_INFO,
+ TILE_OPC_INFOL,
+ TILE_OPC_J,
+ TILE_OPC_JAL,
+ TILE_OPC_MOVE,
+ TILE_OPC_MOVE_SN,
+ TILE_OPC_MOVEI,
+ TILE_OPC_MOVEI_SN,
+ TILE_OPC_MOVELI,
+ TILE_OPC_MOVELI_SN,
+ TILE_OPC_MOVELIS,
+ TILE_OPC_PREFETCH,
+ TILE_OPC_ADD,
+ TILE_OPC_ADD_SN,
+ TILE_OPC_ADDB,
+ TILE_OPC_ADDB_SN,
+ TILE_OPC_ADDBS_U,
+ TILE_OPC_ADDBS_U_SN,
+ TILE_OPC_ADDH,
+ TILE_OPC_ADDH_SN,
+ TILE_OPC_ADDHS,
+ TILE_OPC_ADDHS_SN,
+ TILE_OPC_ADDI,
+ TILE_OPC_ADDI_SN,
+ TILE_OPC_ADDIB,
+ TILE_OPC_ADDIB_SN,
+ TILE_OPC_ADDIH,
+ TILE_OPC_ADDIH_SN,
+ TILE_OPC_ADDLI,
+ TILE_OPC_ADDLI_SN,
+ TILE_OPC_ADDLIS,
+ TILE_OPC_ADDS,
+ TILE_OPC_ADDS_SN,
+ TILE_OPC_ADIFFB_U,
+ TILE_OPC_ADIFFB_U_SN,
+ TILE_OPC_ADIFFH,
+ TILE_OPC_ADIFFH_SN,
+ TILE_OPC_AND,
+ TILE_OPC_AND_SN,
+ TILE_OPC_ANDI,
+ TILE_OPC_ANDI_SN,
+ TILE_OPC_AULI,
+ TILE_OPC_AVGB_U,
+ TILE_OPC_AVGB_U_SN,
+ TILE_OPC_AVGH,
+ TILE_OPC_AVGH_SN,
+ TILE_OPC_BBNS,
+ TILE_OPC_BBNS_SN,
+ TILE_OPC_BBNST,
+ TILE_OPC_BBNST_SN,
+ TILE_OPC_BBS,
+ TILE_OPC_BBS_SN,
+ TILE_OPC_BBST,
+ TILE_OPC_BBST_SN,
+ TILE_OPC_BGEZ,
+ TILE_OPC_BGEZ_SN,
+ TILE_OPC_BGEZT,
+ TILE_OPC_BGEZT_SN,
+ TILE_OPC_BGZ,
+ TILE_OPC_BGZ_SN,
+ TILE_OPC_BGZT,
+ TILE_OPC_BGZT_SN,
+ TILE_OPC_BITX,
+ TILE_OPC_BITX_SN,
+ TILE_OPC_BLEZ,
+ TILE_OPC_BLEZ_SN,
+ TILE_OPC_BLEZT,
+ TILE_OPC_BLEZT_SN,
+ TILE_OPC_BLZ,
+ TILE_OPC_BLZ_SN,
+ TILE_OPC_BLZT,
+ TILE_OPC_BLZT_SN,
+ TILE_OPC_BNZ,
+ TILE_OPC_BNZ_SN,
+ TILE_OPC_BNZT,
+ TILE_OPC_BNZT_SN,
+ TILE_OPC_BYTEX,
+ TILE_OPC_BYTEX_SN,
+ TILE_OPC_BZ,
+ TILE_OPC_BZ_SN,
+ TILE_OPC_BZT,
+ TILE_OPC_BZT_SN,
+ TILE_OPC_CLZ,
+ TILE_OPC_CLZ_SN,
+ TILE_OPC_CRC32_32,
+ TILE_OPC_CRC32_32_SN,
+ TILE_OPC_CRC32_8,
+ TILE_OPC_CRC32_8_SN,
+ TILE_OPC_CTZ,
+ TILE_OPC_CTZ_SN,
+ TILE_OPC_DRAIN,
+ TILE_OPC_DTLBPR,
+ TILE_OPC_DWORD_ALIGN,
+ TILE_OPC_DWORD_ALIGN_SN,
+ TILE_OPC_FINV,
+ TILE_OPC_FLUSH,
+ TILE_OPC_FNOP,
+ TILE_OPC_ICOH,
+ TILE_OPC_ILL,
+ TILE_OPC_INTHB,
+ TILE_OPC_INTHB_SN,
+ TILE_OPC_INTHH,
+ TILE_OPC_INTHH_SN,
+ TILE_OPC_INTLB,
+ TILE_OPC_INTLB_SN,
+ TILE_OPC_INTLH,
+ TILE_OPC_INTLH_SN,
+ TILE_OPC_INV,
+ TILE_OPC_IRET,
+ TILE_OPC_JALB,
+ TILE_OPC_JALF,
+ TILE_OPC_JALR,
+ TILE_OPC_JALRP,
+ TILE_OPC_JB,
+ TILE_OPC_JF,
+ TILE_OPC_JR,
+ TILE_OPC_JRP,
+ TILE_OPC_LB,
+ TILE_OPC_LB_SN,
+ TILE_OPC_LB_U,
+ TILE_OPC_LB_U_SN,
+ TILE_OPC_LBADD,
+ TILE_OPC_LBADD_SN,
+ TILE_OPC_LBADD_U,
+ TILE_OPC_LBADD_U_SN,
+ TILE_OPC_LH,
+ TILE_OPC_LH_SN,
+ TILE_OPC_LH_U,
+ TILE_OPC_LH_U_SN,
+ TILE_OPC_LHADD,
+ TILE_OPC_LHADD_SN,
+ TILE_OPC_LHADD_U,
+ TILE_OPC_LHADD_U_SN,
+ TILE_OPC_LNK,
+ TILE_OPC_LNK_SN,
+ TILE_OPC_LW,
+ TILE_OPC_LW_SN,
+ TILE_OPC_LW_NA,
+ TILE_OPC_LW_NA_SN,
+ TILE_OPC_LWADD,
+ TILE_OPC_LWADD_SN,
+ TILE_OPC_LWADD_NA,
+ TILE_OPC_LWADD_NA_SN,
+ TILE_OPC_MAXB_U,
+ TILE_OPC_MAXB_U_SN,
+ TILE_OPC_MAXH,
+ TILE_OPC_MAXH_SN,
+ TILE_OPC_MAXIB_U,
+ TILE_OPC_MAXIB_U_SN,
+ TILE_OPC_MAXIH,
+ TILE_OPC_MAXIH_SN,
+ TILE_OPC_MF,
+ TILE_OPC_MFSPR,
+ TILE_OPC_MINB_U,
+ TILE_OPC_MINB_U_SN,
+ TILE_OPC_MINH,
+ TILE_OPC_MINH_SN,
+ TILE_OPC_MINIB_U,
+ TILE_OPC_MINIB_U_SN,
+ TILE_OPC_MINIH,
+ TILE_OPC_MINIH_SN,
+ TILE_OPC_MM,
+ TILE_OPC_MNZ,
+ TILE_OPC_MNZ_SN,
+ TILE_OPC_MNZB,
+ TILE_OPC_MNZB_SN,
+ TILE_OPC_MNZH,
+ TILE_OPC_MNZH_SN,
+ TILE_OPC_MTSPR,
+ TILE_OPC_MULHH_SS,
+ TILE_OPC_MULHH_SS_SN,
+ TILE_OPC_MULHH_SU,
+ TILE_OPC_MULHH_SU_SN,
+ TILE_OPC_MULHH_UU,
+ TILE_OPC_MULHH_UU_SN,
+ TILE_OPC_MULHHA_SS,
+ TILE_OPC_MULHHA_SS_SN,
+ TILE_OPC_MULHHA_SU,
+ TILE_OPC_MULHHA_SU_SN,
+ TILE_OPC_MULHHA_UU,
+ TILE_OPC_MULHHA_UU_SN,
+ TILE_OPC_MULHHSA_UU,
+ TILE_OPC_MULHHSA_UU_SN,
+ TILE_OPC_MULHL_SS,
+ TILE_OPC_MULHL_SS_SN,
+ TILE_OPC_MULHL_SU,
+ TILE_OPC_MULHL_SU_SN,
+ TILE_OPC_MULHL_US,
+ TILE_OPC_MULHL_US_SN,
+ TILE_OPC_MULHL_UU,
+ TILE_OPC_MULHL_UU_SN,
+ TILE_OPC_MULHLA_SS,
+ TILE_OPC_MULHLA_SS_SN,
+ TILE_OPC_MULHLA_SU,
+ TILE_OPC_MULHLA_SU_SN,
+ TILE_OPC_MULHLA_US,
+ TILE_OPC_MULHLA_US_SN,
+ TILE_OPC_MULHLA_UU,
+ TILE_OPC_MULHLA_UU_SN,
+ TILE_OPC_MULHLSA_UU,
+ TILE_OPC_MULHLSA_UU_SN,
+ TILE_OPC_MULLL_SS,
+ TILE_OPC_MULLL_SS_SN,
+ TILE_OPC_MULLL_SU,
+ TILE_OPC_MULLL_SU_SN,
+ TILE_OPC_MULLL_UU,
+ TILE_OPC_MULLL_UU_SN,
+ TILE_OPC_MULLLA_SS,
+ TILE_OPC_MULLLA_SS_SN,
+ TILE_OPC_MULLLA_SU,
+ TILE_OPC_MULLLA_SU_SN,
+ TILE_OPC_MULLLA_UU,
+ TILE_OPC_MULLLA_UU_SN,
+ TILE_OPC_MULLLSA_UU,
+ TILE_OPC_MULLLSA_UU_SN,
+ TILE_OPC_MVNZ,
+ TILE_OPC_MVNZ_SN,
+ TILE_OPC_MVZ,
+ TILE_OPC_MVZ_SN,
+ TILE_OPC_MZ,
+ TILE_OPC_MZ_SN,
+ TILE_OPC_MZB,
+ TILE_OPC_MZB_SN,
+ TILE_OPC_MZH,
+ TILE_OPC_MZH_SN,
+ TILE_OPC_NAP,
+ TILE_OPC_NOP,
+ TILE_OPC_NOR,
+ TILE_OPC_NOR_SN,
+ TILE_OPC_OR,
+ TILE_OPC_OR_SN,
+ TILE_OPC_ORI,
+ TILE_OPC_ORI_SN,
+ TILE_OPC_PACKBS_U,
+ TILE_OPC_PACKBS_U_SN,
+ TILE_OPC_PACKHB,
+ TILE_OPC_PACKHB_SN,
+ TILE_OPC_PACKHS,
+ TILE_OPC_PACKHS_SN,
+ TILE_OPC_PACKLB,
+ TILE_OPC_PACKLB_SN,
+ TILE_OPC_PCNT,
+ TILE_OPC_PCNT_SN,
+ TILE_OPC_RL,
+ TILE_OPC_RL_SN,
+ TILE_OPC_RLI,
+ TILE_OPC_RLI_SN,
+ TILE_OPC_S1A,
+ TILE_OPC_S1A_SN,
+ TILE_OPC_S2A,
+ TILE_OPC_S2A_SN,
+ TILE_OPC_S3A,
+ TILE_OPC_S3A_SN,
+ TILE_OPC_SADAB_U,
+ TILE_OPC_SADAB_U_SN,
+ TILE_OPC_SADAH,
+ TILE_OPC_SADAH_SN,
+ TILE_OPC_SADAH_U,
+ TILE_OPC_SADAH_U_SN,
+ TILE_OPC_SADB_U,
+ TILE_OPC_SADB_U_SN,
+ TILE_OPC_SADH,
+ TILE_OPC_SADH_SN,
+ TILE_OPC_SADH_U,
+ TILE_OPC_SADH_U_SN,
+ TILE_OPC_SB,
+ TILE_OPC_SBADD,
+ TILE_OPC_SEQ,
+ TILE_OPC_SEQ_SN,
+ TILE_OPC_SEQB,
+ TILE_OPC_SEQB_SN,
+ TILE_OPC_SEQH,
+ TILE_OPC_SEQH_SN,
+ TILE_OPC_SEQI,
+ TILE_OPC_SEQI_SN,
+ TILE_OPC_SEQIB,
+ TILE_OPC_SEQIB_SN,
+ TILE_OPC_SEQIH,
+ TILE_OPC_SEQIH_SN,
+ TILE_OPC_SH,
+ TILE_OPC_SHADD,
+ TILE_OPC_SHL,
+ TILE_OPC_SHL_SN,
+ TILE_OPC_SHLB,
+ TILE_OPC_SHLB_SN,
+ TILE_OPC_SHLH,
+ TILE_OPC_SHLH_SN,
+ TILE_OPC_SHLI,
+ TILE_OPC_SHLI_SN,
+ TILE_OPC_SHLIB,
+ TILE_OPC_SHLIB_SN,
+ TILE_OPC_SHLIH,
+ TILE_OPC_SHLIH_SN,
+ TILE_OPC_SHR,
+ TILE_OPC_SHR_SN,
+ TILE_OPC_SHRB,
+ TILE_OPC_SHRB_SN,
+ TILE_OPC_SHRH,
+ TILE_OPC_SHRH_SN,
+ TILE_OPC_SHRI,
+ TILE_OPC_SHRI_SN,
+ TILE_OPC_SHRIB,
+ TILE_OPC_SHRIB_SN,
+ TILE_OPC_SHRIH,
+ TILE_OPC_SHRIH_SN,
+ TILE_OPC_SLT,
+ TILE_OPC_SLT_SN,
+ TILE_OPC_SLT_U,
+ TILE_OPC_SLT_U_SN,
+ TILE_OPC_SLTB,
+ TILE_OPC_SLTB_SN,
+ TILE_OPC_SLTB_U,
+ TILE_OPC_SLTB_U_SN,
+ TILE_OPC_SLTE,
+ TILE_OPC_SLTE_SN,
+ TILE_OPC_SLTE_U,
+ TILE_OPC_SLTE_U_SN,
+ TILE_OPC_SLTEB,
+ TILE_OPC_SLTEB_SN,
+ TILE_OPC_SLTEB_U,
+ TILE_OPC_SLTEB_U_SN,
+ TILE_OPC_SLTEH,
+ TILE_OPC_SLTEH_SN,
+ TILE_OPC_SLTEH_U,
+ TILE_OPC_SLTEH_U_SN,
+ TILE_OPC_SLTH,
+ TILE_OPC_SLTH_SN,
+ TILE_OPC_SLTH_U,
+ TILE_OPC_SLTH_U_SN,
+ TILE_OPC_SLTI,
+ TILE_OPC_SLTI_SN,
+ TILE_OPC_SLTI_U,
+ TILE_OPC_SLTI_U_SN,
+ TILE_OPC_SLTIB,
+ TILE_OPC_SLTIB_SN,
+ TILE_OPC_SLTIB_U,
+ TILE_OPC_SLTIB_U_SN,
+ TILE_OPC_SLTIH,
+ TILE_OPC_SLTIH_SN,
+ TILE_OPC_SLTIH_U,
+ TILE_OPC_SLTIH_U_SN,
+ TILE_OPC_SNE,
+ TILE_OPC_SNE_SN,
+ TILE_OPC_SNEB,
+ TILE_OPC_SNEB_SN,
+ TILE_OPC_SNEH,
+ TILE_OPC_SNEH_SN,
+ TILE_OPC_SRA,
+ TILE_OPC_SRA_SN,
+ TILE_OPC_SRAB,
+ TILE_OPC_SRAB_SN,
+ TILE_OPC_SRAH,
+ TILE_OPC_SRAH_SN,
+ TILE_OPC_SRAI,
+ TILE_OPC_SRAI_SN,
+ TILE_OPC_SRAIB,
+ TILE_OPC_SRAIB_SN,
+ TILE_OPC_SRAIH,
+ TILE_OPC_SRAIH_SN,
+ TILE_OPC_SUB,
+ TILE_OPC_SUB_SN,
+ TILE_OPC_SUBB,
+ TILE_OPC_SUBB_SN,
+ TILE_OPC_SUBBS_U,
+ TILE_OPC_SUBBS_U_SN,
+ TILE_OPC_SUBH,
+ TILE_OPC_SUBH_SN,
+ TILE_OPC_SUBHS,
+ TILE_OPC_SUBHS_SN,
+ TILE_OPC_SUBS,
+ TILE_OPC_SUBS_SN,
+ TILE_OPC_SW,
+ TILE_OPC_SWADD,
+ TILE_OPC_SWINT0,
+ TILE_OPC_SWINT1,
+ TILE_OPC_SWINT2,
+ TILE_OPC_SWINT3,
+ TILE_OPC_TBLIDXB0,
+ TILE_OPC_TBLIDXB0_SN,
+ TILE_OPC_TBLIDXB1,
+ TILE_OPC_TBLIDXB1_SN,
+ TILE_OPC_TBLIDXB2,
+ TILE_OPC_TBLIDXB2_SN,
+ TILE_OPC_TBLIDXB3,
+ TILE_OPC_TBLIDXB3_SN,
+ TILE_OPC_TNS,
+ TILE_OPC_TNS_SN,
+ TILE_OPC_WH64,
+ TILE_OPC_XOR,
+ TILE_OPC_XOR_SN,
+ TILE_OPC_XORI,
+ TILE_OPC_XORI_SN,
+ TILE_OPC_NONE
+} tile_mnemonic;
+
+/* 64-bit pattern for a { bpt ; nop } bundle. */
+#define TILE_BPT_BUNDLE 0x400b3cae70166000ULL
+
+
+#define TILE_ELF_MACHINE_CODE EM_TILEPRO
+
+#define TILE_ELF_NAME "elf32-tilepro"
+
+enum
+{
+ TILE_SN_MAX_OPERANDS = 6 /* route */
+};
+
+typedef enum
+{
+ TILE_SN_OPC_BZ,
+ TILE_SN_OPC_BNZ,
+ TILE_SN_OPC_JRR,
+ TILE_SN_OPC_FNOP,
+ TILE_SN_OPC_BLZ,
+ TILE_SN_OPC_NOP,
+ TILE_SN_OPC_MOVEI,
+ TILE_SN_OPC_MOVE,
+ TILE_SN_OPC_BGEZ,
+ TILE_SN_OPC_JR,
+ TILE_SN_OPC_BLEZ,
+ TILE_SN_OPC_BBNS,
+ TILE_SN_OPC_JALRR,
+ TILE_SN_OPC_BPT,
+ TILE_SN_OPC_JALR,
+ TILE_SN_OPC_SHR1,
+ TILE_SN_OPC_BGZ,
+ TILE_SN_OPC_BBS,
+ TILE_SN_OPC_SHL8II,
+ TILE_SN_OPC_ADDI,
+ TILE_SN_OPC_HALT,
+ TILE_SN_OPC_ROUTE,
+ TILE_SN_OPC_NONE
+} tile_sn_mnemonic;
+
+extern const unsigned char tile_sn_route_encode[6 * 6 * 6];
+extern const signed char tile_sn_route_decode[256][3];
+extern const char tile_sn_direction_names[6][5];
+extern const signed char tile_sn_dest_map[6][6];
+
+
+static __inline unsigned int
+get_BrOff_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_BrOff_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000);
+}
+
+static __inline unsigned int
+get_BrType_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0xf);
+}
+
+static __inline unsigned int
+get_Dest_Imm8_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x0000003f) |
+ (((unsigned int)(n >> 43)) & 0x000000c0);
+}
+
+static __inline unsigned int
+get_Dest_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 2)) & 0x3);
+}
+
+static __inline unsigned int
+get_Dest_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Dest_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Imm16_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm16_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xffff);
+}
+
+static __inline unsigned int
+get_Imm8_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0xff);
+}
+
+static __inline unsigned int
+get_Imm8_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0xff);
+}
+
+static __inline unsigned int
+get_ImmOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 20)) & 0x7f);
+}
+
+static __inline unsigned int
+get_ImmOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 51)) & 0x7f);
+}
+
+static __inline unsigned int
+get_ImmRROpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 8)) & 0x3);
+}
+
+static __inline unsigned int
+get_JOffLong_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000) |
+ (((unsigned int)(n >> 14)) & 0x001e0000) |
+ (((unsigned int)(n >> 16)) & 0x07e00000) |
+ (((unsigned int)(n >> 31)) & 0x18000000);
+}
+
+static __inline unsigned int
+get_JOff_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x00007fff) |
+ (((unsigned int)(n >> 20)) & 0x00018000) |
+ (((unsigned int)(n >> 14)) & 0x001e0000) |
+ (((unsigned int)(n >> 16)) & 0x07e00000) |
+ (((unsigned int)(n >> 31)) & 0x08000000);
+}
+
+static __inline unsigned int
+get_MF_Imm15_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x00003fff) |
+ (((unsigned int)(n >> 44)) & 0x00004000);
+}
+
+static __inline unsigned int
+get_MMEnd_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMEnd_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMStart_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 23)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MMStart_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 54)) & 0x1f);
+}
+
+static __inline unsigned int
+get_MT_Imm15_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 31)) & 0x0000003f) |
+ (((unsigned int)(n >> 37)) & 0x00003fc0) |
+ (((unsigned int)(n >> 44)) & 0x00004000);
+}
+
+static __inline unsigned int
+get_Mode(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 63)) & 0x1);
+}
+
+static __inline unsigned int
+get_NoRegOpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 10)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Opcode_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 28)) & 0x7);
+}
+
+static __inline unsigned int
+get_Opcode_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 59)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 27)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 59)) & 0xf);
+}
+
+static __inline unsigned int
+get_Opcode_Y2(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 56)) & 0x7);
+}
+
+static __inline unsigned int
+get_RROpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 4)) & 0xf);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x1ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x1ff);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 18)) & 0x3);
+}
+
+static __inline unsigned int
+get_RRROpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 49)) & 0x3);
+}
+
+static __inline unsigned int
+get_RouteOpcodeExtension_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_S_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 27)) & 0x1);
+}
+
+static __inline unsigned int
+get_S_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 58)) & 0x1);
+}
+
+static __inline unsigned int
+get_ShAmt_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_ShAmt_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_SrcA_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 6)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 37)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcA_Y2(tile_bundle_bits n)
+{
+ return (((n >> 26)) & 0x00000001) |
+ (((unsigned int)(n >> 50)) & 0x0000003e);
+}
+
+static __inline unsigned int
+get_SrcBDest_Y2(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 20)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x3f);
+}
+
+static __inline unsigned int
+get_SrcB_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x3f);
+}
+
+static __inline unsigned int
+get_Src_SN(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 0)) & 0x3);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 12)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnOpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 43)) & 0x1f);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_X0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 17)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_X1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 48)) & 0x3ff);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_Y0(tile_bundle_bits num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((n >> 17)) & 0x7);
+}
+
+static __inline unsigned int
+get_UnShOpcodeExtension_Y1(tile_bundle_bits n)
+{
+ return (((unsigned int)(n >> 48)) & 0x7);
+}
+
+
+static __inline int
+sign_extend(int n, int num_bits)
+{
+ int shift = (int)(sizeof(int) * 8 - num_bits);
+ return (n << shift) >> shift;
+}
+
+
+
+static __inline tile_bundle_bits
+create_BrOff_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_BrOff_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20);
+}
+
+static __inline tile_bundle_bits
+create_BrType_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Imm8_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tile_bundle_bits)(n & 0x000000c0)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Dest_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 2);
+}
+
+static __inline tile_bundle_bits
+create_Dest_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Dest_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Dest_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_Imm16_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xffff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm16_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xffff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xff) << 12);
+}
+
+static __inline tile_bundle_bits
+create_Imm8_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xff)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_ImmOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7f) << 20);
+}
+
+static __inline tile_bundle_bits
+create_ImmOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7f)) << 51);
+}
+
+static __inline tile_bundle_bits
+create_ImmRROpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 8);
+}
+
+static __inline tile_bundle_bits
+create_JOffLong_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20) |
+ (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
+ (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
+ (((tile_bundle_bits)(n & 0x18000000)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_JOff_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00007fff)) << 43) |
+ (((tile_bundle_bits)(n & 0x00018000)) << 20) |
+ (((tile_bundle_bits)(n & 0x001e0000)) << 14) |
+ (((tile_bundle_bits)(n & 0x07e00000)) << 16) |
+ (((tile_bundle_bits)(n & 0x08000000)) << 31);
+}
+
+static __inline tile_bundle_bits
+create_MF_Imm15_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x00003fff)) << 37) |
+ (((tile_bundle_bits)(n & 0x00004000)) << 44);
+}
+
+static __inline tile_bundle_bits
+create_MMEnd_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 18);
+}
+
+static __inline tile_bundle_bits
+create_MMEnd_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_MMStart_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 23);
+}
+
+static __inline tile_bundle_bits
+create_MMStart_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 54);
+}
+
+static __inline tile_bundle_bits
+create_MT_Imm15_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x0000003f)) << 31) |
+ (((tile_bundle_bits)(n & 0x00003fc0)) << 37) |
+ (((tile_bundle_bits)(n & 0x00004000)) << 44);
+}
+
+static __inline tile_bundle_bits
+create_Mode(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1)) << 63);
+}
+
+static __inline tile_bundle_bits
+create_NoRegOpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 0);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 10);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7) << 28);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 59);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 27);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0xf)) << 59);
+}
+
+static __inline tile_bundle_bits
+create_Opcode_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7)) << 56);
+}
+
+static __inline tile_bundle_bits
+create_RROpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0xf) << 4);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1ff) << 18);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1ff)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 18);
+}
+
+static __inline tile_bundle_bits
+create_RRROpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3)) << 49);
+}
+
+static __inline tile_bundle_bits
+create_RouteOpcodeExtension_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 0);
+}
+
+static __inline tile_bundle_bits
+create_S_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1) << 27);
+}
+
+static __inline tile_bundle_bits
+create_S_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1)) << 58);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_ShAmt_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 6);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 6);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 37);
+}
+
+static __inline tile_bundle_bits
+create_SrcA_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x00000001) << 26) |
+ (((tile_bundle_bits)(n & 0x0000003e)) << 50);
+}
+
+static __inline tile_bundle_bits
+create_SrcBDest_Y2(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 20);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_SrcB_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_Src_SN(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3) << 0);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x1f) << 12);
+}
+
+static __inline tile_bundle_bits
+create_UnOpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x1f)) << 43);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_X0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x3ff) << 17);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_X1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x3ff)) << 48);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_Y0(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return ((n & 0x7) << 17);
+}
+
+static __inline tile_bundle_bits
+create_UnShOpcodeExtension_Y1(int num)
+{
+ const unsigned int n = (unsigned int)num;
+ return (((tile_bundle_bits)(n & 0x7)) << 48);
+}
+
+
+typedef unsigned short tile_sn_instruction_bits;
+
+
+typedef enum
+{
+ TILE_PIPELINE_X0,
+ TILE_PIPELINE_X1,
+ TILE_PIPELINE_Y0,
+ TILE_PIPELINE_Y1,
+ TILE_PIPELINE_Y2,
+} tile_pipeline;
+
+#define tile_is_x_pipeline(p) ((int)(p) <= (int)TILE_PIPELINE_X1)
+
+typedef enum
+{
+ TILE_OP_TYPE_REGISTER,
+ TILE_OP_TYPE_IMMEDIATE,
+ TILE_OP_TYPE_ADDRESS,
+ TILE_OP_TYPE_SPR
+} tile_operand_type;
+
+/* This is the bit that determines if a bundle is in the Y encoding. */
+#define TILE_BUNDLE_Y_ENCODING_MASK ((tile_bundle_bits)1 << 63)
+
+enum
+{
+ /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */
+ TILE_MAX_INSTRUCTIONS_PER_BUNDLE = 3,
+
+ /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */
+ TILE_NUM_PIPELINE_ENCODINGS = 5,
+
+ /* Log base 2 of TILE_BUNDLE_SIZE_IN_BYTES. */
+ TILE_LOG2_BUNDLE_SIZE_IN_BYTES = 3,
+
+ /* Instructions take this many bytes. */
+ TILE_BUNDLE_SIZE_IN_BYTES = 1 << TILE_LOG2_BUNDLE_SIZE_IN_BYTES,
+
+ /* Log base 2 of TILE_BUNDLE_ALIGNMENT_IN_BYTES. */
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3,
+
+ /* Bundles should be aligned modulo this number of bytes. */
+ TILE_BUNDLE_ALIGNMENT_IN_BYTES =
+ (1 << TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES),
+
+ /* Log base 2 of TILE_SN_INSTRUCTION_SIZE_IN_BYTES. */
+ TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1,
+
+ /* Static network instructions take this many bytes. */
+ TILE_SN_INSTRUCTION_SIZE_IN_BYTES =
+ (1 << TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES),
+
+ /* Number of registers (some are magic, such as network I/O). */
+ TILE_NUM_REGISTERS = 64,
+
+ /* Number of static network registers. */
+ TILE_NUM_SN_REGISTERS = 4
+};
+
+
+struct tile_operand
+{
+ /* Is this operand a register, immediate or address? */
+ tile_operand_type type;
+
+ /* The default relocation type for this operand. */
+ signed int default_reloc : 16;
+
+ /* How many bits is this value? (used for range checking) */
+ unsigned int num_bits : 5;
+
+ /* Is the value signed? (used for range checking) */
+ unsigned int is_signed : 1;
+
+ /* Is this operand a source register? */
+ unsigned int is_src_reg : 1;
+
+ /* Is this operand written? (i.e. is it a destination register) */
+ unsigned int is_dest_reg : 1;
+
+ /* Is this operand PC-relative? */
+ unsigned int is_pc_relative : 1;
+
+ /* By how many bits do we right shift the value before inserting? */
+ unsigned int rightshift : 2;
+
+ /* Return the bits for this operand to be ORed into an existing bundle. */
+ tile_bundle_bits (*insert) (int op);
+
+ /* Extract this operand and return it. */
+ unsigned int (*extract) (tile_bundle_bits bundle);
+};
+
+
+extern const struct tile_operand tile_operands[];
+
+/* One finite-state machine per pipe for rapid instruction decoding. */
+extern const unsigned short * const
+tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS];
+
+
+struct tile_opcode
+{
+ /* The opcode mnemonic, e.g. "add" */
+ const char *name;
+
+ /* The enum value for this mnemonic. */
+ tile_mnemonic mnemonic;
+
+ /* A bit mask of which of the five pipes this instruction
+ is compatible with:
+ X0 0x01
+ X1 0x02
+ Y0 0x04
+ Y1 0x08
+ Y2 0x10 */
+ unsigned char pipes;
+
+ /* How many operands are there? */
+ unsigned char num_operands;
+
+ /* Which register does this write implicitly, or TREG_ZERO if none? */
+ unsigned char implicitly_written_register;
+
+ /* Can this be bundled with other instructions (almost always true). */
+ unsigned char can_bundle;
+
+ /* The description of the operands. Each of these is an
+ * index into the tile_operands[] table. */
+ unsigned char operands[TILE_NUM_PIPELINE_ENCODINGS][TILE_MAX_OPERANDS];
+
+ /* A mask of which bits have predefined values for each pipeline.
+ * This is useful for disassembly. */
+ tile_bundle_bits fixed_bit_masks[TILE_NUM_PIPELINE_ENCODINGS];
+
+ /* For each bit set in fixed_bit_masks, what the value is for this
+ * instruction. */
+ tile_bundle_bits fixed_bit_values[TILE_NUM_PIPELINE_ENCODINGS];
+};
+
+extern const struct tile_opcode tile_opcodes[];
+
+struct tile_sn_opcode
+{
+ /* The opcode mnemonic, e.g. "add" */
+ const char *name;
+
+ /* The enum value for this mnemonic. */
+ tile_sn_mnemonic mnemonic;
+
+ /* How many operands are there? */
+ unsigned char num_operands;
+
+ /* The description of the operands. Each of these is an
+ * index into the tile_operands[] table. */
+ unsigned char operands[TILE_SN_MAX_OPERANDS];
+
+ /* A mask of which bits have predefined values.
+ * This is useful for disassembly. */
+ tile_sn_instruction_bits fixed_bit_mask;
+
+ /* For each bit set in fixed_bit_masks, what its value is. */
+ tile_sn_instruction_bits fixed_bit_values;
+};
+
+extern const struct tile_sn_opcode tile_sn_opcodes[];
+
+/* Used for non-textual disassembly into structs. */
+struct tile_decoded_instruction
+{
+ const struct tile_opcode *opcode;
+ const struct tile_operand *operands[TILE_MAX_OPERANDS];
+ int operand_values[TILE_MAX_OPERANDS];
+};
+
+
+/* Disassemble a bundle into a struct for machine processing. */
+extern int parse_insn_tile(tile_bundle_bits bits,
+ unsigned int pc,
+ struct tile_decoded_instruction
+ decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]);
+
+
+/* Canonical names of all the registers. */
+/* ISSUE: This table lives in "tile-dis.c" */
+extern const char * const tile_register_names[];
+
+/* Descriptor for a special-purpose register. */
+struct tile_spr
+{
+ /* The number */
+ int number;
+
+ /* The name */
+ const char *name;
+};
+
+/* List of all the SPRs; ordered by increasing number. */
+extern const struct tile_spr tile_sprs[];
+
+/* Number of special-purpose registers. */
+extern const int tile_num_sprs;
+
+extern const char *
+get_tile_spr_name (int num);
+
+#endif /* opcode_tile_h */
diff --git a/arch/tile/include/asm/opcode_constants.h b/arch/tile/include/asm/opcode_constants.h
new file mode 100644
index 000000000000..37a9f2958cb1
--- /dev/null
+++ b/arch/tile/include/asm/opcode_constants.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_OPCODE_CONSTANTS_H
+#define _ASM_TILE_OPCODE_CONSTANTS_H
+
+#include <arch/chip.h>
+
+#if CHIP_WORD_SIZE() == 64
+#include <asm/opcode_constants_64.h>
+#else
+#include <asm/opcode_constants_32.h>
+#endif
+
+#endif /* _ASM_TILE_OPCODE_CONSTANTS_H */
diff --git a/arch/tile/include/asm/opcode_constants_32.h b/arch/tile/include/asm/opcode_constants_32.h
new file mode 100644
index 000000000000..227d033b180c
--- /dev/null
+++ b/arch/tile/include/asm/opcode_constants_32.h
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+
+
+#ifndef _TILE_OPCODE_CONSTANTS_H
+#define _TILE_OPCODE_CONSTANTS_H
+enum
+{
+ ADDBS_U_SPECIAL_0_OPCODE_X0 = 98,
+ ADDBS_U_SPECIAL_0_OPCODE_X1 = 68,
+ ADDB_SPECIAL_0_OPCODE_X0 = 1,
+ ADDB_SPECIAL_0_OPCODE_X1 = 1,
+ ADDHS_SPECIAL_0_OPCODE_X0 = 99,
+ ADDHS_SPECIAL_0_OPCODE_X1 = 69,
+ ADDH_SPECIAL_0_OPCODE_X0 = 2,
+ ADDH_SPECIAL_0_OPCODE_X1 = 2,
+ ADDIB_IMM_0_OPCODE_X0 = 1,
+ ADDIB_IMM_0_OPCODE_X1 = 1,
+ ADDIH_IMM_0_OPCODE_X0 = 2,
+ ADDIH_IMM_0_OPCODE_X1 = 2,
+ ADDI_IMM_0_OPCODE_X0 = 3,
+ ADDI_IMM_0_OPCODE_X1 = 3,
+ ADDI_IMM_1_OPCODE_SN = 1,
+ ADDI_OPCODE_Y0 = 9,
+ ADDI_OPCODE_Y1 = 7,
+ ADDLIS_OPCODE_X0 = 1,
+ ADDLIS_OPCODE_X1 = 2,
+ ADDLI_OPCODE_X0 = 2,
+ ADDLI_OPCODE_X1 = 3,
+ ADDS_SPECIAL_0_OPCODE_X0 = 96,
+ ADDS_SPECIAL_0_OPCODE_X1 = 66,
+ ADD_SPECIAL_0_OPCODE_X0 = 3,
+ ADD_SPECIAL_0_OPCODE_X1 = 3,
+ ADD_SPECIAL_0_OPCODE_Y0 = 0,
+ ADD_SPECIAL_0_OPCODE_Y1 = 0,
+ ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4,
+ ADIFFH_SPECIAL_0_OPCODE_X0 = 5,
+ ANDI_IMM_0_OPCODE_X0 = 1,
+ ANDI_IMM_0_OPCODE_X1 = 4,
+ ANDI_OPCODE_Y0 = 10,
+ ANDI_OPCODE_Y1 = 8,
+ AND_SPECIAL_0_OPCODE_X0 = 6,
+ AND_SPECIAL_0_OPCODE_X1 = 4,
+ AND_SPECIAL_2_OPCODE_Y0 = 0,
+ AND_SPECIAL_2_OPCODE_Y1 = 0,
+ AULI_OPCODE_X0 = 3,
+ AULI_OPCODE_X1 = 4,
+ AVGB_U_SPECIAL_0_OPCODE_X0 = 7,
+ AVGH_SPECIAL_0_OPCODE_X0 = 8,
+ BBNST_BRANCH_OPCODE_X1 = 15,
+ BBNS_BRANCH_OPCODE_X1 = 14,
+ BBNS_OPCODE_SN = 63,
+ BBST_BRANCH_OPCODE_X1 = 13,
+ BBS_BRANCH_OPCODE_X1 = 12,
+ BBS_OPCODE_SN = 62,
+ BGEZT_BRANCH_OPCODE_X1 = 7,
+ BGEZ_BRANCH_OPCODE_X1 = 6,
+ BGEZ_OPCODE_SN = 61,
+ BGZT_BRANCH_OPCODE_X1 = 5,
+ BGZ_BRANCH_OPCODE_X1 = 4,
+ BGZ_OPCODE_SN = 58,
+ BITX_UN_0_SHUN_0_OPCODE_X0 = 1,
+ BITX_UN_0_SHUN_0_OPCODE_Y0 = 1,
+ BLEZT_BRANCH_OPCODE_X1 = 11,
+ BLEZ_BRANCH_OPCODE_X1 = 10,
+ BLEZ_OPCODE_SN = 59,
+ BLZT_BRANCH_OPCODE_X1 = 9,
+ BLZ_BRANCH_OPCODE_X1 = 8,
+ BLZ_OPCODE_SN = 60,
+ BNZT_BRANCH_OPCODE_X1 = 3,
+ BNZ_BRANCH_OPCODE_X1 = 2,
+ BNZ_OPCODE_SN = 57,
+ BPT_NOREG_RR_IMM_0_OPCODE_SN = 1,
+ BRANCH_OPCODE_X1 = 5,
+ BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2,
+ BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2,
+ BZT_BRANCH_OPCODE_X1 = 1,
+ BZ_BRANCH_OPCODE_X1 = 0,
+ BZ_OPCODE_SN = 56,
+ CLZ_UN_0_SHUN_0_OPCODE_X0 = 3,
+ CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3,
+ CRC32_32_SPECIAL_0_OPCODE_X0 = 9,
+ CRC32_8_SPECIAL_0_OPCODE_X0 = 10,
+ CTZ_UN_0_SHUN_0_OPCODE_X0 = 4,
+ CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4,
+ DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1,
+ DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2,
+ DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95,
+ FINV_UN_0_SHUN_0_OPCODE_X1 = 3,
+ FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4,
+ FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3,
+ FNOP_UN_0_SHUN_0_OPCODE_X0 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_X1 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1,
+ HALT_NOREG_RR_IMM_0_OPCODE_SN = 0,
+ ICOH_UN_0_SHUN_0_OPCODE_X1 = 6,
+ ILL_UN_0_SHUN_0_OPCODE_X1 = 7,
+ ILL_UN_0_SHUN_0_OPCODE_Y1 = 2,
+ IMM_0_OPCODE_SN = 0,
+ IMM_0_OPCODE_X0 = 4,
+ IMM_0_OPCODE_X1 = 6,
+ IMM_1_OPCODE_SN = 1,
+ IMM_OPCODE_0_X0 = 5,
+ INTHB_SPECIAL_0_OPCODE_X0 = 11,
+ INTHB_SPECIAL_0_OPCODE_X1 = 5,
+ INTHH_SPECIAL_0_OPCODE_X0 = 12,
+ INTHH_SPECIAL_0_OPCODE_X1 = 6,
+ INTLB_SPECIAL_0_OPCODE_X0 = 13,
+ INTLB_SPECIAL_0_OPCODE_X1 = 7,
+ INTLH_SPECIAL_0_OPCODE_X0 = 14,
+ INTLH_SPECIAL_0_OPCODE_X1 = 8,
+ INV_UN_0_SHUN_0_OPCODE_X1 = 8,
+ IRET_UN_0_SHUN_0_OPCODE_X1 = 9,
+ JALB_OPCODE_X1 = 13,
+ JALF_OPCODE_X1 = 12,
+ JALRP_SPECIAL_0_OPCODE_X1 = 9,
+ JALRR_IMM_1_OPCODE_SN = 3,
+ JALR_RR_IMM_0_OPCODE_SN = 5,
+ JALR_SPECIAL_0_OPCODE_X1 = 10,
+ JB_OPCODE_X1 = 11,
+ JF_OPCODE_X1 = 10,
+ JRP_SPECIAL_0_OPCODE_X1 = 11,
+ JRR_IMM_1_OPCODE_SN = 2,
+ JR_RR_IMM_0_OPCODE_SN = 4,
+ JR_SPECIAL_0_OPCODE_X1 = 12,
+ LBADD_IMM_0_OPCODE_X1 = 22,
+ LBADD_U_IMM_0_OPCODE_X1 = 23,
+ LB_OPCODE_Y2 = 0,
+ LB_UN_0_SHUN_0_OPCODE_X1 = 10,
+ LB_U_OPCODE_Y2 = 1,
+ LB_U_UN_0_SHUN_0_OPCODE_X1 = 11,
+ LHADD_IMM_0_OPCODE_X1 = 24,
+ LHADD_U_IMM_0_OPCODE_X1 = 25,
+ LH_OPCODE_Y2 = 2,
+ LH_UN_0_SHUN_0_OPCODE_X1 = 12,
+ LH_U_OPCODE_Y2 = 3,
+ LH_U_UN_0_SHUN_0_OPCODE_X1 = 13,
+ LNK_SPECIAL_0_OPCODE_X1 = 13,
+ LWADD_IMM_0_OPCODE_X1 = 26,
+ LWADD_NA_IMM_0_OPCODE_X1 = 27,
+ LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24,
+ LW_OPCODE_Y2 = 4,
+ LW_UN_0_SHUN_0_OPCODE_X1 = 14,
+ MAXB_U_SPECIAL_0_OPCODE_X0 = 15,
+ MAXB_U_SPECIAL_0_OPCODE_X1 = 14,
+ MAXH_SPECIAL_0_OPCODE_X0 = 16,
+ MAXH_SPECIAL_0_OPCODE_X1 = 15,
+ MAXIB_U_IMM_0_OPCODE_X0 = 4,
+ MAXIB_U_IMM_0_OPCODE_X1 = 5,
+ MAXIH_IMM_0_OPCODE_X0 = 5,
+ MAXIH_IMM_0_OPCODE_X1 = 6,
+ MFSPR_IMM_0_OPCODE_X1 = 7,
+ MF_UN_0_SHUN_0_OPCODE_X1 = 15,
+ MINB_U_SPECIAL_0_OPCODE_X0 = 17,
+ MINB_U_SPECIAL_0_OPCODE_X1 = 16,
+ MINH_SPECIAL_0_OPCODE_X0 = 18,
+ MINH_SPECIAL_0_OPCODE_X1 = 17,
+ MINIB_U_IMM_0_OPCODE_X0 = 6,
+ MINIB_U_IMM_0_OPCODE_X1 = 8,
+ MINIH_IMM_0_OPCODE_X0 = 7,
+ MINIH_IMM_0_OPCODE_X1 = 9,
+ MM_OPCODE_X0 = 6,
+ MM_OPCODE_X1 = 7,
+ MNZB_SPECIAL_0_OPCODE_X0 = 19,
+ MNZB_SPECIAL_0_OPCODE_X1 = 18,
+ MNZH_SPECIAL_0_OPCODE_X0 = 20,
+ MNZH_SPECIAL_0_OPCODE_X1 = 19,
+ MNZ_SPECIAL_0_OPCODE_X0 = 21,
+ MNZ_SPECIAL_0_OPCODE_X1 = 20,
+ MNZ_SPECIAL_1_OPCODE_Y0 = 0,
+ MNZ_SPECIAL_1_OPCODE_Y1 = 1,
+ MOVEI_IMM_1_OPCODE_SN = 0,
+ MOVE_RR_IMM_0_OPCODE_SN = 8,
+ MTSPR_IMM_0_OPCODE_X1 = 10,
+ MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22,
+ MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0,
+ MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23,
+ MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24,
+ MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1,
+ MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25,
+ MULHH_SS_SPECIAL_0_OPCODE_X0 = 26,
+ MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0,
+ MULHH_SU_SPECIAL_0_OPCODE_X0 = 27,
+ MULHH_UU_SPECIAL_0_OPCODE_X0 = 28,
+ MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1,
+ MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29,
+ MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30,
+ MULHLA_US_SPECIAL_0_OPCODE_X0 = 31,
+ MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32,
+ MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33,
+ MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0,
+ MULHL_SS_SPECIAL_0_OPCODE_X0 = 34,
+ MULHL_SU_SPECIAL_0_OPCODE_X0 = 35,
+ MULHL_US_SPECIAL_0_OPCODE_X0 = 36,
+ MULHL_UU_SPECIAL_0_OPCODE_X0 = 37,
+ MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38,
+ MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2,
+ MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39,
+ MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40,
+ MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3,
+ MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41,
+ MULLL_SS_SPECIAL_0_OPCODE_X0 = 42,
+ MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2,
+ MULLL_SU_SPECIAL_0_OPCODE_X0 = 43,
+ MULLL_UU_SPECIAL_0_OPCODE_X0 = 44,
+ MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3,
+ MVNZ_SPECIAL_0_OPCODE_X0 = 45,
+ MVNZ_SPECIAL_1_OPCODE_Y0 = 1,
+ MVZ_SPECIAL_0_OPCODE_X0 = 46,
+ MVZ_SPECIAL_1_OPCODE_Y0 = 2,
+ MZB_SPECIAL_0_OPCODE_X0 = 47,
+ MZB_SPECIAL_0_OPCODE_X1 = 21,
+ MZH_SPECIAL_0_OPCODE_X0 = 48,
+ MZH_SPECIAL_0_OPCODE_X1 = 22,
+ MZ_SPECIAL_0_OPCODE_X0 = 49,
+ MZ_SPECIAL_0_OPCODE_X1 = 23,
+ MZ_SPECIAL_1_OPCODE_Y0 = 3,
+ MZ_SPECIAL_1_OPCODE_Y1 = 2,
+ NAP_UN_0_SHUN_0_OPCODE_X1 = 16,
+ NOP_NOREG_RR_IMM_0_OPCODE_SN = 2,
+ NOP_UN_0_SHUN_0_OPCODE_X0 = 6,
+ NOP_UN_0_SHUN_0_OPCODE_X1 = 17,
+ NOP_UN_0_SHUN_0_OPCODE_Y0 = 6,
+ NOP_UN_0_SHUN_0_OPCODE_Y1 = 3,
+ NOREG_RR_IMM_0_OPCODE_SN = 0,
+ NOR_SPECIAL_0_OPCODE_X0 = 50,
+ NOR_SPECIAL_0_OPCODE_X1 = 24,
+ NOR_SPECIAL_2_OPCODE_Y0 = 1,
+ NOR_SPECIAL_2_OPCODE_Y1 = 1,
+ ORI_IMM_0_OPCODE_X0 = 8,
+ ORI_IMM_0_OPCODE_X1 = 11,
+ ORI_OPCODE_Y0 = 11,
+ ORI_OPCODE_Y1 = 9,
+ OR_SPECIAL_0_OPCODE_X0 = 51,
+ OR_SPECIAL_0_OPCODE_X1 = 25,
+ OR_SPECIAL_2_OPCODE_Y0 = 2,
+ OR_SPECIAL_2_OPCODE_Y1 = 2,
+ PACKBS_U_SPECIAL_0_OPCODE_X0 = 103,
+ PACKBS_U_SPECIAL_0_OPCODE_X1 = 73,
+ PACKHB_SPECIAL_0_OPCODE_X0 = 52,
+ PACKHB_SPECIAL_0_OPCODE_X1 = 26,
+ PACKHS_SPECIAL_0_OPCODE_X0 = 102,
+ PACKHS_SPECIAL_0_OPCODE_X1 = 72,
+ PACKLB_SPECIAL_0_OPCODE_X0 = 53,
+ PACKLB_SPECIAL_0_OPCODE_X1 = 27,
+ PCNT_UN_0_SHUN_0_OPCODE_X0 = 7,
+ PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7,
+ RLI_SHUN_0_OPCODE_X0 = 1,
+ RLI_SHUN_0_OPCODE_X1 = 1,
+ RLI_SHUN_0_OPCODE_Y0 = 1,
+ RLI_SHUN_0_OPCODE_Y1 = 1,
+ RL_SPECIAL_0_OPCODE_X0 = 54,
+ RL_SPECIAL_0_OPCODE_X1 = 28,
+ RL_SPECIAL_3_OPCODE_Y0 = 0,
+ RL_SPECIAL_3_OPCODE_Y1 = 0,
+ RR_IMM_0_OPCODE_SN = 0,
+ S1A_SPECIAL_0_OPCODE_X0 = 55,
+ S1A_SPECIAL_0_OPCODE_X1 = 29,
+ S1A_SPECIAL_0_OPCODE_Y0 = 1,
+ S1A_SPECIAL_0_OPCODE_Y1 = 1,
+ S2A_SPECIAL_0_OPCODE_X0 = 56,
+ S2A_SPECIAL_0_OPCODE_X1 = 30,
+ S2A_SPECIAL_0_OPCODE_Y0 = 2,
+ S2A_SPECIAL_0_OPCODE_Y1 = 2,
+ S3A_SPECIAL_0_OPCODE_X0 = 57,
+ S3A_SPECIAL_0_OPCODE_X1 = 31,
+ S3A_SPECIAL_5_OPCODE_Y0 = 1,
+ S3A_SPECIAL_5_OPCODE_Y1 = 1,
+ SADAB_U_SPECIAL_0_OPCODE_X0 = 58,
+ SADAH_SPECIAL_0_OPCODE_X0 = 59,
+ SADAH_U_SPECIAL_0_OPCODE_X0 = 60,
+ SADB_U_SPECIAL_0_OPCODE_X0 = 61,
+ SADH_SPECIAL_0_OPCODE_X0 = 62,
+ SADH_U_SPECIAL_0_OPCODE_X0 = 63,
+ SBADD_IMM_0_OPCODE_X1 = 28,
+ SB_OPCODE_Y2 = 5,
+ SB_SPECIAL_0_OPCODE_X1 = 32,
+ SEQB_SPECIAL_0_OPCODE_X0 = 64,
+ SEQB_SPECIAL_0_OPCODE_X1 = 33,
+ SEQH_SPECIAL_0_OPCODE_X0 = 65,
+ SEQH_SPECIAL_0_OPCODE_X1 = 34,
+ SEQIB_IMM_0_OPCODE_X0 = 9,
+ SEQIB_IMM_0_OPCODE_X1 = 12,
+ SEQIH_IMM_0_OPCODE_X0 = 10,
+ SEQIH_IMM_0_OPCODE_X1 = 13,
+ SEQI_IMM_0_OPCODE_X0 = 11,
+ SEQI_IMM_0_OPCODE_X1 = 14,
+ SEQI_OPCODE_Y0 = 12,
+ SEQI_OPCODE_Y1 = 10,
+ SEQ_SPECIAL_0_OPCODE_X0 = 66,
+ SEQ_SPECIAL_0_OPCODE_X1 = 35,
+ SEQ_SPECIAL_5_OPCODE_Y0 = 2,
+ SEQ_SPECIAL_5_OPCODE_Y1 = 2,
+ SHADD_IMM_0_OPCODE_X1 = 29,
+ SHL8II_IMM_0_OPCODE_SN = 3,
+ SHLB_SPECIAL_0_OPCODE_X0 = 67,
+ SHLB_SPECIAL_0_OPCODE_X1 = 36,
+ SHLH_SPECIAL_0_OPCODE_X0 = 68,
+ SHLH_SPECIAL_0_OPCODE_X1 = 37,
+ SHLIB_SHUN_0_OPCODE_X0 = 2,
+ SHLIB_SHUN_0_OPCODE_X1 = 2,
+ SHLIH_SHUN_0_OPCODE_X0 = 3,
+ SHLIH_SHUN_0_OPCODE_X1 = 3,
+ SHLI_SHUN_0_OPCODE_X0 = 4,
+ SHLI_SHUN_0_OPCODE_X1 = 4,
+ SHLI_SHUN_0_OPCODE_Y0 = 2,
+ SHLI_SHUN_0_OPCODE_Y1 = 2,
+ SHL_SPECIAL_0_OPCODE_X0 = 69,
+ SHL_SPECIAL_0_OPCODE_X1 = 38,
+ SHL_SPECIAL_3_OPCODE_Y0 = 1,
+ SHL_SPECIAL_3_OPCODE_Y1 = 1,
+ SHR1_RR_IMM_0_OPCODE_SN = 9,
+ SHRB_SPECIAL_0_OPCODE_X0 = 70,
+ SHRB_SPECIAL_0_OPCODE_X1 = 39,
+ SHRH_SPECIAL_0_OPCODE_X0 = 71,
+ SHRH_SPECIAL_0_OPCODE_X1 = 40,
+ SHRIB_SHUN_0_OPCODE_X0 = 5,
+ SHRIB_SHUN_0_OPCODE_X1 = 5,
+ SHRIH_SHUN_0_OPCODE_X0 = 6,
+ SHRIH_SHUN_0_OPCODE_X1 = 6,
+ SHRI_SHUN_0_OPCODE_X0 = 7,
+ SHRI_SHUN_0_OPCODE_X1 = 7,
+ SHRI_SHUN_0_OPCODE_Y0 = 3,
+ SHRI_SHUN_0_OPCODE_Y1 = 3,
+ SHR_SPECIAL_0_OPCODE_X0 = 72,
+ SHR_SPECIAL_0_OPCODE_X1 = 41,
+ SHR_SPECIAL_3_OPCODE_Y0 = 2,
+ SHR_SPECIAL_3_OPCODE_Y1 = 2,
+ SHUN_0_OPCODE_X0 = 7,
+ SHUN_0_OPCODE_X1 = 8,
+ SHUN_0_OPCODE_Y0 = 13,
+ SHUN_0_OPCODE_Y1 = 11,
+ SH_OPCODE_Y2 = 6,
+ SH_SPECIAL_0_OPCODE_X1 = 42,
+ SLTB_SPECIAL_0_OPCODE_X0 = 73,
+ SLTB_SPECIAL_0_OPCODE_X1 = 43,
+ SLTB_U_SPECIAL_0_OPCODE_X0 = 74,
+ SLTB_U_SPECIAL_0_OPCODE_X1 = 44,
+ SLTEB_SPECIAL_0_OPCODE_X0 = 75,
+ SLTEB_SPECIAL_0_OPCODE_X1 = 45,
+ SLTEB_U_SPECIAL_0_OPCODE_X0 = 76,
+ SLTEB_U_SPECIAL_0_OPCODE_X1 = 46,
+ SLTEH_SPECIAL_0_OPCODE_X0 = 77,
+ SLTEH_SPECIAL_0_OPCODE_X1 = 47,
+ SLTEH_U_SPECIAL_0_OPCODE_X0 = 78,
+ SLTEH_U_SPECIAL_0_OPCODE_X1 = 48,
+ SLTE_SPECIAL_0_OPCODE_X0 = 79,
+ SLTE_SPECIAL_0_OPCODE_X1 = 49,
+ SLTE_SPECIAL_4_OPCODE_Y0 = 0,
+ SLTE_SPECIAL_4_OPCODE_Y1 = 0,
+ SLTE_U_SPECIAL_0_OPCODE_X0 = 80,
+ SLTE_U_SPECIAL_0_OPCODE_X1 = 50,
+ SLTE_U_SPECIAL_4_OPCODE_Y0 = 1,
+ SLTE_U_SPECIAL_4_OPCODE_Y1 = 1,
+ SLTH_SPECIAL_0_OPCODE_X0 = 81,
+ SLTH_SPECIAL_0_OPCODE_X1 = 51,
+ SLTH_U_SPECIAL_0_OPCODE_X0 = 82,
+ SLTH_U_SPECIAL_0_OPCODE_X1 = 52,
+ SLTIB_IMM_0_OPCODE_X0 = 12,
+ SLTIB_IMM_0_OPCODE_X1 = 15,
+ SLTIB_U_IMM_0_OPCODE_X0 = 13,
+ SLTIB_U_IMM_0_OPCODE_X1 = 16,
+ SLTIH_IMM_0_OPCODE_X0 = 14,
+ SLTIH_IMM_0_OPCODE_X1 = 17,
+ SLTIH_U_IMM_0_OPCODE_X0 = 15,
+ SLTIH_U_IMM_0_OPCODE_X1 = 18,
+ SLTI_IMM_0_OPCODE_X0 = 16,
+ SLTI_IMM_0_OPCODE_X1 = 19,
+ SLTI_OPCODE_Y0 = 14,
+ SLTI_OPCODE_Y1 = 12,
+ SLTI_U_IMM_0_OPCODE_X0 = 17,
+ SLTI_U_IMM_0_OPCODE_X1 = 20,
+ SLTI_U_OPCODE_Y0 = 15,
+ SLTI_U_OPCODE_Y1 = 13,
+ SLT_SPECIAL_0_OPCODE_X0 = 83,
+ SLT_SPECIAL_0_OPCODE_X1 = 53,
+ SLT_SPECIAL_4_OPCODE_Y0 = 2,
+ SLT_SPECIAL_4_OPCODE_Y1 = 2,
+ SLT_U_SPECIAL_0_OPCODE_X0 = 84,
+ SLT_U_SPECIAL_0_OPCODE_X1 = 54,
+ SLT_U_SPECIAL_4_OPCODE_Y0 = 3,
+ SLT_U_SPECIAL_4_OPCODE_Y1 = 3,
+ SNEB_SPECIAL_0_OPCODE_X0 = 85,
+ SNEB_SPECIAL_0_OPCODE_X1 = 55,
+ SNEH_SPECIAL_0_OPCODE_X0 = 86,
+ SNEH_SPECIAL_0_OPCODE_X1 = 56,
+ SNE_SPECIAL_0_OPCODE_X0 = 87,
+ SNE_SPECIAL_0_OPCODE_X1 = 57,
+ SNE_SPECIAL_5_OPCODE_Y0 = 3,
+ SNE_SPECIAL_5_OPCODE_Y1 = 3,
+ SPECIAL_0_OPCODE_X0 = 0,
+ SPECIAL_0_OPCODE_X1 = 1,
+ SPECIAL_0_OPCODE_Y0 = 1,
+ SPECIAL_0_OPCODE_Y1 = 1,
+ SPECIAL_1_OPCODE_Y0 = 2,
+ SPECIAL_1_OPCODE_Y1 = 2,
+ SPECIAL_2_OPCODE_Y0 = 3,
+ SPECIAL_2_OPCODE_Y1 = 3,
+ SPECIAL_3_OPCODE_Y0 = 4,
+ SPECIAL_3_OPCODE_Y1 = 4,
+ SPECIAL_4_OPCODE_Y0 = 5,
+ SPECIAL_4_OPCODE_Y1 = 5,
+ SPECIAL_5_OPCODE_Y0 = 6,
+ SPECIAL_5_OPCODE_Y1 = 6,
+ SPECIAL_6_OPCODE_Y0 = 7,
+ SPECIAL_7_OPCODE_Y0 = 8,
+ SRAB_SPECIAL_0_OPCODE_X0 = 88,
+ SRAB_SPECIAL_0_OPCODE_X1 = 58,
+ SRAH_SPECIAL_0_OPCODE_X0 = 89,
+ SRAH_SPECIAL_0_OPCODE_X1 = 59,
+ SRAIB_SHUN_0_OPCODE_X0 = 8,
+ SRAIB_SHUN_0_OPCODE_X1 = 8,
+ SRAIH_SHUN_0_OPCODE_X0 = 9,
+ SRAIH_SHUN_0_OPCODE_X1 = 9,
+ SRAI_SHUN_0_OPCODE_X0 = 10,
+ SRAI_SHUN_0_OPCODE_X1 = 10,
+ SRAI_SHUN_0_OPCODE_Y0 = 4,
+ SRAI_SHUN_0_OPCODE_Y1 = 4,
+ SRA_SPECIAL_0_OPCODE_X0 = 90,
+ SRA_SPECIAL_0_OPCODE_X1 = 60,
+ SRA_SPECIAL_3_OPCODE_Y0 = 3,
+ SRA_SPECIAL_3_OPCODE_Y1 = 3,
+ SUBBS_U_SPECIAL_0_OPCODE_X0 = 100,
+ SUBBS_U_SPECIAL_0_OPCODE_X1 = 70,
+ SUBB_SPECIAL_0_OPCODE_X0 = 91,
+ SUBB_SPECIAL_0_OPCODE_X1 = 61,
+ SUBHS_SPECIAL_0_OPCODE_X0 = 101,
+ SUBHS_SPECIAL_0_OPCODE_X1 = 71,
+ SUBH_SPECIAL_0_OPCODE_X0 = 92,
+ SUBH_SPECIAL_0_OPCODE_X1 = 62,
+ SUBS_SPECIAL_0_OPCODE_X0 = 97,
+ SUBS_SPECIAL_0_OPCODE_X1 = 67,
+ SUB_SPECIAL_0_OPCODE_X0 = 93,
+ SUB_SPECIAL_0_OPCODE_X1 = 63,
+ SUB_SPECIAL_0_OPCODE_Y0 = 3,
+ SUB_SPECIAL_0_OPCODE_Y1 = 3,
+ SWADD_IMM_0_OPCODE_X1 = 30,
+ SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18,
+ SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19,
+ SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20,
+ SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21,
+ SW_OPCODE_Y2 = 7,
+ SW_SPECIAL_0_OPCODE_X1 = 64,
+ TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8,
+ TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8,
+ TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9,
+ TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9,
+ TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10,
+ TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10,
+ TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11,
+ TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11,
+ TNS_UN_0_SHUN_0_OPCODE_X1 = 22,
+ UN_0_SHUN_0_OPCODE_X0 = 11,
+ UN_0_SHUN_0_OPCODE_X1 = 11,
+ UN_0_SHUN_0_OPCODE_Y0 = 5,
+ UN_0_SHUN_0_OPCODE_Y1 = 5,
+ WH64_UN_0_SHUN_0_OPCODE_X1 = 23,
+ XORI_IMM_0_OPCODE_X0 = 2,
+ XORI_IMM_0_OPCODE_X1 = 21,
+ XOR_SPECIAL_0_OPCODE_X0 = 94,
+ XOR_SPECIAL_0_OPCODE_X1 = 65,
+ XOR_SPECIAL_2_OPCODE_Y0 = 3,
+ XOR_SPECIAL_2_OPCODE_Y1 = 3
+};
+
+#endif /* !_TILE_OPCODE_CONSTANTS_H */
diff --git a/arch/tile/include/asm/opcode_constants_64.h b/arch/tile/include/asm/opcode_constants_64.h
new file mode 100644
index 000000000000..227d033b180c
--- /dev/null
+++ b/arch/tile/include/asm/opcode_constants_64.h
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/* This file is machine-generated; DO NOT EDIT! */
+
+
+#ifndef _TILE_OPCODE_CONSTANTS_H
+#define _TILE_OPCODE_CONSTANTS_H
+enum
+{
+ ADDBS_U_SPECIAL_0_OPCODE_X0 = 98,
+ ADDBS_U_SPECIAL_0_OPCODE_X1 = 68,
+ ADDB_SPECIAL_0_OPCODE_X0 = 1,
+ ADDB_SPECIAL_0_OPCODE_X1 = 1,
+ ADDHS_SPECIAL_0_OPCODE_X0 = 99,
+ ADDHS_SPECIAL_0_OPCODE_X1 = 69,
+ ADDH_SPECIAL_0_OPCODE_X0 = 2,
+ ADDH_SPECIAL_0_OPCODE_X1 = 2,
+ ADDIB_IMM_0_OPCODE_X0 = 1,
+ ADDIB_IMM_0_OPCODE_X1 = 1,
+ ADDIH_IMM_0_OPCODE_X0 = 2,
+ ADDIH_IMM_0_OPCODE_X1 = 2,
+ ADDI_IMM_0_OPCODE_X0 = 3,
+ ADDI_IMM_0_OPCODE_X1 = 3,
+ ADDI_IMM_1_OPCODE_SN = 1,
+ ADDI_OPCODE_Y0 = 9,
+ ADDI_OPCODE_Y1 = 7,
+ ADDLIS_OPCODE_X0 = 1,
+ ADDLIS_OPCODE_X1 = 2,
+ ADDLI_OPCODE_X0 = 2,
+ ADDLI_OPCODE_X1 = 3,
+ ADDS_SPECIAL_0_OPCODE_X0 = 96,
+ ADDS_SPECIAL_0_OPCODE_X1 = 66,
+ ADD_SPECIAL_0_OPCODE_X0 = 3,
+ ADD_SPECIAL_0_OPCODE_X1 = 3,
+ ADD_SPECIAL_0_OPCODE_Y0 = 0,
+ ADD_SPECIAL_0_OPCODE_Y1 = 0,
+ ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4,
+ ADIFFH_SPECIAL_0_OPCODE_X0 = 5,
+ ANDI_IMM_0_OPCODE_X0 = 1,
+ ANDI_IMM_0_OPCODE_X1 = 4,
+ ANDI_OPCODE_Y0 = 10,
+ ANDI_OPCODE_Y1 = 8,
+ AND_SPECIAL_0_OPCODE_X0 = 6,
+ AND_SPECIAL_0_OPCODE_X1 = 4,
+ AND_SPECIAL_2_OPCODE_Y0 = 0,
+ AND_SPECIAL_2_OPCODE_Y1 = 0,
+ AULI_OPCODE_X0 = 3,
+ AULI_OPCODE_X1 = 4,
+ AVGB_U_SPECIAL_0_OPCODE_X0 = 7,
+ AVGH_SPECIAL_0_OPCODE_X0 = 8,
+ BBNST_BRANCH_OPCODE_X1 = 15,
+ BBNS_BRANCH_OPCODE_X1 = 14,
+ BBNS_OPCODE_SN = 63,
+ BBST_BRANCH_OPCODE_X1 = 13,
+ BBS_BRANCH_OPCODE_X1 = 12,
+ BBS_OPCODE_SN = 62,
+ BGEZT_BRANCH_OPCODE_X1 = 7,
+ BGEZ_BRANCH_OPCODE_X1 = 6,
+ BGEZ_OPCODE_SN = 61,
+ BGZT_BRANCH_OPCODE_X1 = 5,
+ BGZ_BRANCH_OPCODE_X1 = 4,
+ BGZ_OPCODE_SN = 58,
+ BITX_UN_0_SHUN_0_OPCODE_X0 = 1,
+ BITX_UN_0_SHUN_0_OPCODE_Y0 = 1,
+ BLEZT_BRANCH_OPCODE_X1 = 11,
+ BLEZ_BRANCH_OPCODE_X1 = 10,
+ BLEZ_OPCODE_SN = 59,
+ BLZT_BRANCH_OPCODE_X1 = 9,
+ BLZ_BRANCH_OPCODE_X1 = 8,
+ BLZ_OPCODE_SN = 60,
+ BNZT_BRANCH_OPCODE_X1 = 3,
+ BNZ_BRANCH_OPCODE_X1 = 2,
+ BNZ_OPCODE_SN = 57,
+ BPT_NOREG_RR_IMM_0_OPCODE_SN = 1,
+ BRANCH_OPCODE_X1 = 5,
+ BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2,
+ BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2,
+ BZT_BRANCH_OPCODE_X1 = 1,
+ BZ_BRANCH_OPCODE_X1 = 0,
+ BZ_OPCODE_SN = 56,
+ CLZ_UN_0_SHUN_0_OPCODE_X0 = 3,
+ CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3,
+ CRC32_32_SPECIAL_0_OPCODE_X0 = 9,
+ CRC32_8_SPECIAL_0_OPCODE_X0 = 10,
+ CTZ_UN_0_SHUN_0_OPCODE_X0 = 4,
+ CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4,
+ DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1,
+ DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2,
+ DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95,
+ FINV_UN_0_SHUN_0_OPCODE_X1 = 3,
+ FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4,
+ FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3,
+ FNOP_UN_0_SHUN_0_OPCODE_X0 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_X1 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5,
+ FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1,
+ HALT_NOREG_RR_IMM_0_OPCODE_SN = 0,
+ ICOH_UN_0_SHUN_0_OPCODE_X1 = 6,
+ ILL_UN_0_SHUN_0_OPCODE_X1 = 7,
+ ILL_UN_0_SHUN_0_OPCODE_Y1 = 2,
+ IMM_0_OPCODE_SN = 0,
+ IMM_0_OPCODE_X0 = 4,
+ IMM_0_OPCODE_X1 = 6,
+ IMM_1_OPCODE_SN = 1,
+ IMM_OPCODE_0_X0 = 5,
+ INTHB_SPECIAL_0_OPCODE_X0 = 11,
+ INTHB_SPECIAL_0_OPCODE_X1 = 5,
+ INTHH_SPECIAL_0_OPCODE_X0 = 12,
+ INTHH_SPECIAL_0_OPCODE_X1 = 6,
+ INTLB_SPECIAL_0_OPCODE_X0 = 13,
+ INTLB_SPECIAL_0_OPCODE_X1 = 7,
+ INTLH_SPECIAL_0_OPCODE_X0 = 14,
+ INTLH_SPECIAL_0_OPCODE_X1 = 8,
+ INV_UN_0_SHUN_0_OPCODE_X1 = 8,
+ IRET_UN_0_SHUN_0_OPCODE_X1 = 9,
+ JALB_OPCODE_X1 = 13,
+ JALF_OPCODE_X1 = 12,
+ JALRP_SPECIAL_0_OPCODE_X1 = 9,
+ JALRR_IMM_1_OPCODE_SN = 3,
+ JALR_RR_IMM_0_OPCODE_SN = 5,
+ JALR_SPECIAL_0_OPCODE_X1 = 10,
+ JB_OPCODE_X1 = 11,
+ JF_OPCODE_X1 = 10,
+ JRP_SPECIAL_0_OPCODE_X1 = 11,
+ JRR_IMM_1_OPCODE_SN = 2,
+ JR_RR_IMM_0_OPCODE_SN = 4,
+ JR_SPECIAL_0_OPCODE_X1 = 12,
+ LBADD_IMM_0_OPCODE_X1 = 22,
+ LBADD_U_IMM_0_OPCODE_X1 = 23,
+ LB_OPCODE_Y2 = 0,
+ LB_UN_0_SHUN_0_OPCODE_X1 = 10,
+ LB_U_OPCODE_Y2 = 1,
+ LB_U_UN_0_SHUN_0_OPCODE_X1 = 11,
+ LHADD_IMM_0_OPCODE_X1 = 24,
+ LHADD_U_IMM_0_OPCODE_X1 = 25,
+ LH_OPCODE_Y2 = 2,
+ LH_UN_0_SHUN_0_OPCODE_X1 = 12,
+ LH_U_OPCODE_Y2 = 3,
+ LH_U_UN_0_SHUN_0_OPCODE_X1 = 13,
+ LNK_SPECIAL_0_OPCODE_X1 = 13,
+ LWADD_IMM_0_OPCODE_X1 = 26,
+ LWADD_NA_IMM_0_OPCODE_X1 = 27,
+ LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24,
+ LW_OPCODE_Y2 = 4,
+ LW_UN_0_SHUN_0_OPCODE_X1 = 14,
+ MAXB_U_SPECIAL_0_OPCODE_X0 = 15,
+ MAXB_U_SPECIAL_0_OPCODE_X1 = 14,
+ MAXH_SPECIAL_0_OPCODE_X0 = 16,
+ MAXH_SPECIAL_0_OPCODE_X1 = 15,
+ MAXIB_U_IMM_0_OPCODE_X0 = 4,
+ MAXIB_U_IMM_0_OPCODE_X1 = 5,
+ MAXIH_IMM_0_OPCODE_X0 = 5,
+ MAXIH_IMM_0_OPCODE_X1 = 6,
+ MFSPR_IMM_0_OPCODE_X1 = 7,
+ MF_UN_0_SHUN_0_OPCODE_X1 = 15,
+ MINB_U_SPECIAL_0_OPCODE_X0 = 17,
+ MINB_U_SPECIAL_0_OPCODE_X1 = 16,
+ MINH_SPECIAL_0_OPCODE_X0 = 18,
+ MINH_SPECIAL_0_OPCODE_X1 = 17,
+ MINIB_U_IMM_0_OPCODE_X0 = 6,
+ MINIB_U_IMM_0_OPCODE_X1 = 8,
+ MINIH_IMM_0_OPCODE_X0 = 7,
+ MINIH_IMM_0_OPCODE_X1 = 9,
+ MM_OPCODE_X0 = 6,
+ MM_OPCODE_X1 = 7,
+ MNZB_SPECIAL_0_OPCODE_X0 = 19,
+ MNZB_SPECIAL_0_OPCODE_X1 = 18,
+ MNZH_SPECIAL_0_OPCODE_X0 = 20,
+ MNZH_SPECIAL_0_OPCODE_X1 = 19,
+ MNZ_SPECIAL_0_OPCODE_X0 = 21,
+ MNZ_SPECIAL_0_OPCODE_X1 = 20,
+ MNZ_SPECIAL_1_OPCODE_Y0 = 0,
+ MNZ_SPECIAL_1_OPCODE_Y1 = 1,
+ MOVEI_IMM_1_OPCODE_SN = 0,
+ MOVE_RR_IMM_0_OPCODE_SN = 8,
+ MTSPR_IMM_0_OPCODE_X1 = 10,
+ MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22,
+ MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0,
+ MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23,
+ MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24,
+ MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1,
+ MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25,
+ MULHH_SS_SPECIAL_0_OPCODE_X0 = 26,
+ MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0,
+ MULHH_SU_SPECIAL_0_OPCODE_X0 = 27,
+ MULHH_UU_SPECIAL_0_OPCODE_X0 = 28,
+ MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1,
+ MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29,
+ MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30,
+ MULHLA_US_SPECIAL_0_OPCODE_X0 = 31,
+ MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32,
+ MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33,
+ MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0,
+ MULHL_SS_SPECIAL_0_OPCODE_X0 = 34,
+ MULHL_SU_SPECIAL_0_OPCODE_X0 = 35,
+ MULHL_US_SPECIAL_0_OPCODE_X0 = 36,
+ MULHL_UU_SPECIAL_0_OPCODE_X0 = 37,
+ MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38,
+ MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2,
+ MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39,
+ MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40,
+ MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3,
+ MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41,
+ MULLL_SS_SPECIAL_0_OPCODE_X0 = 42,
+ MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2,
+ MULLL_SU_SPECIAL_0_OPCODE_X0 = 43,
+ MULLL_UU_SPECIAL_0_OPCODE_X0 = 44,
+ MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3,
+ MVNZ_SPECIAL_0_OPCODE_X0 = 45,
+ MVNZ_SPECIAL_1_OPCODE_Y0 = 1,
+ MVZ_SPECIAL_0_OPCODE_X0 = 46,
+ MVZ_SPECIAL_1_OPCODE_Y0 = 2,
+ MZB_SPECIAL_0_OPCODE_X0 = 47,
+ MZB_SPECIAL_0_OPCODE_X1 = 21,
+ MZH_SPECIAL_0_OPCODE_X0 = 48,
+ MZH_SPECIAL_0_OPCODE_X1 = 22,
+ MZ_SPECIAL_0_OPCODE_X0 = 49,
+ MZ_SPECIAL_0_OPCODE_X1 = 23,
+ MZ_SPECIAL_1_OPCODE_Y0 = 3,
+ MZ_SPECIAL_1_OPCODE_Y1 = 2,
+ NAP_UN_0_SHUN_0_OPCODE_X1 = 16,
+ NOP_NOREG_RR_IMM_0_OPCODE_SN = 2,
+ NOP_UN_0_SHUN_0_OPCODE_X0 = 6,
+ NOP_UN_0_SHUN_0_OPCODE_X1 = 17,
+ NOP_UN_0_SHUN_0_OPCODE_Y0 = 6,
+ NOP_UN_0_SHUN_0_OPCODE_Y1 = 3,
+ NOREG_RR_IMM_0_OPCODE_SN = 0,
+ NOR_SPECIAL_0_OPCODE_X0 = 50,
+ NOR_SPECIAL_0_OPCODE_X1 = 24,
+ NOR_SPECIAL_2_OPCODE_Y0 = 1,
+ NOR_SPECIAL_2_OPCODE_Y1 = 1,
+ ORI_IMM_0_OPCODE_X0 = 8,
+ ORI_IMM_0_OPCODE_X1 = 11,
+ ORI_OPCODE_Y0 = 11,
+ ORI_OPCODE_Y1 = 9,
+ OR_SPECIAL_0_OPCODE_X0 = 51,
+ OR_SPECIAL_0_OPCODE_X1 = 25,
+ OR_SPECIAL_2_OPCODE_Y0 = 2,
+ OR_SPECIAL_2_OPCODE_Y1 = 2,
+ PACKBS_U_SPECIAL_0_OPCODE_X0 = 103,
+ PACKBS_U_SPECIAL_0_OPCODE_X1 = 73,
+ PACKHB_SPECIAL_0_OPCODE_X0 = 52,
+ PACKHB_SPECIAL_0_OPCODE_X1 = 26,
+ PACKHS_SPECIAL_0_OPCODE_X0 = 102,
+ PACKHS_SPECIAL_0_OPCODE_X1 = 72,
+ PACKLB_SPECIAL_0_OPCODE_X0 = 53,
+ PACKLB_SPECIAL_0_OPCODE_X1 = 27,
+ PCNT_UN_0_SHUN_0_OPCODE_X0 = 7,
+ PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7,
+ RLI_SHUN_0_OPCODE_X0 = 1,
+ RLI_SHUN_0_OPCODE_X1 = 1,
+ RLI_SHUN_0_OPCODE_Y0 = 1,
+ RLI_SHUN_0_OPCODE_Y1 = 1,
+ RL_SPECIAL_0_OPCODE_X0 = 54,
+ RL_SPECIAL_0_OPCODE_X1 = 28,
+ RL_SPECIAL_3_OPCODE_Y0 = 0,
+ RL_SPECIAL_3_OPCODE_Y1 = 0,
+ RR_IMM_0_OPCODE_SN = 0,
+ S1A_SPECIAL_0_OPCODE_X0 = 55,
+ S1A_SPECIAL_0_OPCODE_X1 = 29,
+ S1A_SPECIAL_0_OPCODE_Y0 = 1,
+ S1A_SPECIAL_0_OPCODE_Y1 = 1,
+ S2A_SPECIAL_0_OPCODE_X0 = 56,
+ S2A_SPECIAL_0_OPCODE_X1 = 30,
+ S2A_SPECIAL_0_OPCODE_Y0 = 2,
+ S2A_SPECIAL_0_OPCODE_Y1 = 2,
+ S3A_SPECIAL_0_OPCODE_X0 = 57,
+ S3A_SPECIAL_0_OPCODE_X1 = 31,
+ S3A_SPECIAL_5_OPCODE_Y0 = 1,
+ S3A_SPECIAL_5_OPCODE_Y1 = 1,
+ SADAB_U_SPECIAL_0_OPCODE_X0 = 58,
+ SADAH_SPECIAL_0_OPCODE_X0 = 59,
+ SADAH_U_SPECIAL_0_OPCODE_X0 = 60,
+ SADB_U_SPECIAL_0_OPCODE_X0 = 61,
+ SADH_SPECIAL_0_OPCODE_X0 = 62,
+ SADH_U_SPECIAL_0_OPCODE_X0 = 63,
+ SBADD_IMM_0_OPCODE_X1 = 28,
+ SB_OPCODE_Y2 = 5,
+ SB_SPECIAL_0_OPCODE_X1 = 32,
+ SEQB_SPECIAL_0_OPCODE_X0 = 64,
+ SEQB_SPECIAL_0_OPCODE_X1 = 33,
+ SEQH_SPECIAL_0_OPCODE_X0 = 65,
+ SEQH_SPECIAL_0_OPCODE_X1 = 34,
+ SEQIB_IMM_0_OPCODE_X0 = 9,
+ SEQIB_IMM_0_OPCODE_X1 = 12,
+ SEQIH_IMM_0_OPCODE_X0 = 10,
+ SEQIH_IMM_0_OPCODE_X1 = 13,
+ SEQI_IMM_0_OPCODE_X0 = 11,
+ SEQI_IMM_0_OPCODE_X1 = 14,
+ SEQI_OPCODE_Y0 = 12,
+ SEQI_OPCODE_Y1 = 10,
+ SEQ_SPECIAL_0_OPCODE_X0 = 66,
+ SEQ_SPECIAL_0_OPCODE_X1 = 35,
+ SEQ_SPECIAL_5_OPCODE_Y0 = 2,
+ SEQ_SPECIAL_5_OPCODE_Y1 = 2,
+ SHADD_IMM_0_OPCODE_X1 = 29,
+ SHL8II_IMM_0_OPCODE_SN = 3,
+ SHLB_SPECIAL_0_OPCODE_X0 = 67,
+ SHLB_SPECIAL_0_OPCODE_X1 = 36,
+ SHLH_SPECIAL_0_OPCODE_X0 = 68,
+ SHLH_SPECIAL_0_OPCODE_X1 = 37,
+ SHLIB_SHUN_0_OPCODE_X0 = 2,
+ SHLIB_SHUN_0_OPCODE_X1 = 2,
+ SHLIH_SHUN_0_OPCODE_X0 = 3,
+ SHLIH_SHUN_0_OPCODE_X1 = 3,
+ SHLI_SHUN_0_OPCODE_X0 = 4,
+ SHLI_SHUN_0_OPCODE_X1 = 4,
+ SHLI_SHUN_0_OPCODE_Y0 = 2,
+ SHLI_SHUN_0_OPCODE_Y1 = 2,
+ SHL_SPECIAL_0_OPCODE_X0 = 69,
+ SHL_SPECIAL_0_OPCODE_X1 = 38,
+ SHL_SPECIAL_3_OPCODE_Y0 = 1,
+ SHL_SPECIAL_3_OPCODE_Y1 = 1,
+ SHR1_RR_IMM_0_OPCODE_SN = 9,
+ SHRB_SPECIAL_0_OPCODE_X0 = 70,
+ SHRB_SPECIAL_0_OPCODE_X1 = 39,
+ SHRH_SPECIAL_0_OPCODE_X0 = 71,
+ SHRH_SPECIAL_0_OPCODE_X1 = 40,
+ SHRIB_SHUN_0_OPCODE_X0 = 5,
+ SHRIB_SHUN_0_OPCODE_X1 = 5,
+ SHRIH_SHUN_0_OPCODE_X0 = 6,
+ SHRIH_SHUN_0_OPCODE_X1 = 6,
+ SHRI_SHUN_0_OPCODE_X0 = 7,
+ SHRI_SHUN_0_OPCODE_X1 = 7,
+ SHRI_SHUN_0_OPCODE_Y0 = 3,
+ SHRI_SHUN_0_OPCODE_Y1 = 3,
+ SHR_SPECIAL_0_OPCODE_X0 = 72,
+ SHR_SPECIAL_0_OPCODE_X1 = 41,
+ SHR_SPECIAL_3_OPCODE_Y0 = 2,
+ SHR_SPECIAL_3_OPCODE_Y1 = 2,
+ SHUN_0_OPCODE_X0 = 7,
+ SHUN_0_OPCODE_X1 = 8,
+ SHUN_0_OPCODE_Y0 = 13,
+ SHUN_0_OPCODE_Y1 = 11,
+ SH_OPCODE_Y2 = 6,
+ SH_SPECIAL_0_OPCODE_X1 = 42,
+ SLTB_SPECIAL_0_OPCODE_X0 = 73,
+ SLTB_SPECIAL_0_OPCODE_X1 = 43,
+ SLTB_U_SPECIAL_0_OPCODE_X0 = 74,
+ SLTB_U_SPECIAL_0_OPCODE_X1 = 44,
+ SLTEB_SPECIAL_0_OPCODE_X0 = 75,
+ SLTEB_SPECIAL_0_OPCODE_X1 = 45,
+ SLTEB_U_SPECIAL_0_OPCODE_X0 = 76,
+ SLTEB_U_SPECIAL_0_OPCODE_X1 = 46,
+ SLTEH_SPECIAL_0_OPCODE_X0 = 77,
+ SLTEH_SPECIAL_0_OPCODE_X1 = 47,
+ SLTEH_U_SPECIAL_0_OPCODE_X0 = 78,
+ SLTEH_U_SPECIAL_0_OPCODE_X1 = 48,
+ SLTE_SPECIAL_0_OPCODE_X0 = 79,
+ SLTE_SPECIAL_0_OPCODE_X1 = 49,
+ SLTE_SPECIAL_4_OPCODE_Y0 = 0,
+ SLTE_SPECIAL_4_OPCODE_Y1 = 0,
+ SLTE_U_SPECIAL_0_OPCODE_X0 = 80,
+ SLTE_U_SPECIAL_0_OPCODE_X1 = 50,
+ SLTE_U_SPECIAL_4_OPCODE_Y0 = 1,
+ SLTE_U_SPECIAL_4_OPCODE_Y1 = 1,
+ SLTH_SPECIAL_0_OPCODE_X0 = 81,
+ SLTH_SPECIAL_0_OPCODE_X1 = 51,
+ SLTH_U_SPECIAL_0_OPCODE_X0 = 82,
+ SLTH_U_SPECIAL_0_OPCODE_X1 = 52,
+ SLTIB_IMM_0_OPCODE_X0 = 12,
+ SLTIB_IMM_0_OPCODE_X1 = 15,
+ SLTIB_U_IMM_0_OPCODE_X0 = 13,
+ SLTIB_U_IMM_0_OPCODE_X1 = 16,
+ SLTIH_IMM_0_OPCODE_X0 = 14,
+ SLTIH_IMM_0_OPCODE_X1 = 17,
+ SLTIH_U_IMM_0_OPCODE_X0 = 15,
+ SLTIH_U_IMM_0_OPCODE_X1 = 18,
+ SLTI_IMM_0_OPCODE_X0 = 16,
+ SLTI_IMM_0_OPCODE_X1 = 19,
+ SLTI_OPCODE_Y0 = 14,
+ SLTI_OPCODE_Y1 = 12,
+ SLTI_U_IMM_0_OPCODE_X0 = 17,
+ SLTI_U_IMM_0_OPCODE_X1 = 20,
+ SLTI_U_OPCODE_Y0 = 15,
+ SLTI_U_OPCODE_Y1 = 13,
+ SLT_SPECIAL_0_OPCODE_X0 = 83,
+ SLT_SPECIAL_0_OPCODE_X1 = 53,
+ SLT_SPECIAL_4_OPCODE_Y0 = 2,
+ SLT_SPECIAL_4_OPCODE_Y1 = 2,
+ SLT_U_SPECIAL_0_OPCODE_X0 = 84,
+ SLT_U_SPECIAL_0_OPCODE_X1 = 54,
+ SLT_U_SPECIAL_4_OPCODE_Y0 = 3,
+ SLT_U_SPECIAL_4_OPCODE_Y1 = 3,
+ SNEB_SPECIAL_0_OPCODE_X0 = 85,
+ SNEB_SPECIAL_0_OPCODE_X1 = 55,
+ SNEH_SPECIAL_0_OPCODE_X0 = 86,
+ SNEH_SPECIAL_0_OPCODE_X1 = 56,
+ SNE_SPECIAL_0_OPCODE_X0 = 87,
+ SNE_SPECIAL_0_OPCODE_X1 = 57,
+ SNE_SPECIAL_5_OPCODE_Y0 = 3,
+ SNE_SPECIAL_5_OPCODE_Y1 = 3,
+ SPECIAL_0_OPCODE_X0 = 0,
+ SPECIAL_0_OPCODE_X1 = 1,
+ SPECIAL_0_OPCODE_Y0 = 1,
+ SPECIAL_0_OPCODE_Y1 = 1,
+ SPECIAL_1_OPCODE_Y0 = 2,
+ SPECIAL_1_OPCODE_Y1 = 2,
+ SPECIAL_2_OPCODE_Y0 = 3,
+ SPECIAL_2_OPCODE_Y1 = 3,
+ SPECIAL_3_OPCODE_Y0 = 4,
+ SPECIAL_3_OPCODE_Y1 = 4,
+ SPECIAL_4_OPCODE_Y0 = 5,
+ SPECIAL_4_OPCODE_Y1 = 5,
+ SPECIAL_5_OPCODE_Y0 = 6,
+ SPECIAL_5_OPCODE_Y1 = 6,
+ SPECIAL_6_OPCODE_Y0 = 7,
+ SPECIAL_7_OPCODE_Y0 = 8,
+ SRAB_SPECIAL_0_OPCODE_X0 = 88,
+ SRAB_SPECIAL_0_OPCODE_X1 = 58,
+ SRAH_SPECIAL_0_OPCODE_X0 = 89,
+ SRAH_SPECIAL_0_OPCODE_X1 = 59,
+ SRAIB_SHUN_0_OPCODE_X0 = 8,
+ SRAIB_SHUN_0_OPCODE_X1 = 8,
+ SRAIH_SHUN_0_OPCODE_X0 = 9,
+ SRAIH_SHUN_0_OPCODE_X1 = 9,
+ SRAI_SHUN_0_OPCODE_X0 = 10,
+ SRAI_SHUN_0_OPCODE_X1 = 10,
+ SRAI_SHUN_0_OPCODE_Y0 = 4,
+ SRAI_SHUN_0_OPCODE_Y1 = 4,
+ SRA_SPECIAL_0_OPCODE_X0 = 90,
+ SRA_SPECIAL_0_OPCODE_X1 = 60,
+ SRA_SPECIAL_3_OPCODE_Y0 = 3,
+ SRA_SPECIAL_3_OPCODE_Y1 = 3,
+ SUBBS_U_SPECIAL_0_OPCODE_X0 = 100,
+ SUBBS_U_SPECIAL_0_OPCODE_X1 = 70,
+ SUBB_SPECIAL_0_OPCODE_X0 = 91,
+ SUBB_SPECIAL_0_OPCODE_X1 = 61,
+ SUBHS_SPECIAL_0_OPCODE_X0 = 101,
+ SUBHS_SPECIAL_0_OPCODE_X1 = 71,
+ SUBH_SPECIAL_0_OPCODE_X0 = 92,
+ SUBH_SPECIAL_0_OPCODE_X1 = 62,
+ SUBS_SPECIAL_0_OPCODE_X0 = 97,
+ SUBS_SPECIAL_0_OPCODE_X1 = 67,
+ SUB_SPECIAL_0_OPCODE_X0 = 93,
+ SUB_SPECIAL_0_OPCODE_X1 = 63,
+ SUB_SPECIAL_0_OPCODE_Y0 = 3,
+ SUB_SPECIAL_0_OPCODE_Y1 = 3,
+ SWADD_IMM_0_OPCODE_X1 = 30,
+ SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18,
+ SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19,
+ SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20,
+ SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21,
+ SW_OPCODE_Y2 = 7,
+ SW_SPECIAL_0_OPCODE_X1 = 64,
+ TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8,
+ TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8,
+ TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9,
+ TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9,
+ TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10,
+ TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10,
+ TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11,
+ TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11,
+ TNS_UN_0_SHUN_0_OPCODE_X1 = 22,
+ UN_0_SHUN_0_OPCODE_X0 = 11,
+ UN_0_SHUN_0_OPCODE_X1 = 11,
+ UN_0_SHUN_0_OPCODE_Y0 = 5,
+ UN_0_SHUN_0_OPCODE_Y1 = 5,
+ WH64_UN_0_SHUN_0_OPCODE_X1 = 23,
+ XORI_IMM_0_OPCODE_X0 = 2,
+ XORI_IMM_0_OPCODE_X1 = 21,
+ XOR_SPECIAL_0_OPCODE_X0 = 94,
+ XOR_SPECIAL_0_OPCODE_X1 = 65,
+ XOR_SPECIAL_2_OPCODE_Y0 = 3,
+ XOR_SPECIAL_2_OPCODE_Y1 = 3
+};
+
+#endif /* !_TILE_OPCODE_CONSTANTS_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
new file mode 100644
index 000000000000..c8301c43d6d9
--- /dev/null
+++ b/arch/tile/include/asm/page.h
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PAGE_H
+#define _ASM_TILE_PAGE_H
+
+#include <linux/const.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+
+/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
+#define PAGE_SHIFT 16
+#define HPAGE_SHIFT 24
+
+#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
+#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
+
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+
+/*
+ * The {,H}PAGE_SHIFT values must match the HV_LOG2_PAGE_SIZE_xxx
+ * definitions in <hv/hypervisor.h>. We validate this at build time
+ * here, and again at runtime during early boot. We provide a
+ * separate definition since userspace doesn't have <hv/hypervisor.h>.
+ *
+ * Be careful to distinguish PAGE_SHIFT from HV_PTE_INDEX_PFN, since
+ * they are the same on i386 but not TILE.
+ */
+#if HV_LOG2_PAGE_SIZE_SMALL != PAGE_SHIFT
+# error Small page size mismatch in Linux
+#endif
+#if HV_LOG2_PAGE_SIZE_LARGE != HPAGE_SHIFT
+# error Huge page size mismatch in Linux
+#endif
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+struct page;
+
+static inline void clear_page(void *page)
+{
+ memset(page, 0, PAGE_SIZE);
+}
+
+static inline void copy_page(void *to, void *from)
+{
+ memcpy(to, from, PAGE_SIZE);
+}
+
+static inline void clear_user_page(void *page, unsigned long vaddr,
+ struct page *pg)
+{
+ clear_page(page);
+}
+
+static inline void copy_user_page(void *to, void *from, unsigned long vaddr,
+ struct page *topage)
+{
+ copy_page(to, from);
+}
+
+/*
+ * Hypervisor page tables are made of the same basic structure.
+ */
+
+typedef __u64 pteval_t;
+typedef __u64 pmdval_t;
+typedef __u64 pudval_t;
+typedef __u64 pgdval_t;
+typedef __u64 pgprotval_t;
+
+typedef HV_PTE pte_t;
+typedef HV_PTE pgd_t;
+typedef HV_PTE pgprot_t;
+
+/*
+ * User L2 page tables are managed as one L2 page table per page,
+ * because we use the page allocator for them. This keeps the allocation
+ * simple and makes it potentially useful to implement HIGHPTE at some point.
+ * However, it's also inefficient, since L2 page tables are much smaller
+ * than pages (currently 2KB vs 64KB). So we should revisit this.
+ */
+typedef struct page *pgtable_t;
+
+/* Must be a macro since it is used to create constants. */
+#define __pgprot(val) hv_pte(val)
+
+static inline u64 pgprot_val(pgprot_t pgprot)
+{
+ return hv_pte_val(pgprot);
+}
+
+static inline u64 pte_val(pte_t pte)
+{
+ return hv_pte_val(pte);
+}
+
+static inline u64 pgd_val(pgd_t pgd)
+{
+ return hv_pte_val(pgd);
+}
+
+#ifdef __tilegx__
+
+typedef HV_PTE pmd_t;
+
+static inline u64 pmd_val(pmd_t pmd)
+{
+ return hv_pte_val(pmd);
+}
+
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+#define HUGE_MAX_HSTATE 2
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+#endif
+
+/* Each memory controller has PAs distinct in their high bits. */
+#define NR_PA_HIGHBIT_SHIFT (CHIP_PA_WIDTH() - CHIP_LOG_NUM_MSHIMS())
+#define NR_PA_HIGHBIT_VALUES (1 << CHIP_LOG_NUM_MSHIMS())
+#define __pa_to_highbits(pa) ((phys_addr_t)(pa) >> NR_PA_HIGHBIT_SHIFT)
+#define __pfn_to_highbits(pfn) ((pfn) >> (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT))
+
+#ifdef __tilegx__
+
+/*
+ * We reserve the lower half of memory for user-space programs, and the
+ * upper half for system code. We re-map all of physical memory in the
+ * upper half, which takes a quarter of our VA space. Then we have
+ * the vmalloc regions. The supervisor code lives at 0xfffffff700000000,
+ * with the hypervisor above that.
+ *
+ * Loadable kernel modules are placed immediately after the static
+ * supervisor code, with each being allocated a 256MB region of
+ * address space, so we don't have to worry about the range of "jal"
+ * and other branch instructions.
+ *
+ * For now we keep life simple and just allocate one pmd (4GB) for vmalloc.
+ * Similarly, for now we don't play any struct page mapping games.
+ */
+
+#if CHIP_PA_WIDTH() + 2 > CHIP_VA_WIDTH()
+# error Too much PA to map with the VA available!
+#endif
+#define HALF_VA_SPACE (_AC(1, UL) << (CHIP_VA_WIDTH() - 1))
+
+#define MEM_LOW_END (HALF_VA_SPACE - 1) /* low half */
+#define MEM_HIGH_START (-HALF_VA_SPACE) /* high half */
+#define PAGE_OFFSET MEM_HIGH_START
+#define _VMALLOC_START _AC(0xfffffff500000000, UL) /* 4 GB */
+#define HUGE_VMAP_BASE _AC(0xfffffff600000000, UL) /* 4 GB */
+#define MEM_SV_START _AC(0xfffffff700000000, UL) /* 256 MB */
+#define MEM_SV_INTRPT MEM_SV_START
+#define MEM_MODULE_START _AC(0xfffffff710000000, UL) /* 256 MB */
+#define MEM_MODULE_END (MEM_MODULE_START + (256*1024*1024))
+#define MEM_HV_START _AC(0xfffffff800000000, UL) /* 32 GB */
+
+/* Highest DTLB address we will use */
+#define KERNEL_HIGH_VADDR MEM_SV_START
+
+/* Since we don't currently provide any fixmaps, we use an impossible VA. */
+#define FIXADDR_TOP MEM_HV_START
+
+#else /* !__tilegx__ */
+
+/*
+ * A PAGE_OFFSET of 0xC0000000 means that the kernel has
+ * a virtual address space of one gigabyte, which limits the
+ * amount of physical memory you can use to about 768MB.
+ * If you want more physical memory than this then see the CONFIG_HIGHMEM
+ * option in the kernel configuration.
+ *
+ * The top two 16MB chunks in the table below (VIRT and HV) are
+ * unavailable to Linux. Since the kernel interrupt vectors must live
+ * at 0xfd000000, we map all of the bottom of RAM at this address with
+ * a huge page table entry to minimize its ITLB footprint (as well as
+ * at PAGE_OFFSET). The last architected requirement is that user
+ * interrupt vectors live at 0xfc000000, so we make that range of
+ * memory available to user processes. The remaining regions are sized
+ * as shown; after the first four addresses, we show "typical" values,
+ * since the actual addresses depend on kernel #defines.
+ *
+ * MEM_VIRT_INTRPT 0xff000000
+ * MEM_HV_INTRPT 0xfe000000
+ * MEM_SV_INTRPT (kernel code) 0xfd000000
+ * MEM_USER_INTRPT (user vector) 0xfc000000
+ * FIX_KMAP_xxx 0xf8000000 (via NR_CPUS * KM_TYPE_NR)
+ * PKMAP_BASE 0xf7000000 (via LAST_PKMAP)
+ * HUGE_VMAP 0xf3000000 (via CONFIG_NR_HUGE_VMAPS)
+ * VMALLOC_START 0xf0000000 (via __VMALLOC_RESERVE)
+ * mapped LOWMEM 0xc0000000
+ */
+
+#define MEM_USER_INTRPT _AC(0xfc000000, UL)
+#define MEM_SV_INTRPT _AC(0xfd000000, UL)
+#define MEM_HV_INTRPT _AC(0xfe000000, UL)
+#define MEM_VIRT_INTRPT _AC(0xff000000, UL)
+
+#define INTRPT_SIZE 0x4000
+
+/* Tolerate page size larger than the architecture interrupt region size. */
+#if PAGE_SIZE > INTRPT_SIZE
+#undef INTRPT_SIZE
+#define INTRPT_SIZE PAGE_SIZE
+#endif
+
+#define KERNEL_HIGH_VADDR MEM_USER_INTRPT
+#define FIXADDR_TOP (KERNEL_HIGH_VADDR - PAGE_SIZE)
+
+#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL)
+
+/* On 32-bit architectures we mix kernel modules in with other vmaps. */
+#define MEM_MODULE_START VMALLOC_START
+#define MEM_MODULE_END VMALLOC_END
+
+#endif /* __tilegx__ */
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_HIGHMEM
+
+/* Map kernel virtual addresses to page frames, in HPAGE_SIZE chunks. */
+extern unsigned long pbase_map[];
+extern void *vbase_map[];
+
+static inline unsigned long kaddr_to_pfn(const volatile void *_kaddr)
+{
+ unsigned long kaddr = (unsigned long)_kaddr;
+ return pbase_map[kaddr >> HPAGE_SHIFT] +
+ ((kaddr & (HPAGE_SIZE - 1)) >> PAGE_SHIFT);
+}
+
+static inline void *pfn_to_kaddr(unsigned long pfn)
+{
+ return vbase_map[__pfn_to_highbits(pfn)] + (pfn << PAGE_SHIFT);
+}
+
+static inline phys_addr_t virt_to_phys(const volatile void *kaddr)
+{
+ unsigned long pfn = kaddr_to_pfn(kaddr);
+ return ((phys_addr_t)pfn << PAGE_SHIFT) +
+ ((unsigned long)kaddr & (PAGE_SIZE-1));
+}
+
+static inline void *phys_to_virt(phys_addr_t paddr)
+{
+ return pfn_to_kaddr(paddr >> PAGE_SHIFT) + (paddr & (PAGE_SIZE-1));
+}
+
+/* With HIGHMEM, we pack PAGE_OFFSET through high_memory with all valid VAs. */
+static inline int virt_addr_valid(const volatile void *kaddr)
+{
+ extern void *high_memory; /* copied from <linux/mm.h> */
+ return ((unsigned long)kaddr >= PAGE_OFFSET && kaddr < high_memory);
+}
+
+#else /* !CONFIG_HIGHMEM */
+
+static inline unsigned long kaddr_to_pfn(const volatile void *kaddr)
+{
+ return ((unsigned long)kaddr - PAGE_OFFSET) >> PAGE_SHIFT;
+}
+
+static inline void *pfn_to_kaddr(unsigned long pfn)
+{
+ return (void *)((pfn << PAGE_SHIFT) + PAGE_OFFSET);
+}
+
+static inline phys_addr_t virt_to_phys(const volatile void *kaddr)
+{
+ return (phys_addr_t)((unsigned long)kaddr - PAGE_OFFSET);
+}
+
+static inline void *phys_to_virt(phys_addr_t paddr)
+{
+ return (void *)((unsigned long)paddr + PAGE_OFFSET);
+}
+
+/* Check that the given address is within some mapped range of PAs. */
+#define virt_addr_valid(kaddr) pfn_valid(kaddr_to_pfn(kaddr))
+
+#endif /* !CONFIG_HIGHMEM */
+
+/* All callers are not consistent in how they call these functions. */
+#define __pa(kaddr) virt_to_phys((void *)(unsigned long)(kaddr))
+#define __va(paddr) phys_to_virt((phys_addr_t)(paddr))
+
+extern int devmem_is_allowed(unsigned long pagenr);
+
+#ifdef CONFIG_FLATMEM
+static inline int pfn_valid(unsigned long pfn)
+{
+ return pfn < max_mapnr;
+}
+#endif
+
+/* Provide as macros since these require some other headers included. */
+#define page_to_pa(page) ((phys_addr_t)(page_to_pfn(page)) << PAGE_SHIFT)
+#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn(kaddr))
+#define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page))
+
+struct mm_struct;
+extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr);
+
+#endif /* !__ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS \
+ (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_TILE_PAGE_H */
diff --git a/arch/tile/include/asm/param.h b/arch/tile/include/asm/param.h
new file mode 100644
index 000000000000..965d45427975
--- /dev/null
+++ b/arch/tile/include/asm/param.h
@@ -0,0 +1 @@
+#include <asm-generic/param.h>
diff --git a/arch/tile/include/asm/pci-bridge.h b/arch/tile/include/asm/pci-bridge.h
new file mode 100644
index 000000000000..e853b0e2793b
--- /dev/null
+++ b/arch/tile/include/asm/pci-bridge.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PCI_BRIDGE_H
+#define _ASM_TILE_PCI_BRIDGE_H
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+
+struct device_node;
+struct pci_controller;
+
+/*
+ * pci_io_base returns the memory address at which you can access
+ * the I/O space for PCI bus number `bus' (or NULL on error).
+ */
+extern void __iomem *pci_bus_io_base(unsigned int bus);
+extern unsigned long pci_bus_io_base_phys(unsigned int bus);
+extern unsigned long pci_bus_mem_base_phys(unsigned int bus);
+
+/* Allocate a new PCI host bridge structure */
+extern struct pci_controller *pcibios_alloc_controller(void);
+
+/* Helper function for setting up resources */
+extern void pci_init_resource(struct resource *res, unsigned long start,
+ unsigned long end, int flags, char *name);
+
+/* Get the PCI host controller for a bus */
+extern struct pci_controller *pci_bus_to_hose(int bus);
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+struct pci_controller {
+ int index; /* PCI domain number */
+ struct pci_bus *root_bus;
+
+ int first_busno;
+ int last_busno;
+
+ int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */
+ int hv_mem_fd; /* fd to Hypervisor for MMIO operations */
+
+ struct pci_ops *ops;
+
+ int irq_base; /* Base IRQ from the Hypervisor */
+ int plx_gen1; /* flag for PLX Gen 1 configuration */
+
+ /* Address ranges that are routed to this controller/bridge. */
+ struct resource mem_resources[3];
+};
+
+static inline struct pci_controller *pci_bus_to_host(struct pci_bus *bus)
+{
+ return bus->sysdata;
+}
+
+extern void setup_indirect_pci_nomap(struct pci_controller *hose,
+ void __iomem *cfg_addr, void __iomem *cfg_data);
+extern void setup_indirect_pci(struct pci_controller *hose,
+ u32 cfg_addr, u32 cfg_data);
+extern void setup_grackle(struct pci_controller *hose);
+
+extern unsigned char common_swizzle(struct pci_dev *, unsigned char *);
+
+/*
+ * The following code swizzles for exactly one bridge. The routine
+ * common_swizzle below handles multiple bridges. But there are a
+ * some boards that don't follow the PCI spec's suggestion so we
+ * break this piece out separately.
+ */
+static inline unsigned char bridge_swizzle(unsigned char pin,
+ unsigned char idsel)
+{
+ return (((pin-1) + idsel) % 4) + 1;
+}
+
+/*
+ * The following macro is used to lookup irqs in a standard table
+ * format for those PPC systems that do not already have PCI
+ * interrupts properly routed.
+ */
+/* FIXME - double check this */
+#define PCI_IRQ_TABLE_LOOKUP ({ \
+ long _ctl_ = -1; \
+ if (idsel >= min_idsel && idsel <= max_idsel && pin <= irqs_per_slot) \
+ _ctl_ = pci_irq_table[idsel - min_idsel][pin-1]; \
+ _ctl_; \
+})
+
+/*
+ * Scan the buses below a given PCI host bridge and assign suitable
+ * resources to all devices found.
+ */
+extern int pciauto_bus_scan(struct pci_controller *, int);
+
+#ifdef CONFIG_PCI
+extern unsigned long pci_address_to_pio(phys_addr_t address);
+#else
+static inline unsigned long pci_address_to_pio(phys_addr_t address)
+{
+ return (unsigned long)-1;
+}
+#endif
+
+#endif /* _ASM_TILE_PCI_BRIDGE_H */
diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h
new file mode 100644
index 000000000000..b0c15da2d5d5
--- /dev/null
+++ b/arch/tile/include/asm/pci.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PCI_H
+#define _ASM_TILE_PCI_H
+
+#include <asm/pci-bridge.h>
+
+/*
+ * The hypervisor maps the entirety of CPA-space as bus addresses, so
+ * bus addresses are physical addresses. The networking and block
+ * device layers use this boolean for bounce buffer decisions.
+ */
+#define PCI_DMA_BUS_IS_PHYS 1
+
+struct pci_controller *pci_bus_to_hose(int bus);
+unsigned char __init common_swizzle(struct pci_dev *dev, unsigned char *pinp);
+int __init tile_pci_init(void);
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
+void __devinit pcibios_fixup_bus(struct pci_bus *bus);
+
+int __devinit _tile_cfg_read(struct pci_controller *hose,
+ int bus,
+ int slot,
+ int function,
+ int offset,
+ int size,
+ u32 *val);
+int __devinit _tile_cfg_write(struct pci_controller *hose,
+ int bus,
+ int slot,
+ int function,
+ int offset,
+ int size,
+ u32 val);
+
+/*
+ * These are used to to config reads and writes in the early stages of
+ * setup before the driver infrastructure has been set up enough to be
+ * able to do config reads and writes.
+ */
+#define early_cfg_read(where, size, value) \
+ _tile_cfg_read(controller, \
+ current_bus, \
+ pci_slot, \
+ pci_fn, \
+ where, \
+ size, \
+ value)
+
+#define early_cfg_write(where, size, value) \
+ _tile_cfg_write(controller, \
+ current_bus, \
+ pci_slot, \
+ pci_fn, \
+ where, \
+ size, \
+ value)
+
+
+
+#define PCICFG_BYTE 1
+#define PCICFG_WORD 2
+#define PCICFG_DWORD 4
+
+#define TILE_NUM_PCIE 2
+
+#define pci_domain_nr(bus) (((struct pci_controller *)(bus)->sysdata)->index)
+
+/*
+ * This decides whether to display the domain number in /proc.
+ */
+static inline int pci_proc_domain(struct pci_bus *bus)
+{
+ return 1;
+}
+
+/*
+ * I/O space is currently not supported.
+ */
+
+#define TILE_PCIE_LOWER_IO 0x0
+#define TILE_PCIE_UPPER_IO 0x10000
+#define TILE_PCIE_PCIE_IO_SIZE 0x0000FFFF
+
+#define _PAGE_NO_CACHE 0
+#define _PAGE_GUARDED 0
+
+
+#define pcibios_assign_all_busses() pci_assign_all_buses
+extern int pci_assign_all_buses;
+
+static inline void pcibios_set_master(struct pci_dev *dev)
+{
+ /* No special bus mastering setup handling */
+}
+
+#define PCIBIOS_MIN_MEM 0
+#define PCIBIOS_MIN_IO TILE_PCIE_LOWER_IO
+
+/*
+ * This flag tells if the platform is TILEmpower that needs
+ * special configuration for the PLX switch chip.
+ */
+extern int blade_pci;
+
+/* implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
+
+/* generic pci stuff */
+#include <asm-generic/pci.h>
+
+/* Use any cpu for PCI. */
+#define cpumask_of_pcibus(bus) cpu_online_mask
+
+#endif /* _ASM_TILE_PCI_H */
diff --git a/arch/tile/include/asm/percpu.h b/arch/tile/include/asm/percpu.h
new file mode 100644
index 000000000000..63294f5a8efb
--- /dev/null
+++ b/arch/tile/include/asm/percpu.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PERCPU_H
+#define _ASM_TILE_PERCPU_H
+
+register unsigned long __my_cpu_offset __asm__("tp");
+#define __my_cpu_offset __my_cpu_offset
+#define set_my_cpu_offset(tp) (__my_cpu_offset = (tp))
+
+#include <asm-generic/percpu.h>
+
+#endif /* _ASM_TILE_PERCPU_H */
diff --git a/arch/tile/include/asm/pgalloc.h b/arch/tile/include/asm/pgalloc.h
new file mode 100644
index 000000000000..cf52791a5501
--- /dev/null
+++ b/arch/tile/include/asm/pgalloc.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PGALLOC_H
+#define _ASM_TILE_PGALLOC_H
+
+#include <linux/threads.h>
+#include <linux/mm.h>
+#include <linux/mmzone.h>
+#include <asm/fixmap.h>
+#include <hv/hypervisor.h>
+
+/* Bits for the size of the second-level page table. */
+#define L2_KERNEL_PGTABLE_SHIFT \
+ (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL + HV_LOG2_PTE_SIZE)
+
+/* We currently allocate user L2 page tables by page (unlike kernel L2s). */
+#if L2_KERNEL_PGTABLE_SHIFT < HV_LOG2_PAGE_SIZE_SMALL
+#define L2_USER_PGTABLE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
+#else
+#define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT
+#endif
+
+/* How many pages do we need, as an "order", for a user L2 page table? */
+#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - HV_LOG2_PAGE_SIZE_SMALL)
+
+/* How big is a kernel L2 page table? */
+#define L2_KERNEL_PGTABLE_SIZE (1 << L2_KERNEL_PGTABLE_SHIFT)
+
+static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
+{
+#ifdef CONFIG_64BIT
+ set_pte_order(pmdp, pmd, L2_USER_PGTABLE_ORDER);
+#else
+ set_pte_order(&pmdp->pud.pgd, pmd.pud.pgd, L2_USER_PGTABLE_ORDER);
+#endif
+}
+
+static inline void pmd_populate_kernel(struct mm_struct *mm,
+ pmd_t *pmd, pte_t *ptep)
+{
+ set_pmd(pmd, ptfn_pmd(__pa(ptep) >> HV_LOG2_PAGE_TABLE_ALIGN,
+ __pgprot(_PAGE_PRESENT)));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+ pgtable_t page)
+{
+ set_pmd(pmd, ptfn_pmd(HV_PFN_TO_PTFN(page_to_pfn(page)),
+ __pgprot(_PAGE_PRESENT)));
+}
+
+/*
+ * Allocate and free page tables.
+ */
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
+
+extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address);
+extern void pte_free(struct mm_struct *mm, struct page *pte);
+
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+static inline pte_t *
+pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+ return pfn_to_kaddr(page_to_pfn(pte_alloc_one(mm, address)));
+}
+
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+ BUG_ON((unsigned long)pte & (PAGE_SIZE-1));
+ pte_free(mm, virt_to_page(pte));
+}
+
+extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
+ unsigned long address);
+
+#define check_pgt_cache() do { } while (0)
+
+/*
+ * Get the small-page pte_t lowmem entry for a given pfn.
+ * This may or may not be in use, depending on whether the initial
+ * huge-page entry for the page has already been shattered.
+ */
+pte_t *get_prealloc_pte(unsigned long pfn);
+
+/* During init, we can shatter kernel huge pages if needed. */
+void shatter_pmd(pmd_t *pmd);
+
+#ifdef __tilegx__
+/* We share a single page allocator for both L1 and L2 page tables. */
+#if HV_L1_SIZE != HV_L2_SIZE
+# error Rework assumption that L1 and L2 page tables are same size.
+#endif
+#define L1_USER_PGTABLE_ORDER L2_USER_PGTABLE_ORDER
+#define pud_populate(mm, pud, pmd) \
+ pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd))
+#define pmd_alloc_one(mm, addr) \
+ ((pmd_t *)page_to_virt(pte_alloc_one((mm), (addr))))
+#define pmd_free(mm, pmdp) \
+ pte_free((mm), virt_to_page(pmdp))
+#define __pmd_free_tlb(tlb, pmdp, address) \
+ __pte_free_tlb((tlb), virt_to_page(pmdp), (address))
+#endif
+
+#endif /* _ASM_TILE_PGALLOC_H */
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
new file mode 100644
index 000000000000..beb1504e9c10
--- /dev/null
+++ b/arch/tile/include/asm/pgtable.h
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This file contains the functions and defines necessary to modify and use
+ * the TILE page table tree.
+ */
+
+#ifndef _ASM_TILE_PGTABLE_H
+#define _ASM_TILE_PGTABLE_H
+
+#include <hv/hypervisor.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/bitops.h>
+#include <linux/threads.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+#include <asm/system.h>
+
+struct mm_struct;
+struct vm_area_struct;
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern pgd_t swapper_pg_dir[];
+extern pgprot_t swapper_pgprot;
+extern struct kmem_cache *pgd_cache;
+extern spinlock_t pgd_lock;
+extern struct list_head pgd_list;
+
+/*
+ * The very last slots in the pgd_t are for addresses unusable by Linux
+ * (pgd_addr_invalid() returns true). So we use them for the list structure.
+ * The x86 code we are modelled on uses the page->private/index fields
+ * (older 2.6 kernels) or the lru list (newer 2.6 kernels), but since
+ * our pgds are so much smaller than a page, it seems a waste to
+ * spend a whole page on each pgd.
+ */
+#define PGD_LIST_OFFSET \
+ ((PTRS_PER_PGD * sizeof(pgd_t)) - sizeof(struct list_head))
+#define pgd_to_list(pgd) \
+ ((struct list_head *)((char *)(pgd) + PGD_LIST_OFFSET))
+#define list_to_pgd(list) \
+ ((pgd_t *)((char *)(list) - PGD_LIST_OFFSET))
+
+extern void pgtable_cache_init(void);
+extern void paging_init(void);
+extern void set_page_homes(void);
+
+#define FIRST_USER_ADDRESS 0
+
+#define _PAGE_PRESENT HV_PTE_PRESENT
+#define _PAGE_HUGE_PAGE HV_PTE_PAGE
+#define _PAGE_READABLE HV_PTE_READABLE
+#define _PAGE_WRITABLE HV_PTE_WRITABLE
+#define _PAGE_EXECUTABLE HV_PTE_EXECUTABLE
+#define _PAGE_ACCESSED HV_PTE_ACCESSED
+#define _PAGE_DIRTY HV_PTE_DIRTY
+#define _PAGE_GLOBAL HV_PTE_GLOBAL
+#define _PAGE_USER HV_PTE_USER
+
+/*
+ * All the "standard" bits. Cache-control bits are managed elsewhere.
+ * This is used to test for valid level-2 page table pointers by checking
+ * all the bits, and to mask away the cache control bits for mprotect.
+ */
+#define _PAGE_ALL (\
+ _PAGE_PRESENT | \
+ _PAGE_HUGE_PAGE | \
+ _PAGE_READABLE | \
+ _PAGE_WRITABLE | \
+ _PAGE_EXECUTABLE | \
+ _PAGE_ACCESSED | \
+ _PAGE_DIRTY | \
+ _PAGE_GLOBAL | \
+ _PAGE_USER \
+)
+
+#define PAGE_NONE \
+ __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED)
+#define PAGE_SHARED \
+ __pgprot(_PAGE_PRESENT | _PAGE_READABLE | _PAGE_WRITABLE | \
+ _PAGE_USER | _PAGE_ACCESSED)
+
+#define PAGE_SHARED_EXEC \
+ __pgprot(_PAGE_PRESENT | _PAGE_READABLE | _PAGE_WRITABLE | \
+ _PAGE_EXECUTABLE | _PAGE_USER | _PAGE_ACCESSED)
+#define PAGE_COPY_NOEXEC \
+ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_READABLE)
+#define PAGE_COPY_EXEC \
+ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | \
+ _PAGE_READABLE | _PAGE_EXECUTABLE)
+#define PAGE_COPY \
+ PAGE_COPY_NOEXEC
+#define PAGE_READONLY \
+ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_READABLE)
+#define PAGE_READONLY_EXEC \
+ __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | \
+ _PAGE_READABLE | _PAGE_EXECUTABLE)
+
+#define _PAGE_KERNEL_RO \
+ (_PAGE_PRESENT | _PAGE_GLOBAL | _PAGE_READABLE | _PAGE_ACCESSED)
+#define _PAGE_KERNEL \
+ (_PAGE_KERNEL_RO | _PAGE_WRITABLE | _PAGE_DIRTY)
+#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXECUTABLE)
+
+#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)
+
+#define page_to_kpgprot(p) PAGE_KERNEL
+
+/*
+ * We could tighten these up, but for now writable or executable
+ * implies readable.
+ */
+#define __P000 PAGE_NONE
+#define __P001 PAGE_READONLY
+#define __P010 PAGE_COPY /* this is write-only, which we won't support */
+#define __P011 PAGE_COPY
+#define __P100 PAGE_READONLY_EXEC
+#define __P101 PAGE_READONLY_EXEC
+#define __P110 PAGE_COPY_EXEC
+#define __P111 PAGE_COPY_EXEC
+
+#define __S000 PAGE_NONE
+#define __S001 PAGE_READONLY
+#define __S010 PAGE_SHARED
+#define __S011 PAGE_SHARED
+#define __S100 PAGE_READONLY_EXEC
+#define __S101 PAGE_READONLY_EXEC
+#define __S110 PAGE_SHARED_EXEC
+#define __S111 PAGE_SHARED_EXEC
+
+/*
+ * All the normal _PAGE_ALL bits are ignored for PMDs, except PAGE_PRESENT
+ * and PAGE_HUGE_PAGE, which must be one and zero, respectively.
+ * We set the ignored bits to zero.
+ */
+#define _PAGE_TABLE _PAGE_PRESENT
+
+/* Inherit the caching flags from the old protection bits. */
+#define pgprot_modify(oldprot, newprot) \
+ (pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val }
+
+/* Just setting the PFN to zero suffices. */
+#define pte_pgprot(x) hv_pte_set_pfn((x), 0)
+
+/*
+ * For PTEs and PDEs, we must clear the Present bit first when
+ * clearing a page table entry, so clear the bottom half first and
+ * enforce ordering with a barrier.
+ */
+static inline void __pte_clear(pte_t *ptep)
+{
+#ifdef __tilegx__
+ ptep->val = 0;
+#else
+ u32 *tmp = (u32 *)ptep;
+ tmp[0] = 0;
+ barrier();
+ tmp[1] = 0;
+#endif
+}
+#define pte_clear(mm, addr, ptep) __pte_clear(ptep)
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+#define pte_present hv_pte_get_present
+#define pte_user hv_pte_get_user
+#define pte_read hv_pte_get_readable
+#define pte_dirty hv_pte_get_dirty
+#define pte_young hv_pte_get_accessed
+#define pte_write hv_pte_get_writable
+#define pte_exec hv_pte_get_executable
+#define pte_huge hv_pte_get_page
+#define pte_rdprotect hv_pte_clear_readable
+#define pte_exprotect hv_pte_clear_executable
+#define pte_mkclean hv_pte_clear_dirty
+#define pte_mkold hv_pte_clear_accessed
+#define pte_wrprotect hv_pte_clear_writable
+#define pte_mksmall hv_pte_clear_page
+#define pte_mkread hv_pte_set_readable
+#define pte_mkexec hv_pte_set_executable
+#define pte_mkdirty hv_pte_set_dirty
+#define pte_mkyoung hv_pte_set_accessed
+#define pte_mkwrite hv_pte_set_writable
+#define pte_mkhuge hv_pte_set_page
+
+#define pte_special(pte) 0
+#define pte_mkspecial(pte) (pte)
+
+/*
+ * Use some spare bits in the PTE for user-caching tags.
+ */
+#define pte_set_forcecache hv_pte_set_client0
+#define pte_get_forcecache hv_pte_get_client0
+#define pte_clear_forcecache hv_pte_clear_client0
+#define pte_set_anyhome hv_pte_set_client1
+#define pte_get_anyhome hv_pte_get_client1
+#define pte_clear_anyhome hv_pte_clear_client1
+
+/*
+ * A migrating PTE has PAGE_PRESENT clear but all the other bits preserved.
+ */
+#define pte_migrating hv_pte_get_migrating
+#define pte_mkmigrate(x) hv_pte_set_migrating(hv_pte_clear_present(x))
+#define pte_donemigrate(x) hv_pte_set_present(hv_pte_clear_migrating(x))
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte 0x%016llx.\n", __FILE__, __LINE__, pte_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd 0x%016llx.\n", __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * set_pte_order() sets the given PTE and also sanity-checks the
+ * requested PTE against the page homecaching. Unspecified parts
+ * of the PTE are filled in when it is written to memory, i.e. all
+ * caching attributes if "!forcecache", or the home cpu if "anyhome".
+ */
+extern void set_pte_order(pte_t *ptep, pte_t pte, int order);
+
+#define set_pte(ptep, pteval) set_pte_order(ptep, pteval, 0)
+#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval)
+#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
+
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+
+static inline int pte_none(pte_t pte)
+{
+ return !pte.val;
+}
+
+static inline unsigned long pte_pfn(pte_t pte)
+{
+ return hv_pte_get_pfn(pte);
+}
+
+/* Set or get the remote cache cpu in a pgprot with remote caching. */
+extern pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu);
+extern int get_remote_cache_cpu(pgprot_t prot);
+
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
+{
+ return hv_pte_set_pfn(prot, pfn);
+}
+
+/* Support for priority mappings. */
+extern void start_mm_caching(struct mm_struct *mm);
+extern void check_mm_caching(struct mm_struct *prev, struct mm_struct *next);
+
+/*
+ * Support non-linear file mappings (see sys_remap_file_pages).
+ * This is defined by CLIENT1 set but CLIENT0 and _PAGE_PRESENT clear, and the
+ * file offset in the 32 high bits.
+ */
+#define _PAGE_FILE HV_PTE_CLIENT1
+#define PTE_FILE_MAX_BITS 32
+#define pte_file(pte) (hv_pte_get_client1(pte) && !hv_pte_get_client0(pte))
+#define pte_to_pgoff(pte) ((pte).val >> 32)
+#define pgoff_to_pte(off) ((pte_t) { (((long long)(off)) << 32) | _PAGE_FILE })
+
+/*
+ * Encode and de-code a swap entry (see <linux/swapops.h>).
+ * We put the swap file type+offset in the 32 high bits;
+ * I believe we can just leave the low bits clear.
+ */
+#define __swp_type(swp) ((swp).val & 0x1f)
+#define __swp_offset(swp) ((swp).val >> 5)
+#define __swp_entry(type, off) ((swp_entry_t) { (type) | ((off) << 5) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).val >> 32 })
+#define __swp_entry_to_pte(swp) ((pte_t) { (((long long) ((swp).val)) << 32) })
+
+/*
+ * clone_pgd_range(pgd_t *dst, pgd_t *src, int count);
+ *
+ * dst - pointer to pgd range anwhere on a pgd page
+ * src - ""
+ * count - the number of pgds to copy.
+ *
+ * dst and src can be on the same page, but the range must not overlap,
+ * and must not cross a page boundary.
+ */
+static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count)
+{
+ memcpy(dst, src, count * sizeof(pgd_t));
+}
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+
+#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
+
+/*
+ * If we are doing an mprotect(), just accept the new vma->vm_page_prot
+ * value and combine it with the PFN from the old PTE to get a new PTE.
+ */
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return pfn_pte(hv_pte_get_pfn(pte), newprot);
+}
+
+/*
+ * The pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
+ *
+ * This macro returns the index of the entry in the pgd page which would
+ * control the given virtual address.
+ */
+#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+
+/*
+ * pgd_offset() returns a (pgd_t *)
+ * pgd_index() is used get the offset into the pgd page's array of pgd_t's.
+ */
+#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
+
+/*
+ * A shortcut which implies the use of the kernel's pgd, instead
+ * of a process's.
+ */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+#if defined(CONFIG_HIGHPTE)
+extern pte_t *_pte_offset_map(pmd_t *, unsigned long address, enum km_type);
+#define pte_offset_map(dir, address) \
+ _pte_offset_map(dir, address, KM_PTE0)
+#define pte_offset_map_nested(dir, address) \
+ _pte_offset_map(dir, address, KM_PTE1)
+#define pte_unmap(pte) kunmap_atomic(pte, KM_PTE0)
+#define pte_unmap_nested(pte) kunmap_atomic(pte, KM_PTE1)
+#else
+#define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
+#define pte_offset_map_nested(dir, address) pte_offset_map(dir, address)
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
+#endif
+
+/* Clear a non-executable kernel PTE and flush it from the TLB. */
+#define kpte_clear_flush(ptep, vaddr) \
+do { \
+ pte_clear(&init_mm, (vaddr), (ptep)); \
+ local_flush_tlb_page(FLUSH_NONEXEC, (vaddr), PAGE_SIZE); \
+} while (0)
+
+/*
+ * The kernel page tables contain what we need, and we flush when we
+ * change specific page table entries.
+ */
+#define update_mmu_cache(vma, address, pte) do { } while (0)
+
+#ifdef CONFIG_FLATMEM
+#define kern_addr_valid(addr) (1)
+#endif /* CONFIG_FLATMEM */
+
+#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
+ remap_pfn_range(vma, vaddr, pfn, size, prot)
+
+extern void vmalloc_sync_all(void);
+
+#endif /* !__ASSEMBLY__ */
+
+#ifdef __tilegx__
+#include <asm/pgtable_64.h>
+#else
+#include <asm/pgtable_32.h>
+#endif
+
+#ifndef __ASSEMBLY__
+
+static inline int pmd_none(pmd_t pmd)
+{
+ /*
+ * Only check low word on 32-bit platforms, since it might be
+ * out of sync with upper half.
+ */
+ return (unsigned long)pmd_val(pmd) == 0;
+}
+
+static inline int pmd_present(pmd_t pmd)
+{
+ return pmd_val(pmd) & _PAGE_PRESENT;
+}
+
+static inline int pmd_bad(pmd_t pmd)
+{
+ return ((pmd_val(pmd) & _PAGE_ALL) != _PAGE_TABLE);
+}
+
+static inline unsigned long pages_to_mb(unsigned long npg)
+{
+ return npg >> (20 - PAGE_SHIFT);
+}
+
+/*
+ * The pmd can be thought of an array like this: pmd_t[PTRS_PER_PMD]
+ *
+ * This function returns the index of the entry in the pmd which would
+ * control the given virtual address.
+ */
+static inline unsigned long pmd_index(unsigned long address)
+{
+ return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
+}
+
+/*
+ * A given kernel pmd_t maps to a specific virtual address (either a
+ * kernel huge page or a kernel pte_t table). Since kernel pte_t
+ * tables can be aligned at sub-page granularity, this function can
+ * return non-page-aligned pointers, despite its name.
+ */
+static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+{
+ phys_addr_t pa =
+ (phys_addr_t)pmd_ptfn(pmd) << HV_LOG2_PAGE_TABLE_ALIGN;
+ return (unsigned long)__va(pa);
+}
+
+/*
+ * A pmd_t points to the base of a huge page or to a pte_t array.
+ * If a pte_t array, since we can have multiple per page, we don't
+ * have a one-to-one mapping of pmd_t's to pages. However, this is
+ * OK for pte_lockptr(), since we just end up with potentially one
+ * lock being used for several pte_t arrays.
+ */
+#define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd)))
+
+/*
+ * The pte page can be thought of an array like this: pte_t[PTRS_PER_PTE]
+ *
+ * This macro returns the index of the entry in the pte page which would
+ * control the given virtual address.
+ */
+static inline unsigned long pte_index(unsigned long address)
+{
+ return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+}
+
+static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address)
+{
+ return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address);
+}
+
+static inline int pmd_huge_page(pmd_t pmd)
+{
+ return pmd_val(pmd) & _PAGE_HUGE_PAGE;
+}
+
+#include <asm-generic/pgtable.h>
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_PGTABLE_H */
diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h
new file mode 100644
index 000000000000..b935fb2ad4f3
--- /dev/null
+++ b/arch/tile/include/asm/pgtable_32.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _ASM_TILE_PGTABLE_32_H
+#define _ASM_TILE_PGTABLE_32_H
+
+/*
+ * The level-1 index is defined by the huge page size. A PGD is composed
+ * of PTRS_PER_PGD pgd_t's and is the top level of the page table.
+ */
+#define PGDIR_SHIFT HV_LOG2_PAGE_SIZE_LARGE
+#define PGDIR_SIZE HV_PAGE_SIZE_LARGE
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD (1 << (32 - PGDIR_SHIFT))
+
+/*
+ * The level-2 index is defined by the difference between the huge
+ * page size and the normal page size. A PTE is composed of
+ * PTRS_PER_PTE pte_t's and is the bottom level of the page table.
+ * Note that the hypervisor docs use PTE for what we call pte_t, so
+ * this nomenclature is somewhat confusing.
+ */
+#define PTRS_PER_PTE (1 << (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Right now we initialize only a single pte table. It can be extended
+ * easily, subsequent pte tables have to be allocated in one physical
+ * chunk of RAM.
+ *
+ * HOWEVER, if we are using an allocation scheme with slop after the
+ * end of the page table (e.g. where our L2 page tables are 2KB but
+ * our pages are 64KB and we are allocating via the page allocator)
+ * we can't extend it easily.
+ */
+#define LAST_PKMAP PTRS_PER_PTE
+
+#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE*LAST_PKMAP) & PGDIR_MASK)
+
+#ifdef CONFIG_HIGHMEM
+# define __VMAPPING_END (PKMAP_BASE & ~(HPAGE_SIZE-1))
+#else
+# define __VMAPPING_END (FIXADDR_START & ~(HPAGE_SIZE-1))
+#endif
+
+#ifdef CONFIG_HUGEVMAP
+#define HUGE_VMAP_END __VMAPPING_END
+#define HUGE_VMAP_BASE (HUGE_VMAP_END - CONFIG_NR_HUGE_VMAPS * HPAGE_SIZE)
+#define _VMALLOC_END HUGE_VMAP_BASE
+#else
+#define _VMALLOC_END __VMAPPING_END
+#endif
+
+/*
+ * Align the vmalloc area to an L2 page table, and leave a guard page
+ * at the beginning and end. The vmalloc code also puts in an internal
+ * guard page between each allocation.
+ */
+#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE)
+extern unsigned long VMALLOC_RESERVE /* = CONFIG_VMALLOC_RESERVE */;
+#define _VMALLOC_START (_VMALLOC_END - VMALLOC_RESERVE)
+#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE)
+
+/* This is the maximum possible amount of lowmem. */
+#define MAXMEM (_VMALLOC_START - PAGE_OFFSET)
+
+/* We have no pmd or pud since we are strictly a two-level page table */
+#include <asm-generic/pgtable-nopmd.h>
+
+/* We don't define any pgds for these addresses. */
+static inline int pgd_addr_invalid(unsigned long addr)
+{
+ return addr >= MEM_HV_INTRPT;
+}
+
+/*
+ * Provide versions of these routines that can be used safely when
+ * the hypervisor may be asynchronously modifying dirty/accessed bits.
+ */
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+
+extern int ptep_test_and_clear_young(struct vm_area_struct *,
+ unsigned long addr, pte_t *);
+extern void ptep_set_wrprotect(struct mm_struct *,
+ unsigned long addr, pte_t *);
+
+/* Create a pmd from a PTFN. */
+static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot)
+{
+ return (pmd_t){ { hv_pte_set_ptfn(prot, ptfn) } };
+}
+
+/* Return the page-table frame number (ptfn) that a pmd_t points at. */
+#define pmd_ptfn(pmd) hv_pte_get_ptfn((pmd).pud.pgd)
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ __pte_clear(&pmdp->pud.pgd);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_PGTABLE_32_H */
diff --git a/arch/tile/include/asm/poll.h b/arch/tile/include/asm/poll.h
new file mode 100644
index 000000000000..c98509d3149e
--- /dev/null
+++ b/arch/tile/include/asm/poll.h
@@ -0,0 +1 @@
+#include <asm-generic/poll.h>
diff --git a/arch/tile/include/asm/posix_types.h b/arch/tile/include/asm/posix_types.h
new file mode 100644
index 000000000000..22cae6230ceb
--- /dev/null
+++ b/arch/tile/include/asm/posix_types.h
@@ -0,0 +1 @@
+#include <asm-generic/posix_types.h>
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
new file mode 100644
index 000000000000..96c50d2c4c2b
--- /dev/null
+++ b/arch/tile/include/asm/processor.h
@@ -0,0 +1,339 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PROCESSOR_H
+#define _ASM_TILE_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * NOTE: we don't include <linux/ptrace.h> or <linux/percpu.h> as one
+ * normally would, due to #include dependencies.
+ */
+#include <asm/ptrace.h>
+#include <asm/percpu.h>
+
+#include <arch/chip.h>
+#include <arch/spr_def.h>
+
+struct task_struct;
+struct thread_struct;
+struct list_head;
+
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+void *current_text_addr(void);
+
+#if CHIP_HAS_TILE_DMA()
+/* Capture the state of a suspended DMA. */
+struct tile_dma_state {
+ int enabled;
+ unsigned long src;
+ unsigned long dest;
+ unsigned long strides;
+ unsigned long chunk_size;
+ unsigned long src_chunk;
+ unsigned long dest_chunk;
+ unsigned long byte;
+ unsigned long status;
+};
+
+/*
+ * A mask of the DMA status register for selecting only the 'running'
+ * and 'done' bits.
+ */
+#define DMA_STATUS_MASK \
+ (SPR_DMA_STATUS__RUNNING_MASK | SPR_DMA_STATUS__DONE_MASK)
+#endif
+
+/*
+ * Track asynchronous TLB events (faults and access violations)
+ * that occur while we are in kernel mode from DMA or the SN processor.
+ */
+struct async_tlb {
+ short fault_num; /* original fault number; 0 if none */
+ char is_fault; /* was it a fault (vs an access violation) */
+ char is_write; /* for fault: was it caused by a write? */
+ unsigned long address; /* what address faulted? */
+};
+
+
+struct thread_struct {
+ /* kernel stack pointer */
+ unsigned long ksp;
+ /* kernel PC */
+ unsigned long pc;
+ /* starting user stack pointer (for page migration) */
+ unsigned long usp0;
+ /* pid of process that created this one */
+ pid_t creator_pid;
+#if CHIP_HAS_TILE_DMA()
+ /* DMA info for suspended threads (byte == 0 means no DMA state) */
+ struct tile_dma_state tile_dma_state;
+#endif
+ /* User EX_CONTEXT registers */
+ unsigned long ex_context[2];
+ /* User SYSTEM_SAVE registers */
+ unsigned long system_save[4];
+ /* User interrupt mask */
+ unsigned long long interrupt_mask;
+ /* User interrupt-control 0 state */
+ unsigned long intctrl_0;
+#if CHIP_HAS_PROC_STATUS_SPR()
+ /* Any other miscellaneous processor state bits */
+ unsigned long proc_status;
+#endif
+#if CHIP_HAS_TILE_DMA()
+ /* Async DMA TLB fault information */
+ struct async_tlb dma_async_tlb;
+#endif
+#if CHIP_HAS_SN_PROC()
+ /* Was static network processor when we were switched out? */
+ int sn_proc_running;
+ /* Async SNI TLB fault information */
+ struct async_tlb sn_async_tlb;
+#endif
+};
+
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * Start with "sp" this many bytes below the top of the kernel stack.
+ * This preserves the invariant that a called function may write to *sp.
+ */
+#define STACK_TOP_DELTA 8
+
+/*
+ * When entering the kernel via a fault, start with the top of the
+ * pt_regs structure this many bytes below the top of the page.
+ * This aligns the pt_regs structure optimally for cache-line access.
+ */
+#ifdef __tilegx__
+#define KSTK_PTREGS_GAP 48
+#else
+#define KSTK_PTREGS_GAP 56
+#endif
+
+#ifndef __ASSEMBLY__
+
+#ifdef __tilegx__
+#define TASK_SIZE_MAX (MEM_LOW_END + 1)
+#else
+#define TASK_SIZE_MAX PAGE_OFFSET
+#endif
+
+/* TASK_SIZE and related variables are always checked in "current" context. */
+#ifdef CONFIG_COMPAT
+#define COMPAT_TASK_SIZE (1UL << 31)
+#define TASK_SIZE ((current_thread_info()->status & TS_COMPAT) ?\
+ COMPAT_TASK_SIZE : TASK_SIZE_MAX)
+#else
+#define TASK_SIZE TASK_SIZE_MAX
+#endif
+
+/* We provide a minimal "vdso" a la x86; just the sigreturn code for now. */
+#define VDSO_BASE (TASK_SIZE - PAGE_SIZE)
+
+#define STACK_TOP VDSO_BASE
+
+/* STACK_TOP_MAX is used temporarily in execve and should not check COMPAT. */
+#define STACK_TOP_MAX TASK_SIZE_MAX
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's, if it is using bottom-up mapping.
+ */
+#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
+
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
+#define INIT_THREAD { \
+ .ksp = (unsigned long)init_stack + THREAD_SIZE - STACK_TOP_DELTA, \
+ .interrupt_mask = -1ULL \
+}
+
+/* Kernel stack top for the task that first boots on this cpu. */
+DECLARE_PER_CPU(unsigned long, boot_sp);
+
+/* PC to boot from on this cpu. */
+DECLARE_PER_CPU(unsigned long, boot_pc);
+
+/* Do necessary setup to start up a newly executed thread. */
+static inline void start_thread(struct pt_regs *regs,
+ unsigned long pc, unsigned long usp)
+{
+ regs->pc = pc;
+ regs->sp = usp;
+}
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+ /* Nothing for now */
+}
+
+/* Prepare to copy thread state - unlazy all lazy status. */
+#define prepare_to_copy(tsk) do { } while (0)
+
+extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
+
+/* Helper routines for setting home cache modes at exec() time. */
+
+
+/*
+ * Return saved (kernel) PC of a blocked thread.
+ * Only used in a printk() in kernel/sched.c, so don't work too hard.
+ */
+#define thread_saved_pc(t) ((t)->thread.pc)
+
+unsigned long get_wchan(struct task_struct *p);
+
+/* Return initial ksp value for given task. */
+#define task_ksp0(task) ((unsigned long)(task)->stack + THREAD_SIZE)
+
+/* Return some info about the user process TASK. */
+#define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA)
+#define task_pt_regs(task) \
+ ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1)
+#define task_sp(task) (task_pt_regs(task)->sp)
+#define task_pc(task) (task_pt_regs(task)->pc)
+/* Aliases for pc and sp (used in fs/proc/array.c) */
+#define KSTK_EIP(task) task_pc(task)
+#define KSTK_ESP(task) task_sp(task)
+
+/* Standard format for printing registers and other word-size data. */
+#ifdef __tilegx__
+# define REGFMT "0x%016lx"
+#else
+# define REGFMT "0x%08lx"
+#endif
+
+/*
+ * Do some slow action (e.g. read a slow SPR).
+ * Note that this must also have compiler-barrier semantics since
+ * it may be used in a busy loop reading memory.
+ */
+static inline void cpu_relax(void)
+{
+ __insn_mfspr(SPR_PASS);
+ barrier();
+}
+
+struct siginfo;
+extern void arch_coredump_signal(struct siginfo *, struct pt_regs *);
+#define arch_coredump_signal arch_coredump_signal
+
+/* Provide information about the chip model. */
+extern char chip_model[64];
+
+/* Data on which physical memory controller corresponds to which NUMA node. */
+extern int node_controller[];
+
+
+/* Do we dump information to the console when a user application crashes? */
+extern int show_crashinfo;
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+/* Does the heap allocator return hash-for-home pages by default? */
+extern int hash_default;
+
+/* Should kernel stack pages be hash-for-home? */
+extern int kstack_hash;
+#else
+#define hash_default 0
+#define kstack_hash 0
+#endif
+
+/* Are we using huge pages in the TLB for kernel data? */
+extern int kdata_huge;
+
+/*
+ * Note that with OLOC the prefetch will return an unused read word to
+ * the issuing tile, which will cause some MDN traffic. Benchmarking
+ * should be done to see whether this outweighs prefetching.
+ */
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+#define ARCH_HAS_SPINLOCK_PREFETCH
+
+#define prefetch(ptr) __builtin_prefetch((ptr), 0, 3)
+#define prefetchw(ptr) __builtin_prefetch((ptr), 1, 3)
+
+#ifdef CONFIG_SMP
+#define spin_lock_prefetch(ptr) prefetchw(ptr)
+#else
+/* Nothing to prefetch. */
+#define spin_lock_prefetch(lock) do { } while (0)
+#endif
+
+#else /* __ASSEMBLY__ */
+
+/* Do some slow action (e.g. read a slow SPR). */
+#define CPU_RELAX mfspr zero, SPR_PASS
+
+#endif /* !__ASSEMBLY__ */
+
+/* Assembly code assumes that the PL is in the low bits. */
+#if SPR_EX_CONTEXT_1_1__PL_SHIFT != 0
+# error Fix assembly assumptions about PL
+#endif
+
+/* We sometimes use these macros for EX_CONTEXT_0_1 as well. */
+#if SPR_EX_CONTEXT_1_1__PL_SHIFT != SPR_EX_CONTEXT_0_1__PL_SHIFT || \
+ SPR_EX_CONTEXT_1_1__PL_RMASK != SPR_EX_CONTEXT_0_1__PL_RMASK || \
+ SPR_EX_CONTEXT_1_1__ICS_SHIFT != SPR_EX_CONTEXT_0_1__ICS_SHIFT || \
+ SPR_EX_CONTEXT_1_1__ICS_RMASK != SPR_EX_CONTEXT_0_1__ICS_RMASK
+# error Fix assumptions that EX1 macros work for both PL0 and PL1
+#endif
+
+/* Allow pulling apart and recombining the PL and ICS bits in EX_CONTEXT. */
+#define EX1_PL(ex1) \
+ (((ex1) >> SPR_EX_CONTEXT_1_1__PL_SHIFT) & SPR_EX_CONTEXT_1_1__PL_RMASK)
+#define EX1_ICS(ex1) \
+ (((ex1) >> SPR_EX_CONTEXT_1_1__ICS_SHIFT) & SPR_EX_CONTEXT_1_1__ICS_RMASK)
+#define PL_ICS_EX1(pl, ics) \
+ (((pl) << SPR_EX_CONTEXT_1_1__PL_SHIFT) | \
+ ((ics) << SPR_EX_CONTEXT_1_1__ICS_SHIFT))
+
+/*
+ * Provide symbolic constants for PLs.
+ * Note that assembly code assumes that USER_PL is zero.
+ */
+#define USER_PL 0
+#define KERNEL_PL 1
+
+/* SYSTEM_SAVE_1_0 holds the current cpu number ORed with ksp0. */
+#define CPU_LOG_MASK_VALUE 12
+#define CPU_MASK_VALUE ((1 << CPU_LOG_MASK_VALUE) - 1)
+#if CONFIG_NR_CPUS > CPU_MASK_VALUE
+# error Too many cpus!
+#endif
+#define raw_smp_processor_id() \
+ ((int)__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & CPU_MASK_VALUE)
+#define get_current_ksp0() \
+ (__insn_mfspr(SPR_SYSTEM_SAVE_1_0) & ~CPU_MASK_VALUE)
+#define next_current_ksp0(task) ({ \
+ unsigned long __ksp0 = task_ksp0(task); \
+ int __cpu = raw_smp_processor_id(); \
+ BUG_ON(__ksp0 & CPU_MASK_VALUE); \
+ __ksp0 | __cpu; \
+})
+
+#endif /* _ASM_TILE_PROCESSOR_H */
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h
new file mode 100644
index 000000000000..4d1d9953016a
--- /dev/null
+++ b/arch/tile/include/asm/ptrace.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_PTRACE_H
+#define _ASM_TILE_PTRACE_H
+
+#include <arch/chip.h>
+#include <arch/abi.h>
+
+/* These must match struct pt_regs, below. */
+#if CHIP_WORD_SIZE() == 32
+#define PTREGS_OFFSET_REG(n) ((n)*4)
+#else
+#define PTREGS_OFFSET_REG(n) ((n)*8)
+#endif
+#define PTREGS_OFFSET_BASE 0
+#define PTREGS_OFFSET_TP PTREGS_OFFSET_REG(53)
+#define PTREGS_OFFSET_SP PTREGS_OFFSET_REG(54)
+#define PTREGS_OFFSET_LR PTREGS_OFFSET_REG(55)
+#define PTREGS_NR_GPRS 56
+#define PTREGS_OFFSET_PC PTREGS_OFFSET_REG(56)
+#define PTREGS_OFFSET_EX1 PTREGS_OFFSET_REG(57)
+#define PTREGS_OFFSET_FAULTNUM PTREGS_OFFSET_REG(58)
+#define PTREGS_OFFSET_ORIG_R0 PTREGS_OFFSET_REG(59)
+#define PTREGS_OFFSET_FLAGS PTREGS_OFFSET_REG(60)
+#if CHIP_HAS_CMPEXCH()
+#define PTREGS_OFFSET_CMPEXCH PTREGS_OFFSET_REG(61)
+#endif
+#define PTREGS_SIZE PTREGS_OFFSET_REG(64)
+
+#ifndef __ASSEMBLY__
+
+#ifdef __KERNEL__
+/* Benefit from consistent use of "long" on all chips. */
+typedef unsigned long pt_reg_t;
+#else
+/* Provide appropriate length type to userspace regardless of -m32/-m64. */
+typedef uint_reg_t pt_reg_t;
+#endif
+
+/*
+ * This struct defines the way the registers are stored on the stack during a
+ * system call/exception. It should be a multiple of 8 bytes to preserve
+ * normal stack alignment rules.
+ *
+ * Must track <sys/ucontext.h> and <sys/procfs.h>
+ */
+struct pt_regs {
+ /* Saved main processor registers; 56..63 are special. */
+ /* tp, sp, and lr must immediately follow regs[] for aliasing. */
+ pt_reg_t regs[53];
+ pt_reg_t tp; /* aliases regs[TREG_TP] */
+ pt_reg_t sp; /* aliases regs[TREG_SP] */
+ pt_reg_t lr; /* aliases regs[TREG_LR] */
+
+ /* Saved special registers. */
+ pt_reg_t pc; /* stored in EX_CONTEXT_1_0 */
+ pt_reg_t ex1; /* stored in EX_CONTEXT_1_1 (PL and ICS bit) */
+ pt_reg_t faultnum; /* fault number (INT_SWINT_1 for syscall) */
+ pt_reg_t orig_r0; /* r0 at syscall entry, else zero */
+ pt_reg_t flags; /* flags (see below) */
+#if !CHIP_HAS_CMPEXCH()
+ pt_reg_t pad[3];
+#else
+ pt_reg_t cmpexch; /* value of CMPEXCH_VALUE SPR at interrupt */
+ pt_reg_t pad[2];
+#endif
+};
+
+#endif /* __ASSEMBLY__ */
+
+/* Flag bits in pt_regs.flags */
+#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */
+#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */
+#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */
+
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+
+/* Support TILE-specific ptrace options, with events starting at 16. */
+#define PTRACE_O_TRACEMIGRATE 0x00010000
+#define PTRACE_EVENT_MIGRATE 16
+#ifdef __KERNEL__
+#define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE)
+#define PT_TRACE_MIGRATE 0x00080000
+#define PT_TRACE_MASK_TILE (PT_TRACE_MIGRATE)
+#endif
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+
+#define instruction_pointer(regs) ((regs)->pc)
+#define profile_pc(regs) instruction_pointer(regs)
+
+/* Does the process account for user or for system time? */
+#define user_mode(regs) (EX1_PL((regs)->ex1) == USER_PL)
+
+/* Fill in a struct pt_regs with the current kernel registers. */
+struct pt_regs *get_pt_regs(struct pt_regs *);
+
+extern void show_regs(struct pt_regs *);
+
+#define arch_has_single_step() (1)
+
+/*
+ * A structure for all single-stepper state.
+ *
+ * Also update defines in assembler section if it changes
+ */
+struct single_step_state {
+ /* the page to which we will write hacked-up bundles */
+ void *buffer;
+
+ union {
+ int flags;
+ struct {
+ unsigned long is_enabled:1, update:1, update_reg:6;
+ };
+ };
+
+ unsigned long orig_pc; /* the original PC */
+ unsigned long next_pc; /* return PC if no branch (PC + 1) */
+ unsigned long branch_next_pc; /* return PC if we did branch/jump */
+ unsigned long update_value; /* value to restore to update_target */
+};
+
+/* Single-step the instruction at regs->pc */
+extern void single_step_once(struct pt_regs *regs);
+
+struct task_struct;
+
+extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+ int error_code);
+
+#ifdef __tilegx__
+/* We need this since sigval_t has a user pointer in it, for GETSIGINFO etc. */
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#define SINGLESTEP_STATE_MASK_IS_ENABLED 0x1
+#define SINGLESTEP_STATE_MASK_UPDATE 0x2
+#define SINGLESTEP_STATE_TARGET_LB 2
+#define SINGLESTEP_STATE_TARGET_UB 7
+
+#endif /* !__KERNEL__ */
+
+#endif /* _ASM_TILE_PTRACE_H */
diff --git a/arch/tile/include/asm/resource.h b/arch/tile/include/asm/resource.h
new file mode 100644
index 000000000000..04bc4db8921b
--- /dev/null
+++ b/arch/tile/include/asm/resource.h
@@ -0,0 +1 @@
+#include <asm-generic/resource.h>
diff --git a/arch/tile/include/asm/scatterlist.h b/arch/tile/include/asm/scatterlist.h
new file mode 100644
index 000000000000..c5604242c0d5
--- /dev/null
+++ b/arch/tile/include/asm/scatterlist.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SCATTERLIST_H
+#define _ASM_TILE_SCATTERLIST_H
+
+#define ISA_DMA_THRESHOLD (~0UL)
+
+#include <asm-generic/scatterlist.h>
+
+#endif /* _ASM_TILE_SCATTERLIST_H */
diff --git a/arch/tile/include/asm/sections.h b/arch/tile/include/asm/sections.h
new file mode 100644
index 000000000000..6c111491f0ed
--- /dev/null
+++ b/arch/tile/include/asm/sections.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SECTIONS_H
+#define _ASM_TILE_SECTIONS_H
+
+#define arch_is_kernel_data arch_is_kernel_data
+
+#include <asm-generic/sections.h>
+
+/* Text and data are at different areas in the kernel VA space. */
+extern char _sinitdata[], _einitdata[];
+
+/* Write-once data is writable only till the end of initialization. */
+extern char __w1data_begin[], __w1data_end[];
+
+extern char __feedback_section_start[], __feedback_section_end[];
+
+/* Handle the discontiguity between _sdata and _stext. */
+static inline int arch_is_kernel_data(unsigned long addr)
+{
+ return addr >= (unsigned long)_sdata &&
+ addr < (unsigned long)_end;
+}
+
+#endif /* _ASM_TILE_SECTIONS_H */
diff --git a/arch/tile/include/asm/sembuf.h b/arch/tile/include/asm/sembuf.h
new file mode 100644
index 000000000000..7673b83cfef7
--- /dev/null
+++ b/arch/tile/include/asm/sembuf.h
@@ -0,0 +1 @@
+#include <asm-generic/sembuf.h>
diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h
new file mode 100644
index 000000000000..823ddd47ff6e
--- /dev/null
+++ b/arch/tile/include/asm/setup.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SETUP_H
+#define _ASM_TILE_SETUP_H
+
+#include <linux/pfn.h>
+#include <linux/init.h>
+
+/*
+ * Reserved space for vmalloc and iomap - defined in asm/page.h
+ */
+#define MAXMEM_PFN PFN_DOWN(MAXMEM)
+
+#define COMMAND_LINE_SIZE 2048
+
+void early_panic(const char *fmt, ...);
+void warn_early_printk(void);
+void __init disable_early_printk(void);
+
+#endif /* _ASM_TILE_SETUP_H */
diff --git a/arch/tile/include/asm/shmbuf.h b/arch/tile/include/asm/shmbuf.h
new file mode 100644
index 000000000000..83c05fc2de38
--- /dev/null
+++ b/arch/tile/include/asm/shmbuf.h
@@ -0,0 +1 @@
+#include <asm-generic/shmbuf.h>
diff --git a/arch/tile/include/asm/shmparam.h b/arch/tile/include/asm/shmparam.h
new file mode 100644
index 000000000000..93f30deb95d0
--- /dev/null
+++ b/arch/tile/include/asm/shmparam.h
@@ -0,0 +1 @@
+#include <asm-generic/shmparam.h>
diff --git a/arch/tile/include/asm/sigcontext.h b/arch/tile/include/asm/sigcontext.h
new file mode 100644
index 000000000000..7cd7672e3ad4
--- /dev/null
+++ b/arch/tile/include/asm/sigcontext.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SIGCONTEXT_H
+#define _ASM_TILE_SIGCONTEXT_H
+
+/* NOTE: we can't include <linux/ptrace.h> due to #include dependencies. */
+#include <asm/ptrace.h>
+
+/* Must track <sys/ucontext.h> */
+
+struct sigcontext {
+ struct pt_regs regs;
+};
+
+#endif /* _ASM_TILE_SIGCONTEXT_H */
diff --git a/arch/tile/include/asm/sigframe.h b/arch/tile/include/asm/sigframe.h
new file mode 100644
index 000000000000..994d3d30205f
--- /dev/null
+++ b/arch/tile/include/asm/sigframe.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SIGFRAME_H
+#define _ASM_TILE_SIGFRAME_H
+
+/* Indicate that syscall return should not examine r0 */
+#define INT_SWINT_1_SIGRETURN (~0)
+
+#ifndef __ASSEMBLY__
+
+#include <arch/abi.h>
+
+struct rt_sigframe {
+ unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_SIGFRAME_H */
diff --git a/arch/tile/include/asm/siginfo.h b/arch/tile/include/asm/siginfo.h
new file mode 100644
index 000000000000..0c12d1b9ddf2
--- /dev/null
+++ b/arch/tile/include/asm/siginfo.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SIGINFO_H
+#define _ASM_TILE_SIGINFO_H
+
+#define __ARCH_SI_TRAPNO
+
+#include <asm-generic/siginfo.h>
+
+/*
+ * Additional Tile-specific SIGILL si_codes
+ */
+#define ILL_DBLFLT (__SI_FAULT|9) /* double fault */
+#define ILL_HARDWALL (__SI_FAULT|10) /* user networks hardwall violation */
+#undef NSIGILL
+#define NSIGILL 10
+
+#endif /* _ASM_TILE_SIGINFO_H */
diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h
new file mode 100644
index 000000000000..d20d326d201b
--- /dev/null
+++ b/arch/tile/include/asm/signal.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SIGNAL_H
+#define _ASM_TILE_SIGNAL_H
+
+/* Do not notify a ptracer when this signal is handled. */
+#define SA_NOPTRACE 0x02000000u
+
+/* Used in earlier Tilera releases, so keeping for binary compatibility. */
+#define SA_RESTORER 0x04000000u
+
+#include <asm-generic/signal.h>
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+int restore_sigcontext(struct pt_regs *, struct sigcontext __user *, long *);
+int setup_sigcontext(struct sigcontext __user *, struct pt_regs *);
+#endif
+
+#endif /* _ASM_TILE_SIGNAL_H */
diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h
new file mode 100644
index 000000000000..da24858a7392
--- /dev/null
+++ b/arch/tile/include/asm/smp.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SMP_H
+#define _ASM_TILE_SMP_H
+
+#ifdef CONFIG_SMP
+
+#include <asm/processor.h>
+#include <linux/cpumask.h>
+#include <linux/irqreturn.h>
+
+/* Set up this tile to support receiving hypervisor messages */
+void init_messaging(void);
+
+/* Set up this tile to support receiving device interrupts and IPIs. */
+void init_per_tile_IRQs(void);
+
+/* Send a message to processors specified in mask */
+void send_IPI_many(const struct cpumask *mask, int tag);
+
+/* Send a message to all but the sending processor */
+void send_IPI_allbutself(int tag);
+
+/* Send a message to a specific processor */
+void send_IPI_single(int dest, int tag);
+
+/* Process an IPI message */
+void evaluate_message(int tag);
+
+/* Process an IRQ_RESCHEDULE IPI. */
+irqreturn_t handle_reschedule_ipi(int irq, void *token);
+
+/* Boot a secondary cpu */
+void online_secondary(void);
+
+/* Call a function on a specified set of CPUs (may include this one). */
+extern void on_each_cpu_mask(const struct cpumask *mask,
+ void (*func)(void *), void *info, bool wait);
+
+/* Topology of the supervisor tile grid, and coordinates of boot processor */
+extern HV_Topology smp_topology;
+
+/* Accessors for grid size */
+#define smp_height (smp_topology.height)
+#define smp_width (smp_topology.width)
+
+/* Hypervisor message tags sent via the tile send_IPI*() routines. */
+#define MSG_TAG_START_CPU 1
+#define MSG_TAG_STOP_CPU 2
+#define MSG_TAG_CALL_FUNCTION_MANY 3
+#define MSG_TAG_CALL_FUNCTION_SINGLE 4
+
+/* Hook for the generic smp_call_function_many() routine. */
+static inline void arch_send_call_function_ipi_mask(struct cpumask *mask)
+{
+ send_IPI_many(mask, MSG_TAG_CALL_FUNCTION_MANY);
+}
+
+/* Hook for the generic smp_call_function_single() routine. */
+static inline void arch_send_call_function_single_ipi(int cpu)
+{
+ send_IPI_single(cpu, MSG_TAG_CALL_FUNCTION_SINGLE);
+}
+
+/* Print out the boot string describing which cpus were disabled. */
+void print_disabled_cpus(void);
+
+#else /* !CONFIG_SMP */
+
+#define on_each_cpu_mask(mask, func, info, wait) \
+ do { if (cpumask_test_cpu(0, (mask))) func(info); } while (0)
+
+#define smp_master_cpu 0
+#define smp_height 1
+#define smp_width 1
+
+#endif /* !CONFIG_SMP */
+
+
+/* Which cpus may be used as the lotar in a page table entry. */
+extern struct cpumask cpu_lotar_map;
+#define cpu_is_valid_lotar(cpu) cpumask_test_cpu((cpu), &cpu_lotar_map)
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+/* Which processors are used for hash-for-home mapping */
+extern struct cpumask hash_for_home_map;
+#endif
+
+/* Which cpus can have their cache flushed by hv_flush_remote(). */
+extern struct cpumask cpu_cacheable_map;
+#define cpu_cacheable(cpu) cpumask_test_cpu((cpu), &cpu_cacheable_map)
+
+/* Convert an HV_LOTAR value into a cpu. */
+static inline int hv_lotar_to_cpu(HV_LOTAR lotar)
+{
+ return HV_LOTAR_X(lotar) + (HV_LOTAR_Y(lotar) * smp_width);
+}
+
+/*
+ * Extension of <linux/cpumask.h> functionality when you just want
+ * to express a mask or suppression or inclusion region without
+ * being too concerned about exactly which cpus are valid in that region.
+ */
+int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits);
+
+#define cpulist_parse_crop(buf, dst) \
+ __cpulist_parse_crop((buf), (dst), NR_CPUS)
+static inline int __cpulist_parse_crop(const char *buf, struct cpumask *dstp,
+ int nbits)
+{
+ return bitmap_parselist_crop(buf, cpumask_bits(dstp), nbits);
+}
+
+#endif /* _ASM_TILE_SMP_H */
diff --git a/arch/tile/include/asm/socket.h b/arch/tile/include/asm/socket.h
new file mode 100644
index 000000000000..6b71384b9d8b
--- /dev/null
+++ b/arch/tile/include/asm/socket.h
@@ -0,0 +1 @@
+#include <asm-generic/socket.h>
diff --git a/arch/tile/include/asm/sockios.h b/arch/tile/include/asm/sockios.h
new file mode 100644
index 000000000000..def6d4746ee7
--- /dev/null
+++ b/arch/tile/include/asm/sockios.h
@@ -0,0 +1 @@
+#include <asm-generic/sockios.h>
diff --git a/arch/tile/include/asm/spinlock.h b/arch/tile/include/asm/spinlock.h
new file mode 100644
index 000000000000..1a8bd4740c28
--- /dev/null
+++ b/arch/tile/include/asm/spinlock.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_H
+#define _ASM_TILE_SPINLOCK_H
+
+#ifdef __tilegx__
+#include <asm/spinlock_64.h>
+#else
+#include <asm/spinlock_32.h>
+#endif
+
+#endif /* _ASM_TILE_SPINLOCK_H */
diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h
new file mode 100644
index 000000000000..f3a8473c68da
--- /dev/null
+++ b/arch/tile/include/asm/spinlock_32.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * 32-bit SMP spinlocks.
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_32_H
+#define _ASM_TILE_SPINLOCK_32_H
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <linux/compiler.h>
+
+/*
+ * We only use even ticket numbers so the '1' inserted by a tns is
+ * an unambiguous "ticket is busy" flag.
+ */
+#define TICKET_QUANTUM 2
+
+
+/*
+ * SMP ticket spinlocks, allowing only a single CPU anywhere
+ *
+ * (the type definitions are in asm/spinlock_types.h)
+ */
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+ /*
+ * Note that even if a new ticket is in the process of being
+ * acquired, so lock->next_ticket is 1, it's still reasonable
+ * to claim the lock is held, since it will be momentarily
+ * if not already. There's no need to wait for a "valid"
+ * lock->next_ticket to become available.
+ */
+ return lock->next_ticket != lock->current_ticket;
+}
+
+void arch_spin_lock(arch_spinlock_t *lock);
+
+/* We cannot take an interrupt after getting a ticket, so don't enable them. */
+#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
+
+int arch_spin_trylock(arch_spinlock_t *lock);
+
+static inline void arch_spin_unlock(arch_spinlock_t *lock)
+{
+ /* For efficiency, overlap fetching the old ticket with the wmb(). */
+ int old_ticket = lock->current_ticket;
+ wmb(); /* guarantee anything modified under the lock is visible */
+ lock->current_ticket = old_ticket + TICKET_QUANTUM;
+}
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock);
+
+/*
+ * Read-write spinlocks, allowing multiple readers
+ * but only one writer.
+ *
+ * We use a "tns/store-back" technique on a single word to manage
+ * the lock state, looping around to retry if the tns returns 1.
+ */
+
+/* Internal layout of the word; do not use. */
+#define _WR_NEXT_SHIFT 8
+#define _WR_CURR_SHIFT 16
+#define _WR_WIDTH 8
+#define _RD_COUNT_SHIFT 24
+#define _RD_COUNT_WIDTH 8
+
+/* Internal functions; do not use. */
+void arch_read_lock_slow(arch_rwlock_t *, u32);
+int arch_read_trylock_slow(arch_rwlock_t *);
+void arch_read_unlock_slow(arch_rwlock_t *);
+void arch_write_lock_slow(arch_rwlock_t *, u32);
+void arch_write_unlock_slow(arch_rwlock_t *, u32);
+
+/**
+ * arch_read_can_lock() - would read_trylock() succeed?
+ */
+static inline int arch_read_can_lock(arch_rwlock_t *rwlock)
+{
+ return (rwlock->lock << _RD_COUNT_WIDTH) == 0;
+}
+
+/**
+ * arch_write_can_lock() - would write_trylock() succeed?
+ */
+static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
+{
+ return rwlock->lock == 0;
+}
+
+/**
+ * arch_read_lock() - acquire a read lock.
+ */
+static inline void arch_read_lock(arch_rwlock_t *rwlock)
+{
+ u32 val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val << _RD_COUNT_WIDTH)) {
+ arch_read_lock_slow(rwlock, val);
+ return;
+ }
+ rwlock->lock = val + (1 << _RD_COUNT_SHIFT);
+}
+
+/**
+ * arch_read_lock() - acquire a write lock.
+ */
+static inline void arch_write_lock(arch_rwlock_t *rwlock)
+{
+ u32 val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val != 0)) {
+ arch_write_lock_slow(rwlock, val);
+ return;
+ }
+ rwlock->lock = 1 << _WR_NEXT_SHIFT;
+}
+
+/**
+ * arch_read_trylock() - try to acquire a read lock.
+ */
+static inline int arch_read_trylock(arch_rwlock_t *rwlock)
+{
+ int locked;
+ u32 val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val & 1)) {
+ return arch_read_trylock_slow(rwlock);
+ }
+ locked = (val << _RD_COUNT_WIDTH) == 0;
+ rwlock->lock = val + (locked << _RD_COUNT_SHIFT);
+ return locked;
+}
+
+/**
+ * arch_write_trylock() - try to acquire a write lock.
+ */
+static inline int arch_write_trylock(arch_rwlock_t *rwlock)
+{
+ u32 val = __insn_tns((int *)&rwlock->lock);
+
+ /*
+ * If a tns is in progress, or there's a waiting or active locker,
+ * or active readers, we can't take the lock, so give up.
+ */
+ if (unlikely(val != 0)) {
+ if (!(val & 1))
+ rwlock->lock = val;
+ return 0;
+ }
+
+ /* Set the "next" field to mark it locked. */
+ rwlock->lock = 1 << _WR_NEXT_SHIFT;
+ return 1;
+}
+
+/**
+ * arch_read_unlock() - release a read lock.
+ */
+static inline void arch_read_unlock(arch_rwlock_t *rwlock)
+{
+ u32 val;
+ mb(); /* guarantee anything modified under the lock is visible */
+ val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val & 1)) {
+ arch_read_unlock_slow(rwlock);
+ return;
+ }
+ rwlock->lock = val - (1 << _RD_COUNT_SHIFT);
+}
+
+/**
+ * arch_write_unlock() - release a write lock.
+ */
+static inline void arch_write_unlock(arch_rwlock_t *rwlock)
+{
+ u32 val;
+ mb(); /* guarantee anything modified under the lock is visible */
+ val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val != (1 << _WR_NEXT_SHIFT))) {
+ arch_write_unlock_slow(rwlock, val);
+ return;
+ }
+ rwlock->lock = 0;
+}
+
+#define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
+#define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
+
+#endif /* _ASM_TILE_SPINLOCK_32_H */
diff --git a/arch/tile/include/asm/spinlock_types.h b/arch/tile/include/asm/spinlock_types.h
new file mode 100644
index 000000000000..a71f59b49c50
--- /dev/null
+++ b/arch/tile/include/asm/spinlock_types.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SPINLOCK_TYPES_H
+#define _ASM_TILE_SPINLOCK_TYPES_H
+
+#ifndef __LINUX_SPINLOCK_TYPES_H
+# error "please don't include this file directly"
+#endif
+
+#ifdef __tilegx__
+
+/* Low 15 bits are "next"; high 15 bits are "current". */
+typedef struct arch_spinlock {
+ unsigned int lock;
+} arch_spinlock_t;
+
+#define __ARCH_SPIN_LOCK_UNLOCKED { 0 }
+
+/* High bit is "writer owns"; low 31 bits are a count of readers. */
+typedef struct arch_rwlock {
+ unsigned int lock;
+} arch_rwlock_t;
+
+#define __ARCH_RW_LOCK_UNLOCKED { 0 }
+
+#else
+
+typedef struct arch_spinlock {
+ /* Next ticket number to hand out. */
+ int next_ticket;
+ /* The ticket number that currently owns this lock. */
+ int current_ticket;
+} arch_spinlock_t;
+
+#define __ARCH_SPIN_LOCK_UNLOCKED { 0, 0 }
+
+/*
+ * Byte 0 for tns (only the low bit is used), byte 1 for ticket-lock "next",
+ * byte 2 for ticket-lock "current", byte 3 for reader count.
+ */
+typedef struct arch_rwlock {
+ unsigned int lock;
+} arch_rwlock_t;
+
+#define __ARCH_RW_LOCK_UNLOCKED { 0 }
+
+#endif
+#endif /* _ASM_TILE_SPINLOCK_TYPES_H */
diff --git a/arch/tile/include/asm/stack.h b/arch/tile/include/asm/stack.h
new file mode 100644
index 000000000000..864913bcfbc9
--- /dev/null
+++ b/arch/tile/include/asm/stack.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_STACK_H
+#define _ASM_TILE_STACK_H
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <asm/backtrace.h>
+#include <hv/hypervisor.h>
+
+/* Everything we need to keep track of a backtrace iteration */
+struct KBacktraceIterator {
+ BacktraceIterator it;
+ struct task_struct *task; /* task we are backtracing */
+ HV_PTE *pgtable; /* page table for user space access */
+ int end; /* iteration complete. */
+ int new_context; /* new context is starting */
+ int profile; /* profiling, so stop on async intrpt */
+ int verbose; /* printk extra info (don't want to
+ * do this for profiling) */
+ int is_current; /* backtracing current task */
+};
+
+/* Iteration methods for kernel backtraces */
+
+/*
+ * Initialize a KBacktraceIterator from a task_struct, and optionally from
+ * a set of registers. If the registers are omitted, the process is
+ * assumed to be descheduled, and registers are read from the process's
+ * thread_struct and stack. "verbose" means to printk some additional
+ * information about fault handlers as we pass them on the stack.
+ */
+extern void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
+ struct task_struct *, struct pt_regs *);
+
+/* Initialize iterator based on current stack. */
+extern void KBacktraceIterator_init_current(struct KBacktraceIterator *kbt);
+
+/* No more frames? */
+extern int KBacktraceIterator_end(struct KBacktraceIterator *kbt);
+
+/* Advance to the next frame. */
+extern void KBacktraceIterator_next(struct KBacktraceIterator *kbt);
+
+/*
+ * Dump stack given complete register info. Use only from the
+ * architecture-specific code; show_stack()
+ * and dump_stack() (in entry.S) are architecture-independent entry points.
+ */
+extern void tile_show_stack(struct KBacktraceIterator *, int headers);
+
+/* Dump stack of current process, with registers to seed the backtrace. */
+extern void dump_stack_regs(struct pt_regs *);
+
+
+#endif /* _ASM_TILE_STACK_H */
diff --git a/arch/tile/include/asm/stat.h b/arch/tile/include/asm/stat.h
new file mode 100644
index 000000000000..3dc90fa92c70
--- /dev/null
+++ b/arch/tile/include/asm/stat.h
@@ -0,0 +1 @@
+#include <asm-generic/stat.h>
diff --git a/arch/tile/include/asm/statfs.h b/arch/tile/include/asm/statfs.h
new file mode 100644
index 000000000000..0b91fe198c20
--- /dev/null
+++ b/arch/tile/include/asm/statfs.h
@@ -0,0 +1 @@
+#include <asm-generic/statfs.h>
diff --git a/arch/tile/include/asm/string.h b/arch/tile/include/asm/string.h
new file mode 100644
index 000000000000..7535cf1a30e4
--- /dev/null
+++ b/arch/tile/include/asm/string.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_STRING_H
+#define _ASM_TILE_STRING_H
+
+#define __HAVE_ARCH_MEMCHR
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_STRCHR
+#define __HAVE_ARCH_STRLEN
+
+extern __kernel_size_t strlen(const char *);
+extern char *strchr(const char *s, int c);
+extern void *memchr(const void *s, int c, size_t n);
+extern void *memset(void *, int, __kernel_size_t);
+extern void *memcpy(void *, const void *, __kernel_size_t);
+extern void *memmove(void *, const void *, __kernel_size_t);
+
+#endif /* _ASM_TILE_STRING_H */
diff --git a/arch/tile/include/asm/swab.h b/arch/tile/include/asm/swab.h
new file mode 100644
index 000000000000..25c686a00f1d
--- /dev/null
+++ b/arch/tile/include/asm/swab.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SWAB_H
+#define _ASM_TILE_SWAB_H
+
+/* Tile gcc is always >= 4.3.0, so we use __builtin_bswap. */
+#define __arch_swab32(x) __builtin_bswap32(x)
+#define __arch_swab64(x) __builtin_bswap64(x)
+
+/* Use the variant that is natural for the wordsize. */
+#ifdef CONFIG_64BIT
+#define __arch_swab16(x) (__builtin_bswap64(x) >> 48)
+#else
+#define __arch_swab16(x) (__builtin_bswap32(x) >> 16)
+#endif
+
+#endif /* _ASM_TILE_SWAB_H */
diff --git a/arch/tile/include/asm/syscall.h b/arch/tile/include/asm/syscall.h
new file mode 100644
index 000000000000..d35e0dcb67b1
--- /dev/null
+++ b/arch/tile/include/asm/syscall.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved.
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * See asm-generic/syscall.h for descriptions of what we must do here.
+ */
+
+#ifndef _ASM_TILE_SYSCALL_H
+#define _ASM_TILE_SYSCALL_H
+
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <arch/abi.h>
+
+/*
+ * Only the low 32 bits of orig_r0 are meaningful, so we return int.
+ * This importantly ignores the high bits on 64-bit, so comparisons
+ * sign-extend the low 32 bits.
+ */
+static inline int syscall_get_nr(struct task_struct *t, struct pt_regs *regs)
+{
+ return regs->regs[TREG_SYSCALL_NR];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ regs->regs[0] = regs->orig_r0;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ unsigned long error = regs->regs[0];
+ return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->regs[0];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ regs->regs[0] = (long) error ?: val;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+ memcpy(args, &regs[i], n * sizeof(args[0]));
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+ memcpy(&regs[i], args, n * sizeof(args[0]));
+}
+
+#endif /* _ASM_TILE_SYSCALL_H */
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
new file mode 100644
index 000000000000..9f2b8e2f69d5
--- /dev/null
+++ b/arch/tile/include/asm/syscalls.h
@@ -0,0 +1,40 @@
+/*
+ * syscalls.h - Linux syscall interfaces (arch-specific)
+ *
+ * Copyright (c) 2008 Jaswinder Singh Rajput
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SYSCALLS_H
+#define _ASM_TILE_SYSCALLS_H
+
+#include <linux/compiler.h>
+#include <linux/linkage.h>
+#include <linux/signal.h>
+#include <linux/types.h>
+#include <asm-generic/syscalls.h>
+
+/* kernel/sys.c */
+ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count);
+long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len, int advice);
+int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi, int advice);
+long sys_flush_cache(void);
+
+#ifndef __tilegx__
+/* mm/fault.c */
+int sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
+#endif
+
+#endif /* _ASM_TILE_SYSCALLS_H */
diff --git a/arch/tile/include/asm/system.h b/arch/tile/include/asm/system.h
new file mode 100644
index 000000000000..d6ca7f816c87
--- /dev/null
+++ b/arch/tile/include/asm/system.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_SYSTEM_H
+#define _ASM_TILE_SYSTEM_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/irqflags.h>
+
+/* NOTE: we can't include <linux/ptrace.h> due to #include dependencies. */
+#include <asm/ptrace.h>
+
+#include <arch/chip.h>
+#include <arch/sim_def.h>
+#include <arch/spr_def.h>
+
+/*
+ * read_barrier_depends - Flush all pending reads that subsequents reads
+ * depend on.
+ *
+ * No data-dependent reads from memory-like regions are ever reordered
+ * over this barrier. All reads preceding this primitive are guaranteed
+ * to access memory (but not necessarily other CPUs' caches) before any
+ * reads following this primitive that depend on the data return by
+ * any of the preceding reads. This primitive is much lighter weight than
+ * rmb() on most CPUs, and is never heavier weight than is
+ * rmb().
+ *
+ * These ordering constraints are respected by both the local CPU
+ * and the compiler.
+ *
+ * Ordering is not guaranteed by anything other than these primitives,
+ * not even by data dependencies. See the documentation for
+ * memory_barrier() for examples and URLs to more information.
+ *
+ * For example, the following code would force ordering (the initial
+ * value of "a" is zero, "b" is one, and "p" is "&a"):
+ *
+ * <programlisting>
+ * CPU 0 CPU 1
+ *
+ * b = 2;
+ * memory_barrier();
+ * p = &b; q = p;
+ * read_barrier_depends();
+ * d = *q;
+ * </programlisting>
+ *
+ * because the read of "*q" depends on the read of "p" and these
+ * two reads are separated by a read_barrier_depends(). However,
+ * the following code, with the same initial values for "a" and "b":
+ *
+ * <programlisting>
+ * CPU 0 CPU 1
+ *
+ * a = 2;
+ * memory_barrier();
+ * b = 3; y = b;
+ * read_barrier_depends();
+ * x = a;
+ * </programlisting>
+ *
+ * does not enforce ordering, since there is no data dependency between
+ * the read of "a" and the read of "b". Therefore, on some CPUs, such
+ * as Alpha, "y" could be set to 3 and "x" to 0. Use rmb()
+ * in cases like this where there are no data dependencies.
+ */
+
+#define read_barrier_depends() do { } while (0)
+
+#define __sync() __insn_mf()
+
+#if CHIP_HAS_SPLIT_CYCLE()
+#define get_cycles_low() __insn_mfspr(SPR_CYCLE_LOW)
+#else
+#define get_cycles_low() __insn_mfspr(SPR_CYCLE) /* just get all 64 bits */
+#endif
+
+/* Fence to guarantee visibility of stores to incoherent memory. */
+static inline void
+mb_incoherent(void)
+{
+ __insn_mf();
+
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+ {
+ int __mb_incoherent(void);
+#if CHIP_HAS_TILE_WRITE_PENDING()
+ const unsigned long WRITE_TIMEOUT_CYCLES = 400;
+ unsigned long start = get_cycles_low();
+ do {
+ if (__insn_mfspr(SPR_TILE_WRITE_PENDING) == 0)
+ return;
+ } while ((get_cycles_low() - start) < WRITE_TIMEOUT_CYCLES);
+#endif /* CHIP_HAS_TILE_WRITE_PENDING() */
+ (void) __mb_incoherent();
+ }
+#endif /* CHIP_HAS_MF_WAITS_FOR_VICTIMS() */
+}
+
+#define fast_wmb() __sync()
+#define fast_rmb() __sync()
+#define fast_mb() __sync()
+#define fast_iob() mb_incoherent()
+
+#define wmb() fast_wmb()
+#define rmb() fast_rmb()
+#define mb() fast_mb()
+#define iob() fast_iob()
+
+#ifdef CONFIG_SMP
+#define smp_mb() mb()
+#define smp_rmb() rmb()
+#define smp_wmb() wmb()
+#define smp_read_barrier_depends() read_barrier_depends()
+#else
+#define smp_mb() barrier()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+#define smp_read_barrier_depends() do { } while (0)
+#endif
+
+#define set_mb(var, value) \
+ do { var = value; mb(); } while (0)
+
+#include <linux/irqflags.h>
+
+/*
+ * Pause the DMA engine and static network before task switching.
+ */
+#define prepare_arch_switch(next) _prepare_arch_switch(next)
+void _prepare_arch_switch(struct task_struct *next);
+
+
+/*
+ * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ * The number of callee-saved registers saved on the kernel stack
+ * is defined here for use in copy_thread() and must agree with __switch_to().
+ */
+#endif /* !__ASSEMBLY__ */
+#define CALLEE_SAVED_FIRST_REG 30
+#define CALLEE_SAVED_REGS_COUNT 24 /* r30 to r52, plus an empty to align */
+#ifndef __ASSEMBLY__
+struct task_struct;
+#define switch_to(prev, next, last) ((last) = _switch_to((prev), (next)))
+extern struct task_struct *_switch_to(struct task_struct *prev,
+ struct task_struct *next);
+
+/*
+ * On SMP systems, when the scheduler does migration-cost autodetection,
+ * it needs a way to flush as much of the CPU's caches as possible:
+ *
+ * TODO: fill this in!
+ */
+static inline void sched_cacheflush(void)
+{
+}
+
+#define arch_align_stack(x) (x)
+
+/*
+ * Is the kernel doing fixups of unaligned accesses? If <0, no kernel
+ * intervention occurs and SIGBUS is delivered with no data address
+ * info. If 0, the kernel single-steps the instruction to discover
+ * the data address to provide with the SIGBUS. If 1, the kernel does
+ * a fixup.
+ */
+extern int unaligned_fixup;
+
+/* Is the kernel printing on each unaligned fixup? */
+extern int unaligned_printk;
+
+/* Number of unaligned fixups performed */
+extern unsigned int unaligned_fixup_count;
+
+/* User-level DMA management functions */
+void grant_dma_mpls(void);
+void restrict_dma_mpls(void);
+
+
+/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
+extern int _sim_syscall(int syscall_num, ...);
+#define sim_syscall(syscall_num, ...) \
+ _sim_syscall(SIM_CONTROL_SYSCALL + \
+ ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
+ ## __VA_ARGS__)
+
+/*
+ * Kernel threads can check to see if they need to migrate their
+ * stack whenever they return from a context switch; for user
+ * threads, we defer until they are returning to user-space.
+ */
+#define finish_arch_switch(prev) do { \
+ if (unlikely((prev)->state == TASK_DEAD)) \
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_EXIT | \
+ ((prev)->pid << _SIM_CONTROL_OPERATOR_BITS)); \
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_SWITCH | \
+ (current->pid << _SIM_CONTROL_OPERATOR_BITS)); \
+ if (current->mm == NULL && !kstack_hash && \
+ current_thread_info()->homecache_cpu != smp_processor_id()) \
+ homecache_migrate_kthread(); \
+} while (0)
+
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_SYSTEM_H */
diff --git a/arch/tile/include/asm/termbits.h b/arch/tile/include/asm/termbits.h
new file mode 100644
index 000000000000..3935b106de79
--- /dev/null
+++ b/arch/tile/include/asm/termbits.h
@@ -0,0 +1 @@
+#include <asm-generic/termbits.h>
diff --git a/arch/tile/include/asm/termios.h b/arch/tile/include/asm/termios.h
new file mode 100644
index 000000000000..280d78a9d966
--- /dev/null
+++ b/arch/tile/include/asm/termios.h
@@ -0,0 +1 @@
+#include <asm-generic/termios.h>
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h
new file mode 100644
index 000000000000..9024bf3530aa
--- /dev/null
+++ b/arch/tile/include/asm/thread_info.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2002 David Howells (dhowells@redhat.com)
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_THREAD_INFO_H
+#define _ASM_TILE_THREAD_INFO_H
+
+#include <asm/processor.h>
+#include <asm/page.h>
+#ifndef __ASSEMBLY__
+
+/*
+ * Low level task data that assembly code needs immediate access to.
+ * The structure is placed at the bottom of the supervisor stack.
+ */
+struct thread_info {
+ struct task_struct *task; /* main task structure */
+ struct exec_domain *exec_domain; /* execution domain */
+ unsigned long flags; /* low level flags */
+ unsigned long status; /* thread-synchronous flags */
+ __u32 homecache_cpu; /* CPU we are homecached on */
+ __u32 cpu; /* current CPU */
+ int preempt_count; /* 0 => preemptable,
+ <0 => BUG */
+
+ mm_segment_t addr_limit; /* thread address space
+ (KERNEL_DS or USER_DS) */
+ struct restart_block restart_block;
+ struct single_step_state *step_state; /* single step state
+ (if non-zero) */
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure.
+ */
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .task = &tsk, \
+ .exec_domain = &default_exec_domain, \
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = INIT_PREEMPT_COUNT, \
+ .addr_limit = KERNEL_DS, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+ .step_state = 0, \
+}
+
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+#endif /* !__ASSEMBLY__ */
+
+#if PAGE_SIZE < 8192
+#define THREAD_SIZE_ORDER (13 - PAGE_SHIFT)
+#else
+#define THREAD_SIZE_ORDER (0)
+#endif
+
+#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+#define LOG2_THREAD_SIZE (PAGE_SHIFT + THREAD_SIZE_ORDER)
+
+#define STACK_WARN (THREAD_SIZE/8)
+
+#ifndef __ASSEMBLY__
+
+/* How to get the thread information struct from C. */
+register unsigned long stack_pointer __asm__("sp");
+
+#define current_thread_info() \
+ ((struct thread_info *)(stack_pointer & -THREAD_SIZE))
+
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
+extern struct thread_info *alloc_thread_info(struct task_struct *task);
+extern void free_thread_info(struct thread_info *info);
+
+/* Switch boot idle thread to a freshly-allocated stack and free old stack. */
+extern void cpu_idle_on_new_stack(struct thread_info *old_ti,
+ unsigned long new_sp,
+ unsigned long new_ss10);
+
+#else /* __ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#ifdef __tilegx__
+#define GET_THREAD_INFO(reg) move reg, sp; mm reg, zero, LOG2_THREAD_SIZE, 63
+#else
+#define GET_THREAD_INFO(reg) mm reg, sp, zero, LOG2_THREAD_SIZE, 31
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#define PREEMPT_ACTIVE 0x10000000
+
+/*
+ * Thread information flags that various assembly files may need to access.
+ * Keep flags accessed frequently in low bits, particular since it makes
+ * it easier to build constants in assembly.
+ */
+#define TIF_SIGPENDING 0 /* signal pending */
+#define TIF_NEED_RESCHED 1 /* rescheduling necessary */
+#define TIF_SINGLESTEP 2 /* restore singlestep on return to
+ user mode */
+#define TIF_ASYNC_TLB 3 /* got an async TLB fault in kernel */
+#define TIF_SYSCALL_TRACE 4 /* syscall trace active */
+#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
+#define TIF_SECCOMP 6 /* secure computing */
+#define TIF_MEMDIE 7 /* OOM killer at work */
+
+#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+#define _TIF_ASYNC_TLB (1<<TIF_ASYNC_TLB)
+#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP (1<<TIF_SECCOMP)
+#define _TIF_MEMDIE (1<<TIF_MEMDIE)
+
+/* Work to do on any return to user space. */
+#define _TIF_ALLWORK_MASK \
+ (_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_SINGLESTEP|_TIF_ASYNC_TLB)
+
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#ifdef __tilegx__
+#define TS_COMPAT 0x0001 /* 32-bit compatibility mode */
+#endif
+#define TS_POLLING 0x0004 /* in idle loop but not sleeping */
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal */
+#define TS_EXEC_HASH_SET 0x0010 /* apply TS_EXEC_HASH_xxx flags */
+#define TS_EXEC_HASH_RO 0x0020 /* during exec, hash r/o segments */
+#define TS_EXEC_HASH_RW 0x0040 /* during exec, hash r/w segments */
+#define TS_EXEC_HASH_STACK 0x0080 /* during exec, hash the stack */
+#define TS_EXEC_HASH_FLAGS 0x00f0 /* mask for TS_EXEC_HASH_xxx flags */
+
+#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
+#endif /* _ASM_TILE_THREAD_INFO_H */
diff --git a/arch/tile/include/asm/timex.h b/arch/tile/include/asm/timex.h
new file mode 100644
index 000000000000..3baf5fc4c0a1
--- /dev/null
+++ b/arch/tile/include/asm/timex.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_TIMEX_H
+#define _ASM_TILE_TIMEX_H
+
+/*
+ * This rate should be a multiple of the possible HZ values (100, 250, 1000)
+ * and a fraction of the possible hardware timer frequencies. Our timer
+ * frequency is highly tunable but also quite precise, so for the primary use
+ * of this value (setting ACT_HZ from HZ) we just pick a value that causes
+ * ACT_HZ to be set to HZ. We make the value somewhat large just to be
+ * more robust in case someone tries out a new value of HZ.
+ */
+#define CLOCK_TICK_RATE 1000000
+
+typedef unsigned long long cycles_t;
+
+#if CHIP_HAS_SPLIT_CYCLE()
+cycles_t get_cycles(void);
+#else
+static inline cycles_t get_cycles(void)
+{
+ return __insn_mfspr(SPR_CYCLE);
+}
+#endif
+
+cycles_t get_clock_rate(void);
+
+/* Called at cpu initialization to set some low-level constants. */
+void setup_clock(void);
+
+/* Called at cpu initialization to start the tile-timer clock device. */
+void setup_tile_timer(void);
+
+#endif /* _ASM_TILE_TIMEX_H */
diff --git a/arch/tile/include/asm/tlb.h b/arch/tile/include/asm/tlb.h
new file mode 100644
index 000000000000..4a891a1a8df3
--- /dev/null
+++ b/arch/tile/include/asm/tlb.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_TLB_H
+#define _ASM_TILE_TLB_H
+
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+
+#endif /* _ASM_TILE_TLB_H */
diff --git a/arch/tile/include/asm/tlbflush.h b/arch/tile/include/asm/tlbflush.h
new file mode 100644
index 000000000000..96199d214fb8
--- /dev/null
+++ b/arch/tile/include/asm/tlbflush.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_TLBFLUSH_H
+#define _ASM_TILE_TLBFLUSH_H
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/page.h>
+#include <hv/hypervisor.h>
+
+/*
+ * Rather than associating each mm with its own ASID, we just use
+ * ASIDs to allow us to lazily flush the TLB when we switch mms.
+ * This way we only have to do an actual TLB flush on mm switch
+ * every time we wrap ASIDs, not every single time we switch.
+ *
+ * FIXME: We might improve performance by keeping ASIDs around
+ * properly, though since the hypervisor direct-maps VAs to TSB
+ * entries, we're likely to have lost at least the executable page
+ * mappings by the time we switch back to the original mm.
+ */
+DECLARE_PER_CPU(int, current_asid);
+
+/* The hypervisor tells us what ASIDs are available to us. */
+extern int min_asid, max_asid;
+
+static inline unsigned long hv_page_size(const struct vm_area_struct *vma)
+{
+ return (vma->vm_flags & VM_HUGETLB) ? HPAGE_SIZE : PAGE_SIZE;
+}
+
+/* Pass as vma pointer for non-executable mapping, if no vma available. */
+#define FLUSH_NONEXEC ((const struct vm_area_struct *)-1UL)
+
+/* Flush a single user page on this cpu. */
+static inline void local_flush_tlb_page(const struct vm_area_struct *vma,
+ unsigned long addr,
+ unsigned long page_size)
+{
+ int rc = hv_flush_page(addr, page_size);
+ if (rc < 0)
+ panic("hv_flush_page(%#lx,%#lx) failed: %d",
+ addr, page_size, rc);
+ if (!vma || (vma != FLUSH_NONEXEC && (vma->vm_flags & VM_EXEC)))
+ __flush_icache();
+}
+
+/* Flush range of user pages on this cpu. */
+static inline void local_flush_tlb_pages(const struct vm_area_struct *vma,
+ unsigned long addr,
+ unsigned long page_size,
+ unsigned long len)
+{
+ int rc = hv_flush_pages(addr, page_size, len);
+ if (rc < 0)
+ panic("hv_flush_pages(%#lx,%#lx,%#lx) failed: %d",
+ addr, page_size, len, rc);
+ if (!vma || (vma != FLUSH_NONEXEC && (vma->vm_flags & VM_EXEC)))
+ __flush_icache();
+}
+
+/* Flush all user pages on this cpu. */
+static inline void local_flush_tlb(void)
+{
+ int rc = hv_flush_all(1); /* preserve global mappings */
+ if (rc < 0)
+ panic("hv_flush_all(1) failed: %d", rc);
+ __flush_icache();
+}
+
+/*
+ * Global pages have to be flushed a bit differently. Not a real
+ * performance problem because this does not happen often.
+ */
+static inline void local_flush_tlb_all(void)
+{
+ int i;
+ for (i = 0; ; ++i) {
+ HV_VirtAddrRange r = hv_inquire_virtual(i);
+ if (r.size == 0)
+ break;
+ local_flush_tlb_pages(NULL, r.start, PAGE_SIZE, r.size);
+ local_flush_tlb_pages(NULL, r.start, HPAGE_SIZE, r.size);
+ }
+}
+
+/*
+ * TLB flushing:
+ *
+ * - flush_tlb() flushes the current mm struct TLBs
+ * - flush_tlb_all() flushes all processes TLBs
+ * - flush_tlb_mm(mm) flushes the specified mm context TLB's
+ * - flush_tlb_page(vma, vmaddr) flushes one page
+ * - flush_tlb_range(vma, start, end) flushes a range of pages
+ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ * - flush_tlb_others(cpumask, mm, va) flushes TLBs on other cpus
+ *
+ * Here (as in vm_area_struct), "end" means the first byte after
+ * our end address.
+ */
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+extern void flush_tlb_current_task(void);
+extern void flush_tlb_mm(struct mm_struct *);
+extern void flush_tlb_page(const struct vm_area_struct *, unsigned long);
+extern void flush_tlb_page_mm(const struct vm_area_struct *,
+ struct mm_struct *, unsigned long);
+extern void flush_tlb_range(const struct vm_area_struct *,
+ unsigned long start, unsigned long end);
+
+#define flush_tlb() flush_tlb_current_task()
+
+#endif /* _ASM_TILE_TLBFLUSH_H */
diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h
new file mode 100644
index 000000000000..343172d422a9
--- /dev/null
+++ b/arch/tile/include/asm/topology.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_TOPOLOGY_H
+#define _ASM_TILE_TOPOLOGY_H
+
+#ifdef CONFIG_NUMA
+
+#include <linux/cpumask.h>
+
+/* Mappings between logical cpu number and node number. */
+extern struct cpumask node_2_cpu_mask[];
+extern char cpu_2_node[];
+
+/* Returns the number of the node containing CPU 'cpu'. */
+static inline int cpu_to_node(int cpu)
+{
+ return cpu_2_node[cpu];
+}
+
+/*
+ * Returns the number of the node containing Node 'node'.
+ * This architecture is flat, so it is a pretty simple function!
+ */
+#define parent_node(node) (node)
+
+/* Returns a bitmask of CPUs on Node 'node'. */
+static inline const struct cpumask *cpumask_of_node(int node)
+{
+ return &node_2_cpu_mask[node];
+}
+
+/* For now, use numa node -1 for global allocation. */
+#define pcibus_to_node(bus) ((void)(bus), -1)
+
+/* sched_domains SD_NODE_INIT for TILE architecture */
+#define SD_NODE_INIT (struct sched_domain) { \
+ .min_interval = 8, \
+ .max_interval = 32, \
+ .busy_factor = 32, \
+ .imbalance_pct = 125, \
+ .cache_nice_tries = 1, \
+ .busy_idx = 3, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
+ .flags = SD_LOAD_BALANCE \
+ | SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_BALANCE_FORK \
+ | SD_WAKE_AFFINE \
+ | SD_SERIALIZE, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+}
+
+/* By definition, we create nodes based on online memory. */
+#define node_has_online_mem(nid) 1
+
+#endif /* CONFIG_NUMA */
+
+#include <asm-generic/topology.h>
+
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu) ((void)(cpu), 0)
+#define topology_core_id(cpu) (cpu)
+#define topology_core_cpumask(cpu) ((void)(cpu), cpu_online_mask)
+#define topology_thread_cpumask(cpu) cpumask_of(cpu)
+
+/* indicates that pointers to the topology struct cpumask maps are valid */
+#define arch_provides_topology_pointers yes
+#endif
+
+#endif /* _ASM_TILE_TOPOLOGY_H */
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h
new file mode 100644
index 000000000000..eab33d4a917d
--- /dev/null
+++ b/arch/tile/include/asm/traps.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_TRAPS_H
+#define _ASM_TILE_TRAPS_H
+
+/* mm/fault.c */
+void do_page_fault(struct pt_regs *, int fault_num,
+ unsigned long address, unsigned long write);
+
+/* kernel/traps.c */
+void do_trap(struct pt_regs *, int fault_num, unsigned long reason);
+
+/* kernel/time.c */
+void do_timer_interrupt(struct pt_regs *, int fault_num);
+
+/* kernel/messaging.c */
+void hv_message_intr(struct pt_regs *, int intnum);
+
+/* kernel/irq.c */
+void tile_dev_intr(struct pt_regs *, int intnum);
+
+
+
+#endif /* _ASM_TILE_SYSCALLS_H */
diff --git a/arch/tile/include/asm/types.h b/arch/tile/include/asm/types.h
new file mode 100644
index 000000000000..b9e79bc580dd
--- /dev/null
+++ b/arch/tile/include/asm/types.h
@@ -0,0 +1 @@
+#include <asm-generic/types.h>
diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h
new file mode 100644
index 000000000000..f3058afd5a88
--- /dev/null
+++ b/arch/tile/include/asm/uaccess.h
@@ -0,0 +1,578 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_UACCESS_H
+#define _ASM_TILE_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm-generic/uaccess-unaligned.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The fs value determines whether argument validity checking should be
+ * performed or not. If get_fs() == USER_DS, checking is performed, with
+ * get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons, these macros are grossly misnamed.
+ */
+#define MAKE_MM_SEG(a) ((mm_segment_t) { (a) })
+
+#define KERNEL_DS MAKE_MM_SEG(-1UL)
+#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
+
+#define get_ds() (KERNEL_DS)
+#define get_fs() (current_thread_info()->addr_limit)
+#define set_fs(x) (current_thread_info()->addr_limit = (x))
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#ifndef __tilegx__
+/*
+ * We could allow mapping all 16 MB at 0xfc000000, but we set up a
+ * special hack in arch_setup_additional_pages() to auto-create a mapping
+ * for the first 16 KB, and it would seem strange to have different
+ * user-accessible semantics for memory at 0xfc000000 and above 0xfc004000.
+ */
+static inline int is_arch_mappable_range(unsigned long addr,
+ unsigned long size)
+{
+ return (addr >= MEM_USER_INTRPT &&
+ addr < (MEM_USER_INTRPT + INTRPT_SIZE) &&
+ size <= (MEM_USER_INTRPT + INTRPT_SIZE) - addr);
+}
+#define is_arch_mappable_range is_arch_mappable_range
+#else
+#define is_arch_mappable_range(addr, size) 0
+#endif
+
+/*
+ * Test whether a block of memory is a valid user space address.
+ * Returns 0 if the range is valid, nonzero otherwise.
+ */
+int __range_ok(unsigned long addr, unsigned long size);
+
+/**
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that
+ * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ * to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+#define access_ok(type, addr, size) \
+ (likely(__range_ok((unsigned long)addr, size) == 0))
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+ unsigned long insn, fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+/*
+ * We return the __get_user_N function results in a structure,
+ * thus in r0 and r1. If "err" is zero, "val" is the result
+ * of the read; otherwise, "err" is -EFAULT.
+ *
+ * We rarely need 8-byte values on a 32-bit architecture, but
+ * we size the structure to accommodate. In practice, for the
+ * the smaller reads, we can zero the high word for free, and
+ * the caller will ignore it by virtue of casting anyway.
+ */
+struct __get_user {
+ unsigned long long val;
+ int err;
+};
+
+/*
+ * FIXME: we should express these as inline extended assembler, since
+ * they're fundamentally just a variable dereference and some
+ * supporting exception_table gunk. Note that (a la i386) we can
+ * extend the copy_to_user and copy_from_user routines to call into
+ * such extended assembler routines, though we will have to use a
+ * different return code in that case (1, 2, or 4, rather than -EFAULT).
+ */
+extern struct __get_user __get_user_1(const void *);
+extern struct __get_user __get_user_2(const void *);
+extern struct __get_user __get_user_4(const void *);
+extern struct __get_user __get_user_8(const void *);
+extern int __put_user_1(long, void *);
+extern int __put_user_2(long, void *);
+extern int __put_user_4(long, void *);
+extern int __put_user_8(long long, void *);
+
+/* Unimplemented routines to cause linker failures */
+extern struct __get_user __get_user_bad(void);
+extern int __put_user_bad(void);
+
+/*
+ * Careful: we have to cast the result to the type of the pointer
+ * for sign reasons.
+ */
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ */
+#define __get_user(x, ptr) \
+({ struct __get_user __ret; \
+ __typeof__(*(ptr)) const __user *__gu_addr = (ptr); \
+ __chk_user_ptr(__gu_addr); \
+ switch (sizeof(*(__gu_addr))) { \
+ case 1: \
+ __ret = __get_user_1(__gu_addr); \
+ break; \
+ case 2: \
+ __ret = __get_user_2(__gu_addr); \
+ break; \
+ case 4: \
+ __ret = __get_user_4(__gu_addr); \
+ break; \
+ case 8: \
+ __ret = __get_user_8(__gu_addr); \
+ break; \
+ default: \
+ __ret = __get_user_bad(); \
+ break; \
+ } \
+ (x) = (__typeof__(*__gu_addr)) (__typeof__(*__gu_addr - *__gu_addr)) \
+ __ret.val; \
+ __ret.err; \
+})
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ *
+ * Implementation note: The "case 8" logic of casting to the type of
+ * the result of subtracting the value from itself is basically a way
+ * of keeping all integer types the same, but casting any pointers to
+ * ptrdiff_t, i.e. also an integer type. This way there are no
+ * questionable casts seen by the compiler on an ILP32 platform.
+ */
+#define __put_user(x, ptr) \
+({ \
+ int __pu_err = 0; \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ typeof(*__pu_addr) __pu_val = (x); \
+ __chk_user_ptr(__pu_addr); \
+ switch (sizeof(__pu_val)) { \
+ case 1: \
+ __pu_err = __put_user_1((long)__pu_val, __pu_addr); \
+ break; \
+ case 2: \
+ __pu_err = __put_user_2((long)__pu_val, __pu_addr); \
+ break; \
+ case 4: \
+ __pu_err = __put_user_4((long)__pu_val, __pu_addr); \
+ break; \
+ case 8: \
+ __pu_err = \
+ __put_user_8((__typeof__(__pu_val - __pu_val))__pu_val,\
+ __pu_addr); \
+ break; \
+ default: \
+ __pu_err = __put_user_bad(); \
+ break; \
+ } \
+ __pu_err; \
+})
+
+/*
+ * The versions of get_user and put_user without initial underscores
+ * check the address of their arguments to make sure they are not
+ * in kernel space.
+ */
+#define put_user(x, ptr) \
+({ \
+ __typeof__(*(ptr)) __user *__Pu_addr = (ptr); \
+ access_ok(VERIFY_WRITE, (__Pu_addr), sizeof(*(__Pu_addr))) ? \
+ __put_user((x), (__Pu_addr)) : \
+ -EFAULT; \
+})
+
+#define get_user(x, ptr) \
+({ \
+ __typeof__(*(ptr)) const __user *__Gu_addr = (ptr); \
+ access_ok(VERIFY_READ, (__Gu_addr), sizeof(*(__Gu_addr))) ? \
+ __get_user((x), (__Gu_addr)) : \
+ ((x) = 0, -EFAULT); \
+})
+
+/**
+ * __copy_to_user() - copy data into user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from kernel space to user space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * An alternate version - __copy_to_user_inatomic() - is designed
+ * to be called from atomic context, typically bracketed by calls
+ * to pagefault_disable() and pagefault_enable().
+ */
+extern unsigned long __must_check __copy_to_user_inatomic(
+ void __user *to, const void *from, unsigned long n);
+
+static inline unsigned long __must_check
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ might_fault();
+ return __copy_to_user_inatomic(to, from, n);
+}
+
+static inline unsigned long __must_check
+copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n))
+ n = __copy_to_user(to, from, n);
+ return n;
+}
+
+/**
+ * __copy_from_user() - copy data from user space, with less checking.
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ *
+ * An alternate version - __copy_from_user_inatomic() - is designed
+ * to be called from atomic context, typically bracketed by calls
+ * to pagefault_disable() and pagefault_enable(). This version
+ * does *NOT* pad with zeros.
+ */
+extern unsigned long __must_check __copy_from_user_inatomic(
+ void *to, const void __user *from, unsigned long n);
+extern unsigned long __must_check __copy_from_user_zeroing(
+ void *to, const void __user *from, unsigned long n);
+
+static inline unsigned long __must_check
+__copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ might_fault();
+ return __copy_from_user_zeroing(to, from, n);
+}
+
+static inline unsigned long __must_check
+_copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+ if (access_ok(VERIFY_READ, from, n))
+ n = __copy_from_user(to, from, n);
+ else
+ memset(to, 0, n);
+ return n;
+}
+
+#ifdef CONFIG_DEBUG_COPY_FROM_USER
+extern void copy_from_user_overflow(void)
+ __compiletime_warning("copy_from_user() size is not provably correct");
+
+static inline unsigned long __must_check copy_from_user(void *to,
+ const void __user *from,
+ unsigned long n)
+{
+ int sz = __compiletime_object_size(to);
+
+ if (likely(sz == -1 || sz >= n))
+ n = _copy_from_user(to, from, n);
+ else
+ copy_from_user_overflow();
+
+ return n;
+}
+#else
+#define copy_from_user _copy_from_user
+#endif
+
+#ifdef __tilegx__
+/**
+ * __copy_in_user() - copy data within user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to user space. Caller must check
+ * the specified blocks with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+extern unsigned long __copy_in_user_asm(
+ void __user *to, const void __user *from, unsigned long n);
+
+static inline unsigned long __must_check
+__copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ might_sleep();
+ return __copy_in_user_asm(to, from, n);
+}
+
+static inline unsigned long __must_check
+copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+ if (access_ok(VERIFY_WRITE, to, n) && access_ok(VERIFY_READ, from, n))
+ n = __copy_in_user(to, from, n);
+ return n;
+}
+#endif
+
+
+/**
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
+extern long strnlen_user_asm(const char __user *str, long n);
+static inline long __must_check strnlen_user(const char __user *str, long n)
+{
+ might_fault();
+ return strnlen_user_asm(str, n);
+}
+#define strlen_user(str) strnlen_user(str, LONG_MAX)
+
+/**
+ * strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
+ * @dst: Destination address, in kernel space. This buffer must be at
+ * least @count bytes long.
+ * @src: Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
+extern long strncpy_from_user_asm(char *dst, const char __user *src, long);
+static inline long __must_check __strncpy_from_user(
+ char *dst, const char __user *src, long count)
+{
+ might_fault();
+ return strncpy_from_user_asm(dst, src, count);
+}
+static inline long __must_check strncpy_from_user(
+ char *dst, const char __user *src, long count)
+{
+ if (access_ok(VERIFY_READ, src, 1))
+ return __strncpy_from_user(dst, src, count);
+ return -EFAULT;
+}
+
+/**
+ * clear_user: - Zero a block of memory in user space.
+ * @mem: Destination address, in user space.
+ * @len: Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
+extern unsigned long clear_user_asm(void __user *mem, unsigned long len);
+static inline unsigned long __must_check __clear_user(
+ void __user *mem, unsigned long len)
+{
+ might_fault();
+ return clear_user_asm(mem, len);
+}
+static inline unsigned long __must_check clear_user(
+ void __user *mem, unsigned long len)
+{
+ if (access_ok(VERIFY_WRITE, mem, len))
+ return __clear_user(mem, len);
+ return len;
+}
+
+/**
+ * flush_user: - Flush a block of memory in user space from cache.
+ * @mem: Destination address, in user space.
+ * @len: Number of bytes to flush.
+ *
+ * Returns number of bytes that could not be flushed.
+ * On success, this will be zero.
+ */
+extern unsigned long flush_user_asm(void __user *mem, unsigned long len);
+static inline unsigned long __must_check __flush_user(
+ void __user *mem, unsigned long len)
+{
+ int retval;
+
+ might_fault();
+ retval = flush_user_asm(mem, len);
+ mb_incoherent();
+ return retval;
+}
+
+static inline unsigned long __must_check flush_user(
+ void __user *mem, unsigned long len)
+{
+ if (access_ok(VERIFY_WRITE, mem, len))
+ return __flush_user(mem, len);
+ return len;
+}
+
+/**
+ * inv_user: - Invalidate a block of memory in user space from cache.
+ * @mem: Destination address, in user space.
+ * @len: Number of bytes to invalidate.
+ *
+ * Returns number of bytes that could not be invalidated.
+ * On success, this will be zero.
+ *
+ * Note that on Tile64, the "inv" operation is in fact a
+ * "flush and invalidate", so cache write-backs will occur prior
+ * to the cache being marked invalid.
+ */
+extern unsigned long inv_user_asm(void __user *mem, unsigned long len);
+static inline unsigned long __must_check __inv_user(
+ void __user *mem, unsigned long len)
+{
+ int retval;
+
+ might_fault();
+ retval = inv_user_asm(mem, len);
+ mb_incoherent();
+ return retval;
+}
+static inline unsigned long __must_check inv_user(
+ void __user *mem, unsigned long len)
+{
+ if (access_ok(VERIFY_WRITE, mem, len))
+ return __inv_user(mem, len);
+ return len;
+}
+
+/**
+ * finv_user: - Flush-inval a block of memory in user space from cache.
+ * @mem: Destination address, in user space.
+ * @len: Number of bytes to invalidate.
+ *
+ * Returns number of bytes that could not be flush-invalidated.
+ * On success, this will be zero.
+ */
+extern unsigned long finv_user_asm(void __user *mem, unsigned long len);
+static inline unsigned long __must_check __finv_user(
+ void __user *mem, unsigned long len)
+{
+ int retval;
+
+ might_fault();
+ retval = finv_user_asm(mem, len);
+ mb_incoherent();
+ return retval;
+}
+static inline unsigned long __must_check finv_user(
+ void __user *mem, unsigned long len)
+{
+ if (access_ok(VERIFY_WRITE, mem, len))
+ return __finv_user(mem, len);
+ return len;
+}
+
+#endif /* _ASM_TILE_UACCESS_H */
diff --git a/arch/tile/include/asm/ucontext.h b/arch/tile/include/asm/ucontext.h
new file mode 100644
index 000000000000..9bc07b9f30fb
--- /dev/null
+++ b/arch/tile/include/asm/ucontext.h
@@ -0,0 +1 @@
+#include <asm-generic/ucontext.h>
diff --git a/arch/tile/include/asm/unaligned.h b/arch/tile/include/asm/unaligned.h
new file mode 100644
index 000000000000..137e2de5b102
--- /dev/null
+++ b/arch/tile/include/asm/unaligned.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _ASM_TILE_UNALIGNED_H
+#define _ASM_TILE_UNALIGNED_H
+
+#include <linux/unaligned/le_struct.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
+
+#endif /* _ASM_TILE_UNALIGNED_H */
diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h
new file mode 100644
index 000000000000..03b3d5d665dd
--- /dev/null
+++ b/arch/tile/include/asm/unistd.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#if !defined(_ASM_TILE_UNISTD_H) || defined(__SYSCALL)
+#define _ASM_TILE_UNISTD_H
+
+
+#ifndef __LP64__
+/* Use the flavor of this syscall that matches the 32-bit API better. */
+#define __ARCH_WANT_SYNC_FILE_RANGE2
+#endif
+
+/* Use the standard ABI for syscalls. */
+#include <asm-generic/unistd.h>
+
+#ifndef __tilegx__
+/* "Fast" syscalls provide atomic support for 32-bit chips. */
+#define __NR_FAST_cmpxchg -1
+#define __NR_FAST_atomic_update -2
+#define __NR_FAST_cmpxchg64 -3
+#define __NR_cmpxchg_badaddr (__NR_arch_specific_syscall + 0)
+__SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr)
+#endif
+
+/* Additional Tilera-specific syscalls. */
+#define __NR_flush_cache (__NR_arch_specific_syscall + 1)
+__SYSCALL(__NR_flush_cache, sys_flush_cache)
+
+#ifdef __KERNEL__
+/* In compat mode, we use sys_llseek() for compat_sys_llseek(). */
+#ifdef CONFIG_COMPAT
+#define __ARCH_WANT_SYS_LLSEEK
+#endif
+#endif
+
+#endif /* _ASM_TILE_UNISTD_H */
diff --git a/arch/tile/include/asm/user.h b/arch/tile/include/asm/user.h
new file mode 100644
index 000000000000..cbc8b4d5a5ce
--- /dev/null
+++ b/arch/tile/include/asm/user.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _ASM_TILE_USER_H
+#define _ASM_TILE_USER_H
+
+/* This header is for a.out file formats, which TILE does not support. */
+
+#endif /* _ASM_TILE_USER_H */
diff --git a/arch/tile/include/asm/xor.h b/arch/tile/include/asm/xor.h
new file mode 100644
index 000000000000..c82eb12a5b18
--- /dev/null
+++ b/arch/tile/include/asm/xor.h
@@ -0,0 +1 @@
+#include <asm-generic/xor.h>
diff --git a/arch/tile/include/hv/drv_pcie_rc_intf.h b/arch/tile/include/hv/drv_pcie_rc_intf.h
new file mode 100644
index 000000000000..9bd2243bece0
--- /dev/null
+++ b/arch/tile/include/hv/drv_pcie_rc_intf.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file drv_pcie_rc_intf.h
+ * Interface definitions for the PCIE Root Complex.
+ */
+
+#ifndef _SYS_HV_DRV_PCIE_RC_INTF_H
+#define _SYS_HV_DRV_PCIE_RC_INTF_H
+
+/** File offset for reading the interrupt base number used for PCIE legacy
+ interrupts and PLX Gen 1 requirement flag */
+#define PCIE_RC_CONFIG_MASK_OFF 0
+
+
+/**
+ * Structure used for obtaining PCIe config information, read from the PCIE
+ * subsystem /ctl file at initialization
+ */
+typedef struct pcie_rc_config
+{
+ int intr; /**< interrupt number used for downcall */
+ int plx_gen1; /**< flag for PLX Gen 1 configuration */
+} pcie_rc_config_t;
+
+#endif /* _SYS_HV_DRV_PCIE_RC_INTF_H */
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
new file mode 100644
index 000000000000..84b31551080a
--- /dev/null
+++ b/arch/tile/include/hv/hypervisor.h
@@ -0,0 +1,2366 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file hypervisor.h
+ * The hypervisor's public API.
+ */
+
+#ifndef _TILE_HV_H
+#define _TILE_HV_H
+
+#ifdef __tile__
+#include <arch/chip.h>
+#else
+/* HACK: Allow use by "tools/cpack/". */
+#include "install/include/arch/chip.h"
+#endif
+
+/* Linux builds want unsigned long constants, but assembler wants numbers */
+#ifdef __ASSEMBLER__
+/** One, for assembler */
+#define __HV_SIZE_ONE 1
+#elif !defined(__tile__) && CHIP_VA_WIDTH() > 32
+/** One, for 64-bit on host */
+#define __HV_SIZE_ONE 1ULL
+#else
+/** One, for Linux */
+#define __HV_SIZE_ONE 1UL
+#endif
+
+
+/** The log2 of the span of a level-1 page table, in bytes.
+ */
+#define HV_LOG2_L1_SPAN 32
+
+/** The span of a level-1 page table, in bytes.
+ */
+#define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN)
+
+/** The log2 of the size of small pages, in bytes. This value should
+ * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ */
+#define HV_LOG2_PAGE_SIZE_SMALL 16
+
+/** The size of small pages, in bytes. This value should be verified
+ * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ */
+#define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_SMALL)
+
+/** The log2 of the size of large pages, in bytes. This value should be
+ * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ */
+#define HV_LOG2_PAGE_SIZE_LARGE 24
+
+/** The size of large pages, in bytes. This value should be verified
+ * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ */
+#define HV_PAGE_SIZE_LARGE (__HV_SIZE_ONE << HV_LOG2_PAGE_SIZE_LARGE)
+
+/** The log2 of the granularity at which page tables must be aligned;
+ * in other words, the CPA for a page table must have this many zero
+ * bits at the bottom of the address.
+ */
+#define HV_LOG2_PAGE_TABLE_ALIGN 11
+
+/** The granularity at which page tables must be aligned.
+ */
+#define HV_PAGE_TABLE_ALIGN (__HV_SIZE_ONE << HV_LOG2_PAGE_TABLE_ALIGN)
+
+/** Normal start of hypervisor glue in client physical memory. */
+#define HV_GLUE_START_CPA 0x10000
+
+/** This much space is reserved at HV_GLUE_START_CPA
+ * for the hypervisor glue. The client program must start at
+ * some address higher than this, and in particular the address of
+ * its text section should be equal to zero modulo HV_PAGE_SIZE_LARGE
+ * so that relative offsets to the HV glue are correct.
+ */
+#define HV_GLUE_RESERVED_SIZE 0x10000
+
+/** Each entry in the hv dispatch array takes this many bytes. */
+#define HV_DISPATCH_ENTRY_SIZE 32
+
+/** Version of the hypervisor interface defined by this file */
+#define _HV_VERSION 10
+
+/* Index into hypervisor interface dispatch code blocks.
+ *
+ * Hypervisor calls are invoked from user space by calling code
+ * at an address HV_BASE_ADDRESS + (index) * HV_DISPATCH_ENTRY_SIZE,
+ * where index is one of these enum values.
+ *
+ * Normally a supervisor is expected to produce a set of symbols
+ * starting at HV_BASE_ADDRESS that obey this convention, but a user
+ * program could call directly through function pointers if desired.
+ *
+ * These numbers are part of the binary API and will not be changed
+ * without updating HV_VERSION, which should be a rare event.
+ */
+
+/** reserved. */
+#define _HV_DISPATCH_RESERVED 0
+
+/** hv_init */
+#define HV_DISPATCH_INIT 1
+
+/** hv_install_context */
+#define HV_DISPATCH_INSTALL_CONTEXT 2
+
+/** hv_sysconf */
+#define HV_DISPATCH_SYSCONF 3
+
+/** hv_get_rtc */
+#define HV_DISPATCH_GET_RTC 4
+
+/** hv_set_rtc */
+#define HV_DISPATCH_SET_RTC 5
+
+/** hv_flush_asid */
+#define HV_DISPATCH_FLUSH_ASID 6
+
+/** hv_flush_page */
+#define HV_DISPATCH_FLUSH_PAGE 7
+
+/** hv_flush_pages */
+#define HV_DISPATCH_FLUSH_PAGES 8
+
+/** hv_restart */
+#define HV_DISPATCH_RESTART 9
+
+/** hv_halt */
+#define HV_DISPATCH_HALT 10
+
+/** hv_power_off */
+#define HV_DISPATCH_POWER_OFF 11
+
+/** hv_inquire_physical */
+#define HV_DISPATCH_INQUIRE_PHYSICAL 12
+
+/** hv_inquire_memory_controller */
+#define HV_DISPATCH_INQUIRE_MEMORY_CONTROLLER 13
+
+/** hv_inquire_virtual */
+#define HV_DISPATCH_INQUIRE_VIRTUAL 14
+
+/** hv_inquire_asid */
+#define HV_DISPATCH_INQUIRE_ASID 15
+
+/** hv_nanosleep */
+#define HV_DISPATCH_NANOSLEEP 16
+
+/** hv_console_read_if_ready */
+#define HV_DISPATCH_CONSOLE_READ_IF_READY 17
+
+/** hv_console_write */
+#define HV_DISPATCH_CONSOLE_WRITE 18
+
+/** hv_downcall_dispatch */
+#define HV_DISPATCH_DOWNCALL_DISPATCH 19
+
+/** hv_inquire_topology */
+#define HV_DISPATCH_INQUIRE_TOPOLOGY 20
+
+/** hv_fs_findfile */
+#define HV_DISPATCH_FS_FINDFILE 21
+
+/** hv_fs_fstat */
+#define HV_DISPATCH_FS_FSTAT 22
+
+/** hv_fs_pread */
+#define HV_DISPATCH_FS_PREAD 23
+
+/** hv_physaddr_read64 */
+#define HV_DISPATCH_PHYSADDR_READ64 24
+
+/** hv_physaddr_write64 */
+#define HV_DISPATCH_PHYSADDR_WRITE64 25
+
+/** hv_get_command_line */
+#define HV_DISPATCH_GET_COMMAND_LINE 26
+
+/** hv_set_caching */
+#define HV_DISPATCH_SET_CACHING 27
+
+/** hv_bzero_page */
+#define HV_DISPATCH_BZERO_PAGE 28
+
+/** hv_register_message_state */
+#define HV_DISPATCH_REGISTER_MESSAGE_STATE 29
+
+/** hv_send_message */
+#define HV_DISPATCH_SEND_MESSAGE 30
+
+/** hv_receive_message */
+#define HV_DISPATCH_RECEIVE_MESSAGE 31
+
+/** hv_inquire_context */
+#define HV_DISPATCH_INQUIRE_CONTEXT 32
+
+/** hv_start_all_tiles */
+#define HV_DISPATCH_START_ALL_TILES 33
+
+/** hv_dev_open */
+#define HV_DISPATCH_DEV_OPEN 34
+
+/** hv_dev_close */
+#define HV_DISPATCH_DEV_CLOSE 35
+
+/** hv_dev_pread */
+#define HV_DISPATCH_DEV_PREAD 36
+
+/** hv_dev_pwrite */
+#define HV_DISPATCH_DEV_PWRITE 37
+
+/** hv_dev_poll */
+#define HV_DISPATCH_DEV_POLL 38
+
+/** hv_dev_poll_cancel */
+#define HV_DISPATCH_DEV_POLL_CANCEL 39
+
+/** hv_dev_preada */
+#define HV_DISPATCH_DEV_PREADA 40
+
+/** hv_dev_pwritea */
+#define HV_DISPATCH_DEV_PWRITEA 41
+
+/** hv_flush_remote */
+#define HV_DISPATCH_FLUSH_REMOTE 42
+
+/** hv_console_putc */
+#define HV_DISPATCH_CONSOLE_PUTC 43
+
+/** hv_inquire_tiles */
+#define HV_DISPATCH_INQUIRE_TILES 44
+
+/** hv_confstr */
+#define HV_DISPATCH_CONFSTR 45
+
+/** hv_reexec */
+#define HV_DISPATCH_REEXEC 46
+
+/** hv_set_command_line */
+#define HV_DISPATCH_SET_COMMAND_LINE 47
+
+/** hv_dev_register_intr_state */
+#define HV_DISPATCH_DEV_REGISTER_INTR_STATE 48
+
+/** hv_enable_intr */
+#define HV_DISPATCH_ENABLE_INTR 49
+
+/** hv_disable_intr */
+#define HV_DISPATCH_DISABLE_INTR 50
+
+/** hv_trigger_ipi */
+#define HV_DISPATCH_TRIGGER_IPI 51
+
+/** hv_store_mapping */
+#define HV_DISPATCH_STORE_MAPPING 52
+
+/** hv_inquire_realpa */
+#define HV_DISPATCH_INQUIRE_REALPA 53
+
+/** hv_flush_all */
+#define HV_DISPATCH_FLUSH_ALL 54
+
+/** One more than the largest dispatch value */
+#define _HV_DISPATCH_END 55
+
+
+#ifndef __ASSEMBLER__
+
+#ifdef __KERNEL__
+#include <asm/types.h>
+typedef u32 __hv32; /**< 32-bit value */
+typedef u64 __hv64; /**< 64-bit value */
+#else
+#include <stdint.h>
+typedef uint32_t __hv32; /**< 32-bit value */
+typedef uint64_t __hv64; /**< 64-bit value */
+#endif
+
+
+/** Hypervisor physical address. */
+typedef __hv64 HV_PhysAddr;
+
+#if CHIP_VA_WIDTH() > 32
+/** Hypervisor virtual address. */
+typedef __hv64 HV_VirtAddr;
+#else
+/** Hypervisor virtual address. */
+typedef __hv32 HV_VirtAddr;
+#endif /* CHIP_VA_WIDTH() > 32 */
+
+/** Hypervisor ASID. */
+typedef unsigned int HV_ASID;
+
+/** Hypervisor tile location for a memory access
+ * ("location overridden target").
+ */
+typedef unsigned int HV_LOTAR;
+
+/** Hypervisor size of a page. */
+typedef unsigned long HV_PageSize;
+
+/** A page table entry.
+ */
+typedef struct
+{
+ __hv64 val; /**< Value of PTE */
+} HV_PTE;
+
+/** Hypervisor error code. */
+typedef int HV_Errno;
+
+#endif /* !__ASSEMBLER__ */
+
+#define HV_OK 0 /**< No error */
+#define HV_EINVAL -801 /**< Invalid argument */
+#define HV_ENODEV -802 /**< No such device */
+#define HV_ENOENT -803 /**< No such file or directory */
+#define HV_EBADF -804 /**< Bad file number */
+#define HV_EFAULT -805 /**< Bad address */
+#define HV_ERECIP -806 /**< Bad recipients */
+#define HV_E2BIG -807 /**< Message too big */
+#define HV_ENOTSUP -808 /**< Service not supported */
+#define HV_EBUSY -809 /**< Device busy */
+#define HV_ENOSYS -810 /**< Invalid syscall */
+#define HV_EPERM -811 /**< No permission */
+#define HV_ENOTREADY -812 /**< Device not ready */
+#define HV_EIO -813 /**< I/O error */
+#define HV_ENOMEM -814 /**< Out of memory */
+
+#define HV_ERR_MAX -801 /**< Largest HV error code */
+#define HV_ERR_MIN -814 /**< Smallest HV error code */
+
+#ifndef __ASSEMBLER__
+
+/** Pass HV_VERSION to hv_init to request this version of the interface. */
+typedef enum { HV_VERSION = _HV_VERSION } HV_VersionNumber;
+
+/** Initializes the hypervisor.
+ *
+ * @param interface_version_number The version of the hypervisor interface
+ * that this program expects, typically HV_VERSION.
+ * @param chip_num Architecture number of the chip the client was built for.
+ * @param chip_rev_num Revision number of the chip the client was built for.
+ */
+void hv_init(HV_VersionNumber interface_version_number,
+ int chip_num, int chip_rev_num);
+
+
+/** Queries we can make for hv_sysconf().
+ *
+ * These numbers are part of the binary API and guaranteed not to change.
+ */
+typedef enum {
+ /** An invalid value; do not use. */
+ _HV_SYSCONF_RESERVED = 0,
+
+ /** The length of the glue section containing the hv_ procs, in bytes. */
+ HV_SYSCONF_GLUE_SIZE = 1,
+
+ /** The size of small pages, in bytes. */
+ HV_SYSCONF_PAGE_SIZE_SMALL = 2,
+
+ /** The size of large pages, in bytes. */
+ HV_SYSCONF_PAGE_SIZE_LARGE = 3,
+
+ /** Processor clock speed, in hertz. */
+ HV_SYSCONF_CPU_SPEED = 4,
+
+ /** Processor temperature, in degrees Kelvin. The value
+ * HV_SYSCONF_TEMP_KTOC may be subtracted from this to get degrees
+ * Celsius. If that Celsius value is HV_SYSCONF_OVERTEMP, this indicates
+ * that the temperature has hit an upper limit and is no longer being
+ * accurately tracked.
+ */
+ HV_SYSCONF_CPU_TEMP = 5,
+
+ /** Board temperature, in degrees Kelvin. The value
+ * HV_SYSCONF_TEMP_KTOC may be subtracted from this to get degrees
+ * Celsius. If that Celsius value is HV_SYSCONF_OVERTEMP, this indicates
+ * that the temperature has hit an upper limit and is no longer being
+ * accurately tracked.
+ */
+ HV_SYSCONF_BOARD_TEMP = 6
+
+} HV_SysconfQuery;
+
+/** Offset to subtract from returned Kelvin temperature to get degrees
+ Celsius. */
+#define HV_SYSCONF_TEMP_KTOC 273
+
+/** Pseudo-temperature value indicating that the temperature has
+ * pegged at its upper limit and is no longer accurate; note that this is
+ * the value after subtracting HV_SYSCONF_TEMP_KTOC. */
+#define HV_SYSCONF_OVERTEMP 999
+
+/** Query a configuration value from the hypervisor.
+ * @param query Which value is requested (HV_SYSCONF_xxx).
+ * @return The requested value, or -1 the requested value is illegal or
+ * unavailable.
+ */
+long hv_sysconf(HV_SysconfQuery query);
+
+
+/** Queries we can make for hv_confstr().
+ *
+ * These numbers are part of the binary API and guaranteed not to change.
+ */
+typedef enum {
+ /** An invalid value; do not use. */
+ _HV_CONFSTR_RESERVED = 0,
+
+ /** Board part number. */
+ HV_CONFSTR_BOARD_PART_NUM = 1,
+
+ /** Board serial number. */
+ HV_CONFSTR_BOARD_SERIAL_NUM = 2,
+
+ /** Chip serial number. */
+ HV_CONFSTR_CHIP_SERIAL_NUM = 3,
+
+ /** Board revision level. */
+ HV_CONFSTR_BOARD_REV = 4,
+
+ /** Hypervisor software version. */
+ HV_CONFSTR_HV_SW_VER = 5,
+
+ /** The name for this chip model. */
+ HV_CONFSTR_CHIP_MODEL = 6,
+
+ /** Human-readable board description. */
+ HV_CONFSTR_BOARD_DESC = 7,
+
+ /** Human-readable description of the hypervisor configuration. */
+ HV_CONFSTR_HV_CONFIG = 8,
+
+ /** Human-readable version string for the boot image (for instance,
+ * who built it and when, what configuration file was used). */
+ HV_CONFSTR_HV_CONFIG_VER = 9,
+
+ /** Mezzanine part number. */
+ HV_CONFSTR_MEZZ_PART_NUM = 10,
+
+ /** Mezzanine serial number. */
+ HV_CONFSTR_MEZZ_SERIAL_NUM = 11,
+
+ /** Mezzanine revision level. */
+ HV_CONFSTR_MEZZ_REV = 12,
+
+ /** Human-readable mezzanine description. */
+ HV_CONFSTR_MEZZ_DESC = 13,
+
+ /** Control path for the onboard network switch. */
+ HV_CONFSTR_SWITCH_CONTROL = 14,
+
+ /** Chip revision level. */
+ HV_CONFSTR_CHIP_REV = 15
+
+} HV_ConfstrQuery;
+
+/** Query a configuration string from the hypervisor.
+ *
+ * @param query Identifier for the specific string to be retrieved
+ * (HV_CONFSTR_xxx).
+ * @param buf Buffer in which to place the string.
+ * @param len Length of the buffer.
+ * @return If query is valid, then the length of the corresponding string,
+ * including the trailing null; if this is greater than len, the string
+ * was truncated. If query is invalid, HV_EINVAL. If the specified
+ * buffer is not writable by the client, HV_EFAULT.
+ */
+int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len);
+
+/** State object used to enable and disable one-shot and level-sensitive
+ * interrupts. */
+typedef struct
+{
+#if CHIP_VA_WIDTH() > 32
+ __hv64 opaque[2]; /**< No user-serviceable parts inside */
+#else
+ __hv32 opaque[2]; /**< No user-serviceable parts inside */
+#endif
+}
+HV_IntrState;
+
+/** A set of interrupts. */
+typedef __hv32 HV_IntrMask;
+
+/** Tile coordinate */
+typedef struct
+{
+ /** X coordinate, relative to supervisor's top-left coordinate */
+ int x;
+
+ /** Y coordinate, relative to supervisor's top-left coordinate */
+ int y;
+} HV_Coord;
+
+/** The low interrupt numbers are reserved for use by the client in
+ * delivering IPIs. Any interrupt numbers higher than this value are
+ * reserved for use by HV device drivers. */
+#define HV_MAX_IPI_INTERRUPT 7
+
+/** Register an interrupt state object. This object is used to enable and
+ * disable one-shot and level-sensitive interrupts. Once the state is
+ * registered, the client must not read or write the state object; doing
+ * so will cause undefined results.
+ *
+ * @param intr_state Pointer to interrupt state object.
+ * @return HV_OK on success, or a hypervisor error code.
+ */
+HV_Errno hv_dev_register_intr_state(HV_IntrState* intr_state);
+
+/** Enable a set of one-shot and level-sensitive interrupts.
+ *
+ * @param intr_state Pointer to interrupt state object.
+ * @param enab_mask Bitmap of interrupts to enable.
+ */
+void hv_enable_intr(HV_IntrState* intr_state, HV_IntrMask enab_mask);
+
+/** Disable a set of one-shot and level-sensitive interrupts.
+ *
+ * @param intr_state Pointer to interrupt state object.
+ * @param disab_mask Bitmap of interrupts to disable.
+ */
+void hv_disable_intr(HV_IntrState* intr_state, HV_IntrMask disab_mask);
+
+/** Trigger a one-shot interrupt on some tile
+ *
+ * @param tile Which tile to interrupt.
+ * @param interrupt Interrupt number to trigger; must be between 0 and
+ * HV_MAX_IPI_INTERRUPT.
+ * @return HV_OK on success, or a hypervisor error code.
+ */
+HV_Errno hv_trigger_ipi(HV_Coord tile, int interrupt);
+
+/** Store memory mapping in debug memory so that external debugger can read it.
+ * A maximum of 16 entries can be stored.
+ *
+ * @param va VA of memory that is mapped.
+ * @param len Length of mapped memory.
+ * @param pa PA of memory that is mapped.
+ * @return 0 on success, -1 if the maximum number of mappings is exceeded.
+ */
+int hv_store_mapping(HV_VirtAddr va, unsigned int len, HV_PhysAddr pa);
+
+/** Given a client PA and a length, return its real (HV) PA.
+ *
+ * @param cpa Client physical address.
+ * @param len Length of mapped memory.
+ * @return physical address, or -1 if cpa or len is not valid.
+ */
+HV_PhysAddr hv_inquire_realpa(HV_PhysAddr cpa, unsigned int len);
+
+/** RTC return flag for no RTC chip present.
+ */
+#define HV_RTC_NO_CHIP 0x1
+
+/** RTC return flag for low-voltage condition, indicating that battery had
+ * died and time read is unreliable.
+ */
+#define HV_RTC_LOW_VOLTAGE 0x2
+
+/** Date/Time of day */
+typedef struct {
+#if CHIP_WORD_SIZE() > 32
+ __hv64 tm_sec; /**< Seconds, 0-59 */
+ __hv64 tm_min; /**< Minutes, 0-59 */
+ __hv64 tm_hour; /**< Hours, 0-23 */
+ __hv64 tm_mday; /**< Day of month, 0-30 */
+ __hv64 tm_mon; /**< Month, 0-11 */
+ __hv64 tm_year; /**< Years since 1900, 0-199 */
+ __hv64 flags; /**< Return flags, 0 if no error */
+#else
+ __hv32 tm_sec; /**< Seconds, 0-59 */
+ __hv32 tm_min; /**< Minutes, 0-59 */
+ __hv32 tm_hour; /**< Hours, 0-23 */
+ __hv32 tm_mday; /**< Day of month, 0-30 */
+ __hv32 tm_mon; /**< Month, 0-11 */
+ __hv32 tm_year; /**< Years since 1900, 0-199 */
+ __hv32 flags; /**< Return flags, 0 if no error */
+#endif
+} HV_RTCTime;
+
+/** Read the current time-of-day clock.
+ * @return HV_RTCTime of current time (GMT).
+ */
+HV_RTCTime hv_get_rtc(void);
+
+
+/** Set the current time-of-day clock.
+ * @param time time to reset time-of-day to (GMT).
+ */
+void hv_set_rtc(HV_RTCTime time);
+
+/** Installs a context, comprising a page table and other attributes.
+ *
+ * Once this service completes, page_table will be used to translate
+ * subsequent virtual address references to physical memory.
+ *
+ * Installing a context does not cause an implicit TLB flush. Before
+ * reusing an ASID value for a different address space, the client is
+ * expected to flush old references from the TLB with hv_flush_asid().
+ * (Alternately, hv_flush_all() may be used to flush many ASIDs at once.)
+ * After invalidating a page table entry, changing its attributes, or
+ * changing its target CPA, the client is expected to flush old references
+ * from the TLB with hv_flush_page() or hv_flush_pages(). Making a
+ * previously invalid page valid does not require a flush.
+ *
+ * Specifying an invalid ASID, or an invalid CPA (client physical address)
+ * (either as page_table_pointer, or within the referenced table),
+ * or another page table data item documented as above as illegal may
+ * lead to client termination; since the validation of the table is
+ * done as needed, this may happen before the service returns, or at
+ * some later time, or never, depending upon the client's pattern of
+ * memory references. Page table entries which supply translations for
+ * invalid virtual addresses may result in client termination, or may
+ * be silently ignored. "Invalid" in this context means a value which
+ * was not provided to the client via the appropriate hv_inquire_* routine.
+ *
+ * To support changing the instruction VAs at the same time as
+ * installing the new page table, this call explicitly supports
+ * setting the "lr" register to a different address and then jumping
+ * directly to the hv_install_context() routine. In this case, the
+ * new page table does not need to contain any mapping for the
+ * hv_install_context address itself.
+ *
+ * @param page_table Root of the page table.
+ * @param access PTE providing info on how to read the page table. This
+ * value must be consistent between multiple tiles sharing a page table,
+ * and must also be consistent with any virtual mappings the client
+ * may be using to access the page table.
+ * @param asid HV_ASID the page table is to be used for.
+ * @param flags Context flags, denoting attributes or privileges of the
+ * current context (HV_CTX_xxx).
+ * @return Zero on success, or a hypervisor error code on failure.
+ */
+int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid,
+ __hv32 flags);
+
+#endif /* !__ASSEMBLER__ */
+
+#define HV_CTX_DIRECTIO 0x1 /**< Direct I/O requests are accepted from
+ PL0. */
+
+#ifndef __ASSEMBLER__
+
+/** Value returned from hv_inquire_context(). */
+typedef struct
+{
+ /** Physical address of page table */
+ HV_PhysAddr page_table;
+
+ /** PTE which defines access method for top of page table */
+ HV_PTE access;
+
+ /** ASID associated with this page table */
+ HV_ASID asid;
+
+ /** Context flags */
+ __hv32 flags;
+} HV_Context;
+
+/** Retrieve information about the currently installed context.
+ * @return The data passed to the last successful hv_install_context call.
+ */
+HV_Context hv_inquire_context(void);
+
+
+/** Flushes all translations associated with the named address space
+ * identifier from the TLB and any other hypervisor data structures.
+ * Translations installed with the "global" bit are not flushed.
+ *
+ * Specifying an invalid ASID may lead to client termination. "Invalid"
+ * in this context means a value which was not provided to the client
+ * via <tt>hv_inquire_asid()</tt>.
+ *
+ * @param asid HV_ASID whose entries are to be flushed.
+ * @return Zero on success, or a hypervisor error code on failure.
+*/
+int hv_flush_asid(HV_ASID asid);
+
+
+/** Flushes all translations associated with the named virtual address
+ * and page size from the TLB and other hypervisor data structures. Only
+ * pages visible to the current ASID are affected; note that this includes
+ * global pages in addition to pages specific to the current ASID.
+ *
+ * The supplied VA need not be aligned; it may be anywhere in the
+ * subject page.
+ *
+ * Specifying an invalid virtual address may lead to client termination,
+ * or may silently succeed. "Invalid" in this context means a value
+ * which was not provided to the client via hv_inquire_virtual.
+ *
+ * @param address Address of the page to flush.
+ * @param page_size Size of pages to assume.
+ * @return Zero on success, or a hypervisor error code on failure.
+ */
+int hv_flush_page(HV_VirtAddr address, HV_PageSize page_size);
+
+
+/** Flushes all translations associated with the named virtual address range
+ * and page size from the TLB and other hypervisor data structures. Only
+ * pages visible to the current ASID are affected; note that this includes
+ * global pages in addition to pages specific to the current ASID.
+ *
+ * The supplied VA need not be aligned; it may be anywhere in the
+ * subject page.
+ *
+ * Specifying an invalid virtual address may lead to client termination,
+ * or may silently succeed. "Invalid" in this context means a value
+ * which was not provided to the client via hv_inquire_virtual.
+ *
+ * @param start Address to flush.
+ * @param page_size Size of pages to assume.
+ * @param size The number of bytes to flush. Any page in the range
+ * [start, start + size) will be flushed from the TLB.
+ * @return Zero on success, or a hypervisor error code on failure.
+ */
+int hv_flush_pages(HV_VirtAddr start, HV_PageSize page_size,
+ unsigned long size);
+
+
+/** Flushes all non-global translations (if preserve_global is true),
+ * or absolutely all translations (if preserve_global is false).
+ *
+ * @param preserve_global Non-zero if we want to preserve "global" mappings.
+ * @return Zero on success, or a hypervisor error code on failure.
+*/
+int hv_flush_all(int preserve_global);
+
+
+/** Restart machine with optional restart command and optional args.
+ * @param cmd Const pointer to command to restart with, or NULL
+ * @param args Const pointer to argument string to restart with, or NULL
+ */
+void hv_restart(HV_VirtAddr cmd, HV_VirtAddr args);
+
+
+/** Halt machine. */
+void hv_halt(void);
+
+
+/** Power off machine. */
+void hv_power_off(void);
+
+
+/** Re-enter virtual-is-physical memory translation mode and restart
+ * execution at a given address.
+ * @param entry Client physical address at which to begin execution.
+ * @return A hypervisor error code on failure; if the operation is
+ * successful the call does not return.
+ */
+int hv_reexec(HV_PhysAddr entry);
+
+
+/** Chip topology */
+typedef struct
+{
+ /** Relative coordinates of the querying tile */
+ HV_Coord coord;
+
+ /** Width of the querying supervisor's tile rectangle. */
+ int width;
+
+ /** Height of the querying supervisor's tile rectangle. */
+ int height;
+
+} HV_Topology;
+
+/** Returns information about the tile coordinate system.
+ *
+ * Each supervisor is given a rectangle of tiles it potentially controls.
+ * These tiles are labeled using a relative coordinate system with (0,0) as
+ * the upper left tile regardless of their physical location on the chip.
+ *
+ * This call returns both the size of that rectangle and the position
+ * within that rectangle of the querying tile.
+ *
+ * Not all tiles within that rectangle may be available to the supervisor;
+ * to get the precise set of available tiles, you must also call
+ * hv_inquire_tiles(HV_INQ_TILES_AVAIL, ...).
+ **/
+HV_Topology hv_inquire_topology(void);
+
+/** Sets of tiles we can retrieve with hv_inquire_tiles().
+ *
+ * These numbers are part of the binary API and guaranteed not to change.
+ */
+typedef enum {
+ /** An invalid value; do not use. */
+ _HV_INQ_TILES_RESERVED = 0,
+
+ /** All available tiles within the supervisor's tile rectangle. */
+ HV_INQ_TILES_AVAIL = 1,
+
+ /** The set of tiles used for hash-for-home caching. */
+ HV_INQ_TILES_HFH_CACHE = 2,
+
+ /** The set of tiles that can be legally used as a LOTAR for a PTE. */
+ HV_INQ_TILES_LOTAR = 3
+} HV_InqTileSet;
+
+/** Returns specific information about various sets of tiles within the
+ * supervisor's tile rectangle.
+ *
+ * @param set Which set of tiles to retrieve.
+ * @param cpumask Pointer to a returned bitmask (in row-major order,
+ * supervisor-relative) of tiles. The low bit of the first word
+ * corresponds to the tile at the upper left-hand corner of the
+ * supervisor's rectangle. In order for the supervisor to know the
+ * buffer length to supply, it should first call hv_inquire_topology.
+ * @param length Number of bytes available for the returned bitmask.
+ **/
+HV_Errno hv_inquire_tiles(HV_InqTileSet set, HV_VirtAddr cpumask, int length);
+
+
+/** An identifier for a memory controller. Multiple memory controllers
+ * may be connected to one chip, and this uniquely identifies each one.
+ */
+typedef int HV_MemoryController;
+
+/** A range of physical memory. */
+typedef struct
+{
+ HV_PhysAddr start; /**< Starting address. */
+ __hv64 size; /**< Size in bytes. */
+ HV_MemoryController controller; /**< Which memory controller owns this. */
+} HV_PhysAddrRange;
+
+/** Returns information about a range of physical memory.
+ *
+ * hv_inquire_physical() returns one of the ranges of client
+ * physical addresses which are available to this client.
+ *
+ * The first range is retrieved by specifying an idx of 0, and
+ * successive ranges are returned with subsequent idx values. Ranges
+ * are ordered by increasing start address (i.e., as idx increases,
+ * so does start), do not overlap, and do not touch (i.e., the
+ * available memory is described with the fewest possible ranges).
+ *
+ * If an out-of-range idx value is specified, the returned size will be zero.
+ * A client can count the number of ranges by increasing idx until the
+ * returned size is zero. There will always be at least one valid range.
+ *
+ * Some clients might not be prepared to deal with more than one
+ * physical address range; they still ought to call this routine and
+ * issue a warning message if they're given more than one range, on the
+ * theory that whoever configured the hypervisor to provide that memory
+ * should know that it's being wasted.
+ */
+HV_PhysAddrRange hv_inquire_physical(int idx);
+
+
+/** Memory controller information. */
+typedef struct
+{
+ HV_Coord coord; /**< Relative tile coordinates of the port used by a
+ specified tile to communicate with this controller. */
+ __hv64 speed; /**< Speed of this controller in bytes per second. */
+} HV_MemoryControllerInfo;
+
+/** Returns information about a particular memory controller.
+ *
+ * hv_inquire_memory_controller(coord,idx) returns information about a
+ * particular controller. Two pieces of information are returned:
+ * - The relative coordinates of the port on the controller that the specified
+ * tile would use to contact it. The relative coordinates may lie
+ * outside the supervisor's rectangle, i.e. the controller may not
+ * be attached to a node managed by the querying node's supervisor.
+ * In particular note that x or y may be negative.
+ * - The speed of the memory controller. (This is a not-to-exceed value
+ * based on the raw hardware data rate, and may not be achievable in
+ * practice; it is provided to give clients information on the relative
+ * performance of the available controllers.)
+ *
+ * Clients should avoid calling this interface with invalid values.
+ * A client who does may be terminated.
+ * @param coord Tile for which to calculate the relative port position.
+ * @param controller Index of the controller; identical to value returned
+ * from other routines like hv_inquire_physical.
+ * @return Information about the controller.
+ */
+HV_MemoryControllerInfo hv_inquire_memory_controller(HV_Coord coord,
+ int controller);
+
+
+/** A range of virtual memory. */
+typedef struct
+{
+ HV_VirtAddr start; /**< Starting address. */
+ __hv64 size; /**< Size in bytes. */
+} HV_VirtAddrRange;
+
+/** Returns information about a range of virtual memory.
+ *
+ * hv_inquire_virtual() returns one of the ranges of client
+ * virtual addresses which are available to this client.
+ *
+ * The first range is retrieved by specifying an idx of 0, and
+ * successive ranges are returned with subsequent idx values. Ranges
+ * are ordered by increasing start address (i.e., as idx increases,
+ * so does start), do not overlap, and do not touch (i.e., the
+ * available memory is described with the fewest possible ranges).
+ *
+ * If an out-of-range idx value is specified, the returned size will be zero.
+ * A client can count the number of ranges by increasing idx until the
+ * returned size is zero. There will always be at least one valid range.
+ *
+ * Some clients may well have various virtual addresses hardwired
+ * into themselves; for instance, their instruction stream may
+ * have been compiled expecting to live at a particular address.
+ * Such clients should use this interface to verify they've been
+ * given the virtual address space they expect, and issue a (potentially
+ * fatal) warning message otherwise.
+ *
+ * Note that the returned size is a __hv64, not a __hv32, so it is
+ * possible to express a single range spanning the entire 32-bit
+ * address space.
+ */
+HV_VirtAddrRange hv_inquire_virtual(int idx);
+
+
+/** A range of ASID values. */
+typedef struct
+{
+ HV_ASID start; /**< First ASID in the range. */
+ unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */
+} HV_ASIDRange;
+
+/** Returns information about a range of ASIDs.
+ *
+ * hv_inquire_asid() returns one of the ranges of address
+ * space identifiers which are available to this client.
+ *
+ * The first range is retrieved by specifying an idx of 0, and
+ * successive ranges are returned with subsequent idx values. Ranges
+ * are ordered by increasing start value (i.e., as idx increases,
+ * so does start), do not overlap, and do not touch (i.e., the
+ * available ASIDs are described with the fewest possible ranges).
+ *
+ * If an out-of-range idx value is specified, the returned size will be zero.
+ * A client can count the number of ranges by increasing idx until the
+ * returned size is zero. There will always be at least one valid range.
+ */
+HV_ASIDRange hv_inquire_asid(int idx);
+
+
+/** Waits for at least the specified number of nanoseconds then returns.
+ *
+ * @param nanosecs The number of nanoseconds to sleep.
+ */
+void hv_nanosleep(int nanosecs);
+
+
+/** Reads a character from the console without blocking.
+ *
+ * @return A value from 0-255 indicates the value successfully read.
+ * A negative value means no value was ready.
+ */
+int hv_console_read_if_ready(void);
+
+
+/** Writes a character to the console, blocking if the console is busy.
+ *
+ * This call cannot fail. If the console is broken for some reason,
+ * output will simply vanish.
+ * @param byte Character to write.
+ */
+void hv_console_putc(int byte);
+
+
+/** Writes a string to the console, blocking if the console is busy.
+ * @param bytes Pointer to characters to write.
+ * @param len Number of characters to write.
+ * @return Number of characters written, or HV_EFAULT if the buffer is invalid.
+ */
+int hv_console_write(HV_VirtAddr bytes, int len);
+
+
+/** Dispatch the next interrupt from the client downcall mechanism.
+ *
+ * The hypervisor uses downcalls to notify the client of asynchronous
+ * events. Some of these events are hypervisor-created (like incoming
+ * messages). Some are regular interrupts which initially occur in
+ * the hypervisor, and are normally handled directly by the client;
+ * when these occur in a client's interrupt critical section, they must
+ * be delivered through the downcall mechanism.
+ *
+ * A downcall is initially delivered to the client as an INTCTRL_1
+ * interrupt. Upon entry to the INTCTRL_1 vector, the client must
+ * immediately invoke the hv_downcall_dispatch service. This service
+ * will not return; instead it will cause one of the client's actual
+ * downcall-handling interrupt vectors to be entered. The EX_CONTEXT
+ * registers in the client will be set so that when the client irets,
+ * it will return to the code which was interrupted by the INTCTRL_1
+ * interrupt.
+ *
+ * Any saving of registers should be done by the actual handling
+ * vectors; no registers should be changed by the INTCTRL_1 handler.
+ * In particular, the client should not use a jal instruction to invoke
+ * the hv_downcall_dispatch service, as that would overwrite the client's
+ * lr register. Note that the hv_downcall_dispatch service may overwrite
+ * one or more of the client's system save registers.
+ *
+ * The client must not modify the INTCTRL_1_STATUS SPR. The hypervisor
+ * will set this register to cause a downcall to happen, and will clear
+ * it when no further downcalls are pending.
+ *
+ * When a downcall vector is entered, the INTCTRL_1 interrupt will be
+ * masked. When the client is done processing a downcall, and is ready
+ * to accept another, it must unmask this interrupt; if more downcalls
+ * are pending, this will cause the INTCTRL_1 vector to be reentered.
+ * Currently the following interrupt vectors can be entered through a
+ * downcall:
+ *
+ * INT_MESSAGE_RCV_DWNCL (hypervisor message available)
+ * INT_DMATLB_MISS_DWNCL (DMA TLB miss)
+ * INT_SNITLB_MISS_DWNCL (SNI TLB miss)
+ * INT_DMATLB_ACCESS_DWNCL (DMA TLB access violation)
+ */
+void hv_downcall_dispatch(void);
+
+#endif /* !__ASSEMBLER__ */
+
+/** We use actual interrupt vectors which never occur (they're only there
+ * to allow setting MPLs for related SPRs) for our downcall vectors.
+ */
+/** Message receive downcall interrupt vector */
+#define INT_MESSAGE_RCV_DWNCL INT_BOOT_ACCESS
+/** DMA TLB miss downcall interrupt vector */
+#define INT_DMATLB_MISS_DWNCL INT_DMA_ASID
+/** Static nework processor instruction TLB miss interrupt vector */
+#define INT_SNITLB_MISS_DWNCL INT_SNI_ASID
+/** DMA TLB access violation downcall interrupt vector */
+#define INT_DMATLB_ACCESS_DWNCL INT_DMA_CPL
+/** Device interrupt downcall interrupt vector */
+#define INT_DEV_INTR_DWNCL INT_WORLD_ACCESS
+
+#ifndef __ASSEMBLER__
+
+/** Requests the inode for a specific full pathname.
+ *
+ * Performs a lookup in the hypervisor filesystem for a given filename.
+ * Multiple calls with the same filename will always return the same inode.
+ * If there is no such filename, HV_ENOENT is returned.
+ * A bad filename pointer may result in HV_EFAULT instead.
+ *
+ * @param filename Constant pointer to name of requested file
+ * @return Inode of requested file
+ */
+int hv_fs_findfile(HV_VirtAddr filename);
+
+
+/** Data returned from an fstat request.
+ * Note that this structure should be no more than 40 bytes in size so
+ * that it can always be returned completely in registers.
+ */
+typedef struct
+{
+ int size; /**< Size of file (or HV_Errno on error) */
+ unsigned int flags; /**< Flags (see HV_FS_FSTAT_FLAGS) */
+} HV_FS_StatInfo;
+
+/** Bitmask flags for fstat request */
+typedef enum
+{
+ HV_FS_ISDIR = 0x0001 /**< Is the entry a directory? */
+} HV_FS_FSTAT_FLAGS;
+
+/** Get stat information on a given file inode.
+ *
+ * Return information on the file with the given inode.
+ *
+ * IF the HV_FS_ISDIR bit is set, the "file" is a directory. Reading
+ * it will return NUL-separated filenames (no directory part) relative
+ * to the path to the inode of the directory "file". These can be
+ * appended to the path to the directory "file" after a forward slash
+ * to create additional filenames. Note that it is not required
+ * that all valid paths be decomposable into valid parent directories;
+ * a filesystem may validly have just a few files, none of which have
+ * HV_FS_ISDIR set. However, if clients may wish to enumerate the
+ * files in the filesystem, it is recommended to include all the
+ * appropriate parent directory "files" to give a consistent view.
+ *
+ * An invalid file inode will cause an HV_EBADF error to be returned.
+ *
+ * @param inode The inode number of the query
+ * @return An HV_FS_StatInfo structure
+ */
+HV_FS_StatInfo hv_fs_fstat(int inode);
+
+
+/** Read data from a specific hypervisor file.
+ * On error, may return HV_EBADF for a bad inode or HV_EFAULT for a bad buf.
+ * Reads near the end of the file will return fewer bytes than requested.
+ * Reads at or beyond the end of a file will return zero.
+ *
+ * @param inode the hypervisor file to read
+ * @param buf the buffer to read data into
+ * @param length the number of bytes of data to read
+ * @param offset the offset into the file to read the data from
+ * @return number of bytes successfully read, or an HV_Errno code
+ */
+int hv_fs_pread(int inode, HV_VirtAddr buf, int length, int offset);
+
+
+/** Read a 64-bit word from the specified physical address.
+ * The address must be 8-byte aligned.
+ * Specifying an invalid physical address will lead to client termination.
+ * @param addr The physical address to read
+ * @param access The PTE describing how to read the memory
+ * @return The 64-bit value read from the given address
+ */
+unsigned long long hv_physaddr_read64(HV_PhysAddr addr, HV_PTE access);
+
+
+/** Write a 64-bit word to the specified physical address.
+ * The address must be 8-byte aligned.
+ * Specifying an invalid physical address will lead to client termination.
+ * @param addr The physical address to write
+ * @param access The PTE that says how to write the memory
+ * @param val The 64-bit value to write to the given address
+ */
+void hv_physaddr_write64(HV_PhysAddr addr, HV_PTE access,
+ unsigned long long val);
+
+
+/** Get the value of the command-line for the supervisor, if any.
+ * This will not include the filename of the booted supervisor, but may
+ * include configured-in boot arguments or the hv_restart() arguments.
+ * If the buffer is not long enough the hypervisor will NUL the first
+ * character of the buffer but not write any other data.
+ * @param buf The virtual address to write the command-line string to.
+ * @param length The length of buf, in characters.
+ * @return The actual length of the command line, including the trailing NUL
+ * (may be larger than "length").
+ */
+int hv_get_command_line(HV_VirtAddr buf, int length);
+
+
+/** Set a new value for the command-line for the supervisor, which will
+ * be returned from subsequent invocations of hv_get_command_line() on
+ * this tile.
+ * @param buf The virtual address to read the command-line string from.
+ * @param length The length of buf, in characters; must be no more than
+ * HV_COMMAND_LINE_LEN.
+ * @return Zero if successful, or a hypervisor error code.
+ */
+HV_Errno hv_set_command_line(HV_VirtAddr buf, int length);
+
+/** Maximum size of a command line passed to hv_set_command_line(); note
+ * that a line returned from hv_get_command_line() could be larger than
+ * this.*/
+#define HV_COMMAND_LINE_LEN 256
+
+/** Tell the hypervisor how to cache non-priority pages
+ * (its own as well as pages explicitly represented in page tables).
+ * Normally these will be represented as red/black pages, but
+ * when the supervisor starts to allocate "priority" pages in the PTE
+ * the hypervisor will need to start marking those pages as (e.g.) "red"
+ * and non-priority pages as either "black" (if they cache-alias
+ * with the existing priority pages) or "red/black" (if they don't).
+ * The bitmask provides information on which parts of the cache
+ * have been used for pinned pages so far on this tile; if (1 << N)
+ * appears in the bitmask, that indicates that a page has been marked
+ * "priority" whose PFN equals N, mod 8.
+ * @param bitmask A bitmap of priority page set values
+ */
+void hv_set_caching(unsigned int bitmask);
+
+
+/** Zero out a specified number of pages.
+ * The va and size must both be multiples of 4096.
+ * Caches are bypassed and memory is directly set to zero.
+ * This API is implemented only in the magic hypervisor and is intended
+ * to provide a performance boost to the minimal supervisor by
+ * giving it a fast way to zero memory pages when allocating them.
+ * @param va Virtual address where the page has been mapped
+ * @param size Number of bytes (must be a page size multiple)
+ */
+void hv_bzero_page(HV_VirtAddr va, unsigned int size);
+
+
+/** State object for the hypervisor messaging subsystem. */
+typedef struct
+{
+#if CHIP_VA_WIDTH() > 32
+ __hv64 opaque[2]; /**< No user-serviceable parts inside */
+#else
+ __hv32 opaque[2]; /**< No user-serviceable parts inside */
+#endif
+}
+HV_MsgState;
+
+/** Register to receive incoming messages.
+ *
+ * This routine configures the current tile so that it can receive
+ * incoming messages. It must be called before the client can receive
+ * messages with the hv_receive_message routine, and must be called on
+ * each tile which will receive messages.
+ *
+ * msgstate is the virtual address of a state object of type HV_MsgState.
+ * Once the state is registered, the client must not read or write the
+ * state object; doing so will cause undefined results.
+ *
+ * If this routine is called with msgstate set to 0, the client's message
+ * state will be freed and it will no longer be able to receive messages.
+ * Note that this may cause the loss of any as-yet-undelivered messages
+ * for the client.
+ *
+ * If another client attempts to send a message to a client which has
+ * not yet called hv_register_message_state, or which has freed its
+ * message state, the message will not be delivered, as if the client
+ * had insufficient buffering.
+ *
+ * This routine returns HV_OK if the registration was successful, and
+ * HV_EINVAL if the supplied state object is unsuitable. Note that some
+ * errors may not be detected during this routine, but might be detected
+ * during a subsequent message delivery.
+ * @param msgstate State object.
+ **/
+HV_Errno hv_register_message_state(HV_MsgState* msgstate);
+
+/** Possible message recipient states. */
+typedef enum
+{
+ HV_TO_BE_SENT, /**< Not sent (not attempted, or recipient not ready) */
+ HV_SENT, /**< Successfully sent */
+ HV_BAD_RECIP /**< Bad recipient coordinates (permanent error) */
+} HV_Recip_State;
+
+/** Message recipient. */
+typedef struct
+{
+ /** X coordinate, relative to supervisor's top-left coordinate */
+ unsigned int x:11;
+
+ /** Y coordinate, relative to supervisor's top-left coordinate */
+ unsigned int y:11;
+
+ /** Status of this recipient */
+ HV_Recip_State state:10;
+} HV_Recipient;
+
+/** Send a message to a set of recipients.
+ *
+ * This routine sends a message to a set of recipients.
+ *
+ * recips is an array of HV_Recipient structures. Each specifies a tile,
+ * and a message state; initially, it is expected that the state will
+ * be set to HV_TO_BE_SENT. nrecip specifies the number of recipients
+ * in the recips array.
+ *
+ * For each recipient whose state is HV_TO_BE_SENT, the hypervisor attempts
+ * to send that tile the specified message. In order to successfully
+ * receive the message, the receiver must be a valid tile to which the
+ * sender has access, must not be the sending tile itself, and must have
+ * sufficient free buffer space. (The hypervisor guarantees that each
+ * tile which has called hv_register_message_state() will be able to
+ * buffer one message from every other tile which can legally send to it;
+ * more space may be provided but is not guaranteed.) If an invalid tile
+ * is specified, the recipient's state is set to HV_BAD_RECIP; this is a
+ * permanent delivery error. If the message is successfully delivered
+ * to the recipient's buffer, the recipient's state is set to HV_SENT.
+ * Otherwise, the recipient's state is unchanged. Message delivery is
+ * synchronous; all attempts to send messages are completed before this
+ * routine returns.
+ *
+ * If no permanent delivery errors were encountered, the routine returns
+ * the number of messages successfully sent: that is, the number of
+ * recipients whose states changed from HV_TO_BE_SENT to HV_SENT during
+ * this operation. If any permanent delivery errors were encountered,
+ * the routine returns HV_ERECIP. In the event of permanent delivery
+ * errors, it may be the case that delivery was not attempted to all
+ * recipients; if any messages were succesfully delivered, however,
+ * recipients' state values will be updated appropriately.
+ *
+ * It is explicitly legal to specify a recipient structure whose state
+ * is not HV_TO_BE_SENT; such a recipient is ignored. One suggested way
+ * of using hv_send_message to send a message to multiple tiles is to set
+ * up a list of recipients, and then call the routine repeatedly with the
+ * same list, each time accumulating the number of messages successfully
+ * sent, until all messages are sent, a permanent error is encountered,
+ * or the desired number of attempts have been made. When used in this
+ * way, the routine will deliver each message no more than once to each
+ * recipient.
+ *
+ * Note that a message being successfully delivered to the recipient's
+ * buffer space does not guarantee that it is received by the recipient,
+ * either immediately or at any time in the future; the recipient might
+ * never call hv_receive_message, or could register a different state
+ * buffer, losing the message.
+ *
+ * Specifiying the same recipient more than once in the recipient list
+ * is an error, which will not result in an error return but which may
+ * or may not result in more than one message being delivered to the
+ * recipient tile.
+ *
+ * buf and buflen specify the message to be sent. buf is a virtual address
+ * which must be currently mapped in the client's page table; if not, the
+ * routine returns HV_EFAULT. buflen must be greater than zero and less
+ * than or equal to HV_MAX_MESSAGE_SIZE, and nrecip must be less than the
+ * number of tiles to which the sender has access; if not, the routine
+ * returns HV_EINVAL.
+ * @param recips List of recipients.
+ * @param nrecip Number of recipients.
+ * @param buf Address of message data.
+ * @param buflen Length of message data.
+ **/
+int hv_send_message(HV_Recipient *recips, int nrecip,
+ HV_VirtAddr buf, int buflen);
+
+/** Maximum hypervisor message size, in bytes */
+#define HV_MAX_MESSAGE_SIZE 28
+
+
+/** Return value from hv_receive_message() */
+typedef struct
+{
+ int msglen; /**< Message length in bytes, or an error code */
+ __hv32 source; /**< Code identifying message sender (HV_MSG_xxx) */
+} HV_RcvMsgInfo;
+
+#define HV_MSG_TILE 0x0 /**< Message source is another tile */
+#define HV_MSG_INTR 0x1 /**< Message source is a driver interrupt */
+
+/** Receive a message.
+ *
+ * This routine retrieves a message from the client's incoming message
+ * buffer.
+ *
+ * Multiple messages sent from a particular sending tile to a particular
+ * receiving tile are received in the order that they were sent; however,
+ * no ordering is guaranteed between messages sent by different tiles.
+ *
+ * Whenever the a client's message buffer is empty, the first message
+ * subsequently received will cause the client's MESSAGE_RCV_DWNCL
+ * interrupt vector to be invoked through the interrupt downcall mechanism
+ * (see the description of the hv_downcall_dispatch() routine for details
+ * on downcalls).
+ *
+ * Another message-available downcall will not occur until a call to
+ * this routine is made when the message buffer is empty, and a message
+ * subsequently arrives. Note that such a downcall could occur while
+ * this routine is executing. If the calling code does not wish this
+ * to happen, it is recommended that this routine be called with the
+ * INTCTRL_1 interrupt masked, or inside an interrupt critical section.
+ *
+ * msgstate is the value previously passed to hv_register_message_state().
+ * buf is the virtual address of the buffer into which the message will
+ * be written; buflen is the length of the buffer.
+ *
+ * This routine returns an HV_RcvMsgInfo structure. The msglen member
+ * of that structure is the length of the message received, zero if no
+ * message is available, or HV_E2BIG if the message is too large for the
+ * specified buffer. If the message is too large, it is not consumed,
+ * and may be retrieved by a subsequent call to this routine specifying
+ * a sufficiently large buffer. A buffer which is HV_MAX_MESSAGE_SIZE
+ * bytes long is guaranteed to be able to receive any possible message.
+ *
+ * The source member of the HV_RcvMsgInfo structure describes the sender
+ * of the message. For messages sent by another client tile via an
+ * hv_send_message() call, this value is HV_MSG_TILE; for messages sent
+ * as a result of a device interrupt, this value is HV_MSG_INTR.
+ */
+
+HV_RcvMsgInfo hv_receive_message(HV_MsgState msgstate, HV_VirtAddr buf,
+ int buflen);
+
+
+/** Start remaining tiles owned by this supervisor. Initially, only one tile
+ * executes the client program; after it calls this service, the other tiles
+ * are started. This allows the initial tile to do one-time configuration
+ * of shared data structures without having to lock them against simultaneous
+ * access.
+ */
+void hv_start_all_tiles(void);
+
+
+/** Open a hypervisor device.
+ *
+ * This service initializes an I/O device and its hypervisor driver software,
+ * and makes it available for use. The open operation is per-device per-chip;
+ * once it has been performed, the device handle returned may be used in other
+ * device services calls made by any tile.
+ *
+ * @param name Name of the device. A base device name is just a text string
+ * (say, "pcie"). If there is more than one instance of a device, the
+ * base name is followed by a slash and a device number (say, "pcie/0").
+ * Some devices may support further structure beneath those components;
+ * most notably, devices which require control operations do so by
+ * supporting reads and/or writes to a control device whose name
+ * includes a trailing "/ctl" (say, "pcie/0/ctl").
+ * @param flags Flags (HV_DEV_xxx).
+ * @return A positive integer device handle, or a negative error code.
+ */
+int hv_dev_open(HV_VirtAddr name, __hv32 flags);
+
+
+/** Close a hypervisor device.
+ *
+ * This service uninitializes an I/O device and its hypervisor driver
+ * software, and makes it unavailable for use. The close operation is
+ * per-device per-chip; once it has been performed, the device is no longer
+ * available. Normally there is no need to ever call the close service.
+ *
+ * @param devhdl Device handle of the device to be closed.
+ * @return Zero if the close is successful, otherwise, a negative error code.
+ */
+int hv_dev_close(int devhdl);
+
+
+/** Read data from a hypervisor device synchronously.
+ *
+ * This service transfers data from a hypervisor device to a memory buffer.
+ * When the service returns, the data has been written from the memory buffer,
+ * and the buffer will not be further modified by the driver.
+ *
+ * No ordering is guaranteed between requests issued from different tiles.
+ *
+ * Devices may choose to support both the synchronous and asynchronous read
+ * operations, only one of them, or neither of them.
+ *
+ * @param devhdl Device handle of the device to be read from.
+ * @param flags Flags (HV_DEV_xxx).
+ * @param va Virtual address of the target data buffer. This buffer must
+ * be mapped in the currently installed page table; if not, HV_EFAULT
+ * may be returned.
+ * @param len Number of bytes to be transferred.
+ * @param offset Driver-dependent offset. For a random-access device, this is
+ * often a byte offset from the beginning of the device; in other cases,
+ * like on a control device, it may have a different meaning.
+ * @return A non-negative value if the read was at least partially successful;
+ * otherwise, a negative error code. The precise interpretation of
+ * the return value is driver-dependent, but many drivers will return
+ * the number of bytes successfully transferred.
+ */
+int hv_dev_pread(int devhdl, __hv32 flags, HV_VirtAddr va, __hv32 len,
+ __hv64 offset);
+
+#define HV_DEV_NB_EMPTY 0x1 /**< Don't block when no bytes of data can
+ be transferred. */
+#define HV_DEV_NB_PARTIAL 0x2 /**< Don't block when some bytes, but not all
+ of the requested bytes, can be
+ transferred. */
+#define HV_DEV_NOCACHE 0x4 /**< The caller warrants that none of the
+ cache lines which might contain data
+ from the requested buffer are valid.
+ Useful with asynchronous operations
+ only. */
+
+#define HV_DEV_ALLFLAGS (HV_DEV_NB_EMPTY | HV_DEV_NB_PARTIAL | \
+ HV_DEV_NOCACHE) /**< All HV_DEV_xxx flags */
+
+/** Write data to a hypervisor device synchronously.
+ *
+ * This service transfers data from a memory buffer to a hypervisor device.
+ * When the service returns, the data has been read from the memory buffer,
+ * and the buffer may be overwritten by the client; the data may not
+ * necessarily have been conveyed to the actual hardware I/O interface.
+ *
+ * No ordering is guaranteed between requests issued from different tiles.
+ *
+ * Devices may choose to support both the synchronous and asynchronous write
+ * operations, only one of them, or neither of them.
+ *
+ * @param devhdl Device handle of the device to be written to.
+ * @param flags Flags (HV_DEV_xxx).
+ * @param va Virtual address of the source data buffer. This buffer must
+ * be mapped in the currently installed page table; if not, HV_EFAULT
+ * may be returned.
+ * @param len Number of bytes to be transferred.
+ * @param offset Driver-dependent offset. For a random-access device, this is
+ * often a byte offset from the beginning of the device; in other cases,
+ * like on a control device, it may have a different meaning.
+ * @return A non-negative value if the write was at least partially successful;
+ * otherwise, a negative error code. The precise interpretation of
+ * the return value is driver-dependent, but many drivers will return
+ * the number of bytes successfully transferred.
+ */
+int hv_dev_pwrite(int devhdl, __hv32 flags, HV_VirtAddr va, __hv32 len,
+ __hv64 offset);
+
+
+/** Interrupt arguments, used in the asynchronous I/O interfaces. */
+#if CHIP_VA_WIDTH() > 32
+typedef __hv64 HV_IntArg;
+#else
+typedef __hv32 HV_IntArg;
+#endif
+
+/** Interrupt messages are delivered via the mechanism as normal messages,
+ * but have a message source of HV_DEV_INTR. The message is formatted
+ * as an HV_IntrMsg structure.
+ */
+
+typedef struct
+{
+ HV_IntArg intarg; /**< Interrupt argument, passed to the poll/preada/pwritea
+ services */
+ HV_IntArg intdata; /**< Interrupt-specific interrupt data */
+} HV_IntrMsg;
+
+/** Request an interrupt message when a device condition is satisfied.
+ *
+ * This service requests that an interrupt message be delivered to the
+ * requesting tile when a device becomes readable or writable, or when any
+ * data queued to the device via previous write operations from this tile
+ * has been actually sent out on the hardware I/O interface. Devices may
+ * choose to support any, all, or none of the available conditions.
+ *
+ * If multiple conditions are specified, only one message will be
+ * delivered. If the event mask delivered to that interrupt handler
+ * indicates that some of the conditions have not yet occurred, the
+ * client must issue another poll() call if it wishes to wait for those
+ * conditions.
+ *
+ * Only one poll may be outstanding per device handle per tile. If more than
+ * one tile is polling on the same device and condition, they will all be
+ * notified when it happens. Because of this, clients may not assume that
+ * the condition signaled is necessarily still true when they request a
+ * subsequent service; for instance, the readable data which caused the
+ * poll call to interrupt may have been read by another tile in the interim.
+ *
+ * The notification interrupt message could come directly, or via the
+ * downcall (intctrl1) method, depending on what the tile is doing
+ * when the condition is satisfied. Note that it is possible for the
+ * requested interrupt to be delivered after this service is called but
+ * before it returns.
+ *
+ * @param devhdl Device handle of the device to be polled.
+ * @param events Flags denoting the events which will cause the interrupt to
+ * be delivered (HV_DEVPOLL_xxx).
+ * @param intarg Value which will be delivered as the intarg member of the
+ * eventual interrupt message; the intdata member will be set to a
+ * mask of HV_DEVPOLL_xxx values indicating which conditions have been
+ * satisifed.
+ * @return Zero if the interrupt was successfully scheduled; otherwise, a
+ * negative error code.
+ */
+int hv_dev_poll(int devhdl, __hv32 events, HV_IntArg intarg);
+
+#define HV_DEVPOLL_READ 0x1 /**< Test device for readability */
+#define HV_DEVPOLL_WRITE 0x2 /**< Test device for writability */
+#define HV_DEVPOLL_FLUSH 0x4 /**< Test device for output drained */
+
+
+/** Cancel a request for an interrupt when a device event occurs.
+ *
+ * This service requests that no interrupt be delivered when the events
+ * noted in the last-issued poll() call happen. Once this service returns,
+ * the interrupt has been canceled; however, it is possible for the interrupt
+ * to be delivered after this service is called but before it returns.
+ *
+ * @param devhdl Device handle of the device on which to cancel polling.
+ * @return Zero if the poll was successfully canceled; otherwise, a negative
+ * error code.
+ */
+int hv_dev_poll_cancel(int devhdl);
+
+
+/** Scatter-gather list for preada/pwritea calls. */
+typedef struct
+#if CHIP_VA_WIDTH() <= 32
+__attribute__ ((packed, aligned(4)))
+#endif
+{
+ HV_PhysAddr pa; /**< Client physical address of the buffer segment. */
+ HV_PTE pte; /**< Page table entry describing the caching and location
+ override characteristics of the buffer segment. Some
+ drivers ignore this element and will require that
+ the NOCACHE flag be set on their requests. */
+ __hv32 len; /**< Length of the buffer segment. */
+} HV_SGL;
+
+#define HV_SGL_MAXLEN 16 /**< Maximum number of entries in a scatter-gather
+ list */
+
+/** Read data from a hypervisor device asynchronously.
+ *
+ * This service transfers data from a hypervisor device to a memory buffer.
+ * When the service returns, the read has been scheduled. When the read
+ * completes, an interrupt message will be delivered, and the buffer will
+ * not be further modified by the driver.
+ *
+ * The number of possible outstanding asynchronous requests is defined by
+ * each driver, but it is recommended that it be at least two requests
+ * per tile per device.
+ *
+ * No ordering is guaranteed between synchronous and asynchronous requests,
+ * even those issued on the same tile.
+ *
+ * The completion interrupt message could come directly, or via the downcall
+ * (intctrl1) method, depending on what the tile is doing when the read
+ * completes. Interrupts do not coalesce; one is delivered for each
+ * asynchronous I/O request. Note that it is possible for the requested
+ * interrupt to be delivered after this service is called but before it
+ * returns.
+ *
+ * Devices may choose to support both the synchronous and asynchronous read
+ * operations, only one of them, or neither of them.
+ *
+ * @param devhdl Device handle of the device to be read from.
+ * @param flags Flags (HV_DEV_xxx).
+ * @param sgl_len Number of elements in the scatter-gather list.
+ * @param sgl Scatter-gather list describing the memory to which data will be
+ * written.
+ * @param offset Driver-dependent offset. For a random-access device, this is
+ * often a byte offset from the beginning of the device; in other cases,
+ * like on a control device, it may have a different meaning.
+ * @param intarg Value which will be delivered as the intarg member of the
+ * eventual interrupt message; the intdata member will be set to the
+ * normal return value from the read request.
+ * @return Zero if the read was successfully scheduled; otherwise, a negative
+ * error code. Note that some drivers may choose to pre-validate
+ * their arguments, and may thus detect certain device error
+ * conditions at this time rather than when the completion notification
+ * occurs, but this is not required.
+ */
+int hv_dev_preada(int devhdl, __hv32 flags, __hv32 sgl_len,
+ HV_SGL sgl[/* sgl_len */], __hv64 offset, HV_IntArg intarg);
+
+
+/** Write data to a hypervisor device asynchronously.
+ *
+ * This service transfers data from a memory buffer to a hypervisor
+ * device. When the service returns, the write has been scheduled.
+ * When the write completes, an interrupt message will be delivered,
+ * and the buffer may be overwritten by the client; the data may not
+ * necessarily have been conveyed to the actual hardware I/O interface.
+ *
+ * The number of possible outstanding asynchronous requests is defined by
+ * each driver, but it is recommended that it be at least two requests
+ * per tile per device.
+ *
+ * No ordering is guaranteed between synchronous and asynchronous requests,
+ * even those issued on the same tile.
+ *
+ * The completion interrupt message could come directly, or via the downcall
+ * (intctrl1) method, depending on what the tile is doing when the read
+ * completes. Interrupts do not coalesce; one is delivered for each
+ * asynchronous I/O request. Note that it is possible for the requested
+ * interrupt to be delivered after this service is called but before it
+ * returns.
+ *
+ * Devices may choose to support both the synchronous and asynchronous write
+ * operations, only one of them, or neither of them.
+ *
+ * @param devhdl Device handle of the device to be read from.
+ * @param flags Flags (HV_DEV_xxx).
+ * @param sgl_len Number of elements in the scatter-gather list.
+ * @param sgl Scatter-gather list describing the memory from which data will be
+ * read.
+ * @param offset Driver-dependent offset. For a random-access device, this is
+ * often a byte offset from the beginning of the device; in other cases,
+ * like on a control device, it may have a different meaning.
+ * @param intarg Value which will be delivered as the intarg member of the
+ * eventual interrupt message; the intdata member will be set to the
+ * normal return value from the write request.
+ * @return Zero if the write was successfully scheduled; otherwise, a negative
+ * error code. Note that some drivers may choose to pre-validate
+ * their arguments, and may thus detect certain device error
+ * conditions at this time rather than when the completion notification
+ * occurs, but this is not required.
+ */
+int hv_dev_pwritea(int devhdl, __hv32 flags, __hv32 sgl_len,
+ HV_SGL sgl[/* sgl_len */], __hv64 offset, HV_IntArg intarg);
+
+
+/** Define a pair of tile and ASID to identify a user process context. */
+typedef struct
+{
+ /** X coordinate, relative to supervisor's top-left coordinate */
+ unsigned int x:11;
+
+ /** Y coordinate, relative to supervisor's top-left coordinate */
+ unsigned int y:11;
+
+ /** ASID of the process on this x,y tile */
+ HV_ASID asid:10;
+} HV_Remote_ASID;
+
+/** Flush cache and/or TLB state on remote tiles.
+ *
+ * @param cache_pa Client physical address to flush from cache (ignored if
+ * the length encoded in cache_control is zero, or if
+ * HV_FLUSH_EVICT_L2 is set, or if cache_cpumask is NULL).
+ * @param cache_control This argument allows you to specify a length of
+ * physical address space to flush (maximum HV_FLUSH_MAX_CACHE_LEN).
+ * You can "or" in HV_FLUSH_EVICT_L2 to flush the whole L2 cache.
+ * You can "or" in HV_FLUSH_EVICT_LI1 to flush the whole LII cache.
+ * HV_FLUSH_ALL flushes all caches.
+ * @param cache_cpumask Bitmask (in row-major order, supervisor-relative) of
+ * tile indices to perform cache flush on. The low bit of the first
+ * word corresponds to the tile at the upper left-hand corner of the
+ * supervisor's rectangle. If passed as a NULL pointer, equivalent
+ * to an empty bitmask. On chips which support hash-for-home caching,
+ * if passed as -1, equivalent to a mask containing tiles which could
+ * be doing hash-for-home caching.
+ * @param tlb_va Virtual address to flush from TLB (ignored if
+ * tlb_length is zero or tlb_cpumask is NULL).
+ * @param tlb_length Number of bytes of data to flush from the TLB.
+ * @param tlb_pgsize Page size to use for TLB flushes.
+ * tlb_va and tlb_length need not be aligned to this size.
+ * @param tlb_cpumask Bitmask for tlb flush, like cache_cpumask.
+ * If passed as a NULL pointer, equivalent to an empty bitmask.
+ * @param asids Pointer to an HV_Remote_ASID array of tile/ASID pairs to flush.
+ * @param asidcount Number of HV_Remote_ASID entries in asids[].
+ * @return Zero for success, or else HV_EINVAL or HV_EFAULT for errors that
+ * are detected while parsing the arguments.
+ */
+int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
+ unsigned long* cache_cpumask,
+ HV_VirtAddr tlb_va, unsigned long tlb_length,
+ unsigned long tlb_pgsize, unsigned long* tlb_cpumask,
+ HV_Remote_ASID* asids, int asidcount);
+
+/** Include in cache_control to ensure a flush of the entire L2. */
+#define HV_FLUSH_EVICT_L2 (1UL << 31)
+
+/** Include in cache_control to ensure a flush of the entire L1I. */
+#define HV_FLUSH_EVICT_L1I (1UL << 30)
+
+/** Maximum legal size to use for the "length" component of cache_control. */
+#define HV_FLUSH_MAX_CACHE_LEN ((1UL << 30) - 1)
+
+/** Use for cache_control to ensure a flush of all caches. */
+#define HV_FLUSH_ALL -1UL
+
+#else /* __ASSEMBLER__ */
+
+/** Include in cache_control to ensure a flush of the entire L2. */
+#define HV_FLUSH_EVICT_L2 (1 << 31)
+
+/** Include in cache_control to ensure a flush of the entire L1I. */
+#define HV_FLUSH_EVICT_L1I (1 << 30)
+
+/** Maximum legal size to use for the "length" component of cache_control. */
+#define HV_FLUSH_MAX_CACHE_LEN ((1 << 30) - 1)
+
+/** Use for cache_control to ensure a flush of all caches. */
+#define HV_FLUSH_ALL -1
+
+#endif /* __ASSEMBLER__ */
+
+#ifndef __ASSEMBLER__
+
+/** Return a 64-bit value corresponding to the PTE if needed */
+#define hv_pte_val(pte) ((pte).val)
+
+/** Cast a 64-bit value to an HV_PTE */
+#define hv_pte(val) ((HV_PTE) { val })
+
+#endif /* !__ASSEMBLER__ */
+
+
+/** Bits in the size of an HV_PTE */
+#define HV_LOG2_PTE_SIZE 3
+
+/** Size of an HV_PTE */
+#define HV_PTE_SIZE (1 << HV_LOG2_PTE_SIZE)
+
+
+/* Bits in HV_PTE's low word. */
+#define HV_PTE_INDEX_PRESENT 0 /**< PTE is valid */
+#define HV_PTE_INDEX_MIGRATING 1 /**< Page is migrating */
+#define HV_PTE_INDEX_CLIENT0 2 /**< Page client state 0 */
+#define HV_PTE_INDEX_CLIENT1 3 /**< Page client state 1 */
+#define HV_PTE_INDEX_NC 4 /**< L1$/L2$ incoherent with L3$ */
+#define HV_PTE_INDEX_NO_ALLOC_L1 5 /**< Page is uncached in local L1$ */
+#define HV_PTE_INDEX_NO_ALLOC_L2 6 /**< Page is uncached in local L2$ */
+#define HV_PTE_INDEX_CACHED_PRIORITY 7 /**< Page is priority cached */
+#define HV_PTE_INDEX_PAGE 8 /**< PTE describes a page */
+#define HV_PTE_INDEX_GLOBAL 9 /**< Page is global */
+#define HV_PTE_INDEX_USER 10 /**< Page is user-accessible */
+#define HV_PTE_INDEX_ACCESSED 11 /**< Page has been accessed */
+#define HV_PTE_INDEX_DIRTY 12 /**< Page has been written */
+ /* Bits 13-15 are reserved for
+ future use. */
+#define HV_PTE_INDEX_MODE 16 /**< Page mode; see HV_PTE_MODE_xxx */
+#define HV_PTE_MODE_BITS 3 /**< Number of bits in mode */
+ /* Bit 19 is reserved for
+ future use. */
+#define HV_PTE_INDEX_LOTAR 20 /**< Page's LOTAR; must be high bits
+ of word */
+#define HV_PTE_LOTAR_BITS 12 /**< Number of bits in a LOTAR */
+
+/* Bits in HV_PTE's high word. */
+#define HV_PTE_INDEX_READABLE 32 /**< Page is readable */
+#define HV_PTE_INDEX_WRITABLE 33 /**< Page is writable */
+#define HV_PTE_INDEX_EXECUTABLE 34 /**< Page is executable */
+#define HV_PTE_INDEX_PTFN 35 /**< Page's PTFN; must be high bits
+ of word */
+#define HV_PTE_PTFN_BITS 29 /**< Number of bits in a PTFN */
+
+/** Position of the PFN field within the PTE (subset of the PTFN). */
+#define HV_PTE_INDEX_PFN (HV_PTE_INDEX_PTFN + (HV_LOG2_PAGE_SIZE_SMALL - \
+ HV_LOG2_PAGE_TABLE_ALIGN))
+
+/** Length of the PFN field within the PTE (subset of the PTFN). */
+#define HV_PTE_INDEX_PFN_BITS (HV_PTE_INDEX_PTFN_BITS - \
+ (HV_LOG2_PAGE_SIZE_SMALL - \
+ HV_LOG2_PAGE_TABLE_ALIGN))
+
+/*
+ * Legal values for the PTE's mode field
+ */
+/** Data is not resident in any caches; loads and stores access memory
+ * directly.
+ */
+#define HV_PTE_MODE_UNCACHED 1
+
+/** Data is resident in the tile's local L1 and/or L2 caches; if a load
+ * or store misses there, it goes to memory.
+ *
+ * The copy in the local L1$/L2$ is not invalidated when the copy in
+ * memory is changed.
+ */
+#define HV_PTE_MODE_CACHE_NO_L3 2
+
+/** Data is resident in the tile's local L1 and/or L2 caches. If a load
+ * or store misses there, it goes to an L3 cache in a designated tile;
+ * if it misses there, it goes to memory.
+ *
+ * If the NC bit is not set, the copy in the local L1$/L2$ is invalidated
+ * when the copy in the remote L3$ is changed. Otherwise, such
+ * invalidation will not occur.
+ *
+ * Chips for which CHIP_HAS_COHERENT_LOCAL_CACHE() is 0 do not support
+ * invalidation from an L3$ to another tile's L1$/L2$. If the NC bit is
+ * clear on such a chip, no copy is kept in the local L1$/L2$ in this mode.
+ */
+#define HV_PTE_MODE_CACHE_TILE_L3 3
+
+/** Data is resident in the tile's local L1 and/or L2 caches. If a load
+ * or store misses there, it goes to an L3 cache in one of a set of
+ * designated tiles; if it misses there, it goes to memory. Which tile
+ * is chosen from the set depends upon a hash function applied to the
+ * physical address. This mode is not supported on chips for which
+ * CHIP_HAS_CBOX_HOME_MAP() is 0.
+ *
+ * If the NC bit is not set, the copy in the local L1$/L2$ is invalidated
+ * when the copy in the remote L3$ is changed. Otherwise, such
+ * invalidation will not occur.
+ *
+ * Chips for which CHIP_HAS_COHERENT_LOCAL_CACHE() is 0 do not support
+ * invalidation from an L3$ to another tile's L1$/L2$. If the NC bit is
+ * clear on such a chip, no copy is kept in the local L1$/L2$ in this mode.
+ */
+#define HV_PTE_MODE_CACHE_HASH_L3 4
+
+/** Data is not resident in memory; accesses are instead made to an I/O
+ * device, whose tile coordinates are given by the PTE's LOTAR field.
+ * This mode is only supported on chips for which CHIP_HAS_MMIO() is 1.
+ * The EXECUTABLE bit may not be set in an MMIO PTE.
+ */
+#define HV_PTE_MODE_MMIO 5
+
+
+/* C wants 1ULL so it is typed as __hv64, but the assembler needs just numbers.
+ * The assembler can't handle shifts greater than 31, but treats them
+ * as shifts mod 32, so assembler code must be aware of which word
+ * the bit belongs in when using these macros.
+ */
+#ifdef __ASSEMBLER__
+#define __HV_PTE_ONE 1 /**< One, for assembler */
+#else
+#define __HV_PTE_ONE 1ULL /**< One, for C */
+#endif
+
+/** Is this PTE present?
+ *
+ * If this bit is set, this PTE represents a valid translation or level-2
+ * page table pointer. Otherwise, the page table does not contain a
+ * translation for the subject virtual pages.
+ *
+ * If this bit is not set, the other bits in the PTE are not
+ * interpreted by the hypervisor, and may contain any value.
+ */
+#define HV_PTE_PRESENT (__HV_PTE_ONE << HV_PTE_INDEX_PRESENT)
+
+/** Does this PTE map a page?
+ *
+ * If this bit is set in the level-1 page table, the entry should be
+ * interpreted as a level-2 page table entry mapping a large page.
+ *
+ * This bit should not be modified by the client while PRESENT is set, as
+ * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits.
+ *
+ * In a level-2 page table, this bit is ignored and must be zero.
+ */
+#define HV_PTE_PAGE (__HV_PTE_ONE << HV_PTE_INDEX_PAGE)
+
+/** Is this a global (non-ASID) mapping?
+ *
+ * If this bit is set, the translations established by this PTE will
+ * not be flushed from the TLB by the hv_flush_asid() service; they
+ * will be flushed by the hv_flush_page() or hv_flush_pages() services.
+ *
+ * Setting this bit for translations which are identical in all page
+ * tables (for instance, code and data belonging to a client OS) can
+ * be very beneficial, as it will reduce the number of TLB misses.
+ * Note that, while it is not an error which will be detected by the
+ * hypervisor, it is an extremely bad idea to set this bit for
+ * translations which are _not_ identical in all page tables.
+ *
+ * This bit should not be modified by the client while PRESENT is set, as
+ * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_GLOBAL (__HV_PTE_ONE << HV_PTE_INDEX_GLOBAL)
+
+/** Is this mapping accessible to users?
+ *
+ * If this bit is set, code running at any PL will be permitted to
+ * access the virtual addresses mapped by this PTE. Otherwise, only
+ * code running at PL 1 or above will be allowed to do so.
+ *
+ * This bit should not be modified by the client while PRESENT is set, as
+ * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_USER (__HV_PTE_ONE << HV_PTE_INDEX_USER)
+
+/** Has this mapping been accessed?
+ *
+ * This bit is set by the hypervisor when the memory described by the
+ * translation is accessed for the first time. It is never cleared by
+ * the hypervisor, but may be cleared by the client. After the bit
+ * has been cleared, subsequent references are not guaranteed to set
+ * it again until the translation has been flushed from the TLB.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_ACCESSED (__HV_PTE_ONE << HV_PTE_INDEX_ACCESSED)
+
+/** Is this mapping dirty?
+ *
+ * This bit is set by the hypervisor when the memory described by the
+ * translation is written for the first time. It is never cleared by
+ * the hypervisor, but may be cleared by the client. After the bit
+ * has been cleared, subsequent references are not guaranteed to set
+ * it again until the translation has been flushed from the TLB.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_DIRTY (__HV_PTE_ONE << HV_PTE_INDEX_DIRTY)
+
+/** Migrating bit in PTE.
+ *
+ * This bit is guaranteed not to be inspected or modified by the
+ * hypervisor. The name is indicative of the suggested use by the client
+ * to tag pages whose L3 cache is being migrated from one cpu to another.
+ */
+#define HV_PTE_MIGRATING (__HV_PTE_ONE << HV_PTE_INDEX_MIGRATING)
+
+/** Client-private bit in PTE.
+ *
+ * This bit is guaranteed not to be inspected or modified by the
+ * hypervisor.
+ */
+#define HV_PTE_CLIENT0 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT0)
+
+/** Client-private bit in PTE.
+ *
+ * This bit is guaranteed not to be inspected or modified by the
+ * hypervisor.
+ */
+#define HV_PTE_CLIENT1 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT1)
+
+/** Non-coherent (NC) bit in PTE.
+ *
+ * If this bit is set, the mapping that is set up will be non-coherent
+ * (also known as non-inclusive). This means that changes to the L3
+ * cache will not cause a local copy to be invalidated. It is generally
+ * recommended only for read-only mappings.
+ *
+ * In level-1 PTEs, if the Page bit is clear, this bit determines how the
+ * level-2 page table is accessed.
+ */
+#define HV_PTE_NC (__HV_PTE_ONE << HV_PTE_INDEX_NC)
+
+/** Is this page prevented from filling the L1$?
+ *
+ * If this bit is set, the page described by the PTE will not be cached
+ * the local cpu's L1 cache.
+ *
+ * If CHIP_HAS_NC_AND_NOALLOC_BITS() is not true in <chip.h> for this chip,
+ * it is illegal to use this attribute, and may cause client termination.
+ *
+ * In level-1 PTEs, if the Page bit is clear, this bit
+ * determines how the level-2 page table is accessed.
+ */
+#define HV_PTE_NO_ALLOC_L1 (__HV_PTE_ONE << HV_PTE_INDEX_NO_ALLOC_L1)
+
+/** Is this page prevented from filling the L2$?
+ *
+ * If this bit is set, the page described by the PTE will not be cached
+ * the local cpu's L2 cache.
+ *
+ * If CHIP_HAS_NC_AND_NOALLOC_BITS() is not true in <chip.h> for this chip,
+ * it is illegal to use this attribute, and may cause client termination.
+ *
+ * In level-1 PTEs, if the Page bit is clear, this bit determines how the
+ * level-2 page table is accessed.
+ */
+#define HV_PTE_NO_ALLOC_L2 (__HV_PTE_ONE << HV_PTE_INDEX_NO_ALLOC_L2)
+
+/** Is this a priority page?
+ *
+ * If this bit is set, the page described by the PTE will be given
+ * priority in the cache. Normally this translates into allowing the
+ * page to use only the "red" half of the cache. The client may wish to
+ * then use the hv_set_caching service to specify that other pages which
+ * alias this page will use only the "black" half of the cache.
+ *
+ * If the Cached Priority bit is clear, the hypervisor uses the
+ * current hv_set_caching() value to choose how to cache the page.
+ *
+ * It is illegal to set the Cached Priority bit if the Non-Cached bit
+ * is set and the Cached Remotely bit is clear, i.e. if requests to
+ * the page map directly to memory.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_CACHED_PRIORITY (__HV_PTE_ONE << \
+ HV_PTE_INDEX_CACHED_PRIORITY)
+
+/** Is this a readable mapping?
+ *
+ * If this bit is set, code will be permitted to read from (e.g.,
+ * issue load instructions against) the virtual addresses mapped by
+ * this PTE.
+ *
+ * It is illegal for this bit to be clear if the Writable bit is set.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_READABLE (__HV_PTE_ONE << HV_PTE_INDEX_READABLE)
+
+/** Is this a writable mapping?
+ *
+ * If this bit is set, code will be permitted to write to (e.g., issue
+ * store instructions against) the virtual addresses mapped by this
+ * PTE.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_WRITABLE (__HV_PTE_ONE << HV_PTE_INDEX_WRITABLE)
+
+/** Is this an executable mapping?
+ *
+ * If this bit is set, code will be permitted to execute from
+ * (e.g., jump to) the virtual addresses mapped by this PTE.
+ *
+ * This bit applies to any processor on the tile, if there are more
+ * than one.
+ *
+ * This bit is ignored in level-1 PTEs unless the Page bit is set.
+ */
+#define HV_PTE_EXECUTABLE (__HV_PTE_ONE << HV_PTE_INDEX_EXECUTABLE)
+
+/** The width of a LOTAR's x or y bitfield. */
+#define HV_LOTAR_WIDTH 11
+
+/** Converts an x,y pair to a LOTAR value. */
+#define HV_XY_TO_LOTAR(x, y) ((HV_LOTAR)(((x) << HV_LOTAR_WIDTH) | (y)))
+
+/** Extracts the X component of a lotar. */
+#define HV_LOTAR_X(lotar) ((lotar) >> HV_LOTAR_WIDTH)
+
+/** Extracts the Y component of a lotar. */
+#define HV_LOTAR_Y(lotar) ((lotar) & ((1 << HV_LOTAR_WIDTH) - 1))
+
+#ifndef __ASSEMBLER__
+
+/** Define accessor functions for a PTE bit. */
+#define _HV_BIT(name, bit) \
+static __inline int \
+hv_pte_get_##name(HV_PTE pte) \
+{ \
+ return (pte.val >> HV_PTE_INDEX_##bit) & 1; \
+} \
+ \
+static __inline HV_PTE \
+hv_pte_set_##name(HV_PTE pte) \
+{ \
+ pte.val |= 1ULL << HV_PTE_INDEX_##bit; \
+ return pte; \
+} \
+ \
+static __inline HV_PTE \
+hv_pte_clear_##name(HV_PTE pte) \
+{ \
+ pte.val &= ~(1ULL << HV_PTE_INDEX_##bit); \
+ return pte; \
+}
+
+/* Generate accessors to get, set, and clear various PTE flags.
+ */
+_HV_BIT(present, PRESENT)
+_HV_BIT(page, PAGE)
+_HV_BIT(client0, CLIENT0)
+_HV_BIT(client1, CLIENT1)
+_HV_BIT(migrating, MIGRATING)
+_HV_BIT(nc, NC)
+_HV_BIT(readable, READABLE)
+_HV_BIT(writable, WRITABLE)
+_HV_BIT(executable, EXECUTABLE)
+_HV_BIT(accessed, ACCESSED)
+_HV_BIT(dirty, DIRTY)
+_HV_BIT(no_alloc_l1, NO_ALLOC_L1)
+_HV_BIT(no_alloc_l2, NO_ALLOC_L2)
+_HV_BIT(cached_priority, CACHED_PRIORITY)
+_HV_BIT(global, GLOBAL)
+_HV_BIT(user, USER)
+
+#undef _HV_BIT
+
+/** Get the page mode from the PTE.
+ *
+ * This field generally determines whether and how accesses to the page
+ * are cached; the HV_PTE_MODE_xxx symbols define the legal values for the
+ * page mode. The NC, NO_ALLOC_L1, and NO_ALLOC_L2 bits modify this
+ * general policy.
+ */
+static __inline unsigned int
+hv_pte_get_mode(const HV_PTE pte)
+{
+ return (((__hv32) pte.val) >> HV_PTE_INDEX_MODE) &
+ ((1 << HV_PTE_MODE_BITS) - 1);
+}
+
+/** Set the page mode into a PTE. See hv_pte_get_mode. */
+static __inline HV_PTE
+hv_pte_set_mode(HV_PTE pte, unsigned int val)
+{
+ pte.val &= ~(((1ULL << HV_PTE_MODE_BITS) - 1) << HV_PTE_INDEX_MODE);
+ pte.val |= val << HV_PTE_INDEX_MODE;
+ return pte;
+}
+
+/** Get the page frame number from the PTE.
+ *
+ * This field contains the upper bits of the CPA (client physical
+ * address) of the target page; the complete CPA is this field with
+ * HV_LOG2_PAGE_SIZE_SMALL zero bits appended to it.
+ *
+ * For PTEs in a level-1 page table where the Page bit is set, the
+ * CPA must be aligned modulo the large page size.
+ */
+static __inline unsigned int
+hv_pte_get_pfn(const HV_PTE pte)
+{
+ return pte.val >> HV_PTE_INDEX_PFN;
+}
+
+
+/** Set the page frame number into a PTE. See hv_pte_get_pfn. */
+static __inline HV_PTE
+hv_pte_set_pfn(HV_PTE pte, unsigned int val)
+{
+ /*
+ * Note that the use of "PTFN" in the next line is intentional; we
+ * don't want any garbage lower bits left in that field.
+ */
+ pte.val &= ~(((1ULL << HV_PTE_PTFN_BITS) - 1) << HV_PTE_INDEX_PTFN);
+ pte.val |= (__hv64) val << HV_PTE_INDEX_PFN;
+ return pte;
+}
+
+/** Get the page table frame number from the PTE.
+ *
+ * This field contains the upper bits of the CPA (client physical
+ * address) of the target page table; the complete CPA is this field with
+ * with HV_PAGE_TABLE_ALIGN zero bits appended to it.
+ *
+ * For PTEs in a level-1 page table when the Page bit is not set, the
+ * CPA must be aligned modulo the sticter of HV_PAGE_TABLE_ALIGN and
+ * the level-2 page table size.
+ */
+static __inline unsigned long
+hv_pte_get_ptfn(const HV_PTE pte)
+{
+ return pte.val >> HV_PTE_INDEX_PTFN;
+}
+
+
+/** Set the page table frame number into a PTE. See hv_pte_get_ptfn. */
+static __inline HV_PTE
+hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
+{
+ pte.val &= ~(((1ULL << HV_PTE_PTFN_BITS)-1) << HV_PTE_INDEX_PTFN);
+ pte.val |= (__hv64) val << HV_PTE_INDEX_PTFN;
+ return pte;
+}
+
+
+/** Get the remote tile caching this page.
+ *
+ * Specifies the remote tile which is providing the L3 cache for this page.
+ *
+ * This field is ignored unless the page mode is HV_PTE_MODE_CACHE_TILE_L3.
+ *
+ * In level-1 PTEs, if the Page bit is clear, this field determines how the
+ * level-2 page table is accessed.
+ */
+static __inline unsigned int
+hv_pte_get_lotar(const HV_PTE pte)
+{
+ unsigned int lotar = ((__hv32) pte.val) >> HV_PTE_INDEX_LOTAR;
+
+ return HV_XY_TO_LOTAR( (lotar >> (HV_PTE_LOTAR_BITS / 2)),
+ (lotar & ((1 << (HV_PTE_LOTAR_BITS / 2)) - 1)) );
+}
+
+
+/** Set the remote tile caching a page into a PTE. See hv_pte_get_lotar. */
+static __inline HV_PTE
+hv_pte_set_lotar(HV_PTE pte, unsigned int val)
+{
+ unsigned int x = HV_LOTAR_X(val);
+ unsigned int y = HV_LOTAR_Y(val);
+
+ pte.val &= ~(((1ULL << HV_PTE_LOTAR_BITS)-1) << HV_PTE_INDEX_LOTAR);
+ pte.val |= (x << (HV_PTE_INDEX_LOTAR + HV_PTE_LOTAR_BITS / 2)) |
+ (y << HV_PTE_INDEX_LOTAR);
+ return pte;
+}
+
+#endif /* !__ASSEMBLER__ */
+
+/** Converts a client physical address to a pfn. */
+#define HV_CPA_TO_PFN(p) ((p) >> HV_LOG2_PAGE_SIZE_SMALL)
+
+/** Converts a pfn to a client physical address. */
+#define HV_PFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_SIZE_SMALL)
+
+/** Converts a client physical address to a ptfn. */
+#define HV_CPA_TO_PTFN(p) ((p) >> HV_LOG2_PAGE_TABLE_ALIGN)
+
+/** Converts a ptfn to a client physical address. */
+#define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_TABLE_ALIGN)
+
+/** Converts a ptfn to a pfn. */
+#define HV_PTFN_TO_PFN(p) \
+ ((p) >> (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
+
+/** Converts a pfn to a ptfn. */
+#define HV_PFN_TO_PTFN(p) \
+ ((p) << (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
+
+#if CHIP_VA_WIDTH() > 32
+
+/** Log number of HV_PTE entries in L0 page table */
+#define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN)
+
+/** Number of HV_PTE entries in L0 page table */
+#define HV_L0_ENTRIES (1 << HV_LOG2_L0_ENTRIES)
+
+/** Log size of L0 page table in bytes */
+#define HV_LOG2_L0_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L0_ENTRIES)
+
+/** Size of L0 page table in bytes */
+#define HV_L0_SIZE (1 << HV_LOG2_L0_SIZE)
+
+#ifdef __ASSEMBLER__
+
+/** Index in L0 for a specific VA */
+#define HV_L0_INDEX(va) \
+ (((va) >> HV_LOG2_L1_SPAN) & (HV_L0_ENTRIES - 1))
+
+#else
+
+/** Index in L1 for a specific VA */
+#define HV_L0_INDEX(va) \
+ (((HV_VirtAddr)(va) >> HV_LOG2_L1_SPAN) & (HV_L0_ENTRIES - 1))
+
+#endif
+
+#endif /* CHIP_VA_WIDTH() > 32 */
+
+/** Log number of HV_PTE entries in L1 page table */
+#define HV_LOG2_L1_ENTRIES (HV_LOG2_L1_SPAN - HV_LOG2_PAGE_SIZE_LARGE)
+
+/** Number of HV_PTE entries in L1 page table */
+#define HV_L1_ENTRIES (1 << HV_LOG2_L1_ENTRIES)
+
+/** Log size of L1 page table in bytes */
+#define HV_LOG2_L1_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L1_ENTRIES)
+
+/** Size of L1 page table in bytes */
+#define HV_L1_SIZE (1 << HV_LOG2_L1_SIZE)
+
+/** Log number of HV_PTE entries in level-2 page table */
+#define HV_LOG2_L2_ENTRIES (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL)
+
+/** Number of HV_PTE entries in level-2 page table */
+#define HV_L2_ENTRIES (1 << HV_LOG2_L2_ENTRIES)
+
+/** Log size of level-2 page table in bytes */
+#define HV_LOG2_L2_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L2_ENTRIES)
+
+/** Size of level-2 page table in bytes */
+#define HV_L2_SIZE (1 << HV_LOG2_L2_SIZE)
+
+#ifdef __ASSEMBLER__
+
+#if CHIP_VA_WIDTH() > 32
+
+/** Index in L1 for a specific VA */
+#define HV_L1_INDEX(va) \
+ (((va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1))
+
+#else /* CHIP_VA_WIDTH() > 32 */
+
+/** Index in L1 for a specific VA */
+#define HV_L1_INDEX(va) \
+ (((va) >> HV_LOG2_PAGE_SIZE_LARGE))
+
+#endif /* CHIP_VA_WIDTH() > 32 */
+
+/** Index in level-2 page table for a specific VA */
+#define HV_L2_INDEX(va) \
+ (((va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1))
+
+#else /* __ASSEMBLER __ */
+
+#if CHIP_VA_WIDTH() > 32
+
+/** Index in L1 for a specific VA */
+#define HV_L1_INDEX(va) \
+ (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE) & (HV_L1_ENTRIES - 1))
+
+#else /* CHIP_VA_WIDTH() > 32 */
+
+/** Index in L1 for a specific VA */
+#define HV_L1_INDEX(va) \
+ (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_LARGE))
+
+#endif /* CHIP_VA_WIDTH() > 32 */
+
+/** Index in level-2 page table for a specific VA */
+#define HV_L2_INDEX(va) \
+ (((HV_VirtAddr)(va) >> HV_LOG2_PAGE_SIZE_SMALL) & (HV_L2_ENTRIES - 1))
+
+#endif /* __ASSEMBLER __ */
+
+#endif /* _TILE_HV_H */
diff --git a/arch/tile/include/hv/syscall_public.h b/arch/tile/include/hv/syscall_public.h
new file mode 100644
index 000000000000..9cc0837e69fd
--- /dev/null
+++ b/arch/tile/include/hv/syscall_public.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/**
+ * @file syscall.h
+ * Indices for the hypervisor system calls that are intended to be called
+ * directly, rather than only through hypervisor-generated "glue" code.
+ */
+
+#ifndef _SYS_HV_INCLUDE_SYSCALL_PUBLIC_H
+#define _SYS_HV_INCLUDE_SYSCALL_PUBLIC_H
+
+/** Fast syscall flag bit location. When this bit is set, the hypervisor
+ * handles the syscall specially.
+ */
+#define HV_SYS_FAST_SHIFT 14
+
+/** Fast syscall flag bit mask. */
+#define HV_SYS_FAST_MASK (1 << HV_SYS_FAST_SHIFT)
+
+/** Bit location for flagging fast syscalls that can be called from PL0. */
+#define HV_SYS_FAST_PLO_SHIFT 13
+
+/** Fast syscall allowing PL0 bit mask. */
+#define HV_SYS_FAST_PL0_MASK (1 << HV_SYS_FAST_PLO_SHIFT)
+
+/** Perform an MF that waits for all victims to reach DRAM. */
+#define HV_SYS_fence_incoherent (51 | HV_SYS_FAST_MASK \
+ | HV_SYS_FAST_PL0_MASK)
+
+#endif /* !_SYS_HV_INCLUDE_SYSCALL_PUBLIC_H */
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
new file mode 100644
index 000000000000..756e6ec452d3
--- /dev/null
+++ b/arch/tile/kernel/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the Linux/TILE kernel.
+#
+
+extra-y := vmlinux.lds head_$(BITS).o
+obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
+ pci-dma.o proc.o process.o ptrace.o reboot.o \
+ setup.o signal.o single_step.o stack.o sys.o time.o traps.o \
+ intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o
+
+obj-$(CONFIG_TILEGX) += futex_64.o
+obj-$(CONFIG_COMPAT) += compat.o compat_signal.o
+obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
diff --git a/arch/tile/kernel/asm-offsets.c b/arch/tile/kernel/asm-offsets.c
new file mode 100644
index 000000000000..01ddf19cc36d
--- /dev/null
+++ b/arch/tile/kernel/asm-offsets.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Generates definitions from c-type structures used by assembly sources.
+ */
+
+#include <linux/kbuild.h>
+#include <linux/thread_info.h>
+#include <linux/sched.h>
+#include <linux/hardirq.h>
+#include <linux/ptrace.h>
+#include <hv/hypervisor.h>
+
+/* Check for compatible compiler early in the build. */
+#ifdef CONFIG_TILEGX
+# ifndef __tilegx__
+# error Can only build TILE-Gx configurations with tilegx compiler
+# endif
+# ifndef __LP64__
+# error Must not specify -m32 when building the TILE-Gx kernel
+# endif
+#else
+# ifdef __tilegx__
+# error Can not build TILEPro/TILE64 configurations with tilegx compiler
+# endif
+#endif
+
+void foo(void)
+{
+ DEFINE(SINGLESTEP_STATE_BUFFER_OFFSET, \
+ offsetof(struct single_step_state, buffer));
+ DEFINE(SINGLESTEP_STATE_FLAGS_OFFSET, \
+ offsetof(struct single_step_state, flags));
+ DEFINE(SINGLESTEP_STATE_ORIG_PC_OFFSET, \
+ offsetof(struct single_step_state, orig_pc));
+ DEFINE(SINGLESTEP_STATE_NEXT_PC_OFFSET, \
+ offsetof(struct single_step_state, next_pc));
+ DEFINE(SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET, \
+ offsetof(struct single_step_state, branch_next_pc));
+ DEFINE(SINGLESTEP_STATE_UPDATE_VALUE_OFFSET, \
+ offsetof(struct single_step_state, update_value));
+
+ DEFINE(THREAD_INFO_TASK_OFFSET, \
+ offsetof(struct thread_info, task));
+ DEFINE(THREAD_INFO_FLAGS_OFFSET, \
+ offsetof(struct thread_info, flags));
+ DEFINE(THREAD_INFO_STATUS_OFFSET, \
+ offsetof(struct thread_info, status));
+ DEFINE(THREAD_INFO_HOMECACHE_CPU_OFFSET, \
+ offsetof(struct thread_info, homecache_cpu));
+ DEFINE(THREAD_INFO_STEP_STATE_OFFSET, \
+ offsetof(struct thread_info, step_state));
+
+ DEFINE(TASK_STRUCT_THREAD_KSP_OFFSET,
+ offsetof(struct task_struct, thread.ksp));
+ DEFINE(TASK_STRUCT_THREAD_PC_OFFSET,
+ offsetof(struct task_struct, thread.pc));
+
+ DEFINE(HV_TOPOLOGY_WIDTH_OFFSET, \
+ offsetof(HV_Topology, width));
+ DEFINE(HV_TOPOLOGY_HEIGHT_OFFSET, \
+ offsetof(HV_Topology, height));
+
+ DEFINE(IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET, \
+ offsetof(irq_cpustat_t, irq_syscall_count));
+}
diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c
new file mode 100644
index 000000000000..1b0a410ef5e7
--- /dev/null
+++ b/arch/tile/kernel/backtrace.c
@@ -0,0 +1,634 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+#include <asm/backtrace.h>
+
+#include <arch/chip.h>
+
+#if TILE_CHIP < 10
+
+
+#include <asm/opcode-tile.h>
+
+
+#define TREG_SP 54
+#define TREG_LR 55
+
+
+/** A decoded bundle used for backtracer analysis. */
+typedef struct {
+ tile_bundle_bits bits;
+ int num_insns;
+ struct tile_decoded_instruction
+ insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE];
+} BacktraceBundle;
+
+
+/* This implementation only makes sense for native tools. */
+/** Default function to read memory. */
+static bool
+bt_read_memory(void *result, VirtualAddress addr, size_t size, void *extra)
+{
+ /* FIXME: this should do some horrible signal stuff to catch
+ * SEGV cleanly and fail.
+ *
+ * Or else the caller should do the setjmp for efficiency.
+ */
+
+ memcpy(result, (const void *)addr, size);
+ return true;
+}
+
+
+/** Locates an instruction inside the given bundle that
+ * has the specified mnemonic, and whose first 'num_operands_to_match'
+ * operands exactly match those in 'operand_values'.
+ */
+static const struct tile_decoded_instruction*
+find_matching_insn(const BacktraceBundle *bundle,
+ tile_mnemonic mnemonic,
+ const int *operand_values,
+ int num_operands_to_match)
+{
+ int i, j;
+ bool match;
+
+ for (i = 0; i < bundle->num_insns; i++) {
+ const struct tile_decoded_instruction *insn =
+ &bundle->insns[i];
+
+ if (insn->opcode->mnemonic != mnemonic)
+ continue;
+
+ match = true;
+ for (j = 0; j < num_operands_to_match; j++) {
+ if (operand_values[j] != insn->operand_values[j]) {
+ match = false;
+ break;
+ }
+ }
+
+ if (match)
+ return insn;
+ }
+
+ return NULL;
+}
+
+/** Does this bundle contain an 'iret' instruction? */
+static inline bool
+bt_has_iret(const BacktraceBundle *bundle)
+{
+ return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL;
+}
+
+/** Does this bundle contain an 'addi sp, sp, OFFSET' or
+ * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET?
+ */
+static bool
+bt_has_addi_sp(const BacktraceBundle *bundle, int *adjust)
+{
+ static const int vals[2] = { TREG_SP, TREG_SP };
+
+ const struct tile_decoded_instruction *insn =
+ find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2);
+ if (insn == NULL)
+ insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2);
+ if (insn == NULL)
+ return false;
+
+ *adjust = insn->operand_values[2];
+ return true;
+}
+
+/** Does this bundle contain any 'info OP' or 'infol OP'
+ * instruction, and if so, what are their OP? Note that OP is interpreted
+ * as an unsigned value by this code since that's what the caller wants.
+ * Returns the number of info ops found.
+ */
+static int
+bt_get_info_ops(const BacktraceBundle *bundle,
+ int operands[MAX_INFO_OPS_PER_BUNDLE])
+{
+ int num_ops = 0;
+ int i;
+
+ for (i = 0; i < bundle->num_insns; i++) {
+ const struct tile_decoded_instruction *insn =
+ &bundle->insns[i];
+
+ if (insn->opcode->mnemonic == TILE_OPC_INFO ||
+ insn->opcode->mnemonic == TILE_OPC_INFOL) {
+ operands[num_ops++] = insn->operand_values[0];
+ }
+ }
+
+ return num_ops;
+}
+
+/** Does this bundle contain a jrp instruction, and if so, to which
+ * register is it jumping?
+ */
+static bool
+bt_has_jrp(const BacktraceBundle *bundle, int *target_reg)
+{
+ const struct tile_decoded_instruction *insn =
+ find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0);
+ if (insn == NULL)
+ return false;
+
+ *target_reg = insn->operand_values[0];
+ return true;
+}
+
+/** Does this bundle modify the specified register in any way? */
+static bool
+bt_modifies_reg(const BacktraceBundle *bundle, int reg)
+{
+ int i, j;
+ for (i = 0; i < bundle->num_insns; i++) {
+ const struct tile_decoded_instruction *insn =
+ &bundle->insns[i];
+
+ if (insn->opcode->implicitly_written_register == reg)
+ return true;
+
+ for (j = 0; j < insn->opcode->num_operands; j++)
+ if (insn->operands[j]->is_dest_reg &&
+ insn->operand_values[j] == reg)
+ return true;
+ }
+
+ return false;
+}
+
+/** Does this bundle modify sp? */
+static inline bool
+bt_modifies_sp(const BacktraceBundle *bundle)
+{
+ return bt_modifies_reg(bundle, TREG_SP);
+}
+
+/** Does this bundle modify lr? */
+static inline bool
+bt_modifies_lr(const BacktraceBundle *bundle)
+{
+ return bt_modifies_reg(bundle, TREG_LR);
+}
+
+/** Does this bundle contain the instruction 'move fp, sp'? */
+static inline bool
+bt_has_move_r52_sp(const BacktraceBundle *bundle)
+{
+ static const int vals[2] = { 52, TREG_SP };
+ return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL;
+}
+
+/** Does this bundle contain the instruction 'sw sp, lr'? */
+static inline bool
+bt_has_sw_sp_lr(const BacktraceBundle *bundle)
+{
+ static const int vals[2] = { TREG_SP, TREG_LR };
+ return find_matching_insn(bundle, TILE_OPC_SW, vals, 2) != NULL;
+}
+
+/** Locates the caller's PC and SP for a program starting at the
+ * given address.
+ */
+static void
+find_caller_pc_and_caller_sp(CallerLocation *location,
+ const VirtualAddress start_pc,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra)
+{
+ /* Have we explicitly decided what the sp is,
+ * rather than just the default?
+ */
+ bool sp_determined = false;
+
+ /* Has any bundle seen so far modified lr? */
+ bool lr_modified = false;
+
+ /* Have we seen a move from sp to fp? */
+ bool sp_moved_to_r52 = false;
+
+ /* Have we seen a terminating bundle? */
+ bool seen_terminating_bundle = false;
+
+ /* Cut down on round-trip reading overhead by reading several
+ * bundles at a time.
+ */
+ tile_bundle_bits prefetched_bundles[32];
+ int num_bundles_prefetched = 0;
+ int next_bundle = 0;
+ VirtualAddress pc;
+
+ /* Default to assuming that the caller's sp is the current sp.
+ * This is necessary to handle the case where we start backtracing
+ * right at the end of the epilog.
+ */
+ location->sp_location = SP_LOC_OFFSET;
+ location->sp_offset = 0;
+
+ /* Default to having no idea where the caller PC is. */
+ location->pc_location = PC_LOC_UNKNOWN;
+
+ /* Don't even try if the PC is not aligned. */
+ if (start_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0)
+ return;
+
+ for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) {
+
+ BacktraceBundle bundle;
+ int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE];
+ int one_ago, jrp_reg;
+ bool has_jrp;
+
+ if (next_bundle >= num_bundles_prefetched) {
+ /* Prefetch some bytes, but don't cross a page
+ * boundary since that might cause a read failure we
+ * don't care about if we only need the first few
+ * bytes. Note: we don't care what the actual page
+ * size is; using the minimum possible page size will
+ * prevent any problems.
+ */
+ unsigned int bytes_to_prefetch = 4096 - (pc & 4095);
+ if (bytes_to_prefetch > sizeof prefetched_bundles)
+ bytes_to_prefetch = sizeof prefetched_bundles;
+
+ if (!read_memory_func(prefetched_bundles, pc,
+ bytes_to_prefetch,
+ read_memory_func_extra)) {
+ if (pc == start_pc) {
+ /* The program probably called a bad
+ * address, such as a NULL pointer.
+ * So treat this as if we are at the
+ * start of the function prolog so the
+ * backtrace will show how we got here.
+ */
+ location->pc_location = PC_LOC_IN_LR;
+ return;
+ }
+
+ /* Unreadable address. Give up. */
+ break;
+ }
+
+ next_bundle = 0;
+ num_bundles_prefetched =
+ bytes_to_prefetch / sizeof(tile_bundle_bits);
+ }
+
+ /* Decode the next bundle. */
+ bundle.bits = prefetched_bundles[next_bundle++];
+ bundle.num_insns =
+ parse_insn_tile(bundle.bits, pc, bundle.insns);
+ num_info_ops = bt_get_info_ops(&bundle, info_operands);
+
+ /* First look at any one_ago info ops if they are interesting,
+ * since they should shadow any non-one-ago info ops.
+ */
+ for (one_ago = (pc != start_pc) ? 1 : 0;
+ one_ago >= 0; one_ago--) {
+ int i;
+ for (i = 0; i < num_info_ops; i++) {
+ int info_operand = info_operands[i];
+ if (info_operand < CALLER_UNKNOWN_BASE) {
+ /* Weird; reserved value, ignore it. */
+ continue;
+ }
+
+ /* Skip info ops which are not in the
+ * "one_ago" mode we want right now.
+ */
+ if (((info_operand & ONE_BUNDLE_AGO_FLAG) != 0)
+ != (one_ago != 0))
+ continue;
+
+ /* Clear the flag to make later checking
+ * easier. */
+ info_operand &= ~ONE_BUNDLE_AGO_FLAG;
+
+ /* Default to looking at PC_IN_LR_FLAG. */
+ if (info_operand & PC_IN_LR_FLAG)
+ location->pc_location =
+ PC_LOC_IN_LR;
+ else
+ location->pc_location =
+ PC_LOC_ON_STACK;
+
+ switch (info_operand) {
+ case CALLER_UNKNOWN_BASE:
+ location->pc_location = PC_LOC_UNKNOWN;
+ location->sp_location = SP_LOC_UNKNOWN;
+ return;
+
+ case CALLER_SP_IN_R52_BASE:
+ case CALLER_SP_IN_R52_BASE | PC_IN_LR_FLAG:
+ location->sp_location = SP_LOC_IN_R52;
+ return;
+
+ default:
+ {
+ const unsigned int val = info_operand
+ - CALLER_SP_OFFSET_BASE;
+ const unsigned int sp_offset =
+ (val >> NUM_INFO_OP_FLAGS) * 8;
+ if (sp_offset < 32768) {
+ /* This is a properly encoded
+ * SP offset. */
+ location->sp_location =
+ SP_LOC_OFFSET;
+ location->sp_offset =
+ sp_offset;
+ return;
+ } else {
+ /* This looked like an SP
+ * offset, but it's outside
+ * the legal range, so this
+ * must be an unrecognized
+ * info operand. Ignore it.
+ */
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (seen_terminating_bundle) {
+ /* We saw a terminating bundle during the previous
+ * iteration, so we were only looking for an info op.
+ */
+ break;
+ }
+
+ if (bundle.bits == 0) {
+ /* Wacky terminating bundle. Stop looping, and hope
+ * we've already seen enough to find the caller.
+ */
+ break;
+ }
+
+ /*
+ * Try to determine caller's SP.
+ */
+
+ if (!sp_determined) {
+ int adjust;
+ if (bt_has_addi_sp(&bundle, &adjust)) {
+ location->sp_location = SP_LOC_OFFSET;
+
+ if (adjust <= 0) {
+ /* We are in prolog about to adjust
+ * SP. */
+ location->sp_offset = 0;
+ } else {
+ /* We are in epilog restoring SP. */
+ location->sp_offset = adjust;
+ }
+
+ sp_determined = true;
+ } else {
+ if (bt_has_move_r52_sp(&bundle)) {
+ /* Maybe in prolog, creating an
+ * alloca-style frame. But maybe in
+ * the middle of a fixed-size frame
+ * clobbering r52 with SP.
+ */
+ sp_moved_to_r52 = true;
+ }
+
+ if (bt_modifies_sp(&bundle)) {
+ if (sp_moved_to_r52) {
+ /* We saw SP get saved into
+ * r52 earlier (or now), which
+ * must have been in the
+ * prolog, so we now know that
+ * SP is still holding the
+ * caller's sp value.
+ */
+ location->sp_location =
+ SP_LOC_OFFSET;
+ location->sp_offset = 0;
+ } else {
+ /* Someone must have saved
+ * aside the caller's SP value
+ * into r52, so r52 holds the
+ * current value.
+ */
+ location->sp_location =
+ SP_LOC_IN_R52;
+ }
+ sp_determined = true;
+ }
+ }
+ }
+
+ if (bt_has_iret(&bundle)) {
+ /* This is a terminating bundle. */
+ seen_terminating_bundle = true;
+ continue;
+ }
+
+ /*
+ * Try to determine caller's PC.
+ */
+
+ jrp_reg = -1;
+ has_jrp = bt_has_jrp(&bundle, &jrp_reg);
+ if (has_jrp)
+ seen_terminating_bundle = true;
+
+ if (location->pc_location == PC_LOC_UNKNOWN) {
+ if (has_jrp) {
+ if (jrp_reg == TREG_LR && !lr_modified) {
+ /* Looks like a leaf function, or else
+ * lr is already restored. */
+ location->pc_location =
+ PC_LOC_IN_LR;
+ } else {
+ location->pc_location =
+ PC_LOC_ON_STACK;
+ }
+ } else if (bt_has_sw_sp_lr(&bundle)) {
+ /* In prolog, spilling initial lr to stack. */
+ location->pc_location = PC_LOC_IN_LR;
+ } else if (bt_modifies_lr(&bundle)) {
+ lr_modified = true;
+ }
+ }
+ }
+}
+
+void
+backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ VirtualAddress pc, VirtualAddress lr,
+ VirtualAddress sp, VirtualAddress r52)
+{
+ CallerLocation location;
+ VirtualAddress fp, initial_frame_caller_pc;
+
+ if (read_memory_func == NULL) {
+ read_memory_func = bt_read_memory;
+ }
+
+ /* Find out where we are in the initial frame. */
+ find_caller_pc_and_caller_sp(&location, pc,
+ read_memory_func, read_memory_func_extra);
+
+ switch (location.sp_location) {
+ case SP_LOC_UNKNOWN:
+ /* Give up. */
+ fp = -1;
+ break;
+
+ case SP_LOC_IN_R52:
+ fp = r52;
+ break;
+
+ case SP_LOC_OFFSET:
+ fp = sp + location.sp_offset;
+ break;
+
+ default:
+ /* Give up. */
+ fp = -1;
+ break;
+ }
+
+ /* The frame pointer should theoretically be aligned mod 8. If
+ * it's not even aligned mod 4 then something terrible happened
+ * and we should mark it as invalid.
+ */
+ if (fp % 4 != 0)
+ fp = -1;
+
+ /* -1 means "don't know initial_frame_caller_pc". */
+ initial_frame_caller_pc = -1;
+
+ switch (location.pc_location) {
+ case PC_LOC_UNKNOWN:
+ /* Give up. */
+ fp = -1;
+ break;
+
+ case PC_LOC_IN_LR:
+ if (lr == 0 || lr % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) {
+ /* Give up. */
+ fp = -1;
+ } else {
+ initial_frame_caller_pc = lr;
+ }
+ break;
+
+ case PC_LOC_ON_STACK:
+ /* Leave initial_frame_caller_pc as -1,
+ * meaning check the stack.
+ */
+ break;
+
+ default:
+ /* Give up. */
+ fp = -1;
+ break;
+ }
+
+ state->pc = pc;
+ state->sp = sp;
+ state->fp = fp;
+ state->initial_frame_caller_pc = initial_frame_caller_pc;
+ state->read_memory_func = read_memory_func;
+ state->read_memory_func_extra = read_memory_func_extra;
+}
+
+bool
+backtrace_next(BacktraceIterator *state)
+{
+ VirtualAddress next_fp, next_pc, next_frame[2];
+
+ if (state->fp == -1) {
+ /* No parent frame. */
+ return false;
+ }
+
+ /* Try to read the frame linkage data chaining to the next function. */
+ if (!state->read_memory_func(&next_frame, state->fp, sizeof next_frame,
+ state->read_memory_func_extra)) {
+ return false;
+ }
+
+ next_fp = next_frame[1];
+ if (next_fp % 4 != 0) {
+ /* Caller's frame pointer is suspect, so give up.
+ * Technically it should be aligned mod 8, but we will
+ * be forgiving here.
+ */
+ return false;
+ }
+
+ if (state->initial_frame_caller_pc != -1) {
+ /* We must be in the initial stack frame and already know the
+ * caller PC.
+ */
+ next_pc = state->initial_frame_caller_pc;
+
+ /* Force reading stack next time, in case we were in the
+ * initial frame. We don't do this above just to paranoidly
+ * avoid changing the struct at all when we return false.
+ */
+ state->initial_frame_caller_pc = -1;
+ } else {
+ /* Get the caller PC from the frame linkage area. */
+ next_pc = next_frame[0];
+ if (next_pc == 0 ||
+ next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) {
+ /* The PC is suspect, so give up. */
+ return false;
+ }
+ }
+
+ /* Update state to become the caller's stack frame. */
+ state->pc = next_pc;
+ state->sp = state->fp;
+ state->fp = next_fp;
+
+ return true;
+}
+
+#else /* TILE_CHIP < 10 */
+
+void
+backtrace_init(BacktraceIterator *state,
+ BacktraceMemoryReader read_memory_func,
+ void *read_memory_func_extra,
+ VirtualAddress pc, VirtualAddress lr,
+ VirtualAddress sp, VirtualAddress r52)
+{
+ state->pc = pc;
+ state->sp = sp;
+ state->fp = -1;
+ state->initial_frame_caller_pc = -1;
+ state->read_memory_func = read_memory_func;
+ state->read_memory_func_extra = read_memory_func_extra;
+}
+
+bool backtrace_next(BacktraceIterator *state) { return false; }
+
+#endif /* TILE_CHIP < 10 */
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
new file mode 100644
index 000000000000..a374c99deeb6
--- /dev/null
+++ b/arch/tile/kernel/compat.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+/* Adjust unistd.h to provide 32-bit numbers and functions. */
+#define __SYSCALL_COMPAT
+
+#include <linux/compat.h>
+#include <linux/msg.h>
+#include <linux/syscalls.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+#include <linux/fcntl.h>
+#include <linux/smp_lock.h>
+#include <linux/uaccess.h>
+#include <linux/signal.h>
+#include <asm/syscalls.h>
+
+/*
+ * Syscalls that take 64-bit numbers traditionally take them in 32-bit
+ * "high" and "low" value parts on 32-bit architectures.
+ * In principle, one could imagine passing some register arguments as
+ * fully 64-bit on TILE-Gx in 32-bit mode, but it seems easier to
+ * adapt the usual convention.
+ */
+
+long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high)
+{
+ return sys_truncate(filename, ((loff_t)high << 32) | low);
+}
+
+long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high)
+{
+ return sys_ftruncate(fd, ((loff_t)high << 32) | low);
+}
+
+long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high)
+{
+ return sys_pread64(fd, ubuf, count, ((loff_t)high << 32) | low);
+}
+
+long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count,
+ u32 dummy, u32 low, u32 high)
+{
+ return sys_pwrite64(fd, ubuf, count, ((loff_t)high << 32) | low);
+}
+
+long compat_sys_lookup_dcookie(u32 low, u32 high, char __user *buf, size_t len)
+{
+ return sys_lookup_dcookie(((loff_t)high << 32) | low, buf, len);
+}
+
+long compat_sys_sync_file_range2(int fd, unsigned int flags,
+ u32 offset_lo, u32 offset_hi,
+ u32 nbytes_lo, u32 nbytes_hi)
+{
+ return sys_sync_file_range(fd, ((loff_t)offset_hi << 32) | offset_lo,
+ ((loff_t)nbytes_hi << 32) | nbytes_lo,
+ flags);
+}
+
+long compat_sys_fallocate(int fd, int mode,
+ u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi)
+{
+ return sys_fallocate(fd, mode, ((loff_t)offset_hi << 32) | offset_lo,
+ ((loff_t)len_hi << 32) | len_lo);
+}
+
+
+
+long compat_sys_sched_rr_get_interval(compat_pid_t pid,
+ struct compat_timespec __user *interval)
+{
+ struct timespec t;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ set_fs(KERNEL_DS);
+ ret = sys_sched_rr_get_interval(pid, (struct timespec __user *)&t);
+ set_fs(old_fs);
+ if (put_compat_timespec(&t, interval))
+ return -EFAULT;
+ return ret;
+}
+
+ssize_t compat_sys_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
+ size_t count)
+{
+ mm_segment_t old_fs = get_fs();
+ int ret;
+ off_t of;
+
+ if (offset && get_user(of, offset))
+ return -EFAULT;
+
+ set_fs(KERNEL_DS);
+ ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL,
+ count);
+ set_fs(old_fs);
+
+ if (offset && put_user(of, offset))
+ return -EFAULT;
+ return ret;
+}
+
+
+/*
+ * The usual compat_sys_msgsnd() and _msgrcv() seem to be assuming
+ * some different calling convention than our normal 32-bit tile code.
+ */
+
+/* Already defined in ipc/compat.c, but we need it here. */
+struct compat_msgbuf {
+ compat_long_t mtype;
+ char mtext[1];
+};
+
+long tile_compat_sys_msgsnd(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, int msgflg)
+{
+ compat_long_t mtype;
+
+ if (get_user(mtype, &msgp->mtype))
+ return -EFAULT;
+ return do_msgsnd(msqid, mtype, msgp->mtext, msgsz, msgflg);
+}
+
+long tile_compat_sys_msgrcv(int msqid,
+ struct compat_msgbuf __user *msgp,
+ size_t msgsz, long msgtyp, int msgflg)
+{
+ long err, mtype;
+
+ err = do_msgrcv(msqid, &mtype, msgp->mtext, msgsz, msgtyp, msgflg);
+ if (err < 0)
+ goto out;
+
+ if (put_user(mtype, &msgp->mtype))
+ err = -EFAULT;
+ out:
+ return err;
+}
+
+/* Provide the compat syscall number to call mapping. */
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (compat_##call),
+
+/* The generic versions of these don't work for Tile. */
+#define compat_sys_msgrcv tile_compat_sys_msgrcv
+#define compat_sys_msgsnd tile_compat_sys_msgsnd
+
+/* See comments in sys.c */
+#define compat_sys_fadvise64 sys32_fadvise64
+#define compat_sys_fadvise64_64 sys32_fadvise64_64
+#define compat_sys_readahead sys32_readahead
+#define compat_sys_sync_file_range compat_sys_sync_file_range2
+
+/* The native 64-bit "struct stat" matches the 32-bit "struct stat64". */
+#define compat_sys_stat64 sys_newstat
+#define compat_sys_lstat64 sys_newlstat
+#define compat_sys_fstat64 sys_newfstat
+#define compat_sys_fstatat64 sys_newfstatat
+
+/* Pass full 64-bit values through ptrace. */
+#define compat_sys_ptrace tile_compat_sys_ptrace
+
+void *compat_sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls-1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
new file mode 100644
index 000000000000..9fa4ba8ed5f4
--- /dev/null
+++ b/arch/tile/kernel/compat_signal.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <linux/suspend.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h>
+#include <linux/compat.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/sigframe.h>
+#include <arch/interrupts.h>
+
+struct compat_sigaction {
+ compat_uptr_t sa_handler;
+ compat_ulong_t sa_flags;
+ compat_uptr_t sa_restorer;
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+struct compat_sigaltstack {
+ compat_uptr_t ss_sp;
+ int ss_flags;
+ compat_size_t ss_size;
+};
+
+struct compat_ucontext {
+ compat_ulong_t uc_flags;
+ compat_uptr_t uc_link;
+ struct compat_sigaltstack uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+struct compat_siginfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ union {
+ int _pad[SI_PAD_SIZE];
+
+ /* kill() */
+ struct {
+ unsigned int _pid; /* sender's pid */
+ unsigned int _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ compat_sigval_t _sigval; /* same as below */
+ int _sys_private; /* not to be passed to user */
+ int _overrun_incr; /* amount to add to overrun */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ unsigned int _pid; /* sender's pid */
+ unsigned int _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ unsigned int _pid; /* which child */
+ unsigned int _uid; /* sender's uid */
+ int _status; /* exit code */
+ compat_clock_t _utime;
+ compat_clock_t _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ struct {
+ unsigned int _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+ int _trapno; /* TRAP # which caused the signal */
+#endif
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+ } _sifields;
+};
+
+struct compat_rt_sigframe {
+ unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */
+ struct compat_siginfo info;
+ struct compat_ucontext uc;
+};
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
+ struct compat_sigaction __user *oact,
+ size_t sigsetsize)
+{
+ struct k_sigaction new_sa, old_sa;
+ int ret = -EINVAL;
+
+ /* XXX: Don't preclude handling different sized sigset_t's. */
+ if (sigsetsize != sizeof(sigset_t))
+ goto out;
+
+ if (act) {
+ compat_uptr_t handler, restorer;
+
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
+ __get_user(handler, &act->sa_handler) ||
+ __get_user(new_sa.sa.sa_flags, &act->sa_flags) ||
+ __get_user(restorer, &act->sa_restorer) ||
+ __copy_from_user(&new_sa.sa.sa_mask, &act->sa_mask,
+ sizeof(sigset_t)))
+ return -EFAULT;
+ new_sa.sa.sa_handler = compat_ptr(handler);
+ new_sa.sa.sa_restorer = compat_ptr(restorer);
+ }
+
+ ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL);
+
+ if (!ret && oact) {
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
+ __put_user(ptr_to_compat(old_sa.sa.sa_handler),
+ &oact->sa_handler) ||
+ __put_user(ptr_to_compat(old_sa.sa.sa_restorer),
+ &oact->sa_restorer) ||
+ __put_user(old_sa.sa.sa_flags, &oact->sa_flags) ||
+ __copy_to_user(&oact->sa_mask, &old_sa.sa.sa_mask,
+ sizeof(sigset_t)))
+ return -EFAULT;
+ }
+out:
+ return ret;
+}
+
+long compat_sys_rt_sigqueueinfo(int pid, int sig,
+ struct compat_siginfo __user *uinfo)
+{
+ siginfo_t info;
+ int ret;
+ mm_segment_t old_fs = get_fs();
+
+ if (copy_siginfo_from_user32(&info, uinfo))
+ return -EFAULT;
+ set_fs(KERNEL_DS);
+ ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info);
+ set_fs(old_fs);
+ return ret;
+}
+
+int copy_siginfo_to_user32(struct compat_siginfo __user *to, siginfo_t *from)
+{
+ int err;
+
+ if (!access_ok(VERIFY_WRITE, to, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please make sure that
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+
+ if (from->si_code < 0) {
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
+ } else {
+ /*
+ * First 32bits of unions are always present:
+ * si_pid === si_band === si_tid === si_addr(LS half)
+ */
+ err |= __put_user(from->_sifields._pad[0],
+ &to->_sifields._pad[0]);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ /* FALL THROUGH */
+ default:
+ case __SI_KILL >> 16:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ err |= __put_user(ptr_to_compat(from->si_ptr),
+ &to->si_ptr);
+ break;
+ /* This is not generated by the kernel as of now. */
+ case __SI_RT >> 16:
+ case __SI_MESGQ >> 16:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_int, &to->si_int);
+ break;
+ }
+ }
+ return err;
+}
+
+int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
+{
+ int err;
+ u32 ptr32;
+
+ if (!access_ok(VERIFY_READ, from, sizeof(struct compat_siginfo)))
+ return -EFAULT;
+
+ err = __get_user(to->si_signo, &from->si_signo);
+ err |= __get_user(to->si_errno, &from->si_errno);
+ err |= __get_user(to->si_code, &from->si_code);
+
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ err |= __get_user(ptr32, &from->si_ptr);
+ to->si_ptr = compat_ptr(ptr32);
+
+ return err;
+}
+
+long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
+ struct compat_sigaltstack __user *uoss_ptr,
+ struct pt_regs *regs)
+{
+ stack_t uss, uoss;
+ int ret;
+ mm_segment_t seg;
+
+ if (uss_ptr) {
+ u32 ptr;
+
+ memset(&uss, 0, sizeof(stack_t));
+ if (!access_ok(VERIFY_READ, uss_ptr, sizeof(*uss_ptr)) ||
+ __get_user(ptr, &uss_ptr->ss_sp) ||
+ __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
+ __get_user(uss.ss_size, &uss_ptr->ss_size))
+ return -EFAULT;
+ uss.ss_sp = compat_ptr(ptr);
+ }
+ seg = get_fs();
+ set_fs(KERNEL_DS);
+ ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
+ (unsigned long)compat_ptr(regs->sp));
+ set_fs(seg);
+ if (ret >= 0 && uoss_ptr) {
+ if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
+ __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
+ __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
+ __put_user(uoss.ss_size, &uoss_ptr->ss_size))
+ ret = -EFAULT;
+ }
+ return ret;
+}
+
+long _compat_sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct compat_rt_sigframe __user *frame =
+ (struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
+ sigset_t set;
+ long r0;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+ goto badframe;
+
+ if (_compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+ goto badframe;
+
+ return r0;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *compat_get_sigframe(struct k_sigaction *ka,
+ struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = (unsigned long)compat_ptr(regs->sp);
+
+ /*
+ * If we are on the alternate signal stack and would overflow
+ * it, don't. Return an always-bogus address instead so we
+ * will die with SIGSEGV.
+ */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
+ return (void __user *) -1L;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (sas_ss_flags(sp) == 0)
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ sp -= frame_size;
+ /*
+ * Align the stack pointer according to the TILE ABI,
+ * i.e. so that on function entry (sp & 15) == 0.
+ */
+ sp &= -16UL;
+ return (void __user *) sp;
+}
+
+int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ unsigned long restorer;
+ struct compat_rt_sigframe __user *frame;
+ int err = 0;
+ int usig;
+
+ frame = compat_get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ usig = current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32
+ ? current_thread_info()->exec_domain->signal_invmap[sig]
+ : sig;
+
+ /* Always write at least the signal number for the stack backtracer. */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* At sigreturn time, restore the callee-save registers too. */
+ err |= copy_siginfo_to_user32(&frame->info, info);
+ regs->flags |= PT_FLAGS_RESTORE_REGS;
+ } else {
+ err |= __put_user(info->si_signo, &frame->info.si_signo);
+ }
+
+ /* Create the ucontext. */
+ err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user(ptr_to_compat((void *)(current->sas_ss_sp)),
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->sp),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
+
+ restorer = VDSO_BASE;
+ if (ka->sa.sa_flags & SA_RESTORER)
+ restorer = ptr_to_compat_reg(ka->sa.sa_restorer);
+
+ /*
+ * Set up registers for signal handler.
+ * Registers that we don't modify keep the value they had from
+ * user-space at the time we took the signal.
+ */
+ regs->pc = ptr_to_compat_reg(ka->sa.sa_handler);
+ regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
+ regs->sp = ptr_to_compat_reg(frame);
+ regs->lr = restorer;
+ regs->regs[0] = (unsigned long) usig;
+
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* Need extra arguments, so mark to restore caller-saves. */
+ regs->regs[1] = ptr_to_compat_reg(&frame->info);
+ regs->regs[2] = ptr_to_compat_reg(&frame->uc);
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+ }
+
+ /*
+ * Notify any tracer that was single-stepping it.
+ * The tracer may want to single-step inside the
+ * handler too.
+ */
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
new file mode 100644
index 000000000000..e44d441e3f3f
--- /dev/null
+++ b/arch/tile/kernel/early_printk.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/console.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <asm/setup.h>
+#include <hv/hypervisor.h>
+
+static void early_hv_write(struct console *con, const char *s, unsigned n)
+{
+ hv_console_write((HV_VirtAddr) s, n);
+}
+
+static struct console early_hv_console = {
+ .name = "earlyhv",
+ .write = early_hv_write,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+/* Direct interface for emergencies */
+struct console *early_console = &early_hv_console;
+static int early_console_initialized;
+static int early_console_complete;
+
+static void early_vprintk(const char *fmt, va_list ap)
+{
+ char buf[512];
+ int n = vscnprintf(buf, sizeof(buf), fmt, ap);
+ early_console->write(early_console, buf, n);
+}
+
+void early_printk(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ early_vprintk(fmt, ap);
+ va_end(ap);
+}
+
+void early_panic(const char *fmt, ...)
+{
+ va_list ap;
+ raw_local_irq_disable_all();
+ va_start(ap, fmt);
+ early_printk("Kernel panic - not syncing: ");
+ early_vprintk(fmt, ap);
+ early_console->write(early_console, "\n", 1);
+ va_end(ap);
+ dump_stack();
+ hv_halt();
+}
+
+static int __initdata keep_early;
+
+static int __init setup_early_printk(char *str)
+{
+ if (early_console_initialized)
+ return 1;
+
+ if (str != NULL && strncmp(str, "keep", 4) == 0)
+ keep_early = 1;
+
+ early_console = &early_hv_console;
+ early_console_initialized = 1;
+ register_console(early_console);
+
+ return 0;
+}
+
+void __init disable_early_printk(void)
+{
+ early_console_complete = 1;
+ if (!early_console_initialized || !early_console)
+ return;
+ if (!keep_early) {
+ early_printk("disabling early console\n");
+ unregister_console(early_console);
+ early_console_initialized = 0;
+ } else {
+ early_printk("keeping early console\n");
+ }
+}
+
+void warn_early_printk(void)
+{
+ if (early_console_complete || early_console_initialized)
+ return;
+ early_printk("\
+Machine shutting down before console output is fully initialized.\n\
+You may wish to reboot and add the option 'earlyprintk' to your\n\
+boot command line to see any diagnostic early console output.\n\
+");
+}
+
+early_param("earlyprintk", setup_early_printk);
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
new file mode 100644
index 000000000000..136261f7d7f9
--- /dev/null
+++ b/arch/tile/kernel/entry.S
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/linkage.h>
+#include <arch/abi.h>
+#include <asm/unistd.h>
+#include <asm/irqflags.h>
+
+#ifdef __tilegx__
+#define bnzt bnezt
+#endif
+
+STD_ENTRY(current_text_addr)
+ { move r0, lr; jrp lr }
+ STD_ENDPROC(current_text_addr)
+
+STD_ENTRY(_sim_syscall)
+ /*
+ * Wait for r0-r9 to be ready (and lr on the off chance we
+ * want the syscall to locate its caller), then make a magic
+ * simulator syscall.
+ *
+ * We carefully stall until the registers are readable in case they
+ * are the target of a slow load, etc. so that tile-sim will
+ * definitely be able to read all of them inside the magic syscall.
+ *
+ * Technically this is wrong for r3-r9 and lr, since an interrupt
+ * could come in and restore the registers with a slow load right
+ * before executing the mtspr. We may need to modify tile-sim to
+ * explicitly stall for this case, but we do not yet have
+ * a way to implement such a stall.
+ */
+ { and zero, lr, r9 ; and zero, r8, r7 }
+ { and zero, r6, r5 ; and zero, r4, r3 }
+ { and zero, r2, r1 ; mtspr SIM_CONTROL, r0 }
+ { jrp lr }
+ STD_ENDPROC(_sim_syscall)
+
+/*
+ * Implement execve(). The i386 code has a note that forking from kernel
+ * space results in no copy on write until the execve, so we should be
+ * careful not to write to the stack here.
+ */
+STD_ENTRY(kernel_execve)
+ moveli TREG_SYSCALL_NR_NAME, __NR_execve
+ swint1
+ jrp lr
+ STD_ENDPROC(kernel_execve)
+
+/* Delay a fixed number of cycles. */
+STD_ENTRY(__delay)
+ { addi r0, r0, -1; bnzt r0, . }
+ jrp lr
+ STD_ENDPROC(__delay)
+
+/*
+ * We don't run this function directly, but instead copy it to a page
+ * we map into every user process. See vdso_setup().
+ *
+ * Note that libc has a copy of this function that it uses to compare
+ * against the PC when a stack backtrace ends, so if this code is
+ * changed, the libc implementation(s) should also be updated.
+ */
+ .pushsection .data
+ENTRY(__rt_sigreturn)
+ moveli TREG_SYSCALL_NR_NAME,__NR_rt_sigreturn
+ swint1
+ ENDPROC(__rt_sigreturn)
+ ENTRY(__rt_sigreturn_end)
+ .popsection
+
+STD_ENTRY(dump_stack)
+ { move r2, lr; lnk r1 }
+ { move r4, r52; addli r1, r1, dump_stack - . }
+ { move r3, sp; j _dump_stack }
+ jrp lr /* keep backtracer happy */
+ STD_ENDPROC(dump_stack)
+
+STD_ENTRY(KBacktraceIterator_init_current)
+ { move r2, lr; lnk r1 }
+ { move r4, r52; addli r1, r1, KBacktraceIterator_init_current - . }
+ { move r3, sp; j _KBacktraceIterator_init_current }
+ jrp lr /* keep backtracer happy */
+ STD_ENDPROC(KBacktraceIterator_init_current)
+
+/*
+ * Reset our stack to r1/r2 (sp and ksp0+cpu respectively), then
+ * free the old stack (passed in r0) and re-invoke cpu_idle().
+ * We update sp and ksp0 simultaneously to avoid backtracer warnings.
+ */
+STD_ENTRY(cpu_idle_on_new_stack)
+ {
+ move sp, r1
+ mtspr SYSTEM_SAVE_1_0, r2
+ }
+ jal free_thread_info
+ j cpu_idle
+ STD_ENDPROC(cpu_idle_on_new_stack)
+
+/* Loop forever on a nap during SMP boot. */
+STD_ENTRY(smp_nap)
+ nap
+ j smp_nap /* we are not architecturally guaranteed not to exit nap */
+ jrp lr /* clue in the backtracer */
+ STD_ENDPROC(smp_nap)
+
+/*
+ * Enable interrupts racelessly and then nap until interrupted.
+ * This function's _cpu_idle_nap address is special; see intvec.S.
+ * When interrupted at _cpu_idle_nap, we bump the PC forward 8, and
+ * as a result return to the function that called _cpu_idle().
+ */
+STD_ENTRY(_cpu_idle)
+ {
+ lnk r0
+ movei r1, 1
+ }
+ {
+ addli r0, r0, _cpu_idle_nap - .
+ mtspr INTERRUPT_CRITICAL_SECTION, r1
+ }
+ IRQ_ENABLE(r2, r3) /* unmask, but still with ICS set */
+ mtspr EX_CONTEXT_1_1, r1 /* PL1, ICS clear */
+ mtspr EX_CONTEXT_1_0, r0
+ iret
+ .global _cpu_idle_nap
+_cpu_idle_nap:
+ nap
+ jrp lr
+ STD_ENDPROC(_cpu_idle)
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S
new file mode 100644
index 000000000000..2b4f6c091701
--- /dev/null
+++ b/arch/tile/kernel/head_32.S
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * TILE startup code.
+ */
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ */
+
+ __HEAD
+ENTRY(_start)
+ /* Notify the hypervisor of what version of the API we want */
+ {
+ movei r1, TILE_CHIP
+ movei r2, TILE_CHIP_REV
+ }
+ {
+ moveli r0, _HV_VERSION
+ jal hv_init
+ }
+ /* Get a reasonable default ASID in r0 */
+ {
+ move r0, zero
+ jal hv_inquire_asid
+ }
+ /* Install the default page table */
+ {
+ moveli r6, lo16(swapper_pgprot - PAGE_OFFSET)
+ move r4, r0 /* use starting ASID of range for this page table */
+ }
+ {
+ moveli r0, lo16(swapper_pg_dir - PAGE_OFFSET)
+ auli r6, r6, ha16(swapper_pgprot - PAGE_OFFSET)
+ }
+ {
+ lw r2, r6
+ addi r6, r6, 4
+ }
+ {
+ lw r3, r6
+ auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET)
+ }
+ {
+ inv r6
+ move r1, zero /* high 32 bits of CPA is zero */
+ }
+ {
+ moveli lr, lo16(1f)
+ move r5, zero
+ }
+ {
+ auli lr, lr, ha16(1f)
+ j hv_install_context
+ }
+1:
+
+ /* Get our processor number and save it away in SAVE_1_0. */
+ jal hv_inquire_topology
+ mulll_uu r4, r1, r2 /* r1 == y, r2 == width */
+ add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */
+
+#ifdef CONFIG_SMP
+ /*
+ * Load up our per-cpu offset. When the first (master) tile
+ * boots, this value is still zero, so we will load boot_pc
+ * with start_kernel, and boot_sp with init_stack + THREAD_SIZE.
+ * The master tile initializes the per-cpu offset array, so that
+ * when subsequent (secondary) tiles boot, they will instead load
+ * from their per-cpu versions of boot_sp and boot_pc.
+ */
+ moveli r5, lo16(__per_cpu_offset)
+ auli r5, r5, ha16(__per_cpu_offset)
+ s2a r5, r4, r5
+ lw r5, r5
+ bnz r5, 1f
+
+ /*
+ * Save the width and height to the smp_topology variable
+ * for later use.
+ */
+ moveli r0, lo16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+ auli r0, r0, ha16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET)
+ {
+ sw r0, r2
+ addi r0, r0, (HV_TOPOLOGY_HEIGHT_OFFSET - HV_TOPOLOGY_WIDTH_OFFSET)
+ }
+ sw r0, r3
+1:
+#else
+ move r5, zero
+#endif
+
+ /* Load and go with the correct pc and sp. */
+ {
+ addli r1, r5, lo16(boot_sp)
+ addli r0, r5, lo16(boot_pc)
+ }
+ {
+ auli r1, r1, ha16(boot_sp)
+ auli r0, r0, ha16(boot_pc)
+ }
+ lw r0, r0
+ lw sp, r1
+ or r4, sp, r4
+ mtspr SYSTEM_SAVE_1_0, r4 /* save ksp0 + cpu */
+ addi sp, sp, -STACK_TOP_DELTA
+ {
+ move lr, zero /* stop backtraces in the called function */
+ jr r0
+ }
+ ENDPROC(_start)
+
+.section ".bss.page_aligned","w"
+ .align PAGE_SIZE
+ENTRY(empty_zero_page)
+ .fill PAGE_SIZE,1,0
+ END(empty_zero_page)
+
+ .macro PTE va, cpa, bits1, no_org=0
+ .ifeq \no_org
+ .org swapper_pg_dir + HV_L1_INDEX(\va) * HV_PTE_SIZE
+ .endif
+ .word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \
+ (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE)
+ .word (\bits1) | (HV_CPA_TO_PFN(\cpa) << HV_PTE_INDEX_PFN)
+ .endm
+
+.section ".data.page_aligned","wa"
+ .align PAGE_SIZE
+ENTRY(swapper_pg_dir)
+ /*
+ * All data pages from PAGE_OFFSET to MEM_USER_INTRPT are mapped as
+ * VA = PA + PAGE_OFFSET. We remap things with more precise access
+ * permissions and more respect for size of RAM later.
+ */
+ .set addr, 0
+ .rept (MEM_USER_INTRPT - PAGE_OFFSET) >> PGDIR_SHIFT
+ PTE addr + PAGE_OFFSET, addr, HV_PTE_READABLE | HV_PTE_WRITABLE
+ .set addr, addr + PGDIR_SIZE
+ .endr
+
+ /* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */
+ PTE MEM_SV_INTRPT, 0, HV_PTE_READABLE | HV_PTE_EXECUTABLE
+ .org swapper_pg_dir + HV_L1_SIZE
+ END(swapper_pg_dir)
+
+ /*
+ * Isolate swapper_pgprot to its own cache line, since each cpu
+ * starting up will read it using VA-is-PA and local homing.
+ * This would otherwise likely conflict with other data on the cache
+ * line, once we have set its permanent home in the page tables.
+ */
+ __INITDATA
+ .align CHIP_L2_LINE_SIZE()
+ENTRY(swapper_pgprot)
+ PTE 0, 0, HV_PTE_READABLE | HV_PTE_WRITABLE, 1
+ .align CHIP_L2_LINE_SIZE()
+ END(swapper_pgprot)
diff --git a/arch/tile/kernel/hvglue.lds b/arch/tile/kernel/hvglue.lds
new file mode 100644
index 000000000000..698489b4c7ab
--- /dev/null
+++ b/arch/tile/kernel/hvglue.lds
@@ -0,0 +1,56 @@
+/* Hypervisor call vector addresses; see <hv/hypervisor.h> */
+hv_init = TEXT_OFFSET + 0x10020;
+hv_install_context = TEXT_OFFSET + 0x10040;
+hv_sysconf = TEXT_OFFSET + 0x10060;
+hv_get_rtc = TEXT_OFFSET + 0x10080;
+hv_set_rtc = TEXT_OFFSET + 0x100a0;
+hv_flush_asid = TEXT_OFFSET + 0x100c0;
+hv_flush_page = TEXT_OFFSET + 0x100e0;
+hv_flush_pages = TEXT_OFFSET + 0x10100;
+hv_restart = TEXT_OFFSET + 0x10120;
+hv_halt = TEXT_OFFSET + 0x10140;
+hv_power_off = TEXT_OFFSET + 0x10160;
+hv_inquire_physical = TEXT_OFFSET + 0x10180;
+hv_inquire_memory_controller = TEXT_OFFSET + 0x101a0;
+hv_inquire_virtual = TEXT_OFFSET + 0x101c0;
+hv_inquire_asid = TEXT_OFFSET + 0x101e0;
+hv_nanosleep = TEXT_OFFSET + 0x10200;
+hv_console_read_if_ready = TEXT_OFFSET + 0x10220;
+hv_console_write = TEXT_OFFSET + 0x10240;
+hv_downcall_dispatch = TEXT_OFFSET + 0x10260;
+hv_inquire_topology = TEXT_OFFSET + 0x10280;
+hv_fs_findfile = TEXT_OFFSET + 0x102a0;
+hv_fs_fstat = TEXT_OFFSET + 0x102c0;
+hv_fs_pread = TEXT_OFFSET + 0x102e0;
+hv_physaddr_read64 = TEXT_OFFSET + 0x10300;
+hv_physaddr_write64 = TEXT_OFFSET + 0x10320;
+hv_get_command_line = TEXT_OFFSET + 0x10340;
+hv_set_caching = TEXT_OFFSET + 0x10360;
+hv_bzero_page = TEXT_OFFSET + 0x10380;
+hv_register_message_state = TEXT_OFFSET + 0x103a0;
+hv_send_message = TEXT_OFFSET + 0x103c0;
+hv_receive_message = TEXT_OFFSET + 0x103e0;
+hv_inquire_context = TEXT_OFFSET + 0x10400;
+hv_start_all_tiles = TEXT_OFFSET + 0x10420;
+hv_dev_open = TEXT_OFFSET + 0x10440;
+hv_dev_close = TEXT_OFFSET + 0x10460;
+hv_dev_pread = TEXT_OFFSET + 0x10480;
+hv_dev_pwrite = TEXT_OFFSET + 0x104a0;
+hv_dev_poll = TEXT_OFFSET + 0x104c0;
+hv_dev_poll_cancel = TEXT_OFFSET + 0x104e0;
+hv_dev_preada = TEXT_OFFSET + 0x10500;
+hv_dev_pwritea = TEXT_OFFSET + 0x10520;
+hv_flush_remote = TEXT_OFFSET + 0x10540;
+hv_console_putc = TEXT_OFFSET + 0x10560;
+hv_inquire_tiles = TEXT_OFFSET + 0x10580;
+hv_confstr = TEXT_OFFSET + 0x105a0;
+hv_reexec = TEXT_OFFSET + 0x105c0;
+hv_set_command_line = TEXT_OFFSET + 0x105e0;
+hv_dev_register_intr_state = TEXT_OFFSET + 0x10600;
+hv_enable_intr = TEXT_OFFSET + 0x10620;
+hv_disable_intr = TEXT_OFFSET + 0x10640;
+hv_trigger_ipi = TEXT_OFFSET + 0x10660;
+hv_store_mapping = TEXT_OFFSET + 0x10680;
+hv_inquire_realpa = TEXT_OFFSET + 0x106a0;
+hv_flush_all = TEXT_OFFSET + 0x106c0;
+hv_glue_internals = TEXT_OFFSET + 0x106e0;
diff --git a/arch/tile/kernel/init_task.c b/arch/tile/kernel/init_task.c
new file mode 100644
index 000000000000..928b31870669
--- /dev/null
+++ b/arch/tile/kernel/init_task.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/init_task.h>
+#include <linux/mqueue.h>
+#include <linux/module.h>
+#include <linux/start_kernel.h>
+#include <linux/uaccess.h>
+
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+
+/*
+ * Initial thread structure.
+ *
+ * We need to make sure that this is THREAD_SIZE aligned due to the
+ * way process stacks are handled. This is done by having a special
+ * "init_task" linker map entry..
+ */
+union thread_union init_thread_union __init_task_data = {
+ INIT_THREAD_INFO(init_task)
+};
+
+/*
+ * Initial task structure.
+ *
+ * All other task structs will be allocated on slabs in fork.c
+ */
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+/*
+ * per-CPU stack and boot info.
+ */
+DEFINE_PER_CPU(unsigned long, boot_sp) =
+ (unsigned long)init_stack + THREAD_SIZE;
+
+#ifdef CONFIG_SMP
+DEFINE_PER_CPU(unsigned long, boot_pc) = (unsigned long)start_kernel;
+#else
+/*
+ * The variable must be __initdata since it references __init code.
+ * With CONFIG_SMP it is per-cpu data, which is exempt from validation.
+ */
+unsigned long __initdata boot_pc = (unsigned long)start_kernel;
+#endif
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
new file mode 100644
index 000000000000..207271f0cce1
--- /dev/null
+++ b/arch/tile/kernel/intvec_32.S
@@ -0,0 +1,2006 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Linux interrupt vectors.
+ */
+
+#include <linux/linkage.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <asm/ptrace.h>
+#include <asm/thread_info.h>
+#include <asm/unistd.h>
+#include <asm/irqflags.h>
+#include <asm/atomic.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+#include <arch/abi.h>
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+#ifdef CONFIG_PREEMPT
+# error "No support for kernel preemption currently"
+#endif
+
+#if INT_INTCTRL_1 < 32 || INT_INTCTL_1 >= 48
+# error INT_INTCTRL_1 coded to set high interrupt mask
+#endif
+
+#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg)
+
+#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR)
+
+#if !CHIP_HAS_WH64()
+ /* By making this an empty macro, we can use wh64 in the code. */
+ .macro wh64 reg
+ .endm
+#endif
+
+ .macro push_reg reg, ptr=sp, delta=-4
+ {
+ sw \ptr, \reg
+ addli \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro pop_reg reg, ptr=sp, delta=4
+ {
+ lw \reg, \ptr
+ addli \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro pop_reg_zero reg, zreg, ptr=sp, delta=4
+ {
+ move \zreg, zero
+ lw \reg, \ptr
+ addi \ptr, \ptr, \delta
+ }
+ .endm
+
+ .macro push_extra_callee_saves reg
+ PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51))
+ push_reg r51, \reg
+ push_reg r50, \reg
+ push_reg r49, \reg
+ push_reg r48, \reg
+ push_reg r47, \reg
+ push_reg r46, \reg
+ push_reg r45, \reg
+ push_reg r44, \reg
+ push_reg r43, \reg
+ push_reg r42, \reg
+ push_reg r41, \reg
+ push_reg r40, \reg
+ push_reg r39, \reg
+ push_reg r38, \reg
+ push_reg r37, \reg
+ push_reg r36, \reg
+ push_reg r35, \reg
+ push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34)
+ .endm
+
+ .macro panic str
+ .pushsection .rodata, "a"
+1:
+ .asciz "\str"
+ .popsection
+ {
+ moveli r0, lo16(1b)
+ }
+ {
+ auli r0, r0, ha16(1b)
+ jal panic
+ }
+ .endm
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ .pushsection .text.intvec_feedback,"ax"
+intvec_feedback:
+ .popsection
+#endif
+
+ /*
+ * Default interrupt handler.
+ *
+ * vecnum is where we'll put this code.
+ * c_routine is the C routine we'll call.
+ *
+ * The C routine is passed two arguments:
+ * - A pointer to the pt_regs state.
+ * - The interrupt vector number.
+ *
+ * The "processing" argument specifies the code for processing
+ * the interrupt. Defaults to "handle_interrupt".
+ */
+ .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt
+ .org (\vecnum << 8)
+intvec_\vecname:
+ .ifc \vecnum, INT_SWINT_1
+ blz TREG_SYSCALL_NR_NAME, sys_cmpxchg
+ .endif
+
+ /* Temporarily save a register so we have somewhere to work. */
+
+ mtspr SYSTEM_SAVE_1_1, r0
+ mfspr r0, EX_CONTEXT_1_1
+
+ /* The cmpxchg code clears sp to force us to reset it here on fault. */
+ {
+ bz sp, 2f
+ andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ }
+
+ .ifc \vecnum, INT_DOUBLE_FAULT
+ /*
+ * For double-faults from user-space, fall through to the normal
+ * register save and stack setup path. Otherwise, it's the
+ * hypervisor giving us one last chance to dump diagnostics, and we
+ * branch to the kernel_double_fault routine to do so.
+ */
+ bz r0, 1f
+ j _kernel_double_fault
+1:
+ .else
+ /*
+ * If we're coming from user-space, then set sp to the top of
+ * the kernel stack. Otherwise, assume sp is already valid.
+ */
+ {
+ bnz r0, 0f
+ move r0, sp
+ }
+ .endif
+
+ .ifc \c_routine, do_page_fault
+ /*
+ * The page_fault handler may be downcalled directly by the
+ * hypervisor even when Linux is running and has ICS set.
+ *
+ * In this case the contents of EX_CONTEXT_1_1 reflect the
+ * previous fault and can't be relied on to choose whether or
+ * not to reinitialize the stack pointer. So we add a test
+ * to see whether SYSTEM_SAVE_1_2 has the high bit set,
+ * and if so we don't reinitialize sp, since we must be coming
+ * from Linux. (In fact the precise case is !(val & ~1),
+ * but any Linux PC has to have the high bit set.)
+ *
+ * Note that the hypervisor *always* sets SYSTEM_SAVE_1_2 for
+ * any path that turns into a downcall to one of our TLB handlers.
+ */
+ mfspr r0, SYSTEM_SAVE_1_2
+ {
+ blz r0, 0f /* high bit in S_S_1_2 is for a PC to use */
+ move r0, sp
+ }
+ .endif
+
+2:
+ /*
+ * SYSTEM_SAVE_1_0 holds the cpu number in the low bits, and
+ * the current stack top in the higher bits. So we recover
+ * our stack top by just masking off the low bits, then
+ * point sp at the top aligned address on the actual stack page.
+ */
+ mfspr r0, SYSTEM_SAVE_1_0
+ mm r0, r0, zero, LOG2_THREAD_SIZE, 31
+
+0:
+ /*
+ * Align the stack mod 64 so we can properly predict what
+ * cache lines we need to write-hint to reduce memory fetch
+ * latency as we enter the kernel. The layout of memory is
+ * as follows, with cache line 0 at the lowest VA, and cache
+ * line 4 just below the r0 value this "andi" computes.
+ * Note that we never write to cache line 4, and we skip
+ * cache line 1 for syscalls.
+ *
+ * cache line 4: ptregs padding (two words)
+ * cache line 3: r46...lr, pc, ex1, faultnum, orig_r0, flags, pad
+ * cache line 2: r30...r45
+ * cache line 1: r14...r29
+ * cache line 0: 2 x frame, r0..r13
+ */
+ andi r0, r0, -64
+
+ /*
+ * Push the first four registers on the stack, so that we can set
+ * them to vector-unique values before we jump to the common code.
+ *
+ * Registers are pushed on the stack as a struct pt_regs,
+ * with the sp initially just above the struct, and when we're
+ * done, sp points to the base of the struct, minus
+ * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code.
+ *
+ * This routine saves just the first four registers, plus the
+ * stack context so we can do proper backtracing right away,
+ * and defers to handle_interrupt to save the rest.
+ * The backtracer needs pc, ex1, lr, sp, r52, and faultnum.
+ */
+ addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
+ wh64 r0 /* cache line 3 */
+ {
+ sw r0, lr
+ addli r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+ }
+ {
+ sw r0, sp
+ addli sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP
+ }
+ {
+ sw sp, r52
+ addli sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52)
+ }
+ wh64 sp /* cache line 0 */
+ {
+ sw sp, r1
+ addli sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1)
+ }
+ {
+ sw sp, r2
+ addli sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2)
+ }
+ {
+ sw sp, r3
+ addli sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3)
+ }
+ mfspr r0, EX_CONTEXT_1_0
+ .ifc \processing,handle_syscall
+ /*
+ * Bump the saved PC by one bundle so that when we return, we won't
+ * execute the same swint instruction again. We need to do this while
+ * we're in the critical section.
+ */
+ addi r0, r0, 8
+ .endif
+ {
+ sw sp, r0
+ addli sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+ }
+ mfspr r0, EX_CONTEXT_1_1
+ {
+ sw sp, r0
+ addi sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+ /*
+ * Use r0 for syscalls so it's a temporary; use r1 for interrupts
+ * so that it gets passed through unchanged to the handler routine.
+ * Note that the .if conditional confusingly spans bundles.
+ */
+ .ifc \processing,handle_syscall
+ movei r0, \vecnum
+ }
+ {
+ sw sp, r0
+ .else
+ movei r1, \vecnum
+ }
+ {
+ sw sp, r1
+ .endif
+ addli sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM
+ }
+ mfspr r0, SYSTEM_SAVE_1_1 /* Original r0 */
+ {
+ sw sp, r0
+ addi sp, sp, -PTREGS_OFFSET_REG(0) - 4
+ }
+ {
+ sw sp, zero /* write zero into "Next SP" frame pointer */
+ addi sp, sp, -4 /* leave SP pointing at bottom of frame */
+ }
+ .ifc \processing,handle_syscall
+ j handle_syscall
+ .else
+ /*
+ * Capture per-interrupt SPR context to registers.
+ * We overload the meaning of r3 on this path such that if its bit 31
+ * is set, we have to mask all interrupts including NMIs before
+ * clearing the interrupt critical section bit.
+ * See discussion below at "finish_interrupt_save".
+ */
+ .ifc \c_routine, do_page_fault
+ mfspr r2, SYSTEM_SAVE_1_3 /* address of page fault */
+ mfspr r3, SYSTEM_SAVE_1_2 /* info about page fault */
+ .else
+ .ifc \vecnum, INT_DOUBLE_FAULT
+ {
+ mfspr r2, SYSTEM_SAVE_1_2 /* double fault info from HV */
+ movei r3, 0
+ }
+ .else
+ .ifc \c_routine, do_trap
+ {
+ mfspr r2, GPV_REASON
+ movei r3, 0
+ }
+ .else
+ .ifc \c_routine, op_handle_perf_interrupt
+ {
+ mfspr r2, PERF_COUNT_STS
+ movei r3, -1 /* not used, but set for consistency */
+ }
+ .else
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+ .ifc \c_routine, op_handle_aux_perf_interrupt
+ {
+ mfspr r2, AUX_PERF_COUNT_STS
+ movei r3, -1 /* not used, but set for consistency */
+ }
+ .else
+#endif
+ movei r3, 0
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+ .endif
+#endif
+ .endif
+ .endif
+ .endif
+ .endif
+ /* Put function pointer in r0 */
+ moveli r0, lo16(\c_routine)
+ {
+ auli r0, r0, ha16(\c_routine)
+ j \processing
+ }
+ .endif
+ ENDPROC(intvec_\vecname)
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ .pushsection .text.intvec_feedback,"ax"
+ .org (\vecnum << 5)
+ FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8)
+ jrp lr
+ .popsection
+#endif
+
+ .endm
+
+
+ /*
+ * Save the rest of the registers that we didn't save in the actual
+ * vector itself. We can't use r0-r10 inclusive here.
+ */
+ .macro finish_interrupt_save, function
+
+ /* If it's a syscall, save a proper orig_r0, otherwise just zero. */
+ PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0)
+ {
+ .ifc \function,handle_syscall
+ sw r52, r0
+ .else
+ sw r52, zero
+ .endif
+ PTREGS_PTR(r52, PTREGS_OFFSET_TP)
+ }
+
+ /*
+ * For ordinary syscalls, we save neither caller- nor callee-
+ * save registers, since the syscall invoker doesn't expect the
+ * caller-saves to be saved, and the called kernel functions will
+ * take care of saving the callee-saves for us.
+ *
+ * For interrupts we save just the caller-save registers. Saving
+ * them is required (since the "caller" can't save them). Again,
+ * the called kernel functions will restore the callee-save
+ * registers for us appropriately.
+ *
+ * On return, we normally restore nothing special for syscalls,
+ * and just the caller-save registers for interrupts.
+ *
+ * However, there are some important caveats to all this:
+ *
+ * - We always save a few callee-save registers to give us
+ * some scratchpad registers to carry across function calls.
+ *
+ * - fork/vfork/etc require us to save all the callee-save
+ * registers, which we do in PTREGS_SYSCALL_ALL_REGS, below.
+ *
+ * - We always save r0..r5 and r10 for syscalls, since we need
+ * to reload them a bit later for the actual kernel call, and
+ * since we might need them for -ERESTARTNOINTR, etc.
+ *
+ * - Before invoking a signal handler, we save the unsaved
+ * callee-save registers so they are visible to the
+ * signal handler or any ptracer.
+ *
+ * - If the unsaved callee-save registers are modified, we set
+ * a bit in pt_regs so we know to reload them from pt_regs
+ * and not just rely on the kernel function unwinding.
+ * (Done for ptrace register writes and SA_SIGINFO handler.)
+ */
+ {
+ sw r52, tp
+ PTREGS_PTR(r52, PTREGS_OFFSET_REG(33))
+ }
+ wh64 r52 /* cache line 2 */
+ push_reg r33, r52
+ push_reg r32, r52
+ push_reg r31, r52
+ .ifc \function,handle_syscall
+ push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30)
+ push_reg TREG_SYSCALL_NR_NAME, r52, \
+ PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL
+ .else
+
+ push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30)
+ wh64 r52 /* cache line 1 */
+ push_reg r29, r52
+ push_reg r28, r52
+ push_reg r27, r52
+ push_reg r26, r52
+ push_reg r25, r52
+ push_reg r24, r52
+ push_reg r23, r52
+ push_reg r22, r52
+ push_reg r21, r52
+ push_reg r20, r52
+ push_reg r19, r52
+ push_reg r18, r52
+ push_reg r17, r52
+ push_reg r16, r52
+ push_reg r15, r52
+ push_reg r14, r52
+ push_reg r13, r52
+ push_reg r12, r52
+ push_reg r11, r52
+ push_reg r10, r52
+ push_reg r9, r52
+ push_reg r8, r52
+ push_reg r7, r52
+ push_reg r6, r52
+
+ .endif
+
+ push_reg r5, r52
+ sw r52, r4
+
+ /* Load tp with our per-cpu offset. */
+#ifdef CONFIG_SMP
+ {
+ mfspr r20, SYSTEM_SAVE_1_0
+ moveli r21, lo16(__per_cpu_offset)
+ }
+ {
+ auli r21, r21, ha16(__per_cpu_offset)
+ mm r20, r20, zero, 0, LOG2_THREAD_SIZE-1
+ }
+ s2a r20, r20, r21
+ lw tp, r20
+#else
+ move tp, zero
+#endif
+
+ /*
+ * If we will be returning to the kernel, we will need to
+ * reset the interrupt masks to the state they had before.
+ * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled.
+ * We load flags in r32 here so we can jump to .Lrestore_regs
+ * directly after do_page_fault_ics() if necessary.
+ */
+ mfspr r32, EX_CONTEXT_1_1
+ {
+ andi r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS)
+ }
+ bzt r32, 1f /* zero if from user space */
+ IRQS_DISABLED(r32) /* zero if irqs enabled */
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix
+#endif
+1:
+ .ifnc \function,handle_syscall
+ /* Record the fact that we saved the caller-save registers above. */
+ ori r32, r32, PT_FLAGS_CALLER_SAVES
+ .endif
+ sw r21, r32
+
+#ifdef __COLLECT_LINKER_FEEDBACK__
+ /*
+ * Notify the feedback routines that we were in the
+ * appropriate fixed interrupt vector area. Note that we
+ * still have ICS set at this point, so we can't invoke any
+ * atomic operations or we will panic. The feedback
+ * routines internally preserve r0..r10 and r30 up.
+ */
+ .ifnc \function,handle_syscall
+ shli r20, r1, 5
+ .else
+ moveli r20, INT_SWINT_1 << 5
+ .endif
+ addli r20, r20, lo16(intvec_feedback)
+ auli r20, r20, ha16(intvec_feedback)
+ jalr r20
+
+ /* And now notify the feedback routines that we are here. */
+ FEEDBACK_ENTER(\function)
+#endif
+
+ /*
+ * we've captured enough state to the stack (including in
+ * particular our EX_CONTEXT state) that we can now release
+ * the interrupt critical section and replace it with our
+ * standard "interrupts disabled" mask value. This allows
+ * synchronous interrupts (and profile interrupts) to punch
+ * through from this point onwards.
+ *
+ * If bit 31 of r3 is set during a non-NMI interrupt, we know we
+ * are on the path where the hypervisor has punched through our
+ * ICS with a page fault, so we call out to do_page_fault_ics()
+ * to figure out what to do with it. If the fault was in
+ * an atomic op, we unlock the atomic lock, adjust the
+ * saved register state a little, and return "zero" in r4,
+ * falling through into the normal page-fault interrupt code.
+ * If the fault was in a kernel-space atomic operation, then
+ * do_page_fault_ics() resolves it itself, returns "one" in r4,
+ * and as a result goes directly to restoring registers and iret,
+ * without trying to adjust the interrupt masks at all.
+ * The do_page_fault_ics() API involves passing and returning
+ * a five-word struct (in registers) to avoid writing the
+ * save and restore code here.
+ */
+ .ifc \function,handle_nmi
+ IRQ_DISABLE_ALL(r20)
+ .else
+ .ifnc \function,handle_syscall
+ bgezt r3, 1f
+ {
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_page_fault_ics
+ }
+ FEEDBACK_REENTER(\function)
+ bzt r4, 1f
+ j .Lrestore_regs
+1:
+ .endif
+ IRQ_DISABLE(r20, r21)
+ .endif
+ mtspr INTERRUPT_CRITICAL_SECTION, zero
+
+#if CHIP_HAS_WH64()
+ /*
+ * Prepare the first 256 stack bytes to be rapidly accessible
+ * without having to fetch the background data. We don't really
+ * know how far to write-hint, but kernel stacks generally
+ * aren't that big, and write-hinting here does take some time.
+ */
+ addi r52, sp, -64
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ {
+ wh64 r52
+ addi r52, r52, -64
+ }
+ wh64 r52
+#endif
+
+#ifdef CONFIG_TRACE_IRQFLAGS
+ .ifnc \function,handle_nmi
+ /*
+ * We finally have enough state set up to notify the irq
+ * tracing code that irqs were disabled on entry to the handler.
+ * The TRACE_IRQS_OFF call clobbers registers r0-r29.
+ * For syscalls, we already have the register state saved away
+ * on the stack, so we don't bother to do any register saves here,
+ * and later we pop the registers back off the kernel stack.
+ * For interrupt handlers, save r0-r3 in callee-saved registers.
+ */
+ .ifnc \function,handle_syscall
+ { move r30, r0; move r31, r1 }
+ { move r32, r2; move r33, r3 }
+ .endif
+ TRACE_IRQS_OFF
+ .ifnc \function,handle_syscall
+ { move r0, r30; move r1, r31 }
+ { move r2, r32; move r3, r33 }
+ .endif
+ .endif
+#endif
+
+ .endm
+
+ .macro check_single_stepping, kind, not_single_stepping
+ /*
+ * Check for single stepping in user-level priv
+ * kind can be "normal", "ill", or "syscall"
+ * At end, if fall-thru
+ * r29: thread_info->step_state
+ * r28: &pt_regs->pc
+ * r27: pt_regs->pc
+ * r26: thread_info->step_state->buffer
+ */
+
+ /* Check for single stepping */
+ GET_THREAD_INFO(r29)
+ {
+ /* Get pointer to field holding step state */
+ addi r29, r29, THREAD_INFO_STEP_STATE_OFFSET
+
+ /* Get pointer to EX1 in register state */
+ PTREGS_PTR(r27, PTREGS_OFFSET_EX1)
+ }
+ {
+ /* Get pointer to field holding PC */
+ PTREGS_PTR(r28, PTREGS_OFFSET_PC)
+
+ /* Load the pointer to the step state */
+ lw r29, r29
+ }
+ /* Load EX1 */
+ lw r27, r27
+ {
+ /* Points to flags */
+ addi r23, r29, SINGLESTEP_STATE_FLAGS_OFFSET
+
+ /* No single stepping if there is no step state structure */
+ bzt r29, \not_single_stepping
+ }
+ {
+ /* mask off ICS and any other high bits */
+ andi r27, r27, SPR_EX_CONTEXT_1_1__PL_MASK
+
+ /* Load pointer to single step instruction buffer */
+ lw r26, r29
+ }
+ /* Check priv state */
+ bnz r27, \not_single_stepping
+
+ /* Get flags */
+ lw r22, r23
+ {
+ /* Branch if single-step mode not enabled */
+ bbnst r22, \not_single_stepping
+
+ /* Clear enabled flag */
+ andi r22, r22, ~SINGLESTEP_STATE_MASK_IS_ENABLED
+ }
+ .ifc \kind,normal
+ {
+ /* Load PC */
+ lw r27, r28
+
+ /* Point to the entry containing the original PC */
+ addi r24, r29, SINGLESTEP_STATE_ORIG_PC_OFFSET
+ }
+ {
+ /* Disable single stepping flag */
+ sw r23, r22
+ }
+ {
+ /* Get the original pc */
+ lw r24, r24
+
+ /* See if the PC is at the start of the single step buffer */
+ seq r25, r26, r27
+ }
+ /*
+ * NOTE: it is really expected that the PC be in the single step buffer
+ * at this point
+ */
+ bzt r25, \not_single_stepping
+
+ /* Restore the original PC */
+ sw r28, r24
+ .else
+ .ifc \kind,syscall
+ {
+ /* Load PC */
+ lw r27, r28
+
+ /* Point to the entry containing the next PC */
+ addi r24, r29, SINGLESTEP_STATE_NEXT_PC_OFFSET
+ }
+ {
+ /* Increment the stopped PC by the bundle size */
+ addi r26, r26, 8
+
+ /* Disable single stepping flag */
+ sw r23, r22
+ }
+ {
+ /* Get the next pc */
+ lw r24, r24
+
+ /*
+ * See if the PC is one bundle past the start of the
+ * single step buffer
+ */
+ seq r25, r26, r27
+ }
+ {
+ /*
+ * NOTE: it is really expected that the PC be in the
+ * single step buffer at this point
+ */
+ bzt r25, \not_single_stepping
+ }
+ /* Set to the next PC */
+ sw r28, r24
+ .else
+ {
+ /* Point to 3rd bundle in buffer */
+ addi r25, r26, 16
+
+ /* Load PC */
+ lw r27, r28
+ }
+ {
+ /* Disable single stepping flag */
+ sw r23, r22
+
+ /* See if the PC is in the single step buffer */
+ slte_u r24, r26, r27
+ }
+ {
+ slte_u r25, r27, r25
+
+ /*
+ * NOTE: it is really expected that the PC be in the
+ * single step buffer at this point
+ */
+ bzt r24, \not_single_stepping
+ }
+ bzt r25, \not_single_stepping
+ .endif
+ .endif
+ .endm
+
+ /*
+ * Redispatch a downcall.
+ */
+ .macro dc_dispatch vecnum, vecname
+ .org (\vecnum << 8)
+intvec_\vecname:
+ j hv_downcall_dispatch
+ ENDPROC(intvec_\vecname)
+ .endm
+
+ /*
+ * Common code for most interrupts. The C function we're eventually
+ * going to is in r0, and the faultnum is in r1; the original
+ * values for those registers are on the stack.
+ */
+ .pushsection .text.handle_interrupt,"ax"
+handle_interrupt:
+ finish_interrupt_save handle_interrupt
+
+ /*
+ * Check for if we are single stepping in user level. If so, then
+ * we need to restore the PC.
+ */
+
+ check_single_stepping normal, .Ldispatch_interrupt
+.Ldispatch_interrupt:
+
+ /* Jump to the C routine; it should enable irqs as soon as possible. */
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_interrupt)
+ {
+ movei r30, 0 /* not an NMI */
+ j interrupt_return
+ }
+ STD_ENDPROC(handle_interrupt)
+
+/*
+ * This routine takes a boolean in r30 indicating if this is an NMI.
+ * If so, we also expect a boolean in r31 indicating whether to
+ * re-enable the oprofile interrupts.
+ */
+STD_ENTRY(interrupt_return)
+ /* If we're resuming to kernel space, don't check thread flags. */
+ {
+ bnz r30, .Lrestore_all /* NMIs don't special-case user-space */
+ PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
+ }
+ lw r29, r29
+ andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ {
+ bzt r29, .Lresume_userspace
+ PTREGS_PTR(r29, PTREGS_OFFSET_PC)
+ }
+
+ /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */
+ {
+ lw r28, r29
+ moveli r27, lo16(_cpu_idle_nap)
+ }
+ {
+ auli r27, r27, ha16(_cpu_idle_nap)
+ }
+ {
+ seq r27, r27, r28
+ }
+ {
+ bbns r27, .Lrestore_all
+ addi r28, r28, 8
+ }
+ sw r29, r28
+ j .Lrestore_all
+
+.Lresume_userspace:
+ FEEDBACK_REENTER(interrupt_return)
+
+ /*
+ * Disable interrupts so as to make sure we don't
+ * miss an interrupt that sets any of the thread flags (like
+ * need_resched or sigpending) between sampling and the iret.
+ * Routines like schedule() or do_signal() may re-enable
+ * interrupts before returning.
+ */
+ IRQ_DISABLE(r20, r21)
+ TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */
+
+ /* Get base of stack in r32; note r30/31 are used as arguments here. */
+ GET_THREAD_INFO(r32)
+
+
+ /* Check to see if there is any work to do before returning to user. */
+ {
+ addi r29, r32, THREAD_INFO_FLAGS_OFFSET
+ moveli r28, lo16(_TIF_ALLWORK_MASK)
+ }
+ {
+ lw r29, r29
+ auli r28, r28, ha16(_TIF_ALLWORK_MASK)
+ }
+ and r28, r29, r28
+ bnz r28, .Lwork_pending
+
+ /*
+ * In the NMI case we
+ * omit the call to single_process_check_nohz, which normally checks
+ * to see if we should start or stop the scheduler tick, because
+ * we can't call arbitrary Linux code from an NMI context.
+ * We always call the homecache TLB deferral code to re-trigger
+ * the deferral mechanism.
+ *
+ * The other chunk of responsibility this code has is to reset the
+ * interrupt masks appropriately to reset irqs and NMIs. We have
+ * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the
+ * lockdep-type stuff, but we can't set ICS until afterwards, since
+ * ICS can only be used in very tight chunks of code to avoid
+ * tripping over various assertions that it is off.
+ *
+ * (There is what looks like a window of vulnerability here since
+ * we might take a profile interrupt between the two SPR writes
+ * that set the mask, but since we write the low SPR word first,
+ * and our interrupt entry code checks the low SPR word, any
+ * profile interrupt will actually disable interrupts in both SPRs
+ * before returning, which is OK.)
+ */
+.Lrestore_all:
+ PTREGS_PTR(r0, PTREGS_OFFSET_EX1)
+ {
+ lw r0, r0
+ PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS)
+ }
+ {
+ andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK
+ lw r32, r32
+ }
+ bnz r0, 1f
+ j 2f
+#if PT_FLAGS_DISABLE_IRQ != 1
+# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use bbnst below
+#endif
+1: bbnst r32, 2f
+ IRQ_DISABLE(r20,r21)
+ TRACE_IRQS_OFF
+ movei r0, 1
+ mtspr INTERRUPT_CRITICAL_SECTION, r0
+ bzt r30, .Lrestore_regs
+ j 3f
+2: TRACE_IRQS_ON
+ movei r0, 1
+ mtspr INTERRUPT_CRITICAL_SECTION, r0
+ IRQ_ENABLE(r20, r21)
+ bzt r30, .Lrestore_regs
+3:
+
+
+ /*
+ * We now commit to returning from this interrupt, since we will be
+ * doing things like setting EX_CONTEXT SPRs and unwinding the stack
+ * frame. No calls should be made to any other code after this point.
+ * This code should only be entered with ICS set.
+ * r32 must still be set to ptregs.flags.
+ * We launch loads to each cache line separately first, so we can
+ * get some parallelism out of the memory subsystem.
+ * We start zeroing caller-saved registers throughout, since
+ * that will save some cycles if this turns out to be a syscall.
+ */
+.Lrestore_regs:
+ FEEDBACK_REENTER(interrupt_return) /* called from elsewhere */
+
+ /*
+ * Rotate so we have one high bit and one low bit to test.
+ * - low bit says whether to restore all the callee-saved registers,
+ * or just r30-r33, and r52 up.
+ * - high bit (i.e. sign bit) says whether to restore all the
+ * caller-saved registers, or just r0.
+ */
+#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4
+# error Rotate trick does not work :-)
+#endif
+ {
+ rli r20, r32, 30
+ PTREGS_PTR(sp, PTREGS_OFFSET_REG(0))
+ }
+
+ /*
+ * Load cache lines 0, 2, and 3 in that order, then use
+ * the last loaded value, which makes it likely that the other
+ * cache lines have also loaded, at which point we should be
+ * able to safely read all the remaining words on those cache
+ * lines without waiting for the memory subsystem.
+ */
+ pop_reg_zero r0, r1, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0)
+ pop_reg_zero r30, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(30)
+ pop_reg_zero r21, r3, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+ pop_reg_zero lr, r4, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_EX1
+ {
+ mtspr EX_CONTEXT_1_0, r21
+ move r5, zero
+ }
+ {
+ mtspr EX_CONTEXT_1_1, lr
+ andi lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ }
+
+ /* Restore callee-saveds that we actually use. */
+ pop_reg_zero r52, r6, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_REG(52)
+ pop_reg_zero r31, r7
+ pop_reg_zero r32, r8
+ pop_reg_zero r33, r9, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33)
+
+ /*
+ * If we modified other callee-saveds, restore them now.
+ * This is rare, but could be via ptrace or signal handler.
+ */
+ {
+ move r10, zero
+ bbs r20, .Lrestore_callees
+ }
+.Lcontinue_restore_regs:
+
+ /* Check if we're returning from a syscall. */
+ {
+ move r11, zero
+ blzt r20, 1f /* no, so go restore callee-save registers */
+ }
+
+ /*
+ * Check if we're returning to userspace.
+ * Note that if we're not, we don't worry about zeroing everything.
+ */
+ {
+ addli sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29)
+ bnz lr, .Lkernel_return
+ }
+
+ /*
+ * On return from syscall, we've restored r0 from pt_regs, but we
+ * clear the remainder of the caller-saved registers. We could
+ * restore the syscall arguments, but there's not much point,
+ * and it ensures user programs aren't trying to use the
+ * caller-saves if we clear them, as well as avoiding leaking
+ * kernel pointers into userspace.
+ */
+ pop_reg_zero lr, r12, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+ pop_reg_zero tp, r13, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+ {
+ lw sp, sp
+ move r14, zero
+ move r15, zero
+ }
+ { move r16, zero; move r17, zero }
+ { move r18, zero; move r19, zero }
+ { move r20, zero; move r21, zero }
+ { move r22, zero; move r23, zero }
+ { move r24, zero; move r25, zero }
+ { move r26, zero; move r27, zero }
+ { move r28, zero; move r29, zero }
+ iret
+
+ /*
+ * Not a syscall, so restore caller-saved registers.
+ * First kick off a load for cache line 1, which we're touching
+ * for the first time here.
+ */
+ .align 64
+1: pop_reg r29, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(29)
+ pop_reg r1
+ pop_reg r2
+ pop_reg r3
+ pop_reg r4
+ pop_reg r5
+ pop_reg r6
+ pop_reg r7
+ pop_reg r8
+ pop_reg r9
+ pop_reg r10
+ pop_reg r11
+ pop_reg r12
+ pop_reg r13
+ pop_reg r14
+ pop_reg r15
+ pop_reg r16
+ pop_reg r17
+ pop_reg r18
+ pop_reg r19
+ pop_reg r20
+ pop_reg r21
+ pop_reg r22
+ pop_reg r23
+ pop_reg r24
+ pop_reg r25
+ pop_reg r26
+ pop_reg r27
+ pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28)
+ /* r29 already restored above */
+ bnz lr, .Lkernel_return
+ pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR
+ pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP
+ lw sp, sp
+ iret
+
+ /*
+ * We can't restore tp when in kernel mode, since a thread might
+ * have migrated from another cpu and brought a stale tp value.
+ */
+.Lkernel_return:
+ pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR
+ lw sp, sp
+ iret
+
+ /* Restore callee-saved registers from r34 to r51. */
+.Lrestore_callees:
+ addli sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29)
+ pop_reg r34
+ pop_reg r35
+ pop_reg r36
+ pop_reg r37
+ pop_reg r38
+ pop_reg r39
+ pop_reg r40
+ pop_reg r41
+ pop_reg r42
+ pop_reg r43
+ pop_reg r44
+ pop_reg r45
+ pop_reg r46
+ pop_reg r47
+ pop_reg r48
+ pop_reg r49
+ pop_reg r50
+ pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51)
+ j .Lcontinue_restore_regs
+
+.Lwork_pending:
+ /* Mask the reschedule flag */
+ andi r28, r29, _TIF_NEED_RESCHED
+
+ {
+ /*
+ * If the NEED_RESCHED flag is called, we call schedule(), which
+ * may drop this context right here and go do something else.
+ * On return, jump back to .Lresume_userspace and recheck.
+ */
+ bz r28, .Lasync_tlb
+
+ /* Mask the async-tlb flag */
+ andi r28, r29, _TIF_ASYNC_TLB
+ }
+
+ jal schedule
+ FEEDBACK_REENTER(interrupt_return)
+
+ /* Reload the flags and check again */
+ j .Lresume_userspace
+
+.Lasync_tlb:
+ {
+ bz r28, .Lneed_sigpending
+
+ /* Mask the sigpending flag */
+ andi r28, r29, _TIF_SIGPENDING
+ }
+
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal do_async_page_fault
+ FEEDBACK_REENTER(interrupt_return)
+
+ /*
+ * Go restart the "resume userspace" process. We may have
+ * fired a signal, and we need to disable interrupts again.
+ */
+ j .Lresume_userspace
+
+.Lneed_sigpending:
+ /*
+ * At this point we are either doing signal handling or single-step,
+ * so either way make sure we have all the registers saved.
+ */
+ push_extra_callee_saves r0
+
+ {
+ /* If no signal pending, skip to singlestep check */
+ bz r28, .Lneed_singlestep
+
+ /* Mask the singlestep flag */
+ andi r28, r29, _TIF_SINGLESTEP
+ }
+
+ jal do_signal
+ FEEDBACK_REENTER(interrupt_return)
+
+ /* Reload the flags and check again */
+ j .Lresume_userspace
+
+.Lneed_singlestep:
+ {
+ /* Get a pointer to the EX1 field */
+ PTREGS_PTR(r29, PTREGS_OFFSET_EX1)
+
+ /* If we get here, our bit must be set. */
+ bz r28, .Lwork_confusion
+ }
+ /* If we are in priv mode, don't single step */
+ lw r28, r29
+ andi r28, r28, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */
+ bnz r28, .Lrestore_all
+
+ /* Allow interrupts within the single step code */
+ TRACE_IRQS_ON /* Note: clobbers registers r0-r29 */
+ IRQ_ENABLE(r20, r21)
+
+ /* try to single-step the current instruction */
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ jal single_step_once
+ FEEDBACK_REENTER(interrupt_return)
+
+ /* Re-disable interrupts. TRACE_IRQS_OFF in .Lrestore_all. */
+ IRQ_DISABLE(r20,r21)
+
+ j .Lrestore_all
+
+.Lwork_confusion:
+ move r0, r28
+ panic "thread_info allwork flags unhandled on userspace resume: %#x"
+
+ STD_ENDPROC(interrupt_return)
+
+ /*
+ * This interrupt variant clears the INT_INTCTRL_1 interrupt mask bit
+ * before returning, so we can properly get more downcalls.
+ */
+ .pushsection .text.handle_interrupt_downcall,"ax"
+handle_interrupt_downcall:
+ finish_interrupt_save handle_interrupt_downcall
+ check_single_stepping normal, .Ldispatch_downcall
+.Ldispatch_downcall:
+
+ /* Clear INTCTRL_1 from the set of interrupts we ever enable. */
+ GET_INTERRUPTS_ENABLED_MASK_PTR(r30)
+ {
+ addi r30, r30, 4
+ movei r31, INT_MASK(INT_INTCTRL_1)
+ }
+ {
+ lw r20, r30
+ nor r21, r31, zero
+ }
+ and r20, r20, r21
+ sw r30, r20
+
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_interrupt_downcall)
+
+ /* Allow INTCTRL_1 to be enabled next time we enable interrupts. */
+ lw r20, r30
+ or r20, r20, r31
+ sw r30, r20
+
+ {
+ movei r30, 0 /* not an NMI */
+ j interrupt_return
+ }
+ STD_ENDPROC(handle_interrupt_downcall)
+
+ /*
+ * Some interrupts don't check for single stepping
+ */
+ .pushsection .text.handle_interrupt_no_single_step,"ax"
+handle_interrupt_no_single_step:
+ finish_interrupt_save handle_interrupt_no_single_step
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_interrupt_no_single_step)
+ {
+ movei r30, 0 /* not an NMI */
+ j interrupt_return
+ }
+ STD_ENDPROC(handle_interrupt_no_single_step)
+
+ /*
+ * "NMI" interrupts mask ALL interrupts before calling the
+ * handler, and don't check thread flags, etc., on the way
+ * back out. In general, the only things we do here for NMIs
+ * are the register save/restore, fixing the PC if we were
+ * doing single step, and the dataplane kernel-TLB management.
+ * We don't (for example) deal with start/stop of the sched tick.
+ */
+ .pushsection .text.handle_nmi,"ax"
+handle_nmi:
+ finish_interrupt_save handle_nmi
+ check_single_stepping normal, .Ldispatch_nmi
+.Ldispatch_nmi:
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_nmi)
+ j interrupt_return
+ STD_ENDPROC(handle_nmi)
+
+ /*
+ * Parallel code for syscalls to handle_interrupt.
+ */
+ .pushsection .text.handle_syscall,"ax"
+handle_syscall:
+ finish_interrupt_save handle_syscall
+
+ /*
+ * Check for if we are single stepping in user level. If so, then
+ * we need to restore the PC.
+ */
+ check_single_stepping syscall, .Ldispatch_syscall
+.Ldispatch_syscall:
+
+ /* Enable irqs. */
+ TRACE_IRQS_ON
+ IRQ_ENABLE(r20, r21)
+
+ /* Bump the counter for syscalls made on this tile. */
+ moveli r20, lo16(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+ auli r20, r20, ha16(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET)
+ add r20, r20, tp
+ lw r21, r20
+ addi r21, r21, 1
+ sw r20, r21
+
+ /* Trace syscalls, if requested. */
+ GET_THREAD_INFO(r31)
+ addi r31, r31, THREAD_INFO_FLAGS_OFFSET
+ lw r30, r31
+ andi r30, r30, _TIF_SYSCALL_TRACE
+ bzt r30, .Lrestore_syscall_regs
+ jal do_syscall_trace
+ FEEDBACK_REENTER(handle_syscall)
+
+ /*
+ * We always reload our registers from the stack at this
+ * point. They might be valid, if we didn't build with
+ * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not
+ * doing syscall tracing, but there are enough cases now that it
+ * seems simplest just to do the reload unconditionally.
+ */
+.Lrestore_syscall_regs:
+ PTREGS_PTR(r11, PTREGS_OFFSET_REG(0))
+ pop_reg r0, r11
+ pop_reg r1, r11
+ pop_reg r2, r11
+ pop_reg r3, r11
+ pop_reg r4, r11
+ pop_reg r5, r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5)
+ pop_reg TREG_SYSCALL_NR_NAME, r11
+
+ /* Ensure that the syscall number is within the legal range. */
+ moveli r21, __NR_syscalls
+ {
+ slt_u r21, TREG_SYSCALL_NR_NAME, r21
+ moveli r20, lo16(sys_call_table)
+ }
+ {
+ bbns r21, .Linvalid_syscall
+ auli r20, r20, ha16(sys_call_table)
+ }
+ s2a r20, TREG_SYSCALL_NR_NAME, r20
+ lw r20, r20
+
+ /* Jump to syscall handler. */
+ jalr r20; .Lhandle_syscall_link:
+ FEEDBACK_REENTER(handle_syscall)
+
+ /*
+ * Write our r0 onto the stack so it gets restored instead
+ * of whatever the user had there before.
+ */
+ PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+ sw r29, r0
+
+ /* Do syscall trace again, if requested. */
+ lw r30, r31
+ andi r30, r30, _TIF_SYSCALL_TRACE
+ bzt r30, 1f
+ jal do_syscall_trace
+ FEEDBACK_REENTER(handle_syscall)
+1: j .Lresume_userspace /* jump into middle of interrupt_return */
+
+.Linvalid_syscall:
+ /* Report an invalid syscall back to the user program */
+ {
+ PTREGS_PTR(r29, PTREGS_OFFSET_REG(0))
+ movei r28, -ENOSYS
+ }
+ sw r29, r28
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ STD_ENDPROC(handle_syscall)
+
+ /* Return the address for oprofile to suppress in backtraces. */
+STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall)
+ lnk r0
+ {
+ addli r0, r0, .Lhandle_syscall_link - .
+ jrp lr
+ }
+ STD_ENDPROC(handle_syscall_link_address)
+
+STD_ENTRY(ret_from_fork)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ STD_ENDPROC(ret_from_fork)
+
+ /*
+ * Code for ill interrupt.
+ */
+ .pushsection .text.handle_ill,"ax"
+handle_ill:
+ finish_interrupt_save handle_ill
+
+ /*
+ * Check for if we are single stepping in user level. If so, then
+ * we need to restore the PC.
+ */
+ check_single_stepping ill, .Ldispatch_normal_ill
+
+ {
+ /* See if the PC is the 1st bundle in the buffer */
+ seq r25, r27, r26
+
+ /* Point to the 2nd bundle in the buffer */
+ addi r26, r26, 8
+ }
+ {
+ /* Point to the original pc */
+ addi r24, r29, SINGLESTEP_STATE_ORIG_PC_OFFSET
+
+ /* Branch if the PC is the 1st bundle in the buffer */
+ bnz r25, 3f
+ }
+ {
+ /* See if the PC is the 2nd bundle of the buffer */
+ seq r25, r27, r26
+
+ /* Set PC to next instruction */
+ addi r24, r29, SINGLESTEP_STATE_NEXT_PC_OFFSET
+ }
+ {
+ /* Point to flags */
+ addi r25, r29, SINGLESTEP_STATE_FLAGS_OFFSET
+
+ /* Branch if PC is in the second bundle */
+ bz r25, 2f
+ }
+ /* Load flags */
+ lw r25, r25
+ {
+ /*
+ * Get the offset for the register to restore
+ * Note: the lower bound is 2, so we have implicit scaling by 4.
+ * No multiplication of the register number by the size of a register
+ * is needed.
+ */
+ mm r27, r25, zero, SINGLESTEP_STATE_TARGET_LB, \
+ SINGLESTEP_STATE_TARGET_UB
+
+ /* Mask Rewrite_LR */
+ andi r25, r25, SINGLESTEP_STATE_MASK_UPDATE
+ }
+ {
+ addi r29, r29, SINGLESTEP_STATE_UPDATE_VALUE_OFFSET
+
+ /* Don't rewrite temp register */
+ bz r25, 3f
+ }
+ {
+ /* Get the temp value */
+ lw r29, r29
+
+ /* Point to where the register is stored */
+ add r27, r27, sp
+ }
+
+ /* Add in the C ABI save area size to the register offset */
+ addi r27, r27, C_ABI_SAVE_AREA_SIZE
+
+ /* Restore the user's register with the temp value */
+ sw r27, r29
+ j 3f
+
+2:
+ /* Must be in the third bundle */
+ addi r24, r29, SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET
+
+3:
+ /* set PC and continue */
+ lw r26, r24
+ sw r28, r26
+
+ /* Clear TIF_SINGLESTEP */
+ GET_THREAD_INFO(r0)
+
+ addi r1, r0, THREAD_INFO_FLAGS_OFFSET
+ {
+ lw r2, r1
+ addi r0, r0, THREAD_INFO_TASK_OFFSET /* currently a no-op */
+ }
+ andi r2, r2, ~_TIF_SINGLESTEP
+ sw r1, r2
+
+ /* Issue a sigtrap */
+ {
+ lw r0, r0 /* indirect thru thread_info to get task_info*/
+ addi r1, sp, C_ABI_SAVE_AREA_SIZE /* put ptregs pointer into r1 */
+ move r2, zero /* load error code into r2 */
+ }
+
+ jal send_sigtrap /* issue a SIGTRAP */
+ FEEDBACK_REENTER(handle_ill)
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+
+.Ldispatch_normal_ill:
+ {
+ jalr r0
+ PTREGS_PTR(r0, PTREGS_OFFSET_BASE)
+ }
+ FEEDBACK_REENTER(handle_ill)
+ {
+ movei r30, 0 /* not an NMI */
+ j interrupt_return
+ }
+ STD_ENDPROC(handle_ill)
+
+ .pushsection .rodata, "a"
+ .align 8
+bpt_code:
+ bpt
+ ENDPROC(bpt_code)
+ .popsection
+
+/* Various stub interrupt handlers and syscall handlers */
+
+STD_ENTRY_LOCAL(_kernel_double_fault)
+ mfspr r1, EX_CONTEXT_1_0
+ move r2, lr
+ move r3, sp
+ move r4, r52
+ addi sp, sp, -C_ABI_SAVE_AREA_SIZE
+ j kernel_double_fault
+ STD_ENDPROC(_kernel_double_fault)
+
+STD_ENTRY_LOCAL(bad_intr)
+ mfspr r2, EX_CONTEXT_1_0
+ panic "Unhandled interrupt %#x: PC %#lx"
+ STD_ENDPROC(bad_intr)
+
+/* Put address of pt_regs in reg and jump. */
+#define PTREGS_SYSCALL(x, reg) \
+ STD_ENTRY(x); \
+ { \
+ PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
+ j _##x \
+ }; \
+ STD_ENDPROC(x)
+
+PTREGS_SYSCALL(sys_execve, r3)
+PTREGS_SYSCALL(sys_sigaltstack, r2)
+PTREGS_SYSCALL(sys_rt_sigreturn, r0)
+
+/* Save additional callee-saves to pt_regs, put address in reg and jump. */
+#define PTREGS_SYSCALL_ALL_REGS(x, reg) \
+ STD_ENTRY(x); \
+ push_extra_callee_saves reg; \
+ j _##x; \
+ STD_ENDPROC(x)
+
+PTREGS_SYSCALL_ALL_REGS(sys_fork, r0)
+PTREGS_SYSCALL_ALL_REGS(sys_vfork, r0)
+PTREGS_SYSCALL_ALL_REGS(sys_clone, r4)
+PTREGS_SYSCALL_ALL_REGS(sys_cmpxchg_badaddr, r1)
+
+/*
+ * This entrypoint is taken for the cmpxchg and atomic_update fast
+ * swints. We may wish to generalize it to other fast swints at some
+ * point, but for now there are just two very similar ones, which
+ * makes it faster.
+ *
+ * The fast swint code is designed to have a small footprint. It does
+ * not save or restore any GPRs, counting on the caller-save registers
+ * to be available to it on entry. It does not modify any callee-save
+ * registers (including "lr"). It does not check what PL it is being
+ * called at, so you'd better not call it other than at PL0.
+ *
+ * It does not use the stack, but since it might be re-interrupted by
+ * a page fault which would assume the stack was valid, it does
+ * save/restore the stack pointer and zero it out to make sure it gets reset.
+ * Since we always keep interrupts disabled, the hypervisor won't
+ * clobber our EX_CONTEXT_1_x registers, so we don't save/restore them
+ * (other than to advance the PC on return).
+ *
+ * We have to manually validate the user vs kernel address range
+ * (since at PL1 we can read/write both), and for performance reasons
+ * we don't allow cmpxchg on the fc000000 memory region, since we only
+ * validate that the user address is below PAGE_OFFSET.
+ *
+ * We place it in the __HEAD section to ensure it is relatively
+ * near to the intvec_SWINT_1 code (reachable by a conditional branch).
+ *
+ * Must match register usage in do_page_fault().
+ */
+ __HEAD
+ .align 64
+ /* Align much later jump on the start of a cache line. */
+#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ nop; nop
+#endif
+ENTRY(sys_cmpxchg)
+
+ /*
+ * Save "sp" and set it zero for any possible page fault.
+ *
+ * HACK: We want to both zero sp and check r0's alignment,
+ * so we do both at once. If "sp" becomes nonzero we
+ * know r0 is unaligned and branch to the error handler that
+ * restores sp, so this is OK.
+ *
+ * ICS is disabled right now so having a garbage but nonzero
+ * sp is OK, since we won't execute any faulting instructions
+ * when it is nonzero.
+ */
+ {
+ move r27, sp
+ andi sp, r0, 3
+ }
+
+ /*
+ * Get the lock address in ATOMIC_LOCK_REG, and also validate that the
+ * address is less than PAGE_OFFSET, since that won't trap at PL1.
+ * We only use bits less than PAGE_SHIFT to avoid having to worry
+ * about aliasing among multiple mappings of the same physical page,
+ * and we ignore the low 3 bits so we have one lock that covers
+ * both a cmpxchg64() and a cmpxchg() on either its low or high word.
+ * NOTE: this code must match __atomic_hashed_lock() in lib/atomic.c.
+ */
+
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ {
+ /* Check for unaligned input. */
+ bnz sp, .Lcmpxchg_badaddr
+ mm r25, r0, zero, 3, PAGE_SHIFT-1
+ }
+ {
+ crc32_32 r25, zero, r25
+ moveli r21, lo16(atomic_lock_ptr)
+ }
+ {
+ auli r21, r21, ha16(atomic_lock_ptr)
+ auli r23, zero, hi16(PAGE_OFFSET) /* hugepage-aligned */
+ }
+ {
+ shri r20, r25, 32 - ATOMIC_HASH_L1_SHIFT
+ slt_u r23, r0, r23
+
+ /*
+ * Ensure that the TLB is loaded before we take out the lock.
+ * On TILEPro, this will start fetching the value all the way
+ * into our L1 as well (and if it gets modified before we
+ * grab the lock, it will be invalidated from our cache
+ * before we reload it). On tile64, we'll start fetching it
+ * into our L1 if we're the home, and if we're not, we'll
+ * still at least start fetching it into the home's L2.
+ */
+ lw r26, r0
+ }
+ {
+ s2a r21, r20, r21
+ bbns r23, .Lcmpxchg_badaddr
+ }
+ {
+ lw r21, r21
+ seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_cmpxchg64
+ andi r25, r25, ATOMIC_HASH_L2_SIZE - 1
+ }
+ {
+ /* Branch away at this point if we're doing a 64-bit cmpxchg. */
+ bbs r23, .Lcmpxchg64
+ andi r23, r0, 7 /* Precompute alignment for cmpxchg64. */
+ }
+
+ {
+ /*
+ * We very carefully align the code that actually runs with
+ * the lock held (nine bundles) so that we know it is all in
+ * the icache when we start. This instruction (the jump) is
+ * at the start of the first cache line, address zero mod 64;
+ * we jump to somewhere in the second cache line to issue the
+ * tns, then jump back to finish up.
+ */
+ s2a ATOMIC_LOCK_REG_NAME, r25, r21
+ j .Lcmpxchg32_tns
+ }
+
+#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+ {
+ /* Check for unaligned input. */
+ bnz sp, .Lcmpxchg_badaddr
+ auli r23, zero, hi16(PAGE_OFFSET) /* hugepage-aligned */
+ }
+ {
+ /*
+ * Slide bits into position for 'mm'. We want to ignore
+ * the low 3 bits of r0, and consider only the next
+ * ATOMIC_HASH_SHIFT bits.
+ * Because of C pointer arithmetic, we want to compute this:
+ *
+ * ((char*)atomic_locks +
+ * (((r0 >> 3) & (1 << (ATOMIC_HASH_SIZE - 1))) << 2))
+ *
+ * Instead of two shifts we just ">> 1", and use 'mm'
+ * to ignore the low and high bits we don't want.
+ */
+ shri r25, r0, 1
+
+ slt_u r23, r0, r23
+
+ /*
+ * Ensure that the TLB is loaded before we take out the lock.
+ * On tilepro, this will start fetching the value all the way
+ * into our L1 as well (and if it gets modified before we
+ * grab the lock, it will be invalidated from our cache
+ * before we reload it). On tile64, we'll start fetching it
+ * into our L1 if we're the home, and if we're not, we'll
+ * still at least start fetching it into the home's L2.
+ */
+ lw r26, r0
+ }
+ {
+ /* atomic_locks is page aligned so this suffices to get its addr. */
+ auli r21, zero, hi16(atomic_locks)
+
+ bbns r23, .Lcmpxchg_badaddr
+ }
+ {
+ /*
+ * Insert the hash bits into the page-aligned pointer.
+ * ATOMIC_HASH_SHIFT is so big that we don't actually hash
+ * the unmasked address bits, as that may cause unnecessary
+ * collisions.
+ */
+ mm ATOMIC_LOCK_REG_NAME, r25, r21, 2, (ATOMIC_HASH_SHIFT + 2) - 1
+
+ seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_cmpxchg64
+ }
+ {
+ /* Branch away at this point if we're doing a 64-bit cmpxchg. */
+ bbs r23, .Lcmpxchg64
+ andi r23, r0, 7 /* Precompute alignment for cmpxchg64. */
+ }
+ {
+ /*
+ * We very carefully align the code that actually runs with
+ * the lock held (nine bundles) so that we know it is all in
+ * the icache when we start. This instruction (the jump) is
+ * at the start of the first cache line, address zero mod 64;
+ * we jump to somewhere in the second cache line to issue the
+ * tns, then jump back to finish up.
+ */
+ j .Lcmpxchg32_tns
+ }
+
+#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+ ENTRY(__sys_cmpxchg_grab_lock)
+
+ /*
+ * Perform the actual cmpxchg or atomic_update.
+ * Note that __futex_mark_unlocked() in uClibc relies on
+ * atomic_update() to always perform an "mf", so don't make
+ * it optional or conditional without modifying that code.
+ */
+.Ldo_cmpxchg32:
+ {
+ lw r21, r0
+ seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_atomic_update
+ move r24, r2
+ }
+ {
+ seq r22, r21, r1 /* See if cmpxchg matches. */
+ and r25, r21, r1 /* If atomic_update, compute (*mem & mask) */
+ }
+ {
+ or r22, r22, r23 /* Skip compare branch for atomic_update. */
+ add r25, r25, r2 /* Compute (*mem & mask) + addend. */
+ }
+ {
+ mvnz r24, r23, r25 /* Use atomic_update value if appropriate. */
+ bbns r22, .Lcmpxchg32_mismatch
+ }
+ sw r0, r24
+
+ /* Do slow mtspr here so the following "mf" waits less. */
+ {
+ move sp, r27
+ mtspr EX_CONTEXT_1_0, r28
+ }
+ mf
+
+ /* The following instruction is the start of the second cache line. */
+ {
+ move r0, r21
+ sw ATOMIC_LOCK_REG_NAME, zero
+ }
+ iret
+
+ /* Duplicated code here in the case where we don't overlap "mf" */
+.Lcmpxchg32_mismatch:
+ {
+ move r0, r21
+ sw ATOMIC_LOCK_REG_NAME, zero
+ }
+ {
+ move sp, r27
+ mtspr EX_CONTEXT_1_0, r28
+ }
+ iret
+
+ /*
+ * The locking code is the same for 32-bit cmpxchg/atomic_update,
+ * and for 64-bit cmpxchg. We provide it as a macro and put
+ * it into both versions. We can't share the code literally
+ * since it depends on having the right branch-back address.
+ * Note that the first few instructions should share the cache
+ * line with the second half of the actual locked code.
+ */
+ .macro cmpxchg_lock, bitwidth
+
+ /* Lock; if we succeed, jump back up to the read-modify-write. */
+#ifdef CONFIG_SMP
+ tns r21, ATOMIC_LOCK_REG_NAME
+#else
+ /*
+ * Non-SMP preserves all the lock infrastructure, to keep the
+ * code simpler for the interesting (SMP) case. However, we do
+ * one small optimization here and in atomic_asm.S, which is
+ * to fake out acquiring the actual lock in the atomic_lock table.
+ */
+ movei r21, 0
+#endif
+
+ /* Issue the slow SPR here while the tns result is in flight. */
+ mfspr r28, EX_CONTEXT_1_0
+
+ {
+ addi r28, r28, 8 /* return to the instruction after the swint1 */
+ bzt r21, .Ldo_cmpxchg\bitwidth
+ }
+ /*
+ * The preceding instruction is the last thing that must be
+ * on the second cache line.
+ */
+
+#ifdef CONFIG_SMP
+ /*
+ * We failed to acquire the tns lock on our first try. Now use
+ * bounded exponential backoff to retry, like __atomic_spinlock().
+ */
+ {
+ moveli r23, 2048 /* maximum backoff time in cycles */
+ moveli r25, 32 /* starting backoff time in cycles */
+ }
+1: mfspr r26, CYCLE_LOW /* get start point for this backoff */
+2: mfspr r22, CYCLE_LOW /* test to see if we've backed off enough */
+ sub r22, r22, r26
+ slt r22, r22, r25
+ bbst r22, 2b
+ {
+ shli r25, r25, 1 /* double the backoff; retry the tns */
+ tns r21, ATOMIC_LOCK_REG_NAME
+ }
+ slt r26, r23, r25 /* is the proposed backoff too big? */
+ {
+ mvnz r25, r26, r23
+ bzt r21, .Ldo_cmpxchg\bitwidth
+ }
+ j 1b
+#endif /* CONFIG_SMP */
+ .endm
+
+.Lcmpxchg32_tns:
+ cmpxchg_lock 32
+
+ /*
+ * This code is invoked from sys_cmpxchg after most of the
+ * preconditions have been checked. We still need to check
+ * that r0 is 8-byte aligned, since if it's not we won't
+ * actually be atomic. However, ATOMIC_LOCK_REG has the atomic
+ * lock pointer and r27/r28 have the saved SP/PC.
+ * r23 is holding "r0 & 7" so we can test for alignment.
+ * The compare value is in r2/r3; the new value is in r4/r5.
+ * On return, we must put the old value in r0/r1.
+ */
+ .align 64
+.Lcmpxchg64:
+ {
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ s2a ATOMIC_LOCK_REG_NAME, r25, r21
+#endif
+ bzt r23, .Lcmpxchg64_tns
+ }
+ j .Lcmpxchg_badaddr
+
+.Ldo_cmpxchg64:
+ {
+ lw r21, r0
+ addi r25, r0, 4
+ }
+ {
+ lw r1, r25
+ }
+ seq r26, r21, r2
+ {
+ bz r26, .Lcmpxchg64_mismatch
+ seq r26, r1, r3
+ }
+ {
+ bz r26, .Lcmpxchg64_mismatch
+ }
+ sw r0, r4
+ sw r25, r5
+
+ /*
+ * The 32-bit path provides optimized "match" and "mismatch"
+ * iret paths, but we don't have enough bundles in this cache line
+ * to do that, so we just make even the "mismatch" path do an "mf".
+ */
+.Lcmpxchg64_mismatch:
+ {
+ move sp, r27
+ mtspr EX_CONTEXT_1_0, r28
+ }
+ mf
+ {
+ move r0, r21
+ sw ATOMIC_LOCK_REG_NAME, zero
+ }
+ iret
+
+.Lcmpxchg64_tns:
+ cmpxchg_lock 64
+
+
+ /*
+ * Reset sp and revector to sys_cmpxchg_badaddr(), which will
+ * just raise the appropriate signal and exit. Doing it this
+ * way means we don't have to duplicate the code in intvec.S's
+ * int_hand macro that locates the top of the stack.
+ */
+.Lcmpxchg_badaddr:
+ {
+ moveli TREG_SYSCALL_NR_NAME, __NR_cmpxchg_badaddr
+ move sp, r27
+ }
+ j intvec_SWINT_1
+ ENDPROC(sys_cmpxchg)
+ ENTRY(__sys_cmpxchg_end)
+
+
+/* The single-step support may need to read all the registers. */
+int_unalign:
+ push_extra_callee_saves r0
+ j do_trap
+
+/* Include .intrpt1 array of interrupt vectors */
+ .section ".intrpt1", "ax"
+
+#define op_handle_perf_interrupt bad_intr
+#define op_handle_aux_perf_interrupt bad_intr
+
+#define do_hardwall_trap bad_intr
+
+ int_hand INT_ITLB_MISS, ITLB_MISS, \
+ do_page_fault, handle_interrupt_no_single_step
+ int_hand INT_MEM_ERROR, MEM_ERROR, bad_intr
+ int_hand INT_ILL, ILL, do_trap, handle_ill
+ int_hand INT_GPV, GPV, do_trap
+ int_hand INT_SN_ACCESS, SN_ACCESS, do_trap
+ int_hand INT_IDN_ACCESS, IDN_ACCESS, do_trap
+ int_hand INT_UDN_ACCESS, UDN_ACCESS, do_trap
+ int_hand INT_IDN_REFILL, IDN_REFILL, bad_intr
+ int_hand INT_UDN_REFILL, UDN_REFILL, bad_intr
+ int_hand INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr
+ int_hand INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr
+ int_hand INT_SWINT_3, SWINT_3, do_trap
+ int_hand INT_SWINT_2, SWINT_2, do_trap
+ int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall
+ int_hand INT_SWINT_0, SWINT_0, do_trap
+ int_hand INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign
+ int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault
+ int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault
+ int_hand INT_DMATLB_MISS, DMATLB_MISS, do_page_fault
+ int_hand INT_DMATLB_ACCESS, DMATLB_ACCESS, do_page_fault
+ int_hand INT_SNITLB_MISS, SNITLB_MISS, do_page_fault
+ int_hand INT_SN_NOTIFY, SN_NOTIFY, bad_intr
+ int_hand INT_SN_FIREWALL, SN_FIREWALL, do_hardwall_trap
+ int_hand INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr
+ int_hand INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap
+ int_hand INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt
+ int_hand INT_IDN_TIMER, IDN_TIMER, bad_intr
+ int_hand INT_UDN_TIMER, UDN_TIMER, bad_intr
+ int_hand INT_DMA_NOTIFY, DMA_NOTIFY, bad_intr
+ int_hand INT_IDN_CA, IDN_CA, bad_intr
+ int_hand INT_UDN_CA, UDN_CA, bad_intr
+ int_hand INT_IDN_AVAIL, IDN_AVAIL, bad_intr
+ int_hand INT_UDN_AVAIL, UDN_AVAIL, bad_intr
+ int_hand INT_PERF_COUNT, PERF_COUNT, \
+ op_handle_perf_interrupt, handle_nmi
+ int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr
+ int_hand INT_INTCTRL_2, INTCTRL_2, bad_intr
+ dc_dispatch INT_INTCTRL_1, INTCTRL_1
+ int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr
+ int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \
+ hv_message_intr, handle_interrupt_downcall
+ int_hand INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, \
+ tile_dev_intr, handle_interrupt_downcall
+ int_hand INT_I_ASID, I_ASID, bad_intr
+ int_hand INT_D_ASID, D_ASID, bad_intr
+ int_hand INT_DMATLB_MISS_DWNCL, DMATLB_MISS_DWNCL, \
+ do_page_fault, handle_interrupt_downcall
+ int_hand INT_SNITLB_MISS_DWNCL, SNITLB_MISS_DWNCL, \
+ do_page_fault, handle_interrupt_downcall
+ int_hand INT_DMATLB_ACCESS_DWNCL, DMATLB_ACCESS_DWNCL, \
+ do_page_fault, handle_interrupt_downcall
+ int_hand INT_SN_CPL, SN_CPL, bad_intr
+ int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap
+#if CHIP_HAS_AUX_PERF_COUNTERS()
+ int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \
+ op_handle_aux_perf_interrupt, handle_nmi
+#endif
+
+ /* Synthetic interrupt delivered only by the simulator */
+ int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint
diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c
new file mode 100644
index 000000000000..24cc6b2abc2c
--- /dev/null
+++ b/arch/tile/kernel/irq.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+#include <linux/uaccess.h>
+#include <hv/drv_pcie_rc_intf.h>
+
+/*
+ * The set of interrupts we enable for raw_local_irq_enable().
+ * This is initialized to have just a single interrupt that the kernel
+ * doesn't actually use as a sentinel. During kernel init,
+ * interrupts are added as the kernel gets prepared to support them.
+ * NOTE: we could probably initialize them all statically up front.
+ */
+DEFINE_PER_CPU(unsigned long long, interrupts_enabled_mask) =
+ INITIAL_INTERRUPTS_ENABLED;
+EXPORT_PER_CPU_SYMBOL(interrupts_enabled_mask);
+
+/* Define per-tile device interrupt state */
+DEFINE_PER_CPU(HV_IntrState, dev_intr_state);
+
+DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp;
+EXPORT_PER_CPU_SYMBOL(irq_stat);
+
+
+
+/*
+ * Interrupt dispatcher, invoked upon a hypervisor device interrupt downcall
+ */
+void tile_dev_intr(struct pt_regs *regs, int intnum)
+{
+ int irq;
+
+ /*
+ * Get the device interrupt pending mask from where the hypervisor
+ * has tucked it away for us.
+ */
+ unsigned long pending_dev_intr_mask = __insn_mfspr(SPR_SYSTEM_SAVE_1_3);
+
+
+ /* Track time spent here in an interrupt context. */
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: less than 1/8th stack free? */
+ {
+ long sp = stack_pointer - (long) current_thread_info();
+ if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
+ printk(KERN_EMERG "tile_dev_intr: "
+ "stack overflow: %ld\n",
+ sp - sizeof(struct thread_info));
+ dump_stack();
+ }
+ }
+#endif
+
+ for (irq = 0; pending_dev_intr_mask; ++irq) {
+ if (pending_dev_intr_mask & 0x1) {
+ generic_handle_irq(irq);
+
+ /* Count device irqs; IPIs are counted elsewhere. */
+ if (irq > HV_MAX_IPI_INTERRUPT)
+ __get_cpu_var(irq_stat).irq_dev_intr_count++;
+ }
+ pending_dev_intr_mask >>= 1;
+ }
+
+ /*
+ * Track time spent against the current process again and
+ * process any softirqs if they are waiting.
+ */
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+
+/* Mask an interrupt. */
+static void hv_dev_irq_mask(unsigned int irq)
+{
+ HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
+ hv_disable_intr(p_intr_state, 1 << irq);
+}
+
+/* Unmask an interrupt. */
+static void hv_dev_irq_unmask(unsigned int irq)
+{
+ /* Re-enable the hypervisor to generate interrupts. */
+ HV_IntrState *p_intr_state = &__get_cpu_var(dev_intr_state);
+ hv_enable_intr(p_intr_state, 1 << irq);
+}
+
+/*
+ * The HV doesn't latch incoming interrupts while an interrupt is
+ * disabled, so we need to reenable interrupts before running the
+ * handler.
+ *
+ * ISSUE: Enabling the interrupt this early avoids any race conditions
+ * but introduces the possibility of nested interrupt stack overflow.
+ * An imminent change to the HV IRQ model will fix this.
+ */
+static void hv_dev_irq_ack(unsigned int irq)
+{
+ hv_dev_irq_unmask(irq);
+}
+
+/*
+ * Since ack() reenables interrupts, there's nothing to do at eoi().
+ */
+static void hv_dev_irq_eoi(unsigned int irq)
+{
+}
+
+static struct irq_chip hv_dev_irq_chip = {
+ .typename = "hv_dev_irq_chip",
+ .ack = hv_dev_irq_ack,
+ .mask = hv_dev_irq_mask,
+ .unmask = hv_dev_irq_unmask,
+ .eoi = hv_dev_irq_eoi,
+};
+
+static struct irqaction resched_action = {
+ .handler = handle_reschedule_ipi,
+ .name = "resched",
+ .dev_id = handle_reschedule_ipi /* unique token */,
+};
+
+void __init init_IRQ(void)
+{
+ /* Bind IPI irqs. Does this belong somewhere else in init? */
+ tile_irq_activate(IRQ_RESCHEDULE);
+ BUG_ON(setup_irq(IRQ_RESCHEDULE, &resched_action));
+}
+
+void __cpuinit init_per_tile_IRQs(void)
+{
+ int rc;
+
+ /* Set the pointer to the per-tile device interrupt state. */
+ HV_IntrState *sv_ptr = &__get_cpu_var(dev_intr_state);
+ rc = hv_dev_register_intr_state(sv_ptr);
+ if (rc != HV_OK)
+ panic("hv_dev_register_intr_state: error %d", rc);
+
+}
+
+void tile_irq_activate(unsigned int irq)
+{
+ /*
+ * Paravirtualized drivers can call up to the HV to find out
+ * which irq they're associated with. The HV interface
+ * doesn't provide a generic call for discovering all valid
+ * IRQs, so drivers must call this method to initialize newly
+ * discovered IRQs.
+ *
+ * We could also just initialize all 32 IRQs at startup, but
+ * doing so would lead to a kernel fault if an unexpected
+ * interrupt fires and jumps to a NULL action. By defering
+ * the set_irq_chip_and_handler() call, unexpected IRQs are
+ * handled properly by handle_bad_irq().
+ */
+ hv_dev_irq_mask(irq);
+ set_irq_chip_and_handler(irq, &hv_dev_irq_chip, handle_percpu_irq);
+}
+
+void ack_bad_irq(unsigned int irq)
+{
+ printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/*
+ * Generic, controller-independent functions:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v, j;
+ struct irqaction *action;
+ unsigned long flags;
+
+ if (i == 0) {
+ seq_printf(p, " ");
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "CPU%-8d", j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ", i);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_irqs_cpu(i, j));
+#endif
+ seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ seq_printf(p, " %s", action->name);
+
+ for (action = action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+
+ seq_putc(p, '\n');
+skip:
+ raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ }
+ return 0;
+}
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
new file mode 100644
index 000000000000..ed3e1cb8dcc4
--- /dev/null
+++ b/arch/tile/kernel/machine_kexec.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * based on machine_kexec.c from other architectures in linux-2.6.18
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <linux/errno.h>
+#include <linux/vmalloc.h>
+#include <linux/cpumask.h>
+#include <linux/kernel.h>
+#include <linux/elf.h>
+#include <linux/highmem.h>
+#include <linux/mmu_context.h>
+#include <linux/io.h>
+#include <linux/timex.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
+#include <asm/checksum.h>
+#include <hv/hypervisor.h>
+
+
+/*
+ * This stuff is not in elf.h and is not in any other kernel include.
+ * This stuff is needed below in the little boot notes parser to
+ * extract the command line so we can pass it to the hypervisor.
+ */
+struct Elf32_Bhdr {
+ Elf32_Word b_signature;
+ Elf32_Word b_size;
+ Elf32_Half b_checksum;
+ Elf32_Half b_records;
+};
+#define ELF_BOOT_MAGIC 0x0E1FB007
+#define EBN_COMMAND_LINE 0x00000004
+#define roundupsz(X) (((X) + 3) & ~3)
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+
+
+void machine_shutdown(void)
+{
+ /*
+ * Normally we would stop all the other processors here, but
+ * the check in machine_kexec_prepare below ensures we'll only
+ * get this far if we've been booted with "nosmp" on the
+ * command line or without CONFIG_SMP so there's nothing to do
+ * here (for now).
+ */
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /*
+ * Cannot happen. This type of kexec is disabled on this
+ * architecture (and enforced in machine_kexec_prepare below).
+ */
+}
+
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ if (num_online_cpus() > 1) {
+ printk(KERN_WARNING "%s: detected attempt to kexec "
+ "with num_online_cpus() > 1\n",
+ __func__);
+ return -ENOSYS;
+ }
+ if (image->type != KEXEC_TYPE_DEFAULT) {
+ printk(KERN_WARNING "%s: detected attempt to kexec "
+ "with unsupported type: %d\n",
+ __func__,
+ image->type);
+ return -ENOSYS;
+ }
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ /*
+ * We did nothing in machine_kexec_prepare,
+ * so we have nothing to do here.
+ */
+}
+
+/*
+ * If we can find elf boot notes on this page, return the command
+ * line. Otherwise, silently return null. Somewhat kludgy, but no
+ * good way to do this without significantly rearchitecting the
+ * architecture-independent kexec code.
+ */
+
+static unsigned char *kexec_bn2cl(void *pg)
+{
+ struct Elf32_Bhdr *bhdrp;
+ Elf32_Nhdr *nhdrp;
+ unsigned char *desc;
+ unsigned char *command_line;
+ __sum16 csum;
+
+ bhdrp = (struct Elf32_Bhdr *) pg;
+
+ /*
+ * This routine is invoked for every source page, so make
+ * sure to quietly ignore every impossible page.
+ */
+ if (bhdrp->b_signature != ELF_BOOT_MAGIC ||
+ bhdrp->b_size > PAGE_SIZE)
+ return 0;
+
+ /*
+ * If we get a checksum mismatch, it's possible that this is
+ * just a false positive, but relatively unlikely. We dump
+ * out the contents of the section so we can diagnose better.
+ */
+ csum = ip_compute_csum(pg, bhdrp->b_size);
+ if (csum != 0) {
+ int i;
+ unsigned char *p = pg;
+ int nbytes = min((Elf32_Word)1000, bhdrp->b_size);
+ printk(KERN_INFO "%s: bad checksum %#x\n", __func__, csum);
+ printk(KERN_INFO "bytes (%d):", bhdrp->b_size);
+ for (i = 0; i < nbytes; ++i)
+ printk(" %02x", p[i]);
+ if (bhdrp->b_size != nbytes)
+ printk(" ...");
+ printk("\n");
+ return 0;
+ }
+
+ nhdrp = (Elf32_Nhdr *) (bhdrp + 1);
+
+ while (nhdrp->n_type != EBN_COMMAND_LINE) {
+
+ desc = (unsigned char *) (nhdrp + 1);
+ desc += roundupsz(nhdrp->n_descsz);
+
+ nhdrp = (Elf32_Nhdr *) desc;
+
+ /* still in bounds? */
+ if ((unsigned char *) (nhdrp + 1) >
+ ((unsigned char *) pg) + bhdrp->b_size) {
+
+ printk(KERN_INFO "%s: out of bounds\n", __func__);
+ return 0;
+ }
+ }
+
+ command_line = (unsigned char *) (nhdrp + 1);
+ desc = command_line;
+
+ while (*desc != '\0') {
+ desc++;
+ if (((unsigned long)desc & PAGE_MASK) != (unsigned long)pg) {
+ printk(KERN_INFO "%s: ran off end of page\n",
+ __func__);
+ return 0;
+ }
+ }
+
+ return command_line;
+}
+
+static void kexec_find_and_set_command_line(struct kimage *image)
+{
+ kimage_entry_t *ptr, entry;
+
+ unsigned char *command_line = 0;
+ unsigned char *r;
+ HV_Errno hverr;
+
+ for (ptr = &image->head;
+ (entry = *ptr) && !(entry & IND_DONE);
+ ptr = (entry & IND_INDIRECTION) ?
+ phys_to_virt((entry & PAGE_MASK)) : ptr + 1) {
+
+ if ((entry & IND_SOURCE)) {
+ void *va =
+ kmap_atomic_pfn(entry >> PAGE_SHIFT, KM_USER0);
+ r = kexec_bn2cl(va);
+ if (r) {
+ command_line = r;
+ break;
+ }
+ kunmap_atomic(va, KM_USER0);
+ }
+ }
+
+ if (command_line != 0) {
+ printk(KERN_INFO "setting new command line to \"%s\"\n",
+ command_line);
+
+ hverr = hv_set_command_line(
+ (HV_VirtAddr) command_line, strlen(command_line));
+ kunmap_atomic(command_line, KM_USER0);
+ } else {
+ printk(KERN_INFO "%s: no command line found; making empty\n",
+ __func__);
+ hverr = hv_set_command_line((HV_VirtAddr) command_line, 0);
+ }
+ if (hverr) {
+ printk(KERN_WARNING
+ "%s: call to hv_set_command_line returned error: %d\n",
+ __func__, hverr);
+
+ }
+}
+
+/*
+ * The kexec code range-checks all its PAs, so to avoid having it run
+ * amok and allocate memory and then sequester it from every other
+ * controller, we force it to come from controller zero. We also
+ * disable the oom-killer since if we do end up running out of memory,
+ * that almost certainly won't help.
+ */
+struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order)
+{
+ gfp_mask |= __GFP_THISNODE | __GFP_NORETRY;
+ return alloc_pages_node(0, gfp_mask, order);
+}
+
+static void setup_quasi_va_is_pa(void)
+{
+ HV_PTE *pgtable;
+ HV_PTE pte;
+ int i;
+
+ /*
+ * Flush our TLB to prevent conflicts between the previous contents
+ * and the new stuff we're about to add.
+ */
+ local_flush_tlb_all();
+
+ /* setup VA is PA, at least up to PAGE_OFFSET */
+
+ pgtable = (HV_PTE *)current->mm->pgd;
+ pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE);
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
+
+ for (i = 0; i < pgd_index(PAGE_OFFSET); i++)
+ pgtable[i] = pfn_pte(i << (HPAGE_SHIFT - PAGE_SHIFT), pte);
+}
+
+
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ void *reboot_code_buffer;
+ NORET_TYPE void (*rnk)(unsigned long, void *, unsigned long)
+ ATTRIB_NORET;
+
+ /* Mask all interrupts before starting to reboot. */
+ interrupt_mask_set_mask(~0ULL);
+
+ kexec_find_and_set_command_line(image);
+
+ /*
+ * Adjust the home caching of the control page to be cached on
+ * this cpu, and copy the assembly helper into the control
+ * code page, which we map in the vmalloc area.
+ */
+ homecache_change_page_home(image->control_code_page, 0,
+ smp_processor_id());
+ reboot_code_buffer = vmap(&image->control_code_page, 1, 0,
+ __pgprot(_PAGE_KERNEL | _PAGE_EXECUTABLE));
+ memcpy(reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+ __flush_icache_range(
+ (unsigned long) reboot_code_buffer,
+ (unsigned long) reboot_code_buffer + relocate_new_kernel_size);
+
+ setup_quasi_va_is_pa();
+
+ /* now call it */
+ rnk = reboot_code_buffer;
+ (*rnk)(image->head, reboot_code_buffer, image->start);
+}
diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c
new file mode 100644
index 000000000000..f991f5285d8a
--- /dev/null
+++ b/arch/tile/kernel/messaging.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/percpu.h>
+#include <linux/smp.h>
+#include <linux/hardirq.h>
+#include <linux/ptrace.h>
+#include <asm/hv_driver.h>
+#include <asm/irq_regs.h>
+#include <hv/hypervisor.h>
+#include <arch/interrupts.h>
+
+/* All messages are stored here */
+static DEFINE_PER_CPU(HV_MsgState, msg_state);
+
+void __cpuinit init_messaging()
+{
+ /* Allocate storage for messages in kernel space */
+ HV_MsgState *state = &__get_cpu_var(msg_state);
+ int rc = hv_register_message_state(state);
+ if (rc != HV_OK)
+ panic("hv_register_message_state: error %d", rc);
+
+ /* Make sure downcall interrupts will be enabled. */
+ raw_local_irq_unmask(INT_INTCTRL_1);
+}
+
+void hv_message_intr(struct pt_regs *regs, int intnum)
+{
+ /*
+ * We enter with interrupts disabled and leave them disabled,
+ * to match expectations of called functions (e.g.
+ * do_ccupdate_local() in mm/slab.c). This is also consistent
+ * with normal call entry for device interrupts.
+ */
+
+ int message[HV_MAX_MESSAGE_SIZE/sizeof(int)];
+ HV_RcvMsgInfo rmi;
+ int nmsgs = 0;
+
+ /* Track time spent here in an interrupt context */
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: less than 1/8th stack free? */
+ {
+ long sp = stack_pointer - (long) current_thread_info();
+ if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
+ printk(KERN_EMERG "hv_message_intr: "
+ "stack overflow: %ld\n",
+ sp - sizeof(struct thread_info));
+ dump_stack();
+ }
+ }
+#endif
+
+ while (1) {
+ rmi = hv_receive_message(__get_cpu_var(msg_state),
+ (HV_VirtAddr) message,
+ sizeof(message));
+ if (rmi.msglen == 0)
+ break;
+
+ if (rmi.msglen < 0)
+ panic("hv_receive_message failed: %d", rmi.msglen);
+
+ ++nmsgs;
+
+ if (rmi.source == HV_MSG_TILE) {
+ int tag;
+
+ /* we just send tags for now */
+ BUG_ON(rmi.msglen != sizeof(int));
+
+ tag = message[0];
+#ifdef CONFIG_SMP
+ evaluate_message(message[0]);
+#else
+ panic("Received IPI message %d in UP mode", tag);
+#endif
+ } else if (rmi.source == HV_MSG_INTR) {
+ HV_IntrMsg *him = (HV_IntrMsg *)message;
+ struct hv_driver_cb *cb =
+ (struct hv_driver_cb *)him->intarg;
+ cb->callback(cb, him->intdata);
+ __get_cpu_var(irq_stat).irq_hv_msg_count++;
+ }
+ }
+
+ /*
+ * We shouldn't have gotten a message downcall with no
+ * messages available.
+ */
+ if (nmsgs == 0)
+ panic("Message downcall invoked with no messages!");
+
+ /*
+ * Track time spent against the current process again and
+ * process any softirqs if they are waiting.
+ */
+ irq_exit();
+ set_irq_regs(old_regs);
+}
diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c
new file mode 100644
index 000000000000..ed3e91161f88
--- /dev/null
+++ b/arch/tile/kernel/module.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Based on i386 version, copyright (C) 2001 Rusty Russell.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <asm/opcode-tile.h>
+#include <asm/pgtable.h>
+
+#ifdef __tilegx__
+# define Elf_Rela Elf64_Rela
+# define ELF_R_SYM ELF64_R_SYM
+# define ELF_R_TYPE ELF64_R_TYPE
+#else
+# define Elf_Rela Elf32_Rela
+# define ELF_R_SYM ELF32_R_SYM
+# define ELF_R_TYPE ELF32_R_TYPE
+#endif
+
+#ifdef MODULE_DEBUG
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt...)
+#endif
+
+/*
+ * Allocate some address space in the range MEM_MODULE_START to
+ * MEM_MODULE_END and populate it with memory.
+ */
+void *module_alloc(unsigned long size)
+{
+ struct page **pages;
+ pgprot_t prot_rwx = __pgprot(_PAGE_KERNEL | _PAGE_KERNEL_EXEC);
+ struct vm_struct *area;
+ int i = 0;
+ int npages;
+
+ if (size == 0)
+ return NULL;
+ npages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
+ pages = kmalloc(npages * sizeof(struct page *), GFP_KERNEL);
+ if (pages == NULL)
+ return NULL;
+ for (; i < npages; ++i) {
+ pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM);
+ if (!pages[i])
+ goto error;
+ }
+
+ area = __get_vm_area(size, VM_ALLOC, MEM_MODULE_START, MEM_MODULE_END);
+ if (!area)
+ goto error;
+
+ if (map_vm_area(area, prot_rwx, &pages)) {
+ vunmap(area->addr);
+ goto error;
+ }
+
+ return area->addr;
+
+error:
+ while (--i >= 0)
+ __free_page(pages[i]);
+ kfree(pages);
+ return NULL;
+}
+
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ vfree(module_region);
+ /*
+ * FIXME: If module_region == mod->init_region, trim exception
+ * table entries.
+ */
+}
+
+/* We don't need anything special. */
+int module_frob_arch_sections(Elf_Ehdr *hdr,
+ Elf_Shdr *sechdrs,
+ char *secstrings,
+ struct module *mod)
+{
+ return 0;
+}
+
+int apply_relocate(Elf_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ printk(KERN_ERR "module %s: .rel relocation unsupported\n", me->name);
+ return -ENOEXEC;
+}
+
+#ifdef __tilegx__
+/*
+ * Validate that the high 16 bits of "value" is just the sign-extension of
+ * the low 48 bits.
+ */
+static int validate_hw2_last(long value, struct module *me)
+{
+ if (((value << 16) >> 16) != value) {
+ printk("module %s: Out of range HW2_LAST value %#lx\n",
+ me->name, value);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Validate that "value" isn't too big to hold in a JumpOff relocation.
+ */
+static int validate_jumpoff(long value)
+{
+ /* Determine size of jump offset. */
+ int shift = __builtin_clzl(get_JumpOff_X1(create_JumpOff_X1(-1)));
+
+ /* Check to see if it fits into the relocation slot. */
+ long f = get_JumpOff_X1(create_JumpOff_X1(value));
+ f = (f << shift) >> shift;
+
+ return f == value;
+}
+#endif
+
+int apply_relocate_add(Elf_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ unsigned int i;
+ Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf_Sym *sym;
+ u64 *location;
+ unsigned long value;
+
+ DEBUGP("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rel[i].r_offset;
+ /*
+ * This is the symbol it is referring to.
+ * Note that all undefined symbols have been resolved.
+ */
+ sym = (Elf_Sym *)sechdrs[symindex].sh_addr
+ + ELF_R_SYM(rel[i].r_info);
+ value = sym->st_value + rel[i].r_addend;
+
+ switch (ELF_R_TYPE(rel[i].r_info)) {
+
+#define MUNGE(func) (*location = ((*location & ~func(-1)) | func(value)))
+
+#ifndef __tilegx__
+ case R_TILE_32:
+ *(uint32_t *)location = value;
+ break;
+ case R_TILE_IMM16_X0_HA:
+ value = (value + 0x8000) >> 16;
+ /*FALLTHROUGH*/
+ case R_TILE_IMM16_X0_LO:
+ MUNGE(create_Imm16_X0);
+ break;
+ case R_TILE_IMM16_X1_HA:
+ value = (value + 0x8000) >> 16;
+ /*FALLTHROUGH*/
+ case R_TILE_IMM16_X1_LO:
+ MUNGE(create_Imm16_X1);
+ break;
+ case R_TILE_JOFFLONG_X1:
+ value -= (unsigned long) location; /* pc-relative */
+ value = (long) value >> 3; /* count by instrs */
+ MUNGE(create_JOffLong_X1);
+ break;
+#else
+ case R_TILEGX_64:
+ *location = value;
+ break;
+ case R_TILEGX_IMM16_X0_HW2_LAST:
+ if (!validate_hw2_last(value, me))
+ return -ENOEXEC;
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X0_HW1:
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X0_HW0:
+ MUNGE(create_Imm16_X0);
+ break;
+ case R_TILEGX_IMM16_X1_HW2_LAST:
+ if (!validate_hw2_last(value, me))
+ return -ENOEXEC;
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X1_HW1:
+ value >>= 16;
+ /*FALLTHROUGH*/
+ case R_TILEGX_IMM16_X1_HW0:
+ MUNGE(create_Imm16_X1);
+ break;
+ case R_TILEGX_JUMPOFF_X1:
+ value -= (unsigned long) location; /* pc-relative */
+ value = (long) value >> 3; /* count by instrs */
+ if (!validate_jumpoff(value)) {
+ printk("module %s: Out of range jump to"
+ " %#llx at %#llx (%p)\n", me->name,
+ sym->st_value + rel[i].r_addend,
+ rel[i].r_offset, location);
+ return -ENOEXEC;
+ }
+ MUNGE(create_JumpOff_X1);
+ break;
+#endif
+
+#undef MUNGE
+
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %d\n",
+ me->name, (int) ELF_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ /* FIXME: perhaps remove the "writable" bit from the TLB? */
+ return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c
new file mode 100644
index 000000000000..5ad5e13b0fa6
--- /dev/null
+++ b/arch/tile/kernel/pci-dma.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/vmalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/homecache.h>
+
+/* Generic DMA mapping functions: */
+
+/*
+ * Allocate what Linux calls "coherent" memory, which for us just
+ * means uncached.
+ */
+void *dma_alloc_coherent(struct device *dev,
+ size_t size,
+ dma_addr_t *dma_handle,
+ gfp_t gfp)
+{
+ u64 dma_mask = dev->coherent_dma_mask ?: DMA_BIT_MASK(32);
+ int node = dev_to_node(dev);
+ int order = get_order(size);
+ struct page *pg;
+ dma_addr_t addr;
+
+ gfp |= __GFP_ZERO;
+
+ /*
+ * By forcing NUMA node 0 for 32-bit masks we ensure that the
+ * high 32 bits of the resulting PA will be zero. If the mask
+ * size is, e.g., 24, we may still not be able to guarantee a
+ * suitable memory address, in which case we will return NULL.
+ * But such devices are uncommon.
+ */
+ if (dma_mask <= DMA_BIT_MASK(32))
+ node = 0;
+
+ pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_UNCACHED);
+ if (pg == NULL)
+ return NULL;
+
+ addr = page_to_phys(pg);
+ if (addr + size > dma_mask) {
+ homecache_free_pages(addr, order);
+ return NULL;
+ }
+
+ *dma_handle = addr;
+ return page_address(pg);
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+/*
+ * Free memory that was allocated with dma_alloc_coherent.
+ */
+void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ homecache_free_pages((unsigned long)vaddr, get_order(size));
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+/*
+ * The map routines "map" the specified address range for DMA
+ * accesses. The memory belongs to the device after this call is
+ * issued, until it is unmapped with dma_unmap_single.
+ *
+ * We don't need to do any mapping, we just flush the address range
+ * out of the cache and return a DMA address.
+ *
+ * The unmap routines do whatever is necessary before the processor
+ * accesses the memory again, and must be called before the driver
+ * touches the memory. We can get away with a cache invalidate if we
+ * can count on nothing having been touched.
+ */
+
+
+/*
+ * dma_map_single can be passed any memory address, and there appear
+ * to be no alignment constraints.
+ *
+ * There is a chance that the start of the buffer will share a cache
+ * line with some other data that has been touched in the meantime.
+ */
+dma_addr_t dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction)
+{
+ struct page *page;
+ dma_addr_t dma_addr;
+ int thispage;
+
+ BUG_ON(!valid_dma_direction(direction));
+ WARN_ON(size == 0);
+
+ dma_addr = __pa(ptr);
+
+ /* We might have been handed a buffer that wraps a page boundary */
+ while ((int)size > 0) {
+ /* The amount to flush that's on this page */
+ thispage = PAGE_SIZE - ((unsigned long)ptr & (PAGE_SIZE - 1));
+ thispage = min((int)thispage, (int)size);
+ /* Is this valid for any page we could be handed? */
+ page = pfn_to_page(kaddr_to_pfn(ptr));
+ homecache_flush_cache(page, 0);
+ ptr += thispage;
+ size -= thispage;
+ }
+
+ return dma_addr;
+}
+EXPORT_SYMBOL(dma_map_single);
+
+void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+EXPORT_SYMBOL(dma_unmap_single);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
+ enum dma_data_direction direction)
+{
+ struct scatterlist *sg;
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ WARN_ON(nents == 0 || sglist->length == 0);
+
+ for_each_sg(sglist, sg, nents, i) {
+ struct page *page;
+ sg->dma_address = sg_phys(sg);
+ page = pfn_to_page(sg->dma_address >> PAGE_SHIFT);
+ homecache_flush_cache(page, 0);
+ }
+
+ return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ homecache_flush_cache(page, 0);
+
+ return page_to_pa(page) + offset;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ unsigned long start = PFN_DOWN(dma_handle);
+ unsigned long end = PFN_DOWN(dma_handle + size - 1);
+ unsigned long i;
+
+ BUG_ON(!valid_dma_direction(direction));
+ for (i = start; i <= end; ++i)
+ homecache_flush_cache(pfn_to_page(i), 0);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ WARN_ON(nelems == 0 || sg[0].length == 0);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+/*
+ * Flush and invalidate cache for scatterlist.
+ */
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
+{
+ struct scatterlist *sg;
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+ WARN_ON(nelems == 0 || sglist->length == 0);
+
+ for_each_sg(sglist, sg, nelems, i) {
+ dma_sync_single_for_device(dev, sg->dma_address,
+ sg_dma_len(sg), direction);
+ }
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_cpu(dev, dma_handle + offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ dma_sync_single_for_device(dev, dma_handle + offset, size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+/*
+ * dma_alloc_noncoherent() returns non-cacheable memory, so there's no
+ * need to do any flushing here.
+ */
+void dma_cache_sync(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+}
+EXPORT_SYMBOL(dma_cache_sync);
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c
new file mode 100644
index 000000000000..92ef925d2f8d
--- /dev/null
+++ b/arch/tile/kernel/proc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/smp.h>
+#include <linux/seq_file.h>
+#include <linux/threads.h>
+#include <linux/cpumask.h>
+#include <linux/timex.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#include <linux/hardirq.h>
+#include <linux/mman.h>
+#include <linux/smp.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/homecache.h>
+#include <arch/chip.h>
+
+
+/*
+ * Support /proc/cpuinfo
+ */
+
+#define cpu_to_ptr(n) ((void *)((long)(n)+1))
+#define ptr_to_cpu(p) ((long)(p) - 1)
+
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ int n = ptr_to_cpu(v);
+
+ if (n == 0) {
+ char buf[NR_CPUS*5];
+ cpulist_scnprintf(buf, sizeof(buf), cpu_online_mask);
+ seq_printf(m, "cpu count\t: %d\n", num_online_cpus());
+ seq_printf(m, "cpu list\t: %s\n", buf);
+ seq_printf(m, "model name\t: %s\n", chip_model);
+ seq_printf(m, "flags\t\t:\n"); /* nothing for now */
+ seq_printf(m, "cpu MHz\t\t: %llu.%06llu\n",
+ get_clock_rate() / 1000000,
+ (get_clock_rate() % 1000000));
+ seq_printf(m, "bogomips\t: %lu.%02lu\n\n",
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+ }
+
+#ifdef CONFIG_SMP
+ if (!cpu_online(n))
+ return 0;
+#endif
+
+ seq_printf(m, "processor\t: %d\n", n);
+
+ /* Print only num_online_cpus() blank lines total. */
+ if (cpumask_next(n, cpu_online_mask) < nr_cpu_ids)
+ seq_printf(m, "\n");
+
+ return 0;
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL;
+}
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+static void c_stop(struct seq_file *m, void *v)
+{
+}
+const struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
+};
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
new file mode 100644
index 000000000000..c70ff14a48e4
--- /dev/null
+++ b/arch/tile/kernel/process.c
@@ -0,0 +1,647 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/preempt.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kprobes.h>
+#include <linux/elfcore.h>
+#include <linux/tick.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/compat.h>
+#include <linux/hardirq.h>
+#include <linux/syscalls.h>
+#include <asm/system.h>
+#include <asm/stack.h>
+#include <asm/homecache.h>
+#include <arch/chip.h>
+#include <arch/abi.h>
+
+
+/*
+ * Use the (x86) "idle=poll" option to prefer low latency when leaving the
+ * idle loop over low power while in the idle loop, e.g. if we have
+ * one thread per core and we want to get threads out of futex waits fast.
+ */
+static int no_idle_nap;
+static int __init idle_setup(char *str)
+{
+ if (!str)
+ return -EINVAL;
+
+ if (!strcmp(str, "poll")) {
+ printk("using polling idle threads.\n");
+ no_idle_nap = 1;
+ } else if (!strcmp(str, "halt"))
+ no_idle_nap = 0;
+ else
+ return -1;
+
+ return 0;
+}
+early_param("idle", idle_setup);
+
+/*
+ * The idle thread. There's no useful work to be
+ * done, so just try to conserve power and have a
+ * low exit latency (ie sit in a loop waiting for
+ * somebody to say that they'd like to reschedule)
+ */
+void cpu_idle(void)
+{
+ extern void _cpu_idle(void);
+ int cpu = smp_processor_id();
+
+
+ current_thread_info()->status |= TS_POLLING;
+
+ if (no_idle_nap) {
+ while (1) {
+ while (!need_resched())
+ cpu_relax();
+ schedule();
+ }
+ }
+
+ /* endless idle loop with no priority at all */
+ while (1) {
+ tick_nohz_stop_sched_tick(1);
+ while (!need_resched()) {
+ if (cpu_is_offline(cpu))
+ BUG(); /* no HOTPLUG_CPU */
+
+ local_irq_disable();
+ __get_cpu_var(irq_stat).idle_timestamp = jiffies;
+ current_thread_info()->status &= ~TS_POLLING;
+ /*
+ * TS_POLLING-cleared state must be visible before we
+ * test NEED_RESCHED:
+ */
+ smp_mb();
+
+ if (!need_resched())
+ _cpu_idle();
+ else
+ local_irq_enable();
+ current_thread_info()->status |= TS_POLLING;
+ }
+ tick_nohz_restart_sched_tick();
+ preempt_enable_no_resched();
+ schedule();
+ preempt_disable();
+ }
+}
+
+struct thread_info *alloc_thread_info(struct task_struct *task)
+{
+ struct page *page;
+ int flags = GFP_KERNEL;
+
+#ifdef CONFIG_DEBUG_STACK_USAGE
+ flags |= __GFP_ZERO;
+#endif
+
+ page = alloc_pages(flags, THREAD_SIZE_ORDER);
+ if (!page)
+ return 0;
+
+ return (struct thread_info *)page_address(page);
+}
+
+/*
+ * Free a thread_info node, and all of its derivative
+ * data structures.
+ */
+void free_thread_info(struct thread_info *info)
+{
+ struct single_step_state *step_state = info->step_state;
+
+
+ if (step_state) {
+
+ /*
+ * FIXME: we don't munmap step_state->buffer
+ * because the mm_struct for this process (info->task->mm)
+ * has already been zeroed in exit_mm(). Keeping a
+ * reference to it here seems like a bad move, so this
+ * means we can't munmap() the buffer, and therefore if we
+ * ptrace multiple threads in a process, we will slowly
+ * leak user memory. (Note that as soon as the last
+ * thread in a process dies, we will reclaim all user
+ * memory including single-step buffers in the usual way.)
+ * We should either assign a kernel VA to this buffer
+ * somehow, or we should associate the buffer(s) with the
+ * mm itself so we can clean them up that way.
+ */
+ kfree(step_state);
+ }
+
+ free_page((unsigned long)info);
+}
+
+static void save_arch_state(struct thread_struct *t);
+
+extern void ret_from_fork(void);
+
+int copy_thread(unsigned long clone_flags, unsigned long sp,
+ unsigned long stack_size,
+ struct task_struct *p, struct pt_regs *regs)
+{
+ struct pt_regs *childregs;
+ unsigned long ksp;
+
+ /*
+ * When creating a new kernel thread we pass sp as zero.
+ * Assign it to a reasonable value now that we have the stack.
+ */
+ if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0))
+ sp = KSTK_TOP(p);
+
+ /*
+ * Do not clone step state from the parent; each thread
+ * must make its own lazily.
+ */
+ task_thread_info(p)->step_state = NULL;
+
+ /*
+ * Start new thread in ret_from_fork so it schedules properly
+ * and then return from interrupt like the parent.
+ */
+ p->thread.pc = (unsigned long) ret_from_fork;
+
+ /* Save user stack top pointer so we can ID the stack vm area later. */
+ p->thread.usp0 = sp;
+
+ /* Record the pid of the process that created this one. */
+ p->thread.creator_pid = current->pid;
+
+ /*
+ * Copy the registers onto the kernel stack so the
+ * return-from-interrupt code will reload it into registers.
+ */
+ childregs = task_pt_regs(p);
+ *childregs = *regs;
+ childregs->regs[0] = 0; /* return value is zero */
+ childregs->sp = sp; /* override with new user stack pointer */
+
+ /*
+ * Copy the callee-saved registers from the passed pt_regs struct
+ * into the context-switch callee-saved registers area.
+ * We have to restore the callee-saved registers since we may
+ * be cloning a userspace task with userspace register state,
+ * and we won't be unwinding the same kernel frames to restore them.
+ * Zero out the C ABI save area to mark the top of the stack.
+ */
+ ksp = (unsigned long) childregs;
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
+ memcpy((void *)ksp, &regs->regs[CALLEE_SAVED_FIRST_REG],
+ CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ p->thread.ksp = ksp;
+
+#if CHIP_HAS_TILE_DMA()
+ /*
+ * No DMA in the new thread. We model this on the fact that
+ * fork() clears the pending signals, alarms, and aio for the child.
+ */
+ memset(&p->thread.tile_dma_state, 0, sizeof(struct tile_dma_state));
+ memset(&p->thread.dma_async_tlb, 0, sizeof(struct async_tlb));
+#endif
+
+#if CHIP_HAS_SN_PROC()
+ /* Likewise, the new thread is not running static processor code. */
+ p->thread.sn_proc_running = 0;
+ memset(&p->thread.sn_async_tlb, 0, sizeof(struct async_tlb));
+#endif
+
+#if CHIP_HAS_PROC_STATUS_SPR()
+ /* New thread has its miscellaneous processor state bits clear. */
+ p->thread.proc_status = 0;
+#endif
+
+
+
+ /*
+ * Start the new thread with the current architecture state
+ * (user interrupt masks, etc.).
+ */
+ save_arch_state(&p->thread);
+
+ return 0;
+}
+
+/*
+ * Return "current" if it looks plausible, or else a pointer to a dummy.
+ * This can be helpful if we are just trying to emit a clean panic.
+ */
+struct task_struct *validate_current(void)
+{
+ static struct task_struct corrupt = { .comm = "<corrupt>" };
+ struct task_struct *tsk = current;
+ if (unlikely((unsigned long)tsk < PAGE_OFFSET ||
+ (void *)tsk > high_memory ||
+ ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) {
+ printk("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer);
+ tsk = &corrupt;
+ }
+ return tsk;
+}
+
+/* Take and return the pointer to the previous task, for schedule_tail(). */
+struct task_struct *sim_notify_fork(struct task_struct *prev)
+{
+ struct task_struct *tsk = current;
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK_PARENT |
+ (tsk->thread.creator_pid << _SIM_CONTROL_OPERATOR_BITS));
+ __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK |
+ (tsk->pid << _SIM_CONTROL_OPERATOR_BITS));
+ return prev;
+}
+
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+ struct pt_regs *ptregs = task_pt_regs(tsk);
+ elf_core_copy_regs(regs, ptregs);
+ return 1;
+}
+
+#if CHIP_HAS_TILE_DMA()
+
+/* Allow user processes to access the DMA SPRs */
+void grant_dma_mpls(void)
+{
+ __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1);
+ __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1);
+}
+
+/* Forbid user processes from accessing the DMA SPRs */
+void restrict_dma_mpls(void)
+{
+ __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1);
+ __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1);
+}
+
+/* Pause the DMA engine, then save off its state registers. */
+static void save_tile_dma_state(struct tile_dma_state *dma)
+{
+ unsigned long state = __insn_mfspr(SPR_DMA_USER_STATUS);
+ unsigned long post_suspend_state;
+
+ /* If we're running, suspend the engine. */
+ if ((state & DMA_STATUS_MASK) == SPR_DMA_STATUS__RUNNING_MASK)
+ __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK);
+
+ /*
+ * Wait for the engine to idle, then save regs. Note that we
+ * want to record the "running" bit from before suspension,
+ * and the "done" bit from after, so that we can properly
+ * distinguish a case where the user suspended the engine from
+ * the case where the kernel suspended as part of the context
+ * swap.
+ */
+ do {
+ post_suspend_state = __insn_mfspr(SPR_DMA_USER_STATUS);
+ } while (post_suspend_state & SPR_DMA_STATUS__BUSY_MASK);
+
+ dma->src = __insn_mfspr(SPR_DMA_SRC_ADDR);
+ dma->src_chunk = __insn_mfspr(SPR_DMA_SRC_CHUNK_ADDR);
+ dma->dest = __insn_mfspr(SPR_DMA_DST_ADDR);
+ dma->dest_chunk = __insn_mfspr(SPR_DMA_DST_CHUNK_ADDR);
+ dma->strides = __insn_mfspr(SPR_DMA_STRIDE);
+ dma->chunk_size = __insn_mfspr(SPR_DMA_CHUNK_SIZE);
+ dma->byte = __insn_mfspr(SPR_DMA_BYTE);
+ dma->status = (state & SPR_DMA_STATUS__RUNNING_MASK) |
+ (post_suspend_state & SPR_DMA_STATUS__DONE_MASK);
+}
+
+/* Restart a DMA that was running before we were context-switched out. */
+static void restore_tile_dma_state(struct thread_struct *t)
+{
+ const struct tile_dma_state *dma = &t->tile_dma_state;
+
+ /*
+ * The only way to restore the done bit is to run a zero
+ * length transaction.
+ */
+ if ((dma->status & SPR_DMA_STATUS__DONE_MASK) &&
+ !(__insn_mfspr(SPR_DMA_USER_STATUS) & SPR_DMA_STATUS__DONE_MASK)) {
+ __insn_mtspr(SPR_DMA_BYTE, 0);
+ __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK);
+ while (__insn_mfspr(SPR_DMA_USER_STATUS) &
+ SPR_DMA_STATUS__BUSY_MASK)
+ ;
+ }
+
+ __insn_mtspr(SPR_DMA_SRC_ADDR, dma->src);
+ __insn_mtspr(SPR_DMA_SRC_CHUNK_ADDR, dma->src_chunk);
+ __insn_mtspr(SPR_DMA_DST_ADDR, dma->dest);
+ __insn_mtspr(SPR_DMA_DST_CHUNK_ADDR, dma->dest_chunk);
+ __insn_mtspr(SPR_DMA_STRIDE, dma->strides);
+ __insn_mtspr(SPR_DMA_CHUNK_SIZE, dma->chunk_size);
+ __insn_mtspr(SPR_DMA_BYTE, dma->byte);
+
+ /*
+ * Restart the engine if we were running and not done.
+ * Clear a pending async DMA fault that we were waiting on return
+ * to user space to execute, since we expect the DMA engine
+ * to regenerate those faults for us now. Note that we don't
+ * try to clear the TIF_ASYNC_TLB flag, since it's relatively
+ * harmless if set, and it covers both DMA and the SN processor.
+ */
+ if ((dma->status & DMA_STATUS_MASK) == SPR_DMA_STATUS__RUNNING_MASK) {
+ t->dma_async_tlb.fault_num = 0;
+ __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK);
+ }
+}
+
+#endif
+
+static void save_arch_state(struct thread_struct *t)
+{
+#if CHIP_HAS_SPLIT_INTR_MASK()
+ t->interrupt_mask = __insn_mfspr(SPR_INTERRUPT_MASK_0_0) |
+ ((u64)__insn_mfspr(SPR_INTERRUPT_MASK_0_1) << 32);
+#else
+ t->interrupt_mask = __insn_mfspr(SPR_INTERRUPT_MASK_0);
+#endif
+ t->ex_context[0] = __insn_mfspr(SPR_EX_CONTEXT_0_0);
+ t->ex_context[1] = __insn_mfspr(SPR_EX_CONTEXT_0_1);
+ t->system_save[0] = __insn_mfspr(SPR_SYSTEM_SAVE_0_0);
+ t->system_save[1] = __insn_mfspr(SPR_SYSTEM_SAVE_0_1);
+ t->system_save[2] = __insn_mfspr(SPR_SYSTEM_SAVE_0_2);
+ t->system_save[3] = __insn_mfspr(SPR_SYSTEM_SAVE_0_3);
+ t->intctrl_0 = __insn_mfspr(SPR_INTCTRL_0_STATUS);
+#if CHIP_HAS_PROC_STATUS_SPR()
+ t->proc_status = __insn_mfspr(SPR_PROC_STATUS);
+#endif
+}
+
+static void restore_arch_state(const struct thread_struct *t)
+{
+#if CHIP_HAS_SPLIT_INTR_MASK()
+ __insn_mtspr(SPR_INTERRUPT_MASK_0_0, (u32) t->interrupt_mask);
+ __insn_mtspr(SPR_INTERRUPT_MASK_0_1, t->interrupt_mask >> 32);
+#else
+ __insn_mtspr(SPR_INTERRUPT_MASK_0, t->interrupt_mask);
+#endif
+ __insn_mtspr(SPR_EX_CONTEXT_0_0, t->ex_context[0]);
+ __insn_mtspr(SPR_EX_CONTEXT_0_1, t->ex_context[1]);
+ __insn_mtspr(SPR_SYSTEM_SAVE_0_0, t->system_save[0]);
+ __insn_mtspr(SPR_SYSTEM_SAVE_0_1, t->system_save[1]);
+ __insn_mtspr(SPR_SYSTEM_SAVE_0_2, t->system_save[2]);
+ __insn_mtspr(SPR_SYSTEM_SAVE_0_3, t->system_save[3]);
+ __insn_mtspr(SPR_INTCTRL_0_STATUS, t->intctrl_0);
+#if CHIP_HAS_PROC_STATUS_SPR()
+ __insn_mtspr(SPR_PROC_STATUS, t->proc_status);
+#endif
+#if CHIP_HAS_TILE_RTF_HWM()
+ /*
+ * Clear this whenever we switch back to a process in case
+ * the previous process was monkeying with it. Even if enabled
+ * in CBOX_MSR1 via TILE_RTF_HWM_MIN, it's still just a
+ * performance hint, so isn't worth a full save/restore.
+ */
+ __insn_mtspr(SPR_TILE_RTF_HWM, 0);
+#endif
+}
+
+
+void _prepare_arch_switch(struct task_struct *next)
+{
+#if CHIP_HAS_SN_PROC()
+ int snctl;
+#endif
+#if CHIP_HAS_TILE_DMA()
+ struct tile_dma_state *dma = &current->thread.tile_dma_state;
+ if (dma->enabled)
+ save_tile_dma_state(dma);
+#endif
+#if CHIP_HAS_SN_PROC()
+ /*
+ * Suspend the static network processor if it was running.
+ * We do not suspend the fabric itself, just like we don't
+ * try to suspend the UDN.
+ */
+ snctl = __insn_mfspr(SPR_SNCTL);
+ current->thread.sn_proc_running =
+ (snctl & SPR_SNCTL__FRZPROC_MASK) == 0;
+ if (current->thread.sn_proc_running)
+ __insn_mtspr(SPR_SNCTL, snctl | SPR_SNCTL__FRZPROC_MASK);
+#endif
+}
+
+
+extern struct task_struct *__switch_to(struct task_struct *prev,
+ struct task_struct *next,
+ unsigned long new_system_save_1_0);
+
+struct task_struct *__sched _switch_to(struct task_struct *prev,
+ struct task_struct *next)
+{
+ /* DMA state is already saved; save off other arch state. */
+ save_arch_state(&prev->thread);
+
+#if CHIP_HAS_TILE_DMA()
+ /*
+ * Restore DMA in new task if desired.
+ * Note that it is only safe to restart here since interrupts
+ * are disabled, so we can't take any DMATLB miss or access
+ * interrupts before we have finished switching stacks.
+ */
+ if (next->thread.tile_dma_state.enabled) {
+ restore_tile_dma_state(&next->thread);
+ grant_dma_mpls();
+ } else {
+ restrict_dma_mpls();
+ }
+#endif
+
+ /* Restore other arch state. */
+ restore_arch_state(&next->thread);
+
+#if CHIP_HAS_SN_PROC()
+ /*
+ * Restart static network processor in the new process
+ * if it was running before.
+ */
+ if (next->thread.sn_proc_running) {
+ int snctl = __insn_mfspr(SPR_SNCTL);
+ __insn_mtspr(SPR_SNCTL, snctl & ~SPR_SNCTL__FRZPROC_MASK);
+ }
+#endif
+
+
+ /*
+ * Switch kernel SP, PC, and callee-saved registers.
+ * In the context of the new task, return the old task pointer
+ * (i.e. the task that actually called __switch_to).
+ * Pass the value to use for SYSTEM_SAVE_1_0 when we reset our sp.
+ */
+ return __switch_to(prev, next, next_current_ksp0(next));
+}
+
+int _sys_fork(struct pt_regs *regs)
+{
+ return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
+}
+
+int _sys_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tidptr, void __user *child_tidptr,
+ struct pt_regs *regs)
+{
+ if (!newsp)
+ newsp = regs->sp;
+ return do_fork(clone_flags, newsp, regs, 0,
+ parent_tidptr, child_tidptr);
+}
+
+int _sys_vfork(struct pt_regs *regs)
+{
+ return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp,
+ regs, 0, NULL, NULL);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+int _sys_execve(char __user *path, char __user *__user *argv,
+ char __user *__user *envp, struct pt_regs *regs)
+{
+ int error;
+ char *filename;
+
+ filename = getname(path);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, argv, envp, regs);
+ putname(filename);
+out:
+ return error;
+}
+
+#ifdef CONFIG_COMPAT
+int _compat_sys_execve(char __user *path, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs *regs)
+{
+ int error;
+ char *filename;
+
+ filename = getname(path);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = compat_do_execve(filename, argv, envp, regs);
+ putname(filename);
+out:
+ return error;
+}
+#endif
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ struct KBacktraceIterator kbt;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ for (KBacktraceIterator_init(&kbt, p, NULL);
+ !KBacktraceIterator_end(&kbt);
+ KBacktraceIterator_next(&kbt)) {
+ if (!in_sched_functions(kbt.it.pc))
+ return kbt.it.pc;
+ }
+
+ return 0;
+}
+
+/*
+ * We pass in lr as zero (cleared in kernel_thread) and the caller
+ * part of the backtrace ABI on the stack also zeroed (in copy_thread)
+ * so that backtraces will stop with this function.
+ * Note that we don't use r0, since copy_thread() clears it.
+ */
+static void start_kernel_thread(int dummy, int (*fn)(int), int arg)
+{
+ do_exit(fn(arg));
+}
+
+/*
+ * Create a kernel thread
+ */
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(regs));
+ regs.ex1 = PL_ICS_EX1(KERNEL_PL, 0); /* run at kernel PL, no ICS */
+ regs.pc = (long) start_kernel_thread;
+ regs.flags = PT_FLAGS_CALLER_SAVES; /* need to restore r1 and r2 */
+ regs.regs[1] = (long) fn; /* function pointer */
+ regs.regs[2] = (long) arg; /* parameter register */
+
+ /* Ok, create the new process.. */
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs,
+ 0, NULL, NULL);
+}
+EXPORT_SYMBOL(kernel_thread);
+
+/* Flush thread state. */
+void flush_thread(void)
+{
+ /* Nothing */
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+void exit_thread(void)
+{
+ /* Nothing */
+}
+
+#ifdef __tilegx__
+# define LINECOUNT 3
+# define EXTRA_NL "\n"
+#else
+# define LINECOUNT 4
+# define EXTRA_NL ""
+#endif
+
+void show_regs(struct pt_regs *regs)
+{
+ struct task_struct *tsk = validate_current();
+ int i, linebreak;
+ printk("\n");
+ printk(" Pid: %d, comm: %20s, CPU: %d\n",
+ tsk->pid, tsk->comm, smp_processor_id());
+ for (i = linebreak = 0; i < 53; ++i) {
+ printk(" r%-2d: "REGFMT, i, regs->regs[i]);
+ if (++linebreak == LINECOUNT) {
+ linebreak = 0;
+ printk("\n");
+ }
+ }
+ printk(" tp : "REGFMT EXTRA_NL " sp : "REGFMT" lr : "REGFMT"\n",
+ regs->tp, regs->sp, regs->lr);
+ printk(" pc : "REGFMT" ex1: %ld faultnum: %ld\n",
+ regs->pc, regs->ex1, regs->faultnum);
+
+ dump_stack_regs(regs);
+}
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c
new file mode 100644
index 000000000000..468054928e7d
--- /dev/null
+++ b/arch/tile/kernel/ptrace.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Copied from i386: Ross Biro 1/23/92
+ */
+
+#include <linux/kernel.h>
+#include <linux/ptrace.h>
+#include <linux/kprobes.h>
+#include <linux/compat.h>
+#include <linux/uaccess.h>
+
+void user_enable_single_step(struct task_struct *child)
+{
+ set_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+void user_disable_single_step(struct task_struct *child)
+{
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+}
+
+/*
+ * This routine will put a word on the process's privileged stack.
+ */
+static void putreg(struct task_struct *task,
+ unsigned long addr, unsigned long value)
+{
+ unsigned int regno = addr / sizeof(unsigned long);
+ struct pt_regs *childregs = task_pt_regs(task);
+ childregs->regs[regno] = value;
+ childregs->flags |= PT_FLAGS_RESTORE_REGS;
+}
+
+static unsigned long getreg(struct task_struct *task, unsigned long addr)
+{
+ unsigned int regno = addr / sizeof(unsigned long);
+ struct pt_regs *childregs = task_pt_regs(task);
+ return childregs->regs[regno];
+}
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ */
+void ptrace_disable(struct task_struct *child)
+{
+ clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+ /*
+ * These two are currently unused, but will be set by arch_ptrace()
+ * and used in the syscall assembly when we do support them.
+ */
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+}
+
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
+{
+ unsigned long __user *datap;
+ unsigned long tmp;
+ int i;
+ long ret = -EIO;
+
+#ifdef CONFIG_COMPAT
+ if (task_thread_info(current)->status & TS_COMPAT)
+ data = (u32)data;
+ if (task_thread_info(child)->status & TS_COMPAT)
+ addr = (u32)addr;
+#endif
+ datap = (unsigned long __user *)data;
+
+ switch (request) {
+
+ case PTRACE_PEEKUSR: /* Read register from pt_regs. */
+ if (addr & (sizeof(data)-1))
+ break;
+ if (addr < 0 || addr >= PTREGS_SIZE)
+ break;
+ tmp = getreg(child, addr); /* Read register */
+ ret = put_user(tmp, datap);
+ break;
+
+ case PTRACE_POKEUSR: /* Write register in pt_regs. */
+ if (addr & (sizeof(data)-1))
+ break;
+ if (addr < 0 || addr >= PTREGS_SIZE)
+ break;
+ putreg(child, addr, data); /* Write register */
+ break;
+
+ case PTRACE_GETREGS: /* Get all registers from the child. */
+ if (!access_ok(VERIFY_WRITE, datap, PTREGS_SIZE))
+ break;
+ for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
+ ret = __put_user(getreg(child, i), datap);
+ if (ret != 0)
+ break;
+ datap++;
+ }
+ break;
+
+ case PTRACE_SETREGS: /* Set all registers in the child. */
+ if (!access_ok(VERIFY_READ, datap, PTREGS_SIZE))
+ break;
+ for (i = 0; i < PTREGS_SIZE; i += sizeof(long)) {
+ ret = __get_user(tmp, datap);
+ if (ret != 0)
+ break;
+ putreg(child, i, tmp);
+ datap++;
+ }
+ break;
+
+ case PTRACE_GETFPREGS: /* Get the child FPU state. */
+ case PTRACE_SETFPREGS: /* Set the child FPU state. */
+ break;
+
+ case PTRACE_SETOPTIONS:
+ /* Support TILE-specific ptrace options. */
+ child->ptrace &= ~PT_TRACE_MASK_TILE;
+ tmp = data & PTRACE_O_MASK_TILE;
+ data &= ~PTRACE_O_MASK_TILE;
+ ret = ptrace_request(child, request, addr, data);
+ if (tmp & PTRACE_O_TRACEMIGRATE)
+ child->ptrace |= PT_TRACE_MIGRATE;
+ break;
+
+ default:
+#ifdef CONFIG_COMPAT
+ if (task_thread_info(current)->status & TS_COMPAT) {
+ ret = compat_ptrace_request(child, request,
+ addr, data);
+ break;
+ }
+#endif
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+/* Not used; we handle compat issues in arch_ptrace() directly. */
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t addr, compat_ulong_t data)
+{
+ BUG();
+}
+#endif
+
+void do_syscall_trace(void)
+{
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ return;
+
+ if (!(current->ptrace & PT_PTRACED))
+ return;
+
+ /*
+ * The 0x80 provides a way for the tracing parent to distinguish
+ * between a syscall stop and SIGTRAP delivery
+ */
+ ptrace_notify(SIGTRAP|((current->ptrace & PT_TRACESYSGOOD) ? 0x80 : 0));
+
+ /*
+ * this isn't the same as continuing with a signal, but it will do
+ * for normal use. strace only continues with a signal if the
+ * stopping signal is not SIGTRAP. -brl
+ */
+ if (current->exit_code) {
+ send_sig(current->exit_code, current, 1);
+ current->exit_code = 0;
+ }
+}
+
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code)
+{
+ struct siginfo info;
+
+ memset(&info, 0, sizeof(info));
+ info.si_signo = SIGTRAP;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void __user *) regs->pc;
+
+ /* Send us the fakey SIGTRAP */
+ force_sig_info(SIGTRAP, &info, tsk);
+}
+
+/* Handle synthetic interrupt delivered only by the simulator. */
+void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num)
+{
+ send_sigtrap(current, regs, fault_num);
+}
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c
new file mode 100644
index 000000000000..a4523923605e
--- /dev/null
+++ b/arch/tile/kernel/reboot.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/stddef.h>
+#include <linux/reboot.h>
+#include <linux/smp.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <hv/hypervisor.h>
+
+#ifndef CONFIG_SMP
+#define smp_send_stop()
+#endif
+
+void machine_halt(void)
+{
+ warn_early_printk();
+ raw_local_irq_disable_all();
+ smp_send_stop();
+ hv_halt();
+}
+
+void machine_power_off(void)
+{
+ warn_early_printk();
+ raw_local_irq_disable_all();
+ smp_send_stop();
+ hv_power_off();
+}
+
+void machine_restart(char *cmd)
+{
+ raw_local_irq_disable_all();
+ smp_send_stop();
+ hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd);
+}
+
+/*
+ * Power off function, if any
+ */
+void (*pm_power_off)(void) = machine_power_off;
diff --git a/arch/tile/kernel/regs_32.S b/arch/tile/kernel/regs_32.S
new file mode 100644
index 000000000000..e88d6e122783
--- /dev/null
+++ b/arch/tile/kernel/regs_32.S
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/asm-offsets.h>
+#include <arch/spr_def.h>
+#include <asm/processor.h>
+
+/*
+ * See <asm/system.h>; called with prev and next task_struct pointers.
+ * "prev" is returned in r0 for _switch_to and also for ret_from_fork.
+ *
+ * We want to save pc/sp in "prev", and get the new pc/sp from "next".
+ * We also need to save all the callee-saved registers on the stack.
+ *
+ * Intel enables/disables access to the hardware cycle counter in
+ * seccomp (secure computing) environments if necessary, based on
+ * has_secure_computing(). We might want to do this at some point,
+ * though it would require virtualizing the other SPRs under WORLD_ACCESS.
+ *
+ * Since we're saving to the stack, we omit sp from this list.
+ * And for parallels with other architectures, we save lr separately,
+ * in the thread_struct itself (as the "pc" field).
+ *
+ * This code also needs to be aligned with process.c copy_thread()
+ */
+
+#if CALLEE_SAVED_REGS_COUNT != 24
+# error Mismatch between <asm/system.h> and kernel/entry.S
+#endif
+#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 4)
+
+#define SAVE_REG(r) { sw r12, r; addi r12, r12, 4 }
+#define LOAD_REG(r) { lw r, r12; addi r12, r12, 4 }
+#define FOR_EACH_CALLEE_SAVED_REG(f) \
+ f(r30); f(r31); \
+ f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \
+ f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \
+ f(r48); f(r49); f(r50); f(r51); f(r52);
+
+STD_ENTRY_SECTION(__switch_to, .sched.text)
+ {
+ move r10, sp
+ sw sp, lr
+ addi sp, sp, -FRAME_SIZE
+ }
+ {
+ addi r11, sp, 4
+ addi r12, sp, 8
+ }
+ {
+ sw r11, r10
+ addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET
+ }
+ {
+ lw r13, r4 /* Load new sp to a temp register early. */
+ addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET
+ }
+ FOR_EACH_CALLEE_SAVED_REG(SAVE_REG)
+ {
+ sw r3, sp
+ addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET
+ }
+ {
+ sw r3, lr
+ addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET
+ }
+ {
+ lw lr, r4
+ addi r12, r13, 8
+ }
+ {
+ /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */
+ move sp, r13
+ mtspr SYSTEM_SAVE_1_0, r2
+ }
+ FOR_EACH_CALLEE_SAVED_REG(LOAD_REG)
+.L__switch_to_pc:
+ {
+ addi sp, sp, FRAME_SIZE
+ jrp lr /* r0 is still valid here, so return it */
+ }
+ STD_ENDPROC(__switch_to)
+
+/* Return a suitable address for the backtracer for suspended threads */
+STD_ENTRY_SECTION(get_switch_to_pc, .sched.text)
+ lnk r0
+ {
+ addli r0, r0, .L__switch_to_pc - .
+ jrp lr
+ }
+ STD_ENDPROC(get_switch_to_pc)
+
+STD_ENTRY(get_pt_regs)
+ .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \
+ r8, r9, r10, r11, r12, r13, r14, r15, \
+ r16, r17, r18, r19, r20, r21, r22, r23, \
+ r24, r25, r26, r27, r28, r29, r30, r31, \
+ r32, r33, r34, r35, r36, r37, r38, r39, \
+ r40, r41, r42, r43, r44, r45, r46, r47, \
+ r48, r49, r50, r51, r52, tp, sp
+ {
+ sw r0, \reg
+ addi r0, r0, 4
+ }
+ .endr
+ {
+ sw r0, lr
+ addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR
+ }
+ lnk r1
+ {
+ sw r0, r1
+ addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC
+ }
+ mfspr r1, INTERRUPT_CRITICAL_SECTION
+ shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT
+ ori r1, r1, KERNEL_PL
+ {
+ sw r0, r1
+ addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1
+ }
+ {
+ sw r0, zero /* clear faultnum */
+ addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM
+ }
+ {
+ sw r0, zero /* clear orig_r0 */
+ addli r0, r0, -PTREGS_OFFSET_ORIG_R0 /* restore r0 to base */
+ }
+ jrp lr
+ STD_ENDPROC(get_pt_regs)
diff --git a/arch/tile/kernel/relocate_kernel.S b/arch/tile/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..010b418515f8
--- /dev/null
+++ b/arch/tile/kernel/relocate_kernel.S
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * copy new kernel into place and then call hv_reexec
+ *
+ */
+
+#include <linux/linkage.h>
+#include <arch/chip.h>
+#include <asm/page.h>
+#include <hv/hypervisor.h>
+
+#define ___hvb MEM_SV_INTRPT + HV_GLUE_START_CPA
+
+#define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f))
+
+#define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC)
+#define ___hv_halt ___hv_dispatch(HV_DISPATCH_HALT)
+#define ___hv_reexec ___hv_dispatch(HV_DISPATCH_REEXEC)
+#define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE)
+
+#undef RELOCATE_NEW_KERNEL_VERBOSE
+
+STD_ENTRY(relocate_new_kernel)
+
+ move r30, r0 /* page list */
+ move r31, r1 /* address of page we are on */
+ move r32, r2 /* start address of new kernel */
+
+ shri r1, r1, PAGE_SHIFT
+ addi r1, r1, 1
+ shli sp, r1, PAGE_SHIFT
+ addi sp, sp, -8
+ /* we now have a stack (whether we need one or not) */
+
+ moveli r40, lo16(___hv_console_putc)
+ auli r40, r40, ha16(___hv_console_putc)
+
+#ifdef RELOCATE_NEW_KERNEL_VERBOSE
+ moveli r0, 'r'
+ jalr r40
+
+ moveli r0, '_'
+ jalr r40
+
+ moveli r0, 'n'
+ jalr r40
+
+ moveli r0, '_'
+ jalr r40
+
+ moveli r0, 'k'
+ jalr r40
+
+ moveli r0, '\n'
+ jalr r40
+#endif
+
+ /*
+ * Throughout this code r30 is pointer to the element of page
+ * list we are working on.
+ *
+ * Normally we get to the next element of the page list by
+ * incrementing r30 by four. The exception is if the element
+ * on the page list is an IND_INDIRECTION in which case we use
+ * the element with the low bits masked off as the new value
+ * of r30.
+ *
+ * To get this started, we need the value passed to us (which
+ * will always be an IND_INDIRECTION) in memory somewhere with
+ * r30 pointing at it. To do that, we push the value passed
+ * to us on the stack and make r30 point to it.
+ */
+
+ sw sp, r30
+ move r30, sp
+ addi sp, sp, -8
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ /*
+ * On TILEPro, we need to flush all tiles' caches, since we may
+ * have been doing hash-for-home caching there. Note that we
+ * must do this _after_ we're completely done modifying any memory
+ * other than our output buffer (which we know is locally cached).
+ * We want the caches to be fully clean when we do the reexec,
+ * because the hypervisor is going to do this flush again at that
+ * point, and we don't want that second flush to overwrite any memory.
+ */
+ {
+ move r0, zero /* cache_pa */
+ move r1, zero
+ }
+ {
+ auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
+ movei r3, -1 /* cache_cpumask; -1 means all client tiles */
+ }
+ {
+ move r4, zero /* tlb_va */
+ move r5, zero /* tlb_length */
+ }
+ {
+ move r6, zero /* tlb_pgsize */
+ move r7, zero /* tlb_cpumask */
+ }
+ {
+ move r8, zero /* asids */
+ moveli r20, lo16(___hv_flush_remote)
+ }
+ {
+ move r9, zero /* asidcount */
+ auli r20, r20, ha16(___hv_flush_remote)
+ }
+
+ jalr r20
+#endif
+
+ /* r33 is destination pointer, default to zero */
+
+ moveli r33, 0
+
+.Lloop: lw r10, r30
+
+ andi r9, r10, 0xf /* low 4 bits tell us what type it is */
+ xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */
+
+ seqi r0, r9, 0x1 /* IND_DESTINATION */
+ bzt r0, .Ltry2
+
+ move r33, r10
+
+#ifdef RELOCATE_NEW_KERNEL_VERBOSE
+ moveli r0, 'd'
+ jalr r40
+#endif
+
+ addi r30, r30, 4
+ j .Lloop
+
+.Ltry2:
+ seqi r0, r9, 0x2 /* IND_INDIRECTION */
+ bzt r0, .Ltry4
+
+ move r30, r10
+
+#ifdef RELOCATE_NEW_KERNEL_VERBOSE
+ moveli r0, 'i'
+ jalr r40
+#endif
+
+ j .Lloop
+
+.Ltry4:
+ seqi r0, r9, 0x4 /* IND_DONE */
+ bzt r0, .Ltry8
+
+ mf
+
+#ifdef RELOCATE_NEW_KERNEL_VERBOSE
+ moveli r0, 'D'
+ jalr r40
+ moveli r0, '\n'
+ jalr r40
+#endif
+
+ move r0, r32
+ moveli r1, 0 /* arg to hv_reexec is 64 bits */
+
+ moveli r41, lo16(___hv_reexec)
+ auli r41, r41, ha16(___hv_reexec)
+
+ jalr r41
+
+ /* we should not get here */
+
+ moveli r0, '?'
+ jalr r40
+ moveli r0, '\n'
+ jalr r40
+
+ j .Lhalt
+
+.Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */
+ bz r0, .Lerr /* unknown type */
+
+ /* copy page at r10 to page at r33 */
+
+ move r11, r33
+
+ moveli r0, lo16(PAGE_SIZE)
+ auli r0, r0, ha16(PAGE_SIZE)
+ add r33, r33, r0
+
+ /* copy word at r10 to word at r11 until r11 equals r33 */
+
+ /* We know page size must be multiple of 16, so we can unroll
+ * 16 times safely without any edge case checking.
+ *
+ * Issue a flush of the destination every 16 words to avoid
+ * incoherence when starting the new kernel. (Now this is
+ * just good paranoia because the hv_reexec call will also
+ * take care of this.)
+ */
+
+1:
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0; addi r11, r11, 4 }
+ { lw r0, r10; addi r10, r10, 4 }
+ { sw r11, r0 }
+ { flush r11 ; addi r11, r11, 4 }
+
+ seq r0, r33, r11
+ bzt r0, 1b
+
+#ifdef RELOCATE_NEW_KERNEL_VERBOSE
+ moveli r0, 's'
+ jalr r40
+#endif
+
+ addi r30, r30, 4
+ j .Lloop
+
+
+.Lerr: moveli r0, 'e'
+ jalr r40
+ moveli r0, 'r'
+ jalr r40
+ moveli r0, 'r'
+ jalr r40
+ moveli r0, '\n'
+ jalr r40
+.Lhalt:
+ moveli r41, lo16(___hv_halt)
+ auli r41, r41, ha16(___hv_halt)
+
+ jalr r41
+ STD_ENDPROC(relocate_new_kernel)
+
+ .section .rodata,"a"
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long .Lend_relocate_new_kernel - relocate_new_kernel
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
new file mode 100644
index 000000000000..934136b61ceb
--- /dev/null
+++ b/arch/tile/kernel/setup.c
@@ -0,0 +1,1497 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mmzone.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/node.h>
+#include <linux/cpu.h>
+#include <linux/ioport.h>
+#include <linux/kexec.h>
+#include <linux/pci.h>
+#include <linux/initrd.h>
+#include <linux/io.h>
+#include <linux/highmem.h>
+#include <linux/smp.h>
+#include <linux/timex.h>
+#include <asm/setup.h>
+#include <asm/sections.h>
+#include <asm/sections.h>
+#include <asm/cacheflush.h>
+#include <asm/cacheflush.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <hv/hypervisor.h>
+#include <arch/interrupts.h>
+
+/* <linux/smp.h> doesn't provide this definition. */
+#ifndef CONFIG_SMP
+#define setup_max_cpus 1
+#endif
+
+static inline int ABS(int x) { return x >= 0 ? x : -x; }
+
+/* Chip information */
+char chip_model[64] __write_once;
+
+struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
+EXPORT_SYMBOL(node_data);
+
+/* We only create bootmem data on node 0. */
+static bootmem_data_t __initdata node0_bdata;
+
+/* Information on the NUMA nodes that we compute early */
+unsigned long __cpuinitdata node_start_pfn[MAX_NUMNODES];
+unsigned long __cpuinitdata node_end_pfn[MAX_NUMNODES];
+unsigned long __initdata node_memmap_pfn[MAX_NUMNODES];
+unsigned long __initdata node_percpu_pfn[MAX_NUMNODES];
+unsigned long __initdata node_free_pfn[MAX_NUMNODES];
+
+#ifdef CONFIG_HIGHMEM
+/* Page frame index of end of lowmem on each controller. */
+unsigned long __cpuinitdata node_lowmem_end_pfn[MAX_NUMNODES];
+
+/* Number of pages that can be mapped into lowmem. */
+static unsigned long __initdata mappable_physpages;
+#endif
+
+/* Data on which physical memory controller corresponds to which NUMA node */
+int node_controller[MAX_NUMNODES] = { [0 ... MAX_NUMNODES-1] = -1 };
+
+#ifdef CONFIG_HIGHMEM
+/* Map information from VAs to PAs */
+unsigned long pbase_map[1 << (32 - HPAGE_SHIFT)]
+ __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+EXPORT_SYMBOL(pbase_map);
+
+/* Map information from PAs to VAs */
+void *vbase_map[NR_PA_HIGHBIT_VALUES]
+ __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+EXPORT_SYMBOL(vbase_map);
+#endif
+
+/* Node number as a function of the high PA bits */
+int highbits_to_node[NR_PA_HIGHBIT_VALUES] __write_once;
+EXPORT_SYMBOL(highbits_to_node);
+
+static unsigned int __initdata maxmem_pfn = -1U;
+static unsigned int __initdata maxnodemem_pfn[MAX_NUMNODES] = {
+ [0 ... MAX_NUMNODES-1] = -1U
+};
+static nodemask_t __initdata isolnodes;
+
+#ifdef CONFIG_PCI
+enum { DEFAULT_PCI_RESERVE_MB = 64 };
+static unsigned int __initdata pci_reserve_mb = DEFAULT_PCI_RESERVE_MB;
+unsigned long __initdata pci_reserve_start_pfn = -1U;
+unsigned long __initdata pci_reserve_end_pfn = -1U;
+#endif
+
+static int __init setup_maxmem(char *str)
+{
+ long maxmem_mb;
+ if (str == NULL || strict_strtol(str, 0, &maxmem_mb) != 0 ||
+ maxmem_mb == 0)
+ return -EINVAL;
+
+ maxmem_pfn = (maxmem_mb >> (HPAGE_SHIFT - 20)) <<
+ (HPAGE_SHIFT - PAGE_SHIFT);
+ printk("Forcing RAM used to no more than %dMB\n",
+ maxmem_pfn >> (20 - PAGE_SHIFT));
+ return 0;
+}
+early_param("maxmem", setup_maxmem);
+
+static int __init setup_maxnodemem(char *str)
+{
+ char *endp;
+ long maxnodemem_mb, node;
+
+ node = str ? simple_strtoul(str, &endp, 0) : INT_MAX;
+ if (node >= MAX_NUMNODES || *endp != ':' ||
+ strict_strtol(endp+1, 0, &maxnodemem_mb) != 0)
+ return -EINVAL;
+
+ maxnodemem_pfn[node] = (maxnodemem_mb >> (HPAGE_SHIFT - 20)) <<
+ (HPAGE_SHIFT - PAGE_SHIFT);
+ printk("Forcing RAM used on node %ld to no more than %dMB\n",
+ node, maxnodemem_pfn[node] >> (20 - PAGE_SHIFT));
+ return 0;
+}
+early_param("maxnodemem", setup_maxnodemem);
+
+static int __init setup_isolnodes(char *str)
+{
+ char buf[MAX_NUMNODES * 5];
+ if (str == NULL || nodelist_parse(str, isolnodes) != 0)
+ return -EINVAL;
+
+ nodelist_scnprintf(buf, sizeof(buf), isolnodes);
+ printk("Set isolnodes value to '%s'\n", buf);
+ return 0;
+}
+early_param("isolnodes", setup_isolnodes);
+
+#ifdef CONFIG_PCI
+static int __init setup_pci_reserve(char* str)
+{
+ unsigned long mb;
+
+ if (str == NULL || strict_strtoul(str, 0, &mb) != 0 ||
+ mb > 3 * 1024)
+ return -EINVAL;
+
+ pci_reserve_mb = mb;
+ printk("Reserving %dMB for PCIE root complex mappings\n",
+ pci_reserve_mb);
+ return 0;
+}
+early_param("pci_reserve", setup_pci_reserve);
+#endif
+
+#ifndef __tilegx__
+/*
+ * vmalloc=size forces the vmalloc area to be exactly 'size' bytes.
+ * This can be used to increase (or decrease) the vmalloc area.
+ */
+static int __init parse_vmalloc(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ VMALLOC_RESERVE = (memparse(arg, &arg) + PGDIR_SIZE - 1) & PGDIR_MASK;
+
+ /* See validate_va() for more on this test. */
+ if ((long)_VMALLOC_START >= 0)
+ early_panic("\"vmalloc=%#lx\" value too large: maximum %#lx\n",
+ VMALLOC_RESERVE, _VMALLOC_END - 0x80000000UL);
+
+ return 0;
+}
+early_param("vmalloc", parse_vmalloc);
+#endif
+
+#ifdef CONFIG_HIGHMEM
+/*
+ * Determine for each controller where its lowmem is mapped and how
+ * much of it is mapped there. On controller zero, the first few
+ * megabytes are mapped at 0xfd000000 as code, so in principle we
+ * could start our data mappings higher up, but for now we don't
+ * bother, to avoid additional confusion.
+ *
+ * One question is whether, on systems with more than 768 Mb and
+ * controllers of different sizes, to map in a proportionate amount of
+ * each one, or to try to map the same amount from each controller.
+ * (E.g. if we have three controllers with 256MB, 1GB, and 256MB
+ * respectively, do we map 256MB from each, or do we map 128 MB, 512
+ * MB, and 128 MB respectively?) For now we use a proportionate
+ * solution like the latter.
+ *
+ * The VA/PA mapping demands that we align our decisions at 16 MB
+ * boundaries so that we can rapidly convert VA to PA.
+ */
+static void *__init setup_pa_va_mapping(void)
+{
+ unsigned long curr_pages = 0;
+ unsigned long vaddr = PAGE_OFFSET;
+ nodemask_t highonlynodes = isolnodes;
+ int i, j;
+
+ memset(pbase_map, -1, sizeof(pbase_map));
+ memset(vbase_map, -1, sizeof(vbase_map));
+
+ /* Node zero cannot be isolated for LOWMEM purposes. */
+ node_clear(0, highonlynodes);
+
+ /* Count up the number of pages on non-highonlynodes controllers. */
+ mappable_physpages = 0;
+ for_each_online_node(i) {
+ if (!node_isset(i, highonlynodes))
+ mappable_physpages +=
+ node_end_pfn[i] - node_start_pfn[i];
+ }
+
+ for_each_online_node(i) {
+ unsigned long start = node_start_pfn[i];
+ unsigned long end = node_end_pfn[i];
+ unsigned long size = end - start;
+ unsigned long vaddr_end;
+
+ if (node_isset(i, highonlynodes)) {
+ /* Mark this controller as having no lowmem. */
+ node_lowmem_end_pfn[i] = start;
+ continue;
+ }
+
+ curr_pages += size;
+ if (mappable_physpages > MAXMEM_PFN) {
+ vaddr_end = PAGE_OFFSET +
+ (((u64)curr_pages * MAXMEM_PFN /
+ mappable_physpages)
+ << PAGE_SHIFT);
+ } else {
+ vaddr_end = PAGE_OFFSET + (curr_pages << PAGE_SHIFT);
+ }
+ for (j = 0; vaddr < vaddr_end; vaddr += HPAGE_SIZE, ++j) {
+ unsigned long this_pfn =
+ start + (j << HUGETLB_PAGE_ORDER);
+ pbase_map[vaddr >> HPAGE_SHIFT] = this_pfn;
+ if (vbase_map[__pfn_to_highbits(this_pfn)] ==
+ (void *)-1)
+ vbase_map[__pfn_to_highbits(this_pfn)] =
+ (void *)(vaddr & HPAGE_MASK);
+ }
+ node_lowmem_end_pfn[i] = start + (j << HUGETLB_PAGE_ORDER);
+ BUG_ON(node_lowmem_end_pfn[i] > end);
+ }
+
+ /* Return highest address of any mapped memory. */
+ return (void *)vaddr;
+}
+#endif /* CONFIG_HIGHMEM */
+
+/*
+ * Register our most important memory mappings with the debug stub.
+ *
+ * This is up to 4 mappings for lowmem, one mapping per memory
+ * controller, plus one for our text segment.
+ */
+void __cpuinit store_permanent_mappings(void)
+{
+ int i;
+
+ for_each_online_node(i) {
+ HV_PhysAddr pa = ((HV_PhysAddr)node_start_pfn[i]) << PAGE_SHIFT;
+#ifdef CONFIG_HIGHMEM
+ HV_PhysAddr high_mapped_pa = node_lowmem_end_pfn[i];
+#else
+ HV_PhysAddr high_mapped_pa = node_end_pfn[i];
+#endif
+
+ unsigned long pages = high_mapped_pa - node_start_pfn[i];
+ HV_VirtAddr addr = (HV_VirtAddr) __va(pa);
+ hv_store_mapping(addr, pages << PAGE_SHIFT, pa);
+ }
+
+ hv_store_mapping((HV_VirtAddr)_stext,
+ (uint32_t)(_einittext - _stext), 0);
+}
+
+/*
+ * Use hv_inquire_physical() to populate node_{start,end}_pfn[]
+ * and node_online_map, doing suitable sanity-checking.
+ * Also set min_low_pfn, max_low_pfn, and max_pfn.
+ */
+static void __init setup_memory(void)
+{
+ int i, j;
+ int highbits_seen[NR_PA_HIGHBIT_VALUES] = { 0 };
+#ifdef CONFIG_HIGHMEM
+ long highmem_pages;
+#endif
+#ifndef __tilegx__
+ int cap;
+#endif
+#if defined(CONFIG_HIGHMEM) || defined(__tilegx__)
+ long lowmem_pages;
+#endif
+
+ /* We are using a char to hold the cpu_2_node[] mapping */
+ BUG_ON(MAX_NUMNODES > 127);
+
+ /* Discover the ranges of memory available to us */
+ for (i = 0; ; ++i) {
+ unsigned long start, size, end, highbits;
+ HV_PhysAddrRange range = hv_inquire_physical(i);
+ if (range.size == 0)
+ break;
+#ifdef CONFIG_FLATMEM
+ if (i > 0) {
+ printk("Can't use discontiguous PAs: %#llx..%#llx\n",
+ range.size, range.start + range.size);
+ continue;
+ }
+#endif
+#ifndef __tilegx__
+ if ((unsigned long)range.start) {
+ printk("Range not at 4GB multiple: %#llx..%#llx\n",
+ range.start, range.start + range.size);
+ continue;
+ }
+#endif
+ if ((range.start & (HPAGE_SIZE-1)) != 0 ||
+ (range.size & (HPAGE_SIZE-1)) != 0) {
+ unsigned long long start_pa = range.start;
+ unsigned long long size = range.size;
+ range.start = (start_pa + HPAGE_SIZE - 1) & HPAGE_MASK;
+ range.size -= (range.start - start_pa);
+ range.size &= HPAGE_MASK;
+ printk("Range not hugepage-aligned: %#llx..%#llx:"
+ " now %#llx-%#llx\n",
+ start_pa, start_pa + size,
+ range.start, range.start + range.size);
+ }
+ highbits = __pa_to_highbits(range.start);
+ if (highbits >= NR_PA_HIGHBIT_VALUES) {
+ printk("PA high bits too high: %#llx..%#llx\n",
+ range.start, range.start + range.size);
+ continue;
+ }
+ if (highbits_seen[highbits]) {
+ printk("Range overlaps in high bits: %#llx..%#llx\n",
+ range.start, range.start + range.size);
+ continue;
+ }
+ highbits_seen[highbits] = 1;
+ if (PFN_DOWN(range.size) > maxnodemem_pfn[i]) {
+ int size = maxnodemem_pfn[i];
+ if (size > 0) {
+ printk("Maxnodemem reduced node %d to"
+ " %d pages\n", i, size);
+ range.size = (HV_PhysAddr)size << PAGE_SHIFT;
+ } else {
+ printk("Maxnodemem disabled node %d\n", i);
+ continue;
+ }
+ }
+ if (num_physpages + PFN_DOWN(range.size) > maxmem_pfn) {
+ int size = maxmem_pfn - num_physpages;
+ if (size > 0) {
+ printk("Maxmem reduced node %d to %d pages\n",
+ i, size);
+ range.size = (HV_PhysAddr)size << PAGE_SHIFT;
+ } else {
+ printk("Maxmem disabled node %d\n", i);
+ continue;
+ }
+ }
+ if (i >= MAX_NUMNODES) {
+ printk("Too many PA nodes (#%d): %#llx...%#llx\n",
+ i, range.size, range.size + range.start);
+ continue;
+ }
+
+ start = range.start >> PAGE_SHIFT;
+ size = range.size >> PAGE_SHIFT;
+ end = start + size;
+
+#ifndef __tilegx__
+ if (((HV_PhysAddr)end << PAGE_SHIFT) !=
+ (range.start + range.size)) {
+ printk("PAs too high to represent: %#llx..%#llx\n",
+ range.start, range.start + range.size);
+ continue;
+ }
+#endif
+#ifdef CONFIG_PCI
+ /*
+ * Blocks that overlap the pci reserved region must
+ * have enough space to hold the maximum percpu data
+ * region at the top of the range. If there isn't
+ * enough space above the reserved region, just
+ * truncate the node.
+ */
+ if (start <= pci_reserve_start_pfn &&
+ end > pci_reserve_start_pfn) {
+ unsigned int per_cpu_size =
+ __per_cpu_end - __per_cpu_start;
+ unsigned int percpu_pages =
+ NR_CPUS * (PFN_UP(per_cpu_size) >> PAGE_SHIFT);
+ if (end < pci_reserve_end_pfn + percpu_pages) {
+ end = pci_reserve_start_pfn;
+ printk("PCI mapping region reduced node %d to"
+ " %ld pages\n", i, end - start);
+ }
+ }
+#endif
+
+ for (j = __pfn_to_highbits(start);
+ j <= __pfn_to_highbits(end - 1); j++)
+ highbits_to_node[j] = i;
+
+ node_start_pfn[i] = start;
+ node_end_pfn[i] = end;
+ node_controller[i] = range.controller;
+ num_physpages += size;
+ max_pfn = end;
+
+ /* Mark node as online */
+ node_set(i, node_online_map);
+ node_set(i, node_possible_map);
+ }
+
+#ifndef __tilegx__
+ /*
+ * For 4KB pages, mem_map "struct page" data is 1% of the size
+ * of the physical memory, so can be quite big (640 MB for
+ * four 16G zones). These structures must be mapped in
+ * lowmem, and since we currently cap out at about 768 MB,
+ * it's impractical to try to use this much address space.
+ * For now, arbitrarily cap the amount of physical memory
+ * we're willing to use at 8 million pages (32GB of 4KB pages).
+ */
+ cap = 8 * 1024 * 1024; /* 8 million pages */
+ if (num_physpages > cap) {
+ int num_nodes = num_online_nodes();
+ int cap_each = cap / num_nodes;
+ unsigned long dropped_pages = 0;
+ for (i = 0; i < num_nodes; ++i) {
+ int size = node_end_pfn[i] - node_start_pfn[i];
+ if (size > cap_each) {
+ dropped_pages += (size - cap_each);
+ node_end_pfn[i] = node_start_pfn[i] + cap_each;
+ }
+ }
+ num_physpages -= dropped_pages;
+ printk(KERN_WARNING "Only using %ldMB memory;"
+ " ignoring %ldMB.\n",
+ num_physpages >> (20 - PAGE_SHIFT),
+ dropped_pages >> (20 - PAGE_SHIFT));
+ printk(KERN_WARNING "Consider using a larger page size.\n");
+ }
+#endif
+
+ /* Heap starts just above the last loaded address. */
+ min_low_pfn = PFN_UP((unsigned long)_end - PAGE_OFFSET);
+
+#ifdef CONFIG_HIGHMEM
+ /* Find where we map lowmem from each controller. */
+ high_memory = setup_pa_va_mapping();
+
+ /* Set max_low_pfn based on what node 0 can directly address. */
+ max_low_pfn = node_lowmem_end_pfn[0];
+
+ lowmem_pages = (mappable_physpages > MAXMEM_PFN) ?
+ MAXMEM_PFN : mappable_physpages;
+ highmem_pages = (long) (num_physpages - lowmem_pages);
+
+ printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
+ pages_to_mb(highmem_pages > 0 ? highmem_pages : 0));
+ printk(KERN_NOTICE "%ldMB LOWMEM available.\n",
+ pages_to_mb(lowmem_pages));
+#else
+ /* Set max_low_pfn based on what node 0 can directly address. */
+ max_low_pfn = node_end_pfn[0];
+
+#ifndef __tilegx__
+ if (node_end_pfn[0] > MAXMEM_PFN) {
+ printk(KERN_WARNING "Only using %ldMB LOWMEM.\n",
+ MAXMEM>>20);
+ printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+ max_low_pfn = MAXMEM_PFN;
+ max_pfn = MAXMEM_PFN;
+ num_physpages = MAXMEM_PFN;
+ node_end_pfn[0] = MAXMEM_PFN;
+ } else {
+ printk(KERN_NOTICE "%ldMB memory available.\n",
+ pages_to_mb(node_end_pfn[0]));
+ }
+ for (i = 1; i < MAX_NUMNODES; ++i) {
+ node_start_pfn[i] = 0;
+ node_end_pfn[i] = 0;
+ }
+ high_memory = __va(node_end_pfn[0]);
+#else
+ lowmem_pages = 0;
+ for (i = 0; i < MAX_NUMNODES; ++i) {
+ int pages = node_end_pfn[i] - node_start_pfn[i];
+ lowmem_pages += pages;
+ if (pages)
+ high_memory = pfn_to_kaddr(node_end_pfn[i]);
+ }
+ printk(KERN_NOTICE "%ldMB memory available.\n",
+ pages_to_mb(lowmem_pages));
+#endif
+#endif
+}
+
+static void __init setup_bootmem_allocator(void)
+{
+ unsigned long bootmap_size, first_alloc_pfn, last_alloc_pfn;
+
+ /* Provide a node 0 bdata. */
+ NODE_DATA(0)->bdata = &node0_bdata;
+
+#ifdef CONFIG_PCI
+ /* Don't let boot memory alias the PCI region. */
+ last_alloc_pfn = min(max_low_pfn, pci_reserve_start_pfn);
+#else
+ last_alloc_pfn = max_low_pfn;
+#endif
+
+ /*
+ * Initialize the boot-time allocator (with low memory only):
+ * The first argument says where to put the bitmap, and the
+ * second says where the end of allocatable memory is.
+ */
+ bootmap_size = init_bootmem(min_low_pfn, last_alloc_pfn);
+
+ /*
+ * Let the bootmem allocator use all the space we've given it
+ * except for its own bitmap.
+ */
+ first_alloc_pfn = min_low_pfn + PFN_UP(bootmap_size);
+ if (first_alloc_pfn >= last_alloc_pfn)
+ early_panic("Not enough memory on controller 0 for bootmem\n");
+
+ free_bootmem(PFN_PHYS(first_alloc_pfn),
+ PFN_PHYS(last_alloc_pfn - first_alloc_pfn));
+
+#ifdef CONFIG_KEXEC
+ if (crashk_res.start != crashk_res.end)
+ reserve_bootmem(crashk_res.start,
+ crashk_res.end - crashk_res.start + 1, 0);
+#endif
+
+}
+
+void *__init alloc_remap(int nid, unsigned long size)
+{
+ int pages = node_end_pfn[nid] - node_start_pfn[nid];
+ void *map = pfn_to_kaddr(node_memmap_pfn[nid]);
+ BUG_ON(size != pages * sizeof(struct page));
+ memset(map, 0, size);
+ return map;
+}
+
+static int __init percpu_size(void)
+{
+ int size = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE);
+#ifdef CONFIG_MODULES
+ if (size < PERCPU_ENOUGH_ROOM)
+ size = PERCPU_ENOUGH_ROOM;
+#endif
+ /* In several places we assume the per-cpu data fits on a huge page. */
+ BUG_ON(kdata_huge && size > HPAGE_SIZE);
+ return size;
+}
+
+static inline unsigned long alloc_bootmem_pfn(int size, unsigned long goal)
+{
+ void *kva = __alloc_bootmem(size, PAGE_SIZE, goal);
+ unsigned long pfn = kaddr_to_pfn(kva);
+ BUG_ON(goal && PFN_PHYS(pfn) != goal);
+ return pfn;
+}
+
+static void __init zone_sizes_init(void)
+{
+ unsigned long zones_size[MAX_NR_ZONES] = { 0 };
+ unsigned long node_percpu[MAX_NUMNODES] = { 0 };
+ int size = percpu_size();
+ int num_cpus = smp_height * smp_width;
+ int i;
+
+ for (i = 0; i < num_cpus; ++i)
+ node_percpu[cpu_to_node(i)] += size;
+
+ for_each_online_node(i) {
+ unsigned long start = node_start_pfn[i];
+ unsigned long end = node_end_pfn[i];
+#ifdef CONFIG_HIGHMEM
+ unsigned long lowmem_end = node_lowmem_end_pfn[i];
+#else
+ unsigned long lowmem_end = end;
+#endif
+ int memmap_size = (end - start) * sizeof(struct page);
+ node_free_pfn[i] = start;
+
+ /*
+ * Set aside pages for per-cpu data and the mem_map array.
+ *
+ * Since the per-cpu data requires special homecaching,
+ * if we are in kdata_huge mode, we put it at the end of
+ * the lowmem region. If we're not in kdata_huge mode,
+ * we take the per-cpu pages from the bottom of the
+ * controller, since that avoids fragmenting a huge page
+ * that users might want. We always take the memmap
+ * from the bottom of the controller, since with
+ * kdata_huge that lets it be under a huge TLB entry.
+ *
+ * If the user has requested isolnodes for a controller,
+ * though, there'll be no lowmem, so we just alloc_bootmem
+ * the memmap. There will be no percpu memory either.
+ */
+ if (__pfn_to_highbits(start) == 0) {
+ /* In low PAs, allocate via bootmem. */
+ unsigned long goal = 0;
+ node_memmap_pfn[i] =
+ alloc_bootmem_pfn(memmap_size, goal);
+ if (kdata_huge)
+ goal = PFN_PHYS(lowmem_end) - node_percpu[i];
+ if (node_percpu[i])
+ node_percpu_pfn[i] =
+ alloc_bootmem_pfn(node_percpu[i], goal);
+ } else if (cpu_isset(i, isolnodes)) {
+ node_memmap_pfn[i] = alloc_bootmem_pfn(memmap_size, 0);
+ BUG_ON(node_percpu[i] != 0);
+ } else {
+ /* In high PAs, just reserve some pages. */
+ node_memmap_pfn[i] = node_free_pfn[i];
+ node_free_pfn[i] += PFN_UP(memmap_size);
+ if (!kdata_huge) {
+ node_percpu_pfn[i] = node_free_pfn[i];
+ node_free_pfn[i] += PFN_UP(node_percpu[i]);
+ } else {
+ node_percpu_pfn[i] =
+ lowmem_end - PFN_UP(node_percpu[i]);
+ }
+ }
+
+#ifdef CONFIG_HIGHMEM
+ if (start > lowmem_end) {
+ zones_size[ZONE_NORMAL] = 0;
+ zones_size[ZONE_HIGHMEM] = end - start;
+ } else {
+ zones_size[ZONE_NORMAL] = lowmem_end - start;
+ zones_size[ZONE_HIGHMEM] = end - lowmem_end;
+ }
+#else
+ zones_size[ZONE_NORMAL] = end - start;
+#endif
+
+ /*
+ * Everyone shares node 0's bootmem allocator, but
+ * we use alloc_remap(), above, to put the actual
+ * struct page array on the individual controllers,
+ * which is most of the data that we actually care about.
+ * We can't place bootmem allocators on the other
+ * controllers since the bootmem allocator can only
+ * operate on 32-bit physical addresses.
+ */
+ NODE_DATA(i)->bdata = NODE_DATA(0)->bdata;
+
+ free_area_init_node(i, zones_size, start, NULL);
+ printk(KERN_DEBUG " DMA zone: %ld per-cpu pages\n",
+ PFN_UP(node_percpu[i]));
+
+ /* Track the type of memory on each node */
+ if (zones_size[ZONE_NORMAL])
+ node_set_state(i, N_NORMAL_MEMORY);
+#ifdef CONFIG_HIGHMEM
+ if (end != start)
+ node_set_state(i, N_HIGH_MEMORY);
+#endif
+
+ node_set_online(i);
+ }
+}
+
+#ifdef CONFIG_NUMA
+
+/* which logical CPUs are on which nodes */
+struct cpumask node_2_cpu_mask[MAX_NUMNODES] __write_once;
+EXPORT_SYMBOL(node_2_cpu_mask);
+
+/* which node each logical CPU is on */
+char cpu_2_node[NR_CPUS] __write_once __attribute__((aligned(L2_CACHE_BYTES)));
+EXPORT_SYMBOL(cpu_2_node);
+
+/* Return cpu_to_node() except for cpus not yet assigned, which return -1 */
+static int __init cpu_to_bound_node(int cpu, struct cpumask* unbound_cpus)
+{
+ if (!cpu_possible(cpu) || cpumask_test_cpu(cpu, unbound_cpus))
+ return -1;
+ else
+ return cpu_to_node(cpu);
+}
+
+/* Return number of immediately-adjacent tiles sharing the same NUMA node. */
+static int __init node_neighbors(int node, int cpu,
+ struct cpumask *unbound_cpus)
+{
+ int neighbors = 0;
+ int w = smp_width;
+ int h = smp_height;
+ int x = cpu % w;
+ int y = cpu / w;
+ if (x > 0 && cpu_to_bound_node(cpu-1, unbound_cpus) == node)
+ ++neighbors;
+ if (x < w-1 && cpu_to_bound_node(cpu+1, unbound_cpus) == node)
+ ++neighbors;
+ if (y > 0 && cpu_to_bound_node(cpu-w, unbound_cpus) == node)
+ ++neighbors;
+ if (y < h-1 && cpu_to_bound_node(cpu+w, unbound_cpus) == node)
+ ++neighbors;
+ return neighbors;
+}
+
+static void __init setup_numa_mapping(void)
+{
+ int distance[MAX_NUMNODES][NR_CPUS];
+ HV_Coord coord;
+ int cpu, node, cpus, i, x, y;
+ int num_nodes = num_online_nodes();
+ struct cpumask unbound_cpus;
+ nodemask_t default_nodes;
+
+ cpumask_clear(&unbound_cpus);
+
+ /* Get set of nodes we will use for defaults */
+ nodes_andnot(default_nodes, node_online_map, isolnodes);
+ if (nodes_empty(default_nodes)) {
+ BUG_ON(!node_isset(0, node_online_map));
+ printk("Forcing NUMA node zero available as a default node\n");
+ node_set(0, default_nodes);
+ }
+
+ /* Populate the distance[] array */
+ memset(distance, -1, sizeof(distance));
+ cpu = 0;
+ for (coord.y = 0; coord.y < smp_height; ++coord.y) {
+ for (coord.x = 0; coord.x < smp_width;
+ ++coord.x, ++cpu) {
+ BUG_ON(cpu >= nr_cpu_ids);
+ if (!cpu_possible(cpu)) {
+ cpu_2_node[cpu] = -1;
+ continue;
+ }
+ for_each_node_mask(node, default_nodes) {
+ HV_MemoryControllerInfo info =
+ hv_inquire_memory_controller(
+ coord, node_controller[node]);
+ distance[node][cpu] =
+ ABS(info.coord.x) + ABS(info.coord.y);
+ }
+ cpumask_set_cpu(cpu, &unbound_cpus);
+ }
+ }
+ cpus = cpu;
+
+ /*
+ * Round-robin through the NUMA nodes until all the cpus are
+ * assigned. We could be more clever here (e.g. create four
+ * sorted linked lists on the same set of cpu nodes, and pull
+ * off them in round-robin sequence, removing from all four
+ * lists each time) but given the relatively small numbers
+ * involved, O(n^2) seem OK for a one-time cost.
+ */
+ node = first_node(default_nodes);
+ while (!cpumask_empty(&unbound_cpus)) {
+ int best_cpu = -1;
+ int best_distance = INT_MAX;
+ for (cpu = 0; cpu < cpus; ++cpu) {
+ if (cpumask_test_cpu(cpu, &unbound_cpus)) {
+ /*
+ * Compute metric, which is how much
+ * closer the cpu is to this memory
+ * controller than the others, shifted
+ * up, and then the number of
+ * neighbors already in the node as an
+ * epsilon adjustment to try to keep
+ * the nodes compact.
+ */
+ int d = distance[node][cpu] * num_nodes;
+ for_each_node_mask(i, default_nodes) {
+ if (i != node)
+ d -= distance[i][cpu];
+ }
+ d *= 8; /* allow space for epsilon */
+ d -= node_neighbors(node, cpu, &unbound_cpus);
+ if (d < best_distance) {
+ best_cpu = cpu;
+ best_distance = d;
+ }
+ }
+ }
+ BUG_ON(best_cpu < 0);
+ cpumask_set_cpu(best_cpu, &node_2_cpu_mask[node]);
+ cpu_2_node[best_cpu] = node;
+ cpumask_clear_cpu(best_cpu, &unbound_cpus);
+ node = next_node(node, default_nodes);
+ if (node == MAX_NUMNODES)
+ node = first_node(default_nodes);
+ }
+
+ /* Print out node assignments and set defaults for disabled cpus */
+ cpu = 0;
+ for (y = 0; y < smp_height; ++y) {
+ printk(KERN_DEBUG "NUMA cpu-to-node row %d:", y);
+ for (x = 0; x < smp_width; ++x, ++cpu) {
+ if (cpu_to_node(cpu) < 0) {
+ printk(" -");
+ cpu_2_node[cpu] = first_node(default_nodes);
+ } else {
+ printk(" %d", cpu_to_node(cpu));
+ }
+ }
+ printk("\n");
+ }
+}
+
+static struct cpu cpu_devices[NR_CPUS];
+
+static int __init topology_init(void)
+{
+ int i;
+
+ for_each_online_node(i)
+ register_one_node(i);
+
+ for_each_present_cpu(i)
+ register_cpu(&cpu_devices[i], i);
+
+ return 0;
+}
+
+subsys_initcall(topology_init);
+
+#else /* !CONFIG_NUMA */
+
+#define setup_numa_mapping() do { } while (0)
+
+#endif /* CONFIG_NUMA */
+
+/**
+ * setup_mpls() - Allow the user-space code to access various SPRs.
+ *
+ * Also called from online_secondary().
+ */
+void __cpuinit setup_mpls(void)
+{
+ /* Allow asynchronous TLB interrupts. */
+#if CHIP_HAS_TILE_DMA()
+ raw_local_irq_unmask(INT_DMATLB_MISS);
+ raw_local_irq_unmask(INT_DMATLB_ACCESS);
+#endif
+#if CHIP_HAS_SN_PROC()
+ raw_local_irq_unmask(INT_SNITLB_MISS);
+#endif
+
+ /*
+ * Allow user access to many generic SPRs, like the cycle
+ * counter, PASS/FAIL/DONE, INTERRUPT_CRITICAL_SECTION, etc.
+ */
+ __insn_mtspr(SPR_MPL_WORLD_ACCESS_SET_0, 1);
+
+#if CHIP_HAS_SN()
+ /* Static network is not restricted. */
+ __insn_mtspr(SPR_MPL_SN_ACCESS_SET_0, 1);
+#endif
+#if CHIP_HAS_SN_PROC()
+ __insn_mtspr(SPR_MPL_SN_NOTIFY_SET_0, 1);
+ __insn_mtspr(SPR_MPL_SN_CPL_SET_0, 1);
+#endif
+
+ /*
+ * Set the MPL for interrupt control 0 to user level.
+ * This includes access to the SYSTEM_SAVE and EX_CONTEXT SPRs,
+ * as well as the PL 0 interrupt mask.
+ */
+ __insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1);
+}
+
+static int __initdata set_initramfs_file;
+static char __initdata initramfs_file[128] = "initramfs.cpio.gz";
+
+static int __init setup_initramfs_file(char *str)
+{
+ if (str == NULL)
+ return -EINVAL;
+ strncpy(initramfs_file, str, sizeof(initramfs_file) - 1);
+ set_initramfs_file = 1;
+
+ return 0;
+}
+early_param("initramfs_file", setup_initramfs_file);
+
+/*
+ * We look for an additional "initramfs.cpio.gz" file in the hvfs.
+ * If there is one, we allocate some memory for it and it will be
+ * unpacked to the initramfs after any built-in initramfs_data.
+ */
+static void __init load_hv_initrd(void)
+{
+ HV_FS_StatInfo stat;
+ int fd, rc;
+ void *initrd;
+
+ fd = hv_fs_findfile((HV_VirtAddr) initramfs_file);
+ if (fd == HV_ENOENT) {
+ if (set_initramfs_file)
+ printk("No such hvfs initramfs file '%s'\n",
+ initramfs_file);
+ return;
+ }
+ BUG_ON(fd < 0);
+ stat = hv_fs_fstat(fd);
+ BUG_ON(stat.size < 0);
+ if (stat.flags & HV_FS_ISDIR) {
+ printk("Ignoring hvfs file '%s': it's a directory.\n",
+ initramfs_file);
+ return;
+ }
+ initrd = alloc_bootmem_pages(stat.size);
+ rc = hv_fs_pread(fd, (HV_VirtAddr) initrd, stat.size, 0);
+ if (rc != stat.size) {
+ printk("Error reading %d bytes from hvfs file '%s': %d\n",
+ stat.size, initramfs_file, rc);
+ free_bootmem((unsigned long) initrd, stat.size);
+ return;
+ }
+ initrd_start = (unsigned long) initrd;
+ initrd_end = initrd_start + stat.size;
+}
+
+void __init free_initrd_mem(unsigned long begin, unsigned long end)
+{
+ free_bootmem(begin, end - begin);
+}
+
+static void __init validate_hv(void)
+{
+ /*
+ * It may already be too late, but let's check our built-in
+ * configuration against what the hypervisor is providing.
+ */
+ unsigned long glue_size = hv_sysconf(HV_SYSCONF_GLUE_SIZE);
+ int hv_page_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL);
+ int hv_hpage_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE);
+ HV_ASIDRange asid_range;
+
+#ifndef CONFIG_SMP
+ HV_Topology topology = hv_inquire_topology();
+ BUG_ON(topology.coord.x != 0 || topology.coord.y != 0);
+ if (topology.width != 1 || topology.height != 1) {
+ printk("Warning: booting UP kernel on %dx%d grid;"
+ " will ignore all but first tile.\n",
+ topology.width, topology.height);
+ }
+#endif
+
+ if (PAGE_OFFSET + HV_GLUE_START_CPA + glue_size > (unsigned long)_text)
+ early_panic("Hypervisor glue size %ld is too big!\n",
+ glue_size);
+ if (hv_page_size != PAGE_SIZE)
+ early_panic("Hypervisor page size %#x != our %#lx\n",
+ hv_page_size, PAGE_SIZE);
+ if (hv_hpage_size != HPAGE_SIZE)
+ early_panic("Hypervisor huge page size %#x != our %#lx\n",
+ hv_hpage_size, HPAGE_SIZE);
+
+#ifdef CONFIG_SMP
+ /*
+ * Some hypervisor APIs take a pointer to a bitmap array
+ * whose size is at least the number of cpus on the chip.
+ * We use a struct cpumask for this, so it must be big enough.
+ */
+ if ((smp_height * smp_width) > nr_cpu_ids)
+ early_panic("Hypervisor %d x %d grid too big for Linux"
+ " NR_CPUS %d\n", smp_height, smp_width,
+ nr_cpu_ids);
+#endif
+
+ /*
+ * Check that we're using allowed ASIDs, and initialize the
+ * various asid variables to their appropriate initial states.
+ */
+ asid_range = hv_inquire_asid(0);
+ __get_cpu_var(current_asid) = min_asid = asid_range.start;
+ max_asid = asid_range.start + asid_range.size - 1;
+
+ if (hv_confstr(HV_CONFSTR_CHIP_MODEL, (HV_VirtAddr)chip_model,
+ sizeof(chip_model)) < 0) {
+ printk("Warning: HV_CONFSTR_CHIP_MODEL not available\n");
+ strlcpy(chip_model, "unknown", sizeof(chip_model));
+ }
+}
+
+static void __init validate_va(void)
+{
+#ifndef __tilegx__ /* FIXME: GX: probably some validation relevant here */
+ /*
+ * Similarly, make sure we're only using allowed VAs.
+ * We assume we can contiguously use MEM_USER_INTRPT .. MEM_HV_INTRPT,
+ * and 0 .. KERNEL_HIGH_VADDR.
+ * In addition, make sure we CAN'T use the end of memory, since
+ * we use the last chunk of each pgd for the pgd_list.
+ */
+ int i, fc_fd_ok = 0;
+ unsigned long max_va = 0;
+ unsigned long list_va =
+ ((PGD_LIST_OFFSET / sizeof(pgd_t)) << PGDIR_SHIFT);
+
+ for (i = 0; ; ++i) {
+ HV_VirtAddrRange range = hv_inquire_virtual(i);
+ if (range.size == 0)
+ break;
+ if (range.start <= MEM_USER_INTRPT &&
+ range.start + range.size >= MEM_HV_INTRPT)
+ fc_fd_ok = 1;
+ if (range.start == 0)
+ max_va = range.size;
+ BUG_ON(range.start + range.size > list_va);
+ }
+ if (!fc_fd_ok)
+ early_panic("Hypervisor not configured for VAs 0xfc/0xfd\n");
+ if (max_va == 0)
+ early_panic("Hypervisor not configured for low VAs\n");
+ if (max_va < KERNEL_HIGH_VADDR)
+ early_panic("Hypervisor max VA %#lx smaller than %#lx\n",
+ max_va, KERNEL_HIGH_VADDR);
+
+ /* Kernel PCs must have their high bit set; see intvec.S. */
+ if ((long)VMALLOC_START >= 0)
+ early_panic(
+ "Linux VMALLOC region below the 2GB line (%#lx)!\n"
+ "Reconfigure the kernel with fewer NR_HUGE_VMAPS\n"
+ "or smaller VMALLOC_RESERVE.\n",
+ VMALLOC_START);
+#endif
+}
+
+/*
+ * cpu_lotar_map lists all the cpus that are valid for the supervisor
+ * to cache data on at a page level, i.e. what cpus can be placed in
+ * the LOTAR field of a PTE. It is equivalent to the set of possible
+ * cpus plus any other cpus that are willing to share their cache.
+ * It is set by hv_inquire_tiles(HV_INQ_TILES_LOTAR).
+ */
+struct cpumask __write_once cpu_lotar_map;
+EXPORT_SYMBOL(cpu_lotar_map);
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+/*
+ * hash_for_home_map lists all the tiles that hash-for-home data
+ * will be cached on. Note that this may includes tiles that are not
+ * valid for this supervisor to use otherwise (e.g. if a hypervisor
+ * device is being shared between multiple supervisors).
+ * It is set by hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE).
+ */
+struct cpumask hash_for_home_map;
+EXPORT_SYMBOL(hash_for_home_map);
+#endif
+
+/*
+ * cpu_cacheable_map lists all the cpus whose caches the hypervisor can
+ * flush on our behalf. It is set to cpu_possible_map OR'ed with
+ * hash_for_home_map, and it is what should be passed to
+ * hv_flush_remote() to flush all caches. Note that if there are
+ * dedicated hypervisor driver tiles that have authorized use of their
+ * cache, those tiles will only appear in cpu_lotar_map, NOT in
+ * cpu_cacheable_map, as they are a special case.
+ */
+struct cpumask __write_once cpu_cacheable_map;
+EXPORT_SYMBOL(cpu_cacheable_map);
+
+static __initdata struct cpumask disabled_map;
+
+static int __init disabled_cpus(char *str)
+{
+ int boot_cpu = smp_processor_id();
+
+ if (str == NULL || cpulist_parse_crop(str, &disabled_map) != 0)
+ return -EINVAL;
+ if (cpumask_test_cpu(boot_cpu, &disabled_map)) {
+ printk("disabled_cpus: can't disable boot cpu %d\n", boot_cpu);
+ cpumask_clear_cpu(boot_cpu, &disabled_map);
+ }
+ return 0;
+}
+
+early_param("disabled_cpus", disabled_cpus);
+
+void __init print_disabled_cpus()
+{
+ if (!cpumask_empty(&disabled_map)) {
+ char buf[100];
+ cpulist_scnprintf(buf, sizeof(buf), &disabled_map);
+ printk(KERN_INFO "CPUs not available for Linux: %s\n", buf);
+ }
+}
+
+static void __init setup_cpu_maps(void)
+{
+ struct cpumask hv_disabled_map, cpu_possible_init;
+ int boot_cpu = smp_processor_id();
+ int cpus, i, rc;
+
+ /* Learn which cpus are allowed by the hypervisor. */
+ rc = hv_inquire_tiles(HV_INQ_TILES_AVAIL,
+ (HV_VirtAddr) cpumask_bits(&cpu_possible_init),
+ sizeof(cpu_cacheable_map));
+ if (rc < 0)
+ early_panic("hv_inquire_tiles(AVAIL) failed: rc %d\n", rc);
+ if (!cpumask_test_cpu(boot_cpu, &cpu_possible_init))
+ early_panic("Boot CPU %d disabled by hypervisor!\n", boot_cpu);
+
+ /* Compute the cpus disabled by the hvconfig file. */
+ cpumask_complement(&hv_disabled_map, &cpu_possible_init);
+
+ /* Include them with the cpus disabled by "disabled_cpus". */
+ cpumask_or(&disabled_map, &disabled_map, &hv_disabled_map);
+
+ /*
+ * Disable every cpu after "setup_max_cpus". But don't mark
+ * as disabled the cpus that are outside of our initial rectangle,
+ * since that turns out to be confusing.
+ */
+ cpus = 1; /* this cpu */
+ cpumask_set_cpu(boot_cpu, &disabled_map); /* ignore this cpu */
+ for (i = 0; cpus < setup_max_cpus; ++i)
+ if (!cpumask_test_cpu(i, &disabled_map))
+ ++cpus;
+ for (; i < smp_height * smp_width; ++i)
+ cpumask_set_cpu(i, &disabled_map);
+ cpumask_clear_cpu(boot_cpu, &disabled_map); /* reset this cpu */
+ for (i = smp_height * smp_width; i < NR_CPUS; ++i)
+ cpumask_clear_cpu(i, &disabled_map);
+
+ /*
+ * Setup cpu_possible map as every cpu allocated to us, minus
+ * the results of any "disabled_cpus" settings.
+ */
+ cpumask_andnot(&cpu_possible_init, &cpu_possible_init, &disabled_map);
+ init_cpu_possible(&cpu_possible_init);
+
+ /* Learn which cpus are valid for LOTAR caching. */
+ rc = hv_inquire_tiles(HV_INQ_TILES_LOTAR,
+ (HV_VirtAddr) cpumask_bits(&cpu_lotar_map),
+ sizeof(cpu_lotar_map));
+ if (rc < 0) {
+ printk("warning: no HV_INQ_TILES_LOTAR; using AVAIL\n");
+ cpu_lotar_map = cpu_possible_map;
+ }
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ /* Retrieve set of CPUs used for hash-for-home caching */
+ rc = hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE,
+ (HV_VirtAddr) hash_for_home_map.bits,
+ sizeof(hash_for_home_map));
+ if (rc < 0)
+ early_panic("hv_inquire_tiles(HFH_CACHE) failed: rc %d\n", rc);
+ cpumask_or(&cpu_cacheable_map, &cpu_possible_map, &hash_for_home_map);
+#else
+ cpu_cacheable_map = cpu_possible_map;
+#endif
+}
+
+
+static int __init dataplane(char *str)
+{
+ printk("WARNING: dataplane support disabled in this kernel\n");
+ return 0;
+}
+
+early_param("dataplane", dataplane);
+
+#ifdef CONFIG_CMDLINE_BOOL
+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+ int len;
+
+#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
+ len = hv_get_command_line((HV_VirtAddr) boot_command_line,
+ COMMAND_LINE_SIZE);
+ if (boot_command_line[0])
+ printk("WARNING: ignoring dynamic command line \"%s\"\n",
+ boot_command_line);
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+ char *hv_cmdline;
+#if defined(CONFIG_CMDLINE_BOOL)
+ if (builtin_cmdline[0]) {
+ int builtin_len = strlcpy(boot_command_line, builtin_cmdline,
+ COMMAND_LINE_SIZE);
+ if (builtin_len < COMMAND_LINE_SIZE-1)
+ boot_command_line[builtin_len++] = ' ';
+ hv_cmdline = &boot_command_line[builtin_len];
+ len = COMMAND_LINE_SIZE - builtin_len;
+ } else
+#endif
+ {
+ hv_cmdline = boot_command_line;
+ len = COMMAND_LINE_SIZE;
+ }
+ len = hv_get_command_line((HV_VirtAddr) hv_cmdline, len);
+ if (len < 0 || len > COMMAND_LINE_SIZE)
+ early_panic("hv_get_command_line failed: %d\n", len);
+#endif
+
+ *cmdline_p = boot_command_line;
+
+ /* Set disabled_map and setup_max_cpus very early */
+ parse_early_param();
+
+ /* Make sure the kernel is compatible with the hypervisor. */
+ validate_hv();
+ validate_va();
+
+ setup_cpu_maps();
+
+
+#ifdef CONFIG_PCI
+ /*
+ * Initialize the PCI structures. This is done before memory
+ * setup so that we know whether or not a pci_reserve region
+ * is necessary.
+ */
+ if (tile_pci_init() == 0)
+ pci_reserve_mb = 0;
+
+ /* PCI systems reserve a region just below 4GB for mapping iomem. */
+ pci_reserve_end_pfn = (1 << (32 - PAGE_SHIFT));
+ pci_reserve_start_pfn = pci_reserve_end_pfn -
+ (pci_reserve_mb << (20 - PAGE_SHIFT));
+#endif
+
+ init_mm.start_code = (unsigned long) _text;
+ init_mm.end_code = (unsigned long) _etext;
+ init_mm.end_data = (unsigned long) _edata;
+ init_mm.brk = (unsigned long) _end;
+
+ setup_memory();
+ store_permanent_mappings();
+ setup_bootmem_allocator();
+
+ /*
+ * NOTE: before this point _nobody_ is allowed to allocate
+ * any memory using the bootmem allocator.
+ */
+
+ paging_init();
+ setup_numa_mapping();
+ zone_sizes_init();
+ set_page_homes();
+ setup_mpls();
+ setup_clock();
+ load_hv_initrd();
+}
+
+
+/*
+ * Set up per-cpu memory.
+ */
+
+unsigned long __per_cpu_offset[NR_CPUS] __write_once;
+EXPORT_SYMBOL(__per_cpu_offset);
+
+static size_t __initdata pfn_offset[MAX_NUMNODES] = { 0 };
+static unsigned long __initdata percpu_pfn[NR_CPUS] = { 0 };
+
+/*
+ * As the percpu code allocates pages, we return the pages from the
+ * end of the node for the specified cpu.
+ */
+static void *__init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align)
+{
+ int nid = cpu_to_node(cpu);
+ unsigned long pfn = node_percpu_pfn[nid] + pfn_offset[nid];
+
+ BUG_ON(size % PAGE_SIZE != 0);
+ pfn_offset[nid] += size / PAGE_SIZE;
+ if (percpu_pfn[cpu] == 0)
+ percpu_pfn[cpu] = pfn;
+ return pfn_to_kaddr(pfn);
+}
+
+/*
+ * Pages reserved for percpu memory are not freeable, and in any case we are
+ * on a short path to panic() in setup_per_cpu_area() at this point anyway.
+ */
+static void __init pcpu_fc_free(void *ptr, size_t size)
+{
+}
+
+/*
+ * Set up vmalloc page tables using bootmem for the percpu code.
+ */
+static void __init pcpu_fc_populate_pte(unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ BUG_ON(pgd_addr_invalid(addr));
+
+ pgd = swapper_pg_dir + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ BUG_ON(!pud_present(*pud));
+ pmd = pmd_offset(pud, addr);
+ if (pmd_present(*pmd)) {
+ BUG_ON(pmd_huge_page(*pmd));
+ } else {
+ pte = __alloc_bootmem(L2_KERNEL_PGTABLE_SIZE,
+ HV_PAGE_TABLE_ALIGN, 0);
+ pmd_populate_kernel(&init_mm, pmd, pte);
+ }
+}
+
+void __init setup_per_cpu_areas(void)
+{
+ struct page *pg;
+ unsigned long delta, pfn, lowmem_va;
+ unsigned long size = percpu_size();
+ char *ptr;
+ int rc, cpu, i;
+
+ rc = pcpu_page_first_chunk(PERCPU_MODULE_RESERVE, pcpu_fc_alloc,
+ pcpu_fc_free, pcpu_fc_populate_pte);
+ if (rc < 0)
+ panic("Cannot initialize percpu area (err=%d)", rc);
+
+ delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start;
+ for_each_possible_cpu(cpu) {
+ __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu];
+
+ /* finv the copy out of cache so we can change homecache */
+ ptr = pcpu_base_addr + pcpu_unit_offsets[cpu];
+ __finv_buffer(ptr, size);
+ pfn = percpu_pfn[cpu];
+
+ /* Rewrite the page tables to cache on that cpu */
+ pg = pfn_to_page(pfn);
+ for (i = 0; i < size; i += PAGE_SIZE, ++pfn, ++pg) {
+
+ /* Update the vmalloc mapping and page home. */
+ pte_t *ptep =
+ virt_to_pte(NULL, (unsigned long)ptr + i);
+ pte_t pte = *ptep;
+ BUG_ON(pfn != pte_pfn(pte));
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
+ pte = set_remote_cache_cpu(pte, cpu);
+ set_pte(ptep, pte);
+
+ /* Update the lowmem mapping for consistency. */
+ lowmem_va = (unsigned long)pfn_to_kaddr(pfn);
+ ptep = virt_to_pte(NULL, lowmem_va);
+ if (pte_huge(*ptep)) {
+ printk(KERN_DEBUG "early shatter of huge page"
+ " at %#lx\n", lowmem_va);
+ shatter_pmd((pmd_t *)ptep);
+ ptep = virt_to_pte(NULL, lowmem_va);
+ BUG_ON(pte_huge(*ptep));
+ }
+ BUG_ON(pfn != pte_pfn(*ptep));
+ set_pte(ptep, pte);
+ }
+ }
+
+ /* Set our thread pointer appropriately. */
+ set_my_cpu_offset(__per_cpu_offset[smp_processor_id()]);
+
+ /* Make sure the finv's have completed. */
+ mb_incoherent();
+
+ /* Flush the TLB so we reference it properly from here on out. */
+ local_flush_tlb_all();
+}
+
+static struct resource data_resource = {
+ .name = "Kernel data",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+static struct resource code_resource = {
+ .name = "Kernel code",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+/*
+ * We reserve all resources above 4GB so that PCI won't try to put
+ * mappings above 4GB; the standard allows that for some devices but
+ * the probing code trunates values to 32 bits.
+ */
+#ifdef CONFIG_PCI
+static struct resource* __init
+insert_non_bus_resource(void)
+{
+ struct resource *res =
+ kzalloc(sizeof(struct resource), GFP_ATOMIC);
+ res->name = "Non-Bus Physical Address Space";
+ res->start = (1ULL << 32);
+ res->end = -1LL;
+ res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ if (insert_resource(&iomem_resource, res)) {
+ kfree(res);
+ return NULL;
+ }
+ return res;
+}
+#endif
+
+static struct resource* __init
+insert_ram_resource(u64 start_pfn, u64 end_pfn)
+{
+ struct resource *res =
+ kzalloc(sizeof(struct resource), GFP_ATOMIC);
+ res->name = "System RAM";
+ res->start = start_pfn << PAGE_SHIFT;
+ res->end = (end_pfn << PAGE_SHIFT) - 1;
+ res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+ if (insert_resource(&iomem_resource, res)) {
+ kfree(res);
+ return NULL;
+ }
+ return res;
+}
+
+/*
+ * Request address space for all standard resources
+ *
+ * If the system includes PCI root complex drivers, we need to create
+ * a window just below 4GB where PCI BARs can be mapped.
+ */
+static int __init request_standard_resources(void)
+{
+ int i;
+ enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET };
+
+ iomem_resource.end = -1LL;
+#ifdef CONFIG_PCI
+ insert_non_bus_resource();
+#endif
+
+ for_each_online_node(i) {
+ u64 start_pfn = node_start_pfn[i];
+ u64 end_pfn = node_end_pfn[i];
+
+#ifdef CONFIG_PCI
+ if (start_pfn <= pci_reserve_start_pfn &&
+ end_pfn > pci_reserve_start_pfn) {
+ if (end_pfn > pci_reserve_end_pfn)
+ insert_ram_resource(pci_reserve_end_pfn,
+ end_pfn);
+ end_pfn = pci_reserve_start_pfn;
+ }
+#endif
+ insert_ram_resource(start_pfn, end_pfn);
+ }
+
+ code_resource.start = __pa(_text - CODE_DELTA);
+ code_resource.end = __pa(_etext - CODE_DELTA)-1;
+ data_resource.start = __pa(_sdata);
+ data_resource.end = __pa(_end)-1;
+
+ insert_resource(&iomem_resource, &code_resource);
+ insert_resource(&iomem_resource, &data_resource);
+
+#ifdef CONFIG_KEXEC
+ insert_resource(&iomem_resource, &crashk_res);
+#endif
+
+ return 0;
+}
+
+subsys_initcall(request_standard_resources);
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
new file mode 100644
index 000000000000..45835cfad407
--- /dev/null
+++ b/arch/tile/kernel/signal.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <linux/suspend.h>
+#include <linux/ptrace.h>
+#include <linux/elf.h>
+#include <linux/compat.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/ucontext.h>
+#include <asm/sigframe.h>
+#include <arch/interrupts.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+
+/* Caller before callee in this file; other callee is in assembler */
+void do_signal(struct pt_regs *regs);
+
+long _sys_sigaltstack(const stack_t __user *uss,
+ stack_t __user *uoss, struct pt_regs *regs)
+{
+ return do_sigaltstack(uss, uoss, regs->sp);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+int restore_sigcontext(struct pt_regs *regs,
+ struct sigcontext __user *sc, long *pr0)
+{
+ int err = 0;
+ int i;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
+ err |= __get_user(((long *)regs)[i],
+ &((long *)(&sc->regs))[i]);
+
+ regs->faultnum = INT_SWINT_1_SIGRETURN;
+
+ err |= __get_user(*pr0, &sc->regs.regs[0]);
+ return err;
+}
+
+int _sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe __user *frame =
+ (struct rt_sigframe __user *)(regs->sp);
+ sigset_t set;
+ long r0;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ sigdelsetmask(&set, ~_BLOCKABLE);
+ spin_lock_irq(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &r0))
+ goto badframe;
+
+ if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->sp) == -EFAULT)
+ goto badframe;
+
+ return r0;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
+{
+ int i, err = 0;
+
+ for (i = 0; i < sizeof(struct pt_regs)/sizeof(long); ++i)
+ err |= __put_user(((long *)regs)[i],
+ &((long *)(&sc->regs))[i]);
+
+ return err;
+}
+
+/*
+ * Determine which stack to use..
+ */
+static inline void __user *get_sigframe(struct k_sigaction *ka,
+ struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long sp;
+
+ /* Default to using normal stack */
+ sp = regs->sp;
+
+ /*
+ * If we are on the alternate signal stack and would overflow
+ * it, don't. Return an always-bogus address instead so we
+ * will die with SIGSEGV.
+ */
+ if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size)))
+ return (void __user *) -1L;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ if (ka->sa.sa_flags & SA_ONSTACK) {
+ if (sas_ss_flags(sp) == 0)
+ sp = current->sas_ss_sp + current->sas_ss_size;
+ }
+
+ sp -= frame_size;
+ /*
+ * Align the stack pointer according to the TILE ABI,
+ * i.e. so that on function entry (sp & 15) == 0.
+ */
+ sp &= -16UL;
+ return (void __user *) sp;
+}
+
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+ sigset_t *set, struct pt_regs *regs)
+{
+ unsigned long restorer;
+ struct rt_sigframe __user *frame;
+ int err = 0;
+ int usig;
+
+ frame = get_sigframe(ka, regs, sizeof(*frame));
+
+ if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
+ goto give_sigsegv;
+
+ usig = current_thread_info()->exec_domain
+ && current_thread_info()->exec_domain->signal_invmap
+ && sig < 32
+ ? current_thread_info()->exec_domain->signal_invmap[sig]
+ : sig;
+
+ /* Always write at least the signal number for the stack backtracer. */
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* At sigreturn time, restore the callee-save registers too. */
+ err |= copy_siginfo_to_user(&frame->info, info);
+ regs->flags |= PT_FLAGS_RESTORE_REGS;
+ } else {
+ err |= __put_user(info->si_signo, &frame->info.si_signo);
+ }
+
+ /* Create the ucontext. */
+ err |= __clear_user(&frame->save_area, sizeof(frame->save_area));
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user((void *)(current->sas_ss_sp),
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->sp),
+ &frame->uc.uc_stack.ss_flags);
+ err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ if (err)
+ goto give_sigsegv;
+
+ restorer = VDSO_BASE;
+ if (ka->sa.sa_flags & SA_RESTORER)
+ restorer = (unsigned long) ka->sa.sa_restorer;
+
+ /*
+ * Set up registers for signal handler.
+ * Registers that we don't modify keep the value they had from
+ * user-space at the time we took the signal.
+ */
+ regs->pc = (unsigned long) ka->sa.sa_handler;
+ regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */
+ regs->sp = (unsigned long) frame;
+ regs->lr = restorer;
+ regs->regs[0] = (unsigned long) usig;
+
+ if (ka->sa.sa_flags & SA_SIGINFO) {
+ /* Need extra arguments, so mark to restore caller-saves. */
+ regs->regs[1] = (unsigned long) &frame->info;
+ regs->regs[2] = (unsigned long) &frame->uc;
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+ }
+
+ /*
+ * Notify any tracer that was single-stepping it.
+ * The tracer may want to single-step inside the
+ * handler too.
+ */
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(sig, current);
+ return -EFAULT;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+
+static int handle_signal(unsigned long sig, siginfo_t *info,
+ struct k_sigaction *ka, sigset_t *oldset,
+ struct pt_regs *regs)
+{
+ int ret;
+
+
+ /* Are we from a system call? */
+ if (regs->faultnum == INT_SWINT_1) {
+ /* If so, check system call restarting.. */
+ switch (regs->regs[0]) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ regs->regs[0] = -EINTR;
+ break;
+
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ regs->regs[0] = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case -ERESTARTNOINTR:
+ /* Reload caller-saves to restore r0..r5 and r10. */
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+ regs->regs[0] = regs->orig_r0;
+ regs->pc -= 8;
+ }
+ }
+
+ /* Set up the stack frame */
+#ifdef CONFIG_COMPAT
+ if (is_compat_task())
+ ret = compat_setup_rt_frame(sig, ka, info, oldset, regs);
+ else
+#endif
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
+ if (ret == 0) {
+ /* This code is only called from system calls or from
+ * the work_pending path in the return-to-user code, and
+ * either way we can re-enable interrupts unconditionally.
+ */
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,
+ &current->blocked, &ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked, sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ return ret;
+}
+
+/*
+ * Note that 'init' is a special process: it doesn't get signals it doesn't
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+void do_signal(struct pt_regs *regs)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+ sigset_t *oldset;
+
+ /*
+ * i386 will check if we're coming from kernel mode and bail out
+ * here. In my experience this just turns weird crashes into
+ * weird spin-hangs. But if we find a case where this seems
+ * helpful, we can reinstate the check on "!user_mode(regs)".
+ */
+
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
+ oldset = &current->saved_sigmask;
+ else
+ oldset = &current->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+ /*
+ * A signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+ }
+
+ return;
+ }
+
+ /* Did we come from a system call? */
+ if (regs->faultnum == INT_SWINT_1) {
+ /* Restart the system call - no handlers present */
+ switch (regs->regs[0]) {
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+ regs->regs[0] = regs->orig_r0;
+ regs->pc -= 8;
+ break;
+
+ case -ERESTART_RESTARTBLOCK:
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+ regs->regs[TREG_SYSCALL_NR] = __NR_restart_syscall;
+ regs->pc -= 8;
+ break;
+ }
+ }
+
+ /* If there's no signal to deliver, just put the saved sigmask back. */
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+}
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c
new file mode 100644
index 000000000000..266aae123632
--- /dev/null
+++ b/arch/tile/kernel/single_step.c
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * A code-rewriter that enables instruction single-stepping.
+ * Derived from iLib's single-stepping code.
+ */
+
+#ifndef __tilegx__ /* No support for single-step yet. */
+
+/* These functions are only used on the TILE platform */
+#include <linux/slab.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+#include <linux/mman.h>
+#include <linux/types.h>
+#include <asm/cacheflush.h>
+#include <asm/opcode-tile.h>
+#include <asm/opcode_constants.h>
+#include <arch/abi.h>
+
+#define signExtend17(val) sign_extend((val), 17)
+#define TILE_X1_MASK (0xffffffffULL << 31)
+
+int unaligned_printk;
+
+static int __init setup_unaligned_printk(char *str)
+{
+ long val;
+ if (strict_strtol(str, 0, &val) != 0)
+ return 0;
+ unaligned_printk = val;
+ printk("Printk for each unaligned data accesses is %s\n",
+ unaligned_printk ? "enabled" : "disabled");
+ return 1;
+}
+__setup("unaligned_printk=", setup_unaligned_printk);
+
+unsigned int unaligned_fixup_count;
+
+enum mem_op {
+ MEMOP_NONE,
+ MEMOP_LOAD,
+ MEMOP_STORE,
+ MEMOP_LOAD_POSTINCR,
+ MEMOP_STORE_POSTINCR
+};
+
+static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, int32_t offset)
+{
+ tile_bundle_bits result;
+
+ /* mask out the old offset */
+ tile_bundle_bits mask = create_BrOff_X1(-1);
+ result = n & (~mask);
+
+ /* or in the new offset */
+ result |= create_BrOff_X1(offset);
+
+ return result;
+}
+
+static inline tile_bundle_bits move_X1(tile_bundle_bits n, int dest, int src)
+{
+ tile_bundle_bits result;
+ tile_bundle_bits op;
+
+ result = n & (~TILE_X1_MASK);
+
+ op = create_Opcode_X1(SPECIAL_0_OPCODE_X1) |
+ create_RRROpcodeExtension_X1(OR_SPECIAL_0_OPCODE_X1) |
+ create_Dest_X1(dest) |
+ create_SrcB_X1(TREG_ZERO) |
+ create_SrcA_X1(src) ;
+
+ result |= op;
+ return result;
+}
+
+static inline tile_bundle_bits nop_X1(tile_bundle_bits n)
+{
+ return move_X1(n, TREG_ZERO, TREG_ZERO);
+}
+
+static inline tile_bundle_bits addi_X1(
+ tile_bundle_bits n, int dest, int src, int imm)
+{
+ n &= ~TILE_X1_MASK;
+
+ n |= (create_SrcA_X1(src) |
+ create_Dest_X1(dest) |
+ create_Imm8_X1(imm) |
+ create_S_X1(0) |
+ create_Opcode_X1(IMM_0_OPCODE_X1) |
+ create_ImmOpcodeExtension_X1(ADDI_IMM_0_OPCODE_X1));
+
+ return n;
+}
+
+static tile_bundle_bits rewrite_load_store_unaligned(
+ struct single_step_state *state,
+ tile_bundle_bits bundle,
+ struct pt_regs *regs,
+ enum mem_op mem_op,
+ int size, int sign_ext)
+{
+ unsigned char *addr;
+ int val_reg, addr_reg, err, val;
+
+ /* Get address and value registers */
+ if (bundle & TILE_BUNDLE_Y_ENCODING_MASK) {
+ addr_reg = get_SrcA_Y2(bundle);
+ val_reg = get_SrcBDest_Y2(bundle);
+ } else if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) {
+ addr_reg = get_SrcA_X1(bundle);
+ val_reg = get_Dest_X1(bundle);
+ } else {
+ addr_reg = get_SrcA_X1(bundle);
+ val_reg = get_SrcB_X1(bundle);
+ }
+
+ /*
+ * If registers are not GPRs, don't try to handle it.
+ *
+ * FIXME: we could handle non-GPR loads by getting the real value
+ * from memory, writing it to the single step buffer, using a
+ * temp_reg to hold a pointer to that memory, then executing that
+ * instruction and resetting temp_reg. For non-GPR stores, it's a
+ * little trickier; we could use the single step buffer for that
+ * too, but we'd have to add some more state bits so that we could
+ * call back in here to copy that value to the real target. For
+ * now, we just handle the simple case.
+ */
+ if ((val_reg >= PTREGS_NR_GPRS &&
+ (val_reg != TREG_ZERO ||
+ mem_op == MEMOP_LOAD ||
+ mem_op == MEMOP_LOAD_POSTINCR)) ||
+ addr_reg >= PTREGS_NR_GPRS)
+ return bundle;
+
+ /* If it's aligned, don't handle it specially */
+ addr = (void *)regs->regs[addr_reg];
+ if (((unsigned long)addr % size) == 0)
+ return bundle;
+
+#ifndef __LITTLE_ENDIAN
+# error We assume little-endian representation with copy_xx_user size 2 here
+#endif
+ /* Handle unaligned load/store */
+ if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) {
+ unsigned short val_16;
+ switch (size) {
+ case 2:
+ err = copy_from_user(&val_16, addr, sizeof(val_16));
+ val = sign_ext ? ((short)val_16) : val_16;
+ break;
+ case 4:
+ err = copy_from_user(&val, addr, sizeof(val));
+ break;
+ default:
+ BUG();
+ }
+ if (err == 0) {
+ state->update_reg = val_reg;
+ state->update_value = val;
+ state->update = 1;
+ }
+ } else {
+ val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg];
+ err = copy_to_user(addr, &val, size);
+ }
+
+ if (err) {
+ siginfo_t info = {
+ .si_signo = SIGSEGV,
+ .si_code = SEGV_MAPERR,
+ .si_addr = (void __user *)addr
+ };
+ force_sig_info(info.si_signo, &info, current);
+ return (tile_bundle_bits) 0;
+ }
+
+ if (unaligned_fixup == 0) {
+ siginfo_t info = {
+ .si_signo = SIGBUS,
+ .si_code = BUS_ADRALN,
+ .si_addr = (void __user *)addr
+ };
+ force_sig_info(info.si_signo, &info, current);
+ return (tile_bundle_bits) 0;
+ }
+
+ if (unaligned_printk || unaligned_fixup_count == 0) {
+ printk("Process %d/%s: PC %#lx: Fixup of"
+ " unaligned %s at %#lx.\n",
+ current->pid, current->comm, regs->pc,
+ (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) ?
+ "load" : "store",
+ (unsigned long)addr);
+ if (!unaligned_printk) {
+ printk("\n"
+"Unaligned fixups in the kernel will slow your application considerably.\n"
+"You can find them by writing \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n"
+"which requests the kernel show all unaligned fixups, or writing a \"0\"\n"
+"to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n"
+"access will become a SIGBUS you can debug. No further warnings will be\n"
+"shown so as to avoid additional slowdown, but you can track the number\n"
+"of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n"
+"Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n"
+ "\n");
+ }
+ }
+ ++unaligned_fixup_count;
+
+ if (bundle & TILE_BUNDLE_Y_ENCODING_MASK) {
+ /* Convert the Y2 instruction to a prefetch. */
+ bundle &= ~(create_SrcBDest_Y2(-1) |
+ create_Opcode_Y2(-1));
+ bundle |= (create_SrcBDest_Y2(TREG_ZERO) |
+ create_Opcode_Y2(LW_OPCODE_Y2));
+ /* Replace the load postincr with an addi */
+ } else if (mem_op == MEMOP_LOAD_POSTINCR) {
+ bundle = addi_X1(bundle, addr_reg, addr_reg,
+ get_Imm8_X1(bundle));
+ /* Replace the store postincr with an addi */
+ } else if (mem_op == MEMOP_STORE_POSTINCR) {
+ bundle = addi_X1(bundle, addr_reg, addr_reg,
+ get_Dest_Imm8_X1(bundle));
+ } else {
+ /* Convert the X1 instruction to a nop. */
+ bundle &= ~(create_Opcode_X1(-1) |
+ create_UnShOpcodeExtension_X1(-1) |
+ create_UnOpcodeExtension_X1(-1));
+ bundle |= (create_Opcode_X1(SHUN_0_OPCODE_X1) |
+ create_UnShOpcodeExtension_X1(
+ UN_0_SHUN_0_OPCODE_X1) |
+ create_UnOpcodeExtension_X1(
+ NOP_UN_0_SHUN_0_OPCODE_X1));
+ }
+
+ return bundle;
+}
+
+/**
+ * single_step_once() - entry point when single stepping has been triggered.
+ * @regs: The machine register state
+ *
+ * When we arrive at this routine via a trampoline, the single step
+ * engine copies the executing bundle to the single step buffer.
+ * If the instruction is a condition branch, then the target is
+ * reset to one past the next instruction. If the instruction
+ * sets the lr, then that is noted. If the instruction is a jump
+ * or call, then the new target pc is preserved and the current
+ * bundle instruction set to null.
+ *
+ * The necessary post-single-step rewriting information is stored in
+ * single_step_state-> We use data segment values because the
+ * stack will be rewound when we run the rewritten single-stepped
+ * instruction.
+ */
+void single_step_once(struct pt_regs *regs)
+{
+ extern tile_bundle_bits __single_step_ill_insn;
+ extern tile_bundle_bits __single_step_j_insn;
+ extern tile_bundle_bits __single_step_addli_insn;
+ extern tile_bundle_bits __single_step_auli_insn;
+ struct thread_info *info = (void *)current_thread_info();
+ struct single_step_state *state = info->step_state;
+ int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP);
+ tile_bundle_bits *buffer, *pc;
+ tile_bundle_bits bundle;
+ int temp_reg;
+ int target_reg = TREG_LR;
+ int err;
+ enum mem_op mem_op = MEMOP_NONE;
+ int size = 0, sign_ext = 0; /* happy compiler */
+
+ asm(
+" .pushsection .rodata.single_step\n"
+" .align 8\n"
+" .globl __single_step_ill_insn\n"
+"__single_step_ill_insn:\n"
+" ill\n"
+" .globl __single_step_addli_insn\n"
+"__single_step_addli_insn:\n"
+" { nop; addli r0, zero, 0 }\n"
+" .globl __single_step_auli_insn\n"
+"__single_step_auli_insn:\n"
+" { nop; auli r0, r0, 0 }\n"
+" .globl __single_step_j_insn\n"
+"__single_step_j_insn:\n"
+" j .\n"
+" .popsection\n"
+ );
+
+ if (state == NULL) {
+ /* allocate a page of writable, executable memory */
+ state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL);
+ if (state == NULL) {
+ printk("Out of kernel memory trying to single-step\n");
+ return;
+ }
+
+ /* allocate a cache line of writable, executable memory */
+ down_write(&current->mm->mmap_sem);
+ buffer = (void *) do_mmap(0, 0, 64,
+ PROT_EXEC | PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ 0);
+ up_write(&current->mm->mmap_sem);
+
+ if ((int)buffer < 0 && (int)buffer > -PAGE_SIZE) {
+ kfree(state);
+ printk("Out of kernel pages trying to single-step\n");
+ return;
+ }
+
+ state->buffer = buffer;
+ state->is_enabled = 0;
+
+ info->step_state = state;
+
+ /* Validate our stored instruction patterns */
+ BUG_ON(get_Opcode_X1(__single_step_addli_insn) !=
+ ADDLI_OPCODE_X1);
+ BUG_ON(get_Opcode_X1(__single_step_auli_insn) !=
+ AULI_OPCODE_X1);
+ BUG_ON(get_SrcA_X1(__single_step_addli_insn) != TREG_ZERO);
+ BUG_ON(get_Dest_X1(__single_step_addli_insn) != 0);
+ BUG_ON(get_JOffLong_X1(__single_step_j_insn) != 0);
+ }
+
+ /*
+ * If we are returning from a syscall, we still haven't hit the
+ * "ill" for the swint1 instruction. So back the PC up to be
+ * pointing at the swint1, but we'll actually return directly
+ * back to the "ill" so we come back in via SIGILL as if we
+ * had "executed" the swint1 without ever being in kernel space.
+ */
+ if (regs->faultnum == INT_SWINT_1)
+ regs->pc -= 8;
+
+ pc = (tile_bundle_bits *)(regs->pc);
+ bundle = pc[0];
+
+ /* We'll follow the instruction with 2 ill op bundles */
+ state->orig_pc = (unsigned long) pc;
+ state->next_pc = (unsigned long)(pc + 1);
+ state->branch_next_pc = 0;
+ state->update = 0;
+
+ if (!(bundle & TILE_BUNDLE_Y_ENCODING_MASK)) {
+ /* two wide, check for control flow */
+ int opcode = get_Opcode_X1(bundle);
+
+ switch (opcode) {
+ /* branches */
+ case BRANCH_OPCODE_X1:
+ {
+ int32_t offset = signExtend17(get_BrOff_X1(bundle));
+
+ /*
+ * For branches, we use a rewriting trick to let the
+ * hardware evaluate whether the branch is taken or
+ * untaken. We record the target offset and then
+ * rewrite the branch instruction to target 1 insn
+ * ahead if the branch is taken. We then follow the
+ * rewritten branch with two bundles, each containing
+ * an "ill" instruction. The supervisor examines the
+ * pc after the single step code is executed, and if
+ * the pc is the first ill instruction, then the
+ * branch (if any) was not taken. If the pc is the
+ * second ill instruction, then the branch was
+ * taken. The new pc is computed for these cases, and
+ * inserted into the registers for the thread. If
+ * the pc is the start of the single step code, then
+ * an exception or interrupt was taken before the
+ * code started processing, and the same "original"
+ * pc is restored. This change, different from the
+ * original implementation, has the advantage of
+ * executing a single user instruction.
+ */
+ state->branch_next_pc = (unsigned long)(pc + offset);
+
+ /* rewrite branch offset to go forward one bundle */
+ bundle = set_BrOff_X1(bundle, 2);
+ }
+ break;
+
+ /* jumps */
+ case JALB_OPCODE_X1:
+ case JALF_OPCODE_X1:
+ state->update = 1;
+ state->next_pc =
+ (unsigned long) (pc + get_JOffLong_X1(bundle));
+ break;
+
+ case JB_OPCODE_X1:
+ case JF_OPCODE_X1:
+ state->next_pc =
+ (unsigned long) (pc + get_JOffLong_X1(bundle));
+ bundle = nop_X1(bundle);
+ break;
+
+ case SPECIAL_0_OPCODE_X1:
+ switch (get_RRROpcodeExtension_X1(bundle)) {
+ /* jump-register */
+ case JALRP_SPECIAL_0_OPCODE_X1:
+ case JALR_SPECIAL_0_OPCODE_X1:
+ state->update = 1;
+ state->next_pc =
+ regs->regs[get_SrcA_X1(bundle)];
+ break;
+
+ case JRP_SPECIAL_0_OPCODE_X1:
+ case JR_SPECIAL_0_OPCODE_X1:
+ state->next_pc =
+ regs->regs[get_SrcA_X1(bundle)];
+ bundle = nop_X1(bundle);
+ break;
+
+ case LNK_SPECIAL_0_OPCODE_X1:
+ state->update = 1;
+ target_reg = get_Dest_X1(bundle);
+ break;
+
+ /* stores */
+ case SH_SPECIAL_0_OPCODE_X1:
+ mem_op = MEMOP_STORE;
+ size = 2;
+ break;
+
+ case SW_SPECIAL_0_OPCODE_X1:
+ mem_op = MEMOP_STORE;
+ size = 4;
+ break;
+ }
+ break;
+
+ /* loads and iret */
+ case SHUN_0_OPCODE_X1:
+ if (get_UnShOpcodeExtension_X1(bundle) ==
+ UN_0_SHUN_0_OPCODE_X1) {
+ switch (get_UnOpcodeExtension_X1(bundle)) {
+ case LH_UN_0_SHUN_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD;
+ size = 2;
+ sign_ext = 1;
+ break;
+
+ case LH_U_UN_0_SHUN_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD;
+ size = 2;
+ sign_ext = 0;
+ break;
+
+ case LW_UN_0_SHUN_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD;
+ size = 4;
+ break;
+
+ case IRET_UN_0_SHUN_0_OPCODE_X1:
+ {
+ unsigned long ex0_0 = __insn_mfspr(
+ SPR_EX_CONTEXT_0_0);
+ unsigned long ex0_1 = __insn_mfspr(
+ SPR_EX_CONTEXT_0_1);
+ /*
+ * Special-case it if we're iret'ing
+ * to PL0 again. Otherwise just let
+ * it run and it will generate SIGILL.
+ */
+ if (EX1_PL(ex0_1) == USER_PL) {
+ state->next_pc = ex0_0;
+ regs->ex1 = ex0_1;
+ bundle = nop_X1(bundle);
+ }
+ }
+ }
+ }
+ break;
+
+#if CHIP_HAS_WH64()
+ /* postincrement operations */
+ case IMM_0_OPCODE_X1:
+ switch (get_ImmOpcodeExtension_X1(bundle)) {
+ case LWADD_IMM_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD_POSTINCR;
+ size = 4;
+ break;
+
+ case LHADD_IMM_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD_POSTINCR;
+ size = 2;
+ sign_ext = 1;
+ break;
+
+ case LHADD_U_IMM_0_OPCODE_X1:
+ mem_op = MEMOP_LOAD_POSTINCR;
+ size = 2;
+ sign_ext = 0;
+ break;
+
+ case SWADD_IMM_0_OPCODE_X1:
+ mem_op = MEMOP_STORE_POSTINCR;
+ size = 4;
+ break;
+
+ case SHADD_IMM_0_OPCODE_X1:
+ mem_op = MEMOP_STORE_POSTINCR;
+ size = 2;
+ break;
+
+ default:
+ break;
+ }
+ break;
+#endif /* CHIP_HAS_WH64() */
+ }
+
+ if (state->update) {
+ /*
+ * Get an available register. We start with a
+ * bitmask with 1's for available registers.
+ * We truncate to the low 32 registers since
+ * we are guaranteed to have set bits in the
+ * low 32 bits, then use ctz to pick the first.
+ */
+ u32 mask = (u32) ~((1ULL << get_Dest_X0(bundle)) |
+ (1ULL << get_SrcA_X0(bundle)) |
+ (1ULL << get_SrcB_X0(bundle)) |
+ (1ULL << target_reg));
+ temp_reg = __builtin_ctz(mask);
+ state->update_reg = temp_reg;
+ state->update_value = regs->regs[temp_reg];
+ regs->regs[temp_reg] = (unsigned long) (pc+1);
+ regs->flags |= PT_FLAGS_RESTORE_REGS;
+ bundle = move_X1(bundle, target_reg, temp_reg);
+ }
+ } else {
+ int opcode = get_Opcode_Y2(bundle);
+
+ switch (opcode) {
+ /* loads */
+ case LH_OPCODE_Y2:
+ mem_op = MEMOP_LOAD;
+ size = 2;
+ sign_ext = 1;
+ break;
+
+ case LH_U_OPCODE_Y2:
+ mem_op = MEMOP_LOAD;
+ size = 2;
+ sign_ext = 0;
+ break;
+
+ case LW_OPCODE_Y2:
+ mem_op = MEMOP_LOAD;
+ size = 4;
+ break;
+
+ /* stores */
+ case SH_OPCODE_Y2:
+ mem_op = MEMOP_STORE;
+ size = 2;
+ break;
+
+ case SW_OPCODE_Y2:
+ mem_op = MEMOP_STORE;
+ size = 4;
+ break;
+ }
+ }
+
+ /*
+ * Check if we need to rewrite an unaligned load/store.
+ * Returning zero is a special value meaning we need to SIGSEGV.
+ */
+ if (mem_op != MEMOP_NONE && unaligned_fixup >= 0) {
+ bundle = rewrite_load_store_unaligned(state, bundle, regs,
+ mem_op, size, sign_ext);
+ if (bundle == 0)
+ return;
+ }
+
+ /* write the bundle to our execution area */
+ buffer = state->buffer;
+ err = __put_user(bundle, buffer++);
+
+ /*
+ * If we're really single-stepping, we take an INT_ILL after.
+ * If we're just handling an unaligned access, we can just
+ * jump directly back to where we were in user code.
+ */
+ if (is_single_step) {
+ err |= __put_user(__single_step_ill_insn, buffer++);
+ err |= __put_user(__single_step_ill_insn, buffer++);
+ } else {
+ long delta;
+
+ if (state->update) {
+ /* We have some state to update; do it inline */
+ int ha16;
+ bundle = __single_step_addli_insn;
+ bundle |= create_Dest_X1(state->update_reg);
+ bundle |= create_Imm16_X1(state->update_value);
+ err |= __put_user(bundle, buffer++);
+ bundle = __single_step_auli_insn;
+ bundle |= create_Dest_X1(state->update_reg);
+ bundle |= create_SrcA_X1(state->update_reg);
+ ha16 = (state->update_value + 0x8000) >> 16;
+ bundle |= create_Imm16_X1(ha16);
+ err |= __put_user(bundle, buffer++);
+ state->update = 0;
+ }
+
+ /* End with a jump back to the next instruction */
+ delta = ((regs->pc + TILE_BUNDLE_SIZE_IN_BYTES) -
+ (unsigned long)buffer) >>
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES;
+ bundle = __single_step_j_insn;
+ bundle |= create_JOffLong_X1(delta);
+ err |= __put_user(bundle, buffer++);
+ }
+
+ if (err) {
+ printk("Fault when writing to single-step buffer\n");
+ return;
+ }
+
+ /*
+ * Flush the buffer.
+ * We do a local flush only, since this is a thread-specific buffer.
+ */
+ __flush_icache_range((unsigned long) state->buffer,
+ (unsigned long) buffer);
+
+ /* Indicate enabled */
+ state->is_enabled = is_single_step;
+ regs->pc = (unsigned long) state->buffer;
+
+ /* Fault immediately if we are coming back from a syscall. */
+ if (regs->faultnum == INT_SWINT_1)
+ regs->pc += 8;
+}
+
+#endif /* !__tilegx__ */
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
new file mode 100644
index 000000000000..782c1bfa6dfe
--- /dev/null
+++ b/arch/tile/kernel/smp.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * TILE SMP support routines.
+ */
+
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <asm/cacheflush.h>
+
+HV_Topology smp_topology __write_once;
+
+
+/*
+ * Top-level send_IPI*() functions to send messages to other cpus.
+ */
+
+/* Set by smp_send_stop() to avoid recursive panics. */
+static int stopping_cpus;
+
+void send_IPI_single(int cpu, int tag)
+{
+ HV_Recipient recip = {
+ .y = cpu / smp_width,
+ .x = cpu % smp_width,
+ .state = HV_TO_BE_SENT
+ };
+ int rc = hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag));
+ BUG_ON(rc <= 0);
+}
+
+void send_IPI_many(const struct cpumask *mask, int tag)
+{
+ HV_Recipient recip[NR_CPUS];
+ int cpu, sent;
+ int nrecip = 0;
+ int my_cpu = smp_processor_id();
+ for_each_cpu(cpu, mask) {
+ HV_Recipient *r;
+ BUG_ON(cpu == my_cpu);
+ r = &recip[nrecip++];
+ r->y = cpu / smp_width;
+ r->x = cpu % smp_width;
+ r->state = HV_TO_BE_SENT;
+ }
+ sent = 0;
+ while (sent < nrecip) {
+ int rc = hv_send_message(recip, nrecip,
+ (HV_VirtAddr)&tag, sizeof(tag));
+ if (rc <= 0) {
+ if (!stopping_cpus) /* avoid recursive panic */
+ panic("hv_send_message returned %d", rc);
+ break;
+ }
+ sent += rc;
+ }
+}
+
+void send_IPI_allbutself(int tag)
+{
+ struct cpumask mask;
+ cpumask_copy(&mask, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &mask);
+ send_IPI_many(&mask, tag);
+}
+
+
+/*
+ * Provide smp_call_function_mask, but also run function locally
+ * if specified in the mask.
+ */
+void on_each_cpu_mask(const struct cpumask *mask, void (*func)(void *),
+ void *info, bool wait)
+{
+ int cpu = get_cpu();
+ smp_call_function_many(mask, func, info, wait);
+ if (cpumask_test_cpu(cpu, mask)) {
+ local_irq_disable();
+ func(info);
+ local_irq_enable();
+ }
+ put_cpu();
+}
+
+
+/*
+ * Functions related to starting/stopping cpus.
+ */
+
+/* Handler to start the current cpu. */
+static void smp_start_cpu_interrupt(void)
+{
+ extern unsigned long start_cpu_function_addr;
+ get_irq_regs()->pc = start_cpu_function_addr;
+}
+
+/* Handler to stop the current cpu. */
+static void smp_stop_cpu_interrupt(void)
+{
+ set_cpu_online(smp_processor_id(), 0);
+ raw_local_irq_disable_all();
+ for (;;)
+ asm("nap");
+}
+
+/* This function calls the 'stop' function on all other CPUs in the system. */
+void smp_send_stop(void)
+{
+ stopping_cpus = 1;
+ send_IPI_allbutself(MSG_TAG_STOP_CPU);
+}
+
+
+/*
+ * Dispatch code called from hv_message_intr() for HV_MSG_TILE hv messages.
+ */
+void evaluate_message(int tag)
+{
+ switch (tag) {
+ case MSG_TAG_START_CPU: /* Start up a cpu */
+ smp_start_cpu_interrupt();
+ break;
+
+ case MSG_TAG_STOP_CPU: /* Sent to shut down slave CPU's */
+ smp_stop_cpu_interrupt();
+ break;
+
+ case MSG_TAG_CALL_FUNCTION_MANY: /* Call function on cpumask */
+ generic_smp_call_function_interrupt();
+ break;
+
+ case MSG_TAG_CALL_FUNCTION_SINGLE: /* Call function on one other CPU */
+ generic_smp_call_function_single_interrupt();
+ break;
+
+ default:
+ panic("Unknown IPI message tag %d", tag);
+ break;
+ }
+}
+
+
+/*
+ * flush_icache_range() code uses smp_call_function().
+ */
+
+struct ipi_flush {
+ unsigned long start;
+ unsigned long end;
+};
+
+static void ipi_flush_icache_range(void *info)
+{
+ struct ipi_flush *flush = (struct ipi_flush *) info;
+ __flush_icache_range(flush->start, flush->end);
+}
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ struct ipi_flush flush = { start, end };
+ preempt_disable();
+ on_each_cpu(ipi_flush_icache_range, &flush, 1);
+ preempt_enable();
+}
+
+
+/*
+ * The smp_send_reschedule() path does not use the hv_message_intr()
+ * path but instead the faster tile_dev_intr() path for interrupts.
+ */
+
+irqreturn_t handle_reschedule_ipi(int irq, void *token)
+{
+ /*
+ * Nothing to do here; when we return from interrupt, the
+ * rescheduling will occur there. But do bump the interrupt
+ * profiler count in the meantime.
+ */
+ __get_cpu_var(irq_stat).irq_resched_count++;
+
+ return IRQ_HANDLED;
+}
+
+void smp_send_reschedule(int cpu)
+{
+ HV_Coord coord;
+
+ WARN_ON(cpu_is_offline(cpu));
+ coord.y = cpu / smp_width;
+ coord.x = cpu % smp_width;
+ hv_trigger_ipi(coord, IRQ_RESCHEDULE);
+}
diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c
new file mode 100644
index 000000000000..aa3aafdb4b93
--- /dev/null
+++ b/arch/tile/kernel/smpboot.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/smp_lock.h>
+#include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/percpu.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/sections.h>
+
+/*
+ * This assembly function is provided in entry.S.
+ * When called, it loops on a nap instruction forever.
+ * FIXME: should be in a header somewhere.
+ */
+extern void smp_nap(void);
+
+/* State of each CPU. */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
+/* The messaging code jumps to this pointer during boot-up */
+unsigned long start_cpu_function_addr;
+
+/* Called very early during startup to mark boot cpu as online */
+void __init smp_prepare_boot_cpu(void)
+{
+ int cpu = smp_processor_id();
+ set_cpu_online(cpu, 1);
+ set_cpu_present(cpu, 1);
+ __get_cpu_var(cpu_state) = CPU_ONLINE;
+
+ init_messaging();
+}
+
+static void start_secondary(void);
+
+/*
+ * Called at the top of init() to launch all the other CPUs.
+ * They run free to complete their initialization and then wait
+ * until they get an IPI from the boot cpu to come online.
+ */
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ long rc;
+ int cpu, cpu_count;
+ int boot_cpu = smp_processor_id();
+
+ current_thread_info()->cpu = boot_cpu;
+
+ /*
+ * Pin this task to the boot CPU while we bring up the others,
+ * just to make sure we don't uselessly migrate as they come up.
+ */
+ rc = sched_setaffinity(current->pid, cpumask_of(boot_cpu));
+ if (rc != 0)
+ printk("Couldn't set init affinity to boot cpu (%ld)\n", rc);
+
+ /* Print information about disabled and dataplane cpus. */
+ print_disabled_cpus();
+
+ /*
+ * Tell the messaging subsystem how to respond to the
+ * startup message. We use a level of indirection to avoid
+ * confusing the linker with the fact that the messaging
+ * subsystem is calling __init code.
+ */
+ start_cpu_function_addr = (unsigned long) &online_secondary;
+
+ /* Set up thread context for all new processors. */
+ cpu_count = 1;
+ for (cpu = 0; cpu < NR_CPUS; ++cpu) {
+ struct task_struct *idle;
+
+ if (cpu == boot_cpu)
+ continue;
+
+ if (!cpu_possible(cpu)) {
+ /*
+ * Make this processor do nothing on boot.
+ * Note that we don't give the boot_pc function
+ * a stack, so it has to be assembly code.
+ */
+ per_cpu(boot_sp, cpu) = 0;
+ per_cpu(boot_pc, cpu) = (unsigned long) smp_nap;
+ continue;
+ }
+
+ /* Create a new idle thread to run start_secondary() */
+ idle = fork_idle(cpu);
+ if (IS_ERR(idle))
+ panic("failed fork for CPU %d", cpu);
+ idle->thread.pc = (unsigned long) start_secondary;
+
+ /* Make this thread the boot thread for this processor */
+ per_cpu(boot_sp, cpu) = task_ksp0(idle);
+ per_cpu(boot_pc, cpu) = idle->thread.pc;
+
+ ++cpu_count;
+ }
+ BUG_ON(cpu_count > (max_cpus ? max_cpus : 1));
+
+ /* Fire up the other tiles, if any */
+ init_cpu_present(cpu_possible_mask);
+ if (cpumask_weight(cpu_present_mask) > 1) {
+ mb(); /* make sure all data is visible to new processors */
+ hv_start_all_tiles();
+ }
+}
+
+static __initdata struct cpumask init_affinity;
+
+static __init int reset_init_affinity(void)
+{
+ long rc = sched_setaffinity(current->pid, &init_affinity);
+ if (rc != 0)
+ printk(KERN_WARNING "couldn't reset init affinity (%ld)\n",
+ rc);
+ return 0;
+}
+late_initcall(reset_init_affinity);
+
+struct cpumask cpu_started __cpuinitdata;
+
+/*
+ * Activate a secondary processor. Very minimal; don't add anything
+ * to this path without knowing what you're doing, since SMP booting
+ * is pretty fragile.
+ */
+static void __cpuinit start_secondary(void)
+{
+ int cpuid = smp_processor_id();
+
+ /* Set our thread pointer appropriately. */
+ set_my_cpu_offset(__per_cpu_offset[cpuid]);
+
+ preempt_disable();
+
+ /*
+ * In large machines even this will slow us down, since we
+ * will be contending for for the printk spinlock.
+ */
+ /* printk(KERN_DEBUG "Initializing CPU#%d\n", cpuid); */
+
+ /* Initialize the current asid for our first page table. */
+ __get_cpu_var(current_asid) = min_asid;
+
+ /* Set up this thread as another owner of the init_mm */
+ atomic_inc(&init_mm.mm_count);
+ current->active_mm = &init_mm;
+ if (current->mm)
+ BUG();
+ enter_lazy_tlb(&init_mm, current);
+
+ /* Enable IRQs. */
+ init_per_tile_IRQs();
+
+ /* Allow hypervisor messages to be received */
+ init_messaging();
+ local_irq_enable();
+
+ /* Indicate that we're ready to come up. */
+ /* Must not do this before we're ready to receive messages */
+ if (cpumask_test_and_set_cpu(cpuid, &cpu_started)) {
+ printk(KERN_WARNING "CPU#%d already started!\n", cpuid);
+ for (;;)
+ local_irq_enable();
+ }
+
+ smp_nap();
+}
+
+void setup_mpls(void); /* from kernel/setup.c */
+void store_permanent_mappings(void);
+
+/*
+ * Bring a secondary processor online.
+ */
+void __cpuinit online_secondary()
+{
+ /*
+ * low-memory mappings have been cleared, flush them from
+ * the local TLBs too.
+ */
+ local_flush_tlb();
+
+ BUG_ON(in_interrupt());
+
+ /* This must be done before setting cpu_online_mask */
+ wmb();
+
+ /*
+ * We need to hold call_lock, so there is no inconsistency
+ * between the time smp_call_function() determines number of
+ * IPI recipients, and the time when the determination is made
+ * for which cpus receive the IPI. Holding this
+ * lock helps us to not include this cpu in a currently in progress
+ * smp_call_function().
+ */
+ ipi_call_lock();
+ set_cpu_online(smp_processor_id(), 1);
+ ipi_call_unlock();
+ __get_cpu_var(cpu_state) = CPU_ONLINE;
+
+ /* Set up MPLs for this processor */
+ setup_mpls();
+
+
+ /* Set up tile-timer clock-event device on this cpu */
+ setup_tile_timer();
+
+ preempt_enable();
+
+ store_permanent_mappings();
+
+ cpu_idle();
+}
+
+int __cpuinit __cpu_up(unsigned int cpu)
+{
+ /* Wait 5s total for all CPUs for them to come online */
+ static int timeout;
+ for (; !cpumask_test_cpu(cpu, &cpu_started); timeout++) {
+ if (timeout >= 50000) {
+ printk(KERN_INFO "skipping unresponsive cpu%d\n", cpu);
+ local_irq_enable();
+ return -EIO;
+ }
+ udelay(100);
+ }
+
+ local_irq_enable();
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+
+ /* Unleash the CPU! */
+ send_IPI_single(cpu, MSG_TAG_START_CPU);
+ while (!cpumask_test_cpu(cpu, cpu_online_mask))
+ cpu_relax();
+ return 0;
+}
+
+static void panic_start_cpu(void)
+{
+ panic("Received a MSG_START_CPU IPI after boot finished.");
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+ int cpu, next, rc;
+
+ /* Reset the response to a (now illegal) MSG_START_CPU IPI. */
+ start_cpu_function_addr = (unsigned long) &panic_start_cpu;
+
+ cpumask_copy(&init_affinity, cpu_online_mask);
+
+ /*
+ * Pin ourselves to a single cpu in the initial affinity set
+ * so that kernel mappings for the rootfs are not in the dataplane,
+ * if set, and to avoid unnecessary migrating during bringup.
+ * Use the last cpu just in case the whole chip has been
+ * isolated from the scheduler, to keep init away from likely
+ * more useful user code. This also ensures that work scheduled
+ * via schedule_delayed_work() in the init routines will land
+ * on this cpu.
+ */
+ for (cpu = cpumask_first(&init_affinity);
+ (next = cpumask_next(cpu, &init_affinity)) < nr_cpu_ids;
+ cpu = next)
+ ;
+ rc = sched_setaffinity(current->pid, cpumask_of(cpu));
+ if (rc != 0)
+ printk("Couldn't set init affinity to cpu %d (%d)\n", cpu, rc);
+}
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c
new file mode 100644
index 000000000000..382170b4b40a
--- /dev/null
+++ b/arch/tile/kernel/stack.c
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/kallsyms.h>
+#include <linux/stacktrace.h>
+#include <linux/uaccess.h>
+#include <linux/mmzone.h>
+#include <asm/backtrace.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+#include <asm/ucontext.h>
+#include <asm/sigframe.h>
+#include <asm/stack.h>
+#include <arch/abi.h>
+#include <arch/interrupts.h>
+
+
+/* Is address on the specified kernel stack? */
+static int in_kernel_stack(struct KBacktraceIterator *kbt, VirtualAddress sp)
+{
+ ulong kstack_base = (ulong) kbt->task->stack;
+ if (kstack_base == 0) /* corrupt task pointer; just follow stack... */
+ return sp >= PAGE_OFFSET && sp < (unsigned long)high_memory;
+ return sp >= kstack_base && sp < kstack_base + THREAD_SIZE;
+}
+
+/* Is address in the specified kernel code? */
+static int in_kernel_text(VirtualAddress address)
+{
+ return (address >= MEM_SV_INTRPT &&
+ address < MEM_SV_INTRPT + HPAGE_SIZE);
+}
+
+/* Is address valid for reading? */
+static int valid_address(struct KBacktraceIterator *kbt, VirtualAddress address)
+{
+ HV_PTE *l1_pgtable = kbt->pgtable;
+ HV_PTE *l2_pgtable;
+ unsigned long pfn;
+ HV_PTE pte;
+ struct page *page;
+
+ pte = l1_pgtable[HV_L1_INDEX(address)];
+ if (!hv_pte_get_present(pte))
+ return 0;
+ pfn = hv_pte_get_pfn(pte);
+ if (pte_huge(pte)) {
+ if (!pfn_valid(pfn)) {
+ printk(KERN_ERR "huge page has bad pfn %#lx\n", pfn);
+ return 0;
+ }
+ return hv_pte_get_present(pte) && hv_pte_get_readable(pte);
+ }
+
+ page = pfn_to_page(pfn);
+ if (PageHighMem(page)) {
+ printk(KERN_ERR "L2 page table not in LOWMEM (%#llx)\n",
+ HV_PFN_TO_CPA(pfn));
+ return 0;
+ }
+ l2_pgtable = (HV_PTE *)pfn_to_kaddr(pfn);
+ pte = l2_pgtable[HV_L2_INDEX(address)];
+ return hv_pte_get_present(pte) && hv_pte_get_readable(pte);
+}
+
+/* Callback for backtracer; basically a glorified memcpy */
+static bool read_memory_func(void *result, VirtualAddress address,
+ unsigned int size, void *vkbt)
+{
+ int retval;
+ struct KBacktraceIterator *kbt = (struct KBacktraceIterator *)vkbt;
+ if (in_kernel_text(address)) {
+ /* OK to read kernel code. */
+ } else if (address >= PAGE_OFFSET) {
+ /* We only tolerate kernel-space reads of this task's stack */
+ if (!in_kernel_stack(kbt, address))
+ return 0;
+ } else if (kbt->pgtable == NULL) {
+ return 0; /* can't read user space in other tasks */
+ } else if (!valid_address(kbt, address)) {
+ return 0; /* invalid user-space address */
+ }
+ pagefault_disable();
+ retval = __copy_from_user_inatomic(result, (const void *)address,
+ size);
+ pagefault_enable();
+ return (retval == 0);
+}
+
+/* Return a pt_regs pointer for a valid fault handler frame */
+static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt)
+{
+#ifndef __tilegx__
+ const char *fault = NULL; /* happy compiler */
+ char fault_buf[64];
+ VirtualAddress sp = kbt->it.sp;
+ struct pt_regs *p;
+
+ if (!in_kernel_stack(kbt, sp))
+ return NULL;
+ if (!in_kernel_stack(kbt, sp + C_ABI_SAVE_AREA_SIZE + PTREGS_SIZE-1))
+ return NULL;
+ p = (struct pt_regs *)(sp + C_ABI_SAVE_AREA_SIZE);
+ if (p->faultnum == INT_SWINT_1 || p->faultnum == INT_SWINT_1_SIGRETURN)
+ fault = "syscall";
+ else {
+ if (kbt->verbose) { /* else we aren't going to use it */
+ snprintf(fault_buf, sizeof(fault_buf),
+ "interrupt %ld", p->faultnum);
+ fault = fault_buf;
+ }
+ }
+ if (EX1_PL(p->ex1) == KERNEL_PL &&
+ in_kernel_text(p->pc) &&
+ in_kernel_stack(kbt, p->sp) &&
+ p->sp >= sp) {
+ if (kbt->verbose)
+ printk(KERN_ERR " <%s while in kernel mode>\n", fault);
+ } else if (EX1_PL(p->ex1) == USER_PL &&
+ p->pc < PAGE_OFFSET &&
+ p->sp < PAGE_OFFSET) {
+ if (kbt->verbose)
+ printk(KERN_ERR " <%s while in user mode>\n", fault);
+ } else if (kbt->verbose) {
+ printk(KERN_ERR " (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n",
+ p->pc, p->sp, p->ex1);
+ p = NULL;
+ }
+ if (!kbt->profile || (INT_MASK(p->faultnum) & QUEUED_INTERRUPTS) == 0)
+ return p;
+#endif
+ return NULL;
+}
+
+/* Is the pc pointing to a sigreturn trampoline? */
+static int is_sigreturn(VirtualAddress pc)
+{
+ return (pc == VDSO_BASE);
+}
+
+/* Return a pt_regs pointer for a valid signal handler frame */
+static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt)
+{
+ BacktraceIterator *b = &kbt->it;
+
+ if (b->pc == VDSO_BASE) {
+ struct rt_sigframe *frame;
+ unsigned long sigframe_top =
+ b->sp + sizeof(struct rt_sigframe) - 1;
+ if (!valid_address(kbt, b->sp) ||
+ !valid_address(kbt, sigframe_top)) {
+ if (kbt->verbose)
+ printk(" (odd signal: sp %#lx?)\n",
+ (unsigned long)(b->sp));
+ return NULL;
+ }
+ frame = (struct rt_sigframe *)b->sp;
+ if (kbt->verbose) {
+ printk(KERN_ERR " <received signal %d>\n",
+ frame->info.si_signo);
+ }
+ return &frame->uc.uc_mcontext.regs;
+ }
+ return NULL;
+}
+
+int KBacktraceIterator_is_sigreturn(struct KBacktraceIterator *kbt)
+{
+ return is_sigreturn(kbt->it.pc);
+}
+
+static int KBacktraceIterator_restart(struct KBacktraceIterator *kbt)
+{
+ struct pt_regs *p;
+
+ p = valid_fault_handler(kbt);
+ if (p == NULL)
+ p = valid_sigframe(kbt);
+ if (p == NULL)
+ return 0;
+ backtrace_init(&kbt->it, read_memory_func, kbt,
+ p->pc, p->lr, p->sp, p->regs[52]);
+ kbt->new_context = 1;
+ return 1;
+}
+
+/* Find a frame that isn't a sigreturn, if there is one. */
+static int KBacktraceIterator_next_item_inclusive(
+ struct KBacktraceIterator *kbt)
+{
+ for (;;) {
+ do {
+ if (!KBacktraceIterator_is_sigreturn(kbt))
+ return 1;
+ } while (backtrace_next(&kbt->it));
+
+ if (!KBacktraceIterator_restart(kbt))
+ return 0;
+ }
+}
+
+/*
+ * If the current sp is on a page different than what we recorded
+ * as the top-of-kernel-stack last time we context switched, we have
+ * probably blown the stack, and nothing is going to work out well.
+ * If we can at least get out a warning, that may help the debug,
+ * though we probably won't be able to backtrace into the code that
+ * actually did the recursive damage.
+ */
+static void validate_stack(struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+ unsigned long ksp0 = get_current_ksp0();
+ unsigned long ksp0_base = ksp0 - THREAD_SIZE;
+ unsigned long sp = stack_pointer;
+
+ if (EX1_PL(regs->ex1) == KERNEL_PL && regs->sp >= ksp0) {
+ printk("WARNING: cpu %d: kernel stack page %#lx underrun!\n"
+ " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n",
+ cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr);
+ }
+
+ else if (sp < ksp0_base + sizeof(struct thread_info)) {
+ printk("WARNING: cpu %d: kernel stack page %#lx overrun!\n"
+ " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n",
+ cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr);
+ }
+}
+
+void KBacktraceIterator_init(struct KBacktraceIterator *kbt,
+ struct task_struct *t, struct pt_regs *regs)
+{
+ VirtualAddress pc, lr, sp, r52;
+ int is_current;
+
+ /*
+ * Set up callback information. We grab the kernel stack base
+ * so we will allow reads of that address range, and if we're
+ * asking about the current process we grab the page table
+ * so we can check user accesses before trying to read them.
+ * We flush the TLB to avoid any weird skew issues.
+ */
+ is_current = (t == NULL);
+ kbt->is_current = is_current;
+ if (is_current)
+ t = validate_current();
+ kbt->task = t;
+ kbt->pgtable = NULL;
+ kbt->verbose = 0; /* override in caller if desired */
+ kbt->profile = 0; /* override in caller if desired */
+ kbt->end = 0;
+ kbt->new_context = 0;
+ if (is_current) {
+ HV_PhysAddr pgdir_pa = hv_inquire_context().page_table;
+ if (pgdir_pa == (unsigned long)swapper_pg_dir - PAGE_OFFSET) {
+ /*
+ * Not just an optimization: this also allows
+ * this to work at all before va/pa mappings
+ * are set up.
+ */
+ kbt->pgtable = swapper_pg_dir;
+ } else {
+ struct page *page = pfn_to_page(PFN_DOWN(pgdir_pa));
+ if (!PageHighMem(page))
+ kbt->pgtable = __va(pgdir_pa);
+ else
+ printk(KERN_ERR "page table not in LOWMEM"
+ " (%#llx)\n", pgdir_pa);
+ }
+ local_flush_tlb_all();
+ validate_stack(regs);
+ }
+
+ if (regs == NULL) {
+ extern const void *get_switch_to_pc(void);
+ if (is_current || t->state == TASK_RUNNING) {
+ /* Can't do this; we need registers */
+ kbt->end = 1;
+ return;
+ }
+ pc = (ulong) get_switch_to_pc();
+ lr = t->thread.pc;
+ sp = t->thread.ksp;
+ r52 = 0;
+ } else {
+ pc = regs->pc;
+ lr = regs->lr;
+ sp = regs->sp;
+ r52 = regs->regs[52];
+ }
+
+ backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52);
+ kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+}
+EXPORT_SYMBOL(KBacktraceIterator_init);
+
+int KBacktraceIterator_end(struct KBacktraceIterator *kbt)
+{
+ return kbt->end;
+}
+EXPORT_SYMBOL(KBacktraceIterator_end);
+
+void KBacktraceIterator_next(struct KBacktraceIterator *kbt)
+{
+ kbt->new_context = 0;
+ if (!backtrace_next(&kbt->it) &&
+ !KBacktraceIterator_restart(kbt)) {
+ kbt->end = 1;
+ return;
+ }
+
+ kbt->end = !KBacktraceIterator_next_item_inclusive(kbt);
+}
+EXPORT_SYMBOL(KBacktraceIterator_next);
+
+/*
+ * This method wraps the backtracer's more generic support.
+ * It is only invoked from the architecture-specific code; show_stack()
+ * and dump_stack() (in entry.S) are architecture-independent entry points.
+ */
+void tile_show_stack(struct KBacktraceIterator *kbt, int headers)
+{
+ int i;
+
+ if (headers) {
+ /*
+ * Add a blank line since if we are called from panic(),
+ * then bust_spinlocks() spit out a space in front of us
+ * and it will mess up our KERN_ERR.
+ */
+ printk("\n");
+ printk(KERN_ERR "Starting stack dump of tid %d, pid %d (%s)"
+ " on cpu %d at cycle %lld\n",
+ kbt->task->pid, kbt->task->tgid, kbt->task->comm,
+ smp_processor_id(), get_cycles());
+ }
+#ifdef __tilegx__
+ if (kbt->is_current) {
+ __insn_mtspr(SPR_SIM_CONTROL,
+ SIM_DUMP_SPR_ARG(SIM_DUMP_BACKTRACE));
+ }
+#endif
+ kbt->verbose = 1;
+ i = 0;
+ for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) {
+ char *modname;
+ const char *name;
+ unsigned long address = kbt->it.pc;
+ unsigned long offset, size;
+ char namebuf[KSYM_NAME_LEN+100];
+
+ if (address >= PAGE_OFFSET)
+ name = kallsyms_lookup(address, &size, &offset,
+ &modname, namebuf);
+ else
+ name = NULL;
+
+ if (!name)
+ namebuf[0] = '\0';
+ else {
+ size_t namelen = strlen(namebuf);
+ size_t remaining = (sizeof(namebuf) - 1) - namelen;
+ char *p = namebuf + namelen;
+ int rc = snprintf(p, remaining, "+%#lx/%#lx ",
+ offset, size);
+ if (modname && rc < remaining)
+ snprintf(p + rc, remaining - rc,
+ "[%s] ", modname);
+ namebuf[sizeof(namebuf)-1] = '\0';
+ }
+
+ printk(KERN_ERR " frame %d: 0x%lx %s(sp 0x%lx)\n",
+ i++, address, namebuf, (unsigned long)(kbt->it.sp));
+
+ if (i >= 100) {
+ printk(KERN_ERR "Stack dump truncated"
+ " (%d frames)\n", i);
+ break;
+ }
+ }
+ if (headers)
+ printk(KERN_ERR "Stack dump complete\n");
+}
+EXPORT_SYMBOL(tile_show_stack);
+
+
+/* This is called from show_regs() and _dump_stack() */
+void dump_stack_regs(struct pt_regs *regs)
+{
+ struct KBacktraceIterator kbt;
+ KBacktraceIterator_init(&kbt, NULL, regs);
+ tile_show_stack(&kbt, 1);
+}
+EXPORT_SYMBOL(dump_stack_regs);
+
+static struct pt_regs *regs_to_pt_regs(struct pt_regs *regs,
+ ulong pc, ulong lr, ulong sp, ulong r52)
+{
+ memset(regs, 0, sizeof(struct pt_regs));
+ regs->pc = pc;
+ regs->lr = lr;
+ regs->sp = sp;
+ regs->regs[52] = r52;
+ return regs;
+}
+
+/* This is called from dump_stack() and just converts to pt_regs */
+void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
+{
+ struct pt_regs regs;
+ dump_stack_regs(regs_to_pt_regs(&regs, pc, lr, sp, r52));
+}
+
+/* This is called from KBacktraceIterator_init_current() */
+void _KBacktraceIterator_init_current(struct KBacktraceIterator *kbt, ulong pc,
+ ulong lr, ulong sp, ulong r52)
+{
+ struct pt_regs regs;
+ KBacktraceIterator_init(kbt, NULL,
+ regs_to_pt_regs(&regs, pc, lr, sp, r52));
+}
+
+/* This is called only from kernel/sched.c, with esp == NULL */
+void show_stack(struct task_struct *task, unsigned long *esp)
+{
+ struct KBacktraceIterator kbt;
+ if (task == NULL || task == current)
+ KBacktraceIterator_init_current(&kbt);
+ else
+ KBacktraceIterator_init(&kbt, task, NULL);
+ tile_show_stack(&kbt, 0);
+}
+
+#ifdef CONFIG_STACKTRACE
+
+/* Support generic Linux stack API too */
+
+void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace)
+{
+ struct KBacktraceIterator kbt;
+ int skip = trace->skip;
+ int i = 0;
+
+ if (task == NULL || task == current)
+ KBacktraceIterator_init_current(&kbt);
+ else
+ KBacktraceIterator_init(&kbt, task, NULL);
+ for (; !KBacktraceIterator_end(&kbt); KBacktraceIterator_next(&kbt)) {
+ if (skip) {
+ --skip;
+ continue;
+ }
+ if (i >= trace->max_entries || kbt.it.pc < PAGE_OFFSET)
+ break;
+ trace->entries[i++] = kbt.it.pc;
+ }
+ trace->nr_entries = i;
+}
+EXPORT_SYMBOL(save_stack_trace_tsk);
+
+void save_stack_trace(struct stack_trace *trace)
+{
+ save_stack_trace_tsk(NULL, trace);
+}
+
+#endif
+
+/* In entry.S */
+EXPORT_SYMBOL(KBacktraceIterator_init_current);
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
new file mode 100644
index 000000000000..0427978cea0a
--- /dev/null
+++ b/arch/tile/kernel/sys.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This file contains various random system calls that
+ * have a non-standard calling sequence on the Linux/TILE
+ * platform.
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/syscalls.h>
+#include <linux/mman.h>
+#include <linux/file.h>
+#include <linux/mempolicy.h>
+#include <linux/binfmts.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/signal.h>
+#include <asm/syscalls.h>
+
+#include <asm/pgtable.h>
+#include <asm/homecache.h>
+#include <arch/chip.h>
+
+SYSCALL_DEFINE0(flush_cache)
+{
+ homecache_evict(cpumask_of(smp_processor_id()));
+ return 0;
+}
+
+/*
+ * Syscalls that pass 64-bit values on 32-bit systems normally
+ * pass them as (low,high) word packed into the immediately adjacent
+ * registers. If the low word naturally falls on an even register,
+ * our ABI makes it work correctly; if not, we adjust it here.
+ * Handling it here means we don't have to fix uclibc AND glibc AND
+ * any other standard libcs we want to support.
+ */
+
+#if !defined(__tilegx__) || defined(CONFIG_COMPAT)
+
+ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count)
+{
+ return sys_readahead(fd, ((loff_t)offset_hi << 32) | offset_lo, count);
+}
+
+long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len, int advice)
+{
+ return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo,
+ len, advice);
+}
+
+int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi,
+ u32 len_lo, u32 len_hi, int advice)
+{
+ return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo,
+ ((loff_t)len_hi << 32) | len_lo, advice);
+}
+
+#endif /* 32-bit syscall wrappers */
+
+/*
+ * This API uses a 4KB-page-count offset into the file descriptor.
+ * It is likely not the right API to use on a 64-bit platform.
+ */
+SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, unsigned long, off_4k)
+{
+#define PAGE_ADJUST (PAGE_SHIFT - 12)
+ if (off_4k & ((1 << PAGE_ADJUST) - 1))
+ return -EINVAL;
+ return sys_mmap_pgoff(addr, len, prot, flags, fd,
+ off_4k >> PAGE_ADJUST);
+}
+
+/*
+ * This API uses a byte offset into the file descriptor.
+ * It is likely not the right API to use on a 32-bit platform.
+ */
+SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, off_t, offset)
+{
+ if (offset & ((1 << PAGE_SHIFT) - 1))
+ return -EINVAL;
+ return sys_mmap_pgoff(addr, len, prot, flags, fd,
+ offset >> PAGE_SHIFT);
+}
+
+
+/* Provide the actual syscall number to call mapping. */
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+#ifndef __tilegx__
+/* See comments at the top of the file. */
+#define sys_fadvise64 sys32_fadvise64
+#define sys_fadvise64_64 sys32_fadvise64_64
+#define sys_readahead sys32_readahead
+#define sys_sync_file_range sys_sync_file_range2
+#endif
+
+void *sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls-1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
diff --git a/arch/tile/kernel/tile-desc_32.c b/arch/tile/kernel/tile-desc_32.c
new file mode 100644
index 000000000000..3b78369f86b0
--- /dev/null
+++ b/arch/tile/kernel/tile-desc_32.c
@@ -0,0 +1,13826 @@
+/* Define to include "bfd.h" and get actual BFD relocations below. */
+/* #define WANT_BFD_RELOCS */
+
+#ifdef WANT_BFD_RELOCS
+#include "bfd.h"
+#define MAYBE_BFD_RELOC(X) (X)
+#else
+#define MAYBE_BFD_RELOC(X) -1
+#endif
+
+/* Special registers. */
+#define TREG_LR 55
+#define TREG_SN 56
+#define TREG_ZERO 63
+
+/* FIXME: Rename this. */
+#include <asm/opcode-tile.h>
+
+
+const struct tile_opcode tile_opcodes[394] =
+{
+ { "bpt", TILE_OPC_BPT, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbffffff80000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b3cae00000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "info", TILE_OPC_INFO, 0xf /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0 },
+ { 1 },
+ { 2 },
+ { 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00fffULL,
+ 0xfff807ff80000000ULL,
+ 0x8000000078000fffULL,
+ 0xf80007ff80000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000050100fffULL,
+ 0x302007ff80000000ULL,
+ 0x8000000050000fffULL,
+ 0xc00007ff80000000ULL,
+ -1ULL
+ }
+ },
+ { "infol", TILE_OPC_INFOL, 0x3 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 4 },
+ { 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000fffULL,
+ 0xf80007ff80000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000030000fffULL,
+ 0x200007ff80000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "j", TILE_OPC_J, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 6 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf000000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x5000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jal", TILE_OPC_JAL, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_LR, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 6 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf000000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x6000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "move", TILE_OPC_MOVE, 0xf /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 9, 10 },
+ { 11, 12 },
+ { 13, 14 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0xfffff80000000000ULL,
+ 0x80000000780ff000ULL,
+ 0xf807f80000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000cff000ULL,
+ 0x0833f80000000000ULL,
+ 0x80000000180bf000ULL,
+ 0x9805f80000000000ULL,
+ -1ULL
+ }
+ },
+ { "move.sn", TILE_OPC_MOVE_SN, 0x3 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008cff000ULL,
+ 0x0c33f80000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "movei", TILE_OPC_MOVEI, 0xf /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 0 },
+ { 9, 1 },
+ { 11, 2 },
+ { 13, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00fc0ULL,
+ 0xfff807e000000000ULL,
+ 0x8000000078000fc0ULL,
+ 0xf80007e000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040800fc0ULL,
+ 0x305807e000000000ULL,
+ 0x8000000058000fc0ULL,
+ 0xc80007e000000000ULL,
+ -1ULL
+ }
+ },
+ { "movei.sn", TILE_OPC_MOVEI_SN, 0x3 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 0 },
+ { 9, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00fc0ULL,
+ 0xfff807e000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048800fc0ULL,
+ 0x345807e000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "moveli", TILE_OPC_MOVELI, 0x3 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 4 },
+ { 9, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000fc0ULL,
+ 0xf80007e000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000020000fc0ULL,
+ 0x180007e000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "moveli.sn", TILE_OPC_MOVELI_SN, 0x3 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 4 },
+ { 9, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000fc0ULL,
+ 0xf80007e000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000010000fc0ULL,
+ 0x100007e000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "movelis", TILE_OPC_MOVELIS, 0x3 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 4 },
+ { 9, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000fc0ULL,
+ 0xf80007e000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000010000fc0ULL,
+ 0x100007e000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "prefetch", TILE_OPC_PREFETCH, 0x12 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff81f80000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000003f00000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b501f80000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8000000003f00000ULL
+ }
+ },
+ { "add", TILE_OPC_ADD, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000000c0000ULL,
+ 0x0806000000000000ULL,
+ 0x8000000008000000ULL,
+ 0x8800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "add.sn", TILE_OPC_ADD_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000080c0000ULL,
+ 0x0c06000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addb", TILE_OPC_ADDB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000040000ULL,
+ 0x0802000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addb.sn", TILE_OPC_ADDB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008040000ULL,
+ 0x0c02000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addbs_u", TILE_OPC_ADDBS_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001880000ULL,
+ 0x0888000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addbs_u.sn", TILE_OPC_ADDBS_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009880000ULL,
+ 0x0c88000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addh", TILE_OPC_ADDH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000080000ULL,
+ 0x0804000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addh.sn", TILE_OPC_ADDH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008080000ULL,
+ 0x0c04000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addhs", TILE_OPC_ADDHS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000018c0000ULL,
+ 0x088a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addhs.sn", TILE_OPC_ADDHS_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000098c0000ULL,
+ 0x0c8a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addi", TILE_OPC_ADDI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040300000ULL,
+ 0x3018000000000000ULL,
+ 0x8000000048000000ULL,
+ 0xb800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "addi.sn", TILE_OPC_ADDI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048300000ULL,
+ 0x3418000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addib", TILE_OPC_ADDIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040100000ULL,
+ 0x3008000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addib.sn", TILE_OPC_ADDIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048100000ULL,
+ 0x3408000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addih", TILE_OPC_ADDIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040200000ULL,
+ 0x3010000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addih.sn", TILE_OPC_ADDIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048200000ULL,
+ 0x3410000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addli", TILE_OPC_ADDLI, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 4 },
+ { 9, 10, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000020000000ULL,
+ 0x1800000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addli.sn", TILE_OPC_ADDLI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 4 },
+ { 9, 10, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000010000000ULL,
+ 0x1000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "addlis", TILE_OPC_ADDLIS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 4 },
+ { 9, 10, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000010000000ULL,
+ 0x1000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adds", TILE_OPC_ADDS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001800000ULL,
+ 0x0884000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adds.sn", TILE_OPC_ADDS_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009800000ULL,
+ 0x0c84000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adiffb_u", TILE_OPC_ADIFFB_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000100000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adiffb_u.sn", TILE_OPC_ADIFFB_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008100000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adiffh", TILE_OPC_ADIFFH, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000140000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "adiffh.sn", TILE_OPC_ADIFFH_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008140000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "and", TILE_OPC_AND, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000180000ULL,
+ 0x0808000000000000ULL,
+ 0x8000000018000000ULL,
+ 0x9800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "and.sn", TILE_OPC_AND_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008180000ULL,
+ 0x0c08000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "andi", TILE_OPC_ANDI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000050100000ULL,
+ 0x3020000000000000ULL,
+ 0x8000000050000000ULL,
+ 0xc000000000000000ULL,
+ -1ULL
+ }
+ },
+ { "andi.sn", TILE_OPC_ANDI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000058100000ULL,
+ 0x3420000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "auli", TILE_OPC_AULI, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 4 },
+ { 9, 10, 5 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000030000000ULL,
+ 0x2000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "avgb_u", TILE_OPC_AVGB_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000001c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "avgb_u.sn", TILE_OPC_AVGB_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000081c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "avgh", TILE_OPC_AVGH, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000200000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "avgh.sn", TILE_OPC_AVGH_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008200000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbns", TILE_OPC_BBNS, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000700000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbns.sn", TILE_OPC_BBNS_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000700000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbnst", TILE_OPC_BBNST, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000780000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbnst.sn", TILE_OPC_BBNST_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000780000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbs", TILE_OPC_BBS, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000600000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbs.sn", TILE_OPC_BBS_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000600000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbst", TILE_OPC_BBST, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000680000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bbst.sn", TILE_OPC_BBST_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000680000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgez", TILE_OPC_BGEZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000300000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgez.sn", TILE_OPC_BGEZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000300000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgezt", TILE_OPC_BGEZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000380000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgezt.sn", TILE_OPC_BGEZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000380000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgz", TILE_OPC_BGZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000200000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgz.sn", TILE_OPC_BGZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000200000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgzt", TILE_OPC_BGZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000280000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bgzt.sn", TILE_OPC_BGZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000280000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bitx", TILE_OPC_BITX, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 11, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070161000ULL,
+ -1ULL,
+ 0x80000000680a1000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bitx.sn", TILE_OPC_BITX_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078161000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blez", TILE_OPC_BLEZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000500000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blez.sn", TILE_OPC_BLEZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000500000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blezt", TILE_OPC_BLEZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000580000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blezt.sn", TILE_OPC_BLEZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000580000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blz", TILE_OPC_BLZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000400000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blz.sn", TILE_OPC_BLZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000400000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blzt", TILE_OPC_BLZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000480000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "blzt.sn", TILE_OPC_BLZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000480000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bnz", TILE_OPC_BNZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000100000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bnz.sn", TILE_OPC_BNZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000100000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bnzt", TILE_OPC_BNZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000180000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bnzt.sn", TILE_OPC_BNZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000180000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bytex", TILE_OPC_BYTEX, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 11, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070162000ULL,
+ -1ULL,
+ 0x80000000680a2000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bytex.sn", TILE_OPC_BYTEX_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078162000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bz", TILE_OPC_BZ, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bz.sn", TILE_OPC_BZ_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bzt", TILE_OPC_BZT, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2800000080000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "bzt.sn", TILE_OPC_BZT_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 20 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfc00000780000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x2c00000080000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "clz", TILE_OPC_CLZ, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 11, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070163000ULL,
+ -1ULL,
+ 0x80000000680a3000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "clz.sn", TILE_OPC_CLZ_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078163000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "crc32_32", TILE_OPC_CRC32_32, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000240000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "crc32_32.sn", TILE_OPC_CRC32_32_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008240000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "crc32_8", TILE_OPC_CRC32_8, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000280000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "crc32_8.sn", TILE_OPC_CRC32_8_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008280000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "ctz", TILE_OPC_CTZ, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 11, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070164000ULL,
+ -1ULL,
+ 0x80000000680a4000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "ctz.sn", TILE_OPC_CTZ_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078164000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "drain", TILE_OPC_DRAIN, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b080000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "dtlbpr", TILE_OPC_DTLBPR, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b100000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "dword_align", TILE_OPC_DWORD_ALIGN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000017c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "dword_align.sn", TILE_OPC_DWORD_ALIGN_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000097c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "finv", TILE_OPC_FINV, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b180000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "flush", TILE_OPC_FLUSH, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b200000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "fnop", TILE_OPC_FNOP, 0xf /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { },
+ { },
+ { },
+ { },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000077fff000ULL,
+ 0xfbfff80000000000ULL,
+ 0x80000000780ff000ULL,
+ 0xf807f80000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070165000ULL,
+ 0x400b280000000000ULL,
+ 0x80000000680a5000ULL,
+ 0xd805080000000000ULL,
+ -1ULL
+ }
+ },
+ { "icoh", TILE_OPC_ICOH, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b300000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "ill", TILE_OPC_ILL, 0xa /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0xf807f80000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b380000000000ULL,
+ -1ULL,
+ 0xd805100000000000ULL,
+ -1ULL
+ }
+ },
+ { "inthb", TILE_OPC_INTHB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000002c0000ULL,
+ 0x080a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "inthb.sn", TILE_OPC_INTHB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000082c0000ULL,
+ 0x0c0a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "inthh", TILE_OPC_INTHH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000300000ULL,
+ 0x080c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "inthh.sn", TILE_OPC_INTHH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008300000ULL,
+ 0x0c0c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "intlb", TILE_OPC_INTLB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000340000ULL,
+ 0x080e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "intlb.sn", TILE_OPC_INTLB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008340000ULL,
+ 0x0c0e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "intlh", TILE_OPC_INTLH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000380000ULL,
+ 0x0810000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "intlh.sn", TILE_OPC_INTLH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008380000ULL,
+ 0x0c10000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "inv", TILE_OPC_INV, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b400000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "iret", TILE_OPC_IRET, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b480000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jalb", TILE_OPC_JALB, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_LR, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 22 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x6800000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jalf", TILE_OPC_JALF, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_LR, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 22 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x6000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jalr", TILE_OPC_JALR, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_LR, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0814000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jalrp", TILE_OPC_JALRP, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_LR, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0812000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jb", TILE_OPC_JB, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 22 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x5800000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jf", TILE_OPC_JF, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 22 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x5000000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jr", TILE_OPC_JR, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0818000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "jrp", TILE_OPC_JRP, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0816000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lb", TILE_OPC_LB, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 23, 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b500000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8000000000000000ULL
+ }
+ },
+ { "lb.sn", TILE_OPC_LB_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440b500000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lb_u", TILE_OPC_LB_U, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 23, 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b580000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8100000000000000ULL
+ }
+ },
+ { "lb_u.sn", TILE_OPC_LB_U_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440b580000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lbadd", TILE_OPC_LBADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30b0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lbadd.sn", TILE_OPC_LBADD_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34b0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lbadd_u", TILE_OPC_LBADD_U, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30b8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lbadd_u.sn", TILE_OPC_LBADD_U_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34b8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lh", TILE_OPC_LH, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 23, 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b600000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8200000000000000ULL
+ }
+ },
+ { "lh.sn", TILE_OPC_LH_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440b600000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lh_u", TILE_OPC_LH_U, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 23, 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b680000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8300000000000000ULL
+ }
+ },
+ { "lh_u.sn", TILE_OPC_LH_U_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440b680000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lhadd", TILE_OPC_LHADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30c0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lhadd.sn", TILE_OPC_LHADD_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34c0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lhadd_u", TILE_OPC_LHADD_U, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30c8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lhadd_u.sn", TILE_OPC_LHADD_U_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34c8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lnk", TILE_OPC_LNK, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x081a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lnk.sn", TILE_OPC_LNK_SN, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0c1a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lw", TILE_OPC_LW, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 23, 15 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b700000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8400000000000000ULL
+ }
+ },
+ { "lw.sn", TILE_OPC_LW_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440b700000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lw_na", TILE_OPC_LW_NA, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400bc00000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lw_na.sn", TILE_OPC_LW_NA_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440bc00000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lwadd", TILE_OPC_LWADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30d0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lwadd.sn", TILE_OPC_LWADD_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34d0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lwadd_na", TILE_OPC_LWADD_NA, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30d8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "lwadd_na.sn", TILE_OPC_LWADD_NA_SN, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 24, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x34d8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxb_u", TILE_OPC_MAXB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000003c0000ULL,
+ 0x081c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxb_u.sn", TILE_OPC_MAXB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000083c0000ULL,
+ 0x0c1c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxh", TILE_OPC_MAXH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000400000ULL,
+ 0x081e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxh.sn", TILE_OPC_MAXH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008400000ULL,
+ 0x0c1e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxib_u", TILE_OPC_MAXIB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040400000ULL,
+ 0x3028000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxib_u.sn", TILE_OPC_MAXIB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048400000ULL,
+ 0x3428000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxih", TILE_OPC_MAXIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040500000ULL,
+ 0x3030000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "maxih.sn", TILE_OPC_MAXIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048500000ULL,
+ 0x3430000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mf", TILE_OPC_MF, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b780000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mfspr", TILE_OPC_MFSPR, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 25 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbf8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x3038000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minb_u", TILE_OPC_MINB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000440000ULL,
+ 0x0820000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minb_u.sn", TILE_OPC_MINB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008440000ULL,
+ 0x0c20000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minh", TILE_OPC_MINH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000480000ULL,
+ 0x0822000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minh.sn", TILE_OPC_MINH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008480000ULL,
+ 0x0c22000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minib_u", TILE_OPC_MINIB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040600000ULL,
+ 0x3040000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minib_u.sn", TILE_OPC_MINIB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048600000ULL,
+ 0x3440000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minih", TILE_OPC_MINIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040700000ULL,
+ 0x3048000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "minih.sn", TILE_OPC_MINIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048700000ULL,
+ 0x3448000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mm", TILE_OPC_MM, 0x3 /* pipes */, 5 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16, 26, 27 },
+ { 9, 10, 17, 28, 29 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000070000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000060000000ULL,
+ 0x3800000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mnz", TILE_OPC_MNZ, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000540000ULL,
+ 0x0828000000000000ULL,
+ 0x8000000010000000ULL,
+ 0x9002000000000000ULL,
+ -1ULL
+ }
+ },
+ { "mnz.sn", TILE_OPC_MNZ_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008540000ULL,
+ 0x0c28000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mnzb", TILE_OPC_MNZB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000004c0000ULL,
+ 0x0824000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mnzb.sn", TILE_OPC_MNZB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000084c0000ULL,
+ 0x0c24000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mnzh", TILE_OPC_MNZH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000500000ULL,
+ 0x0826000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mnzh.sn", TILE_OPC_MNZH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008500000ULL,
+ 0x0c26000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mtspr", TILE_OPC_MTSPR, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 30, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbf8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x3050000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_ss", TILE_OPC_MULHH_SS, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 11, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000680000ULL,
+ -1ULL,
+ 0x8000000038000000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_ss.sn", TILE_OPC_MULHH_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008680000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_su", TILE_OPC_MULHH_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000006c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_su.sn", TILE_OPC_MULHH_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000086c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_uu", TILE_OPC_MULHH_UU, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 11, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000700000ULL,
+ -1ULL,
+ 0x8000000038040000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhh_uu.sn", TILE_OPC_MULHH_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008700000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_ss", TILE_OPC_MULHHA_SS, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000580000ULL,
+ -1ULL,
+ 0x8000000040000000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_ss.sn", TILE_OPC_MULHHA_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008580000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_su", TILE_OPC_MULHHA_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000005c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_su.sn", TILE_OPC_MULHHA_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000085c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_uu", TILE_OPC_MULHHA_UU, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000600000ULL,
+ -1ULL,
+ 0x8000000040040000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhha_uu.sn", TILE_OPC_MULHHA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008600000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhhsa_uu", TILE_OPC_MULHHSA_UU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000640000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhhsa_uu.sn", TILE_OPC_MULHHSA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008640000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_ss", TILE_OPC_MULHL_SS, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000880000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_ss.sn", TILE_OPC_MULHL_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008880000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_su", TILE_OPC_MULHL_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000008c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_su.sn", TILE_OPC_MULHL_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000088c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_us", TILE_OPC_MULHL_US, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000900000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_us.sn", TILE_OPC_MULHL_US_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008900000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_uu", TILE_OPC_MULHL_UU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000940000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhl_uu.sn", TILE_OPC_MULHL_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008940000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_ss", TILE_OPC_MULHLA_SS, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000740000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_ss.sn", TILE_OPC_MULHLA_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008740000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_su", TILE_OPC_MULHLA_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000780000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_su.sn", TILE_OPC_MULHLA_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008780000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_us", TILE_OPC_MULHLA_US, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000007c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_us.sn", TILE_OPC_MULHLA_US_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000087c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_uu", TILE_OPC_MULHLA_UU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000800000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhla_uu.sn", TILE_OPC_MULHLA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008800000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhlsa_uu", TILE_OPC_MULHLSA_UU, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000840000ULL,
+ -1ULL,
+ 0x8000000030000000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulhlsa_uu.sn", TILE_OPC_MULHLSA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008840000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_ss", TILE_OPC_MULLL_SS, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 11, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000a80000ULL,
+ -1ULL,
+ 0x8000000038080000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_ss.sn", TILE_OPC_MULLL_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008a80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_su", TILE_OPC_MULLL_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000ac0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_su.sn", TILE_OPC_MULLL_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008ac0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_uu", TILE_OPC_MULLL_UU, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 11, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000b00000ULL,
+ -1ULL,
+ 0x80000000380c0000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulll_uu.sn", TILE_OPC_MULLL_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008b00000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_ss", TILE_OPC_MULLLA_SS, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000980000ULL,
+ -1ULL,
+ 0x8000000040080000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_ss.sn", TILE_OPC_MULLLA_SS_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008980000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_su", TILE_OPC_MULLLA_SU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000009c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_su.sn", TILE_OPC_MULLLA_SU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000089c0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_uu", TILE_OPC_MULLLA_UU, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000a00000ULL,
+ -1ULL,
+ 0x80000000400c0000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mullla_uu.sn", TILE_OPC_MULLLA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008a00000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulllsa_uu", TILE_OPC_MULLLSA_UU, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000a40000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mulllsa_uu.sn", TILE_OPC_MULLLSA_UU_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008a40000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mvnz", TILE_OPC_MVNZ, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000b40000ULL,
+ -1ULL,
+ 0x8000000010040000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mvnz.sn", TILE_OPC_MVNZ_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008b40000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mvz", TILE_OPC_MVZ, 0x5 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 31, 12, 18 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0x80000000780c0000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000b80000ULL,
+ -1ULL,
+ 0x8000000010080000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mvz.sn", TILE_OPC_MVZ_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008b80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mz", TILE_OPC_MZ, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000c40000ULL,
+ 0x082e000000000000ULL,
+ 0x80000000100c0000ULL,
+ 0x9004000000000000ULL,
+ -1ULL
+ }
+ },
+ { "mz.sn", TILE_OPC_MZ_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008c40000ULL,
+ 0x0c2e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mzb", TILE_OPC_MZB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000bc0000ULL,
+ 0x082a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mzb.sn", TILE_OPC_MZB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008bc0000ULL,
+ 0x0c2a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mzh", TILE_OPC_MZH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000c00000ULL,
+ 0x082c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "mzh.sn", TILE_OPC_MZH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008c00000ULL,
+ 0x0c2c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "nap", TILE_OPC_NAP, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b800000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "nop", TILE_OPC_NOP, 0xf /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { },
+ { },
+ { },
+ { },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x8000000077fff000ULL,
+ 0xfbfff80000000000ULL,
+ 0x80000000780ff000ULL,
+ 0xf807f80000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070166000ULL,
+ 0x400b880000000000ULL,
+ 0x80000000680a6000ULL,
+ 0xd805180000000000ULL,
+ -1ULL
+ }
+ },
+ { "nor", TILE_OPC_NOR, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000c80000ULL,
+ 0x0830000000000000ULL,
+ 0x8000000018040000ULL,
+ 0x9802000000000000ULL,
+ -1ULL
+ }
+ },
+ { "nor.sn", TILE_OPC_NOR_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008c80000ULL,
+ 0x0c30000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "or", TILE_OPC_OR, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000cc0000ULL,
+ 0x0832000000000000ULL,
+ 0x8000000018080000ULL,
+ 0x9804000000000000ULL,
+ -1ULL
+ }
+ },
+ { "or.sn", TILE_OPC_OR_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008cc0000ULL,
+ 0x0c32000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "ori", TILE_OPC_ORI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040800000ULL,
+ 0x3058000000000000ULL,
+ 0x8000000058000000ULL,
+ 0xc800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "ori.sn", TILE_OPC_ORI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048800000ULL,
+ 0x3458000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packbs_u", TILE_OPC_PACKBS_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000019c0000ULL,
+ 0x0892000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packbs_u.sn", TILE_OPC_PACKBS_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000099c0000ULL,
+ 0x0c92000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packhb", TILE_OPC_PACKHB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000d00000ULL,
+ 0x0834000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packhb.sn", TILE_OPC_PACKHB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008d00000ULL,
+ 0x0c34000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packhs", TILE_OPC_PACKHS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001980000ULL,
+ 0x0890000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packhs.sn", TILE_OPC_PACKHS_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009980000ULL,
+ 0x0c90000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packlb", TILE_OPC_PACKLB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000d40000ULL,
+ 0x0836000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "packlb.sn", TILE_OPC_PACKLB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008d40000ULL,
+ 0x0c36000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "pcnt", TILE_OPC_PCNT, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 11, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070167000ULL,
+ -1ULL,
+ 0x80000000680a7000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "pcnt.sn", TILE_OPC_PCNT_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078167000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "rl", TILE_OPC_RL, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000d80000ULL,
+ 0x0838000000000000ULL,
+ 0x8000000020000000ULL,
+ 0xa000000000000000ULL,
+ -1ULL
+ }
+ },
+ { "rl.sn", TILE_OPC_RL_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008d80000ULL,
+ 0x0c38000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "rli", TILE_OPC_RLI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 11, 12, 34 },
+ { 13, 14, 35 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0x80000000780e0000ULL,
+ 0xf807000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070020000ULL,
+ 0x4001000000000000ULL,
+ 0x8000000068020000ULL,
+ 0xd801000000000000ULL,
+ -1ULL
+ }
+ },
+ { "rli.sn", TILE_OPC_RLI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078020000ULL,
+ 0x4401000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "s1a", TILE_OPC_S1A, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000dc0000ULL,
+ 0x083a000000000000ULL,
+ 0x8000000008040000ULL,
+ 0x8802000000000000ULL,
+ -1ULL
+ }
+ },
+ { "s1a.sn", TILE_OPC_S1A_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008dc0000ULL,
+ 0x0c3a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "s2a", TILE_OPC_S2A, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000e00000ULL,
+ 0x083c000000000000ULL,
+ 0x8000000008080000ULL,
+ 0x8804000000000000ULL,
+ -1ULL
+ }
+ },
+ { "s2a.sn", TILE_OPC_S2A_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008e00000ULL,
+ 0x0c3c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "s3a", TILE_OPC_S3A, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000e40000ULL,
+ 0x083e000000000000ULL,
+ 0x8000000030040000ULL,
+ 0xb002000000000000ULL,
+ -1ULL
+ }
+ },
+ { "s3a.sn", TILE_OPC_S3A_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008e40000ULL,
+ 0x0c3e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadab_u", TILE_OPC_SADAB_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000e80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadab_u.sn", TILE_OPC_SADAB_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008e80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadah", TILE_OPC_SADAH, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000ec0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadah.sn", TILE_OPC_SADAH_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008ec0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadah_u", TILE_OPC_SADAH_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000f00000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadah_u.sn", TILE_OPC_SADAH_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008f00000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadb_u", TILE_OPC_SADB_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000f40000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadb_u.sn", TILE_OPC_SADB_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008f40000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadh", TILE_OPC_SADH, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000f80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadh.sn", TILE_OPC_SADH_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008f80000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadh_u", TILE_OPC_SADH_U, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000000fc0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sadh_u.sn", TILE_OPC_SADH_U_SN, 0x1 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000008fc0000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sb", TILE_OPC_SB, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 17 },
+ { 0, },
+ { 0, },
+ { 15, 36 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0840000000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8500000000000000ULL
+ }
+ },
+ { "sbadd", TILE_OPC_SBADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 24, 17, 37 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbf8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30e0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seq", TILE_OPC_SEQ, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001080000ULL,
+ 0x0846000000000000ULL,
+ 0x8000000030080000ULL,
+ 0xb004000000000000ULL,
+ -1ULL
+ }
+ },
+ { "seq.sn", TILE_OPC_SEQ_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009080000ULL,
+ 0x0c46000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqb", TILE_OPC_SEQB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001000000ULL,
+ 0x0842000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqb.sn", TILE_OPC_SEQB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009000000ULL,
+ 0x0c42000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqh", TILE_OPC_SEQH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001040000ULL,
+ 0x0844000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqh.sn", TILE_OPC_SEQH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009040000ULL,
+ 0x0c44000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqi", TILE_OPC_SEQI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040b00000ULL,
+ 0x3070000000000000ULL,
+ 0x8000000060000000ULL,
+ 0xd000000000000000ULL,
+ -1ULL
+ }
+ },
+ { "seqi.sn", TILE_OPC_SEQI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048b00000ULL,
+ 0x3470000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqib", TILE_OPC_SEQIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040900000ULL,
+ 0x3060000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqib.sn", TILE_OPC_SEQIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048900000ULL,
+ 0x3460000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqih", TILE_OPC_SEQIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040a00000ULL,
+ 0x3068000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "seqih.sn", TILE_OPC_SEQIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048a00000ULL,
+ 0x3468000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sh", TILE_OPC_SH, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 17 },
+ { 0, },
+ { 0, },
+ { 15, 36 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0854000000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8600000000000000ULL
+ }
+ },
+ { "shadd", TILE_OPC_SHADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 24, 17, 37 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbf8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30e8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shl", TILE_OPC_SHL, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001140000ULL,
+ 0x084c000000000000ULL,
+ 0x8000000020040000ULL,
+ 0xa002000000000000ULL,
+ -1ULL
+ }
+ },
+ { "shl.sn", TILE_OPC_SHL_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009140000ULL,
+ 0x0c4c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlb", TILE_OPC_SHLB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000010c0000ULL,
+ 0x0848000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlb.sn", TILE_OPC_SHLB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000090c0000ULL,
+ 0x0c48000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlh", TILE_OPC_SHLH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001100000ULL,
+ 0x084a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlh.sn", TILE_OPC_SHLH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009100000ULL,
+ 0x0c4a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shli", TILE_OPC_SHLI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 11, 12, 34 },
+ { 13, 14, 35 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0x80000000780e0000ULL,
+ 0xf807000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070080000ULL,
+ 0x4004000000000000ULL,
+ 0x8000000068040000ULL,
+ 0xd802000000000000ULL,
+ -1ULL
+ }
+ },
+ { "shli.sn", TILE_OPC_SHLI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078080000ULL,
+ 0x4404000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlib", TILE_OPC_SHLIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070040000ULL,
+ 0x4002000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlib.sn", TILE_OPC_SHLIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078040000ULL,
+ 0x4402000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlih", TILE_OPC_SHLIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070060000ULL,
+ 0x4003000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shlih.sn", TILE_OPC_SHLIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078060000ULL,
+ 0x4403000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shr", TILE_OPC_SHR, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001200000ULL,
+ 0x0852000000000000ULL,
+ 0x8000000020080000ULL,
+ 0xa004000000000000ULL,
+ -1ULL
+ }
+ },
+ { "shr.sn", TILE_OPC_SHR_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009200000ULL,
+ 0x0c52000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrb", TILE_OPC_SHRB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001180000ULL,
+ 0x084e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrb.sn", TILE_OPC_SHRB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009180000ULL,
+ 0x0c4e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrh", TILE_OPC_SHRH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000011c0000ULL,
+ 0x0850000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrh.sn", TILE_OPC_SHRH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000091c0000ULL,
+ 0x0c50000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shri", TILE_OPC_SHRI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 11, 12, 34 },
+ { 13, 14, 35 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0x80000000780e0000ULL,
+ 0xf807000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000700e0000ULL,
+ 0x4007000000000000ULL,
+ 0x8000000068060000ULL,
+ 0xd803000000000000ULL,
+ -1ULL
+ }
+ },
+ { "shri.sn", TILE_OPC_SHRI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000780e0000ULL,
+ 0x4407000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrib", TILE_OPC_SHRIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000700a0000ULL,
+ 0x4005000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrib.sn", TILE_OPC_SHRIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000780a0000ULL,
+ 0x4405000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrih", TILE_OPC_SHRIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000700c0000ULL,
+ 0x4006000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "shrih.sn", TILE_OPC_SHRIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000780c0000ULL,
+ 0x4406000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slt", TILE_OPC_SLT, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000014c0000ULL,
+ 0x086a000000000000ULL,
+ 0x8000000028080000ULL,
+ 0xa804000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slt.sn", TILE_OPC_SLT_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000094c0000ULL,
+ 0x0c6a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slt_u", TILE_OPC_SLT_U, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001500000ULL,
+ 0x086c000000000000ULL,
+ 0x80000000280c0000ULL,
+ 0xa806000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slt_u.sn", TILE_OPC_SLT_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009500000ULL,
+ 0x0c6c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltb", TILE_OPC_SLTB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001240000ULL,
+ 0x0856000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltb.sn", TILE_OPC_SLTB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009240000ULL,
+ 0x0c56000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltb_u", TILE_OPC_SLTB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001280000ULL,
+ 0x0858000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltb_u.sn", TILE_OPC_SLTB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009280000ULL,
+ 0x0c58000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slte", TILE_OPC_SLTE, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000013c0000ULL,
+ 0x0862000000000000ULL,
+ 0x8000000028000000ULL,
+ 0xa800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slte.sn", TILE_OPC_SLTE_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000093c0000ULL,
+ 0x0c62000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slte_u", TILE_OPC_SLTE_U, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001400000ULL,
+ 0x0864000000000000ULL,
+ 0x8000000028040000ULL,
+ 0xa802000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slte_u.sn", TILE_OPC_SLTE_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009400000ULL,
+ 0x0c64000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteb", TILE_OPC_SLTEB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000012c0000ULL,
+ 0x085a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteb.sn", TILE_OPC_SLTEB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000092c0000ULL,
+ 0x0c5a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteb_u", TILE_OPC_SLTEB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001300000ULL,
+ 0x085c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteb_u.sn", TILE_OPC_SLTEB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009300000ULL,
+ 0x0c5c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteh", TILE_OPC_SLTEH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001340000ULL,
+ 0x085e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteh.sn", TILE_OPC_SLTEH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009340000ULL,
+ 0x0c5e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteh_u", TILE_OPC_SLTEH_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001380000ULL,
+ 0x0860000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slteh_u.sn", TILE_OPC_SLTEH_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009380000ULL,
+ 0x0c60000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slth", TILE_OPC_SLTH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001440000ULL,
+ 0x0866000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slth.sn", TILE_OPC_SLTH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009440000ULL,
+ 0x0c66000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slth_u", TILE_OPC_SLTH_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001480000ULL,
+ 0x0868000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slth_u.sn", TILE_OPC_SLTH_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009480000ULL,
+ 0x0c68000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slti", TILE_OPC_SLTI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000041000000ULL,
+ 0x3098000000000000ULL,
+ 0x8000000070000000ULL,
+ 0xe000000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slti.sn", TILE_OPC_SLTI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000049000000ULL,
+ 0x3498000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "slti_u", TILE_OPC_SLTI_U, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 11, 12, 2 },
+ { 13, 14, 3 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xf800000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000041100000ULL,
+ 0x30a0000000000000ULL,
+ 0x8000000078000000ULL,
+ 0xe800000000000000ULL,
+ -1ULL
+ }
+ },
+ { "slti_u.sn", TILE_OPC_SLTI_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000049100000ULL,
+ 0x34a0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltib", TILE_OPC_SLTIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040c00000ULL,
+ 0x3078000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltib.sn", TILE_OPC_SLTIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048c00000ULL,
+ 0x3478000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltib_u", TILE_OPC_SLTIB_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040d00000ULL,
+ 0x3080000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltib_u.sn", TILE_OPC_SLTIB_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048d00000ULL,
+ 0x3480000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltih", TILE_OPC_SLTIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040e00000ULL,
+ 0x3088000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltih.sn", TILE_OPC_SLTIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048e00000ULL,
+ 0x3488000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltih_u", TILE_OPC_SLTIH_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000040f00000ULL,
+ 0x3090000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sltih_u.sn", TILE_OPC_SLTIH_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000048f00000ULL,
+ 0x3490000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sne", TILE_OPC_SNE, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000015c0000ULL,
+ 0x0872000000000000ULL,
+ 0x80000000300c0000ULL,
+ 0xb006000000000000ULL,
+ -1ULL
+ }
+ },
+ { "sne.sn", TILE_OPC_SNE_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000095c0000ULL,
+ 0x0c72000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sneb", TILE_OPC_SNEB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001540000ULL,
+ 0x086e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sneb.sn", TILE_OPC_SNEB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009540000ULL,
+ 0x0c6e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sneh", TILE_OPC_SNEH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001580000ULL,
+ 0x0870000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sneh.sn", TILE_OPC_SNEH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009580000ULL,
+ 0x0c70000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sra", TILE_OPC_SRA, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001680000ULL,
+ 0x0878000000000000ULL,
+ 0x80000000200c0000ULL,
+ 0xa006000000000000ULL,
+ -1ULL
+ }
+ },
+ { "sra.sn", TILE_OPC_SRA_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009680000ULL,
+ 0x0c78000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "srab", TILE_OPC_SRAB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001600000ULL,
+ 0x0874000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "srab.sn", TILE_OPC_SRAB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009600000ULL,
+ 0x0c74000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "srah", TILE_OPC_SRAH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001640000ULL,
+ 0x0876000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "srah.sn", TILE_OPC_SRAH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009640000ULL,
+ 0x0c76000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "srai", TILE_OPC_SRAI, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 11, 12, 34 },
+ { 13, 14, 35 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0x80000000780e0000ULL,
+ 0xf807000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070140000ULL,
+ 0x400a000000000000ULL,
+ 0x8000000068080000ULL,
+ 0xd804000000000000ULL,
+ -1ULL
+ }
+ },
+ { "srai.sn", TILE_OPC_SRAI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078140000ULL,
+ 0x440a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sraib", TILE_OPC_SRAIB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070100000ULL,
+ 0x4008000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sraib.sn", TILE_OPC_SRAIB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078100000ULL,
+ 0x4408000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sraih", TILE_OPC_SRAIH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070120000ULL,
+ 0x4009000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sraih.sn", TILE_OPC_SRAIH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 32 },
+ { 9, 10, 33 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffe0000ULL,
+ 0xffff000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078120000ULL,
+ 0x4409000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sub", TILE_OPC_SUB, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001740000ULL,
+ 0x087e000000000000ULL,
+ 0x80000000080c0000ULL,
+ 0x8806000000000000ULL,
+ -1ULL
+ }
+ },
+ { "sub.sn", TILE_OPC_SUB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009740000ULL,
+ 0x0c7e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subb", TILE_OPC_SUBB, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000016c0000ULL,
+ 0x087a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subb.sn", TILE_OPC_SUBB_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x00000000096c0000ULL,
+ 0x0c7a000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subbs_u", TILE_OPC_SUBBS_U, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001900000ULL,
+ 0x088c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subbs_u.sn", TILE_OPC_SUBBS_U_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009900000ULL,
+ 0x0c8c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subh", TILE_OPC_SUBH, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001700000ULL,
+ 0x087c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subh.sn", TILE_OPC_SUBH_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009700000ULL,
+ 0x0c7c000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subhs", TILE_OPC_SUBHS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001940000ULL,
+ 0x088e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subhs.sn", TILE_OPC_SUBHS_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009940000ULL,
+ 0x0c8e000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subs", TILE_OPC_SUBS, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001840000ULL,
+ 0x0886000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "subs.sn", TILE_OPC_SUBS_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009840000ULL,
+ 0x0c86000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "sw", TILE_OPC_SW, 0x12 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10, 17 },
+ { 0, },
+ { 0, },
+ { 15, 36 }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0x8700000000000000ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x0880000000000000ULL,
+ -1ULL,
+ -1ULL,
+ 0x8700000000000000ULL
+ }
+ },
+ { "swadd", TILE_OPC_SWADD, 0x2 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 24, 17, 37 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbf8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x30f0000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "swint0", TILE_OPC_SWINT0, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b900000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "swint1", TILE_OPC_SWINT1, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400b980000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "swint2", TILE_OPC_SWINT2, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400ba00000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "swint3", TILE_OPC_SWINT3, 0x2 /* pipes */, 0 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 0, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400ba80000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb0", TILE_OPC_TBLIDXB0, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 31, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070168000ULL,
+ -1ULL,
+ 0x80000000680a8000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb0.sn", TILE_OPC_TBLIDXB0_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078168000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb1", TILE_OPC_TBLIDXB1, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 31, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000070169000ULL,
+ -1ULL,
+ 0x80000000680a9000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb1.sn", TILE_OPC_TBLIDXB1_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000078169000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb2", TILE_OPC_TBLIDXB2, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 31, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x000000007016a000ULL,
+ -1ULL,
+ 0x80000000680aa000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb2.sn", TILE_OPC_TBLIDXB2_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x000000007816a000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb3", TILE_OPC_TBLIDXB3, 0x5 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 31, 12 },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0x80000000780ff000ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x000000007016b000ULL,
+ -1ULL,
+ 0x80000000680ab000ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tblidxb3.sn", TILE_OPC_TBLIDXB3_SN, 0x1 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 21, 8 },
+ { 0, },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffff000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x000000007816b000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tns", TILE_OPC_TNS, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400bb00000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "tns.sn", TILE_OPC_TNS_SN, 0x2 /* pipes */, 2 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 9, 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfffff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x440bb00000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "wh64", TILE_OPC_WH64, 0x2 /* pipes */, 1 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 0, },
+ { 10 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0ULL,
+ 0xfbfff80000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ -1ULL,
+ 0x400bb80000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "xor", TILE_OPC_XOR, 0xf /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 11, 12, 18 },
+ { 13, 14, 19 },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0x80000000780c0000ULL,
+ 0xf806000000000000ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000001780000ULL,
+ 0x0882000000000000ULL,
+ 0x80000000180c0000ULL,
+ 0x9806000000000000ULL,
+ -1ULL
+ }
+ },
+ { "xor.sn", TILE_OPC_XOR_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 16 },
+ { 9, 10, 17 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ffc0000ULL,
+ 0xfffe000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000009780000ULL,
+ 0x0c82000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "xori", TILE_OPC_XORI, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_ZERO, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000050200000ULL,
+ 0x30a8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { "xori.sn", TILE_OPC_XORI_SN, 0x3 /* pipes */, 3 /* num_operands */,
+ TREG_SN, /* implicitly_written_register */
+ 1, /* can_bundle */
+ {
+ /* operands */
+ { 7, 8, 0 },
+ { 9, 10, 1 },
+ { 0, },
+ { 0, },
+ { 0, }
+ },
+ {
+ /* fixed_bit_masks */
+ 0x800000007ff00000ULL,
+ 0xfff8000000000000ULL,
+ 0ULL,
+ 0ULL,
+ 0ULL
+ },
+ {
+ /* fixed_bit_values */
+ 0x0000000058200000ULL,
+ 0x34a8000000000000ULL,
+ -1ULL,
+ -1ULL,
+ -1ULL
+ }
+ },
+ { 0, TILE_OPC_NONE, 0, 0, 0, TREG_ZERO, { { 0, } }, { 0, }, { 0, }
+ }
+};
+#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6))
+#define CHILD(array_index) (TILE_OPC_NONE + (array_index))
+
+static const unsigned short decode_X0_fsm[1153] =
+{
+ BITFIELD(22, 9) /* index 0 */,
+ CHILD(513), CHILD(530), CHILD(547), CHILD(564), CHILD(596), CHILD(613),
+ CHILD(630), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, CHILD(663), CHILD(680), CHILD(697), CHILD(714), CHILD(746),
+ CHILD(763), CHILD(780), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813),
+ CHILD(813), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828),
+ CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(873), CHILD(878), CHILD(883),
+ CHILD(903), CHILD(908), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(913),
+ CHILD(918), CHILD(923), CHILD(943), CHILD(948), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, CHILD(953), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(988), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, CHILD(993),
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, CHILD(1076), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(18, 4) /* index 513 */,
+ TILE_OPC_NONE, TILE_OPC_ADDB, TILE_OPC_ADDH, TILE_OPC_ADD,
+ TILE_OPC_ADIFFB_U, TILE_OPC_ADIFFH, TILE_OPC_AND, TILE_OPC_AVGB_U,
+ TILE_OPC_AVGH, TILE_OPC_CRC32_32, TILE_OPC_CRC32_8, TILE_OPC_INTHB,
+ TILE_OPC_INTHH, TILE_OPC_INTLB, TILE_OPC_INTLH, TILE_OPC_MAXB_U,
+ BITFIELD(18, 4) /* index 530 */,
+ TILE_OPC_MAXH, TILE_OPC_MINB_U, TILE_OPC_MINH, TILE_OPC_MNZB, TILE_OPC_MNZH,
+ TILE_OPC_MNZ, TILE_OPC_MULHHA_SS, TILE_OPC_MULHHA_SU, TILE_OPC_MULHHA_UU,
+ TILE_OPC_MULHHSA_UU, TILE_OPC_MULHH_SS, TILE_OPC_MULHH_SU,
+ TILE_OPC_MULHH_UU, TILE_OPC_MULHLA_SS, TILE_OPC_MULHLA_SU,
+ TILE_OPC_MULHLA_US,
+ BITFIELD(18, 4) /* index 547 */,
+ TILE_OPC_MULHLA_UU, TILE_OPC_MULHLSA_UU, TILE_OPC_MULHL_SS,
+ TILE_OPC_MULHL_SU, TILE_OPC_MULHL_US, TILE_OPC_MULHL_UU, TILE_OPC_MULLLA_SS,
+ TILE_OPC_MULLLA_SU, TILE_OPC_MULLLA_UU, TILE_OPC_MULLLSA_UU,
+ TILE_OPC_MULLL_SS, TILE_OPC_MULLL_SU, TILE_OPC_MULLL_UU, TILE_OPC_MVNZ,
+ TILE_OPC_MVZ, TILE_OPC_MZB,
+ BITFIELD(18, 4) /* index 564 */,
+ TILE_OPC_MZH, TILE_OPC_MZ, TILE_OPC_NOR, CHILD(581), TILE_OPC_PACKHB,
+ TILE_OPC_PACKLB, TILE_OPC_RL, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_S3A,
+ TILE_OPC_SADAB_U, TILE_OPC_SADAH, TILE_OPC_SADAH_U, TILE_OPC_SADB_U,
+ TILE_OPC_SADH, TILE_OPC_SADH_U,
+ BITFIELD(12, 2) /* index 581 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(586),
+ BITFIELD(14, 2) /* index 586 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(591),
+ BITFIELD(16, 2) /* index 591 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE,
+ BITFIELD(18, 4) /* index 596 */,
+ TILE_OPC_SEQB, TILE_OPC_SEQH, TILE_OPC_SEQ, TILE_OPC_SHLB, TILE_OPC_SHLH,
+ TILE_OPC_SHL, TILE_OPC_SHRB, TILE_OPC_SHRH, TILE_OPC_SHR, TILE_OPC_SLTB,
+ TILE_OPC_SLTB_U, TILE_OPC_SLTEB, TILE_OPC_SLTEB_U, TILE_OPC_SLTEH,
+ TILE_OPC_SLTEH_U, TILE_OPC_SLTE,
+ BITFIELD(18, 4) /* index 613 */,
+ TILE_OPC_SLTE_U, TILE_OPC_SLTH, TILE_OPC_SLTH_U, TILE_OPC_SLT,
+ TILE_OPC_SLT_U, TILE_OPC_SNEB, TILE_OPC_SNEH, TILE_OPC_SNE, TILE_OPC_SRAB,
+ TILE_OPC_SRAH, TILE_OPC_SRA, TILE_OPC_SUBB, TILE_OPC_SUBH, TILE_OPC_SUB,
+ TILE_OPC_XOR, TILE_OPC_DWORD_ALIGN,
+ BITFIELD(18, 3) /* index 630 */,
+ CHILD(639), CHILD(642), CHILD(645), CHILD(648), CHILD(651), CHILD(654),
+ CHILD(657), CHILD(660),
+ BITFIELD(21, 1) /* index 639 */,
+ TILE_OPC_ADDS, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 642 */,
+ TILE_OPC_SUBS, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 645 */,
+ TILE_OPC_ADDBS_U, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 648 */,
+ TILE_OPC_ADDHS, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 651 */,
+ TILE_OPC_SUBBS_U, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 654 */,
+ TILE_OPC_SUBHS, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 657 */,
+ TILE_OPC_PACKHS, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 660 */,
+ TILE_OPC_PACKBS_U, TILE_OPC_NONE,
+ BITFIELD(18, 4) /* index 663 */,
+ TILE_OPC_NONE, TILE_OPC_ADDB_SN, TILE_OPC_ADDH_SN, TILE_OPC_ADD_SN,
+ TILE_OPC_ADIFFB_U_SN, TILE_OPC_ADIFFH_SN, TILE_OPC_AND_SN,
+ TILE_OPC_AVGB_U_SN, TILE_OPC_AVGH_SN, TILE_OPC_CRC32_32_SN,
+ TILE_OPC_CRC32_8_SN, TILE_OPC_INTHB_SN, TILE_OPC_INTHH_SN,
+ TILE_OPC_INTLB_SN, TILE_OPC_INTLH_SN, TILE_OPC_MAXB_U_SN,
+ BITFIELD(18, 4) /* index 680 */,
+ TILE_OPC_MAXH_SN, TILE_OPC_MINB_U_SN, TILE_OPC_MINH_SN, TILE_OPC_MNZB_SN,
+ TILE_OPC_MNZH_SN, TILE_OPC_MNZ_SN, TILE_OPC_MULHHA_SS_SN,
+ TILE_OPC_MULHHA_SU_SN, TILE_OPC_MULHHA_UU_SN, TILE_OPC_MULHHSA_UU_SN,
+ TILE_OPC_MULHH_SS_SN, TILE_OPC_MULHH_SU_SN, TILE_OPC_MULHH_UU_SN,
+ TILE_OPC_MULHLA_SS_SN, TILE_OPC_MULHLA_SU_SN, TILE_OPC_MULHLA_US_SN,
+ BITFIELD(18, 4) /* index 697 */,
+ TILE_OPC_MULHLA_UU_SN, TILE_OPC_MULHLSA_UU_SN, TILE_OPC_MULHL_SS_SN,
+ TILE_OPC_MULHL_SU_SN, TILE_OPC_MULHL_US_SN, TILE_OPC_MULHL_UU_SN,
+ TILE_OPC_MULLLA_SS_SN, TILE_OPC_MULLLA_SU_SN, TILE_OPC_MULLLA_UU_SN,
+ TILE_OPC_MULLLSA_UU_SN, TILE_OPC_MULLL_SS_SN, TILE_OPC_MULLL_SU_SN,
+ TILE_OPC_MULLL_UU_SN, TILE_OPC_MVNZ_SN, TILE_OPC_MVZ_SN, TILE_OPC_MZB_SN,
+ BITFIELD(18, 4) /* index 714 */,
+ TILE_OPC_MZH_SN, TILE_OPC_MZ_SN, TILE_OPC_NOR_SN, CHILD(731),
+ TILE_OPC_PACKHB_SN, TILE_OPC_PACKLB_SN, TILE_OPC_RL_SN, TILE_OPC_S1A_SN,
+ TILE_OPC_S2A_SN, TILE_OPC_S3A_SN, TILE_OPC_SADAB_U_SN, TILE_OPC_SADAH_SN,
+ TILE_OPC_SADAH_U_SN, TILE_OPC_SADB_U_SN, TILE_OPC_SADH_SN,
+ TILE_OPC_SADH_U_SN,
+ BITFIELD(12, 2) /* index 731 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(736),
+ BITFIELD(14, 2) /* index 736 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(741),
+ BITFIELD(16, 2) /* index 741 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_MOVE_SN,
+ BITFIELD(18, 4) /* index 746 */,
+ TILE_OPC_SEQB_SN, TILE_OPC_SEQH_SN, TILE_OPC_SEQ_SN, TILE_OPC_SHLB_SN,
+ TILE_OPC_SHLH_SN, TILE_OPC_SHL_SN, TILE_OPC_SHRB_SN, TILE_OPC_SHRH_SN,
+ TILE_OPC_SHR_SN, TILE_OPC_SLTB_SN, TILE_OPC_SLTB_U_SN, TILE_OPC_SLTEB_SN,
+ TILE_OPC_SLTEB_U_SN, TILE_OPC_SLTEH_SN, TILE_OPC_SLTEH_U_SN,
+ TILE_OPC_SLTE_SN,
+ BITFIELD(18, 4) /* index 763 */,
+ TILE_OPC_SLTE_U_SN, TILE_OPC_SLTH_SN, TILE_OPC_SLTH_U_SN, TILE_OPC_SLT_SN,
+ TILE_OPC_SLT_U_SN, TILE_OPC_SNEB_SN, TILE_OPC_SNEH_SN, TILE_OPC_SNE_SN,
+ TILE_OPC_SRAB_SN, TILE_OPC_SRAH_SN, TILE_OPC_SRA_SN, TILE_OPC_SUBB_SN,
+ TILE_OPC_SUBH_SN, TILE_OPC_SUB_SN, TILE_OPC_XOR_SN, TILE_OPC_DWORD_ALIGN_SN,
+ BITFIELD(18, 3) /* index 780 */,
+ CHILD(789), CHILD(792), CHILD(795), CHILD(798), CHILD(801), CHILD(804),
+ CHILD(807), CHILD(810),
+ BITFIELD(21, 1) /* index 789 */,
+ TILE_OPC_ADDS_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 792 */,
+ TILE_OPC_SUBS_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 795 */,
+ TILE_OPC_ADDBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 798 */,
+ TILE_OPC_ADDHS_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 801 */,
+ TILE_OPC_SUBBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 804 */,
+ TILE_OPC_SUBHS_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 807 */,
+ TILE_OPC_PACKHS_SN, TILE_OPC_NONE,
+ BITFIELD(21, 1) /* index 810 */,
+ TILE_OPC_PACKBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(6, 2) /* index 813 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(818),
+ BITFIELD(8, 2) /* index 818 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(823),
+ BITFIELD(10, 2) /* index 823 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_MOVELI_SN,
+ BITFIELD(6, 2) /* index 828 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(833),
+ BITFIELD(8, 2) /* index 833 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(838),
+ BITFIELD(10, 2) /* index 838 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_MOVELI,
+ BITFIELD(0, 2) /* index 843 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(848),
+ BITFIELD(2, 2) /* index 848 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(853),
+ BITFIELD(4, 2) /* index 853 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(858),
+ BITFIELD(6, 2) /* index 858 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(863),
+ BITFIELD(8, 2) /* index 863 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(868),
+ BITFIELD(10, 2) /* index 868 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_INFOL,
+ BITFIELD(20, 2) /* index 873 */,
+ TILE_OPC_NONE, TILE_OPC_ADDIB, TILE_OPC_ADDIH, TILE_OPC_ADDI,
+ BITFIELD(20, 2) /* index 878 */,
+ TILE_OPC_MAXIB_U, TILE_OPC_MAXIH, TILE_OPC_MINIB_U, TILE_OPC_MINIH,
+ BITFIELD(20, 2) /* index 883 */,
+ CHILD(888), TILE_OPC_SEQIB, TILE_OPC_SEQIH, TILE_OPC_SEQI,
+ BITFIELD(6, 2) /* index 888 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(893),
+ BITFIELD(8, 2) /* index 893 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(898),
+ BITFIELD(10, 2) /* index 898 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI,
+ BITFIELD(20, 2) /* index 903 */,
+ TILE_OPC_SLTIB, TILE_OPC_SLTIB_U, TILE_OPC_SLTIH, TILE_OPC_SLTIH_U,
+ BITFIELD(20, 2) /* index 908 */,
+ TILE_OPC_SLTI, TILE_OPC_SLTI_U, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(20, 2) /* index 913 */,
+ TILE_OPC_NONE, TILE_OPC_ADDIB_SN, TILE_OPC_ADDIH_SN, TILE_OPC_ADDI_SN,
+ BITFIELD(20, 2) /* index 918 */,
+ TILE_OPC_MAXIB_U_SN, TILE_OPC_MAXIH_SN, TILE_OPC_MINIB_U_SN,
+ TILE_OPC_MINIH_SN,
+ BITFIELD(20, 2) /* index 923 */,
+ CHILD(928), TILE_OPC_SEQIB_SN, TILE_OPC_SEQIH_SN, TILE_OPC_SEQI_SN,
+ BITFIELD(6, 2) /* index 928 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(933),
+ BITFIELD(8, 2) /* index 933 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(938),
+ BITFIELD(10, 2) /* index 938 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_MOVEI_SN,
+ BITFIELD(20, 2) /* index 943 */,
+ TILE_OPC_SLTIB_SN, TILE_OPC_SLTIB_U_SN, TILE_OPC_SLTIH_SN,
+ TILE_OPC_SLTIH_U_SN,
+ BITFIELD(20, 2) /* index 948 */,
+ TILE_OPC_SLTI_SN, TILE_OPC_SLTI_U_SN, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(20, 2) /* index 953 */,
+ TILE_OPC_NONE, CHILD(958), TILE_OPC_XORI, TILE_OPC_NONE,
+ BITFIELD(0, 2) /* index 958 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(963),
+ BITFIELD(2, 2) /* index 963 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(968),
+ BITFIELD(4, 2) /* index 968 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(973),
+ BITFIELD(6, 2) /* index 973 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(978),
+ BITFIELD(8, 2) /* index 978 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(983),
+ BITFIELD(10, 2) /* index 983 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO,
+ BITFIELD(20, 2) /* index 988 */,
+ TILE_OPC_NONE, TILE_OPC_ANDI_SN, TILE_OPC_XORI_SN, TILE_OPC_NONE,
+ BITFIELD(17, 5) /* index 993 */,
+ TILE_OPC_NONE, TILE_OPC_RLI, TILE_OPC_SHLIB, TILE_OPC_SHLIH, TILE_OPC_SHLI,
+ TILE_OPC_SHRIB, TILE_OPC_SHRIH, TILE_OPC_SHRI, TILE_OPC_SRAIB,
+ TILE_OPC_SRAIH, TILE_OPC_SRAI, CHILD(1026), TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(12, 4) /* index 1026 */,
+ TILE_OPC_NONE, CHILD(1043), CHILD(1046), CHILD(1049), CHILD(1052),
+ CHILD(1055), CHILD(1058), CHILD(1061), CHILD(1064), CHILD(1067),
+ CHILD(1070), CHILD(1073), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1043 */,
+ TILE_OPC_BITX, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1046 */,
+ TILE_OPC_BYTEX, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1049 */,
+ TILE_OPC_CLZ, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1052 */,
+ TILE_OPC_CTZ, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1055 */,
+ TILE_OPC_FNOP, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1058 */,
+ TILE_OPC_NOP, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1061 */,
+ TILE_OPC_PCNT, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1064 */,
+ TILE_OPC_TBLIDXB0, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1067 */,
+ TILE_OPC_TBLIDXB1, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1070 */,
+ TILE_OPC_TBLIDXB2, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1073 */,
+ TILE_OPC_TBLIDXB3, TILE_OPC_NONE,
+ BITFIELD(17, 5) /* index 1076 */,
+ TILE_OPC_NONE, TILE_OPC_RLI_SN, TILE_OPC_SHLIB_SN, TILE_OPC_SHLIH_SN,
+ TILE_OPC_SHLI_SN, TILE_OPC_SHRIB_SN, TILE_OPC_SHRIH_SN, TILE_OPC_SHRI_SN,
+ TILE_OPC_SRAIB_SN, TILE_OPC_SRAIH_SN, TILE_OPC_SRAI_SN, CHILD(1109),
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(12, 4) /* index 1109 */,
+ TILE_OPC_NONE, CHILD(1126), CHILD(1129), CHILD(1132), CHILD(1135),
+ CHILD(1055), CHILD(1058), CHILD(1138), CHILD(1141), CHILD(1144),
+ CHILD(1147), CHILD(1150), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1126 */,
+ TILE_OPC_BITX_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1129 */,
+ TILE_OPC_BYTEX_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1132 */,
+ TILE_OPC_CLZ_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1135 */,
+ TILE_OPC_CTZ_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1138 */,
+ TILE_OPC_PCNT_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1141 */,
+ TILE_OPC_TBLIDXB0_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1144 */,
+ TILE_OPC_TBLIDXB1_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1147 */,
+ TILE_OPC_TBLIDXB2_SN, TILE_OPC_NONE,
+ BITFIELD(16, 1) /* index 1150 */,
+ TILE_OPC_TBLIDXB3_SN, TILE_OPC_NONE,
+};
+
+static const unsigned short decode_X1_fsm[1509] =
+{
+ BITFIELD(54, 9) /* index 0 */,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, CHILD(513), CHILD(561), CHILD(594),
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(641), CHILD(689),
+ CHILD(722), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(766),
+ CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766),
+ CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766),
+ CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766),
+ CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766),
+ CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766),
+ CHILD(766), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781),
+ CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781),
+ CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781),
+ CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781),
+ CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781),
+ CHILD(781), CHILD(781), CHILD(781), CHILD(796), CHILD(796), CHILD(796),
+ CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796),
+ CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796),
+ CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796),
+ CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796),
+ CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(826),
+ CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826),
+ CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826),
+ CHILD(826), CHILD(826), CHILD(826), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843),
+ CHILD(843), CHILD(860), CHILD(899), CHILD(923), CHILD(932), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, CHILD(941), CHILD(950), CHILD(974), CHILD(983),
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM,
+ TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, TILE_OPC_MM, CHILD(992),
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ CHILD(1303), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J, TILE_OPC_J,
+ TILE_OPC_J, TILE_OPC_J, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL, TILE_OPC_JAL,
+ TILE_OPC_JAL, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(49, 5) /* index 513 */,
+ TILE_OPC_NONE, TILE_OPC_ADDB, TILE_OPC_ADDH, TILE_OPC_ADD, TILE_OPC_AND,
+ TILE_OPC_INTHB, TILE_OPC_INTHH, TILE_OPC_INTLB, TILE_OPC_INTLH,
+ TILE_OPC_JALRP, TILE_OPC_JALR, TILE_OPC_JRP, TILE_OPC_JR, TILE_OPC_LNK,
+ TILE_OPC_MAXB_U, TILE_OPC_MAXH, TILE_OPC_MINB_U, TILE_OPC_MINH,
+ TILE_OPC_MNZB, TILE_OPC_MNZH, TILE_OPC_MNZ, TILE_OPC_MZB, TILE_OPC_MZH,
+ TILE_OPC_MZ, TILE_OPC_NOR, CHILD(546), TILE_OPC_PACKHB, TILE_OPC_PACKLB,
+ TILE_OPC_RL, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_S3A,
+ BITFIELD(43, 2) /* index 546 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(551),
+ BITFIELD(45, 2) /* index 551 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(556),
+ BITFIELD(47, 2) /* index 556 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE,
+ BITFIELD(49, 5) /* index 561 */,
+ TILE_OPC_SB, TILE_OPC_SEQB, TILE_OPC_SEQH, TILE_OPC_SEQ, TILE_OPC_SHLB,
+ TILE_OPC_SHLH, TILE_OPC_SHL, TILE_OPC_SHRB, TILE_OPC_SHRH, TILE_OPC_SHR,
+ TILE_OPC_SH, TILE_OPC_SLTB, TILE_OPC_SLTB_U, TILE_OPC_SLTEB,
+ TILE_OPC_SLTEB_U, TILE_OPC_SLTEH, TILE_OPC_SLTEH_U, TILE_OPC_SLTE,
+ TILE_OPC_SLTE_U, TILE_OPC_SLTH, TILE_OPC_SLTH_U, TILE_OPC_SLT,
+ TILE_OPC_SLT_U, TILE_OPC_SNEB, TILE_OPC_SNEH, TILE_OPC_SNE, TILE_OPC_SRAB,
+ TILE_OPC_SRAH, TILE_OPC_SRA, TILE_OPC_SUBB, TILE_OPC_SUBH, TILE_OPC_SUB,
+ BITFIELD(49, 4) /* index 594 */,
+ CHILD(611), CHILD(614), CHILD(617), CHILD(620), CHILD(623), CHILD(626),
+ CHILD(629), CHILD(632), CHILD(635), CHILD(638), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 611 */,
+ TILE_OPC_SW, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 614 */,
+ TILE_OPC_XOR, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 617 */,
+ TILE_OPC_ADDS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 620 */,
+ TILE_OPC_SUBS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 623 */,
+ TILE_OPC_ADDBS_U, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 626 */,
+ TILE_OPC_ADDHS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 629 */,
+ TILE_OPC_SUBBS_U, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 632 */,
+ TILE_OPC_SUBHS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 635 */,
+ TILE_OPC_PACKHS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 638 */,
+ TILE_OPC_PACKBS_U, TILE_OPC_NONE,
+ BITFIELD(49, 5) /* index 641 */,
+ TILE_OPC_NONE, TILE_OPC_ADDB_SN, TILE_OPC_ADDH_SN, TILE_OPC_ADD_SN,
+ TILE_OPC_AND_SN, TILE_OPC_INTHB_SN, TILE_OPC_INTHH_SN, TILE_OPC_INTLB_SN,
+ TILE_OPC_INTLH_SN, TILE_OPC_JALRP, TILE_OPC_JALR, TILE_OPC_JRP, TILE_OPC_JR,
+ TILE_OPC_LNK_SN, TILE_OPC_MAXB_U_SN, TILE_OPC_MAXH_SN, TILE_OPC_MINB_U_SN,
+ TILE_OPC_MINH_SN, TILE_OPC_MNZB_SN, TILE_OPC_MNZH_SN, TILE_OPC_MNZ_SN,
+ TILE_OPC_MZB_SN, TILE_OPC_MZH_SN, TILE_OPC_MZ_SN, TILE_OPC_NOR_SN,
+ CHILD(674), TILE_OPC_PACKHB_SN, TILE_OPC_PACKLB_SN, TILE_OPC_RL_SN,
+ TILE_OPC_S1A_SN, TILE_OPC_S2A_SN, TILE_OPC_S3A_SN,
+ BITFIELD(43, 2) /* index 674 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(679),
+ BITFIELD(45, 2) /* index 679 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, CHILD(684),
+ BITFIELD(47, 2) /* index 684 */,
+ TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_OR_SN, TILE_OPC_MOVE_SN,
+ BITFIELD(49, 5) /* index 689 */,
+ TILE_OPC_SB, TILE_OPC_SEQB_SN, TILE_OPC_SEQH_SN, TILE_OPC_SEQ_SN,
+ TILE_OPC_SHLB_SN, TILE_OPC_SHLH_SN, TILE_OPC_SHL_SN, TILE_OPC_SHRB_SN,
+ TILE_OPC_SHRH_SN, TILE_OPC_SHR_SN, TILE_OPC_SH, TILE_OPC_SLTB_SN,
+ TILE_OPC_SLTB_U_SN, TILE_OPC_SLTEB_SN, TILE_OPC_SLTEB_U_SN,
+ TILE_OPC_SLTEH_SN, TILE_OPC_SLTEH_U_SN, TILE_OPC_SLTE_SN,
+ TILE_OPC_SLTE_U_SN, TILE_OPC_SLTH_SN, TILE_OPC_SLTH_U_SN, TILE_OPC_SLT_SN,
+ TILE_OPC_SLT_U_SN, TILE_OPC_SNEB_SN, TILE_OPC_SNEH_SN, TILE_OPC_SNE_SN,
+ TILE_OPC_SRAB_SN, TILE_OPC_SRAH_SN, TILE_OPC_SRA_SN, TILE_OPC_SUBB_SN,
+ TILE_OPC_SUBH_SN, TILE_OPC_SUB_SN,
+ BITFIELD(49, 4) /* index 722 */,
+ CHILD(611), CHILD(739), CHILD(742), CHILD(745), CHILD(748), CHILD(751),
+ CHILD(754), CHILD(757), CHILD(760), CHILD(763), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 739 */,
+ TILE_OPC_XOR_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 742 */,
+ TILE_OPC_ADDS_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 745 */,
+ TILE_OPC_SUBS_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 748 */,
+ TILE_OPC_ADDBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 751 */,
+ TILE_OPC_ADDHS_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 754 */,
+ TILE_OPC_SUBBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 757 */,
+ TILE_OPC_SUBHS_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 760 */,
+ TILE_OPC_PACKHS_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 763 */,
+ TILE_OPC_PACKBS_U_SN, TILE_OPC_NONE,
+ BITFIELD(37, 2) /* index 766 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(771),
+ BITFIELD(39, 2) /* index 771 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, CHILD(776),
+ BITFIELD(41, 2) /* index 776 */,
+ TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_ADDLI_SN, TILE_OPC_MOVELI_SN,
+ BITFIELD(37, 2) /* index 781 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(786),
+ BITFIELD(39, 2) /* index 786 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, CHILD(791),
+ BITFIELD(41, 2) /* index 791 */,
+ TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_ADDLI, TILE_OPC_MOVELI,
+ BITFIELD(31, 2) /* index 796 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(801),
+ BITFIELD(33, 2) /* index 801 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(806),
+ BITFIELD(35, 2) /* index 806 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(811),
+ BITFIELD(37, 2) /* index 811 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(816),
+ BITFIELD(39, 2) /* index 816 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, CHILD(821),
+ BITFIELD(41, 2) /* index 821 */,
+ TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_AULI, TILE_OPC_INFOL,
+ BITFIELD(31, 4) /* index 826 */,
+ TILE_OPC_BZ, TILE_OPC_BZT, TILE_OPC_BNZ, TILE_OPC_BNZT, TILE_OPC_BGZ,
+ TILE_OPC_BGZT, TILE_OPC_BGEZ, TILE_OPC_BGEZT, TILE_OPC_BLZ, TILE_OPC_BLZT,
+ TILE_OPC_BLEZ, TILE_OPC_BLEZT, TILE_OPC_BBS, TILE_OPC_BBST, TILE_OPC_BBNS,
+ TILE_OPC_BBNST,
+ BITFIELD(31, 4) /* index 843 */,
+ TILE_OPC_BZ_SN, TILE_OPC_BZT_SN, TILE_OPC_BNZ_SN, TILE_OPC_BNZT_SN,
+ TILE_OPC_BGZ_SN, TILE_OPC_BGZT_SN, TILE_OPC_BGEZ_SN, TILE_OPC_BGEZT_SN,
+ TILE_OPC_BLZ_SN, TILE_OPC_BLZT_SN, TILE_OPC_BLEZ_SN, TILE_OPC_BLEZT_SN,
+ TILE_OPC_BBS_SN, TILE_OPC_BBST_SN, TILE_OPC_BBNS_SN, TILE_OPC_BBNST_SN,
+ BITFIELD(51, 3) /* index 860 */,
+ TILE_OPC_NONE, TILE_OPC_ADDIB, TILE_OPC_ADDIH, TILE_OPC_ADDI, CHILD(869),
+ TILE_OPC_MAXIB_U, TILE_OPC_MAXIH, TILE_OPC_MFSPR,
+ BITFIELD(31, 2) /* index 869 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(874),
+ BITFIELD(33, 2) /* index 874 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(879),
+ BITFIELD(35, 2) /* index 879 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(884),
+ BITFIELD(37, 2) /* index 884 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(889),
+ BITFIELD(39, 2) /* index 889 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(894),
+ BITFIELD(41, 2) /* index 894 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO,
+ BITFIELD(51, 3) /* index 899 */,
+ TILE_OPC_MINIB_U, TILE_OPC_MINIH, TILE_OPC_MTSPR, CHILD(908),
+ TILE_OPC_SEQIB, TILE_OPC_SEQIH, TILE_OPC_SEQI, TILE_OPC_SLTIB,
+ BITFIELD(37, 2) /* index 908 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(913),
+ BITFIELD(39, 2) /* index 913 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(918),
+ BITFIELD(41, 2) /* index 918 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI,
+ BITFIELD(51, 3) /* index 923 */,
+ TILE_OPC_SLTIB_U, TILE_OPC_SLTIH, TILE_OPC_SLTIH_U, TILE_OPC_SLTI,
+ TILE_OPC_SLTI_U, TILE_OPC_XORI, TILE_OPC_LBADD, TILE_OPC_LBADD_U,
+ BITFIELD(51, 3) /* index 932 */,
+ TILE_OPC_LHADD, TILE_OPC_LHADD_U, TILE_OPC_LWADD, TILE_OPC_LWADD_NA,
+ TILE_OPC_SBADD, TILE_OPC_SHADD, TILE_OPC_SWADD, TILE_OPC_NONE,
+ BITFIELD(51, 3) /* index 941 */,
+ TILE_OPC_NONE, TILE_OPC_ADDIB_SN, TILE_OPC_ADDIH_SN, TILE_OPC_ADDI_SN,
+ TILE_OPC_ANDI_SN, TILE_OPC_MAXIB_U_SN, TILE_OPC_MAXIH_SN, TILE_OPC_MFSPR,
+ BITFIELD(51, 3) /* index 950 */,
+ TILE_OPC_MINIB_U_SN, TILE_OPC_MINIH_SN, TILE_OPC_MTSPR, CHILD(959),
+ TILE_OPC_SEQIB_SN, TILE_OPC_SEQIH_SN, TILE_OPC_SEQI_SN, TILE_OPC_SLTIB_SN,
+ BITFIELD(37, 2) /* index 959 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(964),
+ BITFIELD(39, 2) /* index 964 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, CHILD(969),
+ BITFIELD(41, 2) /* index 969 */,
+ TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_ORI_SN, TILE_OPC_MOVEI_SN,
+ BITFIELD(51, 3) /* index 974 */,
+ TILE_OPC_SLTIB_U_SN, TILE_OPC_SLTIH_SN, TILE_OPC_SLTIH_U_SN,
+ TILE_OPC_SLTI_SN, TILE_OPC_SLTI_U_SN, TILE_OPC_XORI_SN, TILE_OPC_LBADD_SN,
+ TILE_OPC_LBADD_U_SN,
+ BITFIELD(51, 3) /* index 983 */,
+ TILE_OPC_LHADD_SN, TILE_OPC_LHADD_U_SN, TILE_OPC_LWADD_SN,
+ TILE_OPC_LWADD_NA_SN, TILE_OPC_SBADD, TILE_OPC_SHADD, TILE_OPC_SWADD,
+ TILE_OPC_NONE,
+ BITFIELD(46, 7) /* index 992 */,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(1121),
+ CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1124), CHILD(1124),
+ CHILD(1124), CHILD(1124), CHILD(1127), CHILD(1127), CHILD(1127),
+ CHILD(1127), CHILD(1130), CHILD(1130), CHILD(1130), CHILD(1130),
+ CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1136),
+ CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1139), CHILD(1139),
+ CHILD(1139), CHILD(1139), CHILD(1142), CHILD(1142), CHILD(1142),
+ CHILD(1142), CHILD(1145), CHILD(1145), CHILD(1145), CHILD(1145),
+ CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1151),
+ CHILD(1211), CHILD(1259), CHILD(1292), TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1121 */,
+ TILE_OPC_RLI, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1124 */,
+ TILE_OPC_SHLIB, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1127 */,
+ TILE_OPC_SHLIH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1130 */,
+ TILE_OPC_SHLI, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1133 */,
+ TILE_OPC_SHRIB, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1136 */,
+ TILE_OPC_SHRIH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1139 */,
+ TILE_OPC_SHRI, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1142 */,
+ TILE_OPC_SRAIB, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1145 */,
+ TILE_OPC_SRAIH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1148 */,
+ TILE_OPC_SRAI, TILE_OPC_NONE,
+ BITFIELD(43, 3) /* index 1151 */,
+ TILE_OPC_NONE, CHILD(1160), CHILD(1163), CHILD(1166), CHILD(1169),
+ CHILD(1172), CHILD(1175), CHILD(1178),
+ BITFIELD(53, 1) /* index 1160 */,
+ TILE_OPC_DRAIN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1163 */,
+ TILE_OPC_DTLBPR, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1166 */,
+ TILE_OPC_FINV, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1169 */,
+ TILE_OPC_FLUSH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1172 */,
+ TILE_OPC_FNOP, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1175 */,
+ TILE_OPC_ICOH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1178 */,
+ CHILD(1181), TILE_OPC_NONE,
+ BITFIELD(31, 2) /* index 1181 */,
+ CHILD(1186), TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_ILL,
+ BITFIELD(33, 2) /* index 1186 */,
+ TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_ILL, CHILD(1191),
+ BITFIELD(35, 2) /* index 1191 */,
+ TILE_OPC_ILL, CHILD(1196), TILE_OPC_ILL, TILE_OPC_ILL,
+ BITFIELD(37, 2) /* index 1196 */,
+ TILE_OPC_ILL, CHILD(1201), TILE_OPC_ILL, TILE_OPC_ILL,
+ BITFIELD(39, 2) /* index 1201 */,
+ TILE_OPC_ILL, CHILD(1206), TILE_OPC_ILL, TILE_OPC_ILL,
+ BITFIELD(41, 2) /* index 1206 */,
+ TILE_OPC_ILL, TILE_OPC_ILL, TILE_OPC_BPT, TILE_OPC_ILL,
+ BITFIELD(43, 3) /* index 1211 */,
+ CHILD(1220), CHILD(1223), CHILD(1226), CHILD(1244), CHILD(1247),
+ CHILD(1250), CHILD(1253), CHILD(1256),
+ BITFIELD(53, 1) /* index 1220 */,
+ TILE_OPC_INV, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1223 */,
+ TILE_OPC_IRET, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1226 */,
+ CHILD(1229), TILE_OPC_NONE,
+ BITFIELD(31, 2) /* index 1229 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(1234),
+ BITFIELD(33, 2) /* index 1234 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(1239),
+ BITFIELD(35, 2) /* index 1239 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_PREFETCH,
+ BITFIELD(53, 1) /* index 1244 */,
+ TILE_OPC_LB_U, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1247 */,
+ TILE_OPC_LH, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1250 */,
+ TILE_OPC_LH_U, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1253 */,
+ TILE_OPC_LW, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1256 */,
+ TILE_OPC_MF, TILE_OPC_NONE,
+ BITFIELD(43, 3) /* index 1259 */,
+ CHILD(1268), CHILD(1271), CHILD(1274), CHILD(1277), CHILD(1280),
+ CHILD(1283), CHILD(1286), CHILD(1289),
+ BITFIELD(53, 1) /* index 1268 */,
+ TILE_OPC_NAP, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1271 */,
+ TILE_OPC_NOP, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1274 */,
+ TILE_OPC_SWINT0, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1277 */,
+ TILE_OPC_SWINT1, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1280 */,
+ TILE_OPC_SWINT2, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1283 */,
+ TILE_OPC_SWINT3, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1286 */,
+ TILE_OPC_TNS, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1289 */,
+ TILE_OPC_WH64, TILE_OPC_NONE,
+ BITFIELD(43, 2) /* index 1292 */,
+ CHILD(1297), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(45, 1) /* index 1297 */,
+ CHILD(1300), TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1300 */,
+ TILE_OPC_LW_NA, TILE_OPC_NONE,
+ BITFIELD(46, 7) /* index 1303 */,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, CHILD(1432),
+ CHILD(1432), CHILD(1432), CHILD(1432), CHILD(1435), CHILD(1435),
+ CHILD(1435), CHILD(1435), CHILD(1438), CHILD(1438), CHILD(1438),
+ CHILD(1438), CHILD(1441), CHILD(1441), CHILD(1441), CHILD(1441),
+ CHILD(1444), CHILD(1444), CHILD(1444), CHILD(1444), CHILD(1447),
+ CHILD(1447), CHILD(1447), CHILD(1447), CHILD(1450), CHILD(1450),
+ CHILD(1450), CHILD(1450), CHILD(1453), CHILD(1453), CHILD(1453),
+ CHILD(1453), CHILD(1456), CHILD(1456), CHILD(1456), CHILD(1456),
+ CHILD(1459), CHILD(1459), CHILD(1459), CHILD(1459), CHILD(1151),
+ CHILD(1462), CHILD(1486), CHILD(1498), TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1432 */,
+ TILE_OPC_RLI_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1435 */,
+ TILE_OPC_SHLIB_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1438 */,
+ TILE_OPC_SHLIH_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1441 */,
+ TILE_OPC_SHLI_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1444 */,
+ TILE_OPC_SHRIB_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1447 */,
+ TILE_OPC_SHRIH_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1450 */,
+ TILE_OPC_SHRI_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1453 */,
+ TILE_OPC_SRAIB_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1456 */,
+ TILE_OPC_SRAIH_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1459 */,
+ TILE_OPC_SRAI_SN, TILE_OPC_NONE,
+ BITFIELD(43, 3) /* index 1462 */,
+ CHILD(1220), CHILD(1223), CHILD(1471), CHILD(1474), CHILD(1477),
+ CHILD(1480), CHILD(1483), CHILD(1256),
+ BITFIELD(53, 1) /* index 1471 */,
+ TILE_OPC_LB_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1474 */,
+ TILE_OPC_LB_U_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1477 */,
+ TILE_OPC_LH_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1480 */,
+ TILE_OPC_LH_U_SN, TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1483 */,
+ TILE_OPC_LW_SN, TILE_OPC_NONE,
+ BITFIELD(43, 3) /* index 1486 */,
+ CHILD(1268), CHILD(1271), CHILD(1274), CHILD(1277), CHILD(1280),
+ CHILD(1283), CHILD(1495), CHILD(1289),
+ BITFIELD(53, 1) /* index 1495 */,
+ TILE_OPC_TNS_SN, TILE_OPC_NONE,
+ BITFIELD(43, 2) /* index 1498 */,
+ CHILD(1503), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(45, 1) /* index 1503 */,
+ CHILD(1506), TILE_OPC_NONE,
+ BITFIELD(53, 1) /* index 1506 */,
+ TILE_OPC_LW_NA_SN, TILE_OPC_NONE,
+};
+
+static const unsigned short decode_Y0_fsm[168] =
+{
+ BITFIELD(27, 4) /* index 0 */,
+ TILE_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52),
+ CHILD(57), CHILD(62), CHILD(67), TILE_OPC_ADDI, CHILD(72), CHILD(102),
+ TILE_OPC_SEQI, CHILD(117), TILE_OPC_SLTI, TILE_OPC_SLTI_U,
+ BITFIELD(18, 2) /* index 17 */,
+ TILE_OPC_ADD, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_SUB,
+ BITFIELD(18, 2) /* index 22 */,
+ TILE_OPC_MNZ, TILE_OPC_MVNZ, TILE_OPC_MVZ, TILE_OPC_MZ,
+ BITFIELD(18, 2) /* index 27 */,
+ TILE_OPC_AND, TILE_OPC_NOR, CHILD(32), TILE_OPC_XOR,
+ BITFIELD(12, 2) /* index 32 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(37),
+ BITFIELD(14, 2) /* index 37 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(42),
+ BITFIELD(16, 2) /* index 42 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE,
+ BITFIELD(18, 2) /* index 47 */,
+ TILE_OPC_RL, TILE_OPC_SHL, TILE_OPC_SHR, TILE_OPC_SRA,
+ BITFIELD(18, 2) /* index 52 */,
+ TILE_OPC_SLTE, TILE_OPC_SLTE_U, TILE_OPC_SLT, TILE_OPC_SLT_U,
+ BITFIELD(18, 2) /* index 57 */,
+ TILE_OPC_MULHLSA_UU, TILE_OPC_S3A, TILE_OPC_SEQ, TILE_OPC_SNE,
+ BITFIELD(18, 2) /* index 62 */,
+ TILE_OPC_MULHH_SS, TILE_OPC_MULHH_UU, TILE_OPC_MULLL_SS, TILE_OPC_MULLL_UU,
+ BITFIELD(18, 2) /* index 67 */,
+ TILE_OPC_MULHHA_SS, TILE_OPC_MULHHA_UU, TILE_OPC_MULLLA_SS,
+ TILE_OPC_MULLLA_UU,
+ BITFIELD(0, 2) /* index 72 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(77),
+ BITFIELD(2, 2) /* index 77 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(82),
+ BITFIELD(4, 2) /* index 82 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(87),
+ BITFIELD(6, 2) /* index 87 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(92),
+ BITFIELD(8, 2) /* index 92 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(97),
+ BITFIELD(10, 2) /* index 97 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO,
+ BITFIELD(6, 2) /* index 102 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(107),
+ BITFIELD(8, 2) /* index 107 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(112),
+ BITFIELD(10, 2) /* index 112 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI,
+ BITFIELD(15, 5) /* index 117 */,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_RLI,
+ TILE_OPC_RLI, TILE_OPC_RLI, TILE_OPC_RLI, TILE_OPC_SHLI, TILE_OPC_SHLI,
+ TILE_OPC_SHLI, TILE_OPC_SHLI, TILE_OPC_SHRI, TILE_OPC_SHRI, TILE_OPC_SHRI,
+ TILE_OPC_SHRI, TILE_OPC_SRAI, TILE_OPC_SRAI, TILE_OPC_SRAI, TILE_OPC_SRAI,
+ CHILD(150), CHILD(159), TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(12, 3) /* index 150 */,
+ TILE_OPC_NONE, TILE_OPC_BITX, TILE_OPC_BYTEX, TILE_OPC_CLZ, TILE_OPC_CTZ,
+ TILE_OPC_FNOP, TILE_OPC_NOP, TILE_OPC_PCNT,
+ BITFIELD(12, 3) /* index 159 */,
+ TILE_OPC_TBLIDXB0, TILE_OPC_TBLIDXB1, TILE_OPC_TBLIDXB2, TILE_OPC_TBLIDXB3,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+};
+
+static const unsigned short decode_Y1_fsm[140] =
+{
+ BITFIELD(59, 4) /* index 0 */,
+ TILE_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52),
+ CHILD(57), TILE_OPC_ADDI, CHILD(62), CHILD(92), TILE_OPC_SEQI, CHILD(107),
+ TILE_OPC_SLTI, TILE_OPC_SLTI_U, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(49, 2) /* index 17 */,
+ TILE_OPC_ADD, TILE_OPC_S1A, TILE_OPC_S2A, TILE_OPC_SUB,
+ BITFIELD(49, 2) /* index 22 */,
+ TILE_OPC_NONE, TILE_OPC_MNZ, TILE_OPC_MZ, TILE_OPC_NONE,
+ BITFIELD(49, 2) /* index 27 */,
+ TILE_OPC_AND, TILE_OPC_NOR, CHILD(32), TILE_OPC_XOR,
+ BITFIELD(43, 2) /* index 32 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(37),
+ BITFIELD(45, 2) /* index 37 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, CHILD(42),
+ BITFIELD(47, 2) /* index 42 */,
+ TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_OR, TILE_OPC_MOVE,
+ BITFIELD(49, 2) /* index 47 */,
+ TILE_OPC_RL, TILE_OPC_SHL, TILE_OPC_SHR, TILE_OPC_SRA,
+ BITFIELD(49, 2) /* index 52 */,
+ TILE_OPC_SLTE, TILE_OPC_SLTE_U, TILE_OPC_SLT, TILE_OPC_SLT_U,
+ BITFIELD(49, 2) /* index 57 */,
+ TILE_OPC_NONE, TILE_OPC_S3A, TILE_OPC_SEQ, TILE_OPC_SNE,
+ BITFIELD(31, 2) /* index 62 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(67),
+ BITFIELD(33, 2) /* index 67 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(72),
+ BITFIELD(35, 2) /* index 72 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(77),
+ BITFIELD(37, 2) /* index 77 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(82),
+ BITFIELD(39, 2) /* index 82 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, CHILD(87),
+ BITFIELD(41, 2) /* index 87 */,
+ TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_ANDI, TILE_OPC_INFO,
+ BITFIELD(37, 2) /* index 92 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(97),
+ BITFIELD(39, 2) /* index 97 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, CHILD(102),
+ BITFIELD(41, 2) /* index 102 */,
+ TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_ORI, TILE_OPC_MOVEI,
+ BITFIELD(48, 3) /* index 107 */,
+ TILE_OPC_NONE, TILE_OPC_RLI, TILE_OPC_SHLI, TILE_OPC_SHRI, TILE_OPC_SRAI,
+ CHILD(116), TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(43, 3) /* index 116 */,
+ TILE_OPC_NONE, CHILD(125), CHILD(130), CHILD(135), TILE_OPC_NONE,
+ TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(46, 2) /* index 125 */,
+ TILE_OPC_FNOP, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(46, 2) /* index 130 */,
+ TILE_OPC_ILL, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+ BITFIELD(46, 2) /* index 135 */,
+ TILE_OPC_NOP, TILE_OPC_NONE, TILE_OPC_NONE, TILE_OPC_NONE,
+};
+
+static const unsigned short decode_Y2_fsm[24] =
+{
+ BITFIELD(56, 3) /* index 0 */,
+ CHILD(9), TILE_OPC_LB_U, TILE_OPC_LH, TILE_OPC_LH_U, TILE_OPC_LW,
+ TILE_OPC_SB, TILE_OPC_SH, TILE_OPC_SW,
+ BITFIELD(20, 2) /* index 9 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(14),
+ BITFIELD(22, 2) /* index 14 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, CHILD(19),
+ BITFIELD(24, 2) /* index 19 */,
+ TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_LB, TILE_OPC_PREFETCH,
+};
+
+#undef BITFIELD
+#undef CHILD
+const unsigned short * const
+tile_bundle_decoder_fsms[TILE_NUM_PIPELINE_ENCODINGS] =
+{
+ decode_X0_fsm,
+ decode_X1_fsm,
+ decode_Y0_fsm,
+ decode_Y1_fsm,
+ decode_Y2_fsm
+};
+const struct tile_sn_opcode tile_sn_opcodes[23] =
+{
+ { "bz", TILE_SN_OPC_BZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xe000
+ },
+ { "bnz", TILE_SN_OPC_BNZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xe400
+ },
+ { "jrr", TILE_SN_OPC_JRR,
+ 1 /* num_operands */,
+ /* operands */
+ { 39 },
+ /* fixed_bit_mask */
+ 0xff00,
+ /* fixed_bit_value */
+ 0x0600
+ },
+ { "fnop", TILE_SN_OPC_FNOP,
+ 0 /* num_operands */,
+ /* operands */
+ { 0, },
+ /* fixed_bit_mask */
+ 0xffff,
+ /* fixed_bit_value */
+ 0x0003
+ },
+ { "blz", TILE_SN_OPC_BLZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xf000
+ },
+ { "nop", TILE_SN_OPC_NOP,
+ 0 /* num_operands */,
+ /* operands */
+ { 0, },
+ /* fixed_bit_mask */
+ 0xffff,
+ /* fixed_bit_value */
+ 0x0002
+ },
+ { "movei", TILE_SN_OPC_MOVEI,
+ 1 /* num_operands */,
+ /* operands */
+ { 40 },
+ /* fixed_bit_mask */
+ 0xff00,
+ /* fixed_bit_value */
+ 0x0400
+ },
+ { "move", TILE_SN_OPC_MOVE,
+ 2 /* num_operands */,
+ /* operands */
+ { 41, 42 },
+ /* fixed_bit_mask */
+ 0xfff0,
+ /* fixed_bit_value */
+ 0x0080
+ },
+ { "bgez", TILE_SN_OPC_BGEZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xf400
+ },
+ { "jr", TILE_SN_OPC_JR,
+ 1 /* num_operands */,
+ /* operands */
+ { 42 },
+ /* fixed_bit_mask */
+ 0xfff0,
+ /* fixed_bit_value */
+ 0x0040
+ },
+ { "blez", TILE_SN_OPC_BLEZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xec00
+ },
+ { "bbns", TILE_SN_OPC_BBNS,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xfc00
+ },
+ { "jalrr", TILE_SN_OPC_JALRR,
+ 1 /* num_operands */,
+ /* operands */
+ { 39 },
+ /* fixed_bit_mask */
+ 0xff00,
+ /* fixed_bit_value */
+ 0x0700
+ },
+ { "bpt", TILE_SN_OPC_BPT,
+ 0 /* num_operands */,
+ /* operands */
+ { 0, },
+ /* fixed_bit_mask */
+ 0xffff,
+ /* fixed_bit_value */
+ 0x0001
+ },
+ { "jalr", TILE_SN_OPC_JALR,
+ 1 /* num_operands */,
+ /* operands */
+ { 42 },
+ /* fixed_bit_mask */
+ 0xfff0,
+ /* fixed_bit_value */
+ 0x0050
+ },
+ { "shr1", TILE_SN_OPC_SHR1,
+ 2 /* num_operands */,
+ /* operands */
+ { 41, 42 },
+ /* fixed_bit_mask */
+ 0xfff0,
+ /* fixed_bit_value */
+ 0x0090
+ },
+ { "bgz", TILE_SN_OPC_BGZ,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xe800
+ },
+ { "bbs", TILE_SN_OPC_BBS,
+ 1 /* num_operands */,
+ /* operands */
+ { 38 },
+ /* fixed_bit_mask */
+ 0xfc00,
+ /* fixed_bit_value */
+ 0xf800
+ },
+ { "shl8ii", TILE_SN_OPC_SHL8II,
+ 1 /* num_operands */,
+ /* operands */
+ { 39 },
+ /* fixed_bit_mask */
+ 0xff00,
+ /* fixed_bit_value */
+ 0x0300
+ },
+ { "addi", TILE_SN_OPC_ADDI,
+ 1 /* num_operands */,
+ /* operands */
+ { 40 },
+ /* fixed_bit_mask */
+ 0xff00,
+ /* fixed_bit_value */
+ 0x0500
+ },
+ { "halt", TILE_SN_OPC_HALT,
+ 0 /* num_operands */,
+ /* operands */
+ { 0, },
+ /* fixed_bit_mask */
+ 0xffff,
+ /* fixed_bit_value */
+ 0x0000
+ },
+ { "route", TILE_SN_OPC_ROUTE, 0, { 0, }, 0, 0,
+ },
+ { 0, TILE_SN_OPC_NONE, 0, { 0, }, 0, 0,
+ }
+};
+const unsigned char tile_sn_route_encode[6 * 6 * 6] =
+{
+ 0xdf,
+ 0xde,
+ 0xdd,
+ 0xdc,
+ 0xdb,
+ 0xda,
+ 0xb9,
+ 0xb8,
+ 0xa1,
+ 0xa0,
+ 0x11,
+ 0x10,
+ 0x9f,
+ 0x9e,
+ 0x9d,
+ 0x9c,
+ 0x9b,
+ 0x9a,
+ 0x79,
+ 0x78,
+ 0x61,
+ 0x60,
+ 0xb,
+ 0xa,
+ 0x5f,
+ 0x5e,
+ 0x5d,
+ 0x5c,
+ 0x5b,
+ 0x5a,
+ 0x1f,
+ 0x1e,
+ 0x1d,
+ 0x1c,
+ 0x1b,
+ 0x1a,
+ 0xd7,
+ 0xd6,
+ 0xd5,
+ 0xd4,
+ 0xd3,
+ 0xd2,
+ 0xa7,
+ 0xa6,
+ 0xb1,
+ 0xb0,
+ 0x13,
+ 0x12,
+ 0x97,
+ 0x96,
+ 0x95,
+ 0x94,
+ 0x93,
+ 0x92,
+ 0x67,
+ 0x66,
+ 0x71,
+ 0x70,
+ 0x9,
+ 0x8,
+ 0x57,
+ 0x56,
+ 0x55,
+ 0x54,
+ 0x53,
+ 0x52,
+ 0x17,
+ 0x16,
+ 0x15,
+ 0x14,
+ 0x19,
+ 0x18,
+ 0xcf,
+ 0xce,
+ 0xcd,
+ 0xcc,
+ 0xcb,
+ 0xca,
+ 0xaf,
+ 0xae,
+ 0xad,
+ 0xac,
+ 0xab,
+ 0xaa,
+ 0x8f,
+ 0x8e,
+ 0x8d,
+ 0x8c,
+ 0x8b,
+ 0x8a,
+ 0x6f,
+ 0x6e,
+ 0x6d,
+ 0x6c,
+ 0x6b,
+ 0x6a,
+ 0x4f,
+ 0x4e,
+ 0x4d,
+ 0x4c,
+ 0x4b,
+ 0x4a,
+ 0x2f,
+ 0x2e,
+ 0x2d,
+ 0x2c,
+ 0x2b,
+ 0x2a,
+ 0xc9,
+ 0xc8,
+ 0xc5,
+ 0xc4,
+ 0xc3,
+ 0xc2,
+ 0xa9,
+ 0xa8,
+ 0xa5,
+ 0xa4,
+ 0xa3,
+ 0xa2,
+ 0x89,
+ 0x88,
+ 0x85,
+ 0x84,
+ 0x83,
+ 0x82,
+ 0x69,
+ 0x68,
+ 0x65,
+ 0x64,
+ 0x63,
+ 0x62,
+ 0x47,
+ 0x46,
+ 0x45,
+ 0x44,
+ 0x43,
+ 0x42,
+ 0x27,
+ 0x26,
+ 0x25,
+ 0x24,
+ 0x23,
+ 0x22,
+ 0xd9,
+ 0xd8,
+ 0xc1,
+ 0xc0,
+ 0x3b,
+ 0x3a,
+ 0xbf,
+ 0xbe,
+ 0xbd,
+ 0xbc,
+ 0xbb,
+ 0xba,
+ 0x99,
+ 0x98,
+ 0x81,
+ 0x80,
+ 0x31,
+ 0x30,
+ 0x7f,
+ 0x7e,
+ 0x7d,
+ 0x7c,
+ 0x7b,
+ 0x7a,
+ 0x59,
+ 0x58,
+ 0x3d,
+ 0x3c,
+ 0x49,
+ 0x48,
+ 0xf,
+ 0xe,
+ 0xd,
+ 0xc,
+ 0x29,
+ 0x28,
+ 0xc7,
+ 0xc6,
+ 0xd1,
+ 0xd0,
+ 0x39,
+ 0x38,
+ 0xb7,
+ 0xb6,
+ 0xb5,
+ 0xb4,
+ 0xb3,
+ 0xb2,
+ 0x87,
+ 0x86,
+ 0x91,
+ 0x90,
+ 0x33,
+ 0x32,
+ 0x77,
+ 0x76,
+ 0x75,
+ 0x74,
+ 0x73,
+ 0x72,
+ 0x3f,
+ 0x3e,
+ 0x51,
+ 0x50,
+ 0x41,
+ 0x40,
+ 0x37,
+ 0x36,
+ 0x35,
+ 0x34,
+ 0x21,
+ 0x20
+};
+
+const signed char tile_sn_route_decode[256][3] =
+{
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { 5, 3, 1 },
+ { 4, 3, 1 },
+ { 5, 3, 0 },
+ { 4, 3, 0 },
+ { 3, 5, 4 },
+ { 2, 5, 4 },
+ { 1, 5, 4 },
+ { 0, 5, 4 },
+ { 5, 1, 0 },
+ { 4, 1, 0 },
+ { 5, 1, 1 },
+ { 4, 1, 1 },
+ { 3, 5, 1 },
+ { 2, 5, 1 },
+ { 1, 5, 1 },
+ { 0, 5, 1 },
+ { 5, 5, 1 },
+ { 4, 5, 1 },
+ { 5, 5, 0 },
+ { 4, 5, 0 },
+ { 3, 5, 0 },
+ { 2, 5, 0 },
+ { 1, 5, 0 },
+ { 0, 5, 0 },
+ { 5, 5, 5 },
+ { 4, 5, 5 },
+ { 5, 5, 3 },
+ { 4, 5, 3 },
+ { 3, 5, 3 },
+ { 2, 5, 3 },
+ { 1, 5, 3 },
+ { 0, 5, 3 },
+ { 5, 5, 4 },
+ { 4, 5, 4 },
+ { 5, 5, 2 },
+ { 4, 5, 2 },
+ { 3, 5, 2 },
+ { 2, 5, 2 },
+ { 1, 5, 2 },
+ { 0, 5, 2 },
+ { 5, 2, 4 },
+ { 4, 2, 4 },
+ { 5, 2, 5 },
+ { 4, 2, 5 },
+ { 3, 5, 5 },
+ { 2, 5, 5 },
+ { 1, 5, 5 },
+ { 0, 5, 5 },
+ { 5, 0, 5 },
+ { 4, 0, 5 },
+ { 5, 0, 4 },
+ { 4, 0, 4 },
+ { 3, 4, 4 },
+ { 2, 4, 4 },
+ { 1, 4, 5 },
+ { 0, 4, 5 },
+ { 5, 4, 5 },
+ { 4, 4, 5 },
+ { 5, 4, 3 },
+ { 4, 4, 3 },
+ { 3, 4, 3 },
+ { 2, 4, 3 },
+ { 1, 4, 3 },
+ { 0, 4, 3 },
+ { 5, 4, 4 },
+ { 4, 4, 4 },
+ { 5, 4, 2 },
+ { 4, 4, 2 },
+ { 3, 4, 2 },
+ { 2, 4, 2 },
+ { 1, 4, 2 },
+ { 0, 4, 2 },
+ { 3, 4, 5 },
+ { 2, 4, 5 },
+ { 5, 4, 1 },
+ { 4, 4, 1 },
+ { 3, 4, 1 },
+ { 2, 4, 1 },
+ { 1, 4, 1 },
+ { 0, 4, 1 },
+ { 1, 4, 4 },
+ { 0, 4, 4 },
+ { 5, 4, 0 },
+ { 4, 4, 0 },
+ { 3, 4, 0 },
+ { 2, 4, 0 },
+ { 1, 4, 0 },
+ { 0, 4, 0 },
+ { 3, 3, 0 },
+ { 2, 3, 0 },
+ { 5, 3, 3 },
+ { 4, 3, 3 },
+ { 3, 3, 3 },
+ { 2, 3, 3 },
+ { 1, 3, 1 },
+ { 0, 3, 1 },
+ { 1, 3, 3 },
+ { 0, 3, 3 },
+ { 5, 3, 2 },
+ { 4, 3, 2 },
+ { 3, 3, 2 },
+ { 2, 3, 2 },
+ { 1, 3, 2 },
+ { 0, 3, 2 },
+ { 3, 3, 1 },
+ { 2, 3, 1 },
+ { 5, 3, 5 },
+ { 4, 3, 5 },
+ { 3, 3, 5 },
+ { 2, 3, 5 },
+ { 1, 3, 5 },
+ { 0, 3, 5 },
+ { 1, 3, 0 },
+ { 0, 3, 0 },
+ { 5, 3, 4 },
+ { 4, 3, 4 },
+ { 3, 3, 4 },
+ { 2, 3, 4 },
+ { 1, 3, 4 },
+ { 0, 3, 4 },
+ { 3, 2, 4 },
+ { 2, 2, 4 },
+ { 5, 2, 3 },
+ { 4, 2, 3 },
+ { 3, 2, 3 },
+ { 2, 2, 3 },
+ { 1, 2, 5 },
+ { 0, 2, 5 },
+ { 1, 2, 3 },
+ { 0, 2, 3 },
+ { 5, 2, 2 },
+ { 4, 2, 2 },
+ { 3, 2, 2 },
+ { 2, 2, 2 },
+ { 1, 2, 2 },
+ { 0, 2, 2 },
+ { 3, 2, 5 },
+ { 2, 2, 5 },
+ { 5, 2, 1 },
+ { 4, 2, 1 },
+ { 3, 2, 1 },
+ { 2, 2, 1 },
+ { 1, 2, 1 },
+ { 0, 2, 1 },
+ { 1, 2, 4 },
+ { 0, 2, 4 },
+ { 5, 2, 0 },
+ { 4, 2, 0 },
+ { 3, 2, 0 },
+ { 2, 2, 0 },
+ { 1, 2, 0 },
+ { 0, 2, 0 },
+ { 3, 1, 0 },
+ { 2, 1, 0 },
+ { 5, 1, 3 },
+ { 4, 1, 3 },
+ { 3, 1, 3 },
+ { 2, 1, 3 },
+ { 1, 1, 1 },
+ { 0, 1, 1 },
+ { 1, 1, 3 },
+ { 0, 1, 3 },
+ { 5, 1, 2 },
+ { 4, 1, 2 },
+ { 3, 1, 2 },
+ { 2, 1, 2 },
+ { 1, 1, 2 },
+ { 0, 1, 2 },
+ { 3, 1, 1 },
+ { 2, 1, 1 },
+ { 5, 1, 5 },
+ { 4, 1, 5 },
+ { 3, 1, 5 },
+ { 2, 1, 5 },
+ { 1, 1, 5 },
+ { 0, 1, 5 },
+ { 1, 1, 0 },
+ { 0, 1, 0 },
+ { 5, 1, 4 },
+ { 4, 1, 4 },
+ { 3, 1, 4 },
+ { 2, 1, 4 },
+ { 1, 1, 4 },
+ { 0, 1, 4 },
+ { 3, 0, 4 },
+ { 2, 0, 4 },
+ { 5, 0, 3 },
+ { 4, 0, 3 },
+ { 3, 0, 3 },
+ { 2, 0, 3 },
+ { 1, 0, 5 },
+ { 0, 0, 5 },
+ { 1, 0, 3 },
+ { 0, 0, 3 },
+ { 5, 0, 2 },
+ { 4, 0, 2 },
+ { 3, 0, 2 },
+ { 2, 0, 2 },
+ { 1, 0, 2 },
+ { 0, 0, 2 },
+ { 3, 0, 5 },
+ { 2, 0, 5 },
+ { 5, 0, 1 },
+ { 4, 0, 1 },
+ { 3, 0, 1 },
+ { 2, 0, 1 },
+ { 1, 0, 1 },
+ { 0, 0, 1 },
+ { 1, 0, 4 },
+ { 0, 0, 4 },
+ { 5, 0, 0 },
+ { 4, 0, 0 },
+ { 3, 0, 0 },
+ { 2, 0, 0 },
+ { 1, 0, 0 },
+ { 0, 0, 0 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 },
+ { -1, -1, -1 }
+};
+
+const char tile_sn_direction_names[6][5] =
+{
+ "w",
+ "c",
+ "acc",
+ "n",
+ "e",
+ "s"
+};
+
+const signed char tile_sn_dest_map[6][6] = {
+ { -1, 3, 4, 5, 1, 2 } /* val -> w */,
+ { -1, 3, 4, 5, 0, 2 } /* val -> c */,
+ { -1, 3, 4, 5, 0, 1 } /* val -> acc */,
+ { -1, 4, 5, 0, 1, 2 } /* val -> n */,
+ { -1, 3, 5, 0, 1, 2 } /* val -> e */,
+ { -1, 3, 4, 0, 1, 2 } /* val -> s */
+};
+
+const struct tile_operand tile_operands[43] =
+{
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM8_X0), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_X0, /* insert */
+ get_Imm8_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM8_X1), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_X1, /* insert */
+ get_Imm8_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM8_Y0), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_Y0, /* insert */
+ get_Imm8_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM8_Y1), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_Y1, /* insert */
+ get_Imm8_Y1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM16_X0), /* default_reloc */
+ 16, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm16_X0, /* insert */
+ get_Imm16_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_IMM16_X1), /* default_reloc */
+ 16, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm16_X1, /* insert */
+ get_Imm16_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_ADDRESS, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_JOFFLONG_X1), /* default_reloc */
+ 29, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 1, /* is_pc_relative */
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */
+ create_JOffLong_X1, /* insert */
+ get_JOffLong_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_X0, /* insert */
+ get_Dest_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_X0, /* insert */
+ get_SrcA_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_X1, /* insert */
+ get_Dest_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_X1, /* insert */
+ get_SrcA_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_Y0, /* insert */
+ get_Dest_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_Y0, /* insert */
+ get_SrcA_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_Y1, /* insert */
+ get_Dest_Y1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_Y1, /* insert */
+ get_SrcA_Y1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_Y2, /* insert */
+ get_SrcA_Y2 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcB_X0, /* insert */
+ get_SrcB_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcB_X1, /* insert */
+ get_SrcB_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcB_Y0, /* insert */
+ get_SrcB_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcB_Y1, /* insert */
+ get_SrcB_Y1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_ADDRESS, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_BROFF_X1), /* default_reloc */
+ 17, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 1, /* is_pc_relative */
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */
+ create_BrOff_X1, /* insert */
+ get_BrOff_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_X0, /* insert */
+ get_Dest_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_ADDRESS, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 28, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 1, /* is_pc_relative */
+ TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, /* rightshift */
+ create_JOff_X1, /* insert */
+ get_JOff_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcBDest_Y2, /* insert */
+ get_SrcBDest_Y2 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcA_X1, /* insert */
+ get_SrcA_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_SPR, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MF_IMM15_X1), /* default_reloc */
+ 15, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MF_Imm15_X1, /* insert */
+ get_MF_Imm15_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MMSTART_X0), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MMStart_X0, /* insert */
+ get_MMStart_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MMEND_X0), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MMEnd_X0, /* insert */
+ get_MMEnd_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MMSTART_X1), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MMStart_X1, /* insert */
+ get_MMStart_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MMEND_X1), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MMEnd_X1, /* insert */
+ get_MMEnd_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_SPR, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_MT_IMM15_X1), /* default_reloc */
+ 15, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_MT_Imm15_X1, /* insert */
+ get_MT_Imm15_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_Y0, /* insert */
+ get_Dest_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SHAMT_X0), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_ShAmt_X0, /* insert */
+ get_ShAmt_X0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SHAMT_X1), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_ShAmt_X1, /* insert */
+ get_ShAmt_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SHAMT_Y0), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_ShAmt_Y0, /* insert */
+ get_ShAmt_Y0 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SHAMT_Y1), /* default_reloc */
+ 5, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_ShAmt_Y1, /* insert */
+ get_ShAmt_Y1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 6, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_SrcBDest_Y2, /* insert */
+ get_SrcBDest_Y2 /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_Imm8_X1, /* insert */
+ get_Dest_Imm8_X1 /* extract */
+ },
+ {
+ TILE_OP_TYPE_ADDRESS, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SN_BROFF), /* default_reloc */
+ 10, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 1, /* is_pc_relative */
+ TILE_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES, /* rightshift */
+ create_BrOff_SN, /* insert */
+ get_BrOff_SN /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SN_UIMM8), /* default_reloc */
+ 8, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_SN, /* insert */
+ get_Imm8_SN /* extract */
+ },
+ {
+ TILE_OP_TYPE_IMMEDIATE, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_TILE_SN_IMM8), /* default_reloc */
+ 8, /* num_bits */
+ 1, /* is_signed */
+ 0, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Imm8_SN, /* insert */
+ get_Imm8_SN /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 2, /* num_bits */
+ 0, /* is_signed */
+ 0, /* is_src_reg */
+ 1, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Dest_SN, /* insert */
+ get_Dest_SN /* extract */
+ },
+ {
+ TILE_OP_TYPE_REGISTER, /* type */
+ MAYBE_BFD_RELOC(BFD_RELOC_NONE), /* default_reloc */
+ 2, /* num_bits */
+ 0, /* is_signed */
+ 1, /* is_src_reg */
+ 0, /* is_dest_reg */
+ 0, /* is_pc_relative */
+ 0, /* rightshift */
+ create_Src_SN, /* insert */
+ get_Src_SN /* extract */
+ }
+};
+
+const struct tile_spr tile_sprs[] = {
+ { 0, "MPL_ITLB_MISS_SET_0" },
+ { 1, "MPL_ITLB_MISS_SET_1" },
+ { 2, "MPL_ITLB_MISS_SET_2" },
+ { 3, "MPL_ITLB_MISS_SET_3" },
+ { 4, "MPL_ITLB_MISS" },
+ { 256, "ITLB_CURRENT_0" },
+ { 257, "ITLB_CURRENT_1" },
+ { 258, "ITLB_CURRENT_2" },
+ { 259, "ITLB_CURRENT_3" },
+ { 260, "ITLB_INDEX" },
+ { 261, "ITLB_MATCH_0" },
+ { 262, "ITLB_PR" },
+ { 263, "NUMBER_ITLB" },
+ { 264, "REPLACEMENT_ITLB" },
+ { 265, "WIRED_ITLB" },
+ { 266, "ITLB_PERF" },
+ { 512, "MPL_MEM_ERROR_SET_0" },
+ { 513, "MPL_MEM_ERROR_SET_1" },
+ { 514, "MPL_MEM_ERROR_SET_2" },
+ { 515, "MPL_MEM_ERROR_SET_3" },
+ { 516, "MPL_MEM_ERROR" },
+ { 517, "L1_I_ERROR" },
+ { 518, "MEM_ERROR_CBOX_ADDR" },
+ { 519, "MEM_ERROR_CBOX_STATUS" },
+ { 520, "MEM_ERROR_ENABLE" },
+ { 521, "MEM_ERROR_MBOX_ADDR" },
+ { 522, "MEM_ERROR_MBOX_STATUS" },
+ { 523, "SNIC_ERROR_LOG_STATUS" },
+ { 524, "SNIC_ERROR_LOG_VA" },
+ { 525, "XDN_DEMUX_ERROR" },
+ { 1024, "MPL_ILL_SET_0" },
+ { 1025, "MPL_ILL_SET_1" },
+ { 1026, "MPL_ILL_SET_2" },
+ { 1027, "MPL_ILL_SET_3" },
+ { 1028, "MPL_ILL" },
+ { 1536, "MPL_GPV_SET_0" },
+ { 1537, "MPL_GPV_SET_1" },
+ { 1538, "MPL_GPV_SET_2" },
+ { 1539, "MPL_GPV_SET_3" },
+ { 1540, "MPL_GPV" },
+ { 1541, "GPV_REASON" },
+ { 2048, "MPL_SN_ACCESS_SET_0" },
+ { 2049, "MPL_SN_ACCESS_SET_1" },
+ { 2050, "MPL_SN_ACCESS_SET_2" },
+ { 2051, "MPL_SN_ACCESS_SET_3" },
+ { 2052, "MPL_SN_ACCESS" },
+ { 2053, "SNCTL" },
+ { 2054, "SNFIFO_DATA" },
+ { 2055, "SNFIFO_SEL" },
+ { 2056, "SNIC_INVADDR" },
+ { 2057, "SNISTATE" },
+ { 2058, "SNOSTATE" },
+ { 2059, "SNPC" },
+ { 2060, "SNSTATIC" },
+ { 2304, "SN_DATA_AVAIL" },
+ { 2560, "MPL_IDN_ACCESS_SET_0" },
+ { 2561, "MPL_IDN_ACCESS_SET_1" },
+ { 2562, "MPL_IDN_ACCESS_SET_2" },
+ { 2563, "MPL_IDN_ACCESS_SET_3" },
+ { 2564, "MPL_IDN_ACCESS" },
+ { 2565, "IDN_DEMUX_CA_COUNT" },
+ { 2566, "IDN_DEMUX_COUNT_0" },
+ { 2567, "IDN_DEMUX_COUNT_1" },
+ { 2568, "IDN_DEMUX_CTL" },
+ { 2569, "IDN_DEMUX_CURR_TAG" },
+ { 2570, "IDN_DEMUX_QUEUE_SEL" },
+ { 2571, "IDN_DEMUX_STATUS" },
+ { 2572, "IDN_DEMUX_WRITE_FIFO" },
+ { 2573, "IDN_DEMUX_WRITE_QUEUE" },
+ { 2574, "IDN_PENDING" },
+ { 2575, "IDN_SP_FIFO_DATA" },
+ { 2576, "IDN_SP_FIFO_SEL" },
+ { 2577, "IDN_SP_FREEZE" },
+ { 2578, "IDN_SP_STATE" },
+ { 2579, "IDN_TAG_0" },
+ { 2580, "IDN_TAG_1" },
+ { 2581, "IDN_TAG_VALID" },
+ { 2582, "IDN_TILE_COORD" },
+ { 2816, "IDN_CA_DATA" },
+ { 2817, "IDN_CA_REM" },
+ { 2818, "IDN_CA_TAG" },
+ { 2819, "IDN_DATA_AVAIL" },
+ { 3072, "MPL_UDN_ACCESS_SET_0" },
+ { 3073, "MPL_UDN_ACCESS_SET_1" },
+ { 3074, "MPL_UDN_ACCESS_SET_2" },
+ { 3075, "MPL_UDN_ACCESS_SET_3" },
+ { 3076, "MPL_UDN_ACCESS" },
+ { 3077, "UDN_DEMUX_CA_COUNT" },
+ { 3078, "UDN_DEMUX_COUNT_0" },
+ { 3079, "UDN_DEMUX_COUNT_1" },
+ { 3080, "UDN_DEMUX_COUNT_2" },
+ { 3081, "UDN_DEMUX_COUNT_3" },
+ { 3082, "UDN_DEMUX_CTL" },
+ { 3083, "UDN_DEMUX_CURR_TAG" },
+ { 3084, "UDN_DEMUX_QUEUE_SEL" },
+ { 3085, "UDN_DEMUX_STATUS" },
+ { 3086, "UDN_DEMUX_WRITE_FIFO" },
+ { 3087, "UDN_DEMUX_WRITE_QUEUE" },
+ { 3088, "UDN_PENDING" },
+ { 3089, "UDN_SP_FIFO_DATA" },
+ { 3090, "UDN_SP_FIFO_SEL" },
+ { 3091, "UDN_SP_FREEZE" },
+ { 3092, "UDN_SP_STATE" },
+ { 3093, "UDN_TAG_0" },
+ { 3094, "UDN_TAG_1" },
+ { 3095, "UDN_TAG_2" },
+ { 3096, "UDN_TAG_3" },
+ { 3097, "UDN_TAG_VALID" },
+ { 3098, "UDN_TILE_COORD" },
+ { 3328, "UDN_CA_DATA" },
+ { 3329, "UDN_CA_REM" },
+ { 3330, "UDN_CA_TAG" },
+ { 3331, "UDN_DATA_AVAIL" },
+ { 3584, "MPL_IDN_REFILL_SET_0" },
+ { 3585, "MPL_IDN_REFILL_SET_1" },
+ { 3586, "MPL_IDN_REFILL_SET_2" },
+ { 3587, "MPL_IDN_REFILL_SET_3" },
+ { 3588, "MPL_IDN_REFILL" },
+ { 3589, "IDN_REFILL_EN" },
+ { 4096, "MPL_UDN_REFILL_SET_0" },
+ { 4097, "MPL_UDN_REFILL_SET_1" },
+ { 4098, "MPL_UDN_REFILL_SET_2" },
+ { 4099, "MPL_UDN_REFILL_SET_3" },
+ { 4100, "MPL_UDN_REFILL" },
+ { 4101, "UDN_REFILL_EN" },
+ { 4608, "MPL_IDN_COMPLETE_SET_0" },
+ { 4609, "MPL_IDN_COMPLETE_SET_1" },
+ { 4610, "MPL_IDN_COMPLETE_SET_2" },
+ { 4611, "MPL_IDN_COMPLETE_SET_3" },
+ { 4612, "MPL_IDN_COMPLETE" },
+ { 4613, "IDN_REMAINING" },
+ { 5120, "MPL_UDN_COMPLETE_SET_0" },
+ { 5121, "MPL_UDN_COMPLETE_SET_1" },
+ { 5122, "MPL_UDN_COMPLETE_SET_2" },
+ { 5123, "MPL_UDN_COMPLETE_SET_3" },
+ { 5124, "MPL_UDN_COMPLETE" },
+ { 5125, "UDN_REMAINING" },
+ { 5632, "MPL_SWINT_3_SET_0" },
+ { 5633, "MPL_SWINT_3_SET_1" },
+ { 5634, "MPL_SWINT_3_SET_2" },
+ { 5635, "MPL_SWINT_3_SET_3" },
+ { 5636, "MPL_SWINT_3" },
+ { 6144, "MPL_SWINT_2_SET_0" },
+ { 6145, "MPL_SWINT_2_SET_1" },
+ { 6146, "MPL_SWINT_2_SET_2" },
+ { 6147, "MPL_SWINT_2_SET_3" },
+ { 6148, "MPL_SWINT_2" },
+ { 6656, "MPL_SWINT_1_SET_0" },
+ { 6657, "MPL_SWINT_1_SET_1" },
+ { 6658, "MPL_SWINT_1_SET_2" },
+ { 6659, "MPL_SWINT_1_SET_3" },
+ { 6660, "MPL_SWINT_1" },
+ { 7168, "MPL_SWINT_0_SET_0" },
+ { 7169, "MPL_SWINT_0_SET_1" },
+ { 7170, "MPL_SWINT_0_SET_2" },
+ { 7171, "MPL_SWINT_0_SET_3" },
+ { 7172, "MPL_SWINT_0" },
+ { 7680, "MPL_UNALIGN_DATA_SET_0" },
+ { 7681, "MPL_UNALIGN_DATA_SET_1" },
+ { 7682, "MPL_UNALIGN_DATA_SET_2" },
+ { 7683, "MPL_UNALIGN_DATA_SET_3" },
+ { 7684, "MPL_UNALIGN_DATA" },
+ { 8192, "MPL_DTLB_MISS_SET_0" },
+ { 8193, "MPL_DTLB_MISS_SET_1" },
+ { 8194, "MPL_DTLB_MISS_SET_2" },
+ { 8195, "MPL_DTLB_MISS_SET_3" },
+ { 8196, "MPL_DTLB_MISS" },
+ { 8448, "AER_0" },
+ { 8449, "AER_1" },
+ { 8450, "DTLB_BAD_ADDR" },
+ { 8451, "DTLB_BAD_ADDR_REASON" },
+ { 8452, "DTLB_CURRENT_0" },
+ { 8453, "DTLB_CURRENT_1" },
+ { 8454, "DTLB_CURRENT_2" },
+ { 8455, "DTLB_CURRENT_3" },
+ { 8456, "DTLB_INDEX" },
+ { 8457, "DTLB_MATCH_0" },
+ { 8458, "NUMBER_DTLB" },
+ { 8459, "PHYSICAL_MEMORY_MODE" },
+ { 8460, "REPLACEMENT_DTLB" },
+ { 8461, "WIRED_DTLB" },
+ { 8462, "CACHE_RED_WAY_OVERRIDDEN" },
+ { 8463, "DTLB_PERF" },
+ { 8704, "MPL_DTLB_ACCESS_SET_0" },
+ { 8705, "MPL_DTLB_ACCESS_SET_1" },
+ { 8706, "MPL_DTLB_ACCESS_SET_2" },
+ { 8707, "MPL_DTLB_ACCESS_SET_3" },
+ { 8708, "MPL_DTLB_ACCESS" },
+ { 9216, "MPL_DMATLB_MISS_SET_0" },
+ { 9217, "MPL_DMATLB_MISS_SET_1" },
+ { 9218, "MPL_DMATLB_MISS_SET_2" },
+ { 9219, "MPL_DMATLB_MISS_SET_3" },
+ { 9220, "MPL_DMATLB_MISS" },
+ { 9472, "DMA_BAD_ADDR" },
+ { 9473, "DMA_STATUS" },
+ { 9728, "MPL_DMATLB_ACCESS_SET_0" },
+ { 9729, "MPL_DMATLB_ACCESS_SET_1" },
+ { 9730, "MPL_DMATLB_ACCESS_SET_2" },
+ { 9731, "MPL_DMATLB_ACCESS_SET_3" },
+ { 9732, "MPL_DMATLB_ACCESS" },
+ { 10240, "MPL_SNITLB_MISS_SET_0" },
+ { 10241, "MPL_SNITLB_MISS_SET_1" },
+ { 10242, "MPL_SNITLB_MISS_SET_2" },
+ { 10243, "MPL_SNITLB_MISS_SET_3" },
+ { 10244, "MPL_SNITLB_MISS" },
+ { 10245, "NUMBER_SNITLB" },
+ { 10246, "REPLACEMENT_SNITLB" },
+ { 10247, "SNITLB_CURRENT_0" },
+ { 10248, "SNITLB_CURRENT_1" },
+ { 10249, "SNITLB_CURRENT_2" },
+ { 10250, "SNITLB_CURRENT_3" },
+ { 10251, "SNITLB_INDEX" },
+ { 10252, "SNITLB_MATCH_0" },
+ { 10253, "SNITLB_PR" },
+ { 10254, "WIRED_SNITLB" },
+ { 10255, "SNITLB_STATUS" },
+ { 10752, "MPL_SN_NOTIFY_SET_0" },
+ { 10753, "MPL_SN_NOTIFY_SET_1" },
+ { 10754, "MPL_SN_NOTIFY_SET_2" },
+ { 10755, "MPL_SN_NOTIFY_SET_3" },
+ { 10756, "MPL_SN_NOTIFY" },
+ { 10757, "SN_NOTIFY_STATUS" },
+ { 11264, "MPL_SN_FIREWALL_SET_0" },
+ { 11265, "MPL_SN_FIREWALL_SET_1" },
+ { 11266, "MPL_SN_FIREWALL_SET_2" },
+ { 11267, "MPL_SN_FIREWALL_SET_3" },
+ { 11268, "MPL_SN_FIREWALL" },
+ { 11269, "SN_DIRECTION_PROTECT" },
+ { 11776, "MPL_IDN_FIREWALL_SET_0" },
+ { 11777, "MPL_IDN_FIREWALL_SET_1" },
+ { 11778, "MPL_IDN_FIREWALL_SET_2" },
+ { 11779, "MPL_IDN_FIREWALL_SET_3" },
+ { 11780, "MPL_IDN_FIREWALL" },
+ { 11781, "IDN_DIRECTION_PROTECT" },
+ { 12288, "MPL_UDN_FIREWALL_SET_0" },
+ { 12289, "MPL_UDN_FIREWALL_SET_1" },
+ { 12290, "MPL_UDN_FIREWALL_SET_2" },
+ { 12291, "MPL_UDN_FIREWALL_SET_3" },
+ { 12292, "MPL_UDN_FIREWALL" },
+ { 12293, "UDN_DIRECTION_PROTECT" },
+ { 12800, "MPL_TILE_TIMER_SET_0" },
+ { 12801, "MPL_TILE_TIMER_SET_1" },
+ { 12802, "MPL_TILE_TIMER_SET_2" },
+ { 12803, "MPL_TILE_TIMER_SET_3" },
+ { 12804, "MPL_TILE_TIMER" },
+ { 12805, "TILE_TIMER_CONTROL" },
+ { 13312, "MPL_IDN_TIMER_SET_0" },
+ { 13313, "MPL_IDN_TIMER_SET_1" },
+ { 13314, "MPL_IDN_TIMER_SET_2" },
+ { 13315, "MPL_IDN_TIMER_SET_3" },
+ { 13316, "MPL_IDN_TIMER" },
+ { 13317, "IDN_DEADLOCK_COUNT" },
+ { 13318, "IDN_DEADLOCK_TIMEOUT" },
+ { 13824, "MPL_UDN_TIMER_SET_0" },
+ { 13825, "MPL_UDN_TIMER_SET_1" },
+ { 13826, "MPL_UDN_TIMER_SET_2" },
+ { 13827, "MPL_UDN_TIMER_SET_3" },
+ { 13828, "MPL_UDN_TIMER" },
+ { 13829, "UDN_DEADLOCK_COUNT" },
+ { 13830, "UDN_DEADLOCK_TIMEOUT" },
+ { 14336, "MPL_DMA_NOTIFY_SET_0" },
+ { 14337, "MPL_DMA_NOTIFY_SET_1" },
+ { 14338, "MPL_DMA_NOTIFY_SET_2" },
+ { 14339, "MPL_DMA_NOTIFY_SET_3" },
+ { 14340, "MPL_DMA_NOTIFY" },
+ { 14592, "DMA_BYTE" },
+ { 14593, "DMA_CHUNK_SIZE" },
+ { 14594, "DMA_CTR" },
+ { 14595, "DMA_DST_ADDR" },
+ { 14596, "DMA_DST_CHUNK_ADDR" },
+ { 14597, "DMA_SRC_ADDR" },
+ { 14598, "DMA_SRC_CHUNK_ADDR" },
+ { 14599, "DMA_STRIDE" },
+ { 14600, "DMA_USER_STATUS" },
+ { 14848, "MPL_IDN_CA_SET_0" },
+ { 14849, "MPL_IDN_CA_SET_1" },
+ { 14850, "MPL_IDN_CA_SET_2" },
+ { 14851, "MPL_IDN_CA_SET_3" },
+ { 14852, "MPL_IDN_CA" },
+ { 15360, "MPL_UDN_CA_SET_0" },
+ { 15361, "MPL_UDN_CA_SET_1" },
+ { 15362, "MPL_UDN_CA_SET_2" },
+ { 15363, "MPL_UDN_CA_SET_3" },
+ { 15364, "MPL_UDN_CA" },
+ { 15872, "MPL_IDN_AVAIL_SET_0" },
+ { 15873, "MPL_IDN_AVAIL_SET_1" },
+ { 15874, "MPL_IDN_AVAIL_SET_2" },
+ { 15875, "MPL_IDN_AVAIL_SET_3" },
+ { 15876, "MPL_IDN_AVAIL" },
+ { 15877, "IDN_AVAIL_EN" },
+ { 16384, "MPL_UDN_AVAIL_SET_0" },
+ { 16385, "MPL_UDN_AVAIL_SET_1" },
+ { 16386, "MPL_UDN_AVAIL_SET_2" },
+ { 16387, "MPL_UDN_AVAIL_SET_3" },
+ { 16388, "MPL_UDN_AVAIL" },
+ { 16389, "UDN_AVAIL_EN" },
+ { 16896, "MPL_PERF_COUNT_SET_0" },
+ { 16897, "MPL_PERF_COUNT_SET_1" },
+ { 16898, "MPL_PERF_COUNT_SET_2" },
+ { 16899, "MPL_PERF_COUNT_SET_3" },
+ { 16900, "MPL_PERF_COUNT" },
+ { 16901, "PERF_COUNT_0" },
+ { 16902, "PERF_COUNT_1" },
+ { 16903, "PERF_COUNT_CTL" },
+ { 16904, "PERF_COUNT_STS" },
+ { 16905, "WATCH_CTL" },
+ { 16906, "WATCH_MASK" },
+ { 16907, "WATCH_VAL" },
+ { 16912, "PERF_COUNT_DN_CTL" },
+ { 17408, "MPL_INTCTRL_3_SET_0" },
+ { 17409, "MPL_INTCTRL_3_SET_1" },
+ { 17410, "MPL_INTCTRL_3_SET_2" },
+ { 17411, "MPL_INTCTRL_3_SET_3" },
+ { 17412, "MPL_INTCTRL_3" },
+ { 17413, "EX_CONTEXT_3_0" },
+ { 17414, "EX_CONTEXT_3_1" },
+ { 17415, "INTERRUPT_MASK_3_0" },
+ { 17416, "INTERRUPT_MASK_3_1" },
+ { 17417, "INTERRUPT_MASK_RESET_3_0" },
+ { 17418, "INTERRUPT_MASK_RESET_3_1" },
+ { 17419, "INTERRUPT_MASK_SET_3_0" },
+ { 17420, "INTERRUPT_MASK_SET_3_1" },
+ { 17432, "INTCTRL_3_STATUS" },
+ { 17664, "SYSTEM_SAVE_3_0" },
+ { 17665, "SYSTEM_SAVE_3_1" },
+ { 17666, "SYSTEM_SAVE_3_2" },
+ { 17667, "SYSTEM_SAVE_3_3" },
+ { 17920, "MPL_INTCTRL_2_SET_0" },
+ { 17921, "MPL_INTCTRL_2_SET_1" },
+ { 17922, "MPL_INTCTRL_2_SET_2" },
+ { 17923, "MPL_INTCTRL_2_SET_3" },
+ { 17924, "MPL_INTCTRL_2" },
+ { 17925, "EX_CONTEXT_2_0" },
+ { 17926, "EX_CONTEXT_2_1" },
+ { 17927, "INTCTRL_2_STATUS" },
+ { 17928, "INTERRUPT_MASK_2_0" },
+ { 17929, "INTERRUPT_MASK_2_1" },
+ { 17930, "INTERRUPT_MASK_RESET_2_0" },
+ { 17931, "INTERRUPT_MASK_RESET_2_1" },
+ { 17932, "INTERRUPT_MASK_SET_2_0" },
+ { 17933, "INTERRUPT_MASK_SET_2_1" },
+ { 18176, "SYSTEM_SAVE_2_0" },
+ { 18177, "SYSTEM_SAVE_2_1" },
+ { 18178, "SYSTEM_SAVE_2_2" },
+ { 18179, "SYSTEM_SAVE_2_3" },
+ { 18432, "MPL_INTCTRL_1_SET_0" },
+ { 18433, "MPL_INTCTRL_1_SET_1" },
+ { 18434, "MPL_INTCTRL_1_SET_2" },
+ { 18435, "MPL_INTCTRL_1_SET_3" },
+ { 18436, "MPL_INTCTRL_1" },
+ { 18437, "EX_CONTEXT_1_0" },
+ { 18438, "EX_CONTEXT_1_1" },
+ { 18439, "INTCTRL_1_STATUS" },
+ { 18440, "INTCTRL_3_STATUS_REV0" },
+ { 18441, "INTERRUPT_MASK_1_0" },
+ { 18442, "INTERRUPT_MASK_1_1" },
+ { 18443, "INTERRUPT_MASK_RESET_1_0" },
+ { 18444, "INTERRUPT_MASK_RESET_1_1" },
+ { 18445, "INTERRUPT_MASK_SET_1_0" },
+ { 18446, "INTERRUPT_MASK_SET_1_1" },
+ { 18688, "SYSTEM_SAVE_1_0" },
+ { 18689, "SYSTEM_SAVE_1_1" },
+ { 18690, "SYSTEM_SAVE_1_2" },
+ { 18691, "SYSTEM_SAVE_1_3" },
+ { 18944, "MPL_INTCTRL_0_SET_0" },
+ { 18945, "MPL_INTCTRL_0_SET_1" },
+ { 18946, "MPL_INTCTRL_0_SET_2" },
+ { 18947, "MPL_INTCTRL_0_SET_3" },
+ { 18948, "MPL_INTCTRL_0" },
+ { 18949, "EX_CONTEXT_0_0" },
+ { 18950, "EX_CONTEXT_0_1" },
+ { 18951, "INTCTRL_0_STATUS" },
+ { 18952, "INTERRUPT_MASK_0_0" },
+ { 18953, "INTERRUPT_MASK_0_1" },
+ { 18954, "INTERRUPT_MASK_RESET_0_0" },
+ { 18955, "INTERRUPT_MASK_RESET_0_1" },
+ { 18956, "INTERRUPT_MASK_SET_0_0" },
+ { 18957, "INTERRUPT_MASK_SET_0_1" },
+ { 19200, "SYSTEM_SAVE_0_0" },
+ { 19201, "SYSTEM_SAVE_0_1" },
+ { 19202, "SYSTEM_SAVE_0_2" },
+ { 19203, "SYSTEM_SAVE_0_3" },
+ { 19456, "MPL_BOOT_ACCESS_SET_0" },
+ { 19457, "MPL_BOOT_ACCESS_SET_1" },
+ { 19458, "MPL_BOOT_ACCESS_SET_2" },
+ { 19459, "MPL_BOOT_ACCESS_SET_3" },
+ { 19460, "MPL_BOOT_ACCESS" },
+ { 19461, "CBOX_CACHEASRAM_CONFIG" },
+ { 19462, "CBOX_CACHE_CONFIG" },
+ { 19463, "CBOX_MMAP_0" },
+ { 19464, "CBOX_MMAP_1" },
+ { 19465, "CBOX_MMAP_2" },
+ { 19466, "CBOX_MMAP_3" },
+ { 19467, "CBOX_MSR" },
+ { 19468, "CBOX_SRC_ID" },
+ { 19469, "CYCLE_HIGH_MODIFY" },
+ { 19470, "CYCLE_LOW_MODIFY" },
+ { 19471, "DIAG_BCST_CTL" },
+ { 19472, "DIAG_BCST_MASK" },
+ { 19473, "DIAG_BCST_TRIGGER" },
+ { 19474, "DIAG_MUX_CTL" },
+ { 19475, "DIAG_TRACE_CTL" },
+ { 19476, "DIAG_TRACE_STS" },
+ { 19477, "IDN_DEMUX_BUF_THRESH" },
+ { 19478, "SBOX_CONFIG" },
+ { 19479, "TILE_COORD" },
+ { 19480, "UDN_DEMUX_BUF_THRESH" },
+ { 19481, "CBOX_HOME_MAP_ADDR" },
+ { 19482, "CBOX_HOME_MAP_DATA" },
+ { 19483, "CBOX_MSR1" },
+ { 19484, "BIG_ENDIAN_CONFIG" },
+ { 19485, "MEM_STRIPE_CONFIG" },
+ { 19486, "DIAG_TRACE_WAY" },
+ { 19487, "VDN_SNOOP_SHIM_CTL" },
+ { 19488, "PERF_COUNT_PLS" },
+ { 19489, "DIAG_TRACE_DATA" },
+ { 19712, "I_AER_0" },
+ { 19713, "I_AER_1" },
+ { 19714, "I_PHYSICAL_MEMORY_MODE" },
+ { 19968, "MPL_WORLD_ACCESS_SET_0" },
+ { 19969, "MPL_WORLD_ACCESS_SET_1" },
+ { 19970, "MPL_WORLD_ACCESS_SET_2" },
+ { 19971, "MPL_WORLD_ACCESS_SET_3" },
+ { 19972, "MPL_WORLD_ACCESS" },
+ { 19973, "SIM_SOCKET" },
+ { 19974, "CYCLE_HIGH" },
+ { 19975, "CYCLE_LOW" },
+ { 19976, "DONE" },
+ { 19977, "FAIL" },
+ { 19978, "INTERRUPT_CRITICAL_SECTION" },
+ { 19979, "PASS" },
+ { 19980, "SIM_CONTROL" },
+ { 19981, "EVENT_BEGIN" },
+ { 19982, "EVENT_END" },
+ { 19983, "TILE_WRITE_PENDING" },
+ { 19984, "TILE_RTF_HWM" },
+ { 20224, "PROC_STATUS" },
+ { 20225, "STATUS_SATURATE" },
+ { 20480, "MPL_I_ASID_SET_0" },
+ { 20481, "MPL_I_ASID_SET_1" },
+ { 20482, "MPL_I_ASID_SET_2" },
+ { 20483, "MPL_I_ASID_SET_3" },
+ { 20484, "MPL_I_ASID" },
+ { 20485, "I_ASID" },
+ { 20992, "MPL_D_ASID_SET_0" },
+ { 20993, "MPL_D_ASID_SET_1" },
+ { 20994, "MPL_D_ASID_SET_2" },
+ { 20995, "MPL_D_ASID_SET_3" },
+ { 20996, "MPL_D_ASID" },
+ { 20997, "D_ASID" },
+ { 21504, "MPL_DMA_ASID_SET_0" },
+ { 21505, "MPL_DMA_ASID_SET_1" },
+ { 21506, "MPL_DMA_ASID_SET_2" },
+ { 21507, "MPL_DMA_ASID_SET_3" },
+ { 21508, "MPL_DMA_ASID" },
+ { 21509, "DMA_ASID" },
+ { 22016, "MPL_SNI_ASID_SET_0" },
+ { 22017, "MPL_SNI_ASID_SET_1" },
+ { 22018, "MPL_SNI_ASID_SET_2" },
+ { 22019, "MPL_SNI_ASID_SET_3" },
+ { 22020, "MPL_SNI_ASID" },
+ { 22021, "SNI_ASID" },
+ { 22528, "MPL_DMA_CPL_SET_0" },
+ { 22529, "MPL_DMA_CPL_SET_1" },
+ { 22530, "MPL_DMA_CPL_SET_2" },
+ { 22531, "MPL_DMA_CPL_SET_3" },
+ { 22532, "MPL_DMA_CPL" },
+ { 23040, "MPL_SN_CPL_SET_0" },
+ { 23041, "MPL_SN_CPL_SET_1" },
+ { 23042, "MPL_SN_CPL_SET_2" },
+ { 23043, "MPL_SN_CPL_SET_3" },
+ { 23044, "MPL_SN_CPL" },
+ { 23552, "MPL_DOUBLE_FAULT_SET_0" },
+ { 23553, "MPL_DOUBLE_FAULT_SET_1" },
+ { 23554, "MPL_DOUBLE_FAULT_SET_2" },
+ { 23555, "MPL_DOUBLE_FAULT_SET_3" },
+ { 23556, "MPL_DOUBLE_FAULT" },
+ { 23557, "LAST_INTERRUPT_REASON" },
+ { 24064, "MPL_SN_STATIC_ACCESS_SET_0" },
+ { 24065, "MPL_SN_STATIC_ACCESS_SET_1" },
+ { 24066, "MPL_SN_STATIC_ACCESS_SET_2" },
+ { 24067, "MPL_SN_STATIC_ACCESS_SET_3" },
+ { 24068, "MPL_SN_STATIC_ACCESS" },
+ { 24069, "SN_STATIC_CTL" },
+ { 24070, "SN_STATIC_FIFO_DATA" },
+ { 24071, "SN_STATIC_FIFO_SEL" },
+ { 24073, "SN_STATIC_ISTATE" },
+ { 24074, "SN_STATIC_OSTATE" },
+ { 24076, "SN_STATIC_STATIC" },
+ { 24320, "SN_STATIC_DATA_AVAIL" },
+ { 24576, "MPL_AUX_PERF_COUNT_SET_0" },
+ { 24577, "MPL_AUX_PERF_COUNT_SET_1" },
+ { 24578, "MPL_AUX_PERF_COUNT_SET_2" },
+ { 24579, "MPL_AUX_PERF_COUNT_SET_3" },
+ { 24580, "MPL_AUX_PERF_COUNT" },
+ { 24581, "AUX_PERF_COUNT_0" },
+ { 24582, "AUX_PERF_COUNT_1" },
+ { 24583, "AUX_PERF_COUNT_CTL" },
+ { 24584, "AUX_PERF_COUNT_STS" },
+};
+
+const int tile_num_sprs = 499;
+
+
+
+
+/* Canonical name of each register. */
+const char *const tile_register_names[] =
+{
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+ "r32", "r33", "r34", "r35", "r36", "r37", "r38", "r39",
+ "r40", "r41", "r42", "r43", "r44", "r45", "r46", "r47",
+ "r48", "r49", "r50", "r51", "r52", "tp", "sp", "lr",
+ "sn", "idn0", "idn1", "udn0", "udn1", "udn2", "udn3", "zero"
+};
+
+
+/* Given a set of bundle bits and the lookup FSM for a specific pipe,
+ * returns which instruction the bundle contains in that pipe.
+ */
+static const struct tile_opcode *
+find_opcode(tile_bundle_bits bits, const unsigned short *table)
+{
+ int index = 0;
+
+ while (1)
+ {
+ unsigned short bitspec = table[index];
+ unsigned int bitfield =
+ ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6);
+
+ unsigned short next = table[index + 1 + bitfield];
+ if (next <= TILE_OPC_NONE)
+ return &tile_opcodes[next];
+
+ index = next - TILE_OPC_NONE;
+ }
+}
+
+
+int
+parse_insn_tile(tile_bundle_bits bits,
+ unsigned int pc,
+ struct tile_decoded_instruction
+ decoded[TILE_MAX_INSTRUCTIONS_PER_BUNDLE])
+{
+ int num_instructions = 0;
+ int pipe;
+
+ int min_pipe, max_pipe;
+ if ((bits & TILE_BUNDLE_Y_ENCODING_MASK) == 0)
+ {
+ min_pipe = TILE_PIPELINE_X0;
+ max_pipe = TILE_PIPELINE_X1;
+ }
+ else
+ {
+ min_pipe = TILE_PIPELINE_Y0;
+ max_pipe = TILE_PIPELINE_Y2;
+ }
+
+ /* For each pipe, find an instruction that fits. */
+ for (pipe = min_pipe; pipe <= max_pipe; pipe++)
+ {
+ const struct tile_opcode *opc;
+ struct tile_decoded_instruction *d;
+ int i;
+
+ d = &decoded[num_instructions++];
+ opc = find_opcode (bits, tile_bundle_decoder_fsms[pipe]);
+ d->opcode = opc;
+
+ /* Decode each operand, sign extending, etc. as appropriate. */
+ for (i = 0; i < opc->num_operands; i++)
+ {
+ const struct tile_operand *op =
+ &tile_operands[opc->operands[pipe][i]];
+ int opval = op->extract (bits);
+ if (op->is_signed)
+ {
+ /* Sign-extend the operand. */
+ int shift = (int)((sizeof(int) * 8) - op->num_bits);
+ opval = (opval << shift) >> shift;
+ }
+
+ /* Adjust PC-relative scaled branch offsets. */
+ if (op->type == TILE_OP_TYPE_ADDRESS)
+ {
+ opval *= TILE_BUNDLE_SIZE_IN_BYTES;
+ opval += (int)pc;
+ }
+
+ /* Record the final value. */
+ d->operands[i] = op;
+ d->operand_values[i] = opval;
+ }
+ }
+
+ return num_instructions;
+}
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c
new file mode 100644
index 000000000000..47500a324e32
--- /dev/null
+++ b/arch/tile/kernel/time.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Support the cycle counter clocksource and tile timer clock event device.
+ */
+
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/hardirq.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/delay.h>
+#include <asm/irq_regs.h>
+#include <hv/hypervisor.h>
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+
+/*
+ * Define the cycle counter clock source.
+ */
+
+/* How many cycles per second we are running at. */
+static cycles_t cycles_per_sec __write_once;
+
+/*
+ * We set up shift and multiply values with a minsec of five seconds,
+ * since our timer counter counts down 31 bits at a frequency of
+ * no less than 500 MHz. See @minsec for clocks_calc_mult_shift().
+ * We could use a different value for the 64-bit free-running
+ * cycle counter, but we use the same one for consistency, and since
+ * we will be reasonably precise with this value anyway.
+ */
+#define TILE_MINSEC 5
+
+cycles_t get_clock_rate()
+{
+ return cycles_per_sec;
+}
+
+#if CHIP_HAS_SPLIT_CYCLE()
+cycles_t get_cycles()
+{
+ unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH);
+ unsigned int low = __insn_mfspr(SPR_CYCLE_LOW);
+ unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH);
+
+ while (unlikely(high != high2)) {
+ low = __insn_mfspr(SPR_CYCLE_LOW);
+ high = high2;
+ high2 = __insn_mfspr(SPR_CYCLE_HIGH);
+ }
+
+ return (((cycles_t)high) << 32) | low;
+}
+#endif
+
+cycles_t clocksource_get_cycles(struct clocksource *cs)
+{
+ return get_cycles();
+}
+
+static struct clocksource cycle_counter_cs = {
+ .name = "cycle counter",
+ .rating = 300,
+ .read = clocksource_get_cycles,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/*
+ * Called very early from setup_arch() to set cycles_per_sec.
+ * We initialize it early so we can use it to set up loops_per_jiffy.
+ */
+void __init setup_clock(void)
+{
+ cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED);
+ clocksource_calc_mult_shift(&cycle_counter_cs, cycles_per_sec,
+ TILE_MINSEC);
+}
+
+void __init calibrate_delay(void)
+{
+ loops_per_jiffy = get_clock_rate() / HZ;
+ pr_info("Clock rate yields %lu.%02lu BogoMIPS (lpj=%lu)\n",
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy);
+}
+
+/* Called fairly late in init/main.c, but before we go smp. */
+void __init time_init(void)
+{
+ /* Initialize and register the clock source. */
+ clocksource_register(&cycle_counter_cs);
+
+ /* Start up the tile-timer interrupt source on the boot cpu. */
+ setup_tile_timer();
+}
+
+
+/*
+ * Define the tile timer clock event device. The timer is driven by
+ * the TILE_TIMER_CONTROL register, which consists of a 31-bit down
+ * counter, plus bit 31, which signifies that the counter has wrapped
+ * from zero to (2**31) - 1. The INT_TILE_TIMER interrupt will be
+ * raised as long as bit 31 is set.
+ */
+
+#define MAX_TICK 0x7fffffff /* we have 31 bits of countdown timer */
+
+static int tile_timer_set_next_event(unsigned long ticks,
+ struct clock_event_device *evt)
+{
+ BUG_ON(ticks > MAX_TICK);
+ __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks);
+ raw_local_irq_unmask_now(INT_TILE_TIMER);
+ return 0;
+}
+
+/*
+ * Whenever anyone tries to change modes, we just mask interrupts
+ * and wait for the next event to get set.
+ */
+static void tile_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ raw_local_irq_mask_now(INT_TILE_TIMER);
+}
+
+/*
+ * Set min_delta_ns to 1 microsecond, since it takes about
+ * that long to fire the interrupt.
+ */
+static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = {
+ .name = "tile timer",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .min_delta_ns = 1000,
+ .rating = 100,
+ .irq = -1,
+ .set_next_event = tile_timer_set_next_event,
+ .set_mode = tile_timer_set_mode,
+};
+
+void __cpuinit setup_tile_timer(void)
+{
+ struct clock_event_device *evt = &__get_cpu_var(tile_timer);
+
+ /* Fill in fields that are speed-specific. */
+ clockevents_calc_mult_shift(evt, cycles_per_sec, TILE_MINSEC);
+ evt->max_delta_ns = clockevent_delta2ns(MAX_TICK, evt);
+
+ /* Mark as being for this cpu only. */
+ evt->cpumask = cpumask_of(smp_processor_id());
+
+ /* Start out with timer not firing. */
+ raw_local_irq_mask_now(INT_TILE_TIMER);
+
+ /* Register tile timer. */
+ clockevents_register_device(evt);
+}
+
+/* Called from the interrupt vector. */
+void do_timer_interrupt(struct pt_regs *regs, int fault_num)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ struct clock_event_device *evt = &__get_cpu_var(tile_timer);
+
+ /*
+ * Mask the timer interrupt here, since we are a oneshot timer
+ * and there are now by definition no events pending.
+ */
+ raw_local_irq_mask(INT_TILE_TIMER);
+
+ /* Track time spent here in an interrupt context */
+ irq_enter();
+
+ /* Track interrupt count. */
+ __get_cpu_var(irq_stat).irq_timer_count++;
+
+ /* Call the generic timer handler */
+ evt->event_handler(evt);
+
+ /*
+ * Track time spent against the current process again and
+ * process any softirqs if they are waiting.
+ */
+ irq_exit();
+
+ set_irq_regs(old_regs);
+}
+
+/*
+ * Scheduler clock - returns current time in nanosec units.
+ * Note that with LOCKDEP, this is called during lockdep_init(), and
+ * we will claim that sched_clock() is zero for a little while, until
+ * we run setup_clock(), above.
+ */
+unsigned long long sched_clock(void)
+{
+ return clocksource_cyc2ns(get_cycles(),
+ cycle_counter_cs.mult,
+ cycle_counter_cs.shift);
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+ return -EINVAL;
+}
diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c
new file mode 100644
index 000000000000..2dffc1044d83
--- /dev/null
+++ b/arch/tile/kernel/tlb.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <asm/tlbflush.h>
+#include <asm/homecache.h>
+#include <hv/hypervisor.h>
+
+/* From tlbflush.h */
+DEFINE_PER_CPU(int, current_asid);
+int min_asid, max_asid;
+
+/*
+ * Note that we flush the L1I (for VM_EXEC pages) as well as the TLB
+ * so that when we are unmapping an executable page, we also flush it.
+ * Combined with flushing the L1I at context switch time, this means
+ * we don't have to do any other icache flushes.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ HV_Remote_ASID asids[NR_CPUS];
+ int i = 0, cpu;
+ for_each_cpu(cpu, &mm->cpu_vm_mask) {
+ HV_Remote_ASID *asid = &asids[i++];
+ asid->y = cpu / smp_topology.width;
+ asid->x = cpu % smp_topology.width;
+ asid->asid = per_cpu(current_asid, cpu);
+ }
+ flush_remote(0, HV_FLUSH_EVICT_L1I, &mm->cpu_vm_mask,
+ 0, 0, 0, NULL, asids, i);
+}
+
+void flush_tlb_current_task(void)
+{
+ flush_tlb_mm(current->mm);
+}
+
+void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm,
+ unsigned long va)
+{
+ unsigned long size = hv_page_size(vma);
+ int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
+ flush_remote(0, cache, &mm->cpu_vm_mask,
+ va, size, size, &mm->cpu_vm_mask, NULL, 0);
+}
+
+void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va)
+{
+ flush_tlb_page_mm(vma, vma->vm_mm, va);
+}
+EXPORT_SYMBOL(flush_tlb_page);
+
+void flush_tlb_range(const struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ unsigned long size = hv_page_size(vma);
+ struct mm_struct *mm = vma->vm_mm;
+ int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
+ flush_remote(0, cache, &mm->cpu_vm_mask, start, end - start, size,
+ &mm->cpu_vm_mask, NULL, 0);
+}
+
+void flush_tlb_all(void)
+{
+ int i;
+ for (i = 0; ; ++i) {
+ HV_VirtAddrRange r = hv_inquire_virtual(i);
+ if (r.size == 0)
+ break;
+ flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask,
+ r.start, r.size, PAGE_SIZE, cpu_online_mask,
+ NULL, 0);
+ flush_remote(0, 0, NULL,
+ r.start, r.size, HPAGE_SIZE, cpu_online_mask,
+ NULL, 0);
+ }
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask,
+ start, end - start, PAGE_SIZE, cpu_online_mask, NULL, 0);
+}
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c
new file mode 100644
index 000000000000..12cb10f38527
--- /dev/null
+++ b/arch/tile/kernel/traps.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/ptrace.h>
+#include <asm/opcode-tile.h>
+
+#include <arch/interrupts.h>
+#include <arch/spr_def.h>
+
+void __init trap_init(void)
+{
+ /* Nothing needed here since we link code at .intrpt1 */
+}
+
+int unaligned_fixup = 1;
+
+static int __init setup_unaligned_fixup(char *str)
+{
+ /*
+ * Say "=-1" to completely disable it. If you just do "=0", we
+ * will still parse the instruction, then fire a SIGBUS with
+ * the correct address from inside the single_step code.
+ */
+ long val;
+ if (strict_strtol(str, 0, &val) != 0)
+ return 0;
+ unaligned_fixup = val;
+ printk("Fixups for unaligned data accesses are %s\n",
+ unaligned_fixup >= 0 ?
+ (unaligned_fixup ? "enabled" : "disabled") :
+ "completely disabled");
+ return 1;
+}
+__setup("unaligned_fixup=", setup_unaligned_fixup);
+
+#if CHIP_HAS_TILE_DMA()
+
+static int dma_disabled;
+
+static int __init nodma(char *str)
+{
+ printk("User-space DMA is disabled\n");
+ dma_disabled = 1;
+ return 1;
+}
+__setup("nodma", nodma);
+
+/* How to decode SPR_GPV_REASON */
+#define IRET_ERROR (1U << 31)
+#define MT_ERROR (1U << 30)
+#define MF_ERROR (1U << 29)
+#define SPR_INDEX ((1U << 15) - 1)
+#define SPR_MPL_SHIFT 9 /* starting bit position for MPL encoded in SPR */
+
+/*
+ * See if this GPV is just to notify the kernel of SPR use and we can
+ * retry the user instruction after adjusting some MPLs suitably.
+ */
+static int retry_gpv(unsigned int gpv_reason)
+{
+ int mpl;
+
+ if (gpv_reason & IRET_ERROR)
+ return 0;
+
+ BUG_ON((gpv_reason & (MT_ERROR|MF_ERROR)) == 0);
+ mpl = (gpv_reason & SPR_INDEX) >> SPR_MPL_SHIFT;
+ if (mpl == INT_DMA_NOTIFY && !dma_disabled) {
+ /* User is turning on DMA. Allow it and retry. */
+ printk(KERN_DEBUG "Process %d/%s is now enabled for DMA\n",
+ current->pid, current->comm);
+ BUG_ON(current->thread.tile_dma_state.enabled);
+ current->thread.tile_dma_state.enabled = 1;
+ grant_dma_mpls();
+ return 1;
+ }
+
+ return 0;
+}
+
+#endif /* CHIP_HAS_TILE_DMA() */
+
+/* Defined inside do_trap(), below. */
+#ifdef __tilegx__
+extern tilegx_bundle_bits bpt_code;
+#else
+extern tile_bundle_bits bpt_code;
+#endif
+
+void __kprobes do_trap(struct pt_regs *regs, int fault_num,
+ unsigned long reason)
+{
+ siginfo_t info = { 0 };
+ int signo, code;
+ unsigned long address;
+ __typeof__(bpt_code) instr;
+
+ /* Re-enable interrupts. */
+ local_irq_enable();
+
+ /*
+ * If it hits in kernel mode and we can't fix it up, just exit the
+ * current process and hope for the best.
+ */
+ if (!user_mode(regs)) {
+ if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */
+ return;
+ printk(KERN_ALERT "Kernel took bad trap %d at PC %#lx\n",
+ fault_num, regs->pc);
+ if (fault_num == INT_GPV)
+ printk(KERN_ALERT "GPV_REASON is %#lx\n", reason);
+ show_regs(regs);
+ do_exit(SIGKILL); /* FIXME: implement i386 die() */
+ return;
+ }
+
+ switch (fault_num) {
+ case INT_ILL:
+ asm(".pushsection .rodata.bpt_code,\"a\";"
+ ".align 8;"
+ "bpt_code: bpt;"
+ ".size bpt_code,.-bpt_code;"
+ ".popsection");
+
+ if (copy_from_user(&instr, (void *)regs->pc, sizeof(instr))) {
+ printk(KERN_ERR "Unreadable instruction for INT_ILL:"
+ " %#lx\n", regs->pc);
+ do_exit(SIGKILL);
+ return;
+ }
+ if (instr == bpt_code) {
+ signo = SIGTRAP;
+ code = TRAP_BRKPT;
+ } else {
+ signo = SIGILL;
+ code = ILL_ILLOPC;
+ }
+ address = regs->pc;
+ break;
+ case INT_GPV:
+#if CHIP_HAS_TILE_DMA()
+ if (retry_gpv(reason))
+ return;
+#endif
+ /*FALLTHROUGH*/
+ case INT_UDN_ACCESS:
+ case INT_IDN_ACCESS:
+#if CHIP_HAS_SN()
+ case INT_SN_ACCESS:
+#endif
+ signo = SIGILL;
+ code = ILL_PRVREG;
+ address = regs->pc;
+ break;
+ case INT_SWINT_3:
+ case INT_SWINT_2:
+ case INT_SWINT_0:
+ signo = SIGILL;
+ code = ILL_ILLTRP;
+ address = regs->pc;
+ break;
+ case INT_UNALIGN_DATA:
+#ifndef __tilegx__ /* FIXME: GX: no single-step yet */
+ if (unaligned_fixup >= 0) {
+ struct single_step_state *state =
+ current_thread_info()->step_state;
+ if (!state || (void *)(regs->pc) != state->buffer) {
+ single_step_once(regs);
+ return;
+ }
+ }
+#endif
+ signo = SIGBUS;
+ code = BUS_ADRALN;
+ address = 0;
+ break;
+ case INT_DOUBLE_FAULT:
+ /*
+ * For double fault, "reason" is actually passed as
+ * SYSTEM_SAVE_1_2, the hypervisor's double-fault info, so
+ * we can provide the original fault number rather than
+ * the uninteresting "INT_DOUBLE_FAULT" so the user can
+ * learn what actually struck while PL0 ICS was set.
+ */
+ fault_num = reason;
+ signo = SIGILL;
+ code = ILL_DBLFLT;
+ address = regs->pc;
+ break;
+#ifdef __tilegx__
+ case INT_ILL_TRANS:
+ signo = SIGSEGV;
+ code = SEGV_MAPERR;
+ if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK)
+ address = regs->pc;
+ else
+ address = 0; /* FIXME: GX: single-step for address */
+ break;
+#endif
+ default:
+ panic("Unexpected do_trap interrupt number %d", fault_num);
+ return;
+ }
+
+ info.si_signo = signo;
+ info.si_code = code;
+ info.si_addr = (void *)address;
+ if (signo == SIGILL)
+ info.si_trapno = fault_num;
+ force_sig_info(signo, &info, current);
+}
+
+extern void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52);
+
+void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52)
+{
+ _dump_stack(dummy, pc, lr, sp, r52);
+ printk("Double fault: exiting\n");
+ machine_halt();
+}
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..77388c1415bd
--- /dev/null
+++ b/arch/tile/kernel/vmlinux.lds.S
@@ -0,0 +1,98 @@
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+#include <hv/hypervisor.h>
+
+/* Text loads starting from the supervisor interrupt vector address. */
+#define TEXT_OFFSET MEM_SV_INTRPT
+
+OUTPUT_ARCH(tile)
+ENTRY(_start)
+jiffies = jiffies_64;
+
+PHDRS
+{
+ intrpt1 PT_LOAD ;
+ text PT_LOAD ;
+ data PT_LOAD ;
+}
+SECTIONS
+{
+ /* Text is loaded with a different VA than data; start with text. */
+ #undef LOAD_OFFSET
+ #define LOAD_OFFSET TEXT_OFFSET
+
+ /* Interrupt vectors */
+ .intrpt1 (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */
+ {
+ _text = .;
+ _stext = .;
+ *(.intrpt1)
+ } :intrpt1 =0
+
+ /* Hypervisor call vectors */
+ #include "hvglue.lds"
+
+ /* Now the real code */
+ . = ALIGN(0x20000);
+ HEAD_TEXT_SECTION :text =0
+ .text : AT (ADDR(.text) - LOAD_OFFSET) {
+ SCHED_TEXT
+ LOCK_TEXT
+ __fix_text_end = .; /* tile-cpack won't rearrange before this */
+ TEXT_TEXT
+ *(.text.*)
+ *(.coldtext*)
+ *(.fixup)
+ *(.gnu.warning)
+ }
+ _etext = .;
+
+ /* "Init" is divided into two areas with very different virtual addresses. */
+ INIT_TEXT_SECTION(PAGE_SIZE)
+
+ /* Now we skip back to PAGE_OFFSET for the data. */
+ . = (. - TEXT_OFFSET + PAGE_OFFSET);
+ #undef LOAD_OFFSET
+ #define LOAD_OFFSET PAGE_OFFSET
+
+ . = ALIGN(PAGE_SIZE);
+ VMLINUX_SYMBOL(_sinitdata) = .;
+ .init.page : AT (ADDR(.init.page) - LOAD_OFFSET) {
+ *(.init.page)
+ } :data =0
+ INIT_DATA_SECTION(16)
+ PERCPU(PAGE_SIZE)
+ . = ALIGN(PAGE_SIZE);
+ VMLINUX_SYMBOL(_einitdata) = .;
+
+ _sdata = .; /* Start of data section */
+
+ RO_DATA_SECTION(PAGE_SIZE)
+
+ /* initially writeable, then read-only */
+ . = ALIGN(PAGE_SIZE);
+ __w1data_begin = .;
+ .w1data : AT(ADDR(.w1data) - LOAD_OFFSET) {
+ VMLINUX_SYMBOL(__w1data_begin) = .;
+ *(.w1data)
+ VMLINUX_SYMBOL(__w1data_end) = .;
+ }
+
+ RW_DATA_SECTION(L2_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
+
+ _edata = .;
+
+ EXCEPTION_TABLE(L2_CACHE_BYTES)
+ NOTES
+
+
+ BSS_SECTION(8, PAGE_SIZE, 1)
+ _end = . ;
+
+ STABS_DEBUG
+ DWARF_DEBUG
+
+ DISCARDS
+}
diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile
new file mode 100644
index 000000000000..ea9c209d33fb
--- /dev/null
+++ b/arch/tile/lib/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for TILE-specific library files..
+#
+
+lib-y = checksum.o cpumask.o delay.o __invalidate_icache.o \
+ mb_incoherent.o uaccess.o \
+ memcpy_$(BITS).o memchr_$(BITS).o memmove_$(BITS).o memset_$(BITS).o \
+ strchr_$(BITS).o strlen_$(BITS).o
+
+ifneq ($(CONFIG_TILEGX),y)
+lib-y += atomic_32.o atomic_asm_32.o memcpy_tile64.o
+endif
+
+lib-$(CONFIG_SMP) += spinlock_$(BITS).o usercopy_$(BITS).o
+
+obj-$(CONFIG_MODULES) += exports.o
diff --git a/arch/tile/lib/__invalidate_icache.S b/arch/tile/lib/__invalidate_icache.S
new file mode 100644
index 000000000000..92e705059127
--- /dev/null
+++ b/arch/tile/lib/__invalidate_icache.S
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * A routine for synchronizing the instruction and data caches.
+ * Useful for self-modifying code.
+ *
+ * r0 holds the buffer address
+ * r1 holds the size in bytes
+ */
+
+#include <arch/chip.h>
+#include <feedback.h>
+
+#if defined(__NEWLIB__) || defined(__BME__)
+#include <sys/page.h>
+#else
+#include <asm/page.h>
+#endif
+
+#ifdef __tilegx__
+/* Share code among Tile family chips but adjust opcodes appropriately. */
+#define slt cmpltu
+#define bbst blbst
+#define bnezt bnzt
+#endif
+
+#if defined(__tilegx__) && __SIZEOF_POINTER__ == 4
+/* Force 32-bit ops so pointers wrap around appropriately. */
+#define ADD_PTR addx
+#define ADDI_PTR addxi
+#else
+#define ADD_PTR add
+#define ADDI_PTR addi
+#endif
+
+ .section .text.__invalidate_icache, "ax"
+ .global __invalidate_icache
+ .type __invalidate_icache,@function
+ .hidden __invalidate_icache
+ .align 8
+__invalidate_icache:
+ FEEDBACK_ENTER(__invalidate_icache)
+ {
+ ADD_PTR r1, r0, r1 /* end of buffer */
+ blez r1, .Lexit /* skip out if size <= 0 */
+ }
+ {
+ ADDI_PTR r1, r1, -1 /* point to last byte to flush */
+ andi r0, r0, -CHIP_L1I_LINE_SIZE() /* align to cache-line size */
+ }
+ {
+ andi r1, r1, -CHIP_L1I_LINE_SIZE() /* last cache line to flush */
+ mf
+ }
+#if CHIP_L1I_CACHE_SIZE() > PAGE_SIZE
+ {
+ moveli r4, CHIP_L1I_CACHE_SIZE() / PAGE_SIZE /* loop counter */
+ move r2, r0 /* remember starting address */
+ }
+#endif
+ drain
+ {
+ slt r3, r0, r1 /* set up loop invariant */
+#if CHIP_L1I_CACHE_SIZE() > PAGE_SIZE
+ moveli r6, PAGE_SIZE
+#endif
+ }
+.Lentry:
+ {
+ icoh r0
+ ADDI_PTR r0, r0, CHIP_L1I_LINE_SIZE() /* advance buffer */
+ }
+ {
+ slt r3, r0, r1 /* check if buffer < buffer + size */
+ bbst r3, .Lentry /* loop if buffer < buffer + size */
+ }
+#if CHIP_L1I_CACHE_SIZE() > PAGE_SIZE
+ {
+ ADD_PTR r2, r2, r6
+ ADD_PTR r1, r1, r6
+ }
+ {
+ move r0, r2
+ addi r4, r4, -1
+ }
+ {
+ slt r3, r0, r1 /* set up loop invariant */
+ bnezt r4, .Lentry
+ }
+#endif
+ drain
+.Lexit:
+ jrp lr
+
+.Lend___invalidate_icache:
+ .size __invalidate_icache, \
+ .Lend___invalidate_icache - __invalidate_icache
diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c
new file mode 100644
index 000000000000..be1e8acd105d
--- /dev/null
+++ b/arch/tile/lib/atomic_32.c
@@ -0,0 +1,347 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/cache.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/atomic.h>
+#include <arch/chip.h>
+
+/* The routines in atomic_asm.S are private, so we only declare them here. */
+extern struct __get_user __atomic_cmpxchg(volatile int *p,
+ int *lock, int o, int n);
+extern struct __get_user __atomic_xchg(volatile int *p, int *lock, int n);
+extern struct __get_user __atomic_xchg_add(volatile int *p, int *lock, int n);
+extern struct __get_user __atomic_xchg_add_unless(volatile int *p,
+ int *lock, int o, int n);
+extern struct __get_user __atomic_or(volatile int *p, int *lock, int n);
+extern struct __get_user __atomic_andn(volatile int *p, int *lock, int n);
+extern struct __get_user __atomic_xor(volatile int *p, int *lock, int n);
+
+extern u64 __atomic64_cmpxchg(volatile u64 *p, int *lock, u64 o, u64 n);
+extern u64 __atomic64_xchg(volatile u64 *p, int *lock, u64 n);
+extern u64 __atomic64_xchg_add(volatile u64 *p, int *lock, u64 n);
+extern u64 __atomic64_xchg_add_unless(volatile u64 *p,
+ int *lock, u64 o, u64 n);
+
+
+/* See <asm/atomic.h> */
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+
+/*
+ * A block of memory containing locks for atomic ops. Each instance of this
+ * struct will be homed on a different CPU.
+ */
+struct atomic_locks_on_cpu {
+ int lock[ATOMIC_HASH_L2_SIZE];
+} __attribute__((aligned(ATOMIC_HASH_L2_SIZE * 4)));
+
+static DEFINE_PER_CPU(struct atomic_locks_on_cpu, atomic_lock_pool);
+
+/* The locks we'll use until __init_atomic_per_cpu is called. */
+static struct atomic_locks_on_cpu __initdata initial_atomic_locks;
+
+/* Hash into this vector to get a pointer to lock for the given atomic. */
+struct atomic_locks_on_cpu *atomic_lock_ptr[ATOMIC_HASH_L1_SIZE]
+ __write_once = {
+ [0 ... ATOMIC_HASH_L1_SIZE-1] (&initial_atomic_locks)
+};
+
+#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+/* This page is remapped on startup to be hash-for-home. */
+int atomic_locks[PAGE_SIZE / sizeof(int) /* Only ATOMIC_HASH_SIZE is used */]
+ __attribute__((aligned(PAGE_SIZE), section(".bss.page_aligned")));
+
+#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+static inline int *__atomic_hashed_lock(volatile void *v)
+{
+ /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec.S */
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ unsigned long i =
+ (unsigned long) v & ((PAGE_SIZE-1) & -sizeof(long long));
+ unsigned long n = __insn_crc32_32(0, i);
+
+ /* Grab high bits for L1 index. */
+ unsigned long l1_index = n >> ((sizeof(n) * 8) - ATOMIC_HASH_L1_SHIFT);
+ /* Grab low bits for L2 index. */
+ unsigned long l2_index = n & (ATOMIC_HASH_L2_SIZE - 1);
+
+ return &atomic_lock_ptr[l1_index]->lock[l2_index];
+#else
+ /*
+ * Use bits [3, 3 + ATOMIC_HASH_SHIFT) as the lock index.
+ * Using mm works here because atomic_locks is page aligned.
+ */
+ unsigned long ptr = __insn_mm((unsigned long)v >> 1,
+ (unsigned long)atomic_locks,
+ 2, (ATOMIC_HASH_SHIFT + 2) - 1);
+ return (int *)ptr;
+#endif
+}
+
+#ifdef CONFIG_SMP
+/* Return whether the passed pointer is a valid atomic lock pointer. */
+static int is_atomic_lock(int *p)
+{
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ int i;
+ for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) {
+
+ if (p >= &atomic_lock_ptr[i]->lock[0] &&
+ p < &atomic_lock_ptr[i]->lock[ATOMIC_HASH_L2_SIZE]) {
+ return 1;
+ }
+ }
+ return 0;
+#else
+ return p >= &atomic_locks[0] && p < &atomic_locks[ATOMIC_HASH_SIZE];
+#endif
+}
+
+void __atomic_fault_unlock(int *irqlock_word)
+{
+ BUG_ON(!is_atomic_lock(irqlock_word));
+ BUG_ON(*irqlock_word != 1);
+ *irqlock_word = 0;
+}
+
+#endif /* CONFIG_SMP */
+
+static inline int *__atomic_setup(volatile void *v)
+{
+ /* Issue a load to the target to bring it into cache. */
+ *(volatile int *)v;
+ return __atomic_hashed_lock(v);
+}
+
+int _atomic_xchg(atomic_t *v, int n)
+{
+ return __atomic_xchg(&v->counter, __atomic_setup(v), n).val;
+}
+EXPORT_SYMBOL(_atomic_xchg);
+
+int _atomic_xchg_add(atomic_t *v, int i)
+{
+ return __atomic_xchg_add(&v->counter, __atomic_setup(v), i).val;
+}
+EXPORT_SYMBOL(_atomic_xchg_add);
+
+int _atomic_xchg_add_unless(atomic_t *v, int a, int u)
+{
+ /*
+ * Note: argument order is switched here since it is easier
+ * to use the first argument consistently as the "old value"
+ * in the assembly, as is done for _atomic_cmpxchg().
+ */
+ return __atomic_xchg_add_unless(&v->counter, __atomic_setup(v), u, a)
+ .val;
+}
+EXPORT_SYMBOL(_atomic_xchg_add_unless);
+
+int _atomic_cmpxchg(atomic_t *v, int o, int n)
+{
+ return __atomic_cmpxchg(&v->counter, __atomic_setup(v), o, n).val;
+}
+EXPORT_SYMBOL(_atomic_cmpxchg);
+
+unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask)
+{
+ return __atomic_or((int *)p, __atomic_setup(p), mask).val;
+}
+EXPORT_SYMBOL(_atomic_or);
+
+unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask)
+{
+ return __atomic_andn((int *)p, __atomic_setup(p), mask).val;
+}
+EXPORT_SYMBOL(_atomic_andn);
+
+unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask)
+{
+ return __atomic_xor((int *)p, __atomic_setup(p), mask).val;
+}
+EXPORT_SYMBOL(_atomic_xor);
+
+
+u64 _atomic64_xchg(atomic64_t *v, u64 n)
+{
+ return __atomic64_xchg(&v->counter, __atomic_setup(v), n);
+}
+EXPORT_SYMBOL(_atomic64_xchg);
+
+u64 _atomic64_xchg_add(atomic64_t *v, u64 i)
+{
+ return __atomic64_xchg_add(&v->counter, __atomic_setup(v), i);
+}
+EXPORT_SYMBOL(_atomic64_xchg_add);
+
+u64 _atomic64_xchg_add_unless(atomic64_t *v, u64 a, u64 u)
+{
+ /*
+ * Note: argument order is switched here since it is easier
+ * to use the first argument consistently as the "old value"
+ * in the assembly, as is done for _atomic_cmpxchg().
+ */
+ return __atomic64_xchg_add_unless(&v->counter, __atomic_setup(v),
+ u, a);
+}
+EXPORT_SYMBOL(_atomic64_xchg_add_unless);
+
+u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n)
+{
+ return __atomic64_cmpxchg(&v->counter, __atomic_setup(v), o, n);
+}
+EXPORT_SYMBOL(_atomic64_cmpxchg);
+
+
+static inline int *__futex_setup(__user int *v)
+{
+ /*
+ * Issue a prefetch to the counter to bring it into cache.
+ * As for __atomic_setup, but we can't do a read into the L1
+ * since it might fault; instead we do a prefetch into the L2.
+ */
+ __insn_prefetch(v);
+ return __atomic_hashed_lock(v);
+}
+
+struct __get_user futex_set(int *v, int i)
+{
+ return __atomic_xchg(v, __futex_setup(v), i);
+}
+
+struct __get_user futex_add(int *v, int n)
+{
+ return __atomic_xchg_add(v, __futex_setup(v), n);
+}
+
+struct __get_user futex_or(int *v, int n)
+{
+ return __atomic_or(v, __futex_setup(v), n);
+}
+
+struct __get_user futex_andn(int *v, int n)
+{
+ return __atomic_andn(v, __futex_setup(v), n);
+}
+
+struct __get_user futex_xor(int *v, int n)
+{
+ return __atomic_xor(v, __futex_setup(v), n);
+}
+
+struct __get_user futex_cmpxchg(int *v, int o, int n)
+{
+ return __atomic_cmpxchg(v, __futex_setup(v), o, n);
+}
+
+/*
+ * If any of the atomic or futex routines hit a bad address (not in
+ * the page tables at kernel PL) this routine is called. The futex
+ * routines are never used on kernel space, and the normal atomics and
+ * bitops are never used on user space. So a fault on kernel space
+ * must be fatal, but a fault on userspace is a futex fault and we
+ * need to return -EFAULT. Note that the context this routine is
+ * invoked in is the context of the "_atomic_xxx()" routines called
+ * by the functions in this file.
+ */
+struct __get_user __atomic_bad_address(int *addr)
+{
+ if (unlikely(!access_ok(VERIFY_WRITE, addr, sizeof(int))))
+ panic("Bad address used for kernel atomic op: %p\n", addr);
+ return (struct __get_user) { .err = -EFAULT };
+}
+
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+static int __init noatomichash(char *str)
+{
+ printk("noatomichash is deprecated.\n");
+ return 1;
+}
+__setup("noatomichash", noatomichash);
+#endif
+
+void __init __init_atomic_per_cpu(void)
+{
+#if ATOMIC_LOCKS_FOUND_VIA_TABLE()
+
+ unsigned int i;
+ int actual_cpu;
+
+ /*
+ * Before this is called from setup, we just have one lock for
+ * all atomic objects/operations. Here we replace the
+ * elements of atomic_lock_ptr so that they point at per_cpu
+ * integers. This seemingly over-complex approach stems from
+ * the fact that DEFINE_PER_CPU defines an entry for each cpu
+ * in the grid, not each cpu from 0..ATOMIC_HASH_SIZE-1. But
+ * for efficient hashing of atomics to their locks we want a
+ * compile time constant power of 2 for the size of this
+ * table, so we use ATOMIC_HASH_SIZE.
+ *
+ * Here we populate atomic_lock_ptr from the per cpu
+ * atomic_lock_pool, interspersing by actual cpu so that
+ * subsequent elements are homed on consecutive cpus.
+ */
+
+ actual_cpu = cpumask_first(cpu_possible_mask);
+
+ for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) {
+ /*
+ * Preincrement to slightly bias against using cpu 0,
+ * which has plenty of stuff homed on it already.
+ */
+ actual_cpu = cpumask_next(actual_cpu, cpu_possible_mask);
+ if (actual_cpu >= nr_cpu_ids)
+ actual_cpu = cpumask_first(cpu_possible_mask);
+
+ atomic_lock_ptr[i] = &per_cpu(atomic_lock_pool, actual_cpu);
+ }
+
+#else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+ /* Validate power-of-two and "bigger than cpus" assumption */
+ BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1));
+ BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids);
+
+ /*
+ * On TILEPro we prefer to use a single hash-for-home
+ * page, since this means atomic operations are less
+ * likely to encounter a TLB fault and thus should
+ * in general perform faster. You may wish to disable
+ * this in situations where few hash-for-home tiles
+ * are configured.
+ */
+ BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0);
+
+ /* The locks must all fit on one page. */
+ BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE);
+
+ /*
+ * We use the page offset of the atomic value's address as
+ * an index into atomic_locks, excluding the low 3 bits.
+ * That should not produce more indices than ATOMIC_HASH_SIZE.
+ */
+ BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE);
+
+#endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
+
+ /* The futex code makes this assumption, so we validate it here. */
+ BUG_ON(sizeof(atomic_t) != sizeof(int));
+}
diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S
new file mode 100644
index 000000000000..c0d058578192
--- /dev/null
+++ b/arch/tile/lib/atomic_asm_32.S
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Support routines for atomic operations. Each function takes:
+ *
+ * r0: address to manipulate
+ * r1: pointer to atomic lock guarding this operation (for FUTEX_LOCK_REG)
+ * r2: new value to write, or for cmpxchg/add_unless, value to compare against
+ * r3: (cmpxchg/xchg_add_unless) new value to write or add;
+ * (atomic64 ops) high word of value to write
+ * r4/r5: (cmpxchg64/add_unless64) new value to write or add
+ *
+ * The 32-bit routines return a "struct __get_user" so that the futex code
+ * has an opportunity to return -EFAULT to the user if needed.
+ * The 64-bit routines just return a "long long" with the value,
+ * since they are only used from kernel space and don't expect to fault.
+ * Support for 16-bit ops is included in the framework but we don't provide
+ * any (x86_64 has an atomic_inc_short(), so we might want to some day).
+ *
+ * Note that the caller is advised to issue a suitable L1 or L2
+ * prefetch on the address being manipulated to avoid extra stalls.
+ * In addition, the hot path is on two icache lines, and we start with
+ * a jump to the second line to make sure they are both in cache so
+ * that we never stall waiting on icache fill while holding the lock.
+ * (This doesn't work out with most 64-bit ops, since they consume
+ * too many bundles, so may take an extra i-cache stall.)
+ *
+ * These routines set the INTERRUPT_CRITICAL_SECTION bit, just
+ * like sys_cmpxchg(), so that NMIs like PERF_COUNT will not interrupt
+ * the code, just page faults.
+ *
+ * If the load or store faults in a way that can be directly fixed in
+ * the do_page_fault_ics() handler (e.g. a vmalloc reference) we fix it
+ * directly, return to the instruction that faulted, and retry it.
+ *
+ * If the load or store faults in a way that potentially requires us
+ * to release the atomic lock, then retry (e.g. a migrating PTE), we
+ * reset the PC in do_page_fault_ics() to the "tns" instruction so
+ * that on return we will reacquire the lock and restart the op. We
+ * are somewhat overloading the exception_table_entry notion by doing
+ * this, since those entries are not normally used for migrating PTEs.
+ *
+ * If the main page fault handler discovers a bad address, it will see
+ * the PC pointing to the "tns" instruction (due to the earlier
+ * exception_table_entry processing in do_page_fault_ics), and
+ * re-reset the PC to the fault handler, atomic_bad_address(), which
+ * effectively takes over from the atomic op and can either return a
+ * bad "struct __get_user" (for user addresses) or can just panic (for
+ * bad kernel addresses).
+ *
+ * Note that if the value we would store is the same as what we
+ * loaded, we bypass the load. Other platforms with true atomics can
+ * make the guarantee that a non-atomic __clear_bit(), for example,
+ * can safely race with an atomic test_and_set_bit(); this example is
+ * from bit_spinlock.h in slub_lock() / slub_unlock(). We can't do
+ * that on Tile since the "atomic" op is really just a
+ * read/modify/write, and can race with the non-atomic
+ * read/modify/write. However, if we can short-circuit the write when
+ * it is not needed, in the atomic case, we avoid the race.
+ */
+
+#include <linux/linkage.h>
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+
+ .section .text.atomic,"ax"
+ENTRY(__start_atomic_asm_code)
+
+ .macro atomic_op, name, bitwidth, body
+ .align 64
+STD_ENTRY_SECTION(__atomic\name, .text.atomic)
+ {
+ movei r24, 1
+ j 4f /* branch to second cache line */
+ }
+1: {
+ .ifc \bitwidth,16
+ lh r22, r0
+ .else
+ lw r22, r0
+ addi r23, r0, 4
+ .endif
+ }
+ .ifc \bitwidth,64
+ lw r23, r23
+ .endif
+ \body /* set r24, and r25 if 64-bit */
+ {
+ seq r26, r22, r24
+ seq r27, r23, r25
+ }
+ .ifc \bitwidth,64
+ bbnst r27, 2f
+ .endif
+ bbs r26, 3f /* skip write-back if it's the same value */
+2: {
+ .ifc \bitwidth,16
+ sh r0, r24
+ .else
+ sw r0, r24
+ addi r23, r0, 4
+ .endif
+ }
+ .ifc \bitwidth,64
+ sw r23, r25
+ .endif
+ mf
+3: {
+ move r0, r22
+ .ifc \bitwidth,64
+ move r1, r23
+ .else
+ move r1, zero
+ .endif
+ sw ATOMIC_LOCK_REG_NAME, zero
+ }
+ mtspr INTERRUPT_CRITICAL_SECTION, zero
+ jrp lr
+4: {
+ move ATOMIC_LOCK_REG_NAME, r1
+ mtspr INTERRUPT_CRITICAL_SECTION, r24
+ }
+#ifndef CONFIG_SMP
+ j 1b /* no atomic locks */
+#else
+ {
+ tns r21, ATOMIC_LOCK_REG_NAME
+ moveli r23, 2048 /* maximum backoff time in cycles */
+ }
+ {
+ bzt r21, 1b /* branch if lock acquired */
+ moveli r25, 32 /* starting backoff time in cycles */
+ }
+5: mtspr INTERRUPT_CRITICAL_SECTION, zero
+ mfspr r26, CYCLE_LOW /* get start point for this backoff */
+6: mfspr r22, CYCLE_LOW /* test to see if we've backed off enough */
+ sub r22, r22, r26
+ slt r22, r22, r25
+ bbst r22, 6b
+ {
+ mtspr INTERRUPT_CRITICAL_SECTION, r24
+ shli r25, r25, 1 /* double the backoff; retry the tns */
+ }
+ {
+ tns r21, ATOMIC_LOCK_REG_NAME
+ slt r26, r23, r25 /* is the proposed backoff too big? */
+ }
+ {
+ bzt r21, 1b /* branch if lock acquired */
+ mvnz r25, r26, r23
+ }
+ j 5b
+#endif
+ STD_ENDPROC(__atomic\name)
+ .ifc \bitwidth,32
+ .pushsection __ex_table,"a"
+ .word 1b, __atomic\name
+ .word 2b, __atomic\name
+ .word __atomic\name, __atomic_bad_address
+ .popsection
+ .endif
+ .endm
+
+atomic_op _cmpxchg, 32, "seq r26, r22, r2; { bbns r26, 3f; move r24, r3 }"
+atomic_op _xchg, 32, "move r24, r2"
+atomic_op _xchg_add, 32, "add r24, r22, r2"
+atomic_op _xchg_add_unless, 32, \
+ "sne r26, r22, r2; { bbns r26, 3f; add r24, r22, r3 }"
+atomic_op _or, 32, "or r24, r22, r2"
+atomic_op _andn, 32, "nor r2, r2, zero; and r24, r22, r2"
+atomic_op _xor, 32, "xor r24, r22, r2"
+
+atomic_op 64_cmpxchg, 64, "{ seq r26, r22, r2; seq r27, r23, r3 }; \
+ { bbns r26, 3f; move r24, r4 }; { bbns r27, 3f; move r25, r5 }"
+atomic_op 64_xchg, 64, "{ move r24, r2; move r25, r3 }"
+atomic_op 64_xchg_add, 64, "{ add r24, r22, r2; add r25, r23, r3 }; \
+ slt_u r26, r24, r22; add r25, r25, r26"
+atomic_op 64_xchg_add_unless, 64, \
+ "{ sne r26, r22, r2; sne r27, r23, r3 }; \
+ { bbns r26, 3f; add r24, r22, r4 }; \
+ { bbns r27, 3f; add r25, r23, r5 }; \
+ slt_u r26, r24, r22; add r25, r25, r26"
+
+ jrp lr /* happy backtracer */
+
+ENTRY(__end_atomic_asm_code)
diff --git a/arch/tile/lib/checksum.c b/arch/tile/lib/checksum.c
new file mode 100644
index 000000000000..e4bab5bd3f31
--- /dev/null
+++ b/arch/tile/lib/checksum.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * Support code for the main lib/checksum.c.
+ */
+
+#include <net/checksum.h>
+#include <linux/module.h>
+
+static inline unsigned int longto16(unsigned long x)
+{
+ unsigned long ret;
+#ifdef __tilegx__
+ ret = __insn_v2sadu(x, 0);
+ ret = __insn_v2sadu(ret, 0);
+#else
+ ret = __insn_sadh_u(x, 0);
+ ret = __insn_sadh_u(ret, 0);
+#endif
+ return ret;
+}
+
+__wsum do_csum(const unsigned char *buff, int len)
+{
+ int odd, count;
+ unsigned long result = 0;
+
+ if (len <= 0)
+ goto out;
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+ result = (*buff << 8);
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(const unsigned short *)buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+#ifdef __tilegx__
+ if (4 & (unsigned long) buff) {
+ unsigned int w = *(const unsigned int *)buff;
+ result = __insn_v2sadau(result, w, 0);
+ count--;
+ len -= 4;
+ buff += 4;
+ }
+ count >>= 1; /* nr of 64-bit words.. */
+#endif
+
+ /*
+ * This algorithm could wrap around for very
+ * large buffers, but those should be impossible.
+ */
+ BUG_ON(count >= 65530);
+
+ while (count) {
+ unsigned long w = *(const unsigned long *)buff;
+ count--;
+ buff += sizeof(w);
+#ifdef __tilegx__
+ result = __insn_v2sadau(result, w, 0);
+#else
+ result = __insn_sadah_u(result, w, 0);
+#endif
+ }
+#ifdef __tilegx__
+ if (len & 4) {
+ unsigned int w = *(const unsigned int *)buff;
+ result = __insn_v2sadau(result, w, 0);
+ buff += 4;
+ }
+#endif
+ }
+ if (len & 2) {
+ result += *(const unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+ result += *buff;
+ result = longto16(result);
+ if (odd)
+ result = swab16(result);
+out:
+ return result;
+}
diff --git a/arch/tile/lib/cpumask.c b/arch/tile/lib/cpumask.c
new file mode 100644
index 000000000000..af745b3b2559
--- /dev/null
+++ b/arch/tile/lib/cpumask.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/cpumask.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+
+/*
+ * Allow cropping out bits beyond the end of the array.
+ * Move to "lib" directory if more clients want to use this routine.
+ */
+int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits)
+{
+ unsigned a, b;
+
+ bitmap_zero(maskp, nmaskbits);
+ do {
+ if (!isdigit(*bp))
+ return -EINVAL;
+ a = simple_strtoul(bp, (char **)&bp, 10);
+ b = a;
+ if (*bp == '-') {
+ bp++;
+ if (!isdigit(*bp))
+ return -EINVAL;
+ b = simple_strtoul(bp, (char **)&bp, 10);
+ }
+ if (!(a <= b))
+ return -EINVAL;
+ if (b >= nmaskbits)
+ b = nmaskbits-1;
+ while (a <= b) {
+ set_bit(a, maskp);
+ a++;
+ }
+ if (*bp == ',')
+ bp++;
+ } while (*bp != '\0' && *bp != '\n');
+ return 0;
+}
diff --git a/arch/tile/lib/delay.c b/arch/tile/lib/delay.c
new file mode 100644
index 000000000000..5801b03c13ef
--- /dev/null
+++ b/arch/tile/lib/delay.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/thread_info.h>
+#include <asm/fixmap.h>
+#include <hv/hypervisor.h>
+
+void __udelay(unsigned long usecs)
+{
+ hv_nanosleep(usecs * 1000);
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned long nsecs)
+{
+ hv_nanosleep(nsecs);
+}
+EXPORT_SYMBOL(__ndelay);
+
+/* FIXME: should be declared in a header somewhere. */
+EXPORT_SYMBOL(__delay);
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c
new file mode 100644
index 000000000000..af8e70e2a0ce
--- /dev/null
+++ b/arch/tile/lib/exports.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Exports from assembler code and from libtile-cc.
+ */
+
+#include <linux/module.h>
+
+/* arch/tile/lib/usercopy.S */
+#include <linux/uaccess.h>
+EXPORT_SYMBOL(__get_user_1);
+EXPORT_SYMBOL(__get_user_2);
+EXPORT_SYMBOL(__get_user_4);
+EXPORT_SYMBOL(__put_user_1);
+EXPORT_SYMBOL(__put_user_2);
+EXPORT_SYMBOL(__put_user_4);
+EXPORT_SYMBOL(__put_user_8);
+EXPORT_SYMBOL(strnlen_user_asm);
+EXPORT_SYMBOL(strncpy_from_user_asm);
+EXPORT_SYMBOL(clear_user_asm);
+
+/* arch/tile/kernel/entry.S */
+#include <linux/kernel.h>
+#include <asm/processor.h>
+EXPORT_SYMBOL(current_text_addr);
+EXPORT_SYMBOL(dump_stack);
+
+/* arch/tile/lib/__memcpy.S */
+/* NOTE: on TILE64, these symbols appear in arch/tile/lib/memcpy_tile64.c */
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(__copy_to_user_inatomic);
+EXPORT_SYMBOL(__copy_from_user_inatomic);
+EXPORT_SYMBOL(__copy_from_user_zeroing);
+
+/* hypervisor glue */
+#include <hv/hypervisor.h>
+EXPORT_SYMBOL(hv_dev_open);
+EXPORT_SYMBOL(hv_dev_pread);
+EXPORT_SYMBOL(hv_dev_pwrite);
+EXPORT_SYMBOL(hv_dev_close);
+
+/* -ltile-cc */
+uint32_t __udivsi3(uint32_t dividend, uint32_t divisor);
+EXPORT_SYMBOL(__udivsi3);
+int32_t __divsi3(int32_t dividend, int32_t divisor);
+EXPORT_SYMBOL(__divsi3);
+uint64_t __udivdi3(uint64_t dividend, uint64_t divisor);
+EXPORT_SYMBOL(__udivdi3);
+int64_t __divdi3(int64_t dividend, int64_t divisor);
+EXPORT_SYMBOL(__divdi3);
+uint32_t __umodsi3(uint32_t dividend, uint32_t divisor);
+EXPORT_SYMBOL(__umodsi3);
+int32_t __modsi3(int32_t dividend, int32_t divisor);
+EXPORT_SYMBOL(__modsi3);
+uint64_t __umoddi3(uint64_t dividend, uint64_t divisor);
+EXPORT_SYMBOL(__umoddi3);
+int64_t __moddi3(int64_t dividend, int64_t divisor);
+EXPORT_SYMBOL(__moddi3);
+#ifndef __tilegx__
+uint64_t __ll_mul(uint64_t n0, uint64_t n1);
+EXPORT_SYMBOL(__ll_mul);
+#endif
+#ifndef __tilegx__
+int64_t __muldi3(int64_t, int64_t);
+EXPORT_SYMBOL(__muldi3);
+uint64_t __lshrdi3(uint64_t, unsigned int);
+EXPORT_SYMBOL(__lshrdi3);
+#endif
diff --git a/arch/tile/lib/mb_incoherent.S b/arch/tile/lib/mb_incoherent.S
new file mode 100644
index 000000000000..989ad7b68d5a
--- /dev/null
+++ b/arch/tile/lib/mb_incoherent.S
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Assembly code for invoking the HV's fence_incoherent syscall.
+ */
+
+#include <linux/linkage.h>
+#include <hv/syscall_public.h>
+#include <arch/abi.h>
+#include <arch/chip.h>
+
+#if !CHIP_HAS_MF_WAITS_FOR_VICTIMS()
+
+/*
+ * Invoke the hypervisor's fence_incoherent syscall, which guarantees
+ * that all victims for cachelines homed on this tile have reached memory.
+ */
+STD_ENTRY(__mb_incoherent)
+ moveli TREG_SYSCALL_NR_NAME, HV_SYS_fence_incoherent
+ swint2
+ jrp lr
+ STD_ENDPROC(__mb_incoherent)
+
+#endif
diff --git a/arch/tile/lib/memchr_32.c b/arch/tile/lib/memchr_32.c
new file mode 100644
index 000000000000..6235283b4859
--- /dev/null
+++ b/arch/tile/lib/memchr_32.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memchr(const void *s, int c, size_t n)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *)(s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first word, but munge it so that bytes before the array
+ * will not match goal.
+ *
+ * Note that this shift count expression works because we know
+ * shift counts are taken mod 32.
+ */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & before_mask);
+
+ /* Compute the address of the last byte. */
+ const char *const last_byte_ptr = (const char *)s + n - 1;
+
+ /* Compute the address of the word containing the last byte. */
+ const uint32_t *const last_word_ptr =
+ (const uint32_t *)((uintptr_t) last_byte_ptr & -4);
+
+ uint32_t bits;
+ char *ret;
+
+ if (__builtin_expect(n == 0, 0)) {
+ /* Don't dereference any memory if the array is empty. */
+ return NULL;
+ }
+
+ while ((bits = __insn_seqb(v, goal)) == 0) {
+ if (__builtin_expect(p == last_word_ptr, 0)) {
+ /* We already read the last word in the array,
+ * so give up.
+ */
+ return NULL;
+ }
+ v = *++p;
+ }
+
+ /* We found a match, but it might be in a byte past the end
+ * of the array.
+ */
+ ret = ((char *)p) + (__insn_ctz(bits) >> 3);
+ return (ret <= last_byte_ptr) ? ret : NULL;
+}
+EXPORT_SYMBOL(memchr);
diff --git a/arch/tile/lib/memcpy_32.S b/arch/tile/lib/memcpy_32.S
new file mode 100644
index 000000000000..f92984bf60ec
--- /dev/null
+++ b/arch/tile/lib/memcpy_32.S
@@ -0,0 +1,628 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This file shares the implementation of the userspace memcpy and
+ * the kernel's memcpy, copy_to_user and copy_from_user.
+ */
+
+#include <arch/chip.h>
+
+#if CHIP_HAS_WH64() || defined(MEMCPY_TEST_WH64)
+#define MEMCPY_USE_WH64
+#endif
+
+
+#include <linux/linkage.h>
+
+/* On TILE64, we wrap these functions via arch/tile/lib/memcpy_tile64.c */
+#if !CHIP_HAS_COHERENT_LOCAL_CACHE()
+#define memcpy __memcpy_asm
+#define __copy_to_user_inatomic __copy_to_user_inatomic_asm
+#define __copy_from_user_inatomic __copy_from_user_inatomic_asm
+#define __copy_from_user_zeroing __copy_from_user_zeroing_asm
+#endif
+
+#define IS_MEMCPY 0
+#define IS_COPY_FROM_USER 1
+#define IS_COPY_FROM_USER_ZEROING 2
+#define IS_COPY_TO_USER -1
+
+ .section .text.memcpy_common, "ax"
+ .align 64
+
+/* Use this to preface each bundle that can cause an exception so
+ * the kernel can clean up properly. The special cleanup code should
+ * not use these, since it knows what it is doing.
+ */
+#define EX \
+ .pushsection __ex_table, "a"; \
+ .word 9f, memcpy_common_fixup; \
+ .popsection; \
+ 9
+
+
+/* __copy_from_user_inatomic takes the kernel target address in r0,
+ * the user source in r1, and the bytes to copy in r2.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ */
+ENTRY(__copy_from_user_inatomic)
+.type __copy_from_user_inatomic, @function
+ FEEDBACK_ENTER_EXPLICIT(__copy_from_user_inatomic, \
+ .text.memcpy_common, \
+ .Lend_memcpy_common - __copy_from_user_inatomic)
+ { movei r29, IS_COPY_FROM_USER; j memcpy_common }
+ .size __copy_from_user_inatomic, . - __copy_from_user_inatomic
+
+/* __copy_from_user_zeroing is like __copy_from_user_inatomic, but
+ * any uncopiable bytes are zeroed in the target.
+ */
+ENTRY(__copy_from_user_zeroing)
+.type __copy_from_user_zeroing, @function
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
+ { movei r29, IS_COPY_FROM_USER_ZEROING; j memcpy_common }
+ .size __copy_from_user_zeroing, . - __copy_from_user_zeroing
+
+/* __copy_to_user_inatomic takes the user target address in r0,
+ * the kernel source in r1, and the bytes to copy in r2.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ */
+ENTRY(__copy_to_user_inatomic)
+.type __copy_to_user_inatomic, @function
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
+ { movei r29, IS_COPY_TO_USER; j memcpy_common }
+ .size __copy_to_user_inatomic, . - __copy_to_user_inatomic
+
+ENTRY(memcpy)
+.type memcpy, @function
+ FEEDBACK_REENTER(__copy_from_user_inatomic)
+ { movei r29, IS_MEMCPY }
+ .size memcpy, . - memcpy
+ /* Fall through */
+
+ .type memcpy_common, @function
+memcpy_common:
+ /* On entry, r29 holds one of the IS_* macro values from above. */
+
+
+ /* r0 is the dest, r1 is the source, r2 is the size. */
+
+ /* Save aside original dest so we can return it at the end. */
+ { sw sp, lr; move r23, r0; or r4, r0, r1 }
+
+ /* Check for an empty size. */
+ { bz r2, .Ldone; andi r4, r4, 3 }
+
+ /* Save aside original values in case of a fault. */
+ { move r24, r1; move r25, r2 }
+ move r27, lr
+
+ /* Check for an unaligned source or dest. */
+ { bnz r4, .Lcopy_unaligned_maybe_many; addli r4, r2, -256 }
+
+.Lcheck_aligned_copy_size:
+ /* If we are copying < 256 bytes, branch to simple case. */
+ { blzt r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+
+ /* Copying >= 256 bytes, so jump to complex prefetching loop. */
+ { andi r6, r1, 63; j .Lcopy_many }
+
+/*
+ *
+ * Aligned 4 byte at a time copy loop
+ *
+ */
+
+.Lcopy_8_loop:
+ /* Copy two words at a time to hide load latency. */
+EX: { lw r3, r1; addi r1, r1, 4; slti_u r8, r2, 16 }
+EX: { lw r4, r1; addi r1, r1, 4 }
+EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+EX: { sw r0, r4; addi r0, r0, 4; addi r2, r2, -4 }
+.Lcopy_8_check:
+ { bzt r8, .Lcopy_8_loop; slti_u r4, r2, 4 }
+
+ /* Copy odd leftover word, if any. */
+ { bnzt r4, .Lcheck_odd_stragglers }
+EX: { lw r3, r1; addi r1, r1, 4 }
+EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+
+.Lcheck_odd_stragglers:
+ { bnz r2, .Lcopy_unaligned_few }
+
+.Ldone:
+ /* For memcpy return original dest address, else zero. */
+ { mz r0, r29, r23; jrp lr }
+
+
+/*
+ *
+ * Prefetching multiple cache line copy handler (for large transfers).
+ *
+ */
+
+ /* Copy words until r1 is cache-line-aligned. */
+.Lalign_loop:
+EX: { lw r3, r1; addi r1, r1, 4 }
+ { andi r6, r1, 63 }
+EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 }
+.Lcopy_many:
+ { bnzt r6, .Lalign_loop; addi r9, r0, 63 }
+
+ { addi r3, r1, 60; andi r9, r9, -64 }
+
+#ifdef MEMCPY_USE_WH64
+ /* No need to prefetch dst, we'll just do the wh64
+ * right before we copy a line.
+ */
+#endif
+
+EX: { lw r5, r3; addi r3, r3, 64; movei r4, 1 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, .; move r27, lr }
+EX: { lw r6, r3; addi r3, r3, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+EX: { lw r7, r3; addi r3, r3, 64 }
+#ifndef MEMCPY_USE_WH64
+ /* Prefetch the dest */
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ /* Use a real load to cause a TLB miss if necessary. We aren't using
+ * r28, so this should be fine.
+ */
+EX: { lw r28, r9; addi r9, r9, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ { prefetch r9; addi r9, r9, 64 }
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bnzt zero, . }
+ { prefetch r9; addi r9, r9, 64 }
+#endif
+ /* Intentionally stall for a few cycles to leave L2 cache alone. */
+ { bz zero, .Lbig_loop2 }
+
+ /* On entry to this loop:
+ * - r0 points to the start of dst line 0
+ * - r1 points to start of src line 0
+ * - r2 >= (256 - 60), only the first time the loop trips.
+ * - r3 contains r1 + 128 + 60 [pointer to end of source line 2]
+ * This is our prefetch address. When we get near the end
+ * rather than prefetching off the end this is changed to point
+ * to some "safe" recently loaded address.
+ * - r5 contains *(r1 + 60) [i.e. last word of source line 0]
+ * - r6 contains *(r1 + 64 + 60) [i.e. last word of source line 1]
+ * - r9 contains ((r0 + 63) & -64)
+ * [start of next dst cache line.]
+ */
+
+.Lbig_loop:
+ { jal .Lcopy_line2; add r15, r1, r2 }
+
+.Lbig_loop2:
+ /* Copy line 0, first stalling until r5 is ready. */
+EX: { move r12, r5; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+EX: { lw r5, r3; addi r3, r3, 64 }
+ { jal .Lcopy_line }
+
+ /* Copy line 1, first stalling until r6 is ready. */
+EX: { move r12, r6; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+EX: { lw r6, r3; addi r3, r3, 64 }
+ { jal .Lcopy_line }
+
+ /* Copy line 2, first stalling until r7 is ready. */
+EX: { move r12, r7; lw r16, r1 }
+ { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 }
+ /* Prefetch several lines ahead. */
+EX: { lw r7, r3; addi r3, r3, 64 }
+ /* Use up a caches-busy cycle by jumping back to the top of the
+ * loop. Might as well get it out of the way now.
+ */
+ { j .Lbig_loop }
+
+
+ /* On entry:
+ * - r0 points to the destination line.
+ * - r1 points to the source line.
+ * - r3 is the next prefetch address.
+ * - r9 holds the last address used for wh64.
+ * - r12 = WORD_15
+ * - r16 = WORD_0.
+ * - r17 == r1 + 16.
+ * - r27 holds saved lr to restore.
+ *
+ * On exit:
+ * - r0 is incremented by 64.
+ * - r1 is incremented by 64, unless that would point to a word
+ * beyond the end of the source array, in which case it is redirected
+ * to point to an arbitrary word already in the cache.
+ * - r2 is decremented by 64.
+ * - r3 is unchanged, unless it points to a word beyond the
+ * end of the source array, in which case it is redirected
+ * to point to an arbitrary word already in the cache.
+ * Redirecting is OK since if we are that close to the end
+ * of the array we will not come back to this subroutine
+ * and use the contents of the prefetched address.
+ * - r4 is nonzero iff r2 >= 64.
+ * - r9 is incremented by 64, unless it points beyond the
+ * end of the last full destination cache line, in which
+ * case it is redirected to a "safe address" that can be
+ * clobbered (sp - 64)
+ * - lr contains the value in r27.
+ */
+
+/* r26 unused */
+
+.Lcopy_line:
+ /* TODO: when r3 goes past the end, we would like to redirect it
+ * to prefetch the last partial cache line (if any) just once, for the
+ * benefit of the final cleanup loop. But we don't want to
+ * prefetch that line more than once, or subsequent prefetches
+ * will go into the RTF. But then .Lbig_loop should unconditionally
+ * branch to top of loop to execute final prefetch, and its
+ * nop should become a conditional branch.
+ */
+
+ /* We need two non-memory cycles here to cover the resources
+ * used by the loads initiated by the caller.
+ */
+ { add r15, r1, r2 }
+.Lcopy_line2:
+ { slt_u r13, r3, r15; addi r17, r1, 16 }
+
+ /* NOTE: this will stall for one cycle as L1 is busy. */
+
+ /* Fill second L1D line. */
+EX: { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */
+
+#ifdef MEMCPY_TEST_WH64
+ /* Issue a fake wh64 that clobbers the destination words
+ * with random garbage, for testing.
+ */
+ { movei r19, 64; crc32_32 r10, r2, r9 }
+.Lwh64_test_loop:
+EX: { sw r9, r10; addi r9, r9, 4; addi r19, r19, -4 }
+ { bnzt r19, .Lwh64_test_loop; crc32_32 r10, r10, r19 }
+#elif CHIP_HAS_WH64()
+ /* Prepare destination line for writing. */
+EX: { wh64 r9; addi r9, r9, 64 }
+#else
+ /* Prefetch dest line */
+ { prefetch r9; addi r9, r9, 64 }
+#endif
+ /* Load seven words that are L1D hits to cover wh64 L2 usage. */
+
+ /* Load the three remaining words from the last L1D line, which
+ * we know has already filled the L1D.
+ */
+EX: { lw r4, r1; addi r1, r1, 4; addi r20, r1, 16 } /* r4 = WORD_12 */
+EX: { lw r8, r1; addi r1, r1, 4; slt_u r13, r20, r15 }/* r8 = WORD_13 */
+EX: { lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 } /* r11 = WORD_14 */
+
+ /* Load the three remaining words from the first L1D line, first
+ * stalling until it has filled by "looking at" r16.
+ */
+EX: { lw r13, r1; addi r1, r1, 4; move zero, r16 } /* r13 = WORD_1 */
+EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_2 */
+EX: { lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */
+
+ /* Load second word from the second L1D line, first
+ * stalling until it has filled by "looking at" r17.
+ */
+EX: { lw r19, r1; addi r1, r1, 4; move zero, r17 } /* r19 = WORD_5 */
+
+ /* Store last word to the destination line, potentially dirtying it
+ * for the first time, which keeps the L2 busy for two cycles.
+ */
+EX: { sw r10, r12 } /* store(WORD_15) */
+
+ /* Use two L1D hits to cover the sw L2 access above. */
+EX: { lw r10, r1; addi r1, r1, 4 } /* r10 = WORD_6 */
+EX: { lw r12, r1; addi r1, r1, 4 } /* r12 = WORD_7 */
+
+ /* Fill third L1D line. */
+EX: { lw r18, r1; addi r1, r1, 4 } /* r18 = WORD_8 */
+
+ /* Store first L1D line. */
+EX: { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */
+EX: { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */
+EX: { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */
+#ifdef MEMCPY_USE_WH64
+EX: { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */
+#else
+ /* Back up the r9 to a cache line we are already storing to
+ * if it gets past the end of the dest vector. Strictly speaking,
+ * we don't need to back up to the start of a cache line, but it's free
+ * and tidy, so why not?
+ */
+EX: { sw r0, r15; addi r0, r0, 4; andi r13, r0, -64 } /* store(WORD_3) */
+#endif
+ /* Store second L1D line. */
+EX: { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */
+EX: { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */
+EX: { sw r0, r10; addi r0, r0, 4 } /* store(WORD_6) */
+EX: { sw r0, r12; addi r0, r0, 4 } /* store(WORD_7) */
+
+EX: { lw r13, r1; addi r1, r1, 4; move zero, r18 } /* r13 = WORD_9 */
+EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_10 */
+EX: { lw r15, r1; move r1, r20 } /* r15 = WORD_11 */
+
+ /* Store third L1D line. */
+EX: { sw r0, r18; addi r0, r0, 4 } /* store(WORD_8) */
+EX: { sw r0, r13; addi r0, r0, 4 } /* store(WORD_9) */
+EX: { sw r0, r14; addi r0, r0, 4 } /* store(WORD_10) */
+EX: { sw r0, r15; addi r0, r0, 4 } /* store(WORD_11) */
+
+ /* Store rest of fourth L1D line. */
+EX: { sw r0, r4; addi r0, r0, 4 } /* store(WORD_12) */
+ {
+EX: sw r0, r8 /* store(WORD_13) */
+ addi r0, r0, 4
+ /* Will r2 be > 64 after we subtract 64 below? */
+ shri r4, r2, 7
+ }
+ {
+EX: sw r0, r11 /* store(WORD_14) */
+ addi r0, r0, 8
+ /* Record 64 bytes successfully copied. */
+ addi r2, r2, -64
+ }
+
+ { jrp lr; move lr, r27 }
+
+ /* Convey to the backtrace library that the stack frame is size
+ * zero, and the real return address is on the stack rather than
+ * in 'lr'.
+ */
+ { info 8 }
+
+ .align 64
+.Lcopy_unaligned_maybe_many:
+ /* Skip the setup overhead if we aren't copying many bytes. */
+ { slti_u r8, r2, 20; sub r4, zero, r0 }
+ { bnzt r8, .Lcopy_unaligned_few; andi r4, r4, 3 }
+ { bz r4, .Ldest_is_word_aligned; add r18, r1, r2 }
+
+/*
+ *
+ * unaligned 4 byte at a time copy handler.
+ *
+ */
+
+ /* Copy single bytes until r0 == 0 mod 4, so we can store words. */
+.Lalign_dest_loop:
+EX: { lb_u r3, r1; addi r1, r1, 1; addi r4, r4, -1 }
+EX: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r4, .Lalign_dest_loop; andi r3, r1, 3 }
+
+ /* If source and dest are now *both* aligned, do an aligned copy. */
+ { bz r3, .Lcheck_aligned_copy_size; addli r4, r2, -256 }
+
+.Ldest_is_word_aligned:
+
+#if CHIP_HAS_DWORD_ALIGN()
+EX: { andi r8, r0, 63; lwadd_na r6, r1, 4}
+ { slti_u r9, r2, 64; bz r8, .Ldest_is_L2_line_aligned }
+
+ /* This copies unaligned words until either there are fewer
+ * than 4 bytes left to copy, or until the destination pointer
+ * is cache-aligned, whichever comes first.
+ *
+ * On entry:
+ * - r0 is the next store address.
+ * - r1 points 4 bytes past the load address corresponding to r0.
+ * - r2 >= 4
+ * - r6 is the next aligned word loaded.
+ */
+.Lcopy_unaligned_src_words:
+EX: { lwadd_na r7, r1, 4; slti_u r8, r2, 4 + 4 }
+ /* stall */
+ { dword_align r6, r7, r1; slti_u r9, r2, 64 + 4 }
+EX: { swadd r0, r6, 4; addi r2, r2, -4 }
+ { bnz r8, .Lcleanup_unaligned_words; andi r8, r0, 63 }
+ { bnzt r8, .Lcopy_unaligned_src_words; move r6, r7 }
+
+ /* On entry:
+ * - r0 is the next store address.
+ * - r1 points 4 bytes past the load address corresponding to r0.
+ * - r2 >= 4 (# of bytes left to store).
+ * - r6 is the next aligned src word value.
+ * - r9 = (r2 < 64U).
+ * - r18 points one byte past the end of source memory.
+ */
+.Ldest_is_L2_line_aligned:
+
+ {
+ /* Not a full cache line remains. */
+ bnz r9, .Lcleanup_unaligned_words
+ move r7, r6
+ }
+
+ /* r2 >= 64 */
+
+ /* Kick off two prefetches, but don't go past the end. */
+ { addi r3, r1, 63 - 4; addi r8, r1, 64 + 63 - 4 }
+ { prefetch r3; move r3, r8; slt_u r8, r8, r18 }
+ { mvz r3, r8, r1; addi r8, r3, 64 }
+ { prefetch r3; move r3, r8; slt_u r8, r8, r18 }
+ { mvz r3, r8, r1; movei r17, 0 }
+
+.Lcopy_unaligned_line:
+ /* Prefetch another line. */
+ { prefetch r3; addi r15, r1, 60; addi r3, r3, 64 }
+ /* Fire off a load of the last word we are about to copy. */
+EX: { lw_na r15, r15; slt_u r8, r3, r18 }
+
+EX: { mvz r3, r8, r1; wh64 r0 }
+
+ /* This loop runs twice.
+ *
+ * On entry:
+ * - r17 is even before the first iteration, and odd before
+ * the second. It is incremented inside the loop. Encountering
+ * an even value at the end of the loop makes it stop.
+ */
+.Lcopy_half_an_unaligned_line:
+EX: {
+ /* Stall until the last byte is ready. In the steady state this
+ * guarantees all words to load below will be in the L2 cache, which
+ * avoids shunting the loads to the RTF.
+ */
+ move zero, r15
+ lwadd_na r7, r1, 16
+ }
+EX: { lwadd_na r11, r1, 12 }
+EX: { lwadd_na r14, r1, -24 }
+EX: { lwadd_na r8, r1, 4 }
+EX: { lwadd_na r9, r1, 4 }
+EX: {
+ lwadd_na r10, r1, 8
+ /* r16 = (r2 < 64), after we subtract 32 from r2 below. */
+ slti_u r16, r2, 64 + 32
+ }
+EX: { lwadd_na r12, r1, 4; addi r17, r17, 1 }
+EX: { lwadd_na r13, r1, 8; dword_align r6, r7, r1 }
+EX: { swadd r0, r6, 4; dword_align r7, r8, r1 }
+EX: { swadd r0, r7, 4; dword_align r8, r9, r1 }
+EX: { swadd r0, r8, 4; dword_align r9, r10, r1 }
+EX: { swadd r0, r9, 4; dword_align r10, r11, r1 }
+EX: { swadd r0, r10, 4; dword_align r11, r12, r1 }
+EX: { swadd r0, r11, 4; dword_align r12, r13, r1 }
+EX: { swadd r0, r12, 4; dword_align r13, r14, r1 }
+EX: { swadd r0, r13, 4; addi r2, r2, -32 }
+ { move r6, r14; bbst r17, .Lcopy_half_an_unaligned_line }
+
+ { bzt r16, .Lcopy_unaligned_line; move r7, r6 }
+
+ /* On entry:
+ * - r0 is the next store address.
+ * - r1 points 4 bytes past the load address corresponding to r0.
+ * - r2 >= 0 (# of bytes left to store).
+ * - r7 is the next aligned src word value.
+ */
+.Lcleanup_unaligned_words:
+ /* Handle any trailing bytes. */
+ { bz r2, .Lcopy_unaligned_done; slti_u r8, r2, 4 }
+ { bzt r8, .Lcopy_unaligned_src_words; move r6, r7 }
+
+ /* Move r1 back to the point where it corresponds to r0. */
+ { addi r1, r1, -4 }
+
+#else /* !CHIP_HAS_DWORD_ALIGN() */
+
+ /* Compute right/left shift counts and load initial source words. */
+ { andi r5, r1, -4; andi r3, r1, 3 }
+EX: { lw r6, r5; addi r5, r5, 4; shli r3, r3, 3 }
+EX: { lw r7, r5; addi r5, r5, 4; sub r4, zero, r3 }
+
+ /* Load and store one word at a time, using shifts and ORs
+ * to correct for the misaligned src.
+ */
+.Lcopy_unaligned_src_loop:
+ { shr r6, r6, r3; shl r8, r7, r4 }
+EX: { lw r7, r5; or r8, r8, r6; move r6, r7 }
+EX: { sw r0, r8; addi r0, r0, 4; addi r2, r2, -4 }
+ { addi r5, r5, 4; slti_u r8, r2, 8 }
+ { bzt r8, .Lcopy_unaligned_src_loop; addi r1, r1, 4 }
+
+ { bz r2, .Lcopy_unaligned_done }
+#endif /* !CHIP_HAS_DWORD_ALIGN() */
+
+ /* Fall through */
+
+/*
+ *
+ * 1 byte at a time copy handler.
+ *
+ */
+
+.Lcopy_unaligned_few:
+EX: { lb_u r3, r1; addi r1, r1, 1 }
+EX: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r2, .Lcopy_unaligned_few }
+
+.Lcopy_unaligned_done:
+
+ /* For memcpy return original dest address, else zero. */
+ { mz r0, r29, r23; jrp lr }
+
+.Lend_memcpy_common:
+ .size memcpy_common, .Lend_memcpy_common - memcpy_common
+
+ .section .fixup,"ax"
+memcpy_common_fixup:
+ .type memcpy_common_fixup, @function
+
+ /* Skip any bytes we already successfully copied.
+ * r2 (num remaining) is correct, but r0 (dst) and r1 (src)
+ * may not be quite right because of unrolling and prefetching.
+ * So we need to recompute their values as the address just
+ * after the last byte we are sure was successfully loaded and
+ * then stored.
+ */
+
+ /* Determine how many bytes we successfully copied. */
+ { sub r3, r25, r2 }
+
+ /* Add this to the original r0 and r1 to get their new values. */
+ { add r0, r23, r3; add r1, r24, r3 }
+
+ { bzt r29, memcpy_fixup_loop }
+ { blzt r29, copy_to_user_fixup_loop }
+
+copy_from_user_fixup_loop:
+ /* Try copying the rest one byte at a time, expecting a load fault. */
+.Lcfu: { lb_u r3, r1; addi r1, r1, 1 }
+ { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r2, copy_from_user_fixup_loop }
+
+.Lcopy_from_user_fixup_zero_remainder:
+ { bbs r29, 2f } /* low bit set means IS_COPY_FROM_USER */
+ /* byte-at-a-time loop faulted, so zero the rest. */
+ { move r3, r2; bz r2, 2f /* should be impossible, but handle it. */ }
+1: { sb r0, zero; addi r0, r0, 1; addi r3, r3, -1 }
+ { bnzt r3, 1b }
+2: move lr, r27
+ { move r0, r2; jrp lr }
+
+copy_to_user_fixup_loop:
+ /* Try copying the rest one byte at a time, expecting a store fault. */
+ { lb_u r3, r1; addi r1, r1, 1 }
+.Lctu: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r2, copy_to_user_fixup_loop }
+.Lcopy_to_user_fixup_done:
+ move lr, r27
+ { move r0, r2; jrp lr }
+
+memcpy_fixup_loop:
+ /* Try copying the rest one byte at a time. We expect a disastrous
+ * fault to happen since we are in fixup code, but let it happen.
+ */
+ { lb_u r3, r1; addi r1, r1, 1 }
+ { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 }
+ { bnzt r2, memcpy_fixup_loop }
+ /* This should be unreachable, we should have faulted again.
+ * But be paranoid and handle it in case some interrupt changed
+ * the TLB or something.
+ */
+ move lr, r27
+ { move r0, r23; jrp lr }
+
+ .size memcpy_common_fixup, . - memcpy_common_fixup
+
+ .section __ex_table,"a"
+ .word .Lcfu, .Lcopy_from_user_fixup_zero_remainder
+ .word .Lctu, .Lcopy_to_user_fixup_done
diff --git a/arch/tile/lib/memcpy_tile64.c b/arch/tile/lib/memcpy_tile64.c
new file mode 100644
index 000000000000..4f0047342469
--- /dev/null
+++ b/arch/tile/lib/memcpy_tile64.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <asm/fixmap.h>
+#include <asm/kmap_types.h>
+#include <asm/tlbflush.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+
+
+#if !CHIP_HAS_COHERENT_LOCAL_CACHE()
+
+/* Defined in memcpy.S */
+extern unsigned long __memcpy_asm(void *to, const void *from, unsigned long n);
+extern unsigned long __copy_to_user_inatomic_asm(
+ void __user *to, const void *from, unsigned long n);
+extern unsigned long __copy_from_user_inatomic_asm(
+ void *to, const void __user *from, unsigned long n);
+extern unsigned long __copy_from_user_zeroing_asm(
+ void *to, const void __user *from, unsigned long n);
+
+typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long);
+
+/* Size above which to consider TLB games for performance */
+#define LARGE_COPY_CUTOFF 2048
+
+/* Communicate to the simulator what we are trying to do. */
+#define sim_allow_multiple_caching(b) \
+ __insn_mtspr(SPR_SIM_CONTROL, \
+ SIM_CONTROL_ALLOW_MULTIPLE_CACHING | ((b) << _SIM_CONTROL_OPERATOR_BITS))
+
+/*
+ * Copy memory by briefly enabling incoherent cacheline-at-a-time mode.
+ *
+ * We set up our own source and destination PTEs that we fully control.
+ * This is the only way to guarantee that we don't race with another
+ * thread that is modifying the PTE; we can't afford to try the
+ * copy_{to,from}_user() technique of catching the interrupt, since
+ * we must run with interrupts disabled to avoid the risk of some
+ * other code seeing the incoherent data in our cache. (Recall that
+ * our cache is indexed by PA, so even if the other code doesn't use
+ * our KM_MEMCPY virtual addresses, they'll still hit in cache using
+ * the normal VAs that aren't supposed to hit in cache.)
+ */
+static void memcpy_multicache(void *dest, const void *source,
+ pte_t dst_pte, pte_t src_pte, int len)
+{
+ int idx, i;
+ unsigned long flags, newsrc, newdst, endsrc;
+ pmd_t *pmdp;
+ pte_t *ptep;
+ int cpu = get_cpu();
+
+ /*
+ * Disable interrupts so that we don't recurse into memcpy()
+ * in an interrupt handler, nor accidentally reference
+ * the PA of the source from an interrupt routine. Also
+ * notify the simulator that we're playing games so we don't
+ * generate spurious coherency warnings.
+ */
+ local_irq_save(flags);
+ sim_allow_multiple_caching(1);
+
+ /* Set up the new dest mapping */
+ idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + KM_MEMCPY0;
+ newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1));
+ pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst);
+ ptep = pte_offset_kernel(pmdp, newdst);
+ if (pte_val(*ptep) != pte_val(dst_pte)) {
+ set_pte(ptep, dst_pte);
+ local_flush_tlb_page(NULL, newdst, PAGE_SIZE);
+ }
+
+ /* Set up the new source mapping */
+ idx += (KM_MEMCPY0 - KM_MEMCPY1);
+ src_pte = hv_pte_set_nc(src_pte);
+ src_pte = hv_pte_clear_writable(src_pte); /* be paranoid */
+ newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1));
+ pmdp = pmd_offset(pud_offset(pgd_offset_k(newsrc), newsrc), newsrc);
+ ptep = pte_offset_kernel(pmdp, newsrc);
+ *ptep = src_pte; /* set_pte() would be confused by this */
+ local_flush_tlb_page(NULL, newsrc, PAGE_SIZE);
+
+ /* Actually move the data. */
+ __memcpy_asm((void *)newdst, (const void *)newsrc, len);
+
+ /*
+ * Remap the source as locally-cached and not OLOC'ed so that
+ * we can inval without also invaling the remote cpu's cache.
+ * This also avoids known errata with inv'ing cacheable oloc data.
+ */
+ src_pte = hv_pte_set_mode(src_pte, HV_PTE_MODE_CACHE_NO_L3);
+ src_pte = hv_pte_set_writable(src_pte); /* need write access for inv */
+ *ptep = src_pte; /* set_pte() would be confused by this */
+ local_flush_tlb_page(NULL, newsrc, PAGE_SIZE);
+
+ /*
+ * Do the actual invalidation, covering the full L2 cache line
+ * at the end since __memcpy_asm() is somewhat aggressive.
+ */
+ __inv_buffer((void *)newsrc, len);
+
+ /*
+ * We're done: notify the simulator that all is back to normal,
+ * and re-enable interrupts and pre-emption.
+ */
+ sim_allow_multiple_caching(0);
+ local_irq_restore(flags);
+ put_cpu_no_resched();
+}
+
+/*
+ * Identify large copies from remotely-cached memory, and copy them
+ * via memcpy_multicache() if they look good, otherwise fall back
+ * to the particular kind of copying passed as the memcpy_t function.
+ */
+static unsigned long fast_copy(void *dest, const void *source, int len,
+ memcpy_t func)
+{
+ /*
+ * Check if it's big enough to bother with. We may end up doing a
+ * small copy via TLB manipulation if we're near a page boundary,
+ * but presumably we'll make it up when we hit the second page.
+ */
+ while (len >= LARGE_COPY_CUTOFF) {
+ int copy_size, bytes_left_on_page;
+ pte_t *src_ptep, *dst_ptep;
+ pte_t src_pte, dst_pte;
+ struct page *src_page, *dst_page;
+
+ /* Is the source page oloc'ed to a remote cpu? */
+retry_source:
+ src_ptep = virt_to_pte(current->mm, (unsigned long)source);
+ if (src_ptep == NULL)
+ break;
+ src_pte = *src_ptep;
+ if (!hv_pte_get_present(src_pte) ||
+ !hv_pte_get_readable(src_pte) ||
+ hv_pte_get_mode(src_pte) != HV_PTE_MODE_CACHE_TILE_L3)
+ break;
+ if (get_remote_cache_cpu(src_pte) == smp_processor_id())
+ break;
+ src_page = pfn_to_page(hv_pte_get_pfn(src_pte));
+ get_page(src_page);
+ if (pte_val(src_pte) != pte_val(*src_ptep)) {
+ put_page(src_page);
+ goto retry_source;
+ }
+ if (pte_huge(src_pte)) {
+ /* Adjust the PTE to correspond to a small page */
+ int pfn = hv_pte_get_pfn(src_pte);
+ pfn += (((unsigned long)source & (HPAGE_SIZE-1))
+ >> PAGE_SHIFT);
+ src_pte = pfn_pte(pfn, src_pte);
+ src_pte = pte_mksmall(src_pte);
+ }
+
+ /* Is the destination page writable? */
+retry_dest:
+ dst_ptep = virt_to_pte(current->mm, (unsigned long)dest);
+ if (dst_ptep == NULL) {
+ put_page(src_page);
+ break;
+ }
+ dst_pte = *dst_ptep;
+ if (!hv_pte_get_present(dst_pte) ||
+ !hv_pte_get_writable(dst_pte)) {
+ put_page(src_page);
+ break;
+ }
+ dst_page = pfn_to_page(hv_pte_get_pfn(dst_pte));
+ if (dst_page == src_page) {
+ /*
+ * Source and dest are on the same page; this
+ * potentially exposes us to incoherence if any
+ * part of src and dest overlap on a cache line.
+ * Just give up rather than trying to be precise.
+ */
+ put_page(src_page);
+ break;
+ }
+ get_page(dst_page);
+ if (pte_val(dst_pte) != pte_val(*dst_ptep)) {
+ put_page(dst_page);
+ goto retry_dest;
+ }
+ if (pte_huge(dst_pte)) {
+ /* Adjust the PTE to correspond to a small page */
+ int pfn = hv_pte_get_pfn(dst_pte);
+ pfn += (((unsigned long)dest & (HPAGE_SIZE-1))
+ >> PAGE_SHIFT);
+ dst_pte = pfn_pte(pfn, dst_pte);
+ dst_pte = pte_mksmall(dst_pte);
+ }
+
+ /* All looks good: create a cachable PTE and copy from it */
+ copy_size = len;
+ bytes_left_on_page =
+ PAGE_SIZE - (((int)source) & (PAGE_SIZE-1));
+ if (copy_size > bytes_left_on_page)
+ copy_size = bytes_left_on_page;
+ bytes_left_on_page =
+ PAGE_SIZE - (((int)dest) & (PAGE_SIZE-1));
+ if (copy_size > bytes_left_on_page)
+ copy_size = bytes_left_on_page;
+ memcpy_multicache(dest, source, dst_pte, src_pte, copy_size);
+
+ /* Release the pages */
+ put_page(dst_page);
+ put_page(src_page);
+
+ /* Continue on the next page */
+ dest += copy_size;
+ source += copy_size;
+ len -= copy_size;
+ }
+
+ return func(dest, source, len);
+}
+
+void *memcpy(void *to, const void *from, __kernel_size_t n)
+{
+ if (n < LARGE_COPY_CUTOFF)
+ return (void *)__memcpy_asm(to, from, n);
+ else
+ return (void *)fast_copy(to, from, n, __memcpy_asm);
+}
+
+unsigned long __copy_to_user_inatomic(void __user *to, const void *from,
+ unsigned long n)
+{
+ if (n < LARGE_COPY_CUTOFF)
+ return __copy_to_user_inatomic_asm(to, from, n);
+ else
+ return fast_copy(to, from, n, __copy_to_user_inatomic_asm);
+}
+
+unsigned long __copy_from_user_inatomic(void *to, const void __user *from,
+ unsigned long n)
+{
+ if (n < LARGE_COPY_CUTOFF)
+ return __copy_from_user_inatomic_asm(to, from, n);
+ else
+ return fast_copy(to, from, n, __copy_from_user_inatomic_asm);
+}
+
+unsigned long __copy_from_user_zeroing(void *to, const void __user *from,
+ unsigned long n)
+{
+ if (n < LARGE_COPY_CUTOFF)
+ return __copy_from_user_zeroing_asm(to, from, n);
+ else
+ return fast_copy(to, from, n, __copy_from_user_zeroing_asm);
+}
+
+#endif /* !CHIP_HAS_COHERENT_LOCAL_CACHE() */
diff --git a/arch/tile/lib/memmove_32.c b/arch/tile/lib/memmove_32.c
new file mode 100644
index 000000000000..f09d8c4523ec
--- /dev/null
+++ b/arch/tile/lib/memmove_32.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ if ((const char *)src >= (char *)dest + n
+ || (char *)dest >= (const char *)src + n) {
+ /* We found no overlap, so let memcpy do all the heavy
+ * lifting (prefetching, etc.)
+ */
+ return memcpy(dest, src, n);
+ }
+
+ if (n != 0) {
+ const uint8_t *in;
+ uint8_t x;
+ uint8_t *out;
+ int stride;
+
+ if (src < dest) {
+ /* copy backwards */
+ in = (const uint8_t *)src + n - 1;
+ out = (uint8_t *)dest + n - 1;
+ stride = -1;
+ } else {
+ /* copy forwards */
+ in = (const uint8_t *)src;
+ out = (uint8_t *)dest;
+ stride = 1;
+ }
+
+ /* Manually software-pipeline this loop. */
+ x = *in;
+ in += stride;
+
+ while (--n != 0) {
+ *out = x;
+ out += stride;
+ x = *in;
+ in += stride;
+ }
+
+ *out = x;
+ }
+
+ return dest;
+}
+EXPORT_SYMBOL(memmove);
diff --git a/arch/tile/lib/memset_32.c b/arch/tile/lib/memset_32.c
new file mode 100644
index 000000000000..8593bc82398a
--- /dev/null
+++ b/arch/tile/lib/memset_32.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <arch/chip.h>
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+
+void *memset(void *s, int c, size_t n)
+{
+ uint32_t *out32;
+ int n32;
+ uint32_t v16, v32;
+ uint8_t *out8 = s;
+#if !CHIP_HAS_WH64()
+ int ahead32;
+#else
+ int to_align32;
+#endif
+
+ /* Experimentation shows that a trivial tight loop is a win up until
+ * around a size of 20, where writing a word at a time starts to win.
+ */
+#define BYTE_CUTOFF 20
+
+#if BYTE_CUTOFF < 3
+ /* This must be at least at least this big, or some code later
+ * on doesn't work.
+ */
+#error "BYTE_CUTOFF is too small"
+#endif
+
+ if (n < BYTE_CUTOFF) {
+ /* Strangely, this turns out to be the tightest way to
+ * write this loop.
+ */
+ if (n != 0) {
+ do {
+ /* Strangely, combining these into one line
+ * performs worse.
+ */
+ *out8 = c;
+ out8++;
+ } while (--n != 0);
+ }
+
+ return s;
+ }
+
+#if !CHIP_HAS_WH64()
+ /* Use a spare issue slot to start prefetching the first cache
+ * line early. This instruction is free as the store can be buried
+ * in otherwise idle issue slots doing ALU ops.
+ */
+ __insn_prefetch(out8);
+
+ /* We prefetch the end so that a short memset that spans two cache
+ * lines gets some prefetching benefit. Again we believe this is free
+ * to issue.
+ */
+ __insn_prefetch(&out8[n - 1]);
+#endif /* !CHIP_HAS_WH64() */
+
+
+ /* Align 'out8'. We know n >= 3 so this won't write past the end. */
+ while (((uintptr_t) out8 & 3) != 0) {
+ *out8++ = c;
+ --n;
+ }
+
+ /* Align 'n'. */
+ while (n & 3)
+ out8[--n] = c;
+
+ out32 = (uint32_t *) out8;
+ n32 = n >> 2;
+
+ /* Tile input byte out to 32 bits. */
+ v16 = __insn_intlb(c, c);
+ v32 = __insn_intlh(v16, v16);
+
+ /* This must be at least 8 or the following loop doesn't work. */
+#define CACHE_LINE_SIZE_IN_WORDS (CHIP_L2_LINE_SIZE() / 4)
+
+#if !CHIP_HAS_WH64()
+
+ ahead32 = CACHE_LINE_SIZE_IN_WORDS;
+
+ /* We already prefetched the first and last cache lines, so
+ * we only need to do more prefetching if we are storing
+ * to more than two cache lines.
+ */
+ if (n32 > CACHE_LINE_SIZE_IN_WORDS * 2) {
+ int i;
+
+ /* Prefetch the next several cache lines.
+ * This is the setup code for the software-pipelined
+ * loop below.
+ */
+#define MAX_PREFETCH 5
+ ahead32 = n32 & -CACHE_LINE_SIZE_IN_WORDS;
+ if (ahead32 > MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS)
+ ahead32 = MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS;
+
+ for (i = CACHE_LINE_SIZE_IN_WORDS;
+ i < ahead32; i += CACHE_LINE_SIZE_IN_WORDS)
+ __insn_prefetch(&out32[i]);
+ }
+
+ if (n32 > ahead32) {
+ while (1) {
+ int j;
+
+ /* Prefetch by reading one word several cache lines
+ * ahead. Since loads are non-blocking this will
+ * cause the full cache line to be read while we are
+ * finishing earlier cache lines. Using a store
+ * here causes microarchitectural performance
+ * problems where a victimizing store miss goes to
+ * the head of the retry FIFO and locks the pipe for
+ * a few cycles. So a few subsequent stores in this
+ * loop go into the retry FIFO, and then later
+ * stores see other stores to the same cache line
+ * are already in the retry FIFO and themselves go
+ * into the retry FIFO, filling it up and grinding
+ * to a halt waiting for the original miss to be
+ * satisfied.
+ */
+ __insn_prefetch(&out32[ahead32]);
+
+#if 1
+#if CACHE_LINE_SIZE_IN_WORDS % 4 != 0
+#error "Unhandled CACHE_LINE_SIZE_IN_WORDS"
+#endif
+
+ n32 -= CACHE_LINE_SIZE_IN_WORDS;
+
+ /* Save icache space by only partially unrolling
+ * this loop.
+ */
+ for (j = CACHE_LINE_SIZE_IN_WORDS / 4; j > 0; j--) {
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ }
+#else
+ /* Unfortunately, due to a code generator flaw this
+ * allocates a separate register for each of these
+ * stores, which requires a large number of spills,
+ * which makes this procedure enormously bigger
+ * (something like 70%)
+ */
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ n32 -= 16;
+#endif
+
+ /* To save compiled code size, reuse this loop even
+ * when we run out of prefetching to do by dropping
+ * ahead32 down.
+ */
+ if (n32 <= ahead32) {
+ /* Not even a full cache line left,
+ * so stop now.
+ */
+ if (n32 < CACHE_LINE_SIZE_IN_WORDS)
+ break;
+
+ /* Choose a small enough value that we don't
+ * prefetch past the end. There's no sense
+ * in touching cache lines we don't have to.
+ */
+ ahead32 = CACHE_LINE_SIZE_IN_WORDS - 1;
+ }
+ }
+ }
+
+#else /* CHIP_HAS_WH64() */
+
+ /* Determine how many words we need to emit before the 'out32'
+ * pointer becomes aligned modulo the cache line size.
+ */
+ to_align32 =
+ (-((uintptr_t)out32 >> 2)) & (CACHE_LINE_SIZE_IN_WORDS - 1);
+
+ /* Only bother aligning and using wh64 if there is at least
+ * one full cache line to process. This check also prevents
+ * overrunning the end of the buffer with alignment words.
+ */
+ if (to_align32 <= n32 - CACHE_LINE_SIZE_IN_WORDS) {
+ int lines_left;
+
+ /* Align out32 mod the cache line size so we can use wh64. */
+ n32 -= to_align32;
+ for (; to_align32 != 0; to_align32--) {
+ *out32 = v32;
+ out32++;
+ }
+
+ /* Use unsigned divide to turn this into a right shift. */
+ lines_left = (unsigned)n32 / CACHE_LINE_SIZE_IN_WORDS;
+
+ do {
+ /* Only wh64 a few lines at a time, so we don't
+ * exceed the maximum number of victim lines.
+ */
+ int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS())
+ ? lines_left
+ : CHIP_MAX_OUTSTANDING_VICTIMS());
+ uint32_t *wh = out32;
+ int i = x;
+ int j;
+
+ lines_left -= x;
+
+ do {
+ __insn_wh64(wh);
+ wh += CACHE_LINE_SIZE_IN_WORDS;
+ } while (--i);
+
+ for (j = x * (CACHE_LINE_SIZE_IN_WORDS / 4); j != 0; j--) {
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ *out32++ = v32;
+ }
+ } while (lines_left != 0);
+
+ /* We processed all full lines above, so only this many
+ * words remain to be processed.
+ */
+ n32 &= CACHE_LINE_SIZE_IN_WORDS - 1;
+ }
+
+#endif /* CHIP_HAS_WH64() */
+
+ /* Now handle any leftover values. */
+ if (n32 != 0) {
+ do {
+ *out32 = v32;
+ out32++;
+ } while (--n32 != 0);
+ }
+
+ return s;
+}
+EXPORT_SYMBOL(memset);
diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c
new file mode 100644
index 000000000000..485e24d62c6b
--- /dev/null
+++ b/arch/tile/lib/spinlock_32.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+
+#include "spinlock_common.h"
+
+void arch_spin_lock(arch_spinlock_t *lock)
+{
+ int my_ticket;
+ int iterations = 0;
+ int delta;
+
+ while ((my_ticket = __insn_tns((void *)&lock->next_ticket)) & 1)
+ delay_backoff(iterations++);
+
+ /* Increment the next ticket number, implicitly releasing tns lock. */
+ lock->next_ticket = my_ticket + TICKET_QUANTUM;
+
+ /* Wait until it's our turn. */
+ while ((delta = my_ticket - lock->current_ticket) != 0)
+ relax((128 / CYCLES_PER_RELAX_LOOP) * delta);
+}
+EXPORT_SYMBOL(arch_spin_lock);
+
+int arch_spin_trylock(arch_spinlock_t *lock)
+{
+ /*
+ * Grab a ticket; no need to retry if it's busy, we'll just
+ * treat that the same as "locked", since someone else
+ * will lock it momentarily anyway.
+ */
+ int my_ticket = __insn_tns((void *)&lock->next_ticket);
+
+ if (my_ticket == lock->current_ticket) {
+ /* Not currently locked, so lock it by keeping this ticket. */
+ lock->next_ticket = my_ticket + TICKET_QUANTUM;
+ /* Success! */
+ return 1;
+ }
+
+ if (!(my_ticket & 1)) {
+ /* Release next_ticket. */
+ lock->next_ticket = my_ticket;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(arch_spin_trylock);
+
+void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+ u32 iterations = 0;
+ while (arch_spin_is_locked(lock))
+ delay_backoff(iterations++);
+}
+EXPORT_SYMBOL(arch_spin_unlock_wait);
+
+/*
+ * The low byte is always reserved to be the marker for a "tns" operation
+ * since the low bit is set to "1" by a tns. The next seven bits are
+ * zeroes. The next byte holds the "next" writer value, i.e. the ticket
+ * available for the next task that wants to write. The third byte holds
+ * the current writer value, i.e. the writer who holds the current ticket.
+ * If current == next == 0, there are no interested writers.
+ */
+#define WR_NEXT_SHIFT _WR_NEXT_SHIFT
+#define WR_CURR_SHIFT _WR_CURR_SHIFT
+#define WR_WIDTH _WR_WIDTH
+#define WR_MASK ((1 << WR_WIDTH) - 1)
+
+/*
+ * The last eight bits hold the active reader count. This has to be
+ * zero before a writer can start to write.
+ */
+#define RD_COUNT_SHIFT _RD_COUNT_SHIFT
+#define RD_COUNT_WIDTH _RD_COUNT_WIDTH
+#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1)
+
+
+/* Lock the word, spinning until there are no tns-ers. */
+static inline u32 get_rwlock(arch_rwlock_t *rwlock)
+{
+ u32 iterations = 0;
+ for (;;) {
+ u32 val = __insn_tns((int *)&rwlock->lock);
+ if (unlikely(val & 1)) {
+ delay_backoff(iterations++);
+ continue;
+ }
+ return val;
+ }
+}
+
+int arch_read_trylock_slow(arch_rwlock_t *rwlock)
+{
+ u32 val = get_rwlock(rwlock);
+ int locked = (val << RD_COUNT_WIDTH) == 0;
+ rwlock->lock = val + (locked << RD_COUNT_SHIFT);
+ return locked;
+}
+EXPORT_SYMBOL(arch_read_trylock_slow);
+
+void arch_read_unlock_slow(arch_rwlock_t *rwlock)
+{
+ u32 val = get_rwlock(rwlock);
+ rwlock->lock = val - (1 << RD_COUNT_SHIFT);
+}
+EXPORT_SYMBOL(arch_read_unlock_slow);
+
+void arch_write_unlock_slow(arch_rwlock_t *rwlock, u32 val)
+{
+ u32 eq, mask = 1 << WR_CURR_SHIFT;
+ while (unlikely(val & 1)) {
+ /* Limited backoff since we are the highest-priority task. */
+ relax(4);
+ val = __insn_tns((int *)&rwlock->lock);
+ }
+ val = __insn_addb(val, mask);
+ eq = __insn_seqb(val, val << (WR_CURR_SHIFT - WR_NEXT_SHIFT));
+ val = __insn_mz(eq & mask, val);
+ rwlock->lock = val;
+}
+EXPORT_SYMBOL(arch_write_unlock_slow);
+
+/*
+ * We spin until everything but the reader bits (which are in the high
+ * part of the word) are zero, i.e. no active or waiting writers, no tns.
+ *
+ * ISSUE: This approach can permanently starve readers. A reader who sees
+ * a writer could instead take a ticket lock (just like a writer would),
+ * and atomically enter read mode (with 1 reader) when it gets the ticket.
+ * This way both readers and writers will always make forward progress
+ * in a finite time.
+ */
+void arch_read_lock_slow(arch_rwlock_t *rwlock, u32 val)
+{
+ u32 iterations = 0;
+ do {
+ if (!(val & 1))
+ rwlock->lock = val;
+ delay_backoff(iterations++);
+ val = __insn_tns((int *)&rwlock->lock);
+ } while ((val << RD_COUNT_WIDTH) != 0);
+ rwlock->lock = val + (1 << RD_COUNT_SHIFT);
+}
+EXPORT_SYMBOL(arch_read_lock_slow);
+
+void arch_write_lock_slow(arch_rwlock_t *rwlock, u32 val)
+{
+ /*
+ * The trailing underscore on this variable (and curr_ below)
+ * reminds us that the high bits are garbage; we mask them out
+ * when we compare them.
+ */
+ u32 my_ticket_;
+
+ /* Take out the next ticket; this will also stop would-be readers. */
+ if (val & 1)
+ val = get_rwlock(rwlock);
+ rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT);
+
+ /* Extract my ticket value from the original word. */
+ my_ticket_ = val >> WR_NEXT_SHIFT;
+
+ /*
+ * Wait until the "current" field matches our ticket, and
+ * there are no remaining readers.
+ */
+ for (;;) {
+ u32 curr_ = val >> WR_CURR_SHIFT;
+ u32 readers = val >> RD_COUNT_SHIFT;
+ u32 delta = ((my_ticket_ - curr_) & WR_MASK) + !!readers;
+ if (likely(delta == 0))
+ break;
+
+ /* Delay based on how many lock-holders are still out there. */
+ relax((256 / CYCLES_PER_RELAX_LOOP) * delta);
+
+ /*
+ * Get a non-tns value to check; we don't need to tns
+ * it ourselves. Since we're not tns'ing, we retry
+ * more rapidly to get a valid value.
+ */
+ while ((val = rwlock->lock) & 1)
+ relax(4);
+ }
+}
+EXPORT_SYMBOL(arch_write_lock_slow);
+
+int __tns_atomic_acquire(atomic_t *lock)
+{
+ int ret;
+ u32 iterations = 0;
+
+ BUG_ON(__insn_mfspr(SPR_INTERRUPT_CRITICAL_SECTION));
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1);
+
+ while ((ret = __insn_tns((void *)&lock->counter)) == 1)
+ delay_backoff(iterations++);
+ return ret;
+}
+
+void __tns_atomic_release(atomic_t *p, int v)
+{
+ p->counter = v;
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0);
+}
diff --git a/arch/tile/lib/spinlock_common.h b/arch/tile/lib/spinlock_common.h
new file mode 100644
index 000000000000..8dffebde6630
--- /dev/null
+++ b/arch/tile/lib/spinlock_common.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ * This file is included into spinlock_32.c or _64.c.
+ */
+
+/*
+ * The mfspr in __spinlock_relax() is 5 or 6 cycles plus 2 for loop
+ * overhead.
+ */
+#ifdef __tilegx__
+#define CYCLES_PER_RELAX_LOOP 7
+#else
+#define CYCLES_PER_RELAX_LOOP 8
+#endif
+
+/*
+ * Idle the core for CYCLES_PER_RELAX_LOOP * iterations cycles.
+ */
+static inline void
+relax(int iterations)
+{
+ for (/*above*/; iterations > 0; iterations--)
+ __insn_mfspr(SPR_PASS);
+ barrier();
+}
+
+/* Perform bounded exponential backoff.*/
+void delay_backoff(int iterations)
+{
+ u32 exponent, loops;
+
+ /*
+ * 2^exponent is how many times we go around the loop,
+ * which takes 8 cycles. We want to start with a 16- to 31-cycle
+ * loop, so we need to go around minimum 2 = 2^1 times, so we
+ * bias the original value up by 1.
+ */
+ exponent = iterations + 1;
+
+ /*
+ * Don't allow exponent to exceed 7, so we have 128 loops,
+ * or 1,024 (to 2,047) cycles, as our maximum.
+ */
+ if (exponent > 8)
+ exponent = 8;
+
+ loops = 1 << exponent;
+
+ /* Add a randomness factor so two cpus never get in lock step. */
+ loops += __insn_crc32_32(stack_pointer, get_cycles_low()) &
+ (loops - 1);
+
+ relax(1 << exponent);
+}
diff --git a/arch/tile/lib/strchr_32.c b/arch/tile/lib/strchr_32.c
new file mode 100644
index 000000000000..c94e6f7ae7b5
--- /dev/null
+++ b/arch/tile/lib/strchr_32.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+#undef strchr
+
+char *strchr(const char *s, int c)
+{
+ int z, g;
+
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *)(s_int & -4);
+
+ /* Create four copies of the byte for which we are looking. */
+ const uint32_t goal = 0x01010101 * (uint8_t) c;
+
+ /* Read the first aligned word, but force bytes before the string to
+ * match neither zero nor goal (we make sure the high bit of each
+ * byte is 1, and the low 7 bits are all the opposite of the goal
+ * byte).
+ *
+ * Note that this shift count expression works because we know shift
+ * counts are taken mod 32.
+ */
+ const uint32_t before_mask = (1 << (s_int << 3)) - 1;
+ uint32_t v = (*p | before_mask) ^ (goal & __insn_shrib(before_mask, 1));
+
+ uint32_t zero_matches, goal_matches;
+ while (1) {
+ /* Look for a terminating '\0'. */
+ zero_matches = __insn_seqb(v, 0);
+
+ /* Look for the goal byte. */
+ goal_matches = __insn_seqb(v, goal);
+
+ if (__builtin_expect(zero_matches | goal_matches, 0))
+ break;
+
+ v = *++p;
+ }
+
+ z = __insn_ctz(zero_matches);
+ g = __insn_ctz(goal_matches);
+
+ /* If we found c before '\0' we got a match. Note that if c == '\0'
+ * then g == z, and we correctly return the address of the '\0'
+ * rather than NULL.
+ */
+ return (g <= z) ? ((char *)p) + (g >> 3) : NULL;
+}
+EXPORT_SYMBOL(strchr);
diff --git a/arch/tile/lib/strlen_32.c b/arch/tile/lib/strlen_32.c
new file mode 100644
index 000000000000..f26f88e11e4a
--- /dev/null
+++ b/arch/tile/lib/strlen_32.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/module.h>
+
+size_t strlen(const char *s)
+{
+ /* Get an aligned pointer. */
+ const uintptr_t s_int = (uintptr_t) s;
+ const uint32_t *p = (const uint32_t *)(s_int & -4);
+
+ /* Read the first word, but force bytes before the string to be nonzero.
+ * This expression works because we know shift counts are taken mod 32.
+ */
+ uint32_t v = *p | ((1 << (s_int << 3)) - 1);
+
+ uint32_t bits;
+ while ((bits = __insn_seqb(v, 0)) == 0)
+ v = *++p;
+
+ return ((const char *)p) + (__insn_ctz(bits) >> 3) - s;
+}
+EXPORT_SYMBOL(strlen);
diff --git a/arch/tile/lib/uaccess.c b/arch/tile/lib/uaccess.c
new file mode 100644
index 000000000000..9ae182568b77
--- /dev/null
+++ b/arch/tile/lib/uaccess.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+int __range_ok(unsigned long addr, unsigned long size)
+{
+ unsigned long limit = current_thread_info()->addr_limit.seg;
+ __chk_user_ptr(addr);
+ return !((addr < limit && size <= limit - addr) ||
+ is_arch_mappable_range(addr, size));
+}
+EXPORT_SYMBOL(__range_ok);
+
+void copy_from_user_overflow(void)
+{
+ WARN(1, "Buffer overflow detected!\n");
+}
+EXPORT_SYMBOL(copy_from_user_overflow);
diff --git a/arch/tile/lib/usercopy_32.S b/arch/tile/lib/usercopy_32.S
new file mode 100644
index 000000000000..979f76d83746
--- /dev/null
+++ b/arch/tile/lib/usercopy_32.S
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/errno.h>
+#include <asm/cache.h>
+#include <arch/chip.h>
+
+/* Access user memory, but use MMU to avoid propagating kernel exceptions. */
+
+ .pushsection .fixup,"ax"
+
+get_user_fault:
+ { move r0, zero; move r1, zero }
+ { movei r2, -EFAULT; jrp lr }
+ ENDPROC(get_user_fault)
+
+put_user_fault:
+ { movei r0, -EFAULT; jrp lr }
+ ENDPROC(put_user_fault)
+
+ .popsection
+
+/*
+ * __get_user_N functions take a pointer in r0, and return 0 in r2
+ * on success, with the value in r0; or else -EFAULT in r2.
+ */
+#define __get_user_N(bytes, LOAD) \
+ STD_ENTRY(__get_user_##bytes); \
+1: { LOAD r0, r0; move r1, zero; move r2, zero }; \
+ jrp lr; \
+ STD_ENDPROC(__get_user_##bytes); \
+ .pushsection __ex_table,"a"; \
+ .word 1b, get_user_fault; \
+ .popsection
+
+__get_user_N(1, lb_u)
+__get_user_N(2, lh_u)
+__get_user_N(4, lw)
+
+/*
+ * __get_user_8 takes a pointer in r0, and returns 0 in r2
+ * on success, with the value in r0/r1; or else -EFAULT in r2.
+ */
+ STD_ENTRY(__get_user_8);
+1: { lw r0, r0; addi r1, r0, 4 };
+2: { lw r1, r1; move r2, zero };
+ jrp lr;
+ STD_ENDPROC(__get_user_8);
+ .pushsection __ex_table,"a";
+ .word 1b, get_user_fault;
+ .word 2b, get_user_fault;
+ .popsection
+
+/*
+ * __put_user_N functions take a value in r0 and a pointer in r1,
+ * and return 0 in r0 on success or -EFAULT on failure.
+ */
+#define __put_user_N(bytes, STORE) \
+ STD_ENTRY(__put_user_##bytes); \
+1: { STORE r1, r0; move r0, zero }; \
+ jrp lr; \
+ STD_ENDPROC(__put_user_##bytes); \
+ .pushsection __ex_table,"a"; \
+ .word 1b, put_user_fault; \
+ .popsection
+
+__put_user_N(1, sb)
+__put_user_N(2, sh)
+__put_user_N(4, sw)
+
+/*
+ * __put_user_8 takes a value in r0/r1 and a pointer in r2,
+ * and returns 0 in r0 on success or -EFAULT on failure.
+ */
+STD_ENTRY(__put_user_8)
+1: { sw r2, r0; addi r2, r2, 4 }
+2: { sw r2, r1; move r0, zero }
+ jrp lr
+ STD_ENDPROC(__put_user_8)
+ .pushsection __ex_table,"a"
+ .word 1b, put_user_fault
+ .word 2b, put_user_fault
+ .popsection
+
+
+/*
+ * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
+ * It returns the length, including the terminating NUL, or zero on exception.
+ * If length is greater than the bound, returns one plus the bound.
+ */
+STD_ENTRY(strnlen_user_asm)
+ { bz r1, 2f; addi r3, r0, -1 } /* bias down to include NUL */
+1: { lb_u r4, r0; addi r1, r1, -1 }
+ bz r4, 2f
+ { bnzt r1, 1b; addi r0, r0, 1 }
+2: { sub r0, r0, r3; jrp lr }
+ STD_ENDPROC(strnlen_user_asm)
+ .pushsection .fixup,"ax"
+strnlen_user_fault:
+ { move r0, zero; jrp lr }
+ ENDPROC(strnlen_user_fault)
+ .section __ex_table,"a"
+ .word 1b, strnlen_user_fault
+ .popsection
+
+/*
+ * strncpy_from_user_asm takes the kernel target pointer in r0,
+ * the userspace source pointer in r1, and the length bound (including
+ * the trailing NUL) in r2. On success, it returns the string length
+ * (not including the trailing NUL), or -EFAULT on failure.
+ */
+STD_ENTRY(strncpy_from_user_asm)
+ { bz r2, 2f; move r3, r0 }
+1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 }
+ { sb r0, r4; addi r0, r0, 1 }
+ bz r2, 2f
+ bnzt r4, 1b
+ addi r0, r0, -1 /* don't count the trailing NUL */
+2: { sub r0, r0, r3; jrp lr }
+ STD_ENDPROC(strncpy_from_user_asm)
+ .pushsection .fixup,"ax"
+strncpy_from_user_fault:
+ { movei r0, -EFAULT; jrp lr }
+ ENDPROC(strncpy_from_user_fault)
+ .section __ex_table,"a"
+ .word 1b, strncpy_from_user_fault
+ .popsection
+
+/*
+ * clear_user_asm takes the user target address in r0 and the
+ * number of bytes to zero in r1.
+ * It returns the number of uncopiable bytes (hopefully zero) in r0.
+ * Note that we don't use a separate .fixup section here since we fall
+ * through into the "fixup" code as the last straight-line bundle anyway.
+ */
+STD_ENTRY(clear_user_asm)
+ { bz r1, 2f; or r2, r0, r1 }
+ andi r2, r2, 3
+ bzt r2, .Lclear_aligned_user_asm
+1: { sb r0, zero; addi r0, r0, 1; addi r1, r1, -1 }
+ bnzt r1, 1b
+2: { move r0, r1; jrp lr }
+ .pushsection __ex_table,"a"
+ .word 1b, 2b
+ .popsection
+
+.Lclear_aligned_user_asm:
+1: { sw r0, zero; addi r0, r0, 4; addi r1, r1, -4 }
+ bnzt r1, 1b
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(clear_user_asm)
+ .pushsection __ex_table,"a"
+ .word 1b, 2b
+ .popsection
+
+/*
+ * flush_user_asm takes the user target address in r0 and the
+ * number of bytes to flush in r1.
+ * It returns the number of unflushable bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(flush_user_asm)
+ bz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() }
+ { addi r0, r0, CHIP_FLUSH_STRIDE(); bnzt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(flush_user_asm)
+ .pushsection __ex_table,"a"
+ .word 1b, 2b
+ .popsection
+
+/*
+ * inv_user_asm takes the user target address in r0 and the
+ * number of bytes to invalidate in r1.
+ * It returns the number of not inv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(inv_user_asm)
+ bz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() }
+ { addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(inv_user_asm)
+ .pushsection __ex_table,"a"
+ .word 1b, 2b
+ .popsection
+
+/*
+ * finv_user_asm takes the user target address in r0 and the
+ * number of bytes to flush-invalidate in r1.
+ * It returns the number of not finv'able bytes (hopefully zero) in r0.
+ */
+STD_ENTRY(finv_user_asm)
+ bz r1, 2f
+ { movei r2, L2_CACHE_BYTES; add r1, r0, r1 }
+ { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 }
+ { and r0, r0, r2; and r1, r1, r2 }
+ { sub r1, r1, r0 }
+1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() }
+ { addi r0, r0, CHIP_FINV_STRIDE(); bnzt r1, 1b }
+2: { move r0, r1; jrp lr }
+ STD_ENDPROC(finv_user_asm)
+ .pushsection __ex_table,"a"
+ .word 1b, 2b
+ .popsection
diff --git a/arch/tile/mm/Makefile b/arch/tile/mm/Makefile
new file mode 100644
index 000000000000..e252aeddc17d
--- /dev/null
+++ b/arch/tile/mm/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux tile-specific parts of the memory manager.
+#
+
+obj-y := init.o pgtable.o fault.o extable.o elf.o \
+ mmap.o homecache.o migrate_$(BITS).o
+
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_HIGHMEM) += highmem.o
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c
new file mode 100644
index 000000000000..818c9bef060c
--- /dev/null
+++ b/arch/tile/mm/elf.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/binfmts.h>
+#include <linux/compat.h>
+#include <linux/mman.h>
+#include <linux/elf.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+
+/* Notify a running simulator, if any, that an exec just occurred. */
+static void sim_notify_exec(const char *binary_name)
+{
+ unsigned char c;
+ do {
+ c = *binary_name++;
+ __insn_mtspr(SPR_SIM_CONTROL,
+ (SIM_CONTROL_OS_EXEC
+ | (c << _SIM_CONTROL_OPERATOR_BITS)));
+
+ } while (c);
+}
+
+static int notify_exec(void)
+{
+ int retval = 0; /* failure */
+ struct vm_area_struct *vma = current->mm->mmap;
+ while (vma) {
+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
+ break;
+ vma = vma->vm_next;
+ }
+ if (vma) {
+ char *buf = (char *) __get_free_page(GFP_KERNEL);
+ if (buf) {
+ char *path = d_path(&vma->vm_file->f_path,
+ buf, PAGE_SIZE);
+ if (!IS_ERR(path)) {
+ sim_notify_exec(path);
+ retval = 1;
+ }
+ free_page((unsigned long)buf);
+ }
+ }
+ return retval;
+}
+
+/* Notify a running simulator, if any, that we loaded an interpreter. */
+static void sim_notify_interp(unsigned long load_addr)
+{
+ size_t i;
+ for (i = 0; i < sizeof(load_addr); i++) {
+ unsigned char c = load_addr >> (i * 8);
+ __insn_mtspr(SPR_SIM_CONTROL,
+ (SIM_CONTROL_OS_INTERP
+ | (c << _SIM_CONTROL_OPERATOR_BITS)));
+ }
+}
+
+
+/* Kernel address of page used to map read-only kernel data into userspace. */
+static void *vdso_page;
+
+/* One-entry array used for install_special_mapping. */
+static struct page *vdso_pages[1];
+
+int __init vdso_setup(void)
+{
+ extern char __rt_sigreturn[], __rt_sigreturn_end[];
+ vdso_page = (void *)get_zeroed_page(GFP_ATOMIC);
+ memcpy(vdso_page, __rt_sigreturn, __rt_sigreturn_end - __rt_sigreturn);
+ vdso_pages[0] = virt_to_page(vdso_page);
+ return 0;
+}
+device_initcall(vdso_setup);
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_private_data == vdso_pages)
+ return "[vdso]";
+#ifndef __tilegx__
+ if (vma->vm_start == MEM_USER_INTRPT)
+ return "[intrpt]";
+#endif
+ return NULL;
+}
+
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack)
+{
+ struct mm_struct *mm = current->mm;
+ unsigned long vdso_base;
+ int retval = 0;
+
+ /*
+ * Notify the simulator that an exec just occurred.
+ * If we can't find the filename of the mapping, just use
+ * whatever was passed as the linux_binprm filename.
+ */
+ if (!notify_exec())
+ sim_notify_exec(bprm->filename);
+
+ down_write(&mm->mmap_sem);
+
+ /*
+ * MAYWRITE to allow gdb to COW and set breakpoints
+ *
+ * Make sure the vDSO gets into every core dump. Dumping its
+ * contents makes post-mortem fully interpretable later
+ * without matching up the same kernel and hardware config to
+ * see what PC values meant.
+ */
+ vdso_base = VDSO_BASE;
+ retval = install_special_mapping(mm, vdso_base, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ vdso_pages);
+
+#ifndef __tilegx__
+ /*
+ * Set up a user-interrupt mapping here; the user can't
+ * create one themselves since it is above TASK_SIZE.
+ * We make it unwritable by default, so the model for adding
+ * interrupt vectors always involves an mprotect.
+ */
+ if (!retval) {
+ unsigned long addr = MEM_USER_INTRPT;
+ addr = mmap_region(NULL, addr, INTRPT_SIZE,
+ MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0);
+ if (addr > (unsigned long) -PAGE_SIZE)
+ retval = (int) addr;
+ }
+#endif
+
+ up_write(&mm->mmap_sem);
+
+ return retval;
+}
+
+
+void elf_plat_init(struct pt_regs *regs, unsigned long load_addr)
+{
+ /* Zero all registers. */
+ memset(regs, 0, sizeof(*regs));
+
+ /* Report the interpreter's load address. */
+ sim_notify_interp(load_addr);
+}
diff --git a/arch/tile/mm/extable.c b/arch/tile/mm/extable.c
new file mode 100644
index 000000000000..4fb0acb9d154
--- /dev/null
+++ b/arch/tile/mm/extable.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
new file mode 100644
index 000000000000..9b6b92f07def
--- /dev/null
+++ b/arch/tile/mm/fault.c
@@ -0,0 +1,905 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * From i386 code copyright (C) 1995 Linus Torvalds
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/vt_kern.h> /* For unblank_screen() */
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/hugetlb.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+
+#include <asm/system.h>
+#include <asm/pgalloc.h>
+#include <asm/sections.h>
+
+#include <arch/interrupts.h>
+
+/*
+ * Unlock any spinlocks which will prevent us from getting the
+ * message out
+ */
+void bust_spinlocks(int yes)
+{
+ int loglevel_save = console_loglevel;
+
+ if (yes) {
+ oops_in_progress = 1;
+ return;
+ }
+ oops_in_progress = 0;
+ /*
+ * OK, the message is on the console. Now we call printk()
+ * without oops_in_progress set so that printk will give klogd
+ * a poke. Hold onto your hats...
+ */
+ console_loglevel = 15; /* NMI oopser may have shut the console up */
+ printk(" ");
+ console_loglevel = loglevel_save;
+}
+
+static noinline void force_sig_info_fault(int si_signo, int si_code,
+ unsigned long address, int fault_num, struct task_struct *tsk)
+{
+ siginfo_t info;
+
+ if (unlikely(tsk->pid < 2)) {
+ panic("Signal %d (code %d) at %#lx sent to %s!",
+ si_signo, si_code & 0xffff, address,
+ tsk->pid ? "init" : "the idle task");
+ }
+
+ info.si_signo = si_signo;
+ info.si_errno = 0;
+ info.si_code = si_code;
+ info.si_addr = (void __user *)address;
+ info.si_trapno = fault_num;
+ force_sig_info(si_signo, &info, tsk);
+}
+
+#ifndef __tilegx__
+/*
+ * Synthesize the fault a PL0 process would get by doing a word-load of
+ * an unaligned address or a high kernel address. Called indirectly
+ * from sys_cmpxchg() in kernel/intvec.S.
+ */
+int _sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *regs)
+{
+ if (address >= PAGE_OFFSET)
+ force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address,
+ INT_DTLB_MISS, current);
+ else
+ force_sig_info_fault(SIGBUS, BUS_ADRALN, address,
+ INT_UNALIGN_DATA, current);
+
+ /*
+ * Adjust pc to point at the actual instruction, which is unusual
+ * for syscalls normally, but is appropriate when we are claiming
+ * that a syscall swint1 caused a page fault or bus error.
+ */
+ regs->pc -= 8;
+
+ /*
+ * Mark this as a caller-save interrupt, like a normal page fault,
+ * so that when we go through the signal handler path we will
+ * properly restore r0, r1, and r2 for the signal handler arguments.
+ */
+ regs->flags |= PT_FLAGS_CALLER_SAVES;
+
+ return 0;
+}
+#endif
+
+static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
+{
+ unsigned index = pgd_index(address);
+ pgd_t *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+
+ pgd += index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ return NULL;
+
+ pud = pud_offset(pgd, address);
+ pud_k = pud_offset(pgd_k, address);
+ if (!pud_present(*pud_k))
+ return NULL;
+
+ pmd = pmd_offset(pud, address);
+ pmd_k = pmd_offset(pud_k, address);
+ if (!pmd_present(*pmd_k))
+ return NULL;
+ if (!pmd_present(*pmd)) {
+ set_pmd(pmd, *pmd_k);
+ arch_flush_lazy_mmu_mode();
+ } else
+ BUG_ON(pmd_ptfn(*pmd) != pmd_ptfn(*pmd_k));
+ return pmd_k;
+}
+
+/*
+ * Handle a fault on the vmalloc or module mapping area
+ */
+static inline int vmalloc_fault(pgd_t *pgd, unsigned long address)
+{
+ pmd_t *pmd_k;
+ pte_t *pte_k;
+
+ /* Make sure we are in vmalloc area */
+ if (!(address >= VMALLOC_START && address < VMALLOC_END))
+ return -1;
+
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ */
+ pmd_k = vmalloc_sync_one(pgd, address);
+ if (!pmd_k)
+ return -1;
+ if (pmd_huge(*pmd_k))
+ return 0; /* support TILE huge_vmap() API */
+ pte_k = pte_offset_kernel(pmd_k, address);
+ if (!pte_present(*pte_k))
+ return -1;
+ return 0;
+}
+
+/* Wait until this PTE has completed migration. */
+static void wait_for_migration(pte_t *pte)
+{
+ if (pte_migrating(*pte)) {
+ /*
+ * Wait until the migrater fixes up this pte.
+ * We scale the loop count by the clock rate so we'll wait for
+ * a few seconds here.
+ */
+ int retries = 0;
+ int bound = get_clock_rate();
+ while (pte_migrating(*pte)) {
+ barrier();
+ if (++retries > bound)
+ panic("Hit migrating PTE (%#llx) and"
+ " page PFN %#lx still migrating",
+ pte->val, pte_pfn(*pte));
+ }
+ }
+}
+
+/*
+ * It's not generally safe to use "current" to get the page table pointer,
+ * since we might be running an oprofile interrupt in the middle of a
+ * task switch.
+ */
+static pgd_t *get_current_pgd(void)
+{
+ HV_Context ctx = hv_inquire_context();
+ unsigned long pgd_pfn = ctx.page_table >> PAGE_SHIFT;
+ struct page *pgd_page = pfn_to_page(pgd_pfn);
+ BUG_ON(PageHighMem(pgd_page)); /* oops, HIGHPTE? */
+ return (pgd_t *) __va(ctx.page_table);
+}
+
+/*
+ * We can receive a page fault from a migrating PTE at any time.
+ * Handle it by just waiting until the fault resolves.
+ *
+ * It's also possible to get a migrating kernel PTE that resolves
+ * itself during the downcall from hypervisor to Linux. We just check
+ * here to see if the PTE seems valid, and if so we retry it.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may be in an
+ * interrupt or a critical region, and must do as little as possible.
+ * Similarly, we can't use atomic ops here, since we may be handling a
+ * fault caused by an atomic op access.
+ */
+static int handle_migrating_pte(pgd_t *pgd, int fault_num,
+ unsigned long address,
+ int is_kernel_mode, int write)
+{
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ pte_t pteval;
+
+ if (pgd_addr_invalid(address))
+ return 0;
+
+ pgd += pgd_index(address);
+ pud = pud_offset(pgd, address);
+ if (!pud || !pud_present(*pud))
+ return 0;
+ pmd = pmd_offset(pud, address);
+ if (!pmd || !pmd_present(*pmd))
+ return 0;
+ pte = pmd_huge_page(*pmd) ? ((pte_t *)pmd) :
+ pte_offset_kernel(pmd, address);
+ pteval = *pte;
+ if (pte_migrating(pteval)) {
+ wait_for_migration(pte);
+ return 1;
+ }
+
+ if (!is_kernel_mode || !pte_present(pteval))
+ return 0;
+ if (fault_num == INT_ITLB_MISS) {
+ if (pte_exec(pteval))
+ return 1;
+ } else if (write) {
+ if (pte_write(pteval))
+ return 1;
+ } else {
+ if (pte_read(pteval))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * This routine is responsible for faulting in user pages.
+ * It passes the work off to one of the appropriate routines.
+ * It returns true if the fault was successfully handled.
+ */
+static int handle_page_fault(struct pt_regs *regs,
+ int fault_num,
+ int is_page_fault,
+ unsigned long address,
+ int write)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long stack_offset;
+ int fault;
+ int si_code;
+ int is_kernel_mode;
+ pgd_t *pgd;
+
+ /* on TILE, protection faults are always writes */
+ if (!is_page_fault)
+ write = 1;
+
+ is_kernel_mode = (EX1_PL(regs->ex1) != USER_PL);
+
+ tsk = validate_current();
+
+ /*
+ * Check to see if we might be overwriting the stack, and bail
+ * out if so. The page fault code is a relatively likely
+ * place to get trapped in an infinite regress, and once we
+ * overwrite the whole stack, it becomes very hard to recover.
+ */
+ stack_offset = stack_pointer & (THREAD_SIZE-1);
+ if (stack_offset < THREAD_SIZE / 8) {
+ printk(KERN_ALERT "Potential stack overrun: sp %#lx\n",
+ stack_pointer);
+ show_regs(regs);
+ printk(KERN_ALERT "Killing current process %d/%s\n",
+ tsk->pid, tsk->comm);
+ do_group_exit(SIGKILL);
+ }
+
+ /*
+ * Early on, we need to check for migrating PTE entries;
+ * see homecache.c. If we find a migrating PTE, we wait until
+ * the backing page claims to be done migrating, then we procede.
+ * For kernel PTEs, we rewrite the PTE and return and retry.
+ * Otherwise, we treat the fault like a normal "no PTE" fault,
+ * rather than trying to patch up the existing PTE.
+ */
+ pgd = get_current_pgd();
+ if (handle_migrating_pte(pgd, fault_num, address,
+ is_kernel_mode, write))
+ return 1;
+
+ si_code = SEGV_MAPERR;
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ *
+ * This verifies that the fault happens in kernel space
+ * and that the fault was not a protection fault.
+ */
+ if (unlikely(address >= TASK_SIZE &&
+ !is_arch_mappable_range(address, 0))) {
+ if (is_kernel_mode && is_page_fault &&
+ vmalloc_fault(pgd, address) >= 0)
+ return 1;
+ /*
+ * Don't take the mm semaphore here. If we fixup a prefetch
+ * fault we could otherwise deadlock.
+ */
+ mm = NULL; /* happy compiler */
+ vma = NULL;
+ goto bad_area_nosemaphore;
+ }
+
+ /*
+ * If we're trying to touch user-space addresses, we must
+ * be either at PL0, or else with interrupts enabled in the
+ * kernel, so either way we can re-enable interrupts here.
+ */
+ local_irq_enable();
+
+ mm = tsk->mm;
+
+ /*
+ * If we're in an interrupt, have no user context or are running in an
+ * atomic region then we must not take the fault.
+ */
+ if (in_atomic() || !mm) {
+ vma = NULL; /* happy compiler */
+ goto bad_area_nosemaphore;
+ }
+
+ /*
+ * When running in the kernel we expect faults to occur only to
+ * addresses in user space. All other faults represent errors in the
+ * kernel and should generate an OOPS. Unfortunately, in the case of an
+ * erroneous fault occurring in a code path which already holds mmap_sem
+ * we will deadlock attempting to validate the fault against the
+ * address space. Luckily the kernel only validly references user
+ * space from well defined areas of code, which are listed in the
+ * exceptions table.
+ *
+ * As the vast majority of faults will be valid we will only perform
+ * the source reference check when there is a possibility of a deadlock.
+ * Attempt to lock the address space, if we cannot we then validate the
+ * source. If this is invalid we can skip the address space check,
+ * thus avoiding the deadlock.
+ */
+ if (!down_read_trylock(&mm->mmap_sem)) {
+ if (is_kernel_mode &&
+ !search_exception_tables(regs->pc)) {
+ vma = NULL; /* happy compiler */
+ goto bad_area_nosemaphore;
+ }
+ down_read(&mm->mmap_sem);
+ }
+
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (regs->sp < PAGE_OFFSET) {
+ /*
+ * accessing the stack below sp is always a bug.
+ */
+ if (address < regs->sp)
+ goto bad_area;
+ }
+ if (expand_stack(vma, address))
+ goto bad_area;
+
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ si_code = SEGV_ACCERR;
+ if (fault_num == INT_ITLB_MISS) {
+ if (!(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+ } else if (write) {
+#ifdef TEST_VERIFY_AREA
+ if (!is_page_fault && regs->cs == KERNEL_CS)
+ printk("WP fault at "REGFMT"\n", regs->eip);
+#endif
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else {
+ if (!is_page_fault || !(vma->vm_flags & VM_READ))
+ goto bad_area;
+ }
+
+ survive:
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ fault = handle_mm_fault(mm, vma, address, write);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
+ /*
+ * If this was an asynchronous fault,
+ * restart the appropriate engine.
+ */
+ switch (fault_num) {
+#if CHIP_HAS_TILE_DMA()
+ case INT_DMATLB_MISS:
+ case INT_DMATLB_MISS_DWNCL:
+ case INT_DMATLB_ACCESS:
+ case INT_DMATLB_ACCESS_DWNCL:
+ __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK);
+ break;
+#endif
+#if CHIP_HAS_SN_PROC()
+ case INT_SNITLB_MISS:
+ case INT_SNITLB_MISS_DWNCL:
+ __insn_mtspr(SPR_SNCTL,
+ __insn_mfspr(SPR_SNCTL) &
+ ~SPR_SNCTL__FRZPROC_MASK);
+ break;
+#endif
+ }
+
+ up_read(&mm->mmap_sem);
+ return 1;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+ /* User mode accesses just cause a SIGSEGV */
+ if (!is_kernel_mode) {
+ /*
+ * It's possible to have interrupts off here.
+ */
+ local_irq_enable();
+
+ force_sig_info_fault(SIGSEGV, si_code, address,
+ fault_num, tsk);
+ return 0;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if (fixup_exception(regs))
+ return 0;
+
+/*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+
+ bust_spinlocks(1);
+
+ /* FIXME: no lookup_address() yet */
+#ifdef SUPPORT_LOOKUP_ADDRESS
+ if (fault_num == INT_ITLB_MISS) {
+ pte_t *pte = lookup_address(address);
+
+ if (pte && pte_present(*pte) && !pte_exec_kernel(*pte))
+ printk(KERN_CRIT "kernel tried to execute"
+ " non-executable page - exploit attempt?"
+ " (uid: %d)\n", current->uid);
+ }
+#endif
+ if (address < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference\n");
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request\n");
+ printk(" at virtual address "REGFMT", pc "REGFMT"\n",
+ address, regs->pc);
+
+ show_regs(regs);
+
+ if (unlikely(tsk->pid < 2)) {
+ panic("Kernel page fault running %s!",
+ tsk->pid ? "init" : "the idle task");
+ }
+
+ /*
+ * More FIXME: we should probably copy the i386 here and
+ * implement a generic die() routine. Not today.
+ */
+#ifdef SUPPORT_DIE
+ die("Oops", regs);
+#endif
+ bust_spinlocks(1);
+
+ do_group_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ up_read(&mm->mmap_sem);
+ if (is_global_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ printk("VM: killing process %s\n", tsk->comm);
+ if (!is_kernel_mode)
+ do_group_exit(SIGKILL);
+ goto no_context;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (is_kernel_mode)
+ goto no_context;
+
+ force_sig_info_fault(SIGBUS, BUS_ADRERR, address, fault_num, tsk);
+ return 0;
+}
+
+#ifndef __tilegx__
+
+extern char sys_cmpxchg[], __sys_cmpxchg_end[];
+extern char __sys_cmpxchg_grab_lock[];
+extern char __start_atomic_asm_code[], __end_atomic_asm_code[];
+
+/*
+ * We return this structure in registers to avoid having to write
+ * additional save/restore code in the intvec.S caller.
+ */
+struct intvec_state {
+ void *handler;
+ unsigned long vecnum;
+ unsigned long fault_num;
+ unsigned long info;
+ unsigned long retval;
+};
+
+/* We must release ICS before panicking or we won't get anywhere. */
+#define ics_panic(fmt, ...) do { \
+ __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); \
+ panic(fmt, __VA_ARGS__); \
+} while (0)
+
+void do_page_fault(struct pt_regs *regs, int fault_num,
+ unsigned long address, unsigned long write);
+
+/*
+ * When we take an ITLB or DTLB fault or access violation in the
+ * supervisor while the critical section bit is set, the hypervisor is
+ * reluctant to write new values into the EX_CONTEXT_1_x registers,
+ * since that might indicate we have not yet squirreled the SPR
+ * contents away and can thus safely take a recursive interrupt.
+ * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_1_2.
+ */
+struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num,
+ unsigned long address,
+ unsigned long info)
+{
+ unsigned long pc = info & ~1;
+ int write = info & 1;
+ pgd_t *pgd = get_current_pgd();
+
+ /* Retval is 1 at first since we will handle the fault fully. */
+ struct intvec_state state = {
+ do_page_fault, fault_num, address, write, 1
+ };
+
+ /* Validate that we are plausibly in the right routine. */
+ if ((pc & 0x7) != 0 || pc < PAGE_OFFSET ||
+ (fault_num != INT_DTLB_MISS &&
+ fault_num != INT_DTLB_ACCESS)) {
+ unsigned long old_pc = regs->pc;
+ regs->pc = pc;
+ ics_panic("Bad ICS page fault args:"
+ " old PC %#lx, fault %d/%d at %#lx\n",
+ old_pc, fault_num, write, address);
+ }
+
+ /* We might be faulting on a vmalloc page, so check that first. */
+ if (fault_num != INT_DTLB_ACCESS && vmalloc_fault(pgd, address) >= 0)
+ return state;
+
+ /*
+ * If we faulted with ICS set in sys_cmpxchg, we are providing
+ * a user syscall service that should generate a signal on
+ * fault. We didn't set up a kernel stack on initial entry to
+ * sys_cmpxchg, but instead had one set up by the fault, which
+ * (because sys_cmpxchg never releases ICS) came to us via the
+ * SYSTEM_SAVE_1_2 mechanism, and thus EX_CONTEXT_1_[01] are
+ * still referencing the original user code. We release the
+ * atomic lock and rewrite pt_regs so that it appears that we
+ * came from user-space directly, and after we finish the
+ * fault we'll go back to user space and re-issue the swint.
+ * This way the backtrace information is correct if we need to
+ * emit a stack dump at any point while handling this.
+ *
+ * Must match register use in sys_cmpxchg().
+ */
+ if (pc >= (unsigned long) sys_cmpxchg &&
+ pc < (unsigned long) __sys_cmpxchg_end) {
+#ifdef CONFIG_SMP
+ /* Don't unlock before we could have locked. */
+ if (pc >= (unsigned long)__sys_cmpxchg_grab_lock) {
+ int *lock_ptr = (int *)(regs->regs[ATOMIC_LOCK_REG]);
+ __atomic_fault_unlock(lock_ptr);
+ }
+#endif
+ regs->sp = regs->regs[27];
+ }
+
+ /*
+ * We can also fault in the atomic assembly, in which
+ * case we use the exception table to do the first-level fixup.
+ * We may re-fixup again in the real fault handler if it
+ * turns out the faulting address is just bad, and not,
+ * for example, migrating.
+ */
+ else if (pc >= (unsigned long) __start_atomic_asm_code &&
+ pc < (unsigned long) __end_atomic_asm_code) {
+ const struct exception_table_entry *fixup;
+#ifdef CONFIG_SMP
+ /* Unlock the atomic lock. */
+ int *lock_ptr = (int *)(regs->regs[ATOMIC_LOCK_REG]);
+ __atomic_fault_unlock(lock_ptr);
+#endif
+ fixup = search_exception_tables(pc);
+ if (!fixup)
+ ics_panic("ICS atomic fault not in table:"
+ " PC %#lx, fault %d", pc, fault_num);
+ regs->pc = fixup->fixup;
+ regs->ex1 = PL_ICS_EX1(KERNEL_PL, 0);
+ }
+
+ /*
+ * NOTE: the one other type of access that might bring us here
+ * are the memory ops in __tns_atomic_acquire/__tns_atomic_release,
+ * but we don't have to check specially for them since we can
+ * always safely return to the address of the fault and retry,
+ * since no separate atomic locks are involved.
+ */
+
+ /*
+ * Now that we have released the atomic lock (if necessary),
+ * it's safe to spin if the PTE that caused the fault was migrating.
+ */
+ if (fault_num == INT_DTLB_ACCESS)
+ write = 1;
+ if (handle_migrating_pte(pgd, fault_num, address, 1, write))
+ return state;
+
+ /* Return zero so that we continue on with normal fault handling. */
+ state.retval = 0;
+ return state;
+}
+
+#endif /* !__tilegx__ */
+
+/*
+ * This routine handles page faults. It determines the address, and the
+ * problem, and then passes it handle_page_fault() for normal DTLB and
+ * ITLB issues, and for DMA or SN processor faults when we are in user
+ * space. For the latter, if we're in kernel mode, we just save the
+ * interrupt away appropriately and return immediately. We can't do
+ * page faults for user code while in kernel mode.
+ */
+void do_page_fault(struct pt_regs *regs, int fault_num,
+ unsigned long address, unsigned long write)
+{
+ int is_page_fault;
+
+ /* This case should have been handled by do_page_fault_ics(). */
+ BUG_ON(write & ~1);
+
+#if CHIP_HAS_TILE_DMA()
+ /*
+ * If it's a DMA fault, suspend the transfer while we're
+ * handling the miss; we'll restart after it's handled. If we
+ * don't suspend, it's possible that this process could swap
+ * out and back in, and restart the engine since the DMA is
+ * still 'running'.
+ */
+ if (fault_num == INT_DMATLB_MISS ||
+ fault_num == INT_DMATLB_ACCESS ||
+ fault_num == INT_DMATLB_MISS_DWNCL ||
+ fault_num == INT_DMATLB_ACCESS_DWNCL) {
+ __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK);
+ while (__insn_mfspr(SPR_DMA_USER_STATUS) &
+ SPR_DMA_STATUS__BUSY_MASK)
+ ;
+ }
+#endif
+
+ /* Validate fault num and decide if this is a first-time page fault. */
+ switch (fault_num) {
+ case INT_ITLB_MISS:
+ case INT_DTLB_MISS:
+#if CHIP_HAS_TILE_DMA()
+ case INT_DMATLB_MISS:
+ case INT_DMATLB_MISS_DWNCL:
+#endif
+#if CHIP_HAS_SN_PROC()
+ case INT_SNITLB_MISS:
+ case INT_SNITLB_MISS_DWNCL:
+#endif
+ is_page_fault = 1;
+ break;
+
+ case INT_DTLB_ACCESS:
+#if CHIP_HAS_TILE_DMA()
+ case INT_DMATLB_ACCESS:
+ case INT_DMATLB_ACCESS_DWNCL:
+#endif
+ is_page_fault = 0;
+ break;
+
+ default:
+ panic("Bad fault number %d in do_page_fault", fault_num);
+ }
+
+ if (EX1_PL(regs->ex1) != USER_PL) {
+ struct async_tlb *async;
+ switch (fault_num) {
+#if CHIP_HAS_TILE_DMA()
+ case INT_DMATLB_MISS:
+ case INT_DMATLB_ACCESS:
+ case INT_DMATLB_MISS_DWNCL:
+ case INT_DMATLB_ACCESS_DWNCL:
+ async = &current->thread.dma_async_tlb;
+ break;
+#endif
+#if CHIP_HAS_SN_PROC()
+ case INT_SNITLB_MISS:
+ case INT_SNITLB_MISS_DWNCL:
+ async = &current->thread.sn_async_tlb;
+ break;
+#endif
+ default:
+ async = NULL;
+ }
+ if (async) {
+
+ /*
+ * No vmalloc check required, so we can allow
+ * interrupts immediately at this point.
+ */
+ local_irq_enable();
+
+ set_thread_flag(TIF_ASYNC_TLB);
+ if (async->fault_num != 0) {
+ panic("Second async fault %d;"
+ " old fault was %d (%#lx/%ld)",
+ fault_num, async->fault_num,
+ address, write);
+ }
+ BUG_ON(fault_num == 0);
+ async->fault_num = fault_num;
+ async->is_fault = is_page_fault;
+ async->is_write = write;
+ async->address = address;
+ return;
+ }
+ }
+
+ handle_page_fault(regs, fault_num, is_page_fault, address, write);
+}
+
+
+#if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
+/*
+ * Check an async_tlb structure to see if a deferred fault is waiting,
+ * and if so pass it to the page-fault code.
+ */
+static void handle_async_page_fault(struct pt_regs *regs,
+ struct async_tlb *async)
+{
+ if (async->fault_num) {
+ /*
+ * Clear async->fault_num before calling the page-fault
+ * handler so that if we re-interrupt before returning
+ * from the function we have somewhere to put the
+ * information from the new interrupt.
+ */
+ int fault_num = async->fault_num;
+ async->fault_num = 0;
+ handle_page_fault(regs, fault_num, async->is_fault,
+ async->address, async->is_write);
+ }
+}
+#endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */
+
+
+/*
+ * This routine effectively re-issues asynchronous page faults
+ * when we are returning to user space.
+ */
+void do_async_page_fault(struct pt_regs *regs)
+{
+ /*
+ * Clear thread flag early. If we re-interrupt while processing
+ * code here, we will reset it and recall this routine before
+ * returning to user space.
+ */
+ clear_thread_flag(TIF_ASYNC_TLB);
+
+#if CHIP_HAS_TILE_DMA()
+ handle_async_page_fault(regs, &current->thread.dma_async_tlb);
+#endif
+#if CHIP_HAS_SN_PROC()
+ handle_async_page_fault(regs, &current->thread.sn_async_tlb);
+#endif
+}
+
+void vmalloc_sync_all(void)
+{
+#ifdef __tilegx__
+ /* Currently all L1 kernel pmd's are static and shared. */
+ BUG_ON(pgd_index(VMALLOC_END) != pgd_index(VMALLOC_START));
+#else
+ /*
+ * Note that races in the updates of insync and start aren't
+ * problematic: insync can only get set bits added, and updates to
+ * start are only improving performance (without affecting correctness
+ * if undone).
+ */
+ static DECLARE_BITMAP(insync, PTRS_PER_PGD);
+ static unsigned long start = PAGE_OFFSET;
+ unsigned long address;
+
+ BUILD_BUG_ON(PAGE_OFFSET & ~PGDIR_MASK);
+ for (address = start; address >= PAGE_OFFSET; address += PGDIR_SIZE) {
+ if (!test_bit(pgd_index(address), insync)) {
+ unsigned long flags;
+ struct list_head *pos;
+
+ spin_lock_irqsave(&pgd_lock, flags);
+ list_for_each(pos, &pgd_list)
+ if (!vmalloc_sync_one(list_to_pgd(pos),
+ address)) {
+ /* Must be at first entry in list. */
+ BUG_ON(pos != pgd_list.next);
+ break;
+ }
+ spin_unlock_irqrestore(&pgd_lock, flags);
+ if (pos != pgd_list.next)
+ set_bit(pgd_index(address), insync);
+ }
+ if (address == start && test_bit(pgd_index(address), insync))
+ start = address + PGDIR_SIZE;
+ }
+#endif
+}
diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c
new file mode 100644
index 000000000000..1fcecc5b9e03
--- /dev/null
+++ b/arch/tile/mm/highmem.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <asm/homecache.h>
+
+#define kmap_get_pte(vaddr) \
+ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\
+ (vaddr)), (vaddr))
+
+
+void *kmap(struct page *page)
+{
+ void *kva;
+ unsigned long flags;
+ pte_t *ptep;
+
+ might_sleep();
+ if (!PageHighMem(page))
+ return page_address(page);
+ kva = kmap_high(page);
+
+ /*
+ * Rewrite the PTE under the lock. This ensures that the page
+ * is not currently migrating.
+ */
+ ptep = kmap_get_pte((unsigned long)kva);
+ flags = homecache_kpte_lock();
+ set_pte_at(&init_mm, kva, ptep, mk_pte(page, page_to_kpgprot(page)));
+ homecache_kpte_unlock(flags);
+
+ return kva;
+}
+EXPORT_SYMBOL(kmap);
+
+void kunmap(struct page *page)
+{
+ if (in_interrupt())
+ BUG();
+ if (!PageHighMem(page))
+ return;
+ kunmap_high(page);
+}
+EXPORT_SYMBOL(kunmap);
+
+static void debug_kmap_atomic_prot(enum km_type type)
+{
+#ifdef CONFIG_DEBUG_HIGHMEM
+ static unsigned warn_count = 10;
+
+ if (unlikely(warn_count == 0))
+ return;
+
+ if (unlikely(in_interrupt())) {
+ if (in_irq()) {
+ if (type != KM_IRQ0 && type != KM_IRQ1 &&
+ type != KM_BIO_SRC_IRQ &&
+ /* type != KM_BIO_DST_IRQ && */
+ type != KM_BOUNCE_READ) {
+ WARN_ON(1);
+ warn_count--;
+ }
+ } else if (!irqs_disabled()) { /* softirq */
+ if (type != KM_IRQ0 && type != KM_IRQ1 &&
+ type != KM_SOFTIRQ0 && type != KM_SOFTIRQ1 &&
+ type != KM_SKB_SUNRPC_DATA &&
+ type != KM_SKB_DATA_SOFTIRQ &&
+ type != KM_BOUNCE_READ) {
+ WARN_ON(1);
+ warn_count--;
+ }
+ }
+ }
+
+ if (type == KM_IRQ0 || type == KM_IRQ1 || type == KM_BOUNCE_READ ||
+ type == KM_BIO_SRC_IRQ /* || type == KM_BIO_DST_IRQ */) {
+ if (!irqs_disabled()) {
+ WARN_ON(1);
+ warn_count--;
+ }
+ } else if (type == KM_SOFTIRQ0 || type == KM_SOFTIRQ1) {
+ if (irq_count() == 0 && !irqs_disabled()) {
+ WARN_ON(1);
+ warn_count--;
+ }
+ }
+#endif
+}
+
+/*
+ * Describe a single atomic mapping of a page on a given cpu at a
+ * given address, and allow it to be linked into a list.
+ */
+struct atomic_mapped_page {
+ struct list_head list;
+ struct page *page;
+ int cpu;
+ unsigned long va;
+};
+
+static spinlock_t amp_lock = __SPIN_LOCK_UNLOCKED(&amp_lock);
+static struct list_head amp_list = LIST_HEAD_INIT(amp_list);
+
+/*
+ * Combining this structure with a per-cpu declaration lets us give
+ * each cpu an atomic_mapped_page structure per type.
+ */
+struct kmap_amps {
+ struct atomic_mapped_page per_type[KM_TYPE_NR];
+};
+DEFINE_PER_CPU(struct kmap_amps, amps);
+
+/*
+ * Add a page and va, on this cpu, to the list of kmap_atomic pages,
+ * and write the new pte to memory. Writing the new PTE under the
+ * lock guarantees that it is either on the list before migration starts
+ * (if we won the race), or set_pte() sets the migrating bit in the PTE
+ * (if we lost the race). And doing it under the lock guarantees
+ * that when kmap_atomic_fix_one_pte() comes along, it finds a valid
+ * PTE in memory, iff the mapping is still on the amp_list.
+ *
+ * Finally, doing it under the lock lets us safely examine the page
+ * to see if it is immutable or not, for the generic kmap_atomic() case.
+ * If we examine it earlier we are exposed to a race where it looks
+ * writable earlier, but becomes immutable before we write the PTE.
+ */
+static void kmap_atomic_register(struct page *page, enum km_type type,
+ unsigned long va, pte_t *ptep, pte_t pteval)
+{
+ unsigned long flags;
+ struct atomic_mapped_page *amp;
+
+ flags = homecache_kpte_lock();
+ spin_lock(&amp_lock);
+
+ /* With interrupts disabled, now fill in the per-cpu info. */
+ amp = &__get_cpu_var(amps).per_type[type];
+ amp->page = page;
+ amp->cpu = smp_processor_id();
+ amp->va = va;
+
+ /* For generic kmap_atomic(), choose the PTE writability now. */
+ if (!pte_read(pteval))
+ pteval = mk_pte(page, page_to_kpgprot(page));
+
+ list_add(&amp->list, &amp_list);
+ set_pte(ptep, pteval);
+ arch_flush_lazy_mmu_mode();
+
+ spin_unlock(&amp_lock);
+ homecache_kpte_unlock(flags);
+}
+
+/*
+ * Remove a page and va, on this cpu, from the list of kmap_atomic pages.
+ * Linear-time search, but we count on the lists being short.
+ * We don't need to adjust the PTE under the lock (as opposed to the
+ * kmap_atomic_register() case), since we're just unconditionally
+ * zeroing the PTE after it's off the list.
+ */
+static void kmap_atomic_unregister(struct page *page, unsigned long va)
+{
+ unsigned long flags;
+ struct atomic_mapped_page *amp;
+ int cpu = smp_processor_id();
+ spin_lock_irqsave(&amp_lock, flags);
+ list_for_each_entry(amp, &amp_list, list) {
+ if (amp->page == page && amp->cpu == cpu && amp->va == va)
+ break;
+ }
+ BUG_ON(&amp->list == &amp_list);
+ list_del(&amp->list);
+ spin_unlock_irqrestore(&amp_lock, flags);
+}
+
+/* Helper routine for kmap_atomic_fix_kpte(), below. */
+static void kmap_atomic_fix_one_kpte(struct atomic_mapped_page *amp,
+ int finished)
+{
+ pte_t *ptep = kmap_get_pte(amp->va);
+ if (!finished) {
+ set_pte(ptep, pte_mkmigrate(*ptep));
+ flush_remote(0, 0, NULL, amp->va, PAGE_SIZE, PAGE_SIZE,
+ cpumask_of(amp->cpu), NULL, 0);
+ } else {
+ /*
+ * Rewrite a default kernel PTE for this page.
+ * We rely on the fact that set_pte() writes the
+ * present+migrating bits last.
+ */
+ pte_t pte = mk_pte(amp->page, page_to_kpgprot(amp->page));
+ set_pte(ptep, pte);
+ }
+}
+
+/*
+ * This routine is a helper function for homecache_fix_kpte(); see
+ * its comments for more information on the "finished" argument here.
+ *
+ * Note that we hold the lock while doing the remote flushes, which
+ * will stall any unrelated cpus trying to do kmap_atomic operations.
+ * We could just update the PTEs under the lock, and save away copies
+ * of the structs (or just the va+cpu), then flush them after we
+ * release the lock, but it seems easier just to do it all under the lock.
+ */
+void kmap_atomic_fix_kpte(struct page *page, int finished)
+{
+ struct atomic_mapped_page *amp;
+ unsigned long flags;
+ spin_lock_irqsave(&amp_lock, flags);
+ list_for_each_entry(amp, &amp_list, list) {
+ if (amp->page == page)
+ kmap_atomic_fix_one_kpte(amp, finished);
+ }
+ spin_unlock_irqrestore(&amp_lock, flags);
+}
+
+/*
+ * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap
+ * because the kmap code must perform a global TLB invalidation when
+ * the kmap pool wraps.
+ *
+ * Note that they may be slower than on x86 (etc.) because unlike on
+ * those platforms, we do have to take a global lock to map and unmap
+ * pages on Tile (see above).
+ *
+ * When holding an atomic kmap is is not legal to sleep, so atomic
+ * kmaps are appropriate for short, tight code paths only.
+ */
+void *kmap_atomic_prot(struct page *page, enum km_type type, pgprot_t prot)
+{
+ enum fixed_addresses idx;
+ unsigned long vaddr;
+ pte_t *pte;
+
+ /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */
+ pagefault_disable();
+
+ /* Avoid icache flushes by disallowing atomic executable mappings. */
+ BUG_ON(pte_exec(prot));
+
+ if (!PageHighMem(page))
+ return page_address(page);
+
+ debug_kmap_atomic_prot(type);
+
+ idx = type + KM_TYPE_NR*smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ pte = kmap_get_pte(vaddr);
+ BUG_ON(!pte_none(*pte));
+
+ /* Register that this page is mapped atomically on this cpu. */
+ kmap_atomic_register(page, type, vaddr, pte, mk_pte(page, prot));
+
+ return (void *)vaddr;
+}
+EXPORT_SYMBOL(kmap_atomic_prot);
+
+void *kmap_atomic(struct page *page, enum km_type type)
+{
+ /* PAGE_NONE is a magic value that tells us to check immutability. */
+ return kmap_atomic_prot(page, type, PAGE_NONE);
+}
+EXPORT_SYMBOL(kmap_atomic);
+
+void kunmap_atomic(void *kvaddr, enum km_type type)
+{
+ unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
+ enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+
+ /*
+ * Force other mappings to Oops if they try to access this pte without
+ * first remapping it. Keeping stale mappings around is a bad idea.
+ */
+ if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) {
+ pte_t *pte = kmap_get_pte(vaddr);
+ pte_t pteval = *pte;
+ BUG_ON(!pte_present(pteval) && !pte_migrating(pteval));
+ kmap_atomic_unregister(pte_page(pteval), vaddr);
+ kpte_clear_flush(pte, vaddr);
+ } else {
+ /* Must be a lowmem page */
+ BUG_ON(vaddr < PAGE_OFFSET);
+ BUG_ON(vaddr >= (unsigned long)high_memory);
+ }
+
+ arch_flush_lazy_mmu_mode();
+ pagefault_enable();
+}
+EXPORT_SYMBOL(kunmap_atomic);
+
+/*
+ * This API is supposed to allow us to map memory without a "struct page".
+ * Currently we don't support this, though this may change in the future.
+ */
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+{
+ return kmap_atomic(pfn_to_page(pfn), type);
+}
+void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot)
+{
+ return kmap_atomic_prot(pfn_to_page(pfn), type, prot);
+}
+
+struct page *kmap_atomic_to_page(void *ptr)
+{
+ pte_t *pte;
+ unsigned long vaddr = (unsigned long)ptr;
+
+ if (vaddr < FIXADDR_START)
+ return virt_to_page(ptr);
+
+ pte = kmap_get_pte(vaddr);
+ return pte_page(*pte);
+}
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
new file mode 100644
index 000000000000..52feb77133ce
--- /dev/null
+++ b/arch/tile/mm/homecache.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This code maintains the "home" for each page in the system.
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/bootmem.h>
+#include <linux/rmap.h>
+#include <linux/pagemap.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/sysctl.h>
+#include <linux/pagevec.h>
+#include <linux/ptrace.h>
+#include <linux/timex.h>
+#include <linux/cache.h>
+#include <linux/smp.h>
+
+#include <asm/page.h>
+#include <asm/sections.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+#include <asm/homecache.h>
+
+#include "migrate.h"
+
+
+#if CHIP_HAS_COHERENT_LOCAL_CACHE()
+
+/*
+ * The noallocl2 option suppresses all use of the L2 cache to cache
+ * locally from a remote home. There's no point in using it if we
+ * don't have coherent local caching, though.
+ */
+int __write_once noallocl2;
+static int __init set_noallocl2(char *str)
+{
+ noallocl2 = 1;
+ return 0;
+}
+early_param("noallocl2", set_noallocl2);
+
+#else
+
+#define noallocl2 0
+
+#endif
+
+
+
+/* Provide no-op versions of these routines to keep flush_remote() cleaner. */
+#define mark_caches_evicted_start() 0
+#define mark_caches_evicted_finish(mask, timestamp) do {} while (0)
+
+
+
+
+/*
+ * Update the irq_stat for cpus that we are going to interrupt
+ * with TLB or cache flushes. Also handle removing dataplane cpus
+ * from the TLB flush set, and setting dataplane_tlb_state instead.
+ */
+static void hv_flush_update(const struct cpumask *cache_cpumask,
+ struct cpumask *tlb_cpumask,
+ unsigned long tlb_va, unsigned long tlb_length,
+ HV_Remote_ASID *asids, int asidcount)
+{
+ struct cpumask mask;
+ int i, cpu;
+
+ cpumask_clear(&mask);
+ if (cache_cpumask)
+ cpumask_or(&mask, &mask, cache_cpumask);
+ if (tlb_cpumask && tlb_length) {
+ cpumask_or(&mask, &mask, tlb_cpumask);
+ }
+
+ for (i = 0; i < asidcount; ++i)
+ cpumask_set_cpu(asids[i].y * smp_width + asids[i].x, &mask);
+
+ /*
+ * Don't bother to update atomically; losing a count
+ * here is not that critical.
+ */
+ for_each_cpu(cpu, &mask)
+ ++per_cpu(irq_stat, cpu).irq_hv_flush_count;
+}
+
+/*
+ * This wrapper function around hv_flush_remote() does several things:
+ *
+ * - Provides a return value error-checking panic path, since
+ * there's never any good reason for hv_flush_remote() to fail.
+ * - Accepts a 32-bit PFN rather than a 64-bit PA, which generally
+ * is the type that Linux wants to pass around anyway.
+ * - Centralizes the mark_caches_evicted() handling.
+ * - Canonicalizes that lengths of zero make cpumasks NULL.
+ * - Handles deferring TLB flushes for dataplane tiles.
+ * - Tracks remote interrupts in the per-cpu irq_cpustat_t.
+ *
+ * Note that we have to wait until the cache flush completes before
+ * updating the per-cpu last_cache_flush word, since otherwise another
+ * concurrent flush can race, conclude the flush has already
+ * completed, and start to use the page while it's still dirty
+ * remotely (running concurrently with the actual evict, presumably).
+ */
+void flush_remote(unsigned long cache_pfn, unsigned long cache_control,
+ const struct cpumask *cache_cpumask_orig,
+ HV_VirtAddr tlb_va, unsigned long tlb_length,
+ unsigned long tlb_pgsize,
+ const struct cpumask *tlb_cpumask_orig,
+ HV_Remote_ASID *asids, int asidcount)
+{
+ int rc;
+ int timestamp = 0; /* happy compiler */
+ struct cpumask cache_cpumask_copy, tlb_cpumask_copy;
+ struct cpumask *cache_cpumask, *tlb_cpumask;
+ HV_PhysAddr cache_pa;
+ char cache_buf[NR_CPUS*5], tlb_buf[NR_CPUS*5];
+
+ mb(); /* provided just to simplify "magic hypervisor" mode */
+
+ /*
+ * Canonicalize and copy the cpumasks.
+ */
+ if (cache_cpumask_orig && cache_control) {
+ cpumask_copy(&cache_cpumask_copy, cache_cpumask_orig);
+ cache_cpumask = &cache_cpumask_copy;
+ } else {
+ cpumask_clear(&cache_cpumask_copy);
+ cache_cpumask = NULL;
+ }
+ if (cache_cpumask == NULL)
+ cache_control = 0;
+ if (tlb_cpumask_orig && tlb_length) {
+ cpumask_copy(&tlb_cpumask_copy, tlb_cpumask_orig);
+ tlb_cpumask = &tlb_cpumask_copy;
+ } else {
+ cpumask_clear(&tlb_cpumask_copy);
+ tlb_cpumask = NULL;
+ }
+
+ hv_flush_update(cache_cpumask, tlb_cpumask, tlb_va, tlb_length,
+ asids, asidcount);
+ cache_pa = (HV_PhysAddr)cache_pfn << PAGE_SHIFT;
+ if (cache_control & HV_FLUSH_EVICT_L2)
+ timestamp = mark_caches_evicted_start();
+ rc = hv_flush_remote(cache_pa, cache_control,
+ cpumask_bits(cache_cpumask),
+ tlb_va, tlb_length, tlb_pgsize,
+ cpumask_bits(tlb_cpumask),
+ asids, asidcount);
+ if (cache_control & HV_FLUSH_EVICT_L2)
+ mark_caches_evicted_finish(cache_cpumask, timestamp);
+ if (rc == 0)
+ return;
+ cpumask_scnprintf(cache_buf, sizeof(cache_buf), &cache_cpumask_copy);
+ cpumask_scnprintf(tlb_buf, sizeof(tlb_buf), &tlb_cpumask_copy);
+
+ printk("hv_flush_remote(%#llx, %#lx, %p [%s],"
+ " %#lx, %#lx, %#lx, %p [%s], %p, %d) = %d\n",
+ cache_pa, cache_control, cache_cpumask, cache_buf,
+ (unsigned long)tlb_va, tlb_length, tlb_pgsize,
+ tlb_cpumask, tlb_buf,
+ asids, asidcount, rc);
+ if (asidcount > 0) {
+ int i;
+ printk(" asids:");
+ for (i = 0; i < asidcount; ++i)
+ printk(" %d,%d,%d",
+ asids[i].x, asids[i].y, asids[i].asid);
+ printk("\n");
+ }
+ panic("Unsafe to continue.");
+}
+
+void homecache_evict(const struct cpumask *mask)
+{
+ flush_remote(0, HV_FLUSH_EVICT_L2, mask, 0, 0, 0, NULL, NULL, 0);
+}
+
+/* Return a mask of the cpus whose caches currently own these pages. */
+static void homecache_mask(struct page *page, int pages,
+ struct cpumask *home_mask)
+{
+ int i;
+ cpumask_clear(home_mask);
+ for (i = 0; i < pages; ++i) {
+ int home = page_home(&page[i]);
+ if (home == PAGE_HOME_IMMUTABLE ||
+ home == PAGE_HOME_INCOHERENT) {
+ cpumask_copy(home_mask, cpu_possible_mask);
+ return;
+ }
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (home == PAGE_HOME_HASH) {
+ cpumask_or(home_mask, home_mask, &hash_for_home_map);
+ continue;
+ }
+#endif
+ if (home == PAGE_HOME_UNCACHED)
+ continue;
+ BUG_ON(home < 0 || home >= NR_CPUS);
+ cpumask_set_cpu(home, home_mask);
+ }
+}
+
+/*
+ * Return the passed length, or zero if it's long enough that we
+ * believe we should evict the whole L2 cache.
+ */
+static unsigned long cache_flush_length(unsigned long length)
+{
+ return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
+}
+
+/* On the simulator, confirm lines have been evicted everywhere. */
+static void validate_lines_evicted(unsigned long pfn, size_t length)
+{
+ sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
+ (HV_PhysAddr)pfn << PAGE_SHIFT, length);
+}
+
+/* Flush a page out of whatever cache(s) it is in. */
+void homecache_flush_cache(struct page *page, int order)
+{
+ int pages = 1 << order;
+ int length = cache_flush_length(pages * PAGE_SIZE);
+ unsigned long pfn = page_to_pfn(page);
+ struct cpumask home_mask;
+
+ homecache_mask(page, pages, &home_mask);
+ flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
+ validate_lines_evicted(pfn, pages * PAGE_SIZE);
+}
+
+
+/* Report the home corresponding to a given PTE. */
+static int pte_to_home(pte_t pte)
+{
+ if (hv_pte_get_nc(pte))
+ return PAGE_HOME_IMMUTABLE;
+ switch (hv_pte_get_mode(pte)) {
+ case HV_PTE_MODE_CACHE_TILE_L3:
+ return get_remote_cache_cpu(pte);
+ case HV_PTE_MODE_CACHE_NO_L3:
+ return PAGE_HOME_INCOHERENT;
+ case HV_PTE_MODE_UNCACHED:
+ return PAGE_HOME_UNCACHED;
+#if CHIP_HAS_CBOX_HOME_MAP()
+ case HV_PTE_MODE_CACHE_HASH_L3:
+ return PAGE_HOME_HASH;
+#endif
+ }
+ panic("Bad PTE %#llx\n", pte.val);
+}
+
+/* Update the home of a PTE if necessary (can also be used for a pgprot_t). */
+pte_t pte_set_home(pte_t pte, int home)
+{
+ /* Check for non-linear file mapping "PTEs" and pass them through. */
+ if (pte_file(pte))
+ return pte;
+
+#if CHIP_HAS_MMIO()
+ /* Check for MMIO mappings and pass them through. */
+ if (hv_pte_get_mode(pte) == HV_PTE_MODE_MMIO)
+ return pte;
+#endif
+
+
+ /*
+ * Only immutable pages get NC mappings. If we have a
+ * non-coherent PTE, but the underlying page is not
+ * immutable, it's likely the result of a forced
+ * caching setting running up against ptrace setting
+ * the page to be writable underneath. In this case,
+ * just keep the PTE coherent.
+ */
+ if (hv_pte_get_nc(pte) && home != PAGE_HOME_IMMUTABLE) {
+ pte = hv_pte_clear_nc(pte);
+ printk("non-immutable page incoherently referenced: %#llx\n",
+ pte.val);
+ }
+
+ switch (home) {
+
+ case PAGE_HOME_UNCACHED:
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED);
+ break;
+
+ case PAGE_HOME_INCOHERENT:
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
+ break;
+
+ case PAGE_HOME_IMMUTABLE:
+ /*
+ * We could home this page anywhere, since it's immutable,
+ * but by default just home it to follow "hash_default".
+ */
+ BUG_ON(hv_pte_get_writable(pte));
+ if (pte_get_forcecache(pte)) {
+ /* Upgrade "force any cpu" to "No L3" for immutable. */
+ if (hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_TILE_L3
+ && pte_get_anyhome(pte)) {
+ pte = hv_pte_set_mode(pte,
+ HV_PTE_MODE_CACHE_NO_L3);
+ }
+ } else
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default)
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3);
+ else
+#endif
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
+ pte = hv_pte_set_nc(pte);
+ break;
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ case PAGE_HOME_HASH:
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3);
+ break;
+#endif
+
+ default:
+ BUG_ON(home < 0 || home >= NR_CPUS ||
+ !cpu_is_valid_lotar(home));
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
+ pte = set_remote_cache_cpu(pte, home);
+ break;
+ }
+
+#if CHIP_HAS_NC_AND_NOALLOC_BITS()
+ if (noallocl2)
+ pte = hv_pte_set_no_alloc_l2(pte);
+
+ /* Simplify "no local and no l3" to "uncached" */
+ if (hv_pte_get_no_alloc_l2(pte) && hv_pte_get_no_alloc_l1(pte) &&
+ hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_NO_L3) {
+ pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED);
+ }
+#endif
+
+ /* Checking this case here gives a better panic than from the hv. */
+ BUG_ON(hv_pte_get_mode(pte) == 0);
+
+ return pte;
+}
+
+/*
+ * The routines in this section are the "static" versions of the normal
+ * dynamic homecaching routines; they just set the home cache
+ * of a kernel page once, and require a full-chip cache/TLB flush,
+ * so they're not suitable for anything but infrequent use.
+ */
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+static inline int initial_page_home(void) { return PAGE_HOME_HASH; }
+#else
+static inline int initial_page_home(void) { return 0; }
+#endif
+
+int page_home(struct page *page)
+{
+ if (PageHighMem(page)) {
+ return initial_page_home();
+ } else {
+ unsigned long kva = (unsigned long)page_address(page);
+ return pte_to_home(*virt_to_pte(NULL, kva));
+ }
+}
+
+void homecache_change_page_home(struct page *page, int order, int home)
+{
+ int i, pages = (1 << order);
+ unsigned long kva;
+
+ BUG_ON(PageHighMem(page));
+ BUG_ON(page_count(page) > 1);
+ BUG_ON(page_mapcount(page) != 0);
+ kva = (unsigned long) page_address(page);
+ flush_remote(0, HV_FLUSH_EVICT_L2, &cpu_cacheable_map,
+ kva, pages * PAGE_SIZE, PAGE_SIZE, cpu_online_mask,
+ NULL, 0);
+
+ for (i = 0; i < pages; ++i, kva += PAGE_SIZE) {
+ pte_t *ptep = virt_to_pte(NULL, kva);
+ pte_t pteval = *ptep;
+ BUG_ON(!pte_present(pteval) || pte_huge(pteval));
+ *ptep = pte_set_home(pteval, home);
+ }
+}
+
+struct page *homecache_alloc_pages(gfp_t gfp_mask,
+ unsigned int order, int home)
+{
+ struct page *page;
+ BUG_ON(gfp_mask & __GFP_HIGHMEM); /* must be lowmem */
+ page = alloc_pages(gfp_mask, order);
+ if (page)
+ homecache_change_page_home(page, order, home);
+ return page;
+}
+
+struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask,
+ unsigned int order, int home)
+{
+ struct page *page;
+ BUG_ON(gfp_mask & __GFP_HIGHMEM); /* must be lowmem */
+ page = alloc_pages_node(nid, gfp_mask, order);
+ if (page)
+ homecache_change_page_home(page, order, home);
+ return page;
+}
+
+void homecache_free_pages(unsigned long addr, unsigned int order)
+{
+ struct page *page;
+
+ if (addr == 0)
+ return;
+
+ VM_BUG_ON(!virt_addr_valid((void *)addr));
+ page = virt_to_page((void *)addr);
+ if (put_page_testzero(page)) {
+ int pages = (1 << order);
+ homecache_change_page_home(page, order, initial_page_home());
+ while (pages--)
+ __free_page(page++);
+ }
+}
diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c
new file mode 100644
index 000000000000..c38570f8f0d0
--- /dev/null
+++ b/arch/tile/mm/hugetlbpage.c
@@ -0,0 +1,343 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * TILE Huge TLB Page Support for Kernel.
+ * Taken from i386 hugetlb implementation:
+ * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/sysctl.h>
+#include <linux/mman.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pte_t *pte = NULL;
+
+ /* We do not yet support multiple huge page sizes. */
+ BUG_ON(sz != PMD_SIZE);
+
+ pgd = pgd_offset(mm, addr);
+ pud = pud_alloc(mm, pgd, addr);
+ if (pud)
+ pte = (pte_t *) pmd_alloc(mm, pud, addr);
+ BUG_ON(pte && !pte_none(*pte) && !pte_huge(*pte));
+
+ return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ if (pgd_present(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (pud_present(*pud))
+ pmd = pmd_offset(pud, addr);
+ }
+ return (pte_t *) pmd;
+}
+
+#ifdef HUGETLB_TEST
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write)
+{
+ unsigned long start = address;
+ int length = 1;
+ int nr;
+ struct page *page;
+ struct vm_area_struct *vma;
+
+ vma = find_vma(mm, addr);
+ if (!vma || !is_vm_hugetlb_page(vma))
+ return ERR_PTR(-EINVAL);
+
+ pte = huge_pte_offset(mm, address);
+
+ /* hugetlb should be locked, and hence, prefaulted */
+ WARN_ON(!pte || pte_none(*pte));
+
+ page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
+
+ WARN_ON(!PageHead(page));
+
+ return page;
+}
+
+int pmd_huge(pmd_t pmd)
+{
+ return 0;
+}
+
+int pud_huge(pud_t pud)
+{
+ return 0;
+}
+
+struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+ pmd_t *pmd, int write)
+{
+ return NULL;
+}
+
+#else
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+int pmd_huge(pmd_t pmd)
+{
+ return !!(pmd_val(pmd) & _PAGE_HUGE_PAGE);
+}
+
+int pud_huge(pud_t pud)
+{
+ return !!(pud_val(pud) & _PAGE_HUGE_PAGE);
+}
+
+struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+ pmd_t *pmd, int write)
+{
+ struct page *page;
+
+ page = pte_page(*(pte_t *)pmd);
+ if (page)
+ page += ((address & ~PMD_MASK) >> PAGE_SHIFT);
+ return page;
+}
+
+struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address,
+ pud_t *pud, int write)
+{
+ struct page *page;
+
+ page = pte_page(*(pte_t *)pud);
+ if (page)
+ page += ((address & ~PUD_MASK) >> PAGE_SHIFT);
+ return page;
+}
+
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+ return 0;
+}
+
+#endif
+
+#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
+static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
+ unsigned long addr, unsigned long len,
+ unsigned long pgoff, unsigned long flags)
+{
+ struct hstate *h = hstate_file(file);
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ unsigned long start_addr;
+
+ if (len > mm->cached_hole_size) {
+ start_addr = mm->free_area_cache;
+ } else {
+ start_addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ }
+
+full_search:
+ addr = ALIGN(start_addr, huge_page_size(h));
+
+ for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
+ /* At this point: (!vma || addr < vma->vm_end). */
+ if (TASK_SIZE - len < addr) {
+ /*
+ * Start a new search - just in case we missed
+ * some holes.
+ */
+ if (start_addr != TASK_UNMAPPED_BASE) {
+ start_addr = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = 0;
+ goto full_search;
+ }
+ return -ENOMEM;
+ }
+ if (!vma || addr + len <= vma->vm_start) {
+ mm->free_area_cache = addr + len;
+ return addr;
+ }
+ if (addr + mm->cached_hole_size < vma->vm_start)
+ mm->cached_hole_size = vma->vm_start - addr;
+ addr = ALIGN(vma->vm_end, huge_page_size(h));
+ }
+}
+
+static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file,
+ unsigned long addr0, unsigned long len,
+ unsigned long pgoff, unsigned long flags)
+{
+ struct hstate *h = hstate_file(file);
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma, *prev_vma;
+ unsigned long base = mm->mmap_base, addr = addr0;
+ unsigned long largest_hole = mm->cached_hole_size;
+ int first_time = 1;
+
+ /* don't allow allocations above current base */
+ if (mm->free_area_cache > base)
+ mm->free_area_cache = base;
+
+ if (len <= largest_hole) {
+ largest_hole = 0;
+ mm->free_area_cache = base;
+ }
+try_again:
+ /* make sure it can fit in the remaining address space */
+ if (mm->free_area_cache < len)
+ goto fail;
+
+ /* either no address requested or cant fit in requested address hole */
+ addr = (mm->free_area_cache - len) & huge_page_mask(h);
+ do {
+ /*
+ * Lookup failure means no vma is above this address,
+ * i.e. return with success:
+ */
+ vma = find_vma_prev(mm, addr, &prev_vma);
+ if (!vma) {
+ return addr;
+ break;
+ }
+
+ /*
+ * new region fits between prev_vma->vm_end and
+ * vma->vm_start, use it:
+ */
+ if (addr + len <= vma->vm_start &&
+ (!prev_vma || (addr >= prev_vma->vm_end))) {
+ /* remember the address as a hint for next time */
+ mm->cached_hole_size = largest_hole;
+ mm->free_area_cache = addr;
+ return addr;
+ } else {
+ /* pull free_area_cache down to the first hole */
+ if (mm->free_area_cache == vma->vm_end) {
+ mm->free_area_cache = vma->vm_start;
+ mm->cached_hole_size = largest_hole;
+ }
+ }
+
+ /* remember the largest hole we saw so far */
+ if (addr + largest_hole < vma->vm_start)
+ largest_hole = vma->vm_start - addr;
+
+ /* try just below the current vma->vm_start */
+ addr = (vma->vm_start - len) & huge_page_mask(h);
+
+ } while (len <= vma->vm_start);
+
+fail:
+ /*
+ * if hint left us with no space for the requested
+ * mapping then try again:
+ */
+ if (first_time) {
+ mm->free_area_cache = base;
+ largest_hole = 0;
+ first_time = 0;
+ goto try_again;
+ }
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ mm->free_area_cache = TASK_UNMAPPED_BASE;
+ mm->cached_hole_size = ~0UL;
+ addr = hugetlb_get_unmapped_area_bottomup(file, addr0,
+ len, pgoff, flags);
+
+ /*
+ * Restore the topdown base:
+ */
+ mm->free_area_cache = base;
+ mm->cached_hole_size = ~0UL;
+
+ return addr;
+}
+
+unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct hstate *h = hstate_file(file);
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (flags & MAP_FIXED) {
+ if (prepare_hugepage_range(file, addr, len))
+ return -EINVAL;
+ return addr;
+ }
+
+ if (addr) {
+ addr = ALIGN(addr, huge_page_size(h));
+ vma = find_vma(mm, addr);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vma->vm_start))
+ return addr;
+ }
+ if (current->mm->get_unmapped_area == arch_get_unmapped_area)
+ return hugetlb_get_unmapped_area_bottomup(file, addr, len,
+ pgoff, flags);
+ else
+ return hugetlb_get_unmapped_area_topdown(file, addr, len,
+ pgoff, flags);
+}
+
+static __init int setup_hugepagesz(char *opt)
+{
+ unsigned long ps = memparse(opt, &opt);
+ if (ps == PMD_SIZE) {
+ hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
+ } else if (ps == PUD_SIZE) {
+ hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+ } else {
+ printk(KERN_ERR "hugepagesz: Unsupported page size %lu M\n",
+ ps >> 20);
+ return 0;
+ }
+ return 1;
+}
+__setup("hugepagesz=", setup_hugepagesz);
+
+#endif /*HAVE_ARCH_HUGETLB_UNMAPPED_AREA*/
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
new file mode 100644
index 000000000000..125ac53b60fc
--- /dev/null
+++ b/arch/tile/mm/init.c
@@ -0,0 +1,1082 @@
+/*
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/poison.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/efi.h>
+#include <linux/memory_hotplug.h>
+#include <linux/uaccess.h>
+#include <asm/mmu_context.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/dma.h>
+#include <asm/fixmap.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/homecache.h>
+#include <hv/hypervisor.h>
+#include <arch/chip.h>
+
+#include "migrate.h"
+
+/*
+ * We could set FORCE_MAX_ZONEORDER to "(HPAGE_SHIFT - PAGE_SHIFT + 1)"
+ * in the Tile Kconfig, but this generates configure warnings.
+ * Do it here and force people to get it right to compile this file.
+ * The problem is that with 4KB small pages and 16MB huge pages,
+ * the default value doesn't allow us to group enough small pages
+ * together to make up a huge page.
+ */
+#if CONFIG_FORCE_MAX_ZONEORDER < HPAGE_SHIFT - PAGE_SHIFT + 1
+# error "Change FORCE_MAX_ZONEORDER in arch/tile/Kconfig to match page size"
+#endif
+
+#define clear_pgd(pmdptr) (*(pmdptr) = hv_pte(0))
+
+unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE;
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+/* Create an L2 page table */
+static pte_t * __init alloc_pte(void)
+{
+ return __alloc_bootmem(L2_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0);
+}
+
+/*
+ * L2 page tables per controller. We allocate these all at once from
+ * the bootmem allocator and store them here. This saves on kernel L2
+ * page table memory, compared to allocating a full 64K page per L2
+ * page table, and also means that in cases where we use huge pages,
+ * we are guaranteed to later be able to shatter those huge pages and
+ * switch to using these page tables instead, without requiring
+ * further allocation. Each l2_ptes[] entry points to the first page
+ * table for the first hugepage-size piece of memory on the
+ * controller; other page tables are just indexed directly, i.e. the
+ * L2 page tables are contiguous in memory for each controller.
+ */
+static pte_t *l2_ptes[MAX_NUMNODES];
+static int num_l2_ptes[MAX_NUMNODES];
+
+static void init_prealloc_ptes(int node, int pages)
+{
+ BUG_ON(pages & (HV_L2_ENTRIES-1));
+ if (pages) {
+ num_l2_ptes[node] = pages;
+ l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t),
+ HV_PAGE_TABLE_ALIGN, 0);
+ }
+}
+
+pte_t *get_prealloc_pte(unsigned long pfn)
+{
+ int node = pfn_to_nid(pfn);
+ pfn &= ~(-1UL << (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT));
+ BUG_ON(node >= MAX_NUMNODES);
+ BUG_ON(pfn >= num_l2_ptes[node]);
+ return &l2_ptes[node][pfn];
+}
+
+/*
+ * What caching do we expect pages from the heap to have when
+ * they are allocated during bootup? (Once we've installed the
+ * "real" swapper_pg_dir.)
+ */
+static int initial_heap_home(void)
+{
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (hash_default)
+ return PAGE_HOME_HASH;
+#endif
+ return smp_processor_id();
+}
+
+/*
+ * Place a pointer to an L2 page table in a middle page
+ * directory entry.
+ */
+static void __init assign_pte(pmd_t *pmd, pte_t *page_table)
+{
+ phys_addr_t pa = __pa(page_table);
+ unsigned long l2_ptfn = pa >> HV_LOG2_PAGE_TABLE_ALIGN;
+ pte_t pteval = hv_pte_set_ptfn(__pgprot(_PAGE_TABLE), l2_ptfn);
+ BUG_ON((pa & (HV_PAGE_TABLE_ALIGN-1)) != 0);
+ pteval = pte_set_home(pteval, initial_heap_home());
+ *(pte_t *)pmd = pteval;
+ if (page_table != (pte_t *)pmd_page_vaddr(*pmd))
+ BUG();
+}
+
+#ifdef __tilegx__
+
+#if HV_L1_SIZE != HV_L2_SIZE
+# error Rework assumption that L1 and L2 page tables are same size.
+#endif
+
+/* Since pmd_t arrays and pte_t arrays are the same size, just use casts. */
+static inline pmd_t *alloc_pmd(void)
+{
+ return (pmd_t *)alloc_pte();
+}
+
+static inline void assign_pmd(pud_t *pud, pmd_t *pmd)
+{
+ assign_pte((pmd_t *)pud, (pte_t *)pmd);
+}
+
+#endif /* __tilegx__ */
+
+/* Replace the given pmd with a full PTE table. */
+void __init shatter_pmd(pmd_t *pmd)
+{
+ pte_t *pte = get_prealloc_pte(pte_pfn(*(pte_t *)pmd));
+ assign_pte(pmd, pte);
+}
+
+#ifdef CONFIG_HIGHMEM
+/*
+ * This function initializes a certain range of kernel virtual memory
+ * with new bootmem page tables, everywhere page tables are missing in
+ * the given range.
+ */
+
+/*
+ * NOTE: The pagetables are allocated contiguous on the physical space
+ * so we can cache the place of the first one and move around without
+ * checking the pgd every time.
+ */
+static void __init page_table_range_init(unsigned long start,
+ unsigned long end, pgd_t *pgd_base)
+{
+ pgd_t *pgd;
+ int pgd_idx;
+ unsigned long vaddr;
+
+ vaddr = start;
+ pgd_idx = pgd_index(vaddr);
+ pgd = pgd_base + pgd_idx;
+
+ for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) {
+ pmd_t *pmd = pmd_offset(pud_offset(pgd, vaddr), vaddr);
+ if (pmd_none(*pmd))
+ assign_pte(pmd, alloc_pte());
+ vaddr += PMD_SIZE;
+ }
+}
+#endif /* CONFIG_HIGHMEM */
+
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+
+static int __initdata ktext_hash = 1; /* .text pages */
+static int __initdata kdata_hash = 1; /* .data and .bss pages */
+int __write_once hash_default = 1; /* kernel allocator pages */
+EXPORT_SYMBOL(hash_default);
+int __write_once kstack_hash = 1; /* if no homecaching, use h4h */
+#endif /* CHIP_HAS_CBOX_HOME_MAP */
+
+/*
+ * CPUs to use to for striping the pages of kernel data. If hash-for-home
+ * is available, this is only relevant if kcache_hash sets up the
+ * .data and .bss to be page-homed, and we don't want the default mode
+ * of using the full set of kernel cpus for the striping.
+ */
+static __initdata struct cpumask kdata_mask;
+static __initdata int kdata_arg_seen;
+
+int __write_once kdata_huge; /* if no homecaching, small pages */
+
+
+/* Combine a generic pgprot_t with cache home to get a cache-aware pgprot. */
+static pgprot_t __init construct_pgprot(pgprot_t prot, int home)
+{
+ prot = pte_set_home(prot, home);
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (home == PAGE_HOME_IMMUTABLE) {
+ if (ktext_hash)
+ prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3);
+ else
+ prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_NO_L3);
+ }
+#endif
+ return prot;
+}
+
+/*
+ * For a given kernel data VA, how should it be cached?
+ * We return the complete pgprot_t with caching bits set.
+ */
+static pgprot_t __init init_pgprot(ulong address)
+{
+ int cpu;
+ unsigned long page;
+ enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET };
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ /* For kdata=huge, everything is just hash-for-home. */
+ if (kdata_huge)
+ return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
+#endif
+
+ /* We map the aliased pages of permanent text inaccessible. */
+ if (address < (ulong) _sinittext - CODE_DELTA)
+ return PAGE_NONE;
+
+ /*
+ * We map read-only data non-coherent for performance. We could
+ * use neighborhood caching on TILE64, but it's not clear it's a win.
+ */
+ if ((address >= (ulong) __start_rodata &&
+ address < (ulong) __end_rodata) ||
+ address == (ulong) empty_zero_page) {
+ return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE);
+ }
+
+ /* As a performance optimization, keep the boot init stack here. */
+ if (address >= (ulong)&init_thread_union &&
+ address < (ulong)&init_thread_union + THREAD_SIZE)
+ return construct_pgprot(PAGE_KERNEL, smp_processor_id());
+
+#ifndef __tilegx__
+#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ /* Force the atomic_locks[] array page to be hash-for-home. */
+ if (address == (ulong) atomic_locks)
+ return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
+#endif
+#endif
+
+ /*
+ * Everything else that isn't data or bss is heap, so mark it
+ * with the initial heap home (hash-for-home, or this cpu). This
+ * includes any addresses after the loaded image; any address before
+ * _einittext (since we already captured the case of text before
+ * _sinittext); and any init-data pages.
+ *
+ * All the LOWMEM pages that we mark this way will get their
+ * struct page homecache properly marked later, in set_page_homes().
+ * The HIGHMEM pages we leave with a default zero for their
+ * homes, but with a zero free_time we don't have to actually
+ * do a flush action the first time we use them, either.
+ */
+ if (address >= (ulong) _end || address < (ulong) _sdata ||
+ (address >= (ulong) _sinitdata &&
+ address < (ulong) _einitdata))
+ return construct_pgprot(PAGE_KERNEL, initial_heap_home());
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ /* Use hash-for-home if requested for data/bss. */
+ if (kdata_hash)
+ return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH);
+#endif
+
+ /*
+ * Otherwise we just hand out consecutive cpus. To avoid
+ * requiring this function to hold state, we just walk forward from
+ * _sdata by PAGE_SIZE, skipping the readonly and init data, to reach
+ * the requested address, while walking cpu home around kdata_mask.
+ * This is typically no more than a dozen or so iterations.
+ */
+ BUG_ON(_einitdata != __bss_start);
+ for (page = (ulong)_sdata, cpu = NR_CPUS; ; ) {
+ cpu = cpumask_next(cpu, &kdata_mask);
+ if (cpu == NR_CPUS)
+ cpu = cpumask_first(&kdata_mask);
+ if (page >= address)
+ break;
+ page += PAGE_SIZE;
+ if (page == (ulong)__start_rodata)
+ page = (ulong)__end_rodata;
+ if (page == (ulong)&init_thread_union)
+ page += THREAD_SIZE;
+ if (page == (ulong)_sinitdata)
+ page = (ulong)_einitdata;
+ if (page == (ulong)empty_zero_page)
+ page += PAGE_SIZE;
+#ifndef __tilegx__
+#if !ATOMIC_LOCKS_FOUND_VIA_TABLE()
+ if (page == (ulong)atomic_locks)
+ page += PAGE_SIZE;
+#endif
+#endif
+
+ }
+ return construct_pgprot(PAGE_KERNEL, cpu);
+}
+
+/*
+ * This function sets up how we cache the kernel text. If we have
+ * hash-for-home support, normally that is used instead (see the
+ * kcache_hash boot flag for more information). But if we end up
+ * using a page-based caching technique, this option sets up the
+ * details of that. In addition, the "ktext=nocache" option may
+ * always be used to disable local caching of text pages, if desired.
+ */
+
+static int __initdata ktext_arg_seen;
+static int __initdata ktext_small;
+static int __initdata ktext_local;
+static int __initdata ktext_all;
+static int __initdata ktext_nondataplane;
+static int __initdata ktext_nocache;
+static struct cpumask __initdata ktext_mask;
+
+static int __init setup_ktext(char *str)
+{
+ if (str == NULL)
+ return -EINVAL;
+
+ /* If you have a leading "nocache", turn off ktext caching */
+ if (strncmp(str, "nocache", 7) == 0) {
+ ktext_nocache = 1;
+ printk("ktext: disabling local caching of kernel text\n");
+ str += 7;
+ if (*str == ',')
+ ++str;
+ if (*str == '\0')
+ return 0;
+ }
+
+ ktext_arg_seen = 1;
+
+ /* Default setting on Tile64: use a huge page */
+ if (strcmp(str, "huge") == 0)
+ printk("ktext: using one huge locally cached page\n");
+
+ /* Pay TLB cost but get no cache benefit: cache small pages locally */
+ else if (strcmp(str, "local") == 0) {
+ ktext_small = 1;
+ ktext_local = 1;
+ printk("ktext: using small pages with local caching\n");
+ }
+
+ /* Neighborhood cache ktext pages on all cpus. */
+ else if (strcmp(str, "all") == 0) {
+ ktext_small = 1;
+ ktext_all = 1;
+ printk("ktext: using maximal caching neighborhood\n");
+ }
+
+
+ /* Neighborhood ktext pages on specified mask */
+ else if (cpulist_parse(str, &ktext_mask) == 0) {
+ char buf[NR_CPUS * 5];
+ cpulist_scnprintf(buf, sizeof(buf), &ktext_mask);
+ if (cpumask_weight(&ktext_mask) > 1) {
+ ktext_small = 1;
+ printk("ktext: using caching neighborhood %s "
+ "with small pages\n", buf);
+ } else {
+ printk("ktext: caching on cpu %s with one huge page\n",
+ buf);
+ }
+ }
+
+ else if (*str)
+ return -EINVAL;
+
+ return 0;
+}
+
+early_param("ktext", setup_ktext);
+
+
+static inline pgprot_t ktext_set_nocache(pgprot_t prot)
+{
+ if (!ktext_nocache)
+ prot = hv_pte_set_nc(prot);
+#if CHIP_HAS_NC_AND_NOALLOC_BITS()
+ else
+ prot = hv_pte_set_no_alloc_l2(prot);
+#endif
+ return prot;
+}
+
+#ifndef __tilegx__
+static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
+{
+ return pmd_offset(pud_offset(&pgtables[pgd_index(va)], va), va);
+}
+#else
+static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va)
+{
+ pud_t *pud = pud_offset(&pgtables[pgd_index(va)], va);
+ if (pud_none(*pud))
+ assign_pmd(pud, alloc_pmd());
+ return pmd_offset(pud, va);
+}
+#endif
+
+/* Temporary page table we use for staging. */
+static pgd_t pgtables[PTRS_PER_PGD]
+ __attribute__((section(".init.page")));
+
+/*
+ * This maps the physical memory to kernel virtual address space, a total
+ * of max_low_pfn pages, by creating page tables starting from address
+ * PAGE_OFFSET.
+ *
+ * This routine transitions us from using a set of compiled-in large
+ * pages to using some more precise caching, including removing access
+ * to code pages mapped at PAGE_OFFSET (executed only at MEM_SV_START)
+ * marking read-only data as locally cacheable, striping the remaining
+ * .data and .bss across all the available tiles, and removing access
+ * to pages above the top of RAM (thus ensuring a page fault from a bad
+ * virtual address rather than a hypervisor shoot down for accessing
+ * memory outside the assigned limits).
+ */
+static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
+{
+ unsigned long address, pfn;
+ pmd_t *pmd;
+ pte_t *pte;
+ int pte_ofs;
+ const struct cpumask *my_cpu_mask = cpumask_of(smp_processor_id());
+ struct cpumask kstripe_mask;
+ int rc, i;
+
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (ktext_arg_seen && ktext_hash) {
+ printk("warning: \"ktext\" boot argument ignored"
+ " if \"kcache_hash\" sets up text hash-for-home\n");
+ ktext_small = 0;
+ }
+
+ if (kdata_arg_seen && kdata_hash) {
+ printk("warning: \"kdata\" boot argument ignored"
+ " if \"kcache_hash\" sets up data hash-for-home\n");
+ }
+
+ if (kdata_huge && !hash_default) {
+ printk("warning: disabling \"kdata=huge\"; requires"
+ " kcache_hash=all or =allbutstack\n");
+ kdata_huge = 0;
+ }
+#endif
+
+ /*
+ * Set up a mask for cpus to use for kernel striping.
+ * This is normally all cpus, but minus dataplane cpus if any.
+ * If the dataplane covers the whole chip, we stripe over
+ * the whole chip too.
+ */
+ cpumask_copy(&kstripe_mask, cpu_possible_mask);
+ if (!kdata_arg_seen)
+ kdata_mask = kstripe_mask;
+
+ /* Allocate and fill in L2 page tables */
+ for (i = 0; i < MAX_NUMNODES; ++i) {
+#ifdef CONFIG_HIGHMEM
+ unsigned long end_pfn = node_lowmem_end_pfn[i];
+#else
+ unsigned long end_pfn = node_end_pfn[i];
+#endif
+ unsigned long end_huge_pfn = 0;
+
+ /* Pre-shatter the last huge page to allow per-cpu pages. */
+ if (kdata_huge)
+ end_huge_pfn = end_pfn - (HPAGE_SIZE >> PAGE_SHIFT);
+
+ pfn = node_start_pfn[i];
+
+ /* Allocate enough memory to hold L2 page tables for node. */
+ init_prealloc_ptes(i, end_pfn - pfn);
+
+ address = (unsigned long) pfn_to_kaddr(pfn);
+ while (pfn < end_pfn) {
+ BUG_ON(address & (HPAGE_SIZE-1));
+ pmd = get_pmd(pgtables, address);
+ pte = get_prealloc_pte(pfn);
+ if (pfn < end_huge_pfn) {
+ pgprot_t prot = init_pgprot(address);
+ *(pte_t *)pmd = pte_mkhuge(pfn_pte(pfn, prot));
+ for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE;
+ pfn++, pte_ofs++, address += PAGE_SIZE)
+ pte[pte_ofs] = pfn_pte(pfn, prot);
+ } else {
+ if (kdata_huge)
+ printk(KERN_DEBUG "pre-shattered huge"
+ " page at %#lx\n", address);
+ for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE;
+ pfn++, pte_ofs++, address += PAGE_SIZE) {
+ pgprot_t prot = init_pgprot(address);
+ pte[pte_ofs] = pfn_pte(pfn, prot);
+ }
+ assign_pte(pmd, pte);
+ }
+ }
+ }
+
+ /*
+ * Set or check ktext_map now that we have cpu_possible_mask
+ * and kstripe_mask to work with.
+ */
+ if (ktext_all)
+ cpumask_copy(&ktext_mask, cpu_possible_mask);
+ else if (ktext_nondataplane)
+ ktext_mask = kstripe_mask;
+ else if (!cpumask_empty(&ktext_mask)) {
+ /* Sanity-check any mask that was requested */
+ struct cpumask bad;
+ cpumask_andnot(&bad, &ktext_mask, cpu_possible_mask);
+ cpumask_and(&ktext_mask, &ktext_mask, cpu_possible_mask);
+ if (!cpumask_empty(&bad)) {
+ char buf[NR_CPUS * 5];
+ cpulist_scnprintf(buf, sizeof(buf), &bad);
+ printk("ktext: not using unavailable cpus %s\n", buf);
+ }
+ if (cpumask_empty(&ktext_mask)) {
+ printk("ktext: no valid cpus; caching on %d.\n",
+ smp_processor_id());
+ cpumask_copy(&ktext_mask,
+ cpumask_of(smp_processor_id()));
+ }
+ }
+
+ address = MEM_SV_INTRPT;
+ pmd = get_pmd(pgtables, address);
+ if (ktext_small) {
+ /* Allocate an L2 PTE for the kernel text */
+ int cpu = 0;
+ pgprot_t prot = construct_pgprot(PAGE_KERNEL_EXEC,
+ PAGE_HOME_IMMUTABLE);
+
+ if (ktext_local) {
+ if (ktext_nocache)
+ prot = hv_pte_set_mode(prot,
+ HV_PTE_MODE_UNCACHED);
+ else
+ prot = hv_pte_set_mode(prot,
+ HV_PTE_MODE_CACHE_NO_L3);
+ } else {
+ prot = hv_pte_set_mode(prot,
+ HV_PTE_MODE_CACHE_TILE_L3);
+ cpu = cpumask_first(&ktext_mask);
+
+ prot = ktext_set_nocache(prot);
+ }
+
+ BUG_ON(address != (unsigned long)_stext);
+ pfn = 0; /* code starts at PA 0 */
+ pte = alloc_pte();
+ for (pte_ofs = 0; address < (unsigned long)_einittext;
+ pfn++, pte_ofs++, address += PAGE_SIZE) {
+ if (!ktext_local) {
+ prot = set_remote_cache_cpu(prot, cpu);
+ cpu = cpumask_next(cpu, &ktext_mask);
+ if (cpu == NR_CPUS)
+ cpu = cpumask_first(&ktext_mask);
+ }
+ pte[pte_ofs] = pfn_pte(pfn, prot);
+ }
+ assign_pte(pmd, pte);
+ } else {
+ pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC);
+ pteval = pte_mkhuge(pteval);
+#if CHIP_HAS_CBOX_HOME_MAP()
+ if (ktext_hash) {
+ pteval = hv_pte_set_mode(pteval,
+ HV_PTE_MODE_CACHE_HASH_L3);
+ pteval = ktext_set_nocache(pteval);
+ } else
+#endif /* CHIP_HAS_CBOX_HOME_MAP() */
+ if (cpumask_weight(&ktext_mask) == 1) {
+ pteval = set_remote_cache_cpu(pteval,
+ cpumask_first(&ktext_mask));
+ pteval = hv_pte_set_mode(pteval,
+ HV_PTE_MODE_CACHE_TILE_L3);
+ pteval = ktext_set_nocache(pteval);
+ } else if (ktext_nocache)
+ pteval = hv_pte_set_mode(pteval,
+ HV_PTE_MODE_UNCACHED);
+ else
+ pteval = hv_pte_set_mode(pteval,
+ HV_PTE_MODE_CACHE_NO_L3);
+ *(pte_t *)pmd = pteval;
+ }
+
+ /* Set swapper_pgprot here so it is flushed to memory right away. */
+ swapper_pgprot = init_pgprot((unsigned long)swapper_pg_dir);
+
+ /*
+ * Since we may be changing the caching of the stack and page
+ * table itself, we invoke an assembly helper to do the
+ * following steps:
+ *
+ * - flush the cache so we start with an empty slate
+ * - install pgtables[] as the real page table
+ * - flush the TLB so the new page table takes effect
+ */
+ rc = flush_and_install_context(__pa(pgtables),
+ init_pgprot((unsigned long)pgtables),
+ __get_cpu_var(current_asid),
+ cpumask_bits(my_cpu_mask));
+ BUG_ON(rc != 0);
+
+ /* Copy the page table back to the normal swapper_pg_dir. */
+ memcpy(pgd_base, pgtables, sizeof(pgtables));
+ __install_page_table(pgd_base, __get_cpu_var(current_asid),
+ swapper_pgprot);
+}
+
+/*
+ * devmem_is_allowed() checks to see if /dev/mem access to a certain address
+ * is valid. The argument is a physical page number.
+ *
+ * On Tile, the only valid things for which we can just hand out unchecked
+ * PTEs are the kernel code and data. Anything else might change its
+ * homing with time, and we wouldn't know to adjust the /dev/mem PTEs.
+ * Note that init_thread_union is released to heap soon after boot,
+ * so we include it in the init data.
+ *
+ * For TILE-Gx, we might want to consider allowing access to PA
+ * regions corresponding to PCI space, etc.
+ */
+int devmem_is_allowed(unsigned long pagenr)
+{
+ return pagenr < kaddr_to_pfn(_end) &&
+ !(pagenr >= kaddr_to_pfn(&init_thread_union) ||
+ pagenr < kaddr_to_pfn(_einitdata)) &&
+ !(pagenr >= kaddr_to_pfn(_sinittext) ||
+ pagenr <= kaddr_to_pfn(_einittext-1));
+}
+
+#ifdef CONFIG_HIGHMEM
+static void __init permanent_kmaps_init(pgd_t *pgd_base)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+ unsigned long vaddr;
+
+ vaddr = PKMAP_BASE;
+ page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base);
+
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ pud = pud_offset(pgd, vaddr);
+ pmd = pmd_offset(pud, vaddr);
+ pte = pte_offset_kernel(pmd, vaddr);
+ pkmap_page_table = pte;
+}
+#endif /* CONFIG_HIGHMEM */
+
+
+static void __init init_free_pfn_range(unsigned long start, unsigned long end)
+{
+ unsigned long pfn;
+ struct page *page = pfn_to_page(start);
+
+ for (pfn = start; pfn < end; ) {
+ /* Optimize by freeing pages in large batches */
+ int order = __ffs(pfn);
+ int count, i;
+ struct page *p;
+
+ if (order >= MAX_ORDER)
+ order = MAX_ORDER-1;
+ count = 1 << order;
+ while (pfn + count > end) {
+ count >>= 1;
+ --order;
+ }
+ for (p = page, i = 0; i < count; ++i, ++p) {
+ __ClearPageReserved(p);
+ /*
+ * Hacky direct set to avoid unnecessary
+ * lock take/release for EVERY page here.
+ */
+ p->_count.counter = 0;
+ p->_mapcount.counter = -1;
+ }
+ init_page_count(page);
+ __free_pages(page, order);
+ totalram_pages += count;
+
+ page += count;
+ pfn += count;
+ }
+}
+
+static void __init set_non_bootmem_pages_init(void)
+{
+ struct zone *z;
+ for_each_zone(z) {
+ unsigned long start, end;
+ int nid = z->zone_pgdat->node_id;
+
+ start = z->zone_start_pfn;
+ if (start == 0)
+ continue; /* bootmem */
+ end = start + z->spanned_pages;
+ if (zone_idx(z) == ZONE_NORMAL) {
+ BUG_ON(start != node_start_pfn[nid]);
+ start = node_free_pfn[nid];
+ }
+#ifdef CONFIG_HIGHMEM
+ if (zone_idx(z) == ZONE_HIGHMEM)
+ totalhigh_pages += z->spanned_pages;
+#endif
+ if (kdata_huge) {
+ unsigned long percpu_pfn = node_percpu_pfn[nid];
+ if (start < percpu_pfn && end > percpu_pfn)
+ end = percpu_pfn;
+ }
+#ifdef CONFIG_PCI
+ if (start <= pci_reserve_start_pfn &&
+ end > pci_reserve_start_pfn) {
+ if (end > pci_reserve_end_pfn)
+ init_free_pfn_range(pci_reserve_end_pfn, end);
+ end = pci_reserve_start_pfn;
+ }
+#endif
+ init_free_pfn_range(start, end);
+ }
+}
+
+/*
+ * paging_init() sets up the page tables - note that all of lowmem is
+ * already mapped by head.S.
+ */
+void __init paging_init(void)
+{
+#ifdef CONFIG_HIGHMEM
+ unsigned long vaddr, end;
+#endif
+#ifdef __tilegx__
+ pud_t *pud;
+#endif
+ pgd_t *pgd_base = swapper_pg_dir;
+
+ kernel_physical_mapping_init(pgd_base);
+
+#ifdef CONFIG_HIGHMEM
+ /*
+ * Fixed mappings, only the page table structure has to be
+ * created - mappings will be set by set_fixmap():
+ */
+ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
+ end = (FIXADDR_TOP + PMD_SIZE - 1) & PMD_MASK;
+ page_table_range_init(vaddr, end, pgd_base);
+ permanent_kmaps_init(pgd_base);
+#endif
+
+#ifdef __tilegx__
+ /*
+ * Since GX allocates just one pmd_t array worth of vmalloc space,
+ * we go ahead and allocate it statically here, then share it
+ * globally. As a result we don't have to worry about any task
+ * changing init_mm once we get up and running, and there's no
+ * need for e.g. vmalloc_sync_all().
+ */
+ BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END));
+ pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START);
+ assign_pmd(pud, alloc_pmd());
+#endif
+}
+
+
+/*
+ * Walk the kernel page tables and derive the page_home() from
+ * the PTEs, so that set_pte() can properly validate the caching
+ * of all PTEs it sees.
+ */
+void __init set_page_homes(void)
+{
+}
+
+static void __init set_max_mapnr_init(void)
+{
+#ifdef CONFIG_FLATMEM
+ max_mapnr = max_low_pfn;
+#endif
+}
+
+void __init mem_init(void)
+{
+ int codesize, datasize, initsize;
+ int i;
+#ifndef __tilegx__
+ void *last;
+#endif
+
+#ifdef CONFIG_FLATMEM
+ if (!mem_map)
+ BUG();
+#endif
+
+#ifdef CONFIG_HIGHMEM
+ /* check that fixmap and pkmap do not overlap */
+ if (PKMAP_ADDR(LAST_PKMAP-1) >= FIXADDR_START) {
+ printk(KERN_ERR "fixmap and kmap areas overlap"
+ " - this will crash\n");
+ printk(KERN_ERR "pkstart: %lxh pkend: %lxh fixstart %lxh\n",
+ PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP-1),
+ FIXADDR_START);
+ BUG();
+ }
+#endif
+
+ set_max_mapnr_init();
+
+ /* this will put all bootmem onto the freelists */
+ totalram_pages += free_all_bootmem();
+
+ /* count all remaining LOWMEM and give all HIGHMEM to page allocator */
+ set_non_bootmem_pages_init();
+
+ codesize = (unsigned long)&_etext - (unsigned long)&_text;
+ datasize = (unsigned long)&_end - (unsigned long)&_sdata;
+ initsize = (unsigned long)&_einittext - (unsigned long)&_sinittext;
+ initsize += (unsigned long)&_einitdata - (unsigned long)&_sinitdata;
+
+ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk data, %dk init, %ldk highmem)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ num_physpages << (PAGE_SHIFT-10),
+ codesize >> 10,
+ datasize >> 10,
+ initsize >> 10,
+ (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
+ );
+
+ /*
+ * In debug mode, dump some interesting memory mappings.
+ */
+#ifdef CONFIG_HIGHMEM
+ printk(KERN_DEBUG " KMAP %#lx - %#lx\n",
+ FIXADDR_START, FIXADDR_TOP + PAGE_SIZE - 1);
+ printk(KERN_DEBUG " PKMAP %#lx - %#lx\n",
+ PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP) - 1);
+#endif
+#ifdef CONFIG_HUGEVMAP
+ printk(KERN_DEBUG " HUGEMAP %#lx - %#lx\n",
+ HUGE_VMAP_BASE, HUGE_VMAP_END - 1);
+#endif
+ printk(KERN_DEBUG " VMALLOC %#lx - %#lx\n",
+ _VMALLOC_START, _VMALLOC_END - 1);
+#ifdef __tilegx__
+ for (i = MAX_NUMNODES-1; i >= 0; --i) {
+ struct pglist_data *node = &node_data[i];
+ if (node->node_present_pages) {
+ unsigned long start = (unsigned long)
+ pfn_to_kaddr(node->node_start_pfn);
+ unsigned long end = start +
+ (node->node_present_pages << PAGE_SHIFT);
+ printk(KERN_DEBUG " MEM%d %#lx - %#lx\n",
+ i, start, end - 1);
+ }
+ }
+#else
+ last = high_memory;
+ for (i = MAX_NUMNODES-1; i >= 0; --i) {
+ if ((unsigned long)vbase_map[i] != -1UL) {
+ printk(KERN_DEBUG " LOWMEM%d %#lx - %#lx\n",
+ i, (unsigned long) (vbase_map[i]),
+ (unsigned long) (last-1));
+ last = vbase_map[i];
+ }
+ }
+#endif
+
+#ifndef __tilegx__
+ /*
+ * Convert from using one lock for all atomic operations to
+ * one per cpu.
+ */
+ __init_atomic_per_cpu();
+#endif
+}
+
+/*
+ * this is for the non-NUMA, single node SMP system case.
+ * Specifically, in the case of x86, we will always add
+ * memory to the highmem for now.
+ */
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+int arch_add_memory(u64 start, u64 size)
+{
+ struct pglist_data *pgdata = &contig_page_data;
+ struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1;
+ unsigned long start_pfn = start >> PAGE_SHIFT;
+ unsigned long nr_pages = size >> PAGE_SHIFT;
+
+ return __add_pages(zone, start_pfn, nr_pages);
+}
+
+int remove_memory(u64 start, u64 size)
+{
+ return -EINVAL;
+}
+#endif
+
+struct kmem_cache *pgd_cache;
+
+void __init pgtable_cache_init(void)
+{
+ pgd_cache = kmem_cache_create("pgd",
+ PTRS_PER_PGD*sizeof(pgd_t),
+ PTRS_PER_PGD*sizeof(pgd_t),
+ 0,
+ NULL);
+ if (!pgd_cache)
+ panic("pgtable_cache_init(): Cannot create pgd cache");
+}
+
+#if !CHIP_HAS_COHERENT_LOCAL_CACHE()
+/*
+ * The __w1data area holds data that is only written during initialization,
+ * and is read-only and thus freely cacheable thereafter. Fix the page
+ * table entries that cover that region accordingly.
+ */
+static void mark_w1data_ro(void)
+{
+ /* Loop over page table entries */
+ unsigned long addr = (unsigned long)__w1data_begin;
+ BUG_ON((addr & (PAGE_SIZE-1)) != 0);
+ for (; addr <= (unsigned long)__w1data_end - 1; addr += PAGE_SIZE) {
+ unsigned long pfn = kaddr_to_pfn((void *)addr);
+ struct page *page = pfn_to_page(pfn);
+ pte_t *ptep = virt_to_pte(NULL, addr);
+ BUG_ON(pte_huge(*ptep)); /* not relevant for kdata_huge */
+ set_pte_at(&init_mm, addr, ptep, pfn_pte(pfn, PAGE_KERNEL_RO));
+ }
+}
+#endif
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+static long __write_once initfree;
+#else
+static long __write_once initfree = 1;
+#endif
+
+/* Select whether to free (1) or mark unusable (0) the __init pages. */
+static int __init set_initfree(char *str)
+{
+ strict_strtol(str, 0, &initfree);
+ printk("initfree: %s free init pages\n", initfree ? "will" : "won't");
+ return 1;
+}
+__setup("initfree=", set_initfree);
+
+static void free_init_pages(char *what, unsigned long begin, unsigned long end)
+{
+ unsigned long addr = (unsigned long) begin;
+
+ if (kdata_huge && !initfree) {
+ printk("Warning: ignoring initfree=0:"
+ " incompatible with kdata=huge\n");
+ initfree = 1;
+ }
+ end = (end + PAGE_SIZE - 1) & PAGE_MASK;
+ local_flush_tlb_pages(NULL, begin, PAGE_SIZE, end - begin);
+ for (addr = begin; addr < end; addr += PAGE_SIZE) {
+ /*
+ * Note we just reset the home here directly in the
+ * page table. We know this is safe because our caller
+ * just flushed the caches on all the other cpus,
+ * and they won't be touching any of these pages.
+ */
+ int pfn = kaddr_to_pfn((void *)addr);
+ struct page *page = pfn_to_page(pfn);
+ pte_t *ptep = virt_to_pte(NULL, addr);
+ if (!initfree) {
+ /*
+ * If debugging page accesses then do not free
+ * this memory but mark them not present - any
+ * buggy init-section access will create a
+ * kernel page fault:
+ */
+ pte_clear(&init_mm, addr, ptep);
+ continue;
+ }
+ __ClearPageReserved(page);
+ init_page_count(page);
+ if (pte_huge(*ptep))
+ BUG_ON(!kdata_huge);
+ else
+ set_pte_at(&init_mm, addr, ptep,
+ pfn_pte(pfn, PAGE_KERNEL));
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
+ free_page(addr);
+ totalram_pages++;
+ }
+ printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10);
+}
+
+void free_initmem(void)
+{
+ const unsigned long text_delta = MEM_SV_INTRPT - PAGE_OFFSET;
+
+ /*
+ * Evict the dirty initdata on the boot cpu, evict the w1data
+ * wherever it's homed, and evict all the init code everywhere.
+ * We are guaranteed that no one will touch the init pages any
+ * more, and although other cpus may be touching the w1data,
+ * we only actually change the caching on tile64, which won't
+ * be keeping local copies in the other tiles' caches anyway.
+ */
+ homecache_evict(&cpu_cacheable_map);
+
+ /* Free the data pages that we won't use again after init. */
+ free_init_pages("unused kernel data",
+ (unsigned long)_sinitdata,
+ (unsigned long)_einitdata);
+
+ /*
+ * Free the pages mapped from 0xc0000000 that correspond to code
+ * pages from 0xfd000000 that we won't use again after init.
+ */
+ free_init_pages("unused kernel text",
+ (unsigned long)_sinittext - text_delta,
+ (unsigned long)_einittext - text_delta);
+
+#if !CHIP_HAS_COHERENT_LOCAL_CACHE()
+ /*
+ * Upgrade the .w1data section to globally cached.
+ * We don't do this on tilepro, since the cache architecture
+ * pretty much makes it irrelevant, and in any case we end
+ * up having racing issues with other tiles that may touch
+ * the data after we flush the cache but before we update
+ * the PTEs and flush the TLBs, causing sharer shootdowns
+ * later. Even though this is to clean data, it seems like
+ * an unnecessary complication.
+ */
+ mark_w1data_ro();
+#endif
+
+ /* Do a global TLB flush so everyone sees the changes. */
+ flush_tlb_all();
+}
diff --git a/arch/tile/mm/migrate.h b/arch/tile/mm/migrate.h
new file mode 100644
index 000000000000..cd45a0837fa6
--- /dev/null
+++ b/arch/tile/mm/migrate.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Structure definitions for migration, exposed here for use by
+ * arch/tile/kernel/asm-offsets.c.
+ */
+
+#ifndef MM_MIGRATE_H
+#define MM_MIGRATE_H
+
+#include <linux/cpumask.h>
+#include <hv/hypervisor.h>
+
+/*
+ * This function is used as a helper when setting up the initial
+ * page table (swapper_pg_dir).
+ */
+extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access,
+ HV_ASID asid,
+ const unsigned long *cpumask);
+
+/*
+ * This function supports migration as a "helper" as follows:
+ *
+ * - Set the stack PTE itself to "migrating".
+ * - Do a global TLB flush for (va,length) and the specified ASIDs.
+ * - Do a cache-evict on all necessary cpus.
+ * - Write the new stack PTE.
+ *
+ * Note that any non-NULL pointers must not point to the page that
+ * is handled by the stack_pte itself.
+ */
+extern int homecache_migrate_stack_and_flush(pte_t stack_pte, unsigned long va,
+ size_t length, pte_t *stack_ptep,
+ const struct cpumask *cache_cpumask,
+ const struct cpumask *tlb_cpumask,
+ HV_Remote_ASID *asids,
+ int asidcount);
+
+#endif /* MM_MIGRATE_H */
diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S
new file mode 100644
index 000000000000..f738765cd1e6
--- /dev/null
+++ b/arch/tile/mm/migrate_32.S
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * This routine is a helper for migrating the home of a set of pages to
+ * a new cpu. See the documentation in homecache.c for more information.
+ */
+
+#include <linux/linkage.h>
+#include <linux/threads.h>
+#include <asm/page.h>
+#include <asm/types.h>
+#include <asm/asm-offsets.h>
+#include <hv/hypervisor.h>
+
+ .text
+
+/*
+ * First, some definitions that apply to all the code in the file.
+ */
+
+/* Locals (caller-save) */
+#define r_tmp r10
+#define r_save_sp r11
+
+/* What we save where in the stack frame; must include all callee-saves. */
+#define FRAME_SP 4
+#define FRAME_R30 8
+#define FRAME_R31 12
+#define FRAME_R32 16
+#define FRAME_R33 20
+#define FRAME_R34 24
+#define FRAME_R35 28
+#define FRAME_SIZE 32
+
+
+
+
+/*
+ * On entry:
+ *
+ * r0 low word of the new context PA to install (moved to r_context_lo)
+ * r1 high word of the new context PA to install (moved to r_context_hi)
+ * r2 low word of PTE to use for context access (moved to r_access_lo)
+ * r3 high word of PTE to use for context access (moved to r_access_lo)
+ * r4 ASID to use for new context (moved to r_asid)
+ * r5 pointer to cpumask with just this cpu set in it (r_my_cpumask)
+ */
+
+/* Arguments (caller-save) */
+#define r_context_lo_in r0
+#define r_context_hi_in r1
+#define r_access_lo_in r2
+#define r_access_hi_in r3
+#define r_asid_in r4
+#define r_my_cpumask r5
+
+/* Locals (callee-save); must not be more than FRAME_xxx above. */
+#define r_save_ics r30
+#define r_context_lo r31
+#define r_context_hi r32
+#define r_access_lo r33
+#define r_access_hi r34
+#define r_asid r35
+
+STD_ENTRY(flush_and_install_context)
+ /*
+ * Create a stack frame; we can't touch it once we flush the
+ * cache until we install the new page table and flush the TLB.
+ */
+ {
+ move r_save_sp, sp
+ sw sp, lr
+ addi sp, sp, -FRAME_SIZE
+ }
+ addi r_tmp, sp, FRAME_SP
+ {
+ sw r_tmp, r_save_sp
+ addi r_tmp, sp, FRAME_R30
+ }
+ {
+ sw r_tmp, r30
+ addi r_tmp, sp, FRAME_R31
+ }
+ {
+ sw r_tmp, r31
+ addi r_tmp, sp, FRAME_R32
+ }
+ {
+ sw r_tmp, r32
+ addi r_tmp, sp, FRAME_R33
+ }
+ {
+ sw r_tmp, r33
+ addi r_tmp, sp, FRAME_R34
+ }
+ {
+ sw r_tmp, r34
+ addi r_tmp, sp, FRAME_R35
+ }
+ sw r_tmp, r35
+
+ /* Move some arguments to callee-save registers. */
+ {
+ move r_context_lo, r_context_lo_in
+ move r_context_hi, r_context_hi_in
+ }
+ {
+ move r_access_lo, r_access_lo_in
+ move r_access_hi, r_access_hi_in
+ }
+ move r_asid, r_asid_in
+
+ /* Disable interrupts, since we can't use our stack. */
+ {
+ mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
+ movei r_tmp, 1
+ }
+ mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
+
+ /* First, flush our L2 cache. */
+ {
+ move r0, zero /* cache_pa */
+ move r1, zero
+ }
+ {
+ auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
+ move r3, r_my_cpumask /* cache_cpumask */
+ }
+ {
+ move r4, zero /* tlb_va */
+ move r5, zero /* tlb_length */
+ }
+ {
+ move r6, zero /* tlb_pgsize */
+ move r7, zero /* tlb_cpumask */
+ }
+ {
+ move r8, zero /* asids */
+ move r9, zero /* asidcount */
+ }
+ jal hv_flush_remote
+ bnz r0, .Ldone
+
+ /* Now install the new page table. */
+ {
+ move r0, r_context_lo
+ move r1, r_context_hi
+ }
+ {
+ move r2, r_access_lo
+ move r3, r_access_hi
+ }
+ {
+ move r4, r_asid
+ movei r5, HV_CTX_DIRECTIO
+ }
+ jal hv_install_context
+ bnz r0, .Ldone
+
+ /* Finally, flush the TLB. */
+ {
+ movei r0, 0 /* preserve_global */
+ jal hv_flush_all
+ }
+
+.Ldone:
+ /* Reset interrupts back how they were before. */
+ mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
+
+ /* Restore the callee-saved registers and return. */
+ addli lr, sp, FRAME_SIZE
+ {
+ lw lr, lr
+ addli r_tmp, sp, FRAME_R30
+ }
+ {
+ lw r30, r_tmp
+ addli r_tmp, sp, FRAME_R31
+ }
+ {
+ lw r31, r_tmp
+ addli r_tmp, sp, FRAME_R32
+ }
+ {
+ lw r32, r_tmp
+ addli r_tmp, sp, FRAME_R33
+ }
+ {
+ lw r33, r_tmp
+ addli r_tmp, sp, FRAME_R34
+ }
+ {
+ lw r34, r_tmp
+ addli r_tmp, sp, FRAME_R35
+ }
+ {
+ lw r35, r_tmp
+ addi sp, sp, FRAME_SIZE
+ }
+ jrp lr
+ STD_ENDPROC(flush_and_install_context)
diff --git a/arch/tile/mm/mmap.c b/arch/tile/mm/mmap.c
new file mode 100644
index 000000000000..f96f4cec602a
--- /dev/null
+++ b/arch/tile/mm/mmap.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ * Taken from the i386 architecture and simplified.
+ */
+
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/limits.h>
+#include <linux/sched.h>
+#include <linux/mman.h>
+#include <linux/compat.h>
+
+/*
+ * Top of mmap area (just below the process stack).
+ *
+ * Leave an at least ~128 MB hole.
+ */
+#define MIN_GAP (128*1024*1024)
+#define MAX_GAP (TASK_SIZE/6*5)
+
+static inline unsigned long mmap_base(struct mm_struct *mm)
+{
+ unsigned long gap = rlimit(RLIMIT_STACK);
+ unsigned long random_factor = 0;
+
+ if (current->flags & PF_RANDOMIZE)
+ random_factor = get_random_int() % (1024*1024);
+
+ if (gap < MIN_GAP)
+ gap = MIN_GAP;
+ else if (gap > MAX_GAP)
+ gap = MAX_GAP;
+
+ return PAGE_ALIGN(TASK_SIZE - gap - random_factor);
+}
+
+/*
+ * This function, called very early during the creation of a new
+ * process VM image, sets up which VM layout function to use:
+ */
+void arch_pick_mmap_layout(struct mm_struct *mm)
+{
+#if !defined(__tilegx__)
+ int is_32bit = 1;
+#elif defined(CONFIG_COMPAT)
+ int is_32bit = is_compat_task();
+#else
+ int is_32bit = 0;
+#endif
+
+ /*
+ * Use standard layout if the expected stack growth is unlimited
+ * or we are running native 64 bits.
+ */
+ if (!is_32bit || rlimit(RLIMIT_STACK) == RLIM_INFINITY) {
+ mm->mmap_base = TASK_UNMAPPED_BASE;
+ mm->get_unmapped_area = arch_get_unmapped_area;
+ mm->unmap_area = arch_unmap_area;
+ } else {
+ mm->mmap_base = mmap_base(mm);
+ mm->get_unmapped_area = arch_get_unmapped_area_topdown;
+ mm->unmap_area = arch_unmap_area_topdown;
+ }
+}
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
new file mode 100644
index 000000000000..289e729bbd76
--- /dev/null
+++ b/arch/tile/mm/pgtable.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/smp.h>
+#include <linux/highmem.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <linux/spinlock.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/fixmap.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/homecache.h>
+
+#define K(x) ((x) << (PAGE_SHIFT-10))
+
+/*
+ * The normal show_free_areas() is too verbose on Tile, with dozens
+ * of processors and often four NUMA zones each with high and lowmem.
+ */
+void show_mem(void)
+{
+ struct zone *zone;
+
+ printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu"
+ " free:%lu\n slab:%lu mapped:%lu pagetables:%lu bounce:%lu"
+ " pagecache:%lu swap:%lu\n",
+ (global_page_state(NR_ACTIVE_ANON) +
+ global_page_state(NR_ACTIVE_FILE)),
+ (global_page_state(NR_INACTIVE_ANON) +
+ global_page_state(NR_INACTIVE_FILE)),
+ global_page_state(NR_FILE_DIRTY),
+ global_page_state(NR_WRITEBACK),
+ global_page_state(NR_UNSTABLE_NFS),
+ global_page_state(NR_FREE_PAGES),
+ (global_page_state(NR_SLAB_RECLAIMABLE) +
+ global_page_state(NR_SLAB_UNRECLAIMABLE)),
+ global_page_state(NR_FILE_MAPPED),
+ global_page_state(NR_PAGETABLE),
+ global_page_state(NR_BOUNCE),
+ global_page_state(NR_FILE_PAGES),
+ nr_swap_pages);
+
+ for_each_zone(zone) {
+ unsigned long flags, order, total = 0, largest_order = -1;
+
+ if (!populated_zone(zone))
+ continue;
+
+ printk("Node %d %7s: ", zone_to_nid(zone), zone->name);
+ spin_lock_irqsave(&zone->lock, flags);
+ for (order = 0; order < MAX_ORDER; order++) {
+ int nr = zone->free_area[order].nr_free;
+ total += nr << order;
+ if (nr)
+ largest_order = order;
+ }
+ spin_unlock_irqrestore(&zone->lock, flags);
+ printk("%lukB (largest %luKb)\n",
+ K(total), largest_order ? K(1UL) << largest_order : 0);
+ }
+}
+
+/*
+ * Associate a virtual page frame with a given physical page frame
+ * and protection flags for that frame.
+ */
+static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ if (pgd_none(*pgd)) {
+ BUG();
+ return;
+ }
+ pud = pud_offset(pgd, vaddr);
+ if (pud_none(*pud)) {
+ BUG();
+ return;
+ }
+ pmd = pmd_offset(pud, vaddr);
+ if (pmd_none(*pmd)) {
+ BUG();
+ return;
+ }
+ pte = pte_offset_kernel(pmd, vaddr);
+ /* <pfn,flags> stored as-is, to permit clearing entries */
+ set_pte(pte, pfn_pte(pfn, flags));
+
+ /*
+ * It's enough to flush this one mapping.
+ * This appears conservative since it is only called
+ * from __set_fixmap.
+ */
+ local_flush_tlb_page(NULL, vaddr, PAGE_SIZE);
+}
+
+/*
+ * Associate a huge virtual page frame with a given physical page frame
+ * and protection flags for that frame. pfn is for the base of the page,
+ * vaddr is what the page gets mapped to - both must be properly aligned.
+ * The pmd must already be instantiated.
+ */
+void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */
+ printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
+ return; /* BUG(); */
+ }
+ if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */
+ printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
+ return; /* BUG(); */
+ }
+ pgd = swapper_pg_dir + pgd_index(vaddr);
+ if (pgd_none(*pgd)) {
+ printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
+ return; /* BUG(); */
+ }
+ pud = pud_offset(pgd, vaddr);
+ pmd = pmd_offset(pud, vaddr);
+ set_pmd(pmd, ptfn_pmd(HV_PFN_TO_PTFN(pfn), flags));
+ /*
+ * It's enough to flush this one mapping.
+ * We flush both small and huge TSBs to be sure.
+ */
+ local_flush_tlb_page(NULL, vaddr, HPAGE_SIZE);
+ local_flush_tlb_pages(NULL, vaddr, PAGE_SIZE, HPAGE_SIZE);
+}
+
+void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
+{
+ unsigned long address = __fix_to_virt(idx);
+
+ if (idx >= __end_of_fixed_addresses) {
+ BUG();
+ return;
+ }
+ set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
+}
+
+#if defined(CONFIG_HIGHPTE)
+pte_t *_pte_offset_map(pmd_t *dir, unsigned long address, enum km_type type)
+{
+ pte_t *pte = kmap_atomic(pmd_page(*dir), type) +
+ (pmd_ptfn(*dir) << HV_LOG2_PAGE_TABLE_ALIGN) & ~PAGE_MASK;
+ return &pte[pte_index(address)];
+}
+#endif
+
+/*
+ * List of all pgd's needed so it can invalidate entries in both cached
+ * and uncached pgd's. This is essentially codepath-based locking
+ * against pageattr.c; it is the unique case in which a valid change
+ * of kernel pagetables can't be lazily synchronized by vmalloc faults.
+ * vmalloc faults work because attached pagetables are never freed.
+ * The locking scheme was chosen on the basis of manfred's
+ * recommendations and having no core impact whatsoever.
+ * -- wli
+ */
+DEFINE_SPINLOCK(pgd_lock);
+LIST_HEAD(pgd_list);
+
+static inline void pgd_list_add(pgd_t *pgd)
+{
+ list_add(pgd_to_list(pgd), &pgd_list);
+}
+
+static inline void pgd_list_del(pgd_t *pgd)
+{
+ list_del(pgd_to_list(pgd));
+}
+
+#define KERNEL_PGD_INDEX_START pgd_index(PAGE_OFFSET)
+#define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_INDEX_START)
+
+static void pgd_ctor(pgd_t *pgd)
+{
+ unsigned long flags;
+
+ memset(pgd, 0, KERNEL_PGD_INDEX_START*sizeof(pgd_t));
+ spin_lock_irqsave(&pgd_lock, flags);
+
+#ifndef __tilegx__
+ /*
+ * Check that the user interrupt vector has no L2.
+ * It never should for the swapper, and new page tables
+ * should always start with an empty user interrupt vector.
+ */
+ BUG_ON(((u64 *)swapper_pg_dir)[pgd_index(MEM_USER_INTRPT)] != 0);
+#endif
+
+ clone_pgd_range(pgd + KERNEL_PGD_INDEX_START,
+ swapper_pg_dir + KERNEL_PGD_INDEX_START,
+ KERNEL_PGD_PTRS);
+
+ pgd_list_add(pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
+static void pgd_dtor(pgd_t *pgd)
+{
+ unsigned long flags; /* can be called from interrupt context */
+
+ spin_lock_irqsave(&pgd_lock, flags);
+ pgd_list_del(pgd);
+ spin_unlock_irqrestore(&pgd_lock, flags);
+}
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL);
+ if (pgd)
+ pgd_ctor(pgd);
+ return pgd;
+}
+
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+ pgd_dtor(pgd);
+ kmem_cache_free(pgd_cache, pgd);
+}
+
+
+#define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER)
+
+struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ int flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO|__GFP_COMP;
+ struct page *p;
+
+#ifdef CONFIG_HIGHPTE
+ flags |= __GFP_HIGHMEM;
+#endif
+
+ p = alloc_pages(flags, L2_USER_PGTABLE_ORDER);
+ if (p == NULL)
+ return NULL;
+
+ pgtable_page_ctor(p);
+ return p;
+}
+
+/*
+ * Free page immediately (used in __pte_alloc if we raced with another
+ * process). We have to correct whatever pte_alloc_one() did before
+ * returning the pages to the allocator.
+ */
+void pte_free(struct mm_struct *mm, struct page *p)
+{
+ pgtable_page_dtor(p);
+ __free_pages(p, L2_USER_PGTABLE_ORDER);
+}
+
+void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
+ unsigned long address)
+{
+ int i;
+
+ pgtable_page_dtor(pte);
+ tlb->need_flush = 1;
+ if (tlb_fast_mode(tlb)) {
+ struct page *pte_pages[L2_USER_PGTABLE_PAGES];
+ for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i)
+ pte_pages[i] = pte + i;
+ free_pages_and_swap_cache(pte_pages, L2_USER_PGTABLE_PAGES);
+ return;
+ }
+ for (i = 0; i < L2_USER_PGTABLE_PAGES; ++i) {
+ tlb->pages[tlb->nr++] = pte + i;
+ if (tlb->nr >= FREE_PTE_NR)
+ tlb_flush_mmu(tlb, 0, 0);
+ }
+}
+
+#ifndef __tilegx__
+
+/*
+ * FIXME: needs to be atomic vs hypervisor writes. For now we make the
+ * window of vulnerability a bit smaller by doing an unlocked 8-bit update.
+ */
+int ptep_test_and_clear_young(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+#if HV_PTE_INDEX_ACCESSED < 8 || HV_PTE_INDEX_ACCESSED >= 16
+# error Code assumes HV_PTE "accessed" bit in second byte
+#endif
+ u8 *tmp = (u8 *)ptep;
+ u8 second_byte = tmp[1];
+ if (!(second_byte & (1 << (HV_PTE_INDEX_ACCESSED - 8))))
+ return 0;
+ tmp[1] = second_byte & ~(1 << (HV_PTE_INDEX_ACCESSED - 8));
+ return 1;
+}
+
+/*
+ * This implementation is atomic vs hypervisor writes, since the hypervisor
+ * always writes the low word (where "accessed" and "dirty" are) and this
+ * routine only writes the high word.
+ */
+void ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+#if HV_PTE_INDEX_WRITABLE < 32
+# error Code assumes HV_PTE "writable" bit in high word
+#endif
+ u32 *tmp = (u32 *)ptep;
+ tmp[1] = tmp[1] & ~(1 << (HV_PTE_INDEX_WRITABLE - 32));
+}
+
+#endif
+
+pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ if (pgd_addr_invalid(addr))
+ return NULL;
+
+ pgd = mm ? pgd_offset(mm, addr) : swapper_pg_dir + pgd_index(addr);
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ return NULL;
+ pmd = pmd_offset(pud, addr);
+ if (pmd_huge_page(*pmd))
+ return (pte_t *)pmd;
+ if (!pmd_present(*pmd))
+ return NULL;
+ return pte_offset_kernel(pmd, addr);
+}
+
+pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu)
+{
+ unsigned int width = smp_width;
+ int x = cpu % width;
+ int y = cpu / width;
+ BUG_ON(y >= smp_height);
+ BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3);
+ BUG_ON(cpu < 0 || cpu >= NR_CPUS);
+ BUG_ON(!cpu_is_valid_lotar(cpu));
+ return hv_pte_set_lotar(prot, HV_XY_TO_LOTAR(x, y));
+}
+
+int get_remote_cache_cpu(pgprot_t prot)
+{
+ HV_LOTAR lotar = hv_pte_get_lotar(prot);
+ int x = HV_LOTAR_X(lotar);
+ int y = HV_LOTAR_Y(lotar);
+ BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3);
+ return x + y * smp_width;
+}
+
+void set_pte_order(pte_t *ptep, pte_t pte, int order)
+{
+ unsigned long pfn = pte_pfn(pte);
+ struct page *page = pfn_to_page(pfn);
+
+ /* Update the home of a PTE if necessary */
+ pte = pte_set_home(pte, page_home(page));
+
+#ifdef __tilegx__
+ *ptep = pte;
+#else
+ /*
+ * When setting a PTE, write the high bits first, then write
+ * the low bits. This sets the "present" bit only after the
+ * other bits are in place. If a particular PTE update
+ * involves transitioning from one valid PTE to another, it
+ * may be necessary to call set_pte_order() more than once,
+ * transitioning via a suitable intermediate state.
+ * Note that this sequence also means that if we are transitioning
+ * from any migrating PTE to a non-migrating one, we will not
+ * see a half-updated PTE with the migrating bit off.
+ */
+#if HV_PTE_INDEX_PRESENT >= 32 || HV_PTE_INDEX_MIGRATING >= 32
+# error Must write the present and migrating bits last
+#endif
+ ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32);
+ barrier();
+ ((u32 *)ptep)[0] = (u32)(pte_val(pte));
+#endif
+}
+
+/* Can this mm load a PTE with cached_priority set? */
+static inline int mm_is_priority_cached(struct mm_struct *mm)
+{
+ return mm->context.priority_cached;
+}
+
+/*
+ * Add a priority mapping to an mm_context and
+ * notify the hypervisor if this is the first one.
+ */
+void start_mm_caching(struct mm_struct *mm)
+{
+ if (!mm_is_priority_cached(mm)) {
+ mm->context.priority_cached = -1U;
+ hv_set_caching(-1U);
+ }
+}
+
+/*
+ * Validate and return the priority_cached flag. We know if it's zero
+ * that we don't need to scan, since we immediately set it non-zero
+ * when we first consider a MAP_CACHE_PRIORITY mapping.
+ *
+ * We only _try_ to acquire the mmap_sem semaphore; if we can't acquire it,
+ * since we're in an interrupt context (servicing switch_mm) we don't
+ * worry about it and don't unset the "priority_cached" field.
+ * Presumably we'll come back later and have more luck and clear
+ * the value then; for now we'll just keep the cache marked for priority.
+ */
+static unsigned int update_priority_cached(struct mm_struct *mm)
+{
+ if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) {
+ struct vm_area_struct *vm;
+ for (vm = mm->mmap; vm; vm = vm->vm_next) {
+ if (hv_pte_get_cached_priority(vm->vm_page_prot))
+ break;
+ }
+ if (vm == NULL)
+ mm->context.priority_cached = 0;
+ up_write(&mm->mmap_sem);
+ }
+ return mm->context.priority_cached;
+}
+
+/* Set caching correctly for an mm that we are switching to. */
+void check_mm_caching(struct mm_struct *prev, struct mm_struct *next)
+{
+ if (!mm_is_priority_cached(next)) {
+ /*
+ * If the new mm doesn't use priority caching, just see if we
+ * need the hv_set_caching(), or can assume it's already zero.
+ */
+ if (mm_is_priority_cached(prev))
+ hv_set_caching(0);
+ } else {
+ hv_set_caching(update_priority_cached(next));
+ }
+}
+
+#if CHIP_HAS_MMIO()
+
+/* Map an arbitrary MMIO address, homed according to pgprot, into VA space. */
+void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size,
+ pgprot_t home)
+{
+ void *addr;
+ struct vm_struct *area;
+ unsigned long offset, last_addr;
+ pgprot_t pgprot;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+ if (!size || last_addr < phys_addr)
+ return NULL;
+
+ /* Create a read/write, MMIO VA mapping homed at the requested shim. */
+ pgprot = PAGE_KERNEL;
+ pgprot = hv_pte_set_mode(pgprot, HV_PTE_MODE_MMIO);
+ pgprot = hv_pte_set_lotar(pgprot, hv_pte_get_lotar(home));
+
+ /*
+ * Mappings have to be page-aligned
+ */
+ offset = phys_addr & ~PAGE_MASK;
+ phys_addr &= PAGE_MASK;
+ size = PAGE_ALIGN(last_addr+1) - phys_addr;
+
+ /*
+ * Ok, go for it..
+ */
+ area = get_vm_area(size, VM_IOREMAP /* | other flags? */);
+ if (!area)
+ return NULL;
+ area->phys_addr = phys_addr;
+ addr = area->addr;
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
+ remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
+ return NULL;
+ }
+ return (__force void __iomem *) (offset + (char *)addr);
+}
+EXPORT_SYMBOL(ioremap_prot);
+
+/* Map a PCI MMIO bus address into VA space. */
+void __iomem *ioremap(resource_size_t phys_addr, unsigned long size)
+{
+ panic("ioremap for PCI MMIO is not supported");
+}
+EXPORT_SYMBOL(ioremap);
+
+/* Unmap an MMIO VA mapping. */
+void iounmap(volatile void __iomem *addr_in)
+{
+ volatile void __iomem *addr = (volatile void __iomem *)
+ (PAGE_MASK & (unsigned long __force)addr_in);
+#if 1
+ vunmap((void * __force)addr);
+#else
+ /* x86 uses this complicated flow instead of vunmap(). Is
+ * there any particular reason we should do the same? */
+ struct vm_struct *p, *o;
+
+ /* Use the vm area unlocked, assuming the caller
+ ensures there isn't another iounmap for the same address
+ in parallel. Reuse of the virtual address is prevented by
+ leaving it in the global lists until we're done with it.
+ cpa takes care of the direct mappings. */
+ read_lock(&vmlist_lock);
+ for (p = vmlist; p; p = p->next) {
+ if (p->addr == addr)
+ break;
+ }
+ read_unlock(&vmlist_lock);
+
+ if (!p) {
+ printk("iounmap: bad address %p\n", addr);
+ dump_stack();
+ return;
+ }
+
+ /* Finally remove it */
+ o = remove_vm_area((void *)addr);
+ BUG_ON(p != o || o == NULL);
+ kfree(p);
+#endif
+}
+EXPORT_SYMBOL(iounmap);
+
+#endif /* CHIP_HAS_MMIO() */
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index ae42695c3597..162855ce32b4 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -186,7 +186,9 @@ static int hostaudio_open(struct inode *inode, struct file *file)
int ret;
#ifdef DEBUG
+ kparam_block_sysfs_write(dsp);
printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp);
+ kparam_unblock_sysfs_write(dsp);
#endif
state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
@@ -198,7 +200,9 @@ static int hostaudio_open(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
+ kparam_block_sysfs_write(dsp);
ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
+ kparam_unblock_sysfs_write(dsp);
if (ret < 0) {
kfree(state);
return ret;
@@ -254,11 +258,15 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
if (file->f_mode & FMODE_WRITE)
w = 1;
+ kparam_block_sysfs_write(mixer);
ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
+ kparam_unblock_sysfs_write(mixer);
if (ret < 0) {
+ kparam_block_sysfs_write(dsp);
printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
"err = %d\n", dsp, -ret);
+ kparam_unblock_sysfs_write(dsp);
kfree(state);
return ret;
}
@@ -314,8 +322,10 @@ MODULE_LICENSE("GPL");
static int __init hostaudio_init_module(void)
{
+ __kernel_param_lock();
printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
dsp, mixer);
+ __kernel_param_unlock();
module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
if (module_data.dev_audio < 0) {
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 7fcad58e216d..69268014dd8e 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -94,7 +94,7 @@ SECTIONS
.data : {
INIT_TASK_DATA(KERNEL_STACK_SIZE)
. = ALIGN(KERNEL_STACK_SIZE);
- *(.data.init_irqstack)
+ *(.data..init_irqstack)
DATA_DATA
*(.data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 8aa77b61a5ff..ddc9698b66ed 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -34,5 +34,5 @@ union thread_union init_thread_union __init_task_data =
{ INIT_THREAD_INFO(init_task) };
union thread_union cpu0_irqstack
- __attribute__((__section__(".data.init_irqstack"))) =
+ __attribute__((__section__(".data..init_irqstack"))) =
{ INIT_THREAD_INFO(init_task) };
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c
index e22c96993db3..696634214dc6 100644
--- a/arch/um/kernel/skas/uaccess.c
+++ b/arch/um/kernel/skas/uaccess.c
@@ -81,7 +81,7 @@ static int do_op_one_page(unsigned long addr, int len, int is_write,
current->thread.fault_catcher = NULL;
- kunmap_atomic(page, KM_UML_USERCOPY);
+ kunmap_atomic((void *)addr, KM_UML_USERCOPY);
return n;
}
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index e7a6cca667aa..ec6378550671 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -50,7 +50,7 @@ SECTIONS
{
INIT_TASK_DATA(KERNEL_STACK_SIZE)
. = ALIGN(KERNEL_STACK_SIZE);
- *(.data.init_irqstack)
+ *(.data..init_irqstack)
DATA_DATA
*(.gnu.linkonce.d*)
CONSTRUCTORS
diff --git a/arch/x86/.gitignore b/arch/x86/.gitignore
new file mode 100644
index 000000000000..028079065af6
--- /dev/null
+++ b/arch/x86/.gitignore
@@ -0,0 +1,3 @@
+boot/compressed/vmlinux
+tools/test_get_len
+
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index dcb0593b4a66..fc847b4ba274 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -55,6 +55,7 @@ config X86
select HAVE_HW_BREAKPOINT
select HAVE_MIXED_BREAKPOINTS_REGS
select PERF_EVENTS
+ select HAVE_PERF_EVENTS_NMI
select ANON_INODES
select HAVE_ARCH_KMEMCHECK
select HAVE_USER_RETURN_NOTIFIER
@@ -2072,6 +2073,8 @@ source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
+source "drivers/vbus/Kconfig"
+
endmenu
diff --git a/arch/x86/boot/compressed/mkpiggy.c b/arch/x86/boot/compressed/mkpiggy.c
index bcbd36c41432..5c228129d175 100644
--- a/arch/x86/boot/compressed/mkpiggy.c
+++ b/arch/x86/boot/compressed/mkpiggy.c
@@ -77,7 +77,7 @@ int main(int argc, char *argv[])
offs += 32*1024 + 18; /* Add 32K + 18 bytes slack */
offs = (offs+4095) & ~4095; /* Round to a 4K boundary */
- printf(".section \".rodata.compressed\",\"a\",@progbits\n");
+ printf(".section \".rodata..compressed\",\"a\",@progbits\n");
printf(".globl z_input_len\n");
printf("z_input_len = %lu\n", ilen);
printf(".globl z_output_len\n");
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index a6f1a59a5b0c..5ddabceee124 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -26,8 +26,8 @@ SECTIONS
HEAD_TEXT
_ehead = . ;
}
- .rodata.compressed : {
- *(.rodata.compressed)
+ .rodata..compressed : {
+ *(.rodata..compressed)
}
.text : {
_text = .; /* Text */
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index e790bc1fbfa3..17cf65c94804 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -842,4 +842,6 @@ ia32_sys_call_table:
.quad compat_sys_rt_tgsigqueueinfo /* 335 */
.quad sys_perf_event_open
.quad compat_sys_recvmmsg
+ .quad sys_fanotify_init
+ .quad sys32_fanotify_mark
ia32_syscall_end:
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index 626be156d88d..3d093311d5e2 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -546,3 +546,12 @@ asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo,
return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo,
((u64)len_hi << 32) | len_lo);
}
+
+asmlinkage long sys32_fanotify_mark(int fanotify_fd, unsigned int flags,
+ u32 mask_lo, u32 mask_hi,
+ int fd, const char __user *pathname)
+{
+ return sys_fanotify_mark(fanotify_fd, flags,
+ ((u64)mask_hi << 32) | mask_lo,
+ fd, pathname);
+}
diff --git a/arch/x86/include/asm/apb_timer.h b/arch/x86/include/asm/apb_timer.h
index c74a2eebe570..a69b1ac9eaf8 100644
--- a/arch/x86/include/asm/apb_timer.h
+++ b/arch/x86/include/asm/apb_timer.h
@@ -55,7 +55,6 @@ extern unsigned long apbt_quick_calibrate(void);
extern int arch_setup_apbt_irqs(int irq, int trigger, int mask, int cpu);
extern void apbt_setup_secondary_clock(void);
extern unsigned int boot_cpu_id;
-extern int disable_apbt_percpu;
extern struct sfi_timer_table_entry *sfi_get_mtmr(int hint);
extern void sfi_free_mtmr(struct sfi_timer_table_entry *mtmr);
diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h
index 2f9047cfaaca..48f99f15452e 100644
--- a/arch/x86/include/asm/cache.h
+++ b/arch/x86/include/asm/cache.h
@@ -7,7 +7,7 @@
#define L1_CACHE_SHIFT (CONFIG_X86_L1_CACHE_SHIFT)
#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT)
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
#define INTERNODE_CACHE_SHIFT CONFIG_X86_INTERNODE_CACHE_SHIFT
#define INTERNODE_CACHE_BYTES (1 << INTERNODE_CACHE_SHIFT)
diff --git a/arch/x86/include/asm/mrst.h b/arch/x86/include/asm/mrst.h
index 451d30e7f62d..16350740edf6 100644
--- a/arch/x86/include/asm/mrst.h
+++ b/arch/x86/include/asm/mrst.h
@@ -13,6 +13,32 @@
extern int pci_mrst_init(void);
int __init sfi_parse_mrtc(struct sfi_table_header *table);
+/*
+ * Medfield is the follow-up of Moorestown, it combines two chip solution into
+ * one. Other than that it also added always-on and constant tsc and lapic
+ * timers. Medfield is the platform name, and the chip name is called Penwell
+ * we treat Medfield/Penwell as a variant of Moorestown. Penwell can be
+ * identified via MSRs.
+ */
+enum mrst_cpu_type {
+ MRST_CPU_CHIP_LINCROFT = 1,
+ MRST_CPU_CHIP_PENWELL,
+};
+
+extern enum mrst_cpu_type __mrst_cpu_chip;
+static enum mrst_cpu_type mrst_identify_cpu(void)
+{
+ return __mrst_cpu_chip;
+}
+
+enum mrst_timer_options {
+ MRST_TIMER_DEFAULT,
+ MRST_TIMER_APBT_ONLY,
+ MRST_TIMER_LAPIC_APBT,
+};
+
+extern enum mrst_timer_options mrst_timer_options;
+
#define SFI_MTMR_MAX_NUM 8
#define SFI_MRTC_MAX 8
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index b49d8ca228f6..8c7ae4318629 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -110,6 +110,7 @@
#define MSR_AMD64_PATCH_LOADER 0xc0010020
#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140
#define MSR_AMD64_OSVW_STATUS 0xc0010141
+#define MSR_AMD64_DC_CFG 0xc0011022
#define MSR_AMD64_IBSFETCHCTL 0xc0011030
#define MSR_AMD64_IBSFETCHLINAD 0xc0011031
#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032
diff --git a/arch/x86/include/asm/nmi.h b/arch/x86/include/asm/nmi.h
index 93da9c3f3341..932f0f86b4b7 100644
--- a/arch/x86/include/asm/nmi.h
+++ b/arch/x86/include/asm/nmi.h
@@ -17,7 +17,9 @@ int do_nmi_callback(struct pt_regs *regs, int cpu);
extern void die_nmi(char *str, struct pt_regs *regs, int do_panic);
extern int check_nmi_watchdog(void);
+#if !defined(CONFIG_LOCKUP_DETECTOR)
extern int nmi_watchdog_enabled;
+#endif
extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
extern int reserve_perfctr_nmi(unsigned int);
extern void release_perfctr_nmi(unsigned int);
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 8d8797eae5d7..49c7219826f9 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -30,6 +30,7 @@
#define PCI_HAS_IO_ECS 0x40000
#define PCI_NOASSIGN_ROMS 0x80000
#define PCI_ROOT_NO_CRS 0x100000
+#define PCI_NOASSIGN_BARS 0x200000
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
@@ -53,6 +54,8 @@ extern int pcibios_last_bus;
extern struct pci_bus *pci_root_bus;
extern struct pci_ops pci_root_ops;
+void pcibios_scan_specific_bus(int busn);
+
/* pci-irq.c */
struct irq_info {
diff --git a/arch/x86/include/asm/sys_ia32.h b/arch/x86/include/asm/sys_ia32.h
index 3ad421784ae7..cf4e2e381cba 100644
--- a/arch/x86/include/asm/sys_ia32.h
+++ b/arch/x86/include/asm/sys_ia32.h
@@ -80,4 +80,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *);
/* ia32/ipc32.c */
asmlinkage long sys32_ipc(u32, int, int, int, compat_uptr_t, u32);
+
+asmlinkage long sys32_fanotify_mark(int, unsigned int, u32, u32, int,
+ const char __user *);
#endif /* _ASM_X86_SYS_IA32_H */
diff --git a/arch/x86/include/asm/unistd_32.h b/arch/x86/include/asm/unistd_32.h
index beb9b5f8f8a4..80b799cd74f7 100644
--- a/arch/x86/include/asm/unistd_32.h
+++ b/arch/x86/include/asm/unistd_32.h
@@ -343,10 +343,12 @@
#define __NR_rt_tgsigqueueinfo 335
#define __NR_perf_event_open 336
#define __NR_recvmmsg 337
+#define __NR_fanotify_init 338
+#define __NR_fanotify_mark 339
#ifdef __KERNEL__
-#define NR_syscalls 338
+#define NR_syscalls 340
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index ff4307b0e81e..5b7b1d585616 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -663,6 +663,10 @@ __SYSCALL(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo)
__SYSCALL(__NR_perf_event_open, sys_perf_event_open)
#define __NR_recvmmsg 299
__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+#define __NR_fanotify_init 300
+__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
+#define __NR_fanotify_mark 301
+__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index 8ded418b0593..13ab720573e3 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -1,4 +1,4 @@
- .section .text.page_aligned
+ .section .text..page_aligned
#include <linux/linkage.h>
#include <asm/segment.h>
#include <asm/page_types.h>
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index fa5a1474cd18..0d20286d78c6 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -1487,6 +1487,7 @@ static int __attach_device(struct device *dev,
struct protection_domain *domain)
{
struct iommu_dev_data *dev_data, *alias_data;
+ int ret;
dev_data = get_dev_data(dev);
alias_data = get_dev_data(dev_data->alias);
@@ -1498,13 +1499,14 @@ static int __attach_device(struct device *dev,
spin_lock(&domain->lock);
/* Some sanity checks */
+ ret = -EBUSY;
if (alias_data->domain != NULL &&
alias_data->domain != domain)
- return -EBUSY;
+ goto out_unlock;
if (dev_data->domain != NULL &&
dev_data->domain != domain)
- return -EBUSY;
+ goto out_unlock;
/* Do real assignment */
if (dev_data->alias != dev) {
@@ -1520,10 +1522,14 @@ static int __attach_device(struct device *dev,
atomic_inc(&dev_data->bind);
+ ret = 0;
+
+out_unlock:
+
/* ready */
spin_unlock(&domain->lock);
- return 0;
+ return ret;
}
/*
@@ -2324,10 +2330,6 @@ int __init amd_iommu_init_dma_ops(void)
iommu_detected = 1;
swiotlb = 0;
-#ifdef CONFIG_GART_IOMMU
- gart_iommu_aperture_disabled = 1;
- gart_iommu_aperture = 0;
-#endif
/* Make the driver finally visible to the drivers */
dma_ops = &amd_iommu_dma_ops;
diff --git a/arch/x86/kernel/amd_iommu_init.c b/arch/x86/kernel/amd_iommu_init.c
index 3bacb4d0844c..3cc63e2b8dd4 100644
--- a/arch/x86/kernel/amd_iommu_init.c
+++ b/arch/x86/kernel/amd_iommu_init.c
@@ -287,8 +287,12 @@ static u8 * __init iommu_map_mmio_space(u64 address)
{
u8 *ret;
- if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu"))
+ if (!request_mem_region(address, MMIO_REGION_LENGTH, "amd_iommu")) {
+ pr_err("AMD-Vi: Can not reserve memory region %llx for mmio\n",
+ address);
+ pr_err("AMD-Vi: This is a BIOS bug. Please contact your hardware vendor\n");
return NULL;
+ }
ret = ioremap_nocache(address, MMIO_REGION_LENGTH);
if (ret != NULL)
@@ -1314,7 +1318,7 @@ static int __init amd_iommu_init(void)
ret = amd_iommu_init_dma_ops();
if (ret)
- goto free;
+ goto free_disable;
amd_iommu_init_api();
@@ -1332,9 +1336,10 @@ static int __init amd_iommu_init(void)
out:
return ret;
-free:
+free_disable:
disable_iommus();
+free:
amd_iommu_uninit_devices();
free_pages((unsigned long)amd_iommu_pd_alloc_bitmap,
@@ -1353,6 +1358,15 @@ free:
free_unity_maps();
+#ifdef CONFIG_GART_IOMMU
+ /*
+ * We failed to initialize the AMD IOMMU - try fallback to GART
+ * if possible.
+ */
+ gart_iommu_init();
+
+#endif
+
goto out;
}
diff --git a/arch/x86/kernel/apb_timer.c b/arch/x86/kernel/apb_timer.c
index a35347501d36..8dd77800ff5d 100644
--- a/arch/x86/kernel/apb_timer.c
+++ b/arch/x86/kernel/apb_timer.c
@@ -43,10 +43,11 @@
#include <asm/fixmap.h>
#include <asm/apb_timer.h>
+#include <asm/mrst.h>
#define APBT_MASK CLOCKSOURCE_MASK(32)
#define APBT_SHIFT 22
-#define APBT_CLOCKEVENT_RATING 150
+#define APBT_CLOCKEVENT_RATING 110
#define APBT_CLOCKSOURCE_RATING 250
#define APBT_MIN_DELTA_USEC 200
@@ -83,8 +84,6 @@ struct apbt_dev {
char name[10];
};
-int disable_apbt_percpu __cpuinitdata;
-
static DEFINE_PER_CPU(struct apbt_dev, cpu_apbt_dev);
#ifdef CONFIG_SMP
@@ -195,29 +194,6 @@ static struct clock_event_device apbt_clockevent = {
};
/*
- * if user does not want to use per CPU apb timer, just give it a lower rating
- * than local apic timer and skip the late per cpu timer init.
- */
-static inline int __init setup_x86_mrst_timer(char *arg)
-{
- if (!arg)
- return -EINVAL;
-
- if (strcmp("apbt_only", arg) == 0)
- disable_apbt_percpu = 0;
- else if (strcmp("lapic_and_apbt", arg) == 0)
- disable_apbt_percpu = 1;
- else {
- pr_warning("X86 MRST timer option %s not recognised"
- " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
- arg);
- return -EINVAL;
- }
- return 0;
-}
-__setup("x86_mrst_timer=", setup_x86_mrst_timer);
-
-/*
* start count down from 0xffff_ffff. this is done by toggling the enable bit
* then load initial load count to ~0.
*/
@@ -335,7 +311,7 @@ static int __init apbt_clockevent_register(void)
adev->num = smp_processor_id();
memcpy(&adev->evt, &apbt_clockevent, sizeof(struct clock_event_device));
- if (disable_apbt_percpu) {
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
apbt_clockevent.rating = APBT_CLOCKEVENT_RATING - 100;
global_clock_event = &adev->evt;
printk(KERN_DEBUG "%s clockevent registered as global\n",
@@ -429,7 +405,8 @@ static int apbt_cpuhp_notify(struct notifier_block *n,
static __init int apbt_late_init(void)
{
- if (disable_apbt_percpu || !apb_timer_block_enabled)
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT ||
+ !apb_timer_block_enabled)
return 0;
/* This notifier should be called after workqueue is ready */
hotcpu_notifier(apbt_cpuhp_notify, -20);
@@ -450,6 +427,8 @@ static void apbt_set_mode(enum clock_event_mode mode,
int timer_num;
struct apbt_dev *adev = EVT_TO_APBT_DEV(evt);
+ BUG_ON(!apbt_virt_address);
+
timer_num = adev->num;
pr_debug("%s CPU %d timer %d mode=%d\n",
__func__, first_cpu(*evt->cpumask), timer_num, mode);
@@ -676,7 +655,7 @@ void __init apbt_time_init(void)
}
#ifdef CONFIG_SMP
/* kernel cmdline disable apb timer, so we will use lapic timers */
- if (disable_apbt_percpu) {
+ if (mrst_timer_options == MRST_TIMER_LAPIC_APBT) {
printk(KERN_INFO "apbt: disabled per cpu timer\n");
return;
}
diff --git a/arch/x86/kernel/apic/Makefile b/arch/x86/kernel/apic/Makefile
index 565c1bfc507d..910f20b457c4 100644
--- a/arch/x86/kernel/apic/Makefile
+++ b/arch/x86/kernel/apic/Makefile
@@ -2,7 +2,12 @@
# Makefile for local APIC drivers and for the IO-APIC code
#
-obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o nmi.o
+obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o probe_$(BITS).o ipi.o
+ifneq ($(CONFIG_HARDLOCKUP_DETECTOR),y)
+obj-$(CONFIG_X86_LOCAL_APIC) += nmi.o
+endif
+obj-$(CONFIG_HARDLOCKUP_DETECTOR) += hw_nmi.o
+
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_SMP) += ipi.o
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
new file mode 100644
index 000000000000..cefd6942f0e9
--- /dev/null
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -0,0 +1,107 @@
+/*
+ * HW NMI watchdog support
+ *
+ * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *
+ * Arch specific calls to support NMI watchdog
+ *
+ * Bits copied from original nmi.c file
+ *
+ */
+#include <asm/apic.h>
+
+#include <linux/cpumask.h>
+#include <linux/kdebug.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+#include <linux/nmi.h>
+#include <linux/module.h>
+
+/* For reliability, we're prepared to waste bits here. */
+static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+
+u64 hw_nmi_get_sample_period(void)
+{
+ return (u64)(cpu_khz) * 1000 * 60;
+}
+
+#ifdef ARCH_HAS_NMI_WATCHDOG
+void arch_trigger_all_cpu_backtrace(void)
+{
+ int i;
+
+ cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
+
+ printk(KERN_INFO "sending NMI to all CPUs:\n");
+ apic->send_IPI_all(NMI_VECTOR);
+
+ /* Wait for up to 10 seconds for all CPUs to do the backtrace */
+ for (i = 0; i < 10 * 1000; i++) {
+ if (cpumask_empty(to_cpumask(backtrace_mask)))
+ break;
+ mdelay(1);
+ }
+}
+
+static int __kprobes
+arch_trigger_all_cpu_backtrace_handler(struct notifier_block *self,
+ unsigned long cmd, void *__args)
+{
+ struct die_args *args = __args;
+ struct pt_regs *regs;
+ int cpu = smp_processor_id();
+
+ switch (cmd) {
+ case DIE_NMI:
+ case DIE_NMI_IPI:
+ break;
+
+ default:
+ return NOTIFY_DONE;
+ }
+
+ regs = args->regs;
+
+ if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
+ static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+ arch_spin_lock(&lock);
+ printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
+ show_regs(regs);
+ dump_stack();
+ arch_spin_unlock(&lock);
+ cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+ return NOTIFY_STOP;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static __read_mostly struct notifier_block backtrace_notifier = {
+ .notifier_call = arch_trigger_all_cpu_backtrace_handler,
+ .next = NULL,
+ .priority = 1
+};
+
+static int __init register_trigger_all_cpu_backtrace(void)
+{
+ register_die_notifier(&backtrace_notifier);
+ return 0;
+}
+early_initcall(register_trigger_all_cpu_backtrace);
+#endif
+
+/* STUB calls to mimic old nmi_watchdog behaviour */
+#if defined(CONFIG_X86_LOCAL_APIC)
+unsigned int nmi_watchdog = NMI_NONE;
+EXPORT_SYMBOL(nmi_watchdog);
+void acpi_nmi_enable(void) { return; }
+void acpi_nmi_disable(void) { return; }
+#endif
+atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
+EXPORT_SYMBOL(nmi_active);
+int unknown_nmi_panic;
+void cpu_nmi_set_wd_enabled(void) { return; }
+void stop_apic_nmi_watchdog(void *unused) { return; }
+void setup_apic_nmi_watchdog(void *unused) { return; }
+int __init check_nmi_watchdog(void) { return 0; }
diff --git a/arch/x86/kernel/apic/nmi.c b/arch/x86/kernel/apic/nmi.c
index 1edaf15c0b8e..a43f71cb30f8 100644
--- a/arch/x86/kernel/apic/nmi.c
+++ b/arch/x86/kernel/apic/nmi.c
@@ -401,13 +401,6 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
int cpu = smp_processor_id();
int rc = 0;
- /* check for other users first */
- if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
- == NOTIFY_STOP) {
- rc = 1;
- touched = 1;
- }
-
sum = get_timer_irqs(cpu);
if (__get_cpu_var(nmi_touch)) {
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 68e4a6f2211e..c4c864ab5c86 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -576,6 +576,7 @@ static void __cpuinit get_cpu_cap(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level >= 0x80000007)
c->x86_power = cpuid_edx(0x80000007);
+ init_scattered_cpuid_features(c);
}
static void __cpuinit identify_cpu_without_cpuid(struct cpuinfo_x86 *c)
@@ -731,7 +732,6 @@ static void __cpuinit generic_identify(struct cpuinfo_x86 *c)
get_model_name(c); /* Default name */
- init_scattered_cpuid_features(c);
detect_nopl(c);
}
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
index 7ec2123838e6..3a835c984883 100644
--- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
+++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c
@@ -806,6 +806,8 @@ static int find_psb_table(struct powernow_k8_data *data)
* www.amd.com
*/
printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
+ printk(KERN_ERR PFX "Make sure that your BIOS is up to date"
+ " and Cool'N'Quiet support is enabled in BIOS setup\n");
return -ENODEV;
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 707165dbc203..1970ef911c99 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -36,6 +36,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
+#include <linux/edac_mce.h>
#include <asm/processor.h>
#include <asm/hw_irq.h>
@@ -169,6 +170,15 @@ void mce_log(struct mce *mce)
entry = rcu_dereference_check_mce(mcelog.next);
for (;;) {
/*
+ * If edac_mce is enabled, it will check the error type
+ * and will process it, if it is a known error.
+ * Otherwise, the error will be sent through mcelog
+ * interface
+ */
+ if (edac_mce_parse(mce))
+ return;
+
+ /*
* When the buffer fills up discard new entries.
* Assume that the earlier errors are the more
* interesting ones:
@@ -590,6 +600,7 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
*/
if (!(flags & MCP_DONTLOG) && !mce_dont_log_ce) {
mce_log(&m);
+ atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, &m);
add_taint(TAINT_MACHINE_CHECK);
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index c77586061bcb..5db5b7d65a18 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -106,6 +106,7 @@ struct cpu_hw_events {
int n_events;
int n_added;
+ int n_txn;
int assign[X86_PMC_IDX_MAX]; /* event to counter assignment */
u64 tags[X86_PMC_IDX_MAX];
struct perf_event *event_list[X86_PMC_IDX_MAX]; /* in enabled order */
@@ -983,6 +984,7 @@ static int x86_pmu_enable(struct perf_event *event)
out:
cpuc->n_events = n;
cpuc->n_added += n - n0;
+ cpuc->n_txn += n - n0;
return 0;
}
@@ -1089,6 +1091,14 @@ static void x86_pmu_disable(struct perf_event *event)
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
int i;
+ /*
+ * If we're called during a txn, we don't need to do anything.
+ * The events never got scheduled and ->cancel_txn will truncate
+ * the event_list.
+ */
+ if (cpuc->group_flag & PERF_EVENT_TXN_STARTED)
+ return;
+
x86_pmu_stop(event);
for (i = 0; i < cpuc->n_events; i++) {
@@ -1379,6 +1389,7 @@ static void x86_pmu_start_txn(const struct pmu *pmu)
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
cpuc->group_flag |= PERF_EVENT_TXN_STARTED;
+ cpuc->n_txn = 0;
}
/*
@@ -1391,6 +1402,11 @@ static void x86_pmu_cancel_txn(const struct pmu *pmu)
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
cpuc->group_flag &= ~PERF_EVENT_TXN_STARTED;
+ /*
+ * Truncate the collected events.
+ */
+ cpuc->n_added -= cpuc->n_txn;
+ cpuc->n_events -= cpuc->n_txn;
}
/*
@@ -1419,6 +1435,12 @@ static int x86_pmu_commit_txn(const struct pmu *pmu)
*/
memcpy(cpuc->assign, assign, n*sizeof(int));
+ /*
+ * Clear out the txn count so that ->cancel_txn() which gets
+ * run after ->commit_txn() doesn't undo things.
+ */
+ cpuc->n_txn = 0;
+
return 0;
}
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 7bca3c6a02fb..0d6fc71bedb1 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -729,7 +729,7 @@ static int __init e820_mark_nvs_memory(void)
struct e820entry *ei = &e820.map[i];
if (ei->type == E820_NVS)
- hibernate_nvs_register(ei->addr, ei->size);
+ suspend_nvs_register(ei->addr, ei->size);
}
return 0;
diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c
index 3a54dcb9cd0e..43e9ccf44947 100644
--- a/arch/x86/kernel/init_task.c
+++ b/arch/x86/kernel/init_task.c
@@ -34,7 +34,7 @@ EXPORT_SYMBOL(init_task);
/*
* per-CPU TSS segments. Threads are completely 'soft' on Linux,
* no more per-task TSS's. The TSS size is kept cacheline-aligned
- * so they are allowed to end up in the .data.cacheline_aligned
+ * so they are allowed to end up in the .data..cacheline_aligned
* section. Since TSS's are completely CPU-local, we want them
* on exact cacheline boundaries, to eliminate cacheline ping-pong.
*/
diff --git a/arch/x86/kernel/mrst.c b/arch/x86/kernel/mrst.c
index e796448f0eb5..7ee4ed901baf 100644
--- a/arch/x86/kernel/mrst.c
+++ b/arch/x86/kernel/mrst.c
@@ -25,8 +25,34 @@
#include <asm/i8259.h>
#include <asm/apb_timer.h>
+/*
+ * the clockevent devices on Moorestown/Medfield can be APBT or LAPIC clock,
+ * cmdline option x86_mrst_timer can be used to override the configuration
+ * to prefer one or the other.
+ * at runtime, there are basically three timer configurations:
+ * 1. per cpu apbt clock only
+ * 2. per cpu always-on lapic clocks only, this is Penwell/Medfield only
+ * 3. per cpu lapic clock (C3STOP) and one apbt clock, with broadcast.
+ *
+ * by default (without cmdline option), platform code first detects cpu type
+ * to see if we are on lincroft or penwell, then set up both lapic or apbt
+ * clocks accordingly.
+ * i.e. by default, medfield uses configuration #2, moorestown uses #1.
+ * config #3 is supported but not recommended on medfield.
+ *
+ * rating and feature summary:
+ * lapic (with C3STOP) --------- 100
+ * apbt (always-on) ------------ 110
+ * lapic (always-on,ARAT) ------ 150
+ */
+
+__cpuinitdata enum mrst_timer_options mrst_timer_options;
+
static u32 sfi_mtimer_usage[SFI_MTMR_MAX_NUM];
static struct sfi_timer_table_entry sfi_mtimer_array[SFI_MTMR_MAX_NUM];
+enum mrst_cpu_type __mrst_cpu_chip;
+EXPORT_SYMBOL_GPL(__mrst_cpu_chip);
+
int sfi_mtimer_num;
struct sfi_rtc_table_entry sfi_mrtc_array[SFI_MRTC_MAX];
@@ -167,18 +193,6 @@ int __init sfi_parse_mrtc(struct sfi_table_header *table)
return 0;
}
-/*
- * the secondary clock in Moorestown can be APBT or LAPIC clock, default to
- * APBT but cmdline option can also override it.
- */
-static void __cpuinit mrst_setup_secondary_clock(void)
-{
- /* restore default lapic clock if disabled by cmdline */
- if (disable_apbt_percpu)
- return setup_secondary_APIC_clock();
- apbt_setup_secondary_clock();
-}
-
static unsigned long __init mrst_calibrate_tsc(void)
{
unsigned long flags, fast_calibrate;
@@ -195,6 +209,21 @@ static unsigned long __init mrst_calibrate_tsc(void)
void __init mrst_time_init(void)
{
+ switch (mrst_timer_options) {
+ case MRST_TIMER_APBT_ONLY:
+ break;
+ case MRST_TIMER_LAPIC_APBT:
+ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+ break;
+ default:
+ if (!boot_cpu_has(X86_FEATURE_ARAT))
+ break;
+ x86_init.timers.setup_percpu_clockev = setup_boot_APIC_clock;
+ x86_cpuinit.setup_percpu_clockev = setup_secondary_APIC_clock;
+ return;
+ }
+ /* we need at least one APB timer */
sfi_table_parse(SFI_SIG_MTMR, NULL, NULL, sfi_parse_mtmr);
pre_init_apic_IRQ0();
apbt_time_init();
@@ -205,16 +234,21 @@ void __init mrst_rtc_init(void)
sfi_table_parse(SFI_SIG_MRTC, NULL, NULL, sfi_parse_mrtc);
}
-/*
- * if we use per cpu apb timer, the bootclock already setup. if we use lapic
- * timer and one apbt timer for broadcast, we need to set up lapic boot clock.
- */
-static void __init mrst_setup_boot_clock(void)
+void __cpuinit mrst_arch_setup(void)
{
- pr_info("%s: per cpu apbt flag %d \n", __func__, disable_apbt_percpu);
- if (disable_apbt_percpu)
- setup_boot_APIC_clock();
-};
+ if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x27)
+ __mrst_cpu_chip = MRST_CPU_CHIP_PENWELL;
+ else if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 0x26)
+ __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+ else {
+ pr_err("Unknown Moorestown CPU (%d:%d), default to Lincroft\n",
+ boot_cpu_data.x86, boot_cpu_data.x86_model);
+ __mrst_cpu_chip = MRST_CPU_CHIP_LINCROFT;
+ }
+ pr_debug("Moorestown CPU %s identified\n",
+ (__mrst_cpu_chip == MRST_CPU_CHIP_LINCROFT) ?
+ "Lincroft" : "Penwell");
+}
/*
* Moorestown specific x86_init function overrides and early setup
@@ -226,11 +260,13 @@ void __init x86_mrst_early_setup(void)
x86_init.resources.reserve_resources = x86_init_noop;
x86_init.timers.timer_init = mrst_time_init;
- x86_init.timers.setup_percpu_clockev = mrst_setup_boot_clock;
+ x86_init.timers.setup_percpu_clockev = x86_init_noop;
x86_init.irqs.pre_vector_init = x86_init_noop;
- x86_cpuinit.setup_percpu_clockev = mrst_setup_secondary_clock;
+ x86_init.oem.arch_setup = mrst_arch_setup;
+
+ x86_cpuinit.setup_percpu_clockev = apbt_setup_secondary_clock;
x86_platform.calibrate_tsc = mrst_calibrate_tsc;
x86_init.pci.init = pci_mrst_init;
@@ -243,3 +279,26 @@ void __init x86_mrst_early_setup(void)
x86_init.mpparse.get_smp_config = x86_init_uint_noop;
}
+
+/*
+ * if user does not want to use per CPU apb timer, just give it a lower rating
+ * than local apic timer and skip the late per cpu timer init.
+ */
+static inline int __init setup_x86_mrst_timer(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (strcmp("apbt_only", arg) == 0)
+ mrst_timer_options = MRST_TIMER_APBT_ONLY;
+ else if (strcmp("lapic_and_apbt", arg) == 0)
+ mrst_timer_options = MRST_TIMER_LAPIC_APBT;
+ else {
+ pr_warning("X86 MRST timer option %s not recognised"
+ " use x86_mrst_timer=apbt_only or lapic_and_apbt\n",
+ arg);
+ return -EINVAL;
+ }
+ return 0;
+}
+__setup("x86_mrst_timer=", setup_x86_mrst_timer);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index e7e35219b32f..b460db8195fa 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -43,7 +43,6 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
}
return 0;
}
-
void free_thread_xstate(struct task_struct *tsk)
{
fpu_free(&tsk->thread.fpu);
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index a867940a6dfc..de3b63ae3da2 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -21,12 +21,6 @@
#include <asm/cpu.h>
#include <asm/stackprotector.h>
-#ifdef CONFIG_DEBUG_PER_CPU_MAPS
-# define DBG(fmt, ...) pr_dbg(fmt, ##__VA_ARGS__)
-#else
-# define DBG(fmt, ...) do { if (0) pr_dbg(fmt, ##__VA_ARGS__); } while (0)
-#endif
-
DEFINE_PER_CPU(int, cpu_number);
EXPORT_PER_CPU_SYMBOL(cpu_number);
@@ -247,7 +241,7 @@ void __init setup_per_cpu_areas(void)
#endif
#endif
/*
- * Up to this point, the boot CPU has been using .data.init
+ * Up to this point, the boot CPU has been using .init.data
* area. Reload any changed state for the boot CPU.
*/
if (cpu == boot_cpu_id)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 37462f1ddba5..c4f33b2e77d6 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -686,7 +686,7 @@ static void __cpuinit do_fork_idle(struct work_struct *work)
static void __cpuinit announce_cpu(int cpu, int apicid)
{
static int current_node = -1;
- int node = cpu_to_node(cpu);
+ int node = early_cpu_to_node(cpu);
if (system_state == SYSTEM_BOOTING) {
if (node != current_node) {
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index 8b3729341216..07ad5eb7cc5c 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -337,3 +337,5 @@ ENTRY(sys_call_table)
.long sys_rt_tgsigqueueinfo /* 335 */
.long sys_perf_event_open
.long sys_recvmmsg
+ .long sys_fanotify_init
+ .long sys_fanotify_mark
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 142d70c74b02..c7d0ba79cc83 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -392,7 +392,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT)
== NOTIFY_STOP)
return;
+
#ifdef CONFIG_X86_LOCAL_APIC
+ if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
+ == NOTIFY_STOP)
+ return;
+
+#ifndef CONFIG_LOCKUP_DETECTOR
/*
* Ok, so this is none of the documented NMI sources,
* so it must be the NMI watchdog.
@@ -400,6 +406,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs)
if (nmi_watchdog_tick(regs, reason))
return;
if (!do_nmi_callback(regs, cpu))
+#endif /* !CONFIG_LOCKUP_DETECTOR */
unknown_nmi_error(reason, regs);
#else
unknown_nmi_error(reason, regs);
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 2cc249718c46..d0bb52296fa3 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -97,7 +97,7 @@ SECTIONS
HEAD_TEXT
#ifdef CONFIG_X86_32
. = ALIGN(PAGE_SIZE);
- *(.text.page_aligned)
+ *(.text..page_aligned)
#endif
. = ALIGN(8);
_stext = .;
@@ -305,7 +305,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
.bss : AT(ADDR(.bss) - LOAD_OFFSET) {
__bss_start = .;
- *(.bss.page_aligned)
+ *(.bss..page_aligned)
*(.bss)
. = ALIGN(4);
__bss_stop = .;
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 81563e76e28f..6fbcb48d5a9b 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -1870,6 +1870,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
child = page_header(pte & PT64_BASE_ADDR_MASK);
mmu_page_remove_parent_pte(child, sptep);
+ __set_spte(sptep, shadow_trap_nonpresent_pte);
+ kvm_flush_remote_tlbs(vcpu->kvm);
} else if (pfn != spte_to_pfn(*sptep)) {
pgprintk("hfn old %lx new %lx\n",
spte_to_pfn(*sptep), pfn);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 96dc232bfc56..ce438e0fdd26 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -28,6 +28,7 @@
#include <linux/ftrace_event.h>
#include <linux/slab.h>
+#include <asm/tlbflush.h>
#include <asm/desc.h>
#include <asm/virtext.h>
@@ -56,6 +57,8 @@ MODULE_LICENSE("GPL");
#define DEBUGCTL_RESERVED_BITS (~(0x3fULL))
+static bool erratum_383_found __read_mostly;
+
static const u32 host_save_user_msrs[] = {
#ifdef CONFIG_X86_64
MSR_STAR, MSR_LSTAR, MSR_CSTAR, MSR_SYSCALL_MASK, MSR_KERNEL_GS_BASE,
@@ -374,6 +377,31 @@ static void svm_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
svm->vmcb->control.event_inj_err = error_code;
}
+static void svm_init_erratum_383(void)
+{
+ u32 low, high;
+ int err;
+ u64 val;
+
+ /* Only Fam10h is affected */
+ if (boot_cpu_data.x86 != 0x10)
+ return;
+
+ /* Use _safe variants to not break nested virtualization */
+ val = native_read_msr_safe(MSR_AMD64_DC_CFG, &err);
+ if (err)
+ return;
+
+ val |= (1ULL << 47);
+
+ low = lower_32_bits(val);
+ high = upper_32_bits(val);
+
+ native_write_msr_safe(MSR_AMD64_DC_CFG, low, high);
+
+ erratum_383_found = true;
+}
+
static int has_svm(void)
{
const char *msg;
@@ -429,6 +457,8 @@ static int svm_hardware_enable(void *garbage)
wrmsrl(MSR_VM_HSAVE_PA, page_to_pfn(sd->save_area) << PAGE_SHIFT);
+ svm_init_erratum_383();
+
return 0;
}
@@ -1410,8 +1440,59 @@ static int nm_interception(struct vcpu_svm *svm)
return 1;
}
-static int mc_interception(struct vcpu_svm *svm)
+static bool is_erratum_383(void)
{
+ int err, i;
+ u64 value;
+
+ if (!erratum_383_found)
+ return false;
+
+ value = native_read_msr_safe(MSR_IA32_MC0_STATUS, &err);
+ if (err)
+ return false;
+
+ /* Bit 62 may or may not be set for this mce */
+ value &= ~(1ULL << 62);
+
+ if (value != 0xb600000000010015ULL)
+ return false;
+
+ /* Clear MCi_STATUS registers */
+ for (i = 0; i < 6; ++i)
+ native_write_msr_safe(MSR_IA32_MCx_STATUS(i), 0, 0);
+
+ value = native_read_msr_safe(MSR_IA32_MCG_STATUS, &err);
+ if (!err) {
+ u32 low, high;
+
+ value &= ~(1ULL << 2);
+ low = lower_32_bits(value);
+ high = upper_32_bits(value);
+
+ native_write_msr_safe(MSR_IA32_MCG_STATUS, low, high);
+ }
+
+ /* Flush tlb to evict multi-match entries */
+ __flush_tlb_all();
+
+ return true;
+}
+
+static void svm_handle_mce(struct vcpu_svm *svm)
+{
+ if (is_erratum_383()) {
+ /*
+ * Erratum 383 triggered. Guest state is corrupt so kill the
+ * guest.
+ */
+ pr_err("KVM: Guest triggered AMD Erratum 383\n");
+
+ set_bit(KVM_REQ_TRIPLE_FAULT, &svm->vcpu.requests);
+
+ return;
+ }
+
/*
* On an #MC intercept the MCE handler is not called automatically in
* the host. So do it by hand here.
@@ -1420,6 +1501,11 @@ static int mc_interception(struct vcpu_svm *svm)
"int $0x12\n");
/* not sure if we ever come back to this point */
+ return;
+}
+
+static int mc_interception(struct vcpu_svm *svm)
+{
return 1;
}
@@ -3088,6 +3174,14 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
vcpu->arch.regs_avail &= ~(1 << VCPU_EXREG_PDPTR);
vcpu->arch.regs_dirty &= ~(1 << VCPU_EXREG_PDPTR);
}
+
+ /*
+ * We need to handle MC intercepts here before the vcpu has a chance to
+ * change the physical cpu
+ */
+ if (unlikely(svm->vmcb->control.exit_code ==
+ SVM_EXIT_EXCP_BASE + MC_VECTOR))
+ svm_handle_mce(svm);
}
#undef R
diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c
index 550df481accd..787c52ca49c3 100644
--- a/arch/x86/mm/numa.c
+++ b/arch/x86/mm/numa.c
@@ -3,12 +3,6 @@
#include <linux/module.h>
#include <linux/bootmem.h>
-#ifdef CONFIG_DEBUG_PER_CPU_MAPS
-# define DBG(x...) printk(KERN_DEBUG x)
-#else
-# define DBG(x...)
-#endif
-
/*
* Which logical CPUs are on which nodes
*/
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c
index b28d2f1253bb..1ba67dc8006a 100644
--- a/arch/x86/oprofile/nmi_int.c
+++ b/arch/x86/oprofile/nmi_int.c
@@ -634,6 +634,18 @@ static int __init ppro_init(char **cpu_type)
if (force_arch_perfmon && cpu_has_arch_perfmon)
return 0;
+ /*
+ * Documentation on identifying Intel processors by CPU family
+ * and model can be found in the Intel Software Developer's
+ * Manuals (SDM):
+ *
+ * http://www.intel.com/products/processor/manuals/
+ *
+ * As of May 2010 the documentation for this was in the:
+ * "Intel 64 and IA-32 Architectures Software Developer's
+ * Manual Volume 3B: System Programming Guide", "Table B-1
+ * CPUID Signature Values of DisplayFamily_DisplayModel".
+ */
switch (cpu_model) {
case 0 ... 2:
*cpu_type = "i386/ppro";
@@ -655,12 +667,12 @@ static int __init ppro_init(char **cpu_type)
case 15: case 23:
*cpu_type = "i386/core_2";
break;
+ case 0x1a:
case 0x2e:
- case 26:
spec = &op_arch_perfmon_spec;
*cpu_type = "i386/core_i7";
break;
- case 28:
+ case 0x1c:
*cpu_type = "i386/atom";
break;
default:
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 215a27ae050d..a0772af64efb 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -125,6 +125,23 @@ void __init dmi_check_skip_isa_align(void)
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
{
struct resource *rom_r = &dev->resource[PCI_ROM_RESOURCE];
+ struct resource *bar_r;
+ int bar;
+
+ if (pci_probe & PCI_NOASSIGN_BARS) {
+ /*
+ * If the BIOS did not assign the BAR, zero out the
+ * resource so the kernel doesn't attmept to assign
+ * it later on in pci_assign_unassigned_resources
+ */
+ for (bar = 0; bar <= PCI_STD_RESOURCE_END; bar++) {
+ bar_r = &dev->resource[bar];
+ if (bar_r->start == 0 && bar_r->end != 0) {
+ bar_r->flags = 0;
+ bar_r->end = 0;
+ }
+ }
+ }
if (pci_probe & PCI_NOASSIGN_ROMS) {
if (rom_r->parent)
@@ -509,6 +526,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "norom")) {
pci_probe |= PCI_NOASSIGN_ROMS;
return NULL;
+ } else if (!strcmp(str, "nobar")) {
+ pci_probe |= PCI_NOASSIGN_BARS;
+ return NULL;
} else if (!strcmp(str, "assign-busses")) {
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
return NULL;
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index 0db5eaf54560..8d460eaf524f 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -11,28 +11,14 @@
*/
static void __devinit pcibios_fixup_peer_bridges(void)
{
- int n, devfn;
- long node;
+ int n;
if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
return;
DBG("PCI: Peer bridge fixup\n");
- for (n=0; n <= pcibios_last_bus; n++) {
- u32 l;
- if (pci_find_bus(0, n))
- continue;
- node = get_mp_bus_to_node(n);
- for (devfn = 0; devfn < 256; devfn += 8) {
- if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
- l != 0x0000 && l != 0xffff) {
- DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
- printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
- pci_scan_bus_on_node(n, &pci_root_ops, node);
- break;
- }
- }
- }
+ for (n=0; n <= pcibios_last_bus; n++)
+ pcibios_scan_specific_bus(n);
}
int __init pci_legacy_init(void)
@@ -50,6 +36,28 @@ int __init pci_legacy_init(void)
return 0;
}
+void pcibios_scan_specific_bus(int busn)
+{
+ int devfn;
+ long node;
+ u32 l;
+
+ if (pci_find_bus(0, busn))
+ return;
+
+ node = get_mp_bus_to_node(busn);
+ for (devfn = 0; devfn < 256; devfn += 8) {
+ if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
+ l != 0x0000 && l != 0xffff) {
+ DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
+ printk(KERN_INFO "PCI: Discovered peer bus %02x\n", busn);
+ pci_scan_bus_on_node(busn, &pci_root_ops, node);
+ return;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
+
int __init pci_subsys_init(void)
{
/*
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index 987267f79bf5..a9c661108034 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -60,6 +60,6 @@ static void xen_vcpu_notify_restore(void *data)
void xen_arch_resume(void)
{
- smp_call_function(xen_vcpu_notify_restore,
- (void *)CLOCK_EVT_NOTIFY_RESUME, 1);
+ on_each_cpu(xen_vcpu_notify_restore,
+ (void *)CLOCK_EVT_NOTIFY_RESUME, 1);
}
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index ebe228d02b08..52e5dbbb1941 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -84,10 +84,10 @@ config XTENSA_VARIANT_S6000
endchoice
config XTENSA_UNALIGNED_USER
- bool "Unaligned memory access in use space"
+ bool "Unaligned memory access in user space"
help
- The Xtensa architecture currently does not handle unaligned
- memory accesses in hardware but through an exception handler.
+ Xtensa processors are often not configured to handle unaligned
+ memory accesses in hardware, but rather through an exception handler.
Per default, unaligned memory accesses are disabled in user space.
Say Y here to enable unaligned memory access in user space.
@@ -157,8 +157,15 @@ config XTENSA_PLATFORM_ISS
config XTENSA_PLATFORM_XT2000
bool "XT2000"
help
- XT2000 is the name of Tensilica's feature-rich emulation platform.
- This hardware is capable of running a full Linux distribution.
+ XT2000 is the name of Tensilica's older emulation platform.
+
+config XTENSA_PLATFORM_XTAVNET
+ bool "XTAVNET"
+ select XTENSA_CALIBRATE_CCOUNT
+ select ETHOC
+ help
+ Selects support for the Tensilica-configured Avnet emulation boards.
+ These include the LX60 (XT-AV60), LX200 (XT-AV200), and LX110 (XT-AV110).
config XTENSA_PLATFORM_S6105
bool "S6105"
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 4caffac3ca2e..34d8427622eb 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -24,6 +24,7 @@ export VARIANT
# Platform configuration
platform-$(CONFIG_XTENSA_PLATFORM_XT2000) := xt2000
+platform-$(CONFIG_XTENSA_PLATFORM_XTAVNET) := xtavnet
platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
platform-$(CONFIG_XTENSA_PLATFORM_S6105) := s6105
@@ -35,6 +36,8 @@ KBUILD_CFLAGS += -ffreestanding
KBUILD_CFLAGS += -pipe -mlongcalls
+KBUILD_CFLAGS += $(call cc-option,-mforce-no-pic,)
+
vardirs := $(patsubst %,arch/xtensa/variants/%/,$(variant-y))
plfdirs := $(patsubst %,arch/xtensa/platforms/%/,$(platform-y))
@@ -59,7 +62,9 @@ ifneq ($(VARIANT),)
ifneq ($(COMPILE_ARCH), xtensa)
ifndef CROSS_COMPILE
- CROSS_COMPILE = xtensa_$(VARIANT)-
+ CROSS_COMPILE := $(call cc-cross-prefix, xtensa_$(VARIANT)- \
+ xtensa-linux-uclibc- xtensa_$(VARIANT)-linux-uclibc- \
+ xtensa-linux-gnu- xtensa_$(VARIANT)-linux-gnu-)
endif
endif
endif
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile
index 40aa55b485be..8657c62fc78b 100644
--- a/arch/xtensa/boot/Makefile
+++ b/arch/xtensa/boot/Makefile
@@ -23,6 +23,7 @@ subdir-y := lib
bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf
bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf
+bootdir-$(CONFIG_XTENSA_PLATFORM_XTAVNET) += boot-redboot boot-elf
zImage zImage.initrd Image Image.initrd: $(bootdir-y)
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
index f19854035e61..61bac9d62255 100644
--- a/arch/xtensa/configs/iss_defconfig
+++ b/arch/xtensa/configs/iss_defconfig
@@ -77,6 +77,7 @@ CONFIG_XTENSA_ISS_NETWORK=y
#
# Bus options
#
+CONFIG_PCI=n
#
# PCCARD (PCMCIA/CardBus) support
diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h
index a508f2f73bd7..376cd9d5f455 100644
--- a/arch/xtensa/include/asm/cacheflush.h
+++ b/arch/xtensa/include/asm/cacheflush.h
@@ -115,6 +115,7 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon
#define flush_cache_vmap(start,end) do { } while (0)
#define flush_cache_vunmap(start,end) do { } while (0)
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
#define flush_dcache_page(page) do { } while (0)
#define flush_cache_page(vma,addr,pfn) do { } while (0)
diff --git a/arch/xtensa/include/asm/coprocessor.h b/arch/xtensa/include/asm/coprocessor.h
index 65a285d8d3fb..04bc285df1a7 100644
--- a/arch/xtensa/include/asm/coprocessor.h
+++ b/arch/xtensa/include/asm/coprocessor.h
@@ -1,11 +1,11 @@
/*
- * include/asm-xtensa/coprocessor.h
+ * arch/xtensa/include/asm/coprocessor.h
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2003 - 2007 Tensilica Inc.
+ * Copyright (C) 2003-2010 Tensilica Inc.
*/
@@ -14,9 +14,10 @@
#include <linux/stringify.h>
#include <variant/tie.h>
+#include <variant/core.h>
#include <asm/types.h>
-#ifdef __ASSEMBLY__
+#if defined(__ASSEMBLY__) && !defined(LINKER_SCRIPT)
# include <variant/tie-asm.h>
.macro xchal_sa_start a b
@@ -69,7 +70,7 @@
-#endif /* __ASSEMBLY__ */
+#endif /* __ASSEMBLY__ && !LINKER_SCRIPT */
/*
* XTENSA_HAVE_COPROCESSOR(x) returns 1 if coprocessor x is configured.
diff --git a/arch/xtensa/include/asm/elf.h b/arch/xtensa/include/asm/elf.h
index 5eb6d695e987..6e65eadaae14 100644
--- a/arch/xtensa/include/asm/elf.h
+++ b/arch/xtensa/include/asm/elf.h
@@ -14,6 +14,7 @@
#define _XTENSA_ELF_H
#include <asm/ptrace.h>
+#include <asm/coprocessor.h>
/* Xtensa processor ELF architecture-magic number */
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index d04cd3a625fa..145db5cc6191 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -1,11 +1,11 @@
/*
- * include/asm-xtensa/io.h
+ * arch/xtensa/include/asm/io.h
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001-2010 Tensilica Inc.
*/
#ifndef _XTENSA_IO_H
@@ -63,40 +63,33 @@ static inline void * phys_to_virt(unsigned long address)
#define bus_to_virt(x) phys_to_virt(x)
/*
- * Return the virtual (cached) address for the specified bus memory.
+ * Return the virtual (uncached) address for the specified bus memory
+ * (which is, for now, simply a physical address).
* Note that we currently don't support any address outside the KIO segment.
+ * See also arch/mips/include/asm/io.h for nice comments.
*/
-static inline void *ioremap(unsigned long offset, unsigned long size)
+static inline void __iomem *__ioremap(unsigned long offset, unsigned long size)
{
#ifdef CONFIG_MMU
if (offset >= XCHAL_KIO_PADDR
- && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
- return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR);
+ && offset <= XCHAL_KIO_PADDR + XCHAL_KIO_SIZE - 1)
+ return (void __iomem *)(offset - XCHAL_KIO_PADDR + XCHAL_KIO_BYPASS_VADDR);
else
BUG();
#else
- return (void *)offset;
+ return (void __iomem *)offset;
#endif
}
-static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
-{
-#ifdef CONFIG_MMU
- if (offset >= XCHAL_KIO_PADDR
- && offset < XCHAL_KIO_PADDR + XCHAL_KIO_SIZE)
- return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR);
- else
- BUG();
-#else
- return (void *)offset;
-#endif
-}
+#define ioremap(offset, size) __ioremap(offset, size)
+#define ioremap_nocache(offset, size) __ioremap(offset, size)
-static inline void iounmap(void *addr)
+static inline void iounmap(void __iomem *addr)
{
}
+
/*
* Generic I/O
*/
@@ -191,6 +184,13 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
#endif
+#ifndef CONFIG_GENERIC_IOMAP
+/* Partial Simple MMIO */
+#define ioread32(a) __raw_readl(a)
+#define iowrite32(v,a) __raw_writel((v),(a))
+#endif
+
+
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem access
*/
diff --git a/arch/xtensa/include/asm/irq.h b/arch/xtensa/include/asm/irq.h
index 4c0ccc9c4f4c..6af436f4429d 100644
--- a/arch/xtensa/include/asm/irq.h
+++ b/arch/xtensa/include/asm/irq.h
@@ -1,11 +1,11 @@
/*
- * include/asm-xtensa/irq.h
+ * arch/xtensa/include/asm/irq.h
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001-2010 Tensilica Inc.
*/
#ifndef _XTENSA_IRQ_H
@@ -22,6 +22,9 @@ static inline void variant_irq_enable(unsigned int irq) { }
static inline void variant_irq_disable(unsigned int irq) { }
#endif
+/* This number is used when no interrupt has been assigned. */
+#define NO_IRQ (-1)
+
#ifndef VARIANT_NR_IRQS
# define VARIANT_NR_IRQS 0
#endif
diff --git a/arch/xtensa/include/asm/pgalloc.h b/arch/xtensa/include/asm/pgalloc.h
index 4f4a7987eded..40cf9bceda2c 100644
--- a/arch/xtensa/include/asm/pgalloc.h
+++ b/arch/xtensa/include/asm/pgalloc.h
@@ -14,6 +14,7 @@
#ifdef __KERNEL__
#include <linux/highmem.h>
+#include <linux/slab.h>
/*
* Allocating and freeing a pmd is trivial: the 1-entry pmd is
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 0ea4937c0b61..3acb26e8dead 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -12,7 +12,6 @@
#define _XTENSA_PROCESSOR_H
#include <variant/core.h>
-#include <asm/coprocessor.h>
#include <platform/hardware.h>
#include <linux/compiler.h>
diff --git a/arch/xtensa/include/asm/ptrace.h b/arch/xtensa/include/asm/ptrace.h
index 3c549f798727..0d42c934b66f 100644
--- a/arch/xtensa/include/asm/ptrace.h
+++ b/arch/xtensa/include/asm/ptrace.h
@@ -77,6 +77,8 @@
#ifndef __ASSEMBLY__
+#include <asm/coprocessor.h>
+
/*
* This struct defines the way the registers are stored on the
* kernel stack during a system call or other kernel entry.
diff --git a/arch/xtensa/include/asm/serial.h b/arch/xtensa/include/asm/serial.h
index a8a2493260f6..c55a0e2b47ca 100644
--- a/arch/xtensa/include/asm/serial.h
+++ b/arch/xtensa/include/asm/serial.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/serial.h
+ * arch/xtensa/include/asm/serial.h
*
* Configuration details for 8250, 16450, 16550, etc. serial ports
*
@@ -7,12 +7,20 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001-2010 Tensilica Inc.
*/
#ifndef _XTENSA_SERIAL_H
#define _XTENSA_SERIAL_H
+#include <asm/irq.h>
#include <platform/serial.h>
+/* The 8250 driver treats IRQ 0 as absent. For the Xtensa architecture,
+ interrupt 0 is valid, must compare against NO_IRQ instead. */
+#ifdef is_real_interrupt
+#undef is_real_interrupt
+#define is_real_interrupt(irq) ((irq) != NO_IRQ)
+#endif
+
#endif /* _XTENSA_SERIAL_H */
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 6f56d95f2c1e..e426a4ec7f22 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -23,12 +23,12 @@ obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
#
# Replicate rules in scripts/Makefile.build
-sed-y = -e 's/(\(\.[a-z]*it\|\.ref\|\)\.text)/(\1.literal \1.text)/g' \
- -e 's/(\(\.text\.[a-z]*\))/(\1.literal \1)/g'
+sed-y = -e 's/\*(\(\.[a-z]*it\|\.ref\|\)\.text)/*(\1.literal \1.text)/g' \
+ -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
quiet_cmd__cpp_lds_S = LDS $@
- cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ $< \
- | sed $(sed-y) >$@
+ cmd__cpp_lds_S = $(CPP) $(cpp_flags) -P -C -Uxtensa -D__ASSEMBLY__ \
+ -DLINKER_SCRIPT $< | sed $(sed-y) >$@
$(obj)/vmlinux.lds: $(src)/vmlinux.lds.S FORCE
$(call if_changed_dep,_cpp_lds_S)
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index 070ff8af3a21..7dc3f9157185 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -13,6 +13,7 @@
*/
#include <asm/processor.h>
+#include <asm/coprocessor.h>
#include <linux/types.h>
#include <linux/stddef.h>
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 77fc9f6dc016..5fd01f6aaf37 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -16,6 +16,7 @@
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/processor.h>
+#include <asm/coprocessor.h>
#include <asm/thread_info.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index d215adcfd4ea..3ef91a73652d 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -184,8 +184,8 @@ _startup:
* Now clear the BSS segment.
*/
- movi a2, _bss_start # start of BSS
- movi a3, _bss_end # end of BSS
+ movi a2, __bss_start # start of BSS
+ movi a3, __bss_stop # end of BSS
__loopt a2, a3, a4, 2
s32i a0, a2, 0
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 19df764f6399..88ba96e2df25 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -31,7 +31,7 @@ unsigned long ccount_per_jiffy; /* per 1/HZ */
unsigned long nsec_per_ccount; /* nsec per ccount increment */
#endif
-static cycle_t ccount_read(void)
+static cycle_t ccount_read(struct clocksource *cs)
{
return (cycle_t)get_ccount();
}
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index bc0733359a88..e367e3026436 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -105,7 +105,6 @@ good_area:
* make sure we exit gracefully rather than endlessly redo
* the fault.
*/
-survive:
fault = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0);
if (unlikely(fault & VM_FAULT_ERROR)) {
if (fault & VM_FAULT_OOM)
@@ -146,15 +145,10 @@ bad_area:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (is_global_init(current)) {
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- printk("VM: killing process %s\n", current->comm);
- if (user_mode(regs))
- do_group_exit(SIGKILL);
- bad_page_fault(regs, address, SIGKILL);
+ if (!user_mode(regs))
+ bad_page_fault(regs, address, SIGKILL);
+ else
+ pagefault_out_of_memory();
return;
do_sigbus:
diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c
index 87e218f98ef4..f717e20d961b 100644
--- a/arch/xtensa/platforms/iss/network.c
+++ b/arch/xtensa/platforms/iss/network.c
@@ -623,6 +623,19 @@ static struct platform_driver iss_net_driver = {
static int driver_registered;
+static const struct net_device_ops iss_netdev_ops = {
+ .ndo_open = iss_net_open,
+ .ndo_stop = iss_net_close,
+ .ndo_get_stats = iss_net_get_stats,
+ .ndo_start_xmit = iss_net_start_xmit,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = iss_net_change_mtu,
+ .ndo_set_mac_address = iss_net_set_mac,
+ //.ndo_do_ioctl = iss_net_ioctl,
+ .ndo_tx_timeout = iss_net_tx_timeout,
+ .ndo_set_multicast_list = iss_net_set_multicast_list,
+};
+
static int iss_net_configure(int index, char *init)
{
struct net_device *dev;
@@ -686,15 +699,8 @@ static int iss_net_configure(int index, char *init)
*/
snprintf(dev->name, sizeof dev->name, "eth%d", index);
+ dev->netdev_ops = &iss_netdev_ops;
dev->mtu = lp->mtu;
- dev->open = iss_net_open;
- dev->hard_start_xmit = iss_net_start_xmit;
- dev->stop = iss_net_close;
- dev->get_stats = iss_net_get_stats;
- dev->set_multicast_list = iss_net_set_multicast_list;
- dev->tx_timeout = iss_net_tx_timeout;
- dev->set_mac_address = iss_net_set_mac;
- dev->change_mtu = iss_net_change_mtu;
dev->watchdog_timeo = (HZ >> 1);
dev->irq = -1;
diff --git a/arch/xtensa/platforms/xtavnet/Makefile b/arch/xtensa/platforms/xtavnet/Makefile
new file mode 100644
index 000000000000..06b120b40015
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/Makefile
@@ -0,0 +1,10 @@
+# Makefile for the Tensilica Avnet-based Emulation Boards
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are in the main makefile...
+
+obj-y = setup.o lcd.o
+
diff --git a/arch/xtensa/platforms/xtavnet/include/platform/hardware.h b/arch/xtensa/platforms/xtavnet/include/platform/hardware.h
new file mode 100644
index 000000000000..5301be745113
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/include/platform/hardware.h
@@ -0,0 +1,85 @@
+/*
+ * arch/xtensa/platforms/xtavnet/include/platform/hardware.h
+ *
+ * This file contains the hardware configuration of Tensilica Avnet boards
+ * (XT-AV60, XT-AV110, XT-AV200, derived from Avnet LX60, LX110, LX200
+ * boards respectively).
+ *
+ * Copyright (C) 2006-2010 Tensilica Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __XTAVNET_HARDWARE_H
+#define __XTAVNET_HARDWARE_H
+
+#include <variant/core.h>
+
+/* Memory configuration. */
+
+#define PLATFORM_DEFAULT_MEM_START 0x00000000
+#define PLATFORM_DEFAULT_MEM_SIZE 0x04000000
+
+/* Interrupt configuration. */
+
+#define PLATFORM_NR_IRQS 2
+
+/*
+ * Default assignment of XTAVnet devices to external interrupts.
+ *
+ * CONFIG_ARCH_HAS_SMP means the hardware supports SMP, ie. is Xtensa MX.
+ *
+ * Systems with SMP support (MX) have an External Interrupt Distributor
+ * between external interrupts and the core's interrupts. The first three
+ * core interrupts are used for IPI (interprocessor interrupts), so
+ * external (board device) interrupts end up shifted up by 3.
+ */
+
+/* UART interrupt: */
+#ifdef CONFIG_ARCH_HAS_SMP
+#define UART_INTNUM XCHAL_EXTINT3_NUM
+#else
+#define UART_INTNUM XCHAL_EXTINT0_NUM
+#endif
+
+/* Ethernet interrupt: */
+#ifdef CONFIG_ARCH_HAS_SMP
+#define OETH_IRQ XCHAL_EXTINT4_NUM
+#else
+#define OETH_IRQ XCHAL_EXTINT1_NUM
+#endif
+
+/*
+ * Device addresses and parameters.
+ */
+
+/* UART */
+#define UART_PADDR 0xFD050020
+
+/* LCD instruction and data virt. addresses. */
+#define LCD_INSTR_ADDR (char*)(0xFD040000)
+#define LCD_DATA_ADDR (char*)(0xFD040004)
+
+/* Misc. */
+#define XTAVNET_FPGAREGS_VADDR 0xFD020000
+/* Clock frequency in Hz (read-only): */
+#define XTAVNET_CLKFRQ_VADDR (XTAVNET_FPGAREGS_VADDR + 0x04)
+/* Setting of 8 DIP switches: */
+#define DIP_SWITCHES_VADDR (XTAVNET_FPGAREGS_VADDR + 0x0C)
+/* Software reset (write 0xdead): */
+#define XTAVNET_SWRST_VADDR (XTAVNET_FPGAREGS_VADDR + 0x10)
+
+/* OpenCores Ethernet controller: */
+#define OETH_REGS_PADDR IOADDR(0xD030000) /* regs + RX/TX descriptors */
+#define OETH_REGS_VADDR 0xFD030000
+#define OETH_REGS_SIZE 0x1000
+#define OETH_SRAMBUFF_PADDR 0xFD800000
+#define OETH_SRAMBUFF_SIZE (5*0x600 + 5*0x600) /* 5*rx buffs + 5*tx buffs */
+/*#define OETH_SRAMBUFF_SIZE 0x3C00*/ /* probably 0x4000 ? */
+/* The MAC address for these boards is 00:50:c2:13:6f:xx.
+ The last byte (here as zero) is read from the DIP switches on the board. */
+#define OETH_MACADDR 0x00, 0x50, 0xc2, 0x13, 0x6f, 0
+
+#endif /* __XTAVNET_HARDWARE_H */
diff --git a/arch/xtensa/platforms/xtavnet/include/platform/lcd.h b/arch/xtensa/platforms/xtavnet/include/platform/lcd.h
new file mode 100644
index 000000000000..67de96acb2f9
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/include/platform/lcd.h
@@ -0,0 +1,22 @@
+/*
+ * arch/xtensa/platforms/xtavnet/include/platform/lcd.h
+ *
+ * Copyright (C) 2001-2006 Tensilica Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __XTAVNET_LCD_H
+#define __XTAVNET_LCD_H
+
+/* Display string STR at position POS on the LCD. */
+void lcd_disp_at_pos(char *str, unsigned char pos);
+
+/* Shift the contents of the LCD display left or right. */
+void lcd_shiftleft(void);
+void lcd_shiftright(void);
+
+#endif
+
diff --git a/arch/xtensa/platforms/xtavnet/include/platform/serial.h b/arch/xtensa/platforms/xtavnet/include/platform/serial.h
new file mode 100644
index 000000000000..a0cb0caff152
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/include/platform/serial.h
@@ -0,0 +1 @@
+#include <asm-generic/serial.h>
diff --git a/arch/xtensa/platforms/xtavnet/lcd.c b/arch/xtensa/platforms/xtavnet/lcd.c
new file mode 100644
index 000000000000..283986f158ad
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/lcd.c
@@ -0,0 +1,79 @@
+/*
+ * Driver for the LCD display on the Tensilica LX60 Board.
+ * This code has no effect on the LX200 board. (LX110: TBD)
+ *
+ * Copyright (C) 2001-2006 Tensilica Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+/*
+ *
+ * FIXME: this code is from the examples from the LX60 user guide.
+ *
+ * The lcd_pause function does busy waiting, which is probably not
+ * great. Maybe the code could be changed to use kernel timers, or
+ * change the hardware to not need to wait.
+ */
+
+#include <linux/init.h>
+
+#include <platform/hardware.h>
+#include <asm/processor.h>
+#include <platform/lcd.h>
+#include <linux/delay.h>
+
+#define LCD_PAUSE_ITERATIONS 4000
+#define LCD_CLEAR 0x1
+#define LCD_DISPLAY_ON 0xc
+
+/* 8bit and 2 lines display */
+#define LCD_DISPLAY_MODE8BIT 0x38
+#define LCD_DISPLAY_POS 0x80
+#define LCD_SHIFT_LEFT 0x18
+#define LCD_SHIFT_RIGHT 0x1c
+
+static int __init lcd_init(void)
+{
+ *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ mdelay(5);
+ *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ udelay(200);
+ *LCD_INSTR_ADDR = LCD_DISPLAY_MODE8BIT;
+ udelay(50);
+ *LCD_INSTR_ADDR = LCD_DISPLAY_ON;
+ udelay(50);
+ *LCD_INSTR_ADDR = LCD_CLEAR;
+ mdelay(10);
+ lcd_disp_at_pos("XTENSA LINUX", 0);
+
+ return 0;
+}
+
+void lcd_disp_at_pos (char *str, unsigned char pos)
+{
+ *LCD_INSTR_ADDR = LCD_DISPLAY_POS | pos;
+ udelay(100);
+ while (*str != 0){
+ *LCD_DATA_ADDR = *str;
+ udelay(200);
+ str++;
+ }
+}
+
+void lcd_shiftleft(void)
+{
+ *LCD_INSTR_ADDR = LCD_SHIFT_LEFT;
+ udelay(50);
+}
+
+void lcd_shiftright(void)
+{
+ *LCD_INSTR_ADDR = LCD_SHIFT_RIGHT;
+ udelay(50);
+}
+
+arch_initcall(lcd_init);
+
diff --git a/arch/xtensa/platforms/xtavnet/setup.c b/arch/xtensa/platforms/xtavnet/setup.c
new file mode 100644
index 000000000000..256fcb2b2af4
--- /dev/null
+++ b/arch/xtensa/platforms/xtavnet/setup.c
@@ -0,0 +1,269 @@
+/*
+ * arch/xtensa/platform-xtavnet/setup.c
+ *
+ * Setup/initialization for Tensilica Avnet boards (XT-AV60, XT-AV110, XT-AV200,
+ * derived from Avnet LX60, LX110, LX200 boards respectively).
+ * For details, see "Tensilica Avnet LX### (XT-AV###) Board User's Guide"
+ * (where ### is 60, 110, or 200).
+ *
+ * Authors: Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com>
+ * Pete Delaney <piet@tensilica.com>
+ * Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ *
+ * Copyright 2001-2010 Tensilica Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License, version 2. See the file "COPYING" in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/stringify.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <asm/timex.h>
+
+#include <linux/etherdevice.h>
+#include <net/ethoc.h>
+
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/bootparam.h>
+#include <platform/lcd.h>
+#include <platform/hardware.h>
+#include <variant/core.h>
+
+/* For doing extra init. beyond what the ethoc driver does. */
+struct oeth_regs {
+ unsigned moder; /* Mode Register */
+ unsigned int_src; /* Interrupt Source Register */
+ unsigned int_mask; /* Interrupt Mask Register */
+ unsigned ipgt; /* Back to Bak Inter Packet Gap Register */
+ unsigned ipgr1; /* Non Back to Back Inter Packet Gap Register 1 */
+ unsigned ipgr2; /* Non Back to Back Inter Packet Gap Register 2 */
+ unsigned packet_len; /* Packet Length Register (min. and max.) */
+ unsigned collconf; /* Collision and Retry Configuration Register */
+ unsigned tx_bd_num; /* Transmit Buffer Descriptor Number Register */
+ unsigned ctrlmoder; /* Control Module Mode Register */
+ unsigned miimoder; /* MII Mode Register */
+ unsigned miicommand; /* MII Command Register */
+ unsigned miiaddress; /* MII Address Register */
+ unsigned miitx_data; /* MII Transmit Data Register */
+ unsigned miirx_data; /* MII Receive Data Register */
+ unsigned miistatus; /* MII Status Register */
+ unsigned mac_addr0; /* MAC Individual Address Register 0 */
+ unsigned mac_addr1; /* MAC Individual Address Register 1 */
+ unsigned hash_addr0; /* Hash Register 0 */
+ unsigned hash_addr1; /* Hash Register 1 */
+};
+/* MODER Register */
+#define OETH_MODER_RST 0x00000800 /* Reset MAC */
+/* MII Mode Register */
+#define OETH_MIIMODER_CLKDIV 0x000000FF /* Clock Divider */
+
+
+
+void platform_halt(void)
+{
+ /* Just display HALT on LCD display, and loop. */
+ lcd_disp_at_pos(" HALT ", 0);
+ local_irq_disable();
+ while (1);
+}
+
+void platform_power_off(void)
+{
+ /* No software-controlled power-off, just display POWEROFF and loop. */
+ lcd_disp_at_pos ("POWEROFF", 0);
+ local_irq_disable();
+ while (1);
+}
+
+void platform_restart(void)
+{
+ /* Software-initiated board reset. */
+ *(volatile unsigned *)XTAVNET_SWRST_VADDR = 0xdead;
+}
+
+void platform_heartbeat(void)
+{
+ /* Executes every timer tick. */
+}
+
+
+/*
+ * Called from time_init(). "Calibrating" is a misnomer, here we just read
+ * the clock rate from the board specific FPGA registers.
+ */
+void platform_calibrate_ccount(void)
+{
+ long clk_freq = *(long *)XTAVNET_CLKFRQ_VADDR;
+
+ ccount_per_jiffy = clk_freq / HZ;
+ nsec_per_ccount = 1000000000UL / clk_freq;
+}
+
+
+/*----------------------------------------------------------------------------
+ * Ethernet -- OpenCores Ethernet MAC (ethoc driver)
+ */
+
+static struct resource ethoc_res[] = {
+ [0] = { /* register space */
+ .start = OETH_REGS_PADDR,
+ .end = OETH_REGS_PADDR + OETH_REGS_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = { /* buffer space */
+ .start = OETH_SRAMBUFF_PADDR,
+ .end = OETH_SRAMBUFF_PADDR + OETH_SRAMBUFF_SIZE - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ [2] = { /* IRQ number */
+ .start = OETH_IRQ,
+ .end = OETH_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct ethoc_platform_data ethoc_pdata = {
+ .hwaddr = { OETH_MACADDR }, /* last byte written in setup below */
+ .phy_id = -1,
+};
+
+static struct platform_device ethoc_device = {
+ .name = "ethoc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(ethoc_res),
+ .resource = ethoc_res,
+ .dev = {
+ .platform_data = &ethoc_pdata,
+ },
+};
+
+
+/*----------------------------------------------------------------------------
+ * UART
+ */
+
+static struct resource serial_resource = {
+ .start = UART_PADDR,
+ .end = UART_PADDR + 0x1f,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct plat_serial8250_port serial_platform_data[] = {
+ [0] = {
+ .mapbase = UART_PADDR,
+ .irq = UART_INTNUM,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_IOREMAP,
+ .iotype = UPIO_MEM32,
+ .regshift = 2,
+ .uartclk = 0, /* set in xtavnet_init() */
+ },
+ { },
+};
+
+static struct platform_device xtavnet_uart = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = serial_platform_data,
+ },
+ .num_resources = 1,
+ .resource = &serial_resource,
+};
+
+
+/*----------------------------------------------------------------------------
+ */
+
+/* platform devices */
+static struct platform_device *platform_devices[] = {
+ &ethoc_device,
+ &xtavnet_uart,
+};
+
+
+
+/* very early init */
+void __init platform_setup(char **cmdline)
+{
+ if (cmdline) {
+ if (cmdline[0])
+ printk("XTAVnet: platform_setup(cmdline[0]:'%s')\n", cmdline[0]);
+ else
+ printk("XTAVnet: platform_setup(cmdline[0]:<null>)\n");
+ }
+}
+
+/* early initialization, before secondary cpu's have been brought up */
+
+void platform_init(bp_tag_t *bootparams)
+{
+ printk("\n");
+ if( bootparams )
+ printk("XTAVnet: platform_init(bootparams:0x%x)\n", (unsigned)bootparams);
+}
+
+static int xtavnet_init(void)
+{
+ volatile struct oeth_regs *regs = (volatile struct oeth_regs*)OETH_REGS_VADDR;
+
+ /*
+ * Do some of the initialization missing in the ETHOC driver.
+ * (Perhaps not all necessary, but was in a previously used driver.)
+ */
+
+ /* Reset the controller. */
+ regs->moder = OETH_MODER_RST; /* Reset ON */
+ regs->moder &= ~OETH_MODER_RST; /* Reset OFF */
+
+ regs->packet_len = (64 << 16) | 1536;
+ regs->ipgr1 = 0x0000000c;
+ regs->ipgr2 = 0x00000012;
+ regs->collconf = 0x000f003f;
+ regs->ctrlmoder = 0;
+ regs->miimoder = (OETH_MIIMODER_CLKDIV & 0x2);
+
+ /*
+ * Setup dynamic info in platform device init structures.
+ */
+
+ /* Ethernet MAC address. */
+ ethoc_pdata.hwaddr[5] = *(u32*)DIP_SWITCHES_VADDR;
+
+ /* Clock rate varies among FPGA bitstreams; board specific FPGA register
+ * reports the actual clock rate. */
+ serial_platform_data[0].uartclk = *(long *)XTAVNET_CLKFRQ_VADDR;
+
+
+ /* register platform devices */
+ platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
+
+ /* ETHOC driver is a bit quiet; at least display Ethernet MAC, so user
+ knows whether they set it correctly on the DIP switches. */
+ printk("XTAVnet: Ethernet MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ethoc_pdata.hwaddr[0], ethoc_pdata.hwaddr[1], ethoc_pdata.hwaddr[2],
+ ethoc_pdata.hwaddr[3], ethoc_pdata.hwaddr[4], ethoc_pdata.hwaddr[5]);
+
+ return 0;
+}
+
+
+/*
+ * Register to be done during do_initcalls().
+ */
+arch_initcall(xtavnet_init);
+
+
diff --git a/block/blk-core.c b/block/blk-core.c
index 3bc5579d6f54..f84cce42fc58 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -467,6 +467,9 @@ static int blk_init_free_list(struct request_queue *q)
{
struct request_list *rl = &q->rq;
+ if (unlikely(rl->rq_pool))
+ return 0;
+
rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0;
rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0;
rl->elvpriv = 0;
@@ -570,9 +573,17 @@ EXPORT_SYMBOL(blk_init_queue);
struct request_queue *
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
{
- struct request_queue *q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ struct request_queue *uninit_q, *q;
+
+ uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id);
+ if (!uninit_q)
+ return NULL;
+
+ q = blk_init_allocated_queue_node(uninit_q, rfn, lock, node_id);
+ if (!q)
+ blk_cleanup_queue(uninit_q);
- return blk_init_allocated_queue_node(q, rfn, lock, node_id);
+ return q;
}
EXPORT_SYMBOL(blk_init_queue_node);
@@ -592,10 +603,8 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
return NULL;
q->node = node_id;
- if (blk_init_free_list(q)) {
- kmem_cache_free(blk_requestq_cachep, q);
+ if (blk_init_free_list(q))
return NULL;
- }
q->request_fn = rfn;
q->prep_rq_fn = NULL;
@@ -618,7 +627,6 @@ blk_init_allocated_queue_node(struct request_queue *q, request_fn_proc *rfn,
return q;
}
- blk_put_queue(q);
return NULL;
}
EXPORT_SYMBOL(blk_init_allocated_queue_node);
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index ed897b5ef315..5ff4f4850e71 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -64,6 +64,9 @@ static DEFINE_PER_CPU(unsigned long, cfq_ioc_count);
static struct completion *ioc_gone;
static DEFINE_SPINLOCK(ioc_gone_lock);
+static DEFINE_SPINLOCK(cic_index_lock);
+static DEFINE_IDA(cic_index_ida);
+
#define CFQ_PRIO_LISTS IOPRIO_BE_NR
#define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
#define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
@@ -271,6 +274,7 @@ struct cfq_data {
unsigned int cfq_latency;
unsigned int cfq_group_isolation;
+ unsigned int cic_index;
struct list_head cic_list;
/*
@@ -430,6 +434,24 @@ static inline void cic_set_cfqq(struct cfq_io_context *cic,
cic->cfqq[is_sync] = cfqq;
}
+#define CIC_DEAD_KEY 1ul
+#define CIC_DEAD_INDEX_SHIFT 1
+
+static inline void *cfqd_dead_key(struct cfq_data *cfqd)
+{
+ return (void *)(cfqd->cic_index << CIC_DEAD_INDEX_SHIFT | CIC_DEAD_KEY);
+}
+
+static inline struct cfq_data *cic_to_cfqd(struct cfq_io_context *cic)
+{
+ struct cfq_data *cfqd = cic->key;
+
+ if (unlikely((unsigned long) cfqd & CIC_DEAD_KEY))
+ return NULL;
+
+ return cfqd;
+}
+
/*
* We regard a request as SYNC, if it's either a read or has the SYNC bit
* set (in which case it could also be direct WRITE).
@@ -2510,11 +2532,12 @@ static void cfq_cic_free(struct cfq_io_context *cic)
static void cic_free_func(struct io_context *ioc, struct cfq_io_context *cic)
{
unsigned long flags;
+ unsigned long dead_key = (unsigned long) cic->key;
- BUG_ON(!cic->dead_key);
+ BUG_ON(!(dead_key & CIC_DEAD_KEY));
spin_lock_irqsave(&ioc->lock, flags);
- radix_tree_delete(&ioc->radix_root, cic->dead_key);
+ radix_tree_delete(&ioc->radix_root, dead_key >> CIC_DEAD_INDEX_SHIFT);
hlist_del_rcu(&cic->cic_list);
spin_unlock_irqrestore(&ioc->lock, flags);
@@ -2537,15 +2560,10 @@ static void cfq_free_io_context(struct io_context *ioc)
__call_for_each_cic(ioc, cic_free_func);
}
-static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static void cfq_put_cooperator(struct cfq_queue *cfqq)
{
struct cfq_queue *__cfqq, *next;
- if (unlikely(cfqq == cfqd->active_queue)) {
- __cfq_slice_expired(cfqd, cfqq, 0);
- cfq_schedule_dispatch(cfqd);
- }
-
/*
* If this queue was scheduled to merge with another queue, be
* sure to drop the reference taken on that queue (and others in
@@ -2561,6 +2579,16 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
cfq_put_queue(__cfqq);
__cfqq = next;
}
+}
+
+static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ if (unlikely(cfqq == cfqd->active_queue)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
+
+ cfq_put_cooperator(cfqq);
cfq_put_queue(cfqq);
}
@@ -2573,11 +2601,10 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
list_del_init(&cic->queue_list);
/*
- * Make sure key == NULL is seen for dead queues
+ * Make sure dead mark is seen for dead queues
*/
smp_wmb();
- cic->dead_key = (unsigned long) cic->key;
- cic->key = NULL;
+ cic->key = cfqd_dead_key(cfqd);
if (ioc->ioc_data == cic)
rcu_assign_pointer(ioc->ioc_data, NULL);
@@ -2596,7 +2623,7 @@ static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
static void cfq_exit_single_io_context(struct io_context *ioc,
struct cfq_io_context *cic)
{
- struct cfq_data *cfqd = cic->key;
+ struct cfq_data *cfqd = cic_to_cfqd(cic);
if (cfqd) {
struct request_queue *q = cfqd->queue;
@@ -2609,7 +2636,7 @@ static void cfq_exit_single_io_context(struct io_context *ioc,
* race between exiting task and queue
*/
smp_read_barrier_depends();
- if (cic->key)
+ if (cic->key == cfqd)
__cfq_exit_single_io_context(cfqd, cic);
spin_unlock_irqrestore(q->queue_lock, flags);
@@ -2689,7 +2716,7 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
static void changed_ioprio(struct io_context *ioc, struct cfq_io_context *cic)
{
- struct cfq_data *cfqd = cic->key;
+ struct cfq_data *cfqd = cic_to_cfqd(cic);
struct cfq_queue *cfqq;
unsigned long flags;
@@ -2746,7 +2773,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
static void changed_cgroup(struct io_context *ioc, struct cfq_io_context *cic)
{
struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1);
- struct cfq_data *cfqd = cic->key;
+ struct cfq_data *cfqd = cic_to_cfqd(cic);
unsigned long flags;
struct request_queue *q;
@@ -2883,12 +2910,13 @@ cfq_drop_dead_cic(struct cfq_data *cfqd, struct io_context *ioc,
unsigned long flags;
WARN_ON(!list_empty(&cic->queue_list));
+ BUG_ON(cic->key != cfqd_dead_key(cfqd));
spin_lock_irqsave(&ioc->lock, flags);
BUG_ON(ioc->ioc_data == cic);
- radix_tree_delete(&ioc->radix_root, (unsigned long) cfqd);
+ radix_tree_delete(&ioc->radix_root, cfqd->cic_index);
hlist_del_rcu(&cic->cic_list);
spin_unlock_irqrestore(&ioc->lock, flags);
@@ -2900,7 +2928,6 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
{
struct cfq_io_context *cic;
unsigned long flags;
- void *k;
if (unlikely(!ioc))
return NULL;
@@ -2917,13 +2944,11 @@ cfq_cic_lookup(struct cfq_data *cfqd, struct io_context *ioc)
}
do {
- cic = radix_tree_lookup(&ioc->radix_root, (unsigned long) cfqd);
+ cic = radix_tree_lookup(&ioc->radix_root, cfqd->cic_index);
rcu_read_unlock();
if (!cic)
break;
- /* ->key must be copied to avoid race with cfq_exit_queue() */
- k = cic->key;
- if (unlikely(!k)) {
+ if (unlikely(cic->key != cfqd)) {
cfq_drop_dead_cic(cfqd, ioc, cic);
rcu_read_lock();
continue;
@@ -2956,7 +2981,7 @@ static int cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
spin_lock_irqsave(&ioc->lock, flags);
ret = radix_tree_insert(&ioc->radix_root,
- (unsigned long) cfqd, cic);
+ cfqd->cic_index, cic);
if (!ret)
hlist_add_head_rcu(&cic->cic_list, &ioc->cic_list);
spin_unlock_irqrestore(&ioc->lock, flags);
@@ -3516,6 +3541,9 @@ split_cfqq(struct cfq_io_context *cic, struct cfq_queue *cfqq)
}
cic_set_cfqq(cic, NULL, 1);
+
+ cfq_put_cooperator(cfqq);
+
cfq_put_queue(cfqq);
return NULL;
}
@@ -3708,10 +3736,32 @@ static void cfq_exit_queue(struct elevator_queue *e)
cfq_shutdown_timer_wq(cfqd);
+ spin_lock(&cic_index_lock);
+ ida_remove(&cic_index_ida, cfqd->cic_index);
+ spin_unlock(&cic_index_lock);
+
/* Wait for cfqg->blkg->key accessors to exit their grace periods. */
call_rcu(&cfqd->rcu, cfq_cfqd_free);
}
+static int cfq_alloc_cic_index(void)
+{
+ int index, error;
+
+ do {
+ if (!ida_pre_get(&cic_index_ida, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(&cic_index_lock);
+ error = ida_get_new(&cic_index_ida, &index);
+ spin_unlock(&cic_index_lock);
+ if (error && error != -EAGAIN)
+ return error;
+ } while (error);
+
+ return index;
+}
+
static void *cfq_init_queue(struct request_queue *q)
{
struct cfq_data *cfqd;
@@ -3719,10 +3769,16 @@ static void *cfq_init_queue(struct request_queue *q)
struct cfq_group *cfqg;
struct cfq_rb_root *st;
+ i = cfq_alloc_cic_index();
+ if (i < 0)
+ return NULL;
+
cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node);
if (!cfqd)
return NULL;
+ cfqd->cic_index = i;
+
/* Init root service tree */
cfqd->grp_service_tree = CFQ_RB_ROOT;
@@ -3984,6 +4040,7 @@ static void __exit cfq_exit(void)
*/
if (elv_ioc_count_read(cfq_ioc_count))
wait_for_completion(&all_gone);
+ ida_destroy(&cic_index_ida);
cfq_slab_kill();
}
diff --git a/block/elevator.c b/block/elevator.c
index 6df2b5056b51..923a9139106c 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -242,9 +242,11 @@ int elevator_init(struct request_queue *q, char *name)
{
struct elevator_type *e = NULL;
struct elevator_queue *eq;
- int ret = 0;
void *data;
+ if (unlikely(q->elevator))
+ return 0;
+
INIT_LIST_HEAD(&q->queue_head);
q->last_merge = NULL;
q->end_sector = 0;
@@ -284,7 +286,7 @@ int elevator_init(struct request_queue *q, char *name)
}
elevator_attach(q, eq, data);
- return ret;
+ return 0;
}
EXPORT_SYMBOL(elevator_init);
@@ -1097,7 +1099,7 @@ ssize_t elv_iosched_show(struct request_queue *q, char *name)
struct elevator_type *__e;
int len = 0;
- if (!q->elevator)
+ if (!q->elevator || !blk_queue_stackable(q))
return sprintf(name, "none\n");
elv = e->elevator_type;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 9d9434f08c92..1cd497d7a15a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -80,6 +80,11 @@ config CRYPTO_RNG2
config CRYPTO_PCOMP
tristate
+ select CRYPTO_PCOMP2
+ select CRYPTO_ALGAPI
+
+config CRYPTO_PCOMP2
+ tristate
select CRYPTO_ALGAPI2
config CRYPTO_MANAGER
@@ -94,7 +99,15 @@ config CRYPTO_MANAGER2
select CRYPTO_AEAD2
select CRYPTO_HASH2
select CRYPTO_BLKCIPHER2
- select CRYPTO_PCOMP
+ select CRYPTO_PCOMP2
+
+config CRYPTO_MANAGER_TESTS
+ bool "Run algolithms' self-tests"
+ default y
+ depends on CRYPTO_MANAGER2
+ help
+ Run cryptomanager's tests for the new crypto algorithms being
+ registered.
config CRYPTO_GF128MUL
tristate "GF(2^128) multiplication functions (EXPERIMENTAL)"
diff --git a/crypto/Makefile b/crypto/Makefile
index d7e6441df7fe..423b7de61f93 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -26,7 +26,7 @@ crypto_hash-objs += ahash.o
crypto_hash-objs += shash.o
obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o
-obj-$(CONFIG_CRYPTO_PCOMP) += pcompress.o
+obj-$(CONFIG_CRYPTO_PCOMP2) += pcompress.o
cryptomgr-objs := algboss.o testmgr.o
@@ -61,7 +61,7 @@ obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o
obj-$(CONFIG_CRYPTO_DES) += des_generic.o
obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
-obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
+obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o
obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
diff --git a/crypto/algboss.c b/crypto/algboss.c
index c3c196b5823a..40bd391f34d9 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -206,6 +206,7 @@ err:
return NOTIFY_OK;
}
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
static int cryptomgr_test(void *data)
{
struct crypto_test_param *param = data;
@@ -266,6 +267,7 @@ err_put_module:
err:
return NOTIFY_OK;
}
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
void *data)
@@ -273,8 +275,10 @@ static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
switch (msg) {
case CRYPTO_MSG_ALG_REQUEST:
return cryptomgr_schedule_probe(data);
+#ifdef CONFIG_CRYPTO_MANAGER_TESTS
case CRYPTO_MSG_ALG_REGISTER:
return cryptomgr_schedule_test(data);
+#endif
}
return NOTIFY_DONE;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index b9884ee0adb6..a5a22cfcd07b 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -616,7 +616,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
CRYPTO_ALG_TYPE_AHASH_MASK);
if (IS_ERR(auth))
- return ERR_PTR(PTR_ERR(auth));
+ return ERR_CAST(auth);
auth_base = &auth->base;
diff --git a/crypto/ctr.c b/crypto/ctr.c
index 6c3bfabb9d1d..4ca7222cfeb6 100644
--- a/crypto/ctr.c
+++ b/crypto/ctr.c
@@ -185,7 +185,7 @@ static struct crypto_instance *crypto_ctr_alloc(struct rtattr **tb)
alg = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);
/* Block size must be >= 4 bytes. */
err = -EINVAL;
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 5c8aaa0cb0b9..abd980c729eb 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -22,6 +22,17 @@
#include <crypto/rng.h>
#include "internal.h"
+
+#ifndef CONFIG_CRYPTO_MANAGER_TESTS
+
+/* a perfect nop */
+int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
+{
+ return 0;
+}
+
+#else
+
#include "testmgr.h"
/*
@@ -2530,4 +2541,7 @@ notest:
non_fips_alg:
return -EINVAL;
}
+
+#endif /* CONFIG_CRYPTO_MANAGER_TESTS */
+
EXPORT_SYMBOL_GPL(alg_test);
diff --git a/crypto/twofish.c b/crypto/twofish_generic.c
index dfcda231f87a..1f07b843e07c 100644
--- a/crypto/twofish.c
+++ b/crypto/twofish_generic.c
@@ -212,3 +212,4 @@ module_exit(twofish_mod_fini);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION ("Twofish Cipher Algorithm");
+MODULE_ALIAS("twofish");
diff --git a/crypto/xts.c b/crypto/xts.c
index d87b0f3102c3..555ecaab1e54 100644
--- a/crypto/xts.c
+++ b/crypto/xts.c
@@ -224,7 +224,7 @@ static struct crypto_instance *alloc(struct rtattr **tb)
alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
CRYPTO_ALG_TYPE_MASK);
if (IS_ERR(alg))
- return ERR_PTR(PTR_ERR(alg));
+ return ERR_CAST(alg);
inst = crypto_alloc_instance("xts", alg);
if (IS_ERR(inst))
diff --git a/drivers/Makefile b/drivers/Makefile
index 91874e048552..e9c5f57f81f0 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -113,3 +113,4 @@ obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
obj-y += platform/
obj-y += ieee802154/
+obj-y += vbus/
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index d269a8f3329c..446aced33aff 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -46,6 +46,8 @@ static unsigned long power_saving_mwait_eax;
static unsigned char tsc_detected_unstable;
static unsigned char tsc_marked_unstable;
+static unsigned char lapic_detected_unstable;
+static unsigned char lapic_marked_unstable;
static void power_saving_mwait_init(void)
{
@@ -75,9 +77,6 @@ static void power_saving_mwait_init(void)
power_saving_mwait_eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) |
(highest_subcstate - 1);
- for_each_online_cpu(i)
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ON, &i);
-
#if defined(CONFIG_GENERIC_TIME) && defined(CONFIG_X86)
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
@@ -86,13 +85,15 @@ static void power_saving_mwait_init(void)
* AMD Fam10h TSC will tick in all
* C/P/S0/S1 states when this bit is set.
*/
- if (boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
- return;
-
- /*FALL THROUGH*/
+ if (!boot_cpu_has(X86_FEATURE_NONSTOP_TSC))
+ tsc_detected_unstable = 1;
+ if (!boot_cpu_has(X86_FEATURE_ARAT))
+ lapic_detected_unstable = 1;
+ break;
default:
- /* TSC could halt in idle */
+ /* TSC & LAPIC could halt in idle */
tsc_detected_unstable = 1;
+ lapic_detected_unstable = 1;
}
#endif
}
@@ -180,10 +181,20 @@ static int power_saving_thread(void *data)
mark_tsc_unstable("TSC halts in idle");
tsc_marked_unstable = 1;
}
+ if (lapic_detected_unstable && !lapic_marked_unstable) {
+ int i;
+ /* LAPIC could halt in idle, so notify users */
+ for_each_online_cpu(i)
+ clockevents_notify(
+ CLOCK_EVT_NOTIFY_BROADCAST_ON,
+ &i);
+ lapic_marked_unstable = 1;
+ }
local_irq_disable();
cpu = smp_processor_id();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER,
- &cpu);
+ if (lapic_marked_unstable)
+ clockevents_notify(
+ CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
stop_critical_timings();
__monitor((void *)&current_thread_info()->flags, 0, 0);
@@ -192,8 +203,9 @@ static int power_saving_thread(void *data)
__mwait(power_saving_mwait_eax, 1);
start_critical_timings();
- clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT,
- &cpu);
+ if (lapic_marked_unstable)
+ clockevents_notify(
+ CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
local_irq_enable();
if (jiffies > expire_time) {
diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h
index 33181ad350d5..b17d8de9f6ff 100644
--- a/drivers/acpi/acpica/acconfig.h
+++ b/drivers/acpi/acpica/acconfig.h
@@ -119,6 +119,10 @@
#define ACPI_MAX_LOOP_ITERATIONS 0xFFFF
+/* Maximum sleep allowed via Sleep() operator */
+
+#define ACPI_MAX_SLEEP 20000 /* Two seconds */
+
/******************************************************************************
*
* ACPI Specification constants (Do not change unless the specification changes)
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 9070f1fe8f17..899d68afc3c5 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -125,6 +125,14 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
*/
u8 ACPI_INIT_GLOBAL(acpi_gbl_copy_dsdt_locally, FALSE);
+/*
+ * Optionally truncate I/O addresses to 16 bits. Provides compatibility
+ * with other ACPI implementations. NOTE: During ACPICA initialization,
+ * this value is set to TRUE if any Windows OSI strings have been
+ * requested by the BIOS.
+ */
+u8 ACPI_INIT_GLOBAL(acpi_gbl_truncate_io_addresses, FALSE);
+
/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
struct acpi_table_fadt acpi_gbl_FADT;
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 147a7e6bd38f..eb2d420b39ec 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -184,8 +184,9 @@ struct acpi_namespace_node {
u8 flags; /* Miscellaneous flags */
acpi_owner_id owner_id; /* Node creator */
union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */
+ struct acpi_namespace_node *parent; /* Parent node */
struct acpi_namespace_node *child; /* First child */
- struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */
+ struct acpi_namespace_node *peer; /* First peer */
/*
* The following fields are used by the ASL compiler and disassembler only
@@ -199,7 +200,7 @@ struct acpi_namespace_node {
/* Namespace Node flags */
-#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */
+#define ANOBJ_RESERVED 0x01 /* Available for use */
#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */
#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */
#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index 258159cfcdfa..9f60ff002203 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -369,11 +369,4 @@ struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle);
void acpi_ns_terminate(void);
-struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
- *node);
-
-struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
- acpi_namespace_node
- *node);
-
#endif /* __ACNAMESP_H__ */
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index cde18ea82656..54857fa87aaf 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -91,14 +91,14 @@
/* Values for Flag byte above */
-#define AOPOBJ_AML_CONSTANT 0x01
-#define AOPOBJ_STATIC_POINTER 0x02
-#define AOPOBJ_DATA_VALID 0x04
-#define AOPOBJ_OBJECT_INITIALIZED 0x08
-#define AOPOBJ_SETUP_COMPLETE 0x10
-#define AOPOBJ_SINGLE_DATUM 0x20
-#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */
-#define AOPOBJ_MODULE_LEVEL 0x80
+#define AOPOBJ_AML_CONSTANT 0x01 /* Integer is an AML constant */
+#define AOPOBJ_STATIC_POINTER 0x02 /* Data is part of an ACPI table, don't delete */
+#define AOPOBJ_DATA_VALID 0x04 /* Object is intialized and data is valid */
+#define AOPOBJ_OBJECT_INITIALIZED 0x08 /* Region is initialized, _REG was run */
+#define AOPOBJ_SETUP_COMPLETE 0x10 /* Region setup is complete */
+#define AOPOBJ_INVALID 0x20 /* Host OS won't allow a Region address */
+#define AOPOBJ_MODULE_LEVEL 0x40 /* Method is actually module-level code */
+#define AOPOBJ_MODIFIED_NAMESPACE 0x80 /* Method modified the namespace */
/******************************************************************************
*
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index 97116082cb6c..10998d369ad0 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -503,15 +503,16 @@ static const union acpi_predefined_info predefined_names[] =
{{"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}},
{{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2,0}, 0,0}}, /* Fixed-length (2 Int), but is optional */
- {{{0,0,0,0}, 0,0}} /* Table terminator */
-};
+ /* _WDG/_WED are MS extensions defined by "Windows Instrumentation" */
-#if 0
- /* Not implemented */
+ {{"_WDG", 0, ACPI_RTYPE_BUFFER}},
+ {{"_WED", 1,
+ ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER}},
- {{"_WDG", 0, ACPI_RTYPE_BUFFER}}, /* MS Extension */
- {{"_WED", 1, ACPI_RTYPE_PACKAGE}}, /* MS Extension */
+ {{{0, 0, 0, 0}, 0, 0}} /* Table terminator */
+};
+#if 0
/* This is an internally implemented control method, no need to check */
{{"_OSI", 1, ACPI_RTYPE_INTEGER}},
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index 161bc0e3d70a..6e5dd97949fe 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -127,22 +127,22 @@ struct acpi_walk_state {
acpi_parse_upwards ascending_callback;
};
-/* Info used by acpi_ps_init_objects */
+/* Info used by acpi_ns_initialize_objects and acpi_ds_initialize_objects */
struct acpi_init_walk_info {
- u16 method_count;
- u16 device_count;
- u16 op_region_count;
- u16 field_count;
- u16 buffer_count;
- u16 package_count;
- u16 op_region_init;
- u16 field_init;
- u16 buffer_init;
- u16 package_init;
- u16 object_count;
- acpi_owner_id owner_id;
u32 table_index;
+ u32 object_count;
+ u32 method_count;
+ u32 device_count;
+ u32 op_region_count;
+ u32 field_count;
+ u32 buffer_count;
+ u32 package_count;
+ u32 op_region_init;
+ u32 field_init;
+ u32 buffer_init;
+ u32 package_init;
+ acpi_owner_id owner_id;
};
struct acpi_get_devices_info {
@@ -201,11 +201,11 @@ struct acpi_evaluate_info {
/* Info used by acpi_ns_initialize_devices */
struct acpi_device_walk_info {
- u16 device_count;
- u16 num_STA;
- u16 num_INI;
struct acpi_table_desc *table_desc;
struct acpi_evaluate_info *evaluate_info;
+ u32 device_count;
+ u32 num_STA;
+ u32 num_INI;
};
/* TBD: [Restructure] Merge with struct above */
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index abe140318a74..cc4a38c57558 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -171,12 +171,12 @@ acpi_ds_initialize_objects(u32 table_index,
"**** Starting initialization of namespace objects ****\n"));
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
- info.method_count = 0;
- info.op_region_count = 0;
- info.object_count = 0;
- info.device_count = 0;
- info.table_index = table_index;
+ /* Set all init info to zero */
+
+ ACPI_MEMSET(&info, 0, sizeof(struct acpi_init_walk_info));
+
info.owner_id = owner_id;
+ info.table_index = table_index;
/* Walk entire namespace from the supplied root */
@@ -204,13 +204,13 @@ acpi_ds_initialize_objects(u32 table_index,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
+ "\nTable [%4.4s](id %4.4X) - %u Objects with %u Devices %u Methods %u Regions\n",
table->signature, owner_id, info.object_count,
info.device_count, info.method_count,
info.op_region_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Methods, %hd Regions\n", info.method_count,
+ "%u Methods, %u Regions\n", info.method_count,
info.op_region_count));
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 2a9a561c2f01..64750ee96e20 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -584,8 +584,22 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
* want make the objects permanent.
*/
if (!(method_desc->method.flags & AOPOBJ_MODULE_LEVEL)) {
- acpi_ns_delete_namespace_by_owner(method_desc->method.
- owner_id);
+
+ /* Delete any direct children of (created by) this method */
+
+ acpi_ns_delete_namespace_subtree(walk_state->
+ method_node);
+
+ /*
+ * Delete any objects that were created by this method
+ * elsewhere in the namespace (if any were created).
+ */
+ if (method_desc->method.
+ flags & AOPOBJ_MODIFIED_NAMESPACE) {
+ acpi_ns_delete_namespace_by_owner(method_desc->
+ method.
+ owner_id);
+ }
}
}
@@ -605,7 +619,7 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
* we immediately reuse it for the next thread executing this method
*/
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "*** Completed execution of one thread, %d threads remaining\n",
+ "*** Completed execution of one thread, %u threads remaining\n",
method_desc->method.thread_count));
} else {
/* This is the only executing thread for this method */
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index f3d52f59250b..8095306fcd8c 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -102,8 +102,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->arguments[i].name.integer |= (i << 24);
walk_state->arguments[i].descriptor_type = ACPI_DESC_TYPE_NAMED;
walk_state->arguments[i].type = ACPI_TYPE_ANY;
- walk_state->arguments[i].flags =
- ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+ walk_state->arguments[i].flags = ANOBJ_METHOD_ARG;
}
/* Init the method locals */
@@ -116,8 +115,7 @@ void acpi_ds_method_data_init(struct acpi_walk_state *walk_state)
walk_state->local_variables[i].descriptor_type =
ACPI_DESC_TYPE_NAMED;
walk_state->local_variables[i].type = ACPI_TYPE_ANY;
- walk_state->local_variables[i].flags =
- ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+ walk_state->local_variables[i].flags = ANOBJ_METHOD_LOCAL;
}
return_VOID;
@@ -146,7 +144,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
if (walk_state->local_variables[index].object) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%d=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Local%u=%p\n",
index,
walk_state->local_variables[index].
object));
@@ -162,7 +160,7 @@ void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state)
for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
if (walk_state->arguments[index].object) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%d=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Deleting Arg%u=%p\n",
index,
walk_state->arguments[index].object));
@@ -226,7 +224,7 @@ acpi_ds_method_data_init_args(union acpi_operand_object **params,
index++;
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%d args passed to method\n", index));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "%u args passed to method\n", index));
return_ACPI_STATUS(AE_OK);
}
@@ -323,7 +321,7 @@ acpi_ds_method_data_set_value(u8 type,
ACPI_FUNCTION_TRACE(ds_method_data_set_value);
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "NewObj %p Type %2.2X, Refs=%d [%s]\n", object,
+ "NewObj %p Type %2.2X, Refs=%u [%s]\n", object,
type, object->common.reference_count,
acpi_ut_get_type_name(object->common.type)));
@@ -543,7 +541,7 @@ acpi_ds_store_object_to_local(u8 type,
union acpi_operand_object *new_obj_desc;
ACPI_FUNCTION_TRACE(ds_store_object_to_local);
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%d Obj=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Type=%2.2X Index=%u Obj=%p\n",
type, index, obj_desc));
/* Parameter validation */
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 53a7e416f33e..7c0e74227171 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -213,7 +213,7 @@ acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
@@ -257,7 +257,7 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
/* Execute the AML code for the term_arg arguments */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
return_ACPI_STATUS(status);
@@ -394,7 +394,7 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
/* Execute the argument AML */
- status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ status = acpi_ds_execute_arguments(node, node->parent,
extra_desc->extra.aml_length,
extra_desc->extra.aml_start);
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 306c62ab2e88..15135c25aa9b 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -746,7 +746,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
index--;
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ "Arg #%u (%p) done, Arg1=%p\n", index, arg,
first_arg));
}
@@ -760,7 +760,7 @@ acpi_ds_create_operands(struct acpi_walk_state *walk_state,
*/
acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
- ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %u", index));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 2e3b0334072f..f40d271bf568 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -199,7 +199,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
return_ACPI_STATUS(status);
}
- parent_node = acpi_ns_get_parent_node(region_obj->region.node);
+ parent_node = region_obj->region.node->parent;
/*
* Get the _SEG and _BBN values from the device upon which the handler
@@ -248,7 +248,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
break;
}
- pci_root_node = acpi_ns_get_parent_node(pci_root_node);
+ pci_root_node = pci_root_node->parent;
}
/* PCI root bridge not found, use namespace root node */
@@ -280,7 +280,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
*/
pci_device_node = region_obj->region.node;
while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
- pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+ pci_device_node = pci_device_node->parent;
}
if (!pci_device_node) {
@@ -521,7 +521,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
return_ACPI_STATUS(AE_NOT_EXIST);
}
- node = acpi_ns_get_parent_node(region_obj->region.node);
+ node = region_obj->region.node->parent;
space_id = region_obj->region.space_id;
/* Setup defaults */
@@ -654,7 +654,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
/* This node does not have the handler we need; Pop up one level */
- node = acpi_ns_get_parent_node(node);
+ node = node->parent;
}
/* If we get here, there is no handler for this region */
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index d39d438ba1e3..f067bbb0d961 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -742,7 +742,7 @@ acpi_ex_dump_operands(union acpi_operand_object **operands,
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "**** Start operand dump for opcode [%s], %d operands\n",
+ "**** Start operand dump for opcode [%s], %u operands\n",
opcode_name, num_operands));
if (num_operands == 0) {
@@ -812,7 +812,7 @@ void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags)
acpi_ex_out_string("Type", acpi_ut_get_type_name(node->type));
acpi_ex_out_pointer("Attached Object",
acpi_ns_get_attached_object(node));
- acpi_ex_out_pointer("Parent", acpi_ns_get_parent_node(node));
+ acpi_ex_out_pointer("Parent", node->parent);
acpi_ex_dump_object(ACPI_CAST_PTR(union acpi_operand_object, node),
acpi_ex_dump_node);
@@ -945,7 +945,7 @@ acpi_ex_dump_package_obj(union acpi_operand_object *obj_desc,
case ACPI_TYPE_PACKAGE:
- acpi_os_printf("[Package] Contains %d Elements:\n",
+ acpi_os_printf("[Package] Contains %u Elements:\n",
obj_desc->package.count);
for (i = 0; i < obj_desc->package.count; i++) {
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index a6dc26f0b3be..047217303a4b 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -534,13 +534,13 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc,
if (ACPI_SUCCESS(status)) {
if (read_write == ACPI_READ) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Value Read %8.8X%8.8X, Width %d\n",
+ "Value Read %8.8X%8.8X, Width %u\n",
ACPI_FORMAT_UINT64(*value),
obj_desc->common_field.
access_byte_width));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Value Written %8.8X%8.8X, Width %d\n",
+ "Value Written %8.8X%8.8X, Width %u\n",
ACPI_FORMAT_UINT64(*value),
obj_desc->common_field.
access_byte_width));
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 25059dace0ad..98a331d2249b 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -108,11 +108,11 @@ acpi_ex_generate_access(u32 field_bit_offset,
field_byte_length = field_byte_end_offset - field_byte_offset;
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Bit length %d, Bit offset %d\n",
+ "Bit length %u, Bit offset %u\n",
field_bit_length, field_bit_offset));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Byte Length %d, Byte Offset %d, End Offset %d\n",
+ "Byte Length %u, Byte Offset %u, End Offset %u\n",
field_byte_length, field_byte_offset,
field_byte_end_offset));
@@ -147,11 +147,11 @@ acpi_ex_generate_access(u32 field_bit_offset,
accesses = field_end_offset - field_start_offset;
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "AccessWidth %d end is within region\n",
+ "AccessWidth %u end is within region\n",
access_byte_width));
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Field Start %d, Field End %d -- requires %d accesses\n",
+ "Field Start %u, Field End %u -- requires %u accesses\n",
field_start_offset, field_end_offset,
accesses));
@@ -159,7 +159,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
if (accesses <= 1) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Entire field can be accessed with one operation of size %d\n",
+ "Entire field can be accessed with one operation of size %u\n",
access_byte_width));
return_VALUE(access_byte_width);
}
@@ -174,7 +174,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
}
} else {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "AccessWidth %d end is NOT within region\n",
+ "AccessWidth %u end is NOT within region\n",
access_byte_width));
if (access_byte_width == 1) {
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
@@ -190,7 +190,7 @@ acpi_ex_generate_access(u32 field_bit_offset,
* previous access
*/
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
- "Backing off to previous optimal access width of %d\n",
+ "Backing off to previous optimal access width of %u\n",
minimum_access_width));
return_VALUE(minimum_access_width);
}
@@ -385,15 +385,6 @@ acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc,
(field_bit_position -
ACPI_MUL_8(obj_desc->common_field.base_byte_offset));
- /*
- * Does the entire field fit within a single field access element? (datum)
- * (i.e., without crossing a datum boundary)
- */
- if ((obj_desc->common_field.start_field_bit_offset +
- field_bit_length) <= (u16) access_bit_width) {
- obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM;
- }
-
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index 531000fc77d2..8819d2ac5aee 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -194,7 +194,7 @@ acpi_ex_system_memory_space_handler(u32 function,
((u64) address - (u64) mem_info->mapped_physical_address);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
+ "System-Memory (width %u) R/W %u Address=%8.8X%8.8X\n",
bit_width, function,
ACPI_FORMAT_NATIVE_UINT(address)));
@@ -297,7 +297,7 @@ acpi_ex_system_io_space_handler(u32 function,
ACPI_FUNCTION_TRACE(ex_system_io_space_handler);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
+ "System-IO (width %u) R/W %u Address=%8.8X%8.8X\n",
bit_width, function,
ACPI_FORMAT_NATIVE_UINT(address)));
@@ -373,7 +373,7 @@ acpi_ex_pci_config_space_handler(u32 function,
pci_register = (u16) (u32) address;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Pci-Config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
+ "Pci-Config %u (%u) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
function, bit_width, pci_id->segment, pci_id->bus,
pci_id->device, pci_id->function, pci_register));
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index 6d32e09327f1..675aaa91a770 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -201,6 +201,14 @@ acpi_status acpi_ex_system_do_sleep(u64 how_long)
acpi_ex_relinquish_interpreter();
+ /*
+ * For compatibility with other ACPI implementations and to prevent
+ * accidental deep sleeps, limit the sleep time to something reasonable.
+ */
+ if (how_long > ACPI_MAX_SLEEP) {
+ how_long = ACPI_MAX_SLEEP;
+ }
+
acpi_os_sleep(how_long);
/* And now we must get the interpreter again */
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index 36eb803dd9d0..3796811276ac 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -307,7 +307,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
return_ACPI_STATUS(status);
}
ACPI_DEBUG_PRINT((ACPI_DB_INIT,
- "Entering sleep state [S%d]\n", sleep_state));
+ "Entering sleep state [S%u]\n", sleep_state));
/* Clear the SLP_EN and SLP_TYP fields */
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index c10d587c1641..e1d9c777b213 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -222,6 +222,12 @@ acpi_status acpi_hw_read_port(acpi_io_address address, u32 *value, u32 width)
u32 one_byte;
u32 i;
+ /* Truncate address to 16 bits if requested */
+
+ if (acpi_gbl_truncate_io_addresses) {
+ address &= ACPI_UINT16_MAX;
+ }
+
/* Validate the entire request and perform the I/O */
status = acpi_hw_validate_io_request(address, width);
@@ -279,6 +285,12 @@ acpi_status acpi_hw_write_port(acpi_io_address address, u32 value, u32 width)
acpi_status status;
u32 i;
+ /* Truncate address to 16 bits if requested */
+
+ if (acpi_gbl_truncate_io_addresses) {
+ address &= ACPI_UINT16_MAX;
+ }
+
/* Validate the entire request and perform the I/O */
status = acpi_hw_validate_io_request(address, width);
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index 3a2814676ac3..0cd925be5fc1 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -338,8 +338,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
*/
while (!acpi_ns_opens_scope(prefix_node->type) &&
prefix_node->type != ACPI_TYPE_ANY) {
- prefix_node =
- acpi_ns_get_parent_node(prefix_node);
+ prefix_node = prefix_node->parent;
}
}
}
@@ -419,7 +418,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
/* Backup to the parent node */
num_carats++;
- this_node = acpi_ns_get_parent_node(this_node);
+ this_node = this_node->parent;
if (!this_node) {
/* Current scope has no parent scope */
@@ -433,7 +432,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
if (search_parent_flag == ACPI_NS_NO_UPSEARCH) {
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Search scope is [%4.4s], path has %d carat(s)\n",
+ "Search scope is [%4.4s], path has %u carat(s)\n",
acpi_ut_get_node_name
(this_node), num_carats));
}
@@ -495,7 +494,7 @@ acpi_ns_lookup(union acpi_generic_state *scope_info,
path++;
ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
- "Multi Pathname (%d Segments, Flags=%X)\n",
+ "Multi Pathname (%u Segments, Flags=%X)\n",
num_segments, flags));
break;
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 982269c1fa48..1e5ff803d9ad 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -159,7 +159,7 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
ACPI_FUNCTION_TRACE_PTR(ns_remove_node, node);
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
prev_node = NULL;
next_node = parent_node->child;
@@ -168,29 +168,20 @@ void acpi_ns_remove_node(struct acpi_namespace_node *node)
while (next_node != node) {
prev_node = next_node;
- next_node = prev_node->peer;
+ next_node = next_node->peer;
}
if (prev_node) {
/* Node is not first child, unlink it */
- prev_node->peer = next_node->peer;
- if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
- prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
- }
+ prev_node->peer = node->peer;
} else {
- /* Node is first child (has no previous peer) */
-
- if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
-
- /* No peers at all */
-
- parent_node->child = NULL;
- } else { /* Link peer list to parent */
-
- parent_node->child = next_node->peer;
- }
+ /*
+ * Node is first child (has no previous peer).
+ * Link peer list to parent
+ */
+ parent_node->child = node->peer;
}
/* Delete the node and any attached objects */
@@ -228,33 +219,42 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
ACPI_FUNCTION_TRACE(ns_install_node);
- /*
- * Get the owner ID from the Walk state. The owner ID is used to track
- * table deletion and deletion of objects created by methods.
- */
if (walk_state) {
+ /*
+ * Get the owner ID from the Walk state. The owner ID is used to
+ * track table deletion and deletion of objects created by methods.
+ */
owner_id = walk_state->owner_id;
+
+ if ((walk_state->method_desc) &&
+ (parent_node != walk_state->method_node)) {
+ /*
+ * A method is creating a new node that is not a child of the
+ * method (it is non-local). Mark the executing method as having
+ * modified the namespace. This is used for cleanup when the
+ * method exits.
+ */
+ walk_state->method_desc->method.flags |=
+ AOPOBJ_MODIFIED_NAMESPACE;
+ }
}
/* Link the new entry into the parent and existing children */
+ node->peer = NULL;
+ node->parent = parent_node;
child_node = parent_node->child;
+
if (!child_node) {
parent_node->child = node;
- node->flags |= ANOBJ_END_OF_PEER_LIST;
- node->peer = parent_node;
} else {
- while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
+ /* Add node to the end of the peer list */
+
+ while (child_node->peer) {
child_node = child_node->peer;
}
child_node->peer = node;
-
- /* Clear end-of-list flag */
-
- child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
- node->flags |= ANOBJ_END_OF_PEER_LIST;
- node->peer = parent_node;
}
/* Init the new entry */
@@ -288,9 +288,8 @@ void acpi_ns_install_node(struct acpi_walk_state *walk_state, struct acpi_namesp
void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
{
- struct acpi_namespace_node *child_node;
struct acpi_namespace_node *next_node;
- u8 flags;
+ struct acpi_namespace_node *node_to_delete;
ACPI_FUNCTION_TRACE_PTR(ns_delete_children, parent_node);
@@ -298,37 +297,26 @@ void acpi_ns_delete_children(struct acpi_namespace_node *parent_node)
return_VOID;
}
- /* If no children, all done! */
-
- child_node = parent_node->child;
- if (!child_node) {
- return_VOID;
- }
-
/* Deallocate all children at this level */
- do {
-
- /* Get the things we need */
-
- next_node = child_node->peer;
- flags = child_node->flags;
+ next_node = parent_node->child;
+ while (next_node) {
/* Grandchildren should have all been deleted already */
- if (child_node->child) {
+ if (next_node->child) {
ACPI_ERROR((AE_INFO, "Found a grandchild! P=%p C=%p",
- parent_node, child_node));
+ parent_node, next_node));
}
/*
* Delete this child node and move on to the next child in the list.
* No need to unlink the node since we are deleting the entire branch.
*/
- acpi_ns_delete_node(child_node);
- child_node = next_node;
-
- } while (!(flags & ANOBJ_END_OF_PEER_LIST));
+ node_to_delete = next_node;
+ next_node = next_node->peer;
+ acpi_ns_delete_node(node_to_delete);
+ };
/* Clear the parent's child pointer */
@@ -405,7 +393,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
/* Move up the tree to the grandparent */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
}
@@ -510,7 +498,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
/* Move up the tree to the grandparent */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
}
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 2110cc2360f0..a54dc39e304b 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -441,7 +441,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
return (AE_OK);
}
- acpi_os_printf("(R%d)", obj_desc->common.reference_count);
+ acpi_os_printf("(R%u)", obj_desc->common.reference_count);
switch (type) {
case ACPI_TYPE_METHOD:
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index 9bd6f050f299..660a2728908d 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -103,8 +103,8 @@ acpi_status acpi_ns_initialize_objects(void)
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd "
- "Buffers %hd/%hd Packages (%hd nodes)\n",
+ "\nInitialized %u/%u Regions %u/%u Fields %u/%u "
+ "Buffers %u/%u Packages (%u nodes)\n",
info.op_region_init, info.op_region_count,
info.field_init, info.field_count,
info.buffer_init, info.buffer_count,
@@ -112,9 +112,9 @@ acpi_status acpi_ns_initialize_objects(void)
info.object_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Control Methods found\n", info.method_count));
+ "%u Control Methods found\n", info.method_count));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "%hd Op Regions found\n", info.op_region_count));
+ "%u Op Regions found\n", info.op_region_count));
return_ACPI_STATUS(AE_OK);
}
@@ -193,14 +193,23 @@ acpi_status acpi_ns_initialize_devices(void)
acpi_ns_init_one_device, NULL, &info,
NULL);
+ /*
+ * Any _OSI requests should be completed by now. If the BIOS has
+ * requested any Windows OSI strings, we will always truncate
+ * I/O addresses to 16 bits -- for Windows compatibility.
+ */
+ if (acpi_gbl_osi_data >= ACPI_OSI_WIN_2000) {
+ acpi_gbl_truncate_io_addresses = TRUE;
+ }
+
ACPI_FREE(info.evaluate_info);
if (ACPI_FAILURE(status)) {
goto error_exit;
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- "\nExecuted %hd _INI methods requiring %hd _STA executions "
- "(examined %hd objects)\n",
+ "\nExecuted %u _INI methods requiring %u _STA executions "
+ "(examined %u objects)\n",
info.num_INI, info.num_STA, info.device_count));
return_ACPI_STATUS(status);
@@ -401,7 +410,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
* The only _INI methods that we care about are those that are
* present under Device, Processor, and Thermal objects.
*/
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
switch (parent_node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
@@ -411,7 +420,7 @@ acpi_ns_find_ini_methods(acpi_handle obj_handle,
while (parent_node) {
parent_node->flags |= ANOBJ_SUBTREE_HAS_INI;
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
break;
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 7dea0031605c..d3104af57e13 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -93,7 +93,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node,
/* Put the name into the buffer */
ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name);
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
/* Prefix name with the path separator */
@@ -198,7 +198,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node)
return 0;
}
size += ACPI_PATH_SEGMENT_LENGTH;
- next_node = acpi_ns_get_parent_node(next_node);
+ next_node = next_node->parent;
}
if (!size) {
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index 27cda52c76bc..5808c89e9fac 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -136,8 +136,8 @@ acpi_ns_one_complete_parse(u32 pass_number,
/* Parse the AML */
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
- (unsigned)pass_number));
+ ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %u parse\n",
+ pass_number));
status = acpi_ps_parse_aml(walk_state);
cleanup:
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index 61bd0f6755d2..4009498fbabd 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -112,6 +112,13 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
* _PSS: Sort the list descending by Power
* _TSS: Sort the list descending by Power
+ *
+ * Names that must be packages, but cannot be sorted:
+ *
+ * _BCL: Values are tied to the Package index where they appear, and cannot
+ * be moved or sorted. These index values are used for _BQC and _BCM.
+ * However, we can fix the case where a buffer is returned, by converting
+ * it to a Package of integers.
*/
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
{"_ALR", acpi_ns_repair_ALR},
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index a8e42b5e9463..41102a84272f 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -152,17 +152,6 @@ acpi_ns_search_one_scope(u32 target_name,
return_ACPI_STATUS(AE_OK);
}
- /*
- * The last entry in the list points back to the parent,
- * so a flag is used to indicate the end-of-list
- */
- if (node->flags & ANOBJ_END_OF_PEER_LIST) {
-
- /* Searched entire list, we are done */
-
- break;
- }
-
/* Didn't match name, move on to the next peer object */
node = node->peer;
@@ -217,7 +206,7 @@ acpi_ns_search_parent_tree(u32 target_name,
ACPI_FUNCTION_TRACE(ns_search_parent_tree);
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
/*
* If there is no parent (i.e., we are at the root) or type is "local",
@@ -261,7 +250,7 @@ acpi_ns_search_parent_tree(u32 target_name,
/* Not found here, go up another level (until we reach the root) */
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
}
/* Not found in parent tree */
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index bab559712da1..e1add3491b04 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -847,116 +847,3 @@ acpi_ns_get_node(struct acpi_namespace_node *prefix_node,
ACPI_FREE(internal_path);
return_ACPI_STATUS(status);
}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_get_parent_node
- *
- * PARAMETERS: Node - Current table entry
- *
- * RETURN: Parent entry of the given entry
- *
- * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
- *
- ******************************************************************************/
-
-struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node
- *node)
-{
- ACPI_FUNCTION_ENTRY();
-
- if (!node) {
- return (NULL);
- }
-
- /*
- * Walk to the end of this peer list. The last entry is marked with a flag
- * and the peer pointer is really a pointer back to the parent. This saves
- * putting a parent back pointer in each and every named object!
- */
- while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
- node = node->peer;
- }
-
- return (node->peer);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_get_next_valid_node
- *
- * PARAMETERS: Node - Current table entry
- *
- * RETURN: Next valid Node in the linked node list. NULL if no more valid
- * nodes.
- *
- * DESCRIPTION: Find the next valid node within a name table.
- * Useful for implementing NULL-end-of-list loops.
- *
- ******************************************************************************/
-
-struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct
- acpi_namespace_node
- *node)
-{
-
- /* If we are at the end of this peer list, return NULL */
-
- if (node->flags & ANOBJ_END_OF_PEER_LIST) {
- return NULL;
- }
-
- /* Otherwise just return the next peer */
-
- return (node->peer);
-}
-
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_find_parent_name
- *
- * PARAMETERS: *child_node - Named Obj whose name is to be found
- *
- * RETURN: The ACPI name
- *
- * DESCRIPTION: Search for the given obj in its parent scope and return the
- * name segment, or "????" if the parent name can't be found
- * (which "should not happen").
- *
- ******************************************************************************/
-
-acpi_name acpi_ns_find_parent_name(struct acpi_namespace_node * child_node)
-{
- struct acpi_namespace_node *parent_node;
-
- ACPI_FUNCTION_TRACE(ns_find_parent_name);
-
- if (child_node) {
-
- /* Valid entry. Get the parent Node */
-
- parent_node = acpi_ns_get_parent_node(child_node);
- if (parent_node) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Parent of %p [%4.4s] is %p [%4.4s]\n",
- child_node,
- acpi_ut_get_node_name(child_node),
- parent_node,
- acpi_ut_get_node_name(parent_node)));
-
- if (parent_node->name.integer) {
- return_VALUE((acpi_name) parent_node->name.
- integer);
- }
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Unable to find parent of %p (%4.4s)\n",
- child_node,
- acpi_ut_get_node_name(child_node)));
- }
-
- return_VALUE(ACPI_UNKNOWN_NAME);
-}
-#endif
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 00e79fb26029..2cd5be8fe10f 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -79,15 +79,6 @@ struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node
return parent_node->child;
}
- /*
- * Get the next node.
- *
- * If we are at the end of this peer list, return NULL
- */
- if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
- return NULL;
- }
-
/* Otherwise just return the next peer */
return child_node->peer;
@@ -146,9 +137,9 @@ struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type,
return (next_node);
}
- /* Otherwise, move on to the next node */
+ /* Otherwise, move on to the next peer node */
- next_node = acpi_ns_get_next_valid_node(next_node);
+ next_node = next_node->peer;
}
/* Not found */
@@ -355,7 +346,7 @@ acpi_ns_walk_namespace(acpi_object_type type,
*/
level--;
child_node = parent_node;
- parent_node = acpi_ns_get_parent_node(parent_node);
+ parent_node = parent_node->parent;
node_previously_visited = TRUE;
}
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index eafef24ea448..a1f04e9b8030 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -190,7 +190,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
/* Get the parent entry */
- parent_node = acpi_ns_get_parent_node(node);
+ parent_node = node->parent;
*ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node);
/* Return exception if parent is null */
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 66116750a0f9..0558747579ef 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -813,10 +813,10 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
acpi_gbl_root_node_struct.descriptor_type = ACPI_DESC_TYPE_NAMED;
acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE;
+ acpi_gbl_root_node_struct.parent = NULL;
acpi_gbl_root_node_struct.child = NULL;
acpi_gbl_root_node_struct.peer = NULL;
acpi_gbl_root_node_struct.object = NULL;
- acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index db3946e9c66b..216e1e948ff6 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/slab.h>
#include <linux/io.h>
#include <linux/kref.h>
#include <linux/rculist.h>
diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c
index 814b19249616..8f8bd736d4ff 100644
--- a/drivers/acpi/atomicio.c
+++ b/drivers/acpi/atomicio.c
@@ -31,6 +31,7 @@
#include <linux/kref.h>
#include <linux/rculist.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include <acpi/atomicio.h>
#define ACPI_PFX "ACPI: "
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 146135e7a6a1..295dbfa2db9c 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -96,7 +96,8 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
/* --------------------------------------------------------------------------
FS Interface (/sys)
-------------------------------------------------------------------------- */
-static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+static int param_get_debug_layer(char *buffer, const struct kernel_param *kp)
+{
int result = 0;
int i;
@@ -118,7 +119,8 @@ static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
return result;
}
-static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+static int param_get_debug_level(char *buffer, const struct kernel_param *kp)
+{
int result = 0;
int i;
@@ -137,8 +139,18 @@ static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
return result;
}
-module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
-module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+static struct kernel_param_ops acpi_debug_layer_ops = {
+ .set = param_set_uint,
+ .get = param_get_debug_layer,
+};
+
+static struct kernel_param_ops acpi_debug_level_ops = {
+ .set = param_set_uint,
+ .get = param_get_debug_level,
+};
+
+module_param_cb(debug_layer, &acpi_debug_layer_ops, &acpi_dbg_layer, 0644);
+module_param_cb(debug_level, &acpi_debug_level_ops, &acpi_dbg_level, 0644);
static char trace_method_name[6];
module_param_string(trace_method_name, trace_method_name, 6, 0644);
@@ -147,7 +159,7 @@ module_param(trace_debug_layer, uint, 0644);
static unsigned int trace_debug_level;
module_param(trace_debug_level, uint, 0644);
-static int param_set_trace_state(const char *val, struct kernel_param *kp)
+static int param_set_trace_state(const char *val, const struct kernel_param *kp)
{
int result = 0;
@@ -181,7 +193,7 @@ exit:
return result;
}
-static int param_get_trace_state(char *buffer, struct kernel_param *kp)
+static int param_get_trace_state(char *buffer, const struct kernel_param *kp)
{
if (!acpi_gbl_trace_method_name)
return sprintf(buffer, "disable");
@@ -194,8 +206,12 @@ static int param_get_trace_state(char *buffer, struct kernel_param *kp)
return 0;
}
-module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
- NULL, 0644);
+static struct kernel_param_ops param_ops_trace_state = {
+ .set = param_set_trace_state,
+ .get = param_get_trace_state,
+};
+
+module_param_cb(trace_state, &param_ops_trace_state, NULL, 0644);
/* --------------------------------------------------------------------------
DebugFS Interface
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e61d4f8e62a5..5f2027d782e8 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -79,7 +79,7 @@ enum {
EC_FLAGS_GPE_STORM, /* GPE storm detected */
EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
* OpReg are installed */
- EC_FLAGS_FROZEN, /* Transactions are suspended */
+ EC_FLAGS_BLOCKED, /* Transactions are blocked */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -293,7 +293,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
if (t->rdata)
memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->lock);
- if (test_bit(EC_FLAGS_FROZEN, &ec->flags)) {
+ if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
status = -EINVAL;
goto unlock;
}
@@ -459,7 +459,7 @@ int ec_transaction(u8 command,
EXPORT_SYMBOL(ec_transaction);
-void acpi_ec_suspend_transactions(void)
+void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -468,11 +468,11 @@ void acpi_ec_suspend_transactions(void)
mutex_lock(&ec->lock);
/* Prevent transactions from being carried out */
- set_bit(EC_FLAGS_FROZEN, &ec->flags);
+ set_bit(EC_FLAGS_BLOCKED, &ec->flags);
mutex_unlock(&ec->lock);
}
-void acpi_ec_resume_transactions(void)
+void acpi_ec_unblock_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -481,10 +481,20 @@ void acpi_ec_resume_transactions(void)
mutex_lock(&ec->lock);
/* Allow transactions to be carried out again */
- clear_bit(EC_FLAGS_FROZEN, &ec->flags);
+ clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
mutex_unlock(&ec->lock);
}
+void acpi_ec_unblock_transactions_early(void)
+{
+ /*
+ * Allow transactions to happen again (this function is called from
+ * atomic context during wakeup, so we don't need to acquire the mutex).
+ */
+ if (first_ec)
+ clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+}
+
static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 * data)
{
int result;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index e28411367239..f8f190ec066e 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -49,8 +49,9 @@ void acpi_early_processor_set_pdc(void);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
-void acpi_ec_suspend_transactions(void);
-void acpi_ec_resume_transactions(void);
+void acpi_ec_block_transactions(void);
+void acpi_ec_unblock_transactions(void);
+void acpi_ec_unblock_transactions_early(void);
/*--------------------------------------------------------------------------
Suspend/Resume
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 2e8c27d48f2b..b1b385692f46 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -80,7 +80,7 @@ module_param(nocst, uint, 0000);
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
-static s64 us_to_pm_timer_ticks(s64 t)
+static u64 us_to_pm_timer_ticks(s64 t)
{
return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
}
@@ -731,10 +731,10 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_puts(seq, "demotion[--] ");
- seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
+ seq_printf(seq, "latency[%03d] usage[%08d] duration[%020Lu]\n",
pr->power.states[i].latency,
pr->power.states[i].usage,
- (unsigned long long)pr->power.states[i].time);
+ us_to_pm_timer_ticks(pr->power.states[i].time));
}
end:
@@ -861,7 +861,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
ktime_t kt1, kt2;
s64 idle_time_ns;
s64 idle_time;
- s64 sleep_ticks = 0;
pr = __get_cpu_var(processors);
@@ -906,8 +905,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
idle_time = idle_time_ns;
do_div(idle_time, NSEC_PER_USEC);
- sleep_ticks = us_to_pm_timer_ticks(idle_time);
-
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(idle_time_ns);
@@ -918,7 +915,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
cx->usage++;
lapic_timer_state_broadcast(pr, cx, 0);
- cx->time += sleep_ticks;
+ cx->time += idle_time;
return idle_time;
}
@@ -940,7 +937,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
ktime_t kt1, kt2;
s64 idle_time_ns;
s64 idle_time;
- s64 sleep_ticks = 0;
pr = __get_cpu_var(processors);
@@ -1022,11 +1018,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
spin_unlock(&c3_lock);
}
kt2 = ktime_get_real();
- idle_time_ns = ktime_to_us(ktime_sub(kt2, kt1));
+ idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
idle_time = idle_time_ns;
do_div(idle_time, NSEC_PER_USEC);
- sleep_ticks = us_to_pm_timer_ticks(idle_time);
/* Tell the scheduler how much we idled: */
sched_clock_idle_wakeup_event(idle_time_ns);
@@ -1037,7 +1032,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
cx->usage++;
lapic_timer_state_broadcast(pr, cx, 0);
- cx->time += sleep_ticks;
+ cx->time += idle_time;
return idle_time;
}
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 4ab2275b4461..da7386d05fed 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -94,11 +94,13 @@ void __init acpi_old_suspend_ordering(void)
}
/**
- * acpi_pm_disable_gpes - Disable the GPEs.
+ * acpi_pm_freeze - Disable the GPEs and suspend EC transactions.
*/
-static int acpi_pm_disable_gpes(void)
+static int acpi_pm_freeze(void)
{
acpi_disable_all_gpes();
+ acpi_os_wait_events_complete(NULL);
+ acpi_ec_block_transactions();
return 0;
}
@@ -112,6 +114,8 @@ static int __acpi_pm_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
+ suspend_nvs_save();
+
if (error)
acpi_target_sleep_state = ACPI_STATE_S0;
return error;
@@ -126,7 +130,8 @@ static int acpi_pm_prepare(void)
int error = __acpi_pm_prepare();
if (!error)
- acpi_disable_all_gpes();
+ acpi_pm_freeze();
+
return error;
}
@@ -140,6 +145,9 @@ static void acpi_pm_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
+ suspend_nvs_free();
+ acpi_ec_unblock_transactions();
+
if (acpi_state == ACPI_STATE_S0)
return;
@@ -189,6 +197,11 @@ static int acpi_suspend_begin(suspend_state_t pm_state)
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
+ error = suspend_nvs_alloc();
+
+ if (error)
+ return error;
+
if (sleep_states[acpi_state]) {
acpi_target_sleep_state = acpi_state;
acpi_sleep_tts_switch(acpi_target_sleep_state);
@@ -256,6 +269,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
* acpi_leave_sleep_state will reenable specific GPEs later
*/
acpi_disable_all_gpes();
+ /* Allow EC transactions to happen. */
+ acpi_ec_unblock_transactions_early();
local_irq_restore(flags);
printk(KERN_DEBUG "Back to C!\n");
@@ -264,9 +279,16 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
if (acpi_state == ACPI_STATE_S3)
acpi_restore_state_mem();
+ suspend_nvs_restore();
+
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
+static void acpi_suspend_finish(void)
+{
+ acpi_pm_finish();
+}
+
static int acpi_suspend_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -288,7 +310,7 @@ static struct platform_suspend_ops acpi_suspend_ops = {
.begin = acpi_suspend_begin,
.prepare_late = acpi_pm_prepare,
.enter = acpi_suspend_enter,
- .wake = acpi_pm_finish,
+ .wake = acpi_suspend_finish,
.end = acpi_pm_end,
};
@@ -314,9 +336,9 @@ static int acpi_suspend_begin_old(suspend_state_t pm_state)
static struct platform_suspend_ops acpi_suspend_ops_old = {
.valid = acpi_suspend_state_valid,
.begin = acpi_suspend_begin_old,
- .prepare_late = acpi_pm_disable_gpes,
+ .prepare_late = acpi_pm_freeze,
.enter = acpi_suspend_enter,
- .wake = acpi_pm_finish,
+ .wake = acpi_suspend_finish,
.end = acpi_pm_end,
.recover = acpi_pm_finish,
};
@@ -393,7 +415,7 @@ static int acpi_hibernation_begin(void)
{
int error;
- error = s4_no_nvs ? 0 : hibernate_nvs_alloc();
+ error = s4_no_nvs ? 0 : suspend_nvs_alloc();
if (!error) {
acpi_target_sleep_state = ACPI_STATE_S4;
acpi_sleep_tts_switch(acpi_target_sleep_state);
@@ -407,7 +429,7 @@ static int acpi_hibernation_pre_snapshot(void)
int error = acpi_pm_prepare();
if (!error)
- hibernate_nvs_save();
+ suspend_nvs_save();
return error;
}
@@ -430,12 +452,6 @@ static int acpi_hibernation_enter(void)
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
-static void acpi_hibernation_finish(void)
-{
- hibernate_nvs_free();
- acpi_pm_finish();
-}
-
static void acpi_hibernation_leave(void)
{
/*
@@ -452,20 +468,14 @@ static void acpi_hibernation_leave(void)
panic("ACPI S4 hardware signature mismatch");
}
/* Restore the NVS memory area */
- hibernate_nvs_restore();
+ suspend_nvs_restore();
+ /* Allow EC transactions to happen. */
+ acpi_ec_unblock_transactions_early();
}
-static int acpi_pm_pre_restore(void)
+static void acpi_pm_thaw(void)
{
- acpi_disable_all_gpes();
- acpi_os_wait_events_complete(NULL);
- acpi_ec_suspend_transactions();
- return 0;
-}
-
-static void acpi_pm_restore_cleanup(void)
-{
- acpi_ec_resume_transactions();
+ acpi_ec_unblock_transactions();
acpi_enable_all_runtime_gpes();
}
@@ -473,12 +483,12 @@ static struct platform_hibernation_ops acpi_hibernation_ops = {
.begin = acpi_hibernation_begin,
.end = acpi_pm_end,
.pre_snapshot = acpi_hibernation_pre_snapshot,
- .finish = acpi_hibernation_finish,
+ .finish = acpi_pm_finish,
.prepare = acpi_pm_prepare,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_pre_restore,
- .restore_cleanup = acpi_pm_restore_cleanup,
+ .pre_restore = acpi_pm_freeze,
+ .restore_cleanup = acpi_pm_thaw,
};
/**
@@ -501,7 +511,7 @@ static int acpi_hibernation_begin_old(void)
if (!error) {
if (!s4_no_nvs)
- error = hibernate_nvs_alloc();
+ error = suspend_nvs_alloc();
if (!error)
acpi_target_sleep_state = ACPI_STATE_S4;
}
@@ -510,12 +520,9 @@ static int acpi_hibernation_begin_old(void)
static int acpi_hibernation_pre_snapshot_old(void)
{
- int error = acpi_pm_disable_gpes();
-
- if (!error)
- hibernate_nvs_save();
-
- return error;
+ acpi_pm_freeze();
+ suspend_nvs_save();
+ return 0;
}
/*
@@ -526,12 +533,12 @@ static struct platform_hibernation_ops acpi_hibernation_ops_old = {
.begin = acpi_hibernation_begin_old,
.end = acpi_pm_end,
.pre_snapshot = acpi_hibernation_pre_snapshot_old,
- .finish = acpi_hibernation_finish,
- .prepare = acpi_pm_disable_gpes,
+ .finish = acpi_pm_finish,
+ .prepare = acpi_pm_freeze,
.enter = acpi_hibernation_enter,
.leave = acpi_hibernation_leave,
- .pre_restore = acpi_pm_pre_restore,
- .restore_cleanup = acpi_pm_restore_cleanup,
+ .pre_restore = acpi_pm_freeze,
+ .restore_cleanup = acpi_pm_thaw,
.recover = acpi_pm_finish,
};
#endif /* CONFIG_HIBERNATION */
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 73f883333a0d..aa85a98d3a4f 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -168,10 +168,10 @@ config ATA_BMDMA
default y
help
This option adds support for SFF ATA controllers with BMDMA
- capability. BMDMA stands for bus-master DMA and the
- de-facto DMA interface for SFF controllers.
+ capability. BMDMA stands for bus-master DMA and is the
+ de facto DMA interface for SFF controllers.
- If unuser, say Y.
+ If unsure, say Y.
if ATA_BMDMA
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 1984a6e89e84..261f86d102e8 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -541,29 +541,11 @@ static int ahci_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
return -EINVAL;
}
-static int ahci_is_device_present(void __iomem *port_mmio)
-{
- u8 status = readl(port_mmio + PORT_TFDATA) & 0xff;
-
- /* Make sure PxTFD.STS.BSY and PxTFD.STS.DRQ are 0 */
- if (status & (ATA_BUSY | ATA_DRQ))
- return 0;
-
- /* Make sure PxSSTS.DET is 3h */
- status = readl(port_mmio + PORT_SCR_STAT) & 0xf;
- if (status != 3)
- return 0;
- return 1;
-}
-
void ahci_start_engine(struct ata_port *ap)
{
void __iomem *port_mmio = ahci_port_base(ap);
u32 tmp;
- if (!ahci_is_device_present(port_mmio))
- return;
-
/* start DMA */
tmp = readl(port_mmio + PORT_CMD);
tmp |= PORT_CMD_START;
@@ -1892,6 +1874,9 @@ static void ahci_error_handler(struct ata_port *ap)
}
sata_pmp_error_handler(ap);
+
+ if (!ata_dev_enabled(ap->link.device))
+ ahci_stop_engine(ap);
}
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 06b7e49e039c..ddf8e4862787 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -4119,9 +4119,8 @@ int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
dev->n_sectors > n_sectors && dev->n_sectors == n_native_sectors) {
ata_dev_printk(dev, KERN_WARNING,
"new n_sectors matches native, probably "
- "late HPA unlock, continuing\n");
- /* keep using the old n_sectors */
- dev->n_sectors = n_sectors;
+ "late HPA unlock, n_sectors updated\n");
+ /* use the larger n_sectors */
return 0;
}
@@ -6669,6 +6668,7 @@ EXPORT_SYMBOL_GPL(ata_dummy_port_info);
EXPORT_SYMBOL_GPL(ata_link_next);
EXPORT_SYMBOL_GPL(ata_dev_next);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
+EXPORT_SYMBOL_GPL(ata_scsi_unlock_native_capacity);
EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_host_alloc);
EXPORT_SYMBOL_GPL(ata_host_alloc_pinfo);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index cfa9dd3d7253..a54273d2c3c6 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -415,6 +415,35 @@ int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
}
/**
+ * ata_scsi_unlock_native_capacity - unlock native capacity
+ * @sdev: SCSI device to adjust device capacity for
+ *
+ * This function is called if a partition on @sdev extends beyond
+ * the end of the device. It requests EH to unlock HPA.
+ *
+ * LOCKING:
+ * Defined by the SCSI layer. Might sleep.
+ */
+void ata_scsi_unlock_native_capacity(struct scsi_device *sdev)
+{
+ struct ata_port *ap = ata_shost_to_port(sdev->host);
+ struct ata_device *dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ dev = ata_scsi_find_dev(ap, sdev);
+ if (dev && dev->n_sectors < dev->n_native_sectors) {
+ dev->flags |= ATA_DFLAG_UNLOCK_HPA;
+ dev->link->eh_info.action |= ATA_EH_RESET;
+ ata_port_schedule_eh(ap);
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+}
+
+/**
* ata_get_identity - Handler for HDIO_GET_IDENTITY ioctl
* @ap: target port
* @sdev: SCSI device to get identify data for
diff --git a/drivers/ata/pata_macio.c b/drivers/ata/pata_macio.c
index 76640ac76888..75b49d01780b 100644
--- a/drivers/ata/pata_macio.c
+++ b/drivers/ata/pata_macio.c
@@ -1355,8 +1355,11 @@ static struct of_device_id pata_macio_match[] =
static struct macio_driver pata_macio_driver =
{
- .name = "pata-macio",
- .match_table = pata_macio_match,
+ .driver = {
+ .name = "pata-macio",
+ .owner = THIS_MODULE,
+ .of_match_table = pata_macio_match,
+ },
.probe = pata_macio_attach,
.remove = pata_macio_detach,
#ifdef CONFIG_PM
@@ -1366,9 +1369,6 @@ static struct macio_driver pata_macio_driver =
#ifdef CONFIG_PMAC_MEDIABAY
.mediabay_event = pata_macio_mb_event,
#endif
- .driver = {
- .owner = THIS_MODULE,
- },
};
static const struct pci_device_id pata_macio_pci_match[] = {
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 6fd114784116..21161136cad0 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1669,7 +1669,6 @@ static void nv_mcp55_freeze(struct ata_port *ap)
mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
mask &= ~(NV_INT_ALL_MCP55 << shift);
writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
- ata_sff_freeze(ap);
}
static void nv_mcp55_thaw(struct ata_port *ap)
@@ -1683,7 +1682,6 @@ static void nv_mcp55_thaw(struct ata_port *ap)
mask = readl(mmio_base + NV_INT_ENABLE_MCP55);
mask |= (NV_INT_MASK_MCP55 << shift);
writel(mask, mmio_base + NV_INT_ENABLE_MCP55);
- ata_sff_thaw(ap);
}
static void nv_adma_error_handler(struct ata_port *ap)
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index e9250514734b..70b58fe9e5b1 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -539,12 +539,12 @@ static void sil24_config_port(struct ata_port *ap)
writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
/* zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
+ writew(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writew(0x8000, port + PORT_CRC_ERR_THRESH);
+ writew(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writew(0x0000, port + PORT_DECODE_ERR_CNT);
+ writew(0x0000, port + PORT_CRC_ERR_CNT);
+ writew(0x0000, port + PORT_HSHK_ERR_CNT);
/* always use 64bit activation */
writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index 101d8c219caf..4730c42a5ee5 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -575,6 +575,33 @@ static void svia_configure(struct pci_dev *pdev)
tmp8 |= NATIVE_MODE_ALL;
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
}
+
+ /*
+ * vt6421 has problems talking to some drives. The following
+ * is the fix from Joseph Chan <JosephChan@via.com.tw>.
+ *
+ * When host issues HOLD, device may send up to 20DW of data
+ * before acknowledging it with HOLDA and the host should be
+ * able to buffer them in FIFO. Unfortunately, some WD drives
+ * send upto 40DW before acknowledging HOLD and, in the
+ * default configuration, this ends up overflowing vt6421's
+ * FIFO, making the controller abort the transaction with
+ * R_ERR.
+ *
+ * Rx52[2] is the internal 128DW FIFO Flow control watermark
+ * adjusting mechanism enable bit and the default value 0
+ * means host will issue HOLD to device when the left FIFO
+ * size goes below 32DW. Setting it to 1 makes the watermark
+ * 64DW.
+ *
+ * https://bugzilla.kernel.org/show_bug.cgi?id=15173
+ * http://article.gmane.org/gmane.linux.ide/46352
+ */
+ if (pdev->device == 0x3249) {
+ pci_read_config_byte(pdev, 0x52, &tmp8);
+ tmp8 |= 1 << 2;
+ pci_write_config_byte(pdev, 0x52, tmp8);
+ }
}
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index f1a0a00b3b07..be7461c9a87e 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -177,7 +177,7 @@ config ATM_ZATM_DEBUG
config ATM_NICSTAR
tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
- depends on PCI && !64BIT && VIRT_TO_BUS
+ depends on PCI
help
The NICStAR chipset family is used in a large number of ATM NICs for
25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index 56c2e99e458f..ea9cbe596a28 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -67,6 +67,7 @@
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/bitmap.h>
#include <linux/slab.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -778,61 +779,39 @@ he_init_cs_block_rcm(struct he_dev *he_dev)
static int __devinit
he_init_group(struct he_dev *he_dev, int group)
{
+ struct he_buff *heb, *next;
+ dma_addr_t mapping;
int i;
- /* small buffer pool */
- he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
- CONFIG_RBPS_BUFSIZE, 8, 0);
- if (he_dev->rbps_pool == NULL) {
- hprintk("unable to create rbps pages\n");
+ he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
+ he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
+ he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
+ he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+ G0_RBPS_BS + (group * 32));
+
+ /* bitmap table */
+ he_dev->rbpl_table = kmalloc(BITS_TO_LONGS(RBPL_TABLE_SIZE)
+ * sizeof(unsigned long), GFP_KERNEL);
+ if (!he_dev->rbpl_table) {
+ hprintk("unable to allocate rbpl bitmap table\n");
return -ENOMEM;
}
+ bitmap_zero(he_dev->rbpl_table, RBPL_TABLE_SIZE);
- he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
- CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
- if (he_dev->rbps_base == NULL) {
- hprintk("failed to alloc rbps_base\n");
- goto out_destroy_rbps_pool;
+ /* rbpl_virt 64-bit pointers */
+ he_dev->rbpl_virt = kmalloc(RBPL_TABLE_SIZE
+ * sizeof(struct he_buff *), GFP_KERNEL);
+ if (!he_dev->rbpl_virt) {
+ hprintk("unable to allocate rbpl virt table\n");
+ goto out_free_rbpl_table;
}
- memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
- he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
- if (he_dev->rbps_virt == NULL) {
- hprintk("failed to alloc rbps_virt\n");
- goto out_free_rbps_base;
- }
-
- for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
- dma_addr_t dma_handle;
- void *cpuaddr;
-
- cpuaddr = pci_pool_alloc(he_dev->rbps_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
- if (cpuaddr == NULL)
- goto out_free_rbps_virt;
-
- he_dev->rbps_virt[i].virt = cpuaddr;
- he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
- he_dev->rbps_base[i].phys = dma_handle;
-
- }
- he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1];
-
- he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32));
- he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail),
- G0_RBPS_T + (group * 32));
- he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4,
- G0_RBPS_BS + (group * 32));
- he_writel(he_dev,
- RBP_THRESH(CONFIG_RBPS_THRESH) |
- RBP_QSIZE(CONFIG_RBPS_SIZE - 1) |
- RBP_INT_ENB,
- G0_RBPS_QI + (group * 32));
/* large buffer pool */
he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
- CONFIG_RBPL_BUFSIZE, 8, 0);
+ CONFIG_RBPL_BUFSIZE, 64, 0);
if (he_dev->rbpl_pool == NULL) {
hprintk("unable to create rbpl pool\n");
- goto out_free_rbps_virt;
+ goto out_free_rbpl_virt;
}
he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
@@ -842,30 +821,29 @@ he_init_group(struct he_dev *he_dev, int group)
goto out_destroy_rbpl_pool;
}
memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
- he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
- if (he_dev->rbpl_virt == NULL) {
- hprintk("failed to alloc rbpl_virt\n");
- goto out_free_rbpl_base;
- }
+
+ INIT_LIST_HEAD(&he_dev->rbpl_outstanding);
for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
- dma_addr_t dma_handle;
- void *cpuaddr;
- cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &dma_handle);
- if (cpuaddr == NULL)
- goto out_free_rbpl_virt;
+ heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping);
+ if (!heb)
+ goto out_free_rbpl;
+ heb->mapping = mapping;
+ list_add(&heb->entry, &he_dev->rbpl_outstanding);
- he_dev->rbpl_virt[i].virt = cpuaddr;
- he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
- he_dev->rbpl_base[i].phys = dma_handle;
+ set_bit(i, he_dev->rbpl_table);
+ he_dev->rbpl_virt[i] = heb;
+ he_dev->rbpl_hint = i + 1;
+ he_dev->rbpl_base[i].idx = i << RBP_IDX_OFFSET;
+ he_dev->rbpl_base[i].phys = mapping + offsetof(struct he_buff, data);
}
he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1];
he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32));
he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail),
G0_RBPL_T + (group * 32));
- he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4,
+ he_writel(he_dev, (CONFIG_RBPL_BUFSIZE - sizeof(struct he_buff))/4,
G0_RBPL_BS + (group * 32));
he_writel(he_dev,
RBP_THRESH(CONFIG_RBPL_THRESH) |
@@ -879,7 +857,7 @@ he_init_group(struct he_dev *he_dev, int group)
CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
if (he_dev->rbrq_base == NULL) {
hprintk("failed to allocate rbrq\n");
- goto out_free_rbpl_virt;
+ goto out_free_rbpl;
}
memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
@@ -920,33 +898,20 @@ out_free_rbpq_base:
pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE *
sizeof(struct he_rbrq), he_dev->rbrq_base,
he_dev->rbrq_phys);
- i = CONFIG_RBPL_SIZE;
-out_free_rbpl_virt:
- while (i--)
- pci_pool_free(he_dev->rbpl_pool, he_dev->rbpl_virt[i].virt,
- he_dev->rbpl_base[i].phys);
- kfree(he_dev->rbpl_virt);
+out_free_rbpl:
+ list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
-out_free_rbpl_base:
pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE *
sizeof(struct he_rbp), he_dev->rbpl_base,
he_dev->rbpl_phys);
out_destroy_rbpl_pool:
pci_pool_destroy(he_dev->rbpl_pool);
+out_free_rbpl_virt:
+ kfree(he_dev->rbpl_virt);
+out_free_rbpl_table:
+ kfree(he_dev->rbpl_table);
- i = CONFIG_RBPS_SIZE;
-out_free_rbps_virt:
- while (i--)
- pci_pool_free(he_dev->rbps_pool, he_dev->rbps_virt[i].virt,
- he_dev->rbps_base[i].phys);
- kfree(he_dev->rbps_virt);
-
-out_free_rbps_base:
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE *
- sizeof(struct he_rbp), he_dev->rbps_base,
- he_dev->rbps_phys);
-out_destroy_rbps_pool:
- pci_pool_destroy(he_dev->rbps_pool);
return -ENOMEM;
}
@@ -1576,9 +1541,10 @@ he_start(struct atm_dev *dev)
static void
he_stop(struct he_dev *he_dev)
{
- u16 command;
- u32 gen_cntl_0, reg;
+ struct he_buff *heb, *next;
struct pci_dev *pci_dev;
+ u32 gen_cntl_0, reg;
+ u16 command;
pci_dev = he_dev->pci_dev;
@@ -1619,37 +1585,19 @@ he_stop(struct he_dev *he_dev)
he_dev->hsp, he_dev->hsp_phys);
if (he_dev->rbpl_base) {
- int i;
-
- for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
- void *cpuaddr = he_dev->rbpl_virt[i].virt;
- dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
+ list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
- pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle);
- }
pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
* sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
}
+ kfree(he_dev->rbpl_virt);
+ kfree(he_dev->rbpl_table);
+
if (he_dev->rbpl_pool)
pci_pool_destroy(he_dev->rbpl_pool);
- if (he_dev->rbps_base) {
- int i;
-
- for (i = 0; i < CONFIG_RBPS_SIZE; ++i) {
- void *cpuaddr = he_dev->rbps_virt[i].virt;
- dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
-
- pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle);
- }
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
- * sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys);
- }
-
- if (he_dev->rbps_pool)
- pci_pool_destroy(he_dev->rbps_pool);
-
if (he_dev->rbrq_base)
pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
he_dev->rbrq_base, he_dev->rbrq_phys);
@@ -1679,13 +1627,13 @@ static struct he_tpd *
__alloc_tpd(struct he_dev *he_dev)
{
struct he_tpd *tpd;
- dma_addr_t dma_handle;
+ dma_addr_t mapping;
- tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &dma_handle);
+ tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping);
if (tpd == NULL)
return NULL;
- tpd->status = TPD_ADDR(dma_handle);
+ tpd->status = TPD_ADDR(mapping);
tpd->reserved = 0;
tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0;
tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0;
@@ -1714,13 +1662,12 @@ he_service_rbrq(struct he_dev *he_dev, int group)
struct he_rbrq *rbrq_tail = (struct he_rbrq *)
((unsigned long)he_dev->rbrq_base |
he_dev->hsp->group[group].rbrq_tail);
- struct he_rbp *rbp = NULL;
unsigned cid, lastcid = -1;
- unsigned buf_len = 0;
struct sk_buff *skb;
struct atm_vcc *vcc = NULL;
struct he_vcc *he_vcc;
- struct he_iovec *iov;
+ struct he_buff *heb, *next;
+ int i;
int pdus_assembled = 0;
int updated = 0;
@@ -1740,44 +1687,35 @@ he_service_rbrq(struct he_dev *he_dev, int group)
RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "",
RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : "");
- if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF)
- rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
- else
- rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
-
- buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
- cid = RBRQ_CID(he_dev->rbrq_head);
+ i = RBRQ_ADDR(he_dev->rbrq_head) >> RBP_IDX_OFFSET;
+ heb = he_dev->rbpl_virt[i];
+ cid = RBRQ_CID(he_dev->rbrq_head);
if (cid != lastcid)
vcc = __find_vcc(he_dev, cid);
lastcid = cid;
- if (vcc == NULL) {
- hprintk("vcc == NULL (cid 0x%x)\n", cid);
- if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
- rbp->status &= ~RBP_LOANED;
+ if (vcc == NULL || (he_vcc = HE_VCC(vcc)) == NULL) {
+ hprintk("vcc/he_vcc == NULL (cid 0x%x)\n", cid);
+ if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
+ clear_bit(i, he_dev->rbpl_table);
+ list_del(&heb->entry);
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ }
goto next_rbrq_entry;
}
- he_vcc = HE_VCC(vcc);
- if (he_vcc == NULL) {
- hprintk("he_vcc == NULL (cid 0x%x)\n", cid);
- if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
- rbp->status &= ~RBP_LOANED;
- goto next_rbrq_entry;
- }
-
if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
hprintk("HBUF_ERR! (cid 0x%x)\n", cid);
atomic_inc(&vcc->stats->rx_drop);
goto return_host_buffers;
}
- he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head);
- he_vcc->iov_tail->iov_len = buf_len;
- he_vcc->pdu_len += buf_len;
- ++he_vcc->iov_tail;
+ heb->len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
+ clear_bit(i, he_dev->rbpl_table);
+ list_move_tail(&heb->entry, &he_vcc->buffers);
+ he_vcc->pdu_len += heb->len;
if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) {
lastcid = -1;
@@ -1786,12 +1724,6 @@ he_service_rbrq(struct he_dev *he_dev, int group)
goto return_host_buffers;
}
-#ifdef notdef
- if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) {
- hprintk("iovec full! cid 0x%x\n", cid);
- goto return_host_buffers;
- }
-#endif
if (!RBRQ_END_PDU(he_dev->rbrq_head))
goto next_rbrq_entry;
@@ -1819,15 +1751,8 @@ he_service_rbrq(struct he_dev *he_dev, int group)
__net_timestamp(skb);
- for (iov = he_vcc->iov_head;
- iov < he_vcc->iov_tail; ++iov) {
- if (iov->iov_base & RBP_SMALLBUF)
- memcpy(skb_put(skb, iov->iov_len),
- he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
- else
- memcpy(skb_put(skb, iov->iov_len),
- he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
- }
+ list_for_each_entry(heb, &he_vcc->buffers, entry)
+ memcpy(skb_put(skb, heb->len), &heb->data, heb->len);
switch (vcc->qos.aal) {
case ATM_AAL0:
@@ -1867,17 +1792,9 @@ he_service_rbrq(struct he_dev *he_dev, int group)
return_host_buffers:
++pdus_assembled;
- for (iov = he_vcc->iov_head;
- iov < he_vcc->iov_tail; ++iov) {
- if (iov->iov_base & RBP_SMALLBUF)
- rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)];
- else
- rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)];
-
- rbp->status &= ~RBP_LOANED;
- }
-
- he_vcc->iov_tail = he_vcc->iov_head;
+ list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry)
+ pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ INIT_LIST_HEAD(&he_vcc->buffers);
he_vcc->pdu_len = 0;
next_rbrq_entry:
@@ -1978,59 +1895,51 @@ next_tbrq_entry:
}
}
-
static void
he_service_rbpl(struct he_dev *he_dev, int group)
{
- struct he_rbp *newtail;
+ struct he_rbp *new_tail;
struct he_rbp *rbpl_head;
+ struct he_buff *heb;
+ dma_addr_t mapping;
+ int i;
int moved = 0;
rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
for (;;) {
- newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
+ new_tail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
RBPL_MASK(he_dev->rbpl_tail+1));
/* table 3.42 -- rbpl_tail should never be set to rbpl_head */
- if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED))
+ if (new_tail == rbpl_head)
break;
- newtail->status |= RBP_LOANED;
- he_dev->rbpl_tail = newtail;
- ++moved;
- }
-
- if (moved)
- he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
-}
-
-static void
-he_service_rbps(struct he_dev *he_dev, int group)
-{
- struct he_rbp *newtail;
- struct he_rbp *rbps_head;
- int moved = 0;
-
- rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
- RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
-
- for (;;) {
- newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
- RBPS_MASK(he_dev->rbps_tail+1));
+ i = find_next_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE, he_dev->rbpl_hint);
+ if (i > (RBPL_TABLE_SIZE - 1)) {
+ i = find_first_zero_bit(he_dev->rbpl_table, RBPL_TABLE_SIZE);
+ if (i > (RBPL_TABLE_SIZE - 1))
+ break;
+ }
+ he_dev->rbpl_hint = i + 1;
- /* table 3.42 -- rbps_tail should never be set to rbps_head */
- if ((newtail == rbps_head) || (newtail->status & RBP_LOANED))
+ heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping);
+ if (!heb)
break;
-
- newtail->status |= RBP_LOANED;
- he_dev->rbps_tail = newtail;
+ heb->mapping = mapping;
+ list_add(&heb->entry, &he_dev->rbpl_outstanding);
+ he_dev->rbpl_virt[i] = heb;
+ set_bit(i, he_dev->rbpl_table);
+ new_tail->idx = i << RBP_IDX_OFFSET;
+ new_tail->phys = mapping + offsetof(struct he_buff, data);
+
+ he_dev->rbpl_tail = new_tail;
++moved;
}
if (moved)
- he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T);
+ he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
}
static void
@@ -2055,10 +1964,8 @@ he_tasklet(unsigned long data)
HPRINTK("rbrq%d threshold\n", group);
/* fall through */
case ITYPE_RBRQ_TIMER:
- if (he_service_rbrq(he_dev, group)) {
+ if (he_service_rbrq(he_dev, group))
he_service_rbpl(he_dev, group);
- he_service_rbps(he_dev, group);
- }
break;
case ITYPE_TBRQ_THRESH:
HPRINTK("tbrq%d threshold\n", group);
@@ -2070,7 +1977,7 @@ he_tasklet(unsigned long data)
he_service_rbpl(he_dev, group);
break;
case ITYPE_RBPS_THRESH:
- he_service_rbps(he_dev, group);
+ /* shouldn't happen unless small buffers enabled */
break;
case ITYPE_PHY:
HPRINTK("phy interrupt\n");
@@ -2098,7 +2005,6 @@ he_tasklet(unsigned long data)
he_service_rbrq(he_dev, 0);
he_service_rbpl(he_dev, 0);
- he_service_rbps(he_dev, 0);
he_service_tbrq(he_dev, 0);
break;
default:
@@ -2252,7 +2158,7 @@ he_open(struct atm_vcc *vcc)
return -ENOMEM;
}
- he_vcc->iov_tail = he_vcc->iov_head;
+ INIT_LIST_HEAD(&he_vcc->buffers);
he_vcc->pdu_len = 0;
he_vcc->rc_index = -1;
@@ -2406,8 +2312,8 @@ he_open(struct atm_vcc *vcc)
goto open_failed;
}
- rsr1 = RSR1_GROUP(0);
- rsr4 = RSR4_GROUP(0);
+ rsr1 = RSR1_GROUP(0) | RSR1_RBPL_ONLY;
+ rsr4 = RSR4_GROUP(0) | RSR4_RBPL_ONLY;
rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ?
(RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
index c2983e0d4ec1..110a27d2ecfc 100644
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -67,11 +67,6 @@
#define CONFIG_RBPL_BUFSIZE 4096
#define RBPL_MASK(x) (((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1))
-#define CONFIG_RBPS_SIZE 1024
-#define CONFIG_RBPS_THRESH 64
-#define CONFIG_RBPS_BUFSIZE 128
-#define RBPS_MASK(x) (((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1))
-
/* 5.1.3 initialize connection memory */
#define CONFIG_RSRA 0x00000
@@ -203,36 +198,37 @@ struct he_hsp {
} group[HE_NUM_GROUPS];
};
-/* figure 2.9 receive buffer pools */
+/*
+ * figure 2.9 receive buffer pools
+ *
+ * since a virtual address might be more than 32 bits, we store an index
+ * in the virt member of he_rbp. NOTE: the lower six bits in the rbrq
+ * addr member are used for buffer status further limiting us to 26 bits.
+ */
struct he_rbp {
volatile u32 phys;
- volatile u32 status;
+ volatile u32 idx; /* virt */
};
-/* NOTE: it is suggested that virt be the virtual address of the host
- buffer. on a 64-bit machine, this would not work. Instead, we
- store the real virtual address in another list, and store an index
- (and buffer status) in the virt member.
-*/
+#define RBP_IDX_OFFSET 6
-#define RBP_INDEX_OFF 6
-#define RBP_INDEX(x) (((long)(x) >> RBP_INDEX_OFF) & 0xffff)
-#define RBP_LOANED 0x80000000
-#define RBP_SMALLBUF 0x40000000
+/*
+ * the he dma engine will try to hold an extra 16 buffers in its local
+ * caches. and add a couple buffers for safety.
+ */
-struct he_virt {
- void *virt;
-};
+#define RBPL_TABLE_SIZE (CONFIG_RBPL_SIZE + 16 + 2)
-#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE
-#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE
+struct he_buff {
+ struct list_head entry;
+ dma_addr_t mapping;
+ unsigned long len;
+ u8 data[];
+};
#ifdef notyet
struct he_group {
- u32 rpbs_size, rpbs_qsize;
- struct he_rbp rbps_ba;
-
u32 rpbl_size, rpbl_qsize;
struct he_rpb_entry *rbpl_ba;
};
@@ -297,18 +293,15 @@ struct he_dev {
struct he_rbrq *rbrq_base, *rbrq_head;
int rbrq_peak;
+ struct he_buff **rbpl_virt;
+ unsigned long *rbpl_table;
+ unsigned long rbpl_hint;
struct pci_pool *rbpl_pool;
dma_addr_t rbpl_phys;
struct he_rbp *rbpl_base, *rbpl_tail;
- struct he_virt *rbpl_virt;
+ struct list_head rbpl_outstanding;
int rbpl_peak;
- struct pci_pool *rbps_pool;
- dma_addr_t rbps_phys;
- struct he_rbp *rbps_base, *rbps_tail;
- struct he_virt *rbps_virt;
- int rbps_peak;
-
dma_addr_t tbrq_phys;
struct he_tbrq *tbrq_base, *tbrq_head;
int tbrq_peak;
@@ -321,20 +314,12 @@ struct he_dev {
struct he_dev *next;
};
-struct he_iovec
-{
- u32 iov_base;
- u32 iov_len;
-};
-
#define HE_MAXIOV 20
struct he_vcc
{
- struct he_iovec iov_head[HE_MAXIOV];
- struct he_iovec *iov_tail;
+ struct list_head buffers;
int pdu_len;
-
int rc_index;
wait_queue_head_t rx_waitq;
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index b7473a6110a7..59876c66a92a 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
* nicstar.c
*
* Device driver supporting CBR for IDT 77201/77211 "NICStAR" based cards.
@@ -16,12 +15,10 @@
*
*
* (C) INESC 1999
- *
- *
- ******************************************************************************/
-
+ */
-/**** IMPORTANT INFORMATION ***************************************************
+/*
+ * IMPORTANT INFORMATION
*
* There are currently three types of spinlocks:
*
@@ -31,9 +28,9 @@
*
* These must NEVER be grabbed in reverse order.
*
- ******************************************************************************/
+ */
-/* Header files ***************************************************************/
+/* Header files */
#include <linux/module.h>
#include <linux/kernel.h>
@@ -41,6 +38,7 @@
#include <linux/atmdev.h>
#include <linux/atm.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/delay.h>
@@ -50,6 +48,7 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/slab.h>
+#include <linux/idr.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
@@ -61,16 +60,11 @@
#include "idt77105.h"
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
-#if BITS_PER_LONG != 32
-# error FIXME: this driver requires a 32-bit platform
-#endif
-
-/* Additional code ************************************************************/
+/* Additional code */
#include "nicstarmac.c"
-
-/* Configurable parameters ****************************************************/
+/* Configurable parameters */
#undef PHY_LOOPBACK
#undef TX_DEBUG
@@ -78,11 +72,10 @@
#undef GENERAL_DEBUG
#undef EXTRA_DEBUG
-#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
- you're going to use only raw ATM */
+#undef NS_USE_DESTRUCTORS /* For now keep this undefined unless you know
+ you're going to use only raw ATM */
-
-/* Do not touch these *********************************************************/
+/* Do not touch these */
#ifdef TX_DEBUG
#define TXPRINTK(args...) printk(args)
@@ -108,2908 +101,2786 @@
#define XPRINTK(args...)
#endif /* EXTRA_DEBUG */
-
-/* Macros *********************************************************************/
+/* Macros */
#define CMD_BUSY(card) (readl((card)->membase + STAT) & NS_STAT_CMDBZ)
#define NS_DELAY mdelay(1)
-#define ALIGN_BUS_ADDR(addr, alignment) \
- ((((u32) (addr)) + (((u32) (alignment)) - 1)) & ~(((u32) (alignment)) - 1))
-#define ALIGN_ADDRESS(addr, alignment) \
- bus_to_virt(ALIGN_BUS_ADDR(virt_to_bus(addr), alignment))
-
-#undef CEIL
+#define PTR_DIFF(a, b) ((u32)((unsigned long)(a) - (unsigned long)(b)))
#ifndef ATM_SKB
#define ATM_SKB(s) (&(s)->atm)
#endif
+#define scq_virt_to_bus(scq, p) \
+ (scq->dma + ((unsigned long)(p) - (unsigned long)(scq)->org))
-/* Function declarations ******************************************************/
+/* Function declarations */
-static u32 ns_read_sram(ns_dev *card, u32 sram_address);
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count);
+static u32 ns_read_sram(ns_dev * card, u32 sram_address);
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+ int count);
static int __devinit ns_init_card(int i, struct pci_dev *pcidev);
-static void __devinit ns_init_card_error(ns_dev *card, int error);
-static scq_info *get_scq(int size, u32 scd);
-static void free_scq(scq_info *scq, struct atm_vcc *vcc);
+static void __devinit ns_init_card_error(ns_dev * card, int error);
+static scq_info *get_scq(ns_dev *card, int size, u32 scd);
+static void free_scq(ns_dev *card, scq_info * scq, struct atm_vcc *vcc);
static void push_rxbufs(ns_dev *, struct sk_buff *);
static irqreturn_t ns_irq_handler(int irq, void *dev_id);
static int ns_open(struct atm_vcc *vcc);
static void ns_close(struct atm_vcc *vcc);
-static void fill_tst(ns_dev *card, int n, vc_map *vc);
+static void fill_tst(ns_dev * card, int n, vc_map * vc);
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
- struct sk_buff *skb);
-static void process_tsq(ns_dev *card);
-static void drain_scq(ns_dev *card, scq_info *scq, int pos);
-static void process_rsq(ns_dev *card);
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe);
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+ struct sk_buff *skb);
+static void process_tsq(ns_dev * card);
+static void drain_scq(ns_dev * card, scq_info * scq, int pos);
+static void process_rsq(ns_dev * card);
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe);
#ifdef NS_USE_DESTRUCTORS
static void ns_sb_destructor(struct sk_buff *sb);
static void ns_lb_destructor(struct sk_buff *lb);
static void ns_hb_destructor(struct sk_buff *hb);
#endif /* NS_USE_DESTRUCTORS */
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb);
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count);
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb);
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb);
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb);
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page);
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
-static void which_list(ns_dev *card, struct sk_buff *skb);
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb);
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count);
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb);
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb);
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb);
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page);
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb);
+#endif
static void ns_poll(unsigned long arg);
static int ns_parse_mac(char *mac, unsigned char *esi);
static short ns_h2i(char c);
static void ns_phy_put(struct atm_dev *dev, unsigned char value,
- unsigned long addr);
+ unsigned long addr);
static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr);
-
-
-/* Global variables ***********************************************************/
+/* Global variables */
static struct ns_dev *cards[NS_MAX_CARDS];
static unsigned num_cards;
-static struct atmdev_ops atm_ops =
-{
- .open = ns_open,
- .close = ns_close,
- .ioctl = ns_ioctl,
- .send = ns_send,
- .phy_put = ns_phy_put,
- .phy_get = ns_phy_get,
- .proc_read = ns_proc_read,
- .owner = THIS_MODULE,
+static struct atmdev_ops atm_ops = {
+ .open = ns_open,
+ .close = ns_close,
+ .ioctl = ns_ioctl,
+ .send = ns_send,
+ .phy_put = ns_phy_put,
+ .phy_get = ns_phy_get,
+ .proc_read = ns_proc_read,
+ .owner = THIS_MODULE,
};
+
static struct timer_list ns_timer;
static char *mac[NS_MAX_CARDS];
module_param_array(mac, charp, NULL, 0);
MODULE_LICENSE("GPL");
-
-/* Functions*******************************************************************/
+/* Functions */
static int __devinit nicstar_init_one(struct pci_dev *pcidev,
const struct pci_device_id *ent)
{
- static int index = -1;
- unsigned int error;
+ static int index = -1;
+ unsigned int error;
- index++;
- cards[index] = NULL;
+ index++;
+ cards[index] = NULL;
- error = ns_init_card(index, pcidev);
- if (error) {
- cards[index--] = NULL; /* don't increment index */
- goto err_out;
- }
+ error = ns_init_card(index, pcidev);
+ if (error) {
+ cards[index--] = NULL; /* don't increment index */
+ goto err_out;
+ }
- return 0;
+ return 0;
err_out:
- return -ENODEV;
+ return -ENODEV;
}
-
-
static void __devexit nicstar_remove_one(struct pci_dev *pcidev)
{
- int i, j;
- ns_dev *card = pci_get_drvdata(pcidev);
- struct sk_buff *hb;
- struct sk_buff *iovb;
- struct sk_buff *lb;
- struct sk_buff *sb;
-
- i = card->index;
-
- if (cards[i] == NULL)
- return;
-
- if (card->atmdev->phy && card->atmdev->phy->stop)
- card->atmdev->phy->stop(card->atmdev);
-
- /* Stop everything */
- writel(0x00000000, card->membase + CFG);
-
- /* De-register device */
- atm_dev_deregister(card->atmdev);
-
- /* Disable PCI device */
- pci_disable_device(pcidev);
-
- /* Free up resources */
- j = 0;
- PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
- while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- {
- dev_kfree_skb_any(hb);
- j++;
- }
- PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
- j = 0;
- PRINTK("nicstar%d: freeing %d iovec buffers.\n", i, card->iovpool.count);
- while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- {
- dev_kfree_skb_any(iovb);
- j++;
- }
- PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
- while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- dev_kfree_skb_any(lb);
- while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- dev_kfree_skb_any(sb);
- free_scq(card->scq0, NULL);
- for (j = 0; j < NS_FRSCD_NUM; j++)
- {
- if (card->scd2vc[j] != NULL)
- free_scq(card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
- }
- kfree(card->rsq.org);
- kfree(card->tsq.org);
- free_irq(card->pcidev->irq, card);
- iounmap(card->membase);
- kfree(card);
+ int i, j;
+ ns_dev *card = pci_get_drvdata(pcidev);
+ struct sk_buff *hb;
+ struct sk_buff *iovb;
+ struct sk_buff *lb;
+ struct sk_buff *sb;
+
+ i = card->index;
+
+ if (cards[i] == NULL)
+ return;
+
+ if (card->atmdev->phy && card->atmdev->phy->stop)
+ card->atmdev->phy->stop(card->atmdev);
+
+ /* Stop everything */
+ writel(0x00000000, card->membase + CFG);
+
+ /* De-register device */
+ atm_dev_deregister(card->atmdev);
+
+ /* Disable PCI device */
+ pci_disable_device(pcidev);
+
+ /* Free up resources */
+ j = 0;
+ PRINTK("nicstar%d: freeing %d huge buffers.\n", i, card->hbpool.count);
+ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL) {
+ dev_kfree_skb_any(hb);
+ j++;
+ }
+ PRINTK("nicstar%d: %d huge buffers freed.\n", i, j);
+ j = 0;
+ PRINTK("nicstar%d: freeing %d iovec buffers.\n", i,
+ card->iovpool.count);
+ while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL) {
+ dev_kfree_skb_any(iovb);
+ j++;
+ }
+ PRINTK("nicstar%d: %d iovec buffers freed.\n", i, j);
+ while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+ dev_kfree_skb_any(lb);
+ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+ dev_kfree_skb_any(sb);
+ free_scq(card, card->scq0, NULL);
+ for (j = 0; j < NS_FRSCD_NUM; j++) {
+ if (card->scd2vc[j] != NULL)
+ free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
+ }
+ idr_remove_all(&card->idr);
+ idr_destroy(&card->idr);
+ pci_free_consistent(card->pcidev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ card->rsq.org, card->rsq.dma);
+ pci_free_consistent(card->pcidev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ card->tsq.org, card->tsq.dma);
+ free_irq(card->pcidev->irq, card);
+ iounmap(card->membase);
+ kfree(card);
}
-
-
-static struct pci_device_id nicstar_pci_tbl[] __devinitdata =
-{
+static struct pci_device_id nicstar_pci_tbl[] __devinitdata = {
{PCI_VENDOR_ID_IDT, PCI_DEVICE_ID_IDT_IDT77201,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{0,} /* terminate list */
};
-MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);
-
+MODULE_DEVICE_TABLE(pci, nicstar_pci_tbl);
static struct pci_driver nicstar_driver = {
- .name = "nicstar",
- .id_table = nicstar_pci_tbl,
- .probe = nicstar_init_one,
- .remove = __devexit_p(nicstar_remove_one),
+ .name = "nicstar",
+ .id_table = nicstar_pci_tbl,
+ .probe = nicstar_init_one,
+ .remove = __devexit_p(nicstar_remove_one),
};
-
-
static int __init nicstar_init(void)
{
- unsigned error = 0; /* Initialized to remove compile warning */
+ unsigned error = 0; /* Initialized to remove compile warning */
+
+ XPRINTK("nicstar: nicstar_init() called.\n");
- XPRINTK("nicstar: nicstar_init() called.\n");
+ error = pci_register_driver(&nicstar_driver);
- error = pci_register_driver(&nicstar_driver);
-
- TXPRINTK("nicstar: TX debug enabled.\n");
- RXPRINTK("nicstar: RX debug enabled.\n");
- PRINTK("nicstar: General debug enabled.\n");
+ TXPRINTK("nicstar: TX debug enabled.\n");
+ RXPRINTK("nicstar: RX debug enabled.\n");
+ PRINTK("nicstar: General debug enabled.\n");
#ifdef PHY_LOOPBACK
- printk("nicstar: using PHY loopback.\n");
+ printk("nicstar: using PHY loopback.\n");
#endif /* PHY_LOOPBACK */
- XPRINTK("nicstar: nicstar_init() returned.\n");
-
- if (!error) {
- init_timer(&ns_timer);
- ns_timer.expires = jiffies + NS_POLL_PERIOD;
- ns_timer.data = 0UL;
- ns_timer.function = ns_poll;
- add_timer(&ns_timer);
- }
-
- return error;
-}
+ XPRINTK("nicstar: nicstar_init() returned.\n");
+ if (!error) {
+ init_timer(&ns_timer);
+ ns_timer.expires = jiffies + NS_POLL_PERIOD;
+ ns_timer.data = 0UL;
+ ns_timer.function = ns_poll;
+ add_timer(&ns_timer);
+ }
+ return error;
+}
static void __exit nicstar_cleanup(void)
{
- XPRINTK("nicstar: nicstar_cleanup() called.\n");
+ XPRINTK("nicstar: nicstar_cleanup() called.\n");
- del_timer(&ns_timer);
+ del_timer(&ns_timer);
- pci_unregister_driver(&nicstar_driver);
+ pci_unregister_driver(&nicstar_driver);
- XPRINTK("nicstar: nicstar_cleanup() returned.\n");
+ XPRINTK("nicstar: nicstar_cleanup() returned.\n");
}
-
-
-static u32 ns_read_sram(ns_dev *card, u32 sram_address)
+static u32 ns_read_sram(ns_dev * card, u32 sram_address)
{
- unsigned long flags;
- u32 data;
- sram_address <<= 2;
- sram_address &= 0x0007FFFC; /* address must be dword aligned */
- sram_address |= 0x50000000; /* SRAM read command */
- spin_lock_irqsave(&card->res_lock, flags);
- while (CMD_BUSY(card));
- writel(sram_address, card->membase + CMD);
- while (CMD_BUSY(card));
- data = readl(card->membase + DR0);
- spin_unlock_irqrestore(&card->res_lock, flags);
- return data;
+ unsigned long flags;
+ u32 data;
+ sram_address <<= 2;
+ sram_address &= 0x0007FFFC; /* address must be dword aligned */
+ sram_address |= 0x50000000; /* SRAM read command */
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(sram_address, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+ return data;
}
-
-
-static void ns_write_sram(ns_dev *card, u32 sram_address, u32 *value, int count)
+static void ns_write_sram(ns_dev * card, u32 sram_address, u32 * value,
+ int count)
{
- unsigned long flags;
- int i, c;
- count--; /* count range now is 0..3 instead of 1..4 */
- c = count;
- c <<= 2; /* to use increments of 4 */
- spin_lock_irqsave(&card->res_lock, flags);
- while (CMD_BUSY(card));
- for (i = 0; i <= c; i += 4)
- writel(*(value++), card->membase + i);
- /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
- so card->membase + DR0 == card->membase */
- sram_address <<= 2;
- sram_address &= 0x0007FFFC;
- sram_address |= (0x40000000 | count);
- writel(sram_address, card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
+ unsigned long flags;
+ int i, c;
+ count--; /* count range now is 0..3 instead of 1..4 */
+ c = count;
+ c <<= 2; /* to use increments of 4 */
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ for (i = 0; i <= c; i += 4)
+ writel(*(value++), card->membase + i);
+ /* Note: DR# registers are the first 4 dwords in nicstar's memspace,
+ so card->membase + DR0 == card->membase */
+ sram_address <<= 2;
+ sram_address &= 0x0007FFFC;
+ sram_address |= (0x40000000 | count);
+ writel(sram_address, card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
}
-
static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
{
- int j;
- struct ns_dev *card = NULL;
- unsigned char pci_latency;
- unsigned error;
- u32 data;
- u32 u32d[4];
- u32 ns_cfg_rctsize;
- int bcount;
- unsigned long membase;
-
- error = 0;
-
- if (pci_enable_device(pcidev))
- {
- printk("nicstar%d: can't enable PCI device\n", i);
- error = 2;
- ns_init_card_error(card, error);
- return error;
- }
-
- if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL)
- {
- printk("nicstar%d: can't allocate memory for device structure.\n", i);
- error = 2;
- ns_init_card_error(card, error);
- return error;
- }
- cards[i] = card;
- spin_lock_init(&card->int_lock);
- spin_lock_init(&card->res_lock);
-
- pci_set_drvdata(pcidev, card);
-
- card->index = i;
- card->atmdev = NULL;
- card->pcidev = pcidev;
- membase = pci_resource_start(pcidev, 1);
- card->membase = ioremap(membase, NS_IOREMAP_SIZE);
- if (!card->membase)
- {
- printk("nicstar%d: can't ioremap() membase.\n",i);
- error = 3;
- ns_init_card_error(card, error);
- return error;
- }
- PRINTK("nicstar%d: membase at 0x%x.\n", i, card->membase);
-
- pci_set_master(pcidev);
-
- if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0)
- {
- printk("nicstar%d: can't read PCI latency timer.\n", i);
- error = 6;
- ns_init_card_error(card, error);
- return error;
- }
+ int j;
+ struct ns_dev *card = NULL;
+ unsigned char pci_latency;
+ unsigned error;
+ u32 data;
+ u32 u32d[4];
+ u32 ns_cfg_rctsize;
+ int bcount;
+ unsigned long membase;
+
+ error = 0;
+
+ if (pci_enable_device(pcidev)) {
+ printk("nicstar%d: can't enable PCI device\n", i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ if ((pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0) ||
+ (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0)) {
+ printk(KERN_WARNING
+ "nicstar%d: No suitable DMA available.\n", i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ if ((card = kmalloc(sizeof(ns_dev), GFP_KERNEL)) == NULL) {
+ printk
+ ("nicstar%d: can't allocate memory for device structure.\n",
+ i);
+ error = 2;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ cards[i] = card;
+ spin_lock_init(&card->int_lock);
+ spin_lock_init(&card->res_lock);
+
+ pci_set_drvdata(pcidev, card);
+
+ card->index = i;
+ card->atmdev = NULL;
+ card->pcidev = pcidev;
+ membase = pci_resource_start(pcidev, 1);
+ card->membase = ioremap(membase, NS_IOREMAP_SIZE);
+ if (!card->membase) {
+ printk("nicstar%d: can't ioremap() membase.\n", i);
+ error = 3;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ PRINTK("nicstar%d: membase at 0x%p.\n", i, card->membase);
+
+ pci_set_master(pcidev);
+
+ if (pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency) != 0) {
+ printk("nicstar%d: can't read PCI latency timer.\n", i);
+ error = 6;
+ ns_init_card_error(card, error);
+ return error;
+ }
#ifdef NS_PCI_LATENCY
- if (pci_latency < NS_PCI_LATENCY)
- {
- PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
- for (j = 1; j < 4; j++)
- {
- if (pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
- break;
- }
- if (j == 4)
- {
- printk("nicstar%d: can't set PCI latency timer to %d.\n", i, NS_PCI_LATENCY);
- error = 7;
- ns_init_card_error(card, error);
- return error;
- }
- }
+ if (pci_latency < NS_PCI_LATENCY) {
+ PRINTK("nicstar%d: setting PCI latency timer to %d.\n", i,
+ NS_PCI_LATENCY);
+ for (j = 1; j < 4; j++) {
+ if (pci_write_config_byte
+ (pcidev, PCI_LATENCY_TIMER, NS_PCI_LATENCY) != 0)
+ break;
+ }
+ if (j == 4) {
+ printk
+ ("nicstar%d: can't set PCI latency timer to %d.\n",
+ i, NS_PCI_LATENCY);
+ error = 7;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ }
#endif /* NS_PCI_LATENCY */
-
- /* Clear timer overflow */
- data = readl(card->membase + STAT);
- if (data & NS_STAT_TMROF)
- writel(NS_STAT_TMROF, card->membase + STAT);
-
- /* Software reset */
- writel(NS_CFG_SWRST, card->membase + CFG);
- NS_DELAY;
- writel(0x00000000, card->membase + CFG);
-
- /* PHY reset */
- writel(0x00000008, card->membase + GP);
- NS_DELAY;
- writel(0x00000001, card->membase + GP);
- NS_DELAY;
- while (CMD_BUSY(card));
- writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */
- NS_DELAY;
-
- /* Detect PHY type */
- while (CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
- while (CMD_BUSY(card));
- data = readl(card->membase + DR0);
- switch(data) {
- case 0x00000009:
- printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
- card->max_pcr = ATM_25_PCR;
- while(CMD_BUSY(card));
- writel(0x00000008, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
- /* Clear an eventual pending interrupt */
- writel(NS_STAT_SFBQF, card->membase + STAT);
+
+ /* Clear timer overflow */
+ data = readl(card->membase + STAT);
+ if (data & NS_STAT_TMROF)
+ writel(NS_STAT_TMROF, card->membase + STAT);
+
+ /* Software reset */
+ writel(NS_CFG_SWRST, card->membase + CFG);
+ NS_DELAY;
+ writel(0x00000000, card->membase + CFG);
+
+ /* PHY reset */
+ writel(0x00000008, card->membase + GP);
+ NS_DELAY;
+ writel(0x00000001, card->membase + GP);
+ NS_DELAY;
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_WRITE_UTILITY | 0x00000100, card->membase + CMD); /* Sync UTOPIA with SAR clock */
+ NS_DELAY;
+
+ /* Detect PHY type */
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0);
+ switch (data) {
+ case 0x00000009:
+ printk("nicstar%d: PHY seems to be 25 Mbps.\n", i);
+ card->max_pcr = ATM_25_PCR;
+ while (CMD_BUSY(card)) ;
+ writel(0x00000008, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000200, card->membase + CMD);
+ /* Clear an eventual pending interrupt */
+ writel(NS_STAT_SFBQF, card->membase + STAT);
#ifdef PHY_LOOPBACK
- while(CMD_BUSY(card));
- writel(0x00000022, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ writel(0x00000022, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000202, card->membase + CMD);
#endif /* PHY_LOOPBACK */
- break;
- case 0x00000030:
- case 0x00000031:
- printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
- card->max_pcr = ATM_OC3_PCR;
+ break;
+ case 0x00000030:
+ case 0x00000031:
+ printk("nicstar%d: PHY seems to be 155 Mbps.\n", i);
+ card->max_pcr = ATM_OC3_PCR;
#ifdef PHY_LOOPBACK
- while(CMD_BUSY(card));
- writel(0x00000002, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ writel(0x00000002, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000205, card->membase + CMD);
#endif /* PHY_LOOPBACK */
- break;
- default:
- printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
- error = 8;
- ns_init_card_error(card, error);
- return error;
- }
- writel(0x00000000, card->membase + GP);
-
- /* Determine SRAM size */
- data = 0x76543210;
- ns_write_sram(card, 0x1C003, &data, 1);
- data = 0x89ABCDEF;
- ns_write_sram(card, 0x14003, &data, 1);
- if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
- ns_read_sram(card, 0x1C003) == 0x76543210)
- card->sram_size = 128;
- else
- card->sram_size = 32;
- PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
-
- card->rct_size = NS_MAX_RCTSIZE;
+ break;
+ default:
+ printk("nicstar%d: unknown PHY type (0x%08X).\n", i, data);
+ error = 8;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ writel(0x00000000, card->membase + GP);
+
+ /* Determine SRAM size */
+ data = 0x76543210;
+ ns_write_sram(card, 0x1C003, &data, 1);
+ data = 0x89ABCDEF;
+ ns_write_sram(card, 0x14003, &data, 1);
+ if (ns_read_sram(card, 0x14003) == 0x89ABCDEF &&
+ ns_read_sram(card, 0x1C003) == 0x76543210)
+ card->sram_size = 128;
+ else
+ card->sram_size = 32;
+ PRINTK("nicstar%d: %dK x 32bit SRAM size.\n", i, card->sram_size);
+
+ card->rct_size = NS_MAX_RCTSIZE;
#if (NS_MAX_RCTSIZE == 4096)
- if (card->sram_size == 128)
- printk("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n", i);
+ if (card->sram_size == 128)
+ printk
+ ("nicstar%d: limiting maximum VCI. See NS_MAX_RCTSIZE in nicstar.h\n",
+ i);
#elif (NS_MAX_RCTSIZE == 16384)
- if (card->sram_size == 32)
- {
- printk("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n", i);
- card->rct_size = 4096;
- }
+ if (card->sram_size == 32) {
+ printk
+ ("nicstar%d: wasting memory. See NS_MAX_RCTSIZE in nicstar.h\n",
+ i);
+ card->rct_size = 4096;
+ }
#else
#error NS_MAX_RCTSIZE must be either 4096 or 16384 in nicstar.c
#endif
- card->vpibits = NS_VPIBITS;
- if (card->rct_size == 4096)
- card->vcibits = 12 - NS_VPIBITS;
- else /* card->rct_size == 16384 */
- card->vcibits = 14 - NS_VPIBITS;
-
- /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
- if (mac[i] == NULL)
- nicstar_init_eprom(card->membase);
-
- /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
- writel(0x00000000, card->membase + VPM);
-
- /* Initialize TSQ */
- card->tsq.org = kmalloc(NS_TSQSIZE + NS_TSQ_ALIGNMENT, GFP_KERNEL);
- if (card->tsq.org == NULL)
- {
- printk("nicstar%d: can't allocate TSQ.\n", i);
- error = 10;
- ns_init_card_error(card, error);
- return error;
- }
- card->tsq.base = (ns_tsi *) ALIGN_ADDRESS(card->tsq.org, NS_TSQ_ALIGNMENT);
- card->tsq.next = card->tsq.base;
- card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
- for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
- ns_tsi_init(card->tsq.base + j);
- writel(0x00000000, card->membase + TSQH);
- writel((u32) virt_to_bus(card->tsq.base), card->membase + TSQB);
- PRINTK("nicstar%d: TSQ base at 0x%x 0x%x 0x%x.\n", i, (u32) card->tsq.base,
- (u32) virt_to_bus(card->tsq.base), readl(card->membase + TSQB));
-
- /* Initialize RSQ */
- card->rsq.org = kmalloc(NS_RSQSIZE + NS_RSQ_ALIGNMENT, GFP_KERNEL);
- if (card->rsq.org == NULL)
- {
- printk("nicstar%d: can't allocate RSQ.\n", i);
- error = 11;
- ns_init_card_error(card, error);
- return error;
- }
- card->rsq.base = (ns_rsqe *) ALIGN_ADDRESS(card->rsq.org, NS_RSQ_ALIGNMENT);
- card->rsq.next = card->rsq.base;
- card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
- for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
- ns_rsqe_init(card->rsq.base + j);
- writel(0x00000000, card->membase + RSQH);
- writel((u32) virt_to_bus(card->rsq.base), card->membase + RSQB);
- PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
-
- /* Initialize SCQ0, the only VBR SCQ used */
- card->scq1 = NULL;
- card->scq2 = NULL;
- card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
- if (card->scq0 == NULL)
- {
- printk("nicstar%d: can't get SCQ0.\n", i);
- error = 12;
- ns_init_card_error(card, error);
- return error;
- }
- u32d[0] = (u32) virt_to_bus(card->scq0->base);
- u32d[1] = (u32) 0x00000000;
- u32d[2] = (u32) 0xffffffff;
- u32d[3] = (u32) 0x00000000;
- ns_write_sram(card, NS_VRSCD0, u32d, 4);
- ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */
- ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */
- card->scq0->scd = NS_VRSCD0;
- PRINTK("nicstar%d: VBR-SCQ0 base at 0x%x.\n", i, (u32) card->scq0->base);
-
- /* Initialize TSTs */
- card->tst_addr = NS_TST0;
- card->tst_free_entries = NS_TST_NUM_ENTRIES;
- data = NS_TST_OPCODE_VARIABLE;
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- ns_write_sram(card, NS_TST0 + j, &data, 1);
- data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
- ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- ns_write_sram(card, NS_TST1 + j, &data, 1);
- data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
- ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
- for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
- card->tste2vc[j] = NULL;
- writel(NS_TST0 << 2, card->membase + TSTB);
-
-
- /* Initialize RCT. AAL type is set on opening the VC. */
+ card->vpibits = NS_VPIBITS;
+ if (card->rct_size == 4096)
+ card->vcibits = 12 - NS_VPIBITS;
+ else /* card->rct_size == 16384 */
+ card->vcibits = 14 - NS_VPIBITS;
+
+ /* Initialize the nicstar eeprom/eprom stuff, for the MAC addr */
+ if (mac[i] == NULL)
+ nicstar_init_eprom(card->membase);
+
+ /* Set the VPI/VCI MSb mask to zero so we can receive OAM cells */
+ writel(0x00000000, card->membase + VPM);
+
+ /* Initialize TSQ */
+ card->tsq.org = pci_alloc_consistent(card->pcidev,
+ NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ &card->tsq.dma);
+ if (card->tsq.org == NULL) {
+ printk("nicstar%d: can't allocate TSQ.\n", i);
+ error = 10;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ card->tsq.base = PTR_ALIGN(card->tsq.org, NS_TSQ_ALIGNMENT);
+ card->tsq.next = card->tsq.base;
+ card->tsq.last = card->tsq.base + (NS_TSQ_NUM_ENTRIES - 1);
+ for (j = 0; j < NS_TSQ_NUM_ENTRIES; j++)
+ ns_tsi_init(card->tsq.base + j);
+ writel(0x00000000, card->membase + TSQH);
+ writel(ALIGN(card->tsq.dma, NS_TSQ_ALIGNMENT), card->membase + TSQB);
+ PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base);
+
+ /* Initialize RSQ */
+ card->rsq.org = pci_alloc_consistent(card->pcidev,
+ NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ &card->rsq.dma);
+ if (card->rsq.org == NULL) {
+ printk("nicstar%d: can't allocate RSQ.\n", i);
+ error = 11;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ card->rsq.base = PTR_ALIGN(card->rsq.org, NS_RSQ_ALIGNMENT);
+ card->rsq.next = card->rsq.base;
+ card->rsq.last = card->rsq.base + (NS_RSQ_NUM_ENTRIES - 1);
+ for (j = 0; j < NS_RSQ_NUM_ENTRIES; j++)
+ ns_rsqe_init(card->rsq.base + j);
+ writel(0x00000000, card->membase + RSQH);
+ writel(ALIGN(card->rsq.dma, NS_RSQ_ALIGNMENT), card->membase + RSQB);
+ PRINTK("nicstar%d: RSQ base at 0x%p.\n", i, card->rsq.base);
+
+ /* Initialize SCQ0, the only VBR SCQ used */
+ card->scq1 = NULL;
+ card->scq2 = NULL;
+ card->scq0 = get_scq(card, VBR_SCQSIZE, NS_VRSCD0);
+ if (card->scq0 == NULL) {
+ printk("nicstar%d: can't get SCQ0.\n", i);
+ error = 12;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ u32d[0] = scq_virt_to_bus(card->scq0, card->scq0->base);
+ u32d[1] = (u32) 0x00000000;
+ u32d[2] = (u32) 0xffffffff;
+ u32d[3] = (u32) 0x00000000;
+ ns_write_sram(card, NS_VRSCD0, u32d, 4);
+ ns_write_sram(card, NS_VRSCD1, u32d, 4); /* These last two won't be used */
+ ns_write_sram(card, NS_VRSCD2, u32d, 4); /* but are initialized, just in case... */
+ card->scq0->scd = NS_VRSCD0;
+ PRINTK("nicstar%d: VBR-SCQ0 base at 0x%p.\n", i, card->scq0->base);
+
+ /* Initialize TSTs */
+ card->tst_addr = NS_TST0;
+ card->tst_free_entries = NS_TST_NUM_ENTRIES;
+ data = NS_TST_OPCODE_VARIABLE;
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ ns_write_sram(card, NS_TST0 + j, &data, 1);
+ data = ns_tste_make(NS_TST_OPCODE_END, NS_TST0);
+ ns_write_sram(card, NS_TST0 + NS_TST_NUM_ENTRIES, &data, 1);
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ ns_write_sram(card, NS_TST1 + j, &data, 1);
+ data = ns_tste_make(NS_TST_OPCODE_END, NS_TST1);
+ ns_write_sram(card, NS_TST1 + NS_TST_NUM_ENTRIES, &data, 1);
+ for (j = 0; j < NS_TST_NUM_ENTRIES; j++)
+ card->tste2vc[j] = NULL;
+ writel(NS_TST0 << 2, card->membase + TSTB);
+
+ /* Initialize RCT. AAL type is set on opening the VC. */
#ifdef RCQ_SUPPORT
- u32d[0] = NS_RCTE_RAWCELLINTEN;
+ u32d[0] = NS_RCTE_RAWCELLINTEN;
#else
- u32d[0] = 0x00000000;
+ u32d[0] = 0x00000000;
#endif /* RCQ_SUPPORT */
- u32d[1] = 0x00000000;
- u32d[2] = 0x00000000;
- u32d[3] = 0xFFFFFFFF;
- for (j = 0; j < card->rct_size; j++)
- ns_write_sram(card, j * 4, u32d, 4);
-
- memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
-
- for (j = 0; j < NS_FRSCD_NUM; j++)
- card->scd2vc[j] = NULL;
-
- /* Initialize buffer levels */
- card->sbnr.min = MIN_SB;
- card->sbnr.init = NUM_SB;
- card->sbnr.max = MAX_SB;
- card->lbnr.min = MIN_LB;
- card->lbnr.init = NUM_LB;
- card->lbnr.max = MAX_LB;
- card->iovnr.min = MIN_IOVB;
- card->iovnr.init = NUM_IOVB;
- card->iovnr.max = MAX_IOVB;
- card->hbnr.min = MIN_HB;
- card->hbnr.init = NUM_HB;
- card->hbnr.max = MAX_HB;
-
- card->sm_handle = 0x00000000;
- card->sm_addr = 0x00000000;
- card->lg_handle = 0x00000000;
- card->lg_addr = 0x00000000;
-
- card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */
-
- /* Pre-allocate some huge buffers */
- skb_queue_head_init(&card->hbpool.queue);
- card->hbpool.count = 0;
- for (j = 0; j < NUM_HB; j++)
- {
- struct sk_buff *hb;
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d huge buffers.\n",
- i, j, NUM_HB);
- error = 13;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
-
-
- /* Allocate large buffers */
- skb_queue_head_init(&card->lbpool.queue);
- card->lbpool.count = 0; /* Not used */
- for (j = 0; j < NUM_LB; j++)
- {
- struct sk_buff *lb;
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d large buffers.\n",
- i, j, NUM_LB);
- error = 14;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- /* Due to the implementation of push_rxbufs() this is 1, not 0 */
- if (j == 1)
- {
- card->rcbuf = lb;
- card->rawch = (u32) virt_to_bus(lb->data);
- }
- }
- /* Test for strange behaviour which leads to crashes */
- if ((bcount = ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min)
- {
- printk("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
- i, j, bcount);
- error = 14;
- ns_init_card_error(card, error);
- return error;
- }
-
-
- /* Allocate small buffers */
- skb_queue_head_init(&card->sbpool.queue);
- card->sbpool.count = 0; /* Not used */
- for (j = 0; j < NUM_SB; j++)
- {
- struct sk_buff *sb;
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d small buffers.\n",
- i, j, NUM_SB);
- error = 15;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- /* Test for strange behaviour which leads to crashes */
- if ((bcount = ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min)
- {
- printk("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
- i, j, bcount);
- error = 15;
- ns_init_card_error(card, error);
- return error;
- }
-
-
- /* Allocate iovec buffers */
- skb_queue_head_init(&card->iovpool.queue);
- card->iovpool.count = 0;
- for (j = 0; j < NUM_IOVB; j++)
- {
- struct sk_buff *iovb;
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
- if (iovb == NULL)
- {
- printk("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
- i, j, NUM_IOVB);
- error = 16;
- ns_init_card_error(card, error);
- return error;
- }
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- }
-
- /* Configure NICStAR */
- if (card->rct_size == 4096)
- ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
- else /* (card->rct_size == 16384) */
- ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
-
- card->efbie = 1;
-
- card->intcnt = 0;
- if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
- {
- printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
- error = 9;
- ns_init_card_error(card, error);
- return error;
- }
-
- /* Register device */
- card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
- if (card->atmdev == NULL)
- {
- printk("nicstar%d: can't register device.\n", i);
- error = 17;
- ns_init_card_error(card, error);
- return error;
- }
-
- if (ns_parse_mac(mac[i], card->atmdev->esi)) {
- nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
- card->atmdev->esi, 6);
- if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
- nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
- card->atmdev->esi, 6);
- }
- }
-
- printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
-
- card->atmdev->dev_data = card;
- card->atmdev->ci_range.vpi_bits = card->vpibits;
- card->atmdev->ci_range.vci_bits = card->vcibits;
- card->atmdev->link_rate = card->max_pcr;
- card->atmdev->phy = NULL;
+ u32d[1] = 0x00000000;
+ u32d[2] = 0x00000000;
+ u32d[3] = 0xFFFFFFFF;
+ for (j = 0; j < card->rct_size; j++)
+ ns_write_sram(card, j * 4, u32d, 4);
+
+ memset(card->vcmap, 0, NS_MAX_RCTSIZE * sizeof(vc_map));
+
+ for (j = 0; j < NS_FRSCD_NUM; j++)
+ card->scd2vc[j] = NULL;
+
+ /* Initialize buffer levels */
+ card->sbnr.min = MIN_SB;
+ card->sbnr.init = NUM_SB;
+ card->sbnr.max = MAX_SB;
+ card->lbnr.min = MIN_LB;
+ card->lbnr.init = NUM_LB;
+ card->lbnr.max = MAX_LB;
+ card->iovnr.min = MIN_IOVB;
+ card->iovnr.init = NUM_IOVB;
+ card->iovnr.max = MAX_IOVB;
+ card->hbnr.min = MIN_HB;
+ card->hbnr.init = NUM_HB;
+ card->hbnr.max = MAX_HB;
+
+ card->sm_handle = 0x00000000;
+ card->sm_addr = 0x00000000;
+ card->lg_handle = 0x00000000;
+ card->lg_addr = 0x00000000;
+
+ card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */
+
+ idr_init(&card->idr);
+
+ /* Pre-allocate some huge buffers */
+ skb_queue_head_init(&card->hbpool.queue);
+ card->hbpool.count = 0;
+ for (j = 0; j < NUM_HB; j++) {
+ struct sk_buff *hb;
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d huge buffers.\n",
+ i, j, NUM_HB);
+ error = 13;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ }
+
+ /* Allocate large buffers */
+ skb_queue_head_init(&card->lbpool.queue);
+ card->lbpool.count = 0; /* Not used */
+ for (j = 0; j < NUM_LB; j++) {
+ struct sk_buff *lb;
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d large buffers.\n",
+ i, j, NUM_LB);
+ error = 14;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ /* Due to the implementation of push_rxbufs() this is 1, not 0 */
+ if (j == 1) {
+ card->rcbuf = lb;
+ card->rawcell = (struct ns_rcqe *) lb->data;
+ card->rawch = NS_PRV_DMA(lb);
+ }
+ }
+ /* Test for strange behaviour which leads to crashes */
+ if ((bcount =
+ ns_stat_lfbqc_get(readl(card->membase + STAT))) < card->lbnr.min) {
+ printk
+ ("nicstar%d: Strange... Just allocated %d large buffers and lfbqc = %d.\n",
+ i, j, bcount);
+ error = 14;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Allocate small buffers */
+ skb_queue_head_init(&card->sbpool.queue);
+ card->sbpool.count = 0; /* Not used */
+ for (j = 0; j < NUM_SB; j++) {
+ struct sk_buff *sb;
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d small buffers.\n",
+ i, j, NUM_SB);
+ error = 15;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ /* Test for strange behaviour which leads to crashes */
+ if ((bcount =
+ ns_stat_sfbqc_get(readl(card->membase + STAT))) < card->sbnr.min) {
+ printk
+ ("nicstar%d: Strange... Just allocated %d small buffers and sfbqc = %d.\n",
+ i, j, bcount);
+ error = 15;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Allocate iovec buffers */
+ skb_queue_head_init(&card->iovpool.queue);
+ card->iovpool.count = 0;
+ for (j = 0; j < NUM_IOVB; j++) {
+ struct sk_buff *iovb;
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+ if (iovb == NULL) {
+ printk
+ ("nicstar%d: can't allocate %dth of %d iovec buffers.\n",
+ i, j, NUM_IOVB);
+ error = 16;
+ ns_init_card_error(card, error);
+ return error;
+ }
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ }
+
+ /* Configure NICStAR */
+ if (card->rct_size == 4096)
+ ns_cfg_rctsize = NS_CFG_RCTSIZE_4096_ENTRIES;
+ else /* (card->rct_size == 16384) */
+ ns_cfg_rctsize = NS_CFG_RCTSIZE_16384_ENTRIES;
+
+ card->efbie = 1;
+
+ card->intcnt = 0;
+ if (request_irq
+ (pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED,
+ "nicstar", card) != 0) {
+ printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
+ error = 9;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ /* Register device */
+ card->atmdev = atm_dev_register("nicstar", &atm_ops, -1, NULL);
+ if (card->atmdev == NULL) {
+ printk("nicstar%d: can't register device.\n", i);
+ error = 17;
+ ns_init_card_error(card, error);
+ return error;
+ }
+
+ if (ns_parse_mac(mac[i], card->atmdev->esi)) {
+ nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
+ card->atmdev->esi, 6);
+ if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) ==
+ 0) {
+ nicstar_read_eprom(card->membase,
+ NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
+ card->atmdev->esi, 6);
+ }
+ }
+
+ printk("nicstar%d: MAC address %pM\n", i, card->atmdev->esi);
+
+ card->atmdev->dev_data = card;
+ card->atmdev->ci_range.vpi_bits = card->vpibits;
+ card->atmdev->ci_range.vci_bits = card->vcibits;
+ card->atmdev->link_rate = card->max_pcr;
+ card->atmdev->phy = NULL;
#ifdef CONFIG_ATM_NICSTAR_USE_SUNI
- if (card->max_pcr == ATM_OC3_PCR)
- suni_init(card->atmdev);
+ if (card->max_pcr == ATM_OC3_PCR)
+ suni_init(card->atmdev);
#endif /* CONFIG_ATM_NICSTAR_USE_SUNI */
#ifdef CONFIG_ATM_NICSTAR_USE_IDT77105
- if (card->max_pcr == ATM_25_PCR)
- idt77105_init(card->atmdev);
+ if (card->max_pcr == ATM_25_PCR)
+ idt77105_init(card->atmdev);
#endif /* CONFIG_ATM_NICSTAR_USE_IDT77105 */
- if (card->atmdev->phy && card->atmdev->phy->start)
- card->atmdev->phy->start(card->atmdev);
-
- writel(NS_CFG_RXPATH |
- NS_CFG_SMBUFSIZE |
- NS_CFG_LGBUFSIZE |
- NS_CFG_EFBIE |
- NS_CFG_RSQSIZE |
- NS_CFG_VPIBITS |
- ns_cfg_rctsize |
- NS_CFG_RXINT_NODELAY |
- NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */
- NS_CFG_RSQAFIE |
- NS_CFG_TXEN |
- NS_CFG_TXIE |
- NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */
- NS_CFG_PHYIE,
- card->membase + CFG);
-
- num_cards++;
-
- return error;
-}
+ if (card->atmdev->phy && card->atmdev->phy->start)
+ card->atmdev->phy->start(card->atmdev);
+ writel(NS_CFG_RXPATH | NS_CFG_SMBUFSIZE | NS_CFG_LGBUFSIZE | NS_CFG_EFBIE | NS_CFG_RSQSIZE | NS_CFG_VPIBITS | ns_cfg_rctsize | NS_CFG_RXINT_NODELAY | NS_CFG_RAWIE | /* Only enabled if RCQ_SUPPORT */
+ NS_CFG_RSQAFIE | NS_CFG_TXEN | NS_CFG_TXIE | NS_CFG_TSQFIE_OPT | /* Only enabled if ENABLE_TSQFIE */
+ NS_CFG_PHYIE, card->membase + CFG);
+ num_cards++;
-static void __devinit ns_init_card_error(ns_dev *card, int error)
-{
- if (error >= 17)
- {
- writel(0x00000000, card->membase + CFG);
- }
- if (error >= 16)
- {
- struct sk_buff *iovb;
- while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
- dev_kfree_skb_any(iovb);
- }
- if (error >= 15)
- {
- struct sk_buff *sb;
- while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
- dev_kfree_skb_any(sb);
- free_scq(card->scq0, NULL);
- }
- if (error >= 14)
- {
- struct sk_buff *lb;
- while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
- dev_kfree_skb_any(lb);
- }
- if (error >= 13)
- {
- struct sk_buff *hb;
- while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
- dev_kfree_skb_any(hb);
- }
- if (error >= 12)
- {
- kfree(card->rsq.org);
- }
- if (error >= 11)
- {
- kfree(card->tsq.org);
- }
- if (error >= 10)
- {
- free_irq(card->pcidev->irq, card);
- }
- if (error >= 4)
- {
- iounmap(card->membase);
- }
- if (error >= 3)
- {
- pci_disable_device(card->pcidev);
- kfree(card);
- }
+ return error;
}
-
-
-static scq_info *get_scq(int size, u32 scd)
+static void __devinit ns_init_card_error(ns_dev * card, int error)
{
- scq_info *scq;
- int i;
-
- if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
- return NULL;
-
- scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
- if (scq == NULL)
- return NULL;
- scq->org = kmalloc(2 * size, GFP_KERNEL);
- if (scq->org == NULL)
- {
- kfree(scq);
- return NULL;
- }
- scq->skb = kmalloc(sizeof(struct sk_buff *) *
- (size / NS_SCQE_SIZE), GFP_KERNEL);
- if (scq->skb == NULL)
- {
- kfree(scq->org);
- kfree(scq);
- return NULL;
- }
- scq->num_entries = size / NS_SCQE_SIZE;
- scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
- scq->next = scq->base;
- scq->last = scq->base + (scq->num_entries - 1);
- scq->tail = scq->last;
- scq->scd = scd;
- scq->num_entries = size / NS_SCQE_SIZE;
- scq->tbd_count = 0;
- init_waitqueue_head(&scq->scqfull_waitq);
- scq->full = 0;
- spin_lock_init(&scq->lock);
-
- for (i = 0; i < scq->num_entries; i++)
- scq->skb[i] = NULL;
-
- return scq;
+ if (error >= 17) {
+ writel(0x00000000, card->membase + CFG);
+ }
+ if (error >= 16) {
+ struct sk_buff *iovb;
+ while ((iovb = skb_dequeue(&card->iovpool.queue)) != NULL)
+ dev_kfree_skb_any(iovb);
+ }
+ if (error >= 15) {
+ struct sk_buff *sb;
+ while ((sb = skb_dequeue(&card->sbpool.queue)) != NULL)
+ dev_kfree_skb_any(sb);
+ free_scq(card, card->scq0, NULL);
+ }
+ if (error >= 14) {
+ struct sk_buff *lb;
+ while ((lb = skb_dequeue(&card->lbpool.queue)) != NULL)
+ dev_kfree_skb_any(lb);
+ }
+ if (error >= 13) {
+ struct sk_buff *hb;
+ while ((hb = skb_dequeue(&card->hbpool.queue)) != NULL)
+ dev_kfree_skb_any(hb);
+ }
+ if (error >= 12) {
+ kfree(card->rsq.org);
+ }
+ if (error >= 11) {
+ kfree(card->tsq.org);
+ }
+ if (error >= 10) {
+ free_irq(card->pcidev->irq, card);
+ }
+ if (error >= 4) {
+ iounmap(card->membase);
+ }
+ if (error >= 3) {
+ pci_disable_device(card->pcidev);
+ kfree(card);
+ }
}
-
+static scq_info *get_scq(ns_dev *card, int size, u32 scd)
+{
+ scq_info *scq;
+ int i;
+
+ if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
+ return NULL;
+
+ scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
+ if (!scq)
+ return NULL;
+ scq->org = pci_alloc_consistent(card->pcidev, 2 * size, &scq->dma);
+ if (!scq->org) {
+ kfree(scq);
+ return NULL;
+ }
+ scq->skb = kmalloc(sizeof(struct sk_buff *) *
+ (size / NS_SCQE_SIZE), GFP_KERNEL);
+ if (!scq->skb) {
+ kfree(scq->org);
+ kfree(scq);
+ return NULL;
+ }
+ scq->num_entries = size / NS_SCQE_SIZE;
+ scq->base = PTR_ALIGN(scq->org, size);
+ scq->next = scq->base;
+ scq->last = scq->base + (scq->num_entries - 1);
+ scq->tail = scq->last;
+ scq->scd = scd;
+ scq->num_entries = size / NS_SCQE_SIZE;
+ scq->tbd_count = 0;
+ init_waitqueue_head(&scq->scqfull_waitq);
+ scq->full = 0;
+ spin_lock_init(&scq->lock);
+
+ for (i = 0; i < scq->num_entries; i++)
+ scq->skb[i] = NULL;
+
+ return scq;
+}
/* For variable rate SCQ vcc must be NULL */
-static void free_scq(scq_info *scq, struct atm_vcc *vcc)
+static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc)
{
- int i;
-
- if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
- for (i = 0; i < scq->num_entries; i++)
- {
- if (scq->skb[i] != NULL)
- {
- vcc = ATM_SKB(scq->skb[i])->vcc;
- if (vcc->pop != NULL)
- vcc->pop(vcc, scq->skb[i]);
- else
- dev_kfree_skb_any(scq->skb[i]);
- }
- }
- else /* vcc must be != NULL */
- {
- if (vcc == NULL)
- {
- printk("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
- for (i = 0; i < scq->num_entries; i++)
- dev_kfree_skb_any(scq->skb[i]);
- }
- else
- for (i = 0; i < scq->num_entries; i++)
- {
- if (scq->skb[i] != NULL)
- {
- if (vcc->pop != NULL)
- vcc->pop(vcc, scq->skb[i]);
- else
- dev_kfree_skb_any(scq->skb[i]);
- }
- }
- }
- kfree(scq->skb);
- kfree(scq->org);
- kfree(scq);
+ int i;
+
+ if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] != NULL) {
+ vcc = ATM_SKB(scq->skb[i])->vcc;
+ if (vcc->pop != NULL)
+ vcc->pop(vcc, scq->skb[i]);
+ else
+ dev_kfree_skb_any(scq->skb[i]);
+ }
+ } else { /* vcc must be != NULL */
+
+ if (vcc == NULL) {
+ printk
+ ("nicstar: free_scq() called with vcc == NULL for fixed rate scq.");
+ for (i = 0; i < scq->num_entries; i++)
+ dev_kfree_skb_any(scq->skb[i]);
+ } else
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] != NULL) {
+ if (vcc->pop != NULL)
+ vcc->pop(vcc, scq->skb[i]);
+ else
+ dev_kfree_skb_any(scq->skb[i]);
+ }
+ }
+ }
+ kfree(scq->skb);
+ pci_free_consistent(card->pcidev,
+ 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ?
+ VBR_SCQSIZE : CBR_SCQSIZE),
+ scq->org, scq->dma);
+ kfree(scq);
}
-
-
/* The handles passed must be pointers to the sk_buff containing the small
or large buffer(s) cast to u32. */
-static void push_rxbufs(ns_dev *card, struct sk_buff *skb)
+static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
{
- struct ns_skb_cb *cb = NS_SKB_CB(skb);
- u32 handle1, addr1;
- u32 handle2, addr2;
- u32 stat;
- unsigned long flags;
-
- /* *BARF* */
- handle2 = addr2 = 0;
- handle1 = (u32)skb;
- addr1 = (u32)virt_to_bus(skb->data);
+ struct sk_buff *handle1, *handle2;
+ u32 id1 = 0, id2 = 0;
+ u32 addr1, addr2;
+ u32 stat;
+ unsigned long flags;
+ int err;
+
+ /* *BARF* */
+ handle2 = NULL;
+ addr2 = 0;
+ handle1 = skb;
+ addr1 = pci_map_single(card->pcidev,
+ skb->data,
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_TODEVICE);
+ NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */
#ifdef GENERAL_DEBUG
- if (!addr1)
- printk("nicstar%d: push_rxbufs called with addr1 = 0.\n", card->index);
+ if (!addr1)
+ printk("nicstar%d: push_rxbufs called with addr1 = 0.\n",
+ card->index);
#endif /* GENERAL_DEBUG */
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
- if (cb->buf_type == BUF_SM)
- {
- if (!addr2)
- {
- if (card->sm_addr)
- {
- addr2 = card->sm_addr;
- handle2 = card->sm_handle;
- card->sm_addr = 0x00000000;
- card->sm_handle = 0x00000000;
- }
- else /* (!sm_addr) */
- {
- card->sm_addr = addr1;
- card->sm_handle = handle1;
- }
- }
- }
- else /* buf_type == BUF_LG */
- {
- if (!addr2)
- {
- if (card->lg_addr)
- {
- addr2 = card->lg_addr;
- handle2 = card->lg_handle;
- card->lg_addr = 0x00000000;
- card->lg_handle = 0x00000000;
- }
- else /* (!lg_addr) */
- {
- card->lg_addr = addr1;
- card->lg_handle = handle1;
- }
- }
- }
-
- if (addr2)
- {
- if (cb->buf_type == BUF_SM)
- {
- if (card->sbfqc >= card->sbnr.max)
- {
- skb_unlink((struct sk_buff *) handle1, &card->sbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle1);
- skb_unlink((struct sk_buff *) handle2, &card->sbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle2);
- return;
- }
- else
- card->sbfqc += 2;
- }
- else /* (buf_type == BUF_LG) */
- {
- if (card->lbfqc >= card->lbnr.max)
- {
- skb_unlink((struct sk_buff *) handle1, &card->lbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle1);
- skb_unlink((struct sk_buff *) handle2, &card->lbpool.queue);
- dev_kfree_skb_any((struct sk_buff *) handle2);
- return;
- }
- else
- card->lbfqc += 2;
- }
-
- spin_lock_irqsave(&card->res_lock, flags);
-
- while (CMD_BUSY(card));
- writel(addr2, card->membase + DR3);
- writel(handle2, card->membase + DR2);
- writel(addr1, card->membase + DR1);
- writel(handle1, card->membase + DR0);
- writel(NS_CMD_WRITE_FREEBUFQ | cb->buf_type, card->membase + CMD);
-
- spin_unlock_irqrestore(&card->res_lock, flags);
-
- XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n", card->index,
- (cb->buf_type == BUF_SM ? "small" : "large"), addr1, addr2);
- }
-
- if (!card->efbie && card->sbfqc >= card->sbnr.min &&
- card->lbfqc >= card->lbnr.min)
- {
- card->efbie = 1;
- writel((readl(card->membase + CFG) | NS_CFG_EFBIE), card->membase + CFG);
- }
-
- return;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+ if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+ if (!addr2) {
+ if (card->sm_addr) {
+ addr2 = card->sm_addr;
+ handle2 = card->sm_handle;
+ card->sm_addr = 0x00000000;
+ card->sm_handle = 0x00000000;
+ } else { /* (!sm_addr) */
+
+ card->sm_addr = addr1;
+ card->sm_handle = handle1;
+ }
+ }
+ } else { /* buf_type == BUF_LG */
+
+ if (!addr2) {
+ if (card->lg_addr) {
+ addr2 = card->lg_addr;
+ handle2 = card->lg_handle;
+ card->lg_addr = 0x00000000;
+ card->lg_handle = 0x00000000;
+ } else { /* (!lg_addr) */
+
+ card->lg_addr = addr1;
+ card->lg_handle = handle1;
+ }
+ }
+ }
+
+ if (addr2) {
+ if (NS_PRV_BUFTYPE(skb) == BUF_SM) {
+ if (card->sbfqc >= card->sbnr.max) {
+ skb_unlink(handle1, &card->sbpool.queue);
+ dev_kfree_skb_any(handle1);
+ skb_unlink(handle2, &card->sbpool.queue);
+ dev_kfree_skb_any(handle2);
+ return;
+ } else
+ card->sbfqc += 2;
+ } else { /* (buf_type == BUF_LG) */
+
+ if (card->lbfqc >= card->lbnr.max) {
+ skb_unlink(handle1, &card->lbpool.queue);
+ dev_kfree_skb_any(handle1);
+ skb_unlink(handle2, &card->lbpool.queue);
+ dev_kfree_skb_any(handle2);
+ return;
+ } else
+ card->lbfqc += 2;
+ }
+
+ do {
+ if (!idr_pre_get(&card->idr, GFP_ATOMIC)) {
+ printk(KERN_ERR
+ "nicstar%d: no free memory for idr\n",
+ card->index);
+ goto out;
+ }
+
+ if (!id1)
+ err = idr_get_new_above(&card->idr, handle1, 0, &id1);
+
+ if (!id2 && err == 0)
+ err = idr_get_new_above(&card->idr, handle2, 0, &id2);
+
+ } while (err == -EAGAIN);
+
+ if (err)
+ goto out;
+
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(addr2, card->membase + DR3);
+ writel(id2, card->membase + DR2);
+ writel(addr1, card->membase + DR1);
+ writel(id1, card->membase + DR0);
+ writel(NS_CMD_WRITE_FREEBUFQ | NS_PRV_BUFTYPE(skb),
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+
+ XPRINTK("nicstar%d: Pushing %s buffers at 0x%x and 0x%x.\n",
+ card->index,
+ (NS_PRV_BUFTYPE(skb) == BUF_SM ? "small" : "large"),
+ addr1, addr2);
+ }
+
+ if (!card->efbie && card->sbfqc >= card->sbnr.min &&
+ card->lbfqc >= card->lbnr.min) {
+ card->efbie = 1;
+ writel((readl(card->membase + CFG) | NS_CFG_EFBIE),
+ card->membase + CFG);
+ }
+
+out:
+ return;
}
-
-
static irqreturn_t ns_irq_handler(int irq, void *dev_id)
{
- u32 stat_r;
- ns_dev *card;
- struct atm_dev *dev;
- unsigned long flags;
-
- card = (ns_dev *) dev_id;
- dev = card->atmdev;
- card->intcnt++;
-
- PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
-
- spin_lock_irqsave(&card->int_lock, flags);
-
- stat_r = readl(card->membase + STAT);
-
- /* Transmit Status Indicator has been written to T. S. Queue */
- if (stat_r & NS_STAT_TSIF)
- {
- TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
- process_tsq(card);
- writel(NS_STAT_TSIF, card->membase + STAT);
- }
-
- /* Incomplete CS-PDU has been transmitted */
- if (stat_r & NS_STAT_TXICP)
- {
- writel(NS_STAT_TXICP, card->membase + STAT);
- TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
- card->index);
- }
-
- /* Transmit Status Queue 7/8 full */
- if (stat_r & NS_STAT_TSQF)
- {
- writel(NS_STAT_TSQF, card->membase + STAT);
- PRINTK("nicstar%d: TSQ full.\n", card->index);
- process_tsq(card);
- }
-
- /* Timer overflow */
- if (stat_r & NS_STAT_TMROF)
- {
- writel(NS_STAT_TMROF, card->membase + STAT);
- PRINTK("nicstar%d: Timer overflow.\n", card->index);
- }
-
- /* PHY device interrupt signal active */
- if (stat_r & NS_STAT_PHYI)
- {
- writel(NS_STAT_PHYI, card->membase + STAT);
- PRINTK("nicstar%d: PHY interrupt.\n", card->index);
- if (dev->phy && dev->phy->interrupt) {
- dev->phy->interrupt(dev);
- }
- }
-
- /* Small Buffer Queue is full */
- if (stat_r & NS_STAT_SFBQF)
- {
- writel(NS_STAT_SFBQF, card->membase + STAT);
- printk("nicstar%d: Small free buffer queue is full.\n", card->index);
- }
-
- /* Large Buffer Queue is full */
- if (stat_r & NS_STAT_LFBQF)
- {
- writel(NS_STAT_LFBQF, card->membase + STAT);
- printk("nicstar%d: Large free buffer queue is full.\n", card->index);
- }
-
- /* Receive Status Queue is full */
- if (stat_r & NS_STAT_RSQF)
- {
- writel(NS_STAT_RSQF, card->membase + STAT);
- printk("nicstar%d: RSQ full.\n", card->index);
- process_rsq(card);
- }
-
- /* Complete CS-PDU received */
- if (stat_r & NS_STAT_EOPDU)
- {
- RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
- process_rsq(card);
- writel(NS_STAT_EOPDU, card->membase + STAT);
- }
-
- /* Raw cell received */
- if (stat_r & NS_STAT_RAWCF)
- {
- writel(NS_STAT_RAWCF, card->membase + STAT);
+ u32 stat_r;
+ ns_dev *card;
+ struct atm_dev *dev;
+ unsigned long flags;
+
+ card = (ns_dev *) dev_id;
+ dev = card->atmdev;
+ card->intcnt++;
+
+ PRINTK("nicstar%d: NICStAR generated an interrupt\n", card->index);
+
+ spin_lock_irqsave(&card->int_lock, flags);
+
+ stat_r = readl(card->membase + STAT);
+
+ /* Transmit Status Indicator has been written to T. S. Queue */
+ if (stat_r & NS_STAT_TSIF) {
+ TXPRINTK("nicstar%d: TSI interrupt\n", card->index);
+ process_tsq(card);
+ writel(NS_STAT_TSIF, card->membase + STAT);
+ }
+
+ /* Incomplete CS-PDU has been transmitted */
+ if (stat_r & NS_STAT_TXICP) {
+ writel(NS_STAT_TXICP, card->membase + STAT);
+ TXPRINTK("nicstar%d: Incomplete CS-PDU transmitted.\n",
+ card->index);
+ }
+
+ /* Transmit Status Queue 7/8 full */
+ if (stat_r & NS_STAT_TSQF) {
+ writel(NS_STAT_TSQF, card->membase + STAT);
+ PRINTK("nicstar%d: TSQ full.\n", card->index);
+ process_tsq(card);
+ }
+
+ /* Timer overflow */
+ if (stat_r & NS_STAT_TMROF) {
+ writel(NS_STAT_TMROF, card->membase + STAT);
+ PRINTK("nicstar%d: Timer overflow.\n", card->index);
+ }
+
+ /* PHY device interrupt signal active */
+ if (stat_r & NS_STAT_PHYI) {
+ writel(NS_STAT_PHYI, card->membase + STAT);
+ PRINTK("nicstar%d: PHY interrupt.\n", card->index);
+ if (dev->phy && dev->phy->interrupt) {
+ dev->phy->interrupt(dev);
+ }
+ }
+
+ /* Small Buffer Queue is full */
+ if (stat_r & NS_STAT_SFBQF) {
+ writel(NS_STAT_SFBQF, card->membase + STAT);
+ printk("nicstar%d: Small free buffer queue is full.\n",
+ card->index);
+ }
+
+ /* Large Buffer Queue is full */
+ if (stat_r & NS_STAT_LFBQF) {
+ writel(NS_STAT_LFBQF, card->membase + STAT);
+ printk("nicstar%d: Large free buffer queue is full.\n",
+ card->index);
+ }
+
+ /* Receive Status Queue is full */
+ if (stat_r & NS_STAT_RSQF) {
+ writel(NS_STAT_RSQF, card->membase + STAT);
+ printk("nicstar%d: RSQ full.\n", card->index);
+ process_rsq(card);
+ }
+
+ /* Complete CS-PDU received */
+ if (stat_r & NS_STAT_EOPDU) {
+ RXPRINTK("nicstar%d: End of CS-PDU received.\n", card->index);
+ process_rsq(card);
+ writel(NS_STAT_EOPDU, card->membase + STAT);
+ }
+
+ /* Raw cell received */
+ if (stat_r & NS_STAT_RAWCF) {
+ writel(NS_STAT_RAWCF, card->membase + STAT);
#ifndef RCQ_SUPPORT
- printk("nicstar%d: Raw cell received and no support yet...\n",
- card->index);
+ printk("nicstar%d: Raw cell received and no support yet...\n",
+ card->index);
#endif /* RCQ_SUPPORT */
- /* NOTE: the following procedure may keep a raw cell pending until the
- next interrupt. As this preliminary support is only meant to
- avoid buffer leakage, this is not an issue. */
- while (readl(card->membase + RAWCT) != card->rawch)
- {
- ns_rcqe *rawcell;
-
- rawcell = (ns_rcqe *) bus_to_virt(card->rawch);
- if (ns_rcqe_islast(rawcell))
- {
- struct sk_buff *oldbuf;
-
- oldbuf = card->rcbuf;
- card->rcbuf = (struct sk_buff *) ns_rcqe_nextbufhandle(rawcell);
- card->rawch = (u32) virt_to_bus(card->rcbuf->data);
- recycle_rx_buf(card, oldbuf);
- }
- else
- card->rawch += NS_RCQE_SIZE;
- }
- }
-
- /* Small buffer queue is empty */
- if (stat_r & NS_STAT_SFBQE)
- {
- int i;
- struct sk_buff *sb;
-
- writel(NS_STAT_SFBQE, card->membase + STAT);
- printk("nicstar%d: Small free buffer queue empty.\n",
- card->index);
- for (i = 0; i < card->sbnr.min; i++)
- {
- sb = dev_alloc_skb(NS_SMSKBSIZE);
- if (sb == NULL)
- {
- writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
- card->efbie = 0;
- break;
- }
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- card->sbfqc = i;
- process_rsq(card);
- }
-
- /* Large buffer queue empty */
- if (stat_r & NS_STAT_LFBQE)
- {
- int i;
- struct sk_buff *lb;
-
- writel(NS_STAT_LFBQE, card->membase + STAT);
- printk("nicstar%d: Large free buffer queue empty.\n",
- card->index);
- for (i = 0; i < card->lbnr.min; i++)
- {
- lb = dev_alloc_skb(NS_LGSKBSIZE);
- if (lb == NULL)
- {
- writel(readl(card->membase + CFG) & ~NS_CFG_EFBIE, card->membase + CFG);
- card->efbie = 0;
- break;
- }
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- }
- card->lbfqc = i;
- process_rsq(card);
- }
-
- /* Receive Status Queue is 7/8 full */
- if (stat_r & NS_STAT_RSQAF)
- {
- writel(NS_STAT_RSQAF, card->membase + STAT);
- RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
- process_rsq(card);
- }
-
- spin_unlock_irqrestore(&card->int_lock, flags);
- PRINTK("nicstar%d: end of interrupt service\n", card->index);
- return IRQ_HANDLED;
+ /* NOTE: the following procedure may keep a raw cell pending until the
+ next interrupt. As this preliminary support is only meant to
+ avoid buffer leakage, this is not an issue. */
+ while (readl(card->membase + RAWCT) != card->rawch) {
+
+ if (ns_rcqe_islast(card->rawcell)) {
+ struct sk_buff *oldbuf;
+
+ oldbuf = card->rcbuf;
+ card->rcbuf = idr_find(&card->idr,
+ ns_rcqe_nextbufhandle(card->rawcell));
+ card->rawch = NS_PRV_DMA(card->rcbuf);
+ card->rawcell = (struct ns_rcqe *)
+ card->rcbuf->data;
+ recycle_rx_buf(card, oldbuf);
+ } else {
+ card->rawch += NS_RCQE_SIZE;
+ card->rawcell++;
+ }
+ }
+ }
+
+ /* Small buffer queue is empty */
+ if (stat_r & NS_STAT_SFBQE) {
+ int i;
+ struct sk_buff *sb;
+
+ writel(NS_STAT_SFBQE, card->membase + STAT);
+ printk("nicstar%d: Small free buffer queue empty.\n",
+ card->index);
+ for (i = 0; i < card->sbnr.min; i++) {
+ sb = dev_alloc_skb(NS_SMSKBSIZE);
+ if (sb == NULL) {
+ writel(readl(card->membase + CFG) &
+ ~NS_CFG_EFBIE, card->membase + CFG);
+ card->efbie = 0;
+ break;
+ }
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ card->sbfqc = i;
+ process_rsq(card);
+ }
+
+ /* Large buffer queue empty */
+ if (stat_r & NS_STAT_LFBQE) {
+ int i;
+ struct sk_buff *lb;
+
+ writel(NS_STAT_LFBQE, card->membase + STAT);
+ printk("nicstar%d: Large free buffer queue empty.\n",
+ card->index);
+ for (i = 0; i < card->lbnr.min; i++) {
+ lb = dev_alloc_skb(NS_LGSKBSIZE);
+ if (lb == NULL) {
+ writel(readl(card->membase + CFG) &
+ ~NS_CFG_EFBIE, card->membase + CFG);
+ card->efbie = 0;
+ break;
+ }
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ }
+ card->lbfqc = i;
+ process_rsq(card);
+ }
+
+ /* Receive Status Queue is 7/8 full */
+ if (stat_r & NS_STAT_RSQAF) {
+ writel(NS_STAT_RSQAF, card->membase + STAT);
+ RXPRINTK("nicstar%d: RSQ almost full.\n", card->index);
+ process_rsq(card);
+ }
+
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ PRINTK("nicstar%d: end of interrupt service\n", card->index);
+ return IRQ_HANDLED;
}
-
-
static int ns_open(struct atm_vcc *vcc)
{
- ns_dev *card;
- vc_map *vc;
- unsigned long tmpl, modl;
- int tcr, tcra; /* target cell rate, and absolute value */
- int n = 0; /* Number of entries in the TST. Initialized to remove
- the compiler warning. */
- u32 u32d[4];
- int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler
- warning. How I wish compilers were clever enough to
- tell which variables can truly be used
- uninitialized... */
- int inuse; /* tx or rx vc already in use by another vcc */
- short vpi = vcc->vpi;
- int vci = vcc->vci;
-
- card = (ns_dev *) vcc->dev->dev_data;
- PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int) vpi, vci);
- if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
- {
- PRINTK("nicstar%d: unsupported AAL.\n", card->index);
- return -EINVAL;
- }
-
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
- vcc->dev_data = vc;
-
- inuse = 0;
- if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
- inuse = 1;
- if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
- inuse += 2;
- if (inuse)
- {
- printk("nicstar%d: %s vci already in use.\n", card->index,
- inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
- return -EINVAL;
- }
-
- set_bit(ATM_VF_ADDR,&vcc->flags);
-
- /* NOTE: You are not allowed to modify an open connection's QOS. To change
- that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
- needed to do that. */
- if (!test_bit(ATM_VF_PARTIAL,&vcc->flags))
- {
- scq_info *scq;
-
- set_bit(ATM_VF_PARTIAL,&vcc->flags);
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- /* Check requested cell rate and availability of SCD */
- if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0 &&
- vcc->qos.txtp.min_pcr == 0)
- {
- PRINTK("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
- card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
-
- tcr = atm_pcr_goal(&(vcc->qos.txtp));
- tcra = tcr >= 0 ? tcr : -tcr;
-
- PRINTK("nicstar%d: target cell rate = %d.\n", card->index,
- vcc->qos.txtp.max_pcr);
-
- tmpl = (unsigned long)tcra * (unsigned long)NS_TST_NUM_ENTRIES;
- modl = tmpl % card->max_pcr;
-
- n = (int)(tmpl / card->max_pcr);
- if (tcr > 0)
- {
- if (modl > 0) n++;
- }
- else if (tcr == 0)
- {
- if ((n = (card->tst_free_entries - NS_TST_RESERVED)) <= 0)
- {
- PRINTK("nicstar%d: no CBR bandwidth free.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
- }
-
- if (n == 0)
- {
- printk("nicstar%d: selected bandwidth < granularity.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
-
- if (n > (card->tst_free_entries - NS_TST_RESERVED))
- {
- PRINTK("nicstar%d: not enough free CBR bandwidth.\n", card->index);
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EINVAL;
- }
- else
- card->tst_free_entries -= n;
-
- XPRINTK("nicstar%d: writing %d tst entries.\n", card->index, n);
- for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++)
- {
- if (card->scd2vc[frscdi] == NULL)
- {
- card->scd2vc[frscdi] = vc;
- break;
- }
- }
- if (frscdi == NS_FRSCD_NUM)
- {
- PRINTK("nicstar%d: no SCD available for CBR channel.\n", card->index);
- card->tst_free_entries += n;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -EBUSY;
- }
-
- vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
-
- scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
- if (scq == NULL)
- {
- PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
- card->scd2vc[frscdi] = NULL;
- card->tst_free_entries += n;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
- return -ENOMEM;
- }
- vc->scq = scq;
- u32d[0] = (u32) virt_to_bus(scq->base);
- u32d[1] = (u32) 0x00000000;
- u32d[2] = (u32) 0xffffffff;
- u32d[3] = (u32) 0x00000000;
- ns_write_sram(card, vc->cbr_scd, u32d, 4);
-
- fill_tst(card, n, vc);
- }
- else if (vcc->qos.txtp.traffic_class == ATM_UBR)
- {
- vc->cbr_scd = 0x00000000;
- vc->scq = card->scq0;
- }
-
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- vc->tx = 1;
- vc->tx_vcc = vcc;
- vc->tbd_count = 0;
- }
- if (vcc->qos.rxtp.traffic_class != ATM_NONE)
- {
- u32 status;
-
- vc->rx = 1;
- vc->rx_vcc = vcc;
- vc->rx_iov = NULL;
-
- /* Open the connection in hardware */
- if (vcc->qos.aal == ATM_AAL5)
- status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
- else /* vcc->qos.aal == ATM_AAL0 */
- status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
+ ns_dev *card;
+ vc_map *vc;
+ unsigned long tmpl, modl;
+ int tcr, tcra; /* target cell rate, and absolute value */
+ int n = 0; /* Number of entries in the TST. Initialized to remove
+ the compiler warning. */
+ u32 u32d[4];
+ int frscdi = 0; /* Index of the SCD. Initialized to remove the compiler
+ warning. How I wish compilers were clever enough to
+ tell which variables can truly be used
+ uninitialized... */
+ int inuse; /* tx or rx vc already in use by another vcc */
+ short vpi = vcc->vpi;
+ int vci = vcc->vci;
+
+ card = (ns_dev *) vcc->dev->dev_data;
+ PRINTK("nicstar%d: opening vpi.vci %d.%d \n", card->index, (int)vpi,
+ vci);
+ if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+ PRINTK("nicstar%d: unsupported AAL.\n", card->index);
+ return -EINVAL;
+ }
+
+ vc = &(card->vcmap[vpi << card->vcibits | vci]);
+ vcc->dev_data = vc;
+
+ inuse = 0;
+ if (vcc->qos.txtp.traffic_class != ATM_NONE && vc->tx)
+ inuse = 1;
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE && vc->rx)
+ inuse += 2;
+ if (inuse) {
+ printk("nicstar%d: %s vci already in use.\n", card->index,
+ inuse == 1 ? "tx" : inuse == 2 ? "rx" : "tx and rx");
+ return -EINVAL;
+ }
+
+ set_bit(ATM_VF_ADDR, &vcc->flags);
+
+ /* NOTE: You are not allowed to modify an open connection's QOS. To change
+ that, remove the ATM_VF_PARTIAL flag checking. There may be other changes
+ needed to do that. */
+ if (!test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
+ scq_info *scq;
+
+ set_bit(ATM_VF_PARTIAL, &vcc->flags);
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ /* Check requested cell rate and availability of SCD */
+ if (vcc->qos.txtp.max_pcr == 0 && vcc->qos.txtp.pcr == 0
+ && vcc->qos.txtp.min_pcr == 0) {
+ PRINTK
+ ("nicstar%d: trying to open a CBR vc with cell rate = 0 \n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+
+ tcr = atm_pcr_goal(&(vcc->qos.txtp));
+ tcra = tcr >= 0 ? tcr : -tcr;
+
+ PRINTK("nicstar%d: target cell rate = %d.\n",
+ card->index, vcc->qos.txtp.max_pcr);
+
+ tmpl =
+ (unsigned long)tcra *(unsigned long)
+ NS_TST_NUM_ENTRIES;
+ modl = tmpl % card->max_pcr;
+
+ n = (int)(tmpl / card->max_pcr);
+ if (tcr > 0) {
+ if (modl > 0)
+ n++;
+ } else if (tcr == 0) {
+ if ((n =
+ (card->tst_free_entries -
+ NS_TST_RESERVED)) <= 0) {
+ PRINTK
+ ("nicstar%d: no CBR bandwidth free.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+ }
+
+ if (n == 0) {
+ printk
+ ("nicstar%d: selected bandwidth < granularity.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ }
+
+ if (n > (card->tst_free_entries - NS_TST_RESERVED)) {
+ PRINTK
+ ("nicstar%d: not enough free CBR bandwidth.\n",
+ card->index);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EINVAL;
+ } else
+ card->tst_free_entries -= n;
+
+ XPRINTK("nicstar%d: writing %d tst entries.\n",
+ card->index, n);
+ for (frscdi = 0; frscdi < NS_FRSCD_NUM; frscdi++) {
+ if (card->scd2vc[frscdi] == NULL) {
+ card->scd2vc[frscdi] = vc;
+ break;
+ }
+ }
+ if (frscdi == NS_FRSCD_NUM) {
+ PRINTK
+ ("nicstar%d: no SCD available for CBR channel.\n",
+ card->index);
+ card->tst_free_entries += n;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -EBUSY;
+ }
+
+ vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
+
+ scq = get_scq(card, CBR_SCQSIZE, vc->cbr_scd);
+ if (scq == NULL) {
+ PRINTK("nicstar%d: can't get fixed rate SCQ.\n",
+ card->index);
+ card->scd2vc[frscdi] = NULL;
+ card->tst_free_entries += n;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+ return -ENOMEM;
+ }
+ vc->scq = scq;
+ u32d[0] = scq_virt_to_bus(scq, scq->base);
+ u32d[1] = (u32) 0x00000000;
+ u32d[2] = (u32) 0xffffffff;
+ u32d[3] = (u32) 0x00000000;
+ ns_write_sram(card, vc->cbr_scd, u32d, 4);
+
+ fill_tst(card, n, vc);
+ } else if (vcc->qos.txtp.traffic_class == ATM_UBR) {
+ vc->cbr_scd = 0x00000000;
+ vc->scq = card->scq0;
+ }
+
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ vc->tx = 1;
+ vc->tx_vcc = vcc;
+ vc->tbd_count = 0;
+ }
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+ u32 status;
+
+ vc->rx = 1;
+ vc->rx_vcc = vcc;
+ vc->rx_iov = NULL;
+
+ /* Open the connection in hardware */
+ if (vcc->qos.aal == ATM_AAL5)
+ status = NS_RCTE_AAL5 | NS_RCTE_CONNECTOPEN;
+ else /* vcc->qos.aal == ATM_AAL0 */
+ status = NS_RCTE_AAL0 | NS_RCTE_CONNECTOPEN;
#ifdef RCQ_SUPPORT
- status |= NS_RCTE_RAWCELLINTEN;
+ status |= NS_RCTE_RAWCELLINTEN;
#endif /* RCQ_SUPPORT */
- ns_write_sram(card, NS_RCT + (vpi << card->vcibits | vci) *
- NS_RCT_ENTRY_SIZE, &status, 1);
- }
-
- }
-
- set_bit(ATM_VF_READY,&vcc->flags);
- return 0;
-}
+ ns_write_sram(card,
+ NS_RCT +
+ (vpi << card->vcibits | vci) *
+ NS_RCT_ENTRY_SIZE, &status, 1);
+ }
+ }
+ set_bit(ATM_VF_READY, &vcc->flags);
+ return 0;
+}
static void ns_close(struct atm_vcc *vcc)
{
- vc_map *vc;
- ns_dev *card;
- u32 data;
- int i;
-
- vc = vcc->dev_data;
- card = vcc->dev->dev_data;
- PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
- (int) vcc->vpi, vcc->vci);
-
- clear_bit(ATM_VF_READY,&vcc->flags);
-
- if (vcc->qos.rxtp.traffic_class != ATM_NONE)
- {
- u32 addr;
- unsigned long flags;
-
- addr = NS_RCT + (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel(NS_CMD_CLOSE_CONNECTION | addr << 2, card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
-
- vc->rx = 0;
- if (vc->rx_iov != NULL)
- {
- struct sk_buff *iovb;
- u32 stat;
-
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- PRINTK("nicstar%d: closing a VC with pending rx buffers.\n",
- card->index);
- iovb = vc->rx_iov;
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- NS_SKB(iovb)->iovcnt = 0;
- NS_SKB(iovb)->vcc = NULL;
- spin_lock_irqsave(&card->int_lock, flags);
- recycle_iov_buf(card, iovb);
- spin_unlock_irqrestore(&card->int_lock, flags);
- vc->rx_iov = NULL;
- }
- }
-
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- vc->tx = 0;
- }
-
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- unsigned long flags;
- ns_scqe *scqep;
- scq_info *scq;
-
- scq = vc->scq;
-
- for (;;)
- {
- spin_lock_irqsave(&scq->lock, flags);
- scqep = scq->next;
- if (scqep == scq->base)
- scqep = scq->last;
- else
- scqep--;
- if (scqep == scq->tail)
- {
- spin_unlock_irqrestore(&scq->lock, flags);
- break;
- }
- /* If the last entry is not a TSR, place one in the SCQ in order to
- be able to completely drain it and then close. */
- if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next)
- {
- ns_scqe tsr;
- u32 scdi, scqi;
- u32 data;
- int index;
-
- tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
- scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
- scqi = scq->next - scq->base;
- tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
- tsr.word_3 = 0x00000000;
- tsr.word_4 = 0x00000000;
- *scq->next = tsr;
- index = (int) scqi;
- scq->skb[index] = NULL;
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
- }
- spin_unlock_irqrestore(&scq->lock, flags);
- schedule();
- }
-
- /* Free all TST entries */
- data = NS_TST_OPCODE_VARIABLE;
- for (i = 0; i < NS_TST_NUM_ENTRIES; i++)
- {
- if (card->tste2vc[i] == vc)
- {
- ns_write_sram(card, card->tst_addr + i, &data, 1);
- card->tste2vc[i] = NULL;
- card->tst_free_entries++;
- }
- }
-
- card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
- free_scq(vc->scq, vcc);
- }
-
- /* remove all references to vcc before deleting it */
- if (vcc->qos.txtp.traffic_class != ATM_NONE)
- {
- unsigned long flags;
- scq_info *scq = card->scq0;
-
- spin_lock_irqsave(&scq->lock, flags);
-
- for(i = 0; i < scq->num_entries; i++) {
- if(scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
- ATM_SKB(scq->skb[i])->vcc = NULL;
- atm_return(vcc, scq->skb[i]->truesize);
- PRINTK("nicstar: deleted pending vcc mapping\n");
- }
- }
-
- spin_unlock_irqrestore(&scq->lock, flags);
- }
-
- vcc->dev_data = NULL;
- clear_bit(ATM_VF_PARTIAL,&vcc->flags);
- clear_bit(ATM_VF_ADDR,&vcc->flags);
+ vc_map *vc;
+ ns_dev *card;
+ u32 data;
+ int i;
+
+ vc = vcc->dev_data;
+ card = vcc->dev->dev_data;
+ PRINTK("nicstar%d: closing vpi.vci %d.%d \n", card->index,
+ (int)vcc->vpi, vcc->vci);
+
+ clear_bit(ATM_VF_READY, &vcc->flags);
+
+ if (vcc->qos.rxtp.traffic_class != ATM_NONE) {
+ u32 addr;
+ unsigned long flags;
+
+ addr =
+ NS_RCT +
+ (vcc->vpi << card->vcibits | vcc->vci) * NS_RCT_ENTRY_SIZE;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_CLOSE_CONNECTION | addr << 2,
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
+
+ vc->rx = 0;
+ if (vc->rx_iov != NULL) {
+ struct sk_buff *iovb;
+ u32 stat;
+
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ PRINTK
+ ("nicstar%d: closing a VC with pending rx buffers.\n",
+ card->index);
+ iovb = vc->rx_iov;
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ NS_PRV_IOVCNT(iovb) = 0;
+ spin_lock_irqsave(&card->int_lock, flags);
+ recycle_iov_buf(card, iovb);
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ vc->rx_iov = NULL;
+ }
+ }
+
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ vc->tx = 0;
+ }
+
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ unsigned long flags;
+ ns_scqe *scqep;
+ scq_info *scq;
+
+ scq = vc->scq;
+
+ for (;;) {
+ spin_lock_irqsave(&scq->lock, flags);
+ scqep = scq->next;
+ if (scqep == scq->base)
+ scqep = scq->last;
+ else
+ scqep--;
+ if (scqep == scq->tail) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ break;
+ }
+ /* If the last entry is not a TSR, place one in the SCQ in order to
+ be able to completely drain it and then close. */
+ if (!ns_scqe_is_tsr(scqep) && scq->tail != scq->next) {
+ ns_scqe tsr;
+ u32 scdi, scqi;
+ u32 data;
+ int index;
+
+ tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+ scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+ scqi = scq->next - scq->base;
+ tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+ tsr.word_3 = 0x00000000;
+ tsr.word_4 = 0x00000000;
+ *scq->next = tsr;
+ index = (int)scqi;
+ scq->skb[index] = NULL;
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+ }
+ spin_unlock_irqrestore(&scq->lock, flags);
+ schedule();
+ }
+
+ /* Free all TST entries */
+ data = NS_TST_OPCODE_VARIABLE;
+ for (i = 0; i < NS_TST_NUM_ENTRIES; i++) {
+ if (card->tste2vc[i] == vc) {
+ ns_write_sram(card, card->tst_addr + i, &data,
+ 1);
+ card->tste2vc[i] = NULL;
+ card->tst_free_entries++;
+ }
+ }
+
+ card->scd2vc[(vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE] = NULL;
+ free_scq(card, vc->scq, vcc);
+ }
+
+ /* remove all references to vcc before deleting it */
+ if (vcc->qos.txtp.traffic_class != ATM_NONE) {
+ unsigned long flags;
+ scq_info *scq = card->scq0;
+
+ spin_lock_irqsave(&scq->lock, flags);
+
+ for (i = 0; i < scq->num_entries; i++) {
+ if (scq->skb[i] && ATM_SKB(scq->skb[i])->vcc == vcc) {
+ ATM_SKB(scq->skb[i])->vcc = NULL;
+ atm_return(vcc, scq->skb[i]->truesize);
+ PRINTK
+ ("nicstar: deleted pending vcc mapping\n");
+ }
+ }
+
+ spin_unlock_irqrestore(&scq->lock, flags);
+ }
+
+ vcc->dev_data = NULL;
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
#ifdef RX_DEBUG
- {
- u32 stat, cfg;
- stat = readl(card->membase + STAT);
- cfg = readl(card->membase + CFG);
- printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg);
- printk("TSQ: base = 0x%08X next = 0x%08X last = 0x%08X TSQT = 0x%08X \n",
- (u32) card->tsq.base, (u32) card->tsq.next,(u32) card->tsq.last,
- readl(card->membase + TSQT));
- printk("RSQ: base = 0x%08X next = 0x%08X last = 0x%08X RSQT = 0x%08X \n",
- (u32) card->rsq.base, (u32) card->rsq.next,(u32) card->rsq.last,
- readl(card->membase + RSQT));
- printk("Empty free buffer queue interrupt %s \n",
- card->efbie ? "enabled" : "disabled");
- printk("SBCNT = %d count = %d LBCNT = %d count = %d \n",
- ns_stat_sfbqc_get(stat), card->sbpool.count,
- ns_stat_lfbqc_get(stat), card->lbpool.count);
- printk("hbpool.count = %d iovpool.count = %d \n",
- card->hbpool.count, card->iovpool.count);
- }
+ {
+ u32 stat, cfg;
+ stat = readl(card->membase + STAT);
+ cfg = readl(card->membase + CFG);
+ printk("STAT = 0x%08X CFG = 0x%08X \n", stat, cfg);
+ printk
+ ("TSQ: base = 0x%p next = 0x%p last = 0x%p TSQT = 0x%08X \n",
+ card->tsq.base, card->tsq.next,
+ card->tsq.last, readl(card->membase + TSQT));
+ printk
+ ("RSQ: base = 0x%p next = 0x%p last = 0x%p RSQT = 0x%08X \n",
+ card->rsq.base, card->rsq.next,
+ card->rsq.last, readl(card->membase + RSQT));
+ printk("Empty free buffer queue interrupt %s \n",
+ card->efbie ? "enabled" : "disabled");
+ printk("SBCNT = %d count = %d LBCNT = %d count = %d \n",
+ ns_stat_sfbqc_get(stat), card->sbpool.count,
+ ns_stat_lfbqc_get(stat), card->lbpool.count);
+ printk("hbpool.count = %d iovpool.count = %d \n",
+ card->hbpool.count, card->iovpool.count);
+ }
#endif /* RX_DEBUG */
}
-
-
-static void fill_tst(ns_dev *card, int n, vc_map *vc)
+static void fill_tst(ns_dev * card, int n, vc_map * vc)
{
- u32 new_tst;
- unsigned long cl;
- int e, r;
- u32 data;
-
- /* It would be very complicated to keep the two TSTs synchronized while
- assuring that writes are only made to the inactive TST. So, for now I
- will use only one TST. If problems occur, I will change this again */
-
- new_tst = card->tst_addr;
-
- /* Fill procedure */
-
- for (e = 0; e < NS_TST_NUM_ENTRIES; e++)
- {
- if (card->tste2vc[e] == NULL)
- break;
- }
- if (e == NS_TST_NUM_ENTRIES) {
- printk("nicstar%d: No free TST entries found. \n", card->index);
- return;
- }
-
- r = n;
- cl = NS_TST_NUM_ENTRIES;
- data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
-
- while (r > 0)
- {
- if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL)
- {
- card->tste2vc[e] = vc;
- ns_write_sram(card, new_tst + e, &data, 1);
- cl -= NS_TST_NUM_ENTRIES;
- r--;
- }
-
- if (++e == NS_TST_NUM_ENTRIES) {
- e = 0;
- }
- cl += n;
- }
-
- /* End of fill procedure */
-
- data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
- ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
- ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
- card->tst_addr = new_tst;
+ u32 new_tst;
+ unsigned long cl;
+ int e, r;
+ u32 data;
+
+ /* It would be very complicated to keep the two TSTs synchronized while
+ assuring that writes are only made to the inactive TST. So, for now I
+ will use only one TST. If problems occur, I will change this again */
+
+ new_tst = card->tst_addr;
+
+ /* Fill procedure */
+
+ for (e = 0; e < NS_TST_NUM_ENTRIES; e++) {
+ if (card->tste2vc[e] == NULL)
+ break;
+ }
+ if (e == NS_TST_NUM_ENTRIES) {
+ printk("nicstar%d: No free TST entries found. \n", card->index);
+ return;
+ }
+
+ r = n;
+ cl = NS_TST_NUM_ENTRIES;
+ data = ns_tste_make(NS_TST_OPCODE_FIXED, vc->cbr_scd);
+
+ while (r > 0) {
+ if (cl >= NS_TST_NUM_ENTRIES && card->tste2vc[e] == NULL) {
+ card->tste2vc[e] = vc;
+ ns_write_sram(card, new_tst + e, &data, 1);
+ cl -= NS_TST_NUM_ENTRIES;
+ r--;
+ }
+
+ if (++e == NS_TST_NUM_ENTRIES) {
+ e = 0;
+ }
+ cl += n;
+ }
+
+ /* End of fill procedure */
+
+ data = ns_tste_make(NS_TST_OPCODE_END, new_tst);
+ ns_write_sram(card, new_tst + NS_TST_NUM_ENTRIES, &data, 1);
+ ns_write_sram(card, card->tst_addr + NS_TST_NUM_ENTRIES, &data, 1);
+ card->tst_addr = new_tst;
}
-
-
static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
- ns_dev *card;
- vc_map *vc;
- scq_info *scq;
- unsigned long buflen;
- ns_scqe scqe;
- u32 flags; /* TBD flags, not CPU flags */
-
- card = vcc->dev->dev_data;
- TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
- if ((vc = (vc_map *) vcc->dev_data) == NULL)
- {
- printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (!vc->tx)
- {
- printk("nicstar%d: Trying to transmit on a non-tx VC.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0)
- {
- printk("nicstar%d: Only AAL0 and AAL5 are supported.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- if (skb_shinfo(skb)->nr_frags != 0)
- {
- printk("nicstar%d: No scatter-gather yet.\n", card->index);
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EINVAL;
- }
-
- ATM_SKB(skb)->vcc = vcc;
-
- if (vcc->qos.aal == ATM_AAL5)
- {
- buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */
- flags = NS_TBD_AAL5;
- scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data));
- scqe.word_3 = cpu_to_le32((u32) skb->len);
- scqe.word_4 = ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
- ATM_SKB(skb)->atm_options & ATM_ATMOPT_CLP ? 1 : 0);
- flags |= NS_TBD_EOPDU;
- }
- else /* (vcc->qos.aal == ATM_AAL0) */
- {
- buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */
- flags = NS_TBD_AAL0;
- scqe.word_2 = cpu_to_le32((u32) virt_to_bus(skb->data) + NS_AAL0_HEADER);
- scqe.word_3 = cpu_to_le32(0x00000000);
- if (*skb->data & 0x02) /* Payload type 1 - end of pdu */
- flags |= NS_TBD_EOPDU;
- scqe.word_4 = cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
- /* Force the VPI/VCI to be the same as in VCC struct */
- scqe.word_4 |= cpu_to_le32((((u32) vcc->vpi) << NS_TBD_VPI_SHIFT |
- ((u32) vcc->vci) << NS_TBD_VCI_SHIFT) &
- NS_TBD_VC_MASK);
- }
-
- if (vcc->qos.txtp.traffic_class == ATM_CBR)
- {
- scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
- scq = ((vc_map *) vcc->dev_data)->scq;
- }
- else
- {
- scqe.word_1 = ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
- scq = card->scq0;
- }
-
- if (push_scqe(card, vc, scq, &scqe, skb) != 0)
- {
- atomic_inc(&vcc->stats->tx_err);
- dev_kfree_skb_any(skb);
- return -EIO;
- }
- atomic_inc(&vcc->stats->tx);
-
- return 0;
-}
-
+ ns_dev *card;
+ vc_map *vc;
+ scq_info *scq;
+ unsigned long buflen;
+ ns_scqe scqe;
+ u32 flags; /* TBD flags, not CPU flags */
+
+ card = vcc->dev->dev_data;
+ TXPRINTK("nicstar%d: ns_send() called.\n", card->index);
+ if ((vc = (vc_map *) vcc->dev_data) == NULL) {
+ printk("nicstar%d: vcc->dev_data == NULL on ns_send().\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+ if (!vc->tx) {
+ printk("nicstar%d: Trying to transmit on a non-tx VC.\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
-static int push_scqe(ns_dev *card, vc_map *vc, scq_info *scq, ns_scqe *tbd,
- struct sk_buff *skb)
-{
- unsigned long flags;
- ns_scqe tsr;
- u32 scdi, scqi;
- int scq_is_vbr;
- u32 data;
- int index;
-
- spin_lock_irqsave(&scq->lock, flags);
- while (scq->tail == scq->next)
- {
- if (in_interrupt()) {
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Error pushing TBD.\n", card->index);
- return 1;
- }
-
- scq->full = 1;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
-
- if (scq->full) {
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Timeout pushing TBD.\n", card->index);
- return 1;
- }
- }
- *scq->next = *tbd;
- index = (int) (scq->next - scq->base);
- scq->skb[index] = skb;
- XPRINTK("nicstar%d: sending skb at 0x%x (pos %d).\n",
- card->index, (u32) skb, index);
- XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
- card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
- le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
- (u32) scq->next);
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
-
- vc->tbd_count++;
- if (scq->num_entries == VBR_SCQ_NUM_ENTRIES)
- {
- scq->tbd_count++;
- scq_is_vbr = 1;
- }
- else
- scq_is_vbr = 0;
-
- if (vc->tbd_count >= MAX_TBD_PER_VC || scq->tbd_count >= MAX_TBD_PER_SCQ)
- {
- int has_run = 0;
-
- while (scq->tail == scq->next)
- {
- if (in_interrupt()) {
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
- spin_unlock_irqrestore(&scq->lock, flags);
- printk("nicstar%d: Error pushing TSR.\n", card->index);
- return 0;
- }
-
- scq->full = 1;
- if (has_run++) break;
- spin_unlock_irqrestore(&scq->lock, flags);
- interruptible_sleep_on_timeout(&scq->scqfull_waitq, SCQFULL_TIMEOUT);
- spin_lock_irqsave(&scq->lock, flags);
- }
-
- if (!scq->full)
- {
- tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
- if (scq_is_vbr)
- scdi = NS_TSR_SCDISVBR;
- else
- scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
- scqi = scq->next - scq->base;
- tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
- tsr.word_3 = 0x00000000;
- tsr.word_4 = 0x00000000;
-
- *scq->next = tsr;
- index = (int) scqi;
- scq->skb[index] = NULL;
- XPRINTK("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%x.\n",
- card->index, le32_to_cpu(tsr.word_1), le32_to_cpu(tsr.word_2),
- le32_to_cpu(tsr.word_3), le32_to_cpu(tsr.word_4),
- (u32) scq->next);
- if (scq->next == scq->last)
- scq->next = scq->base;
- else
- scq->next++;
- vc->tbd_count = 0;
- scq->tbd_count = 0;
- }
- else
- PRINTK("nicstar%d: Timeout pushing TSR.\n", card->index);
- }
- data = (u32) virt_to_bus(scq->next);
- ns_write_sram(card, scq->scd, &data, 1);
-
- spin_unlock_irqrestore(&scq->lock, flags);
-
- return 0;
-}
+ if (vcc->qos.aal != ATM_AAL5 && vcc->qos.aal != ATM_AAL0) {
+ printk("nicstar%d: Only AAL0 and AAL5 are supported.\n",
+ card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+ if (skb_shinfo(skb)->nr_frags != 0) {
+ printk("nicstar%d: No scatter-gather yet.\n", card->index);
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EINVAL;
+ }
+
+ ATM_SKB(skb)->vcc = vcc;
+
+ NS_PRV_DMA(skb) = pci_map_single(card->pcidev, skb->data,
+ skb->len, PCI_DMA_TODEVICE);
+
+ if (vcc->qos.aal == ATM_AAL5) {
+ buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */
+ flags = NS_TBD_AAL5;
+ scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb));
+ scqe.word_3 = cpu_to_le32(skb->len);
+ scqe.word_4 =
+ ns_tbd_mkword_4(0, (u32) vcc->vpi, (u32) vcc->vci, 0,
+ ATM_SKB(skb)->
+ atm_options & ATM_ATMOPT_CLP ? 1 : 0);
+ flags |= NS_TBD_EOPDU;
+ } else { /* (vcc->qos.aal == ATM_AAL0) */
+
+ buflen = ATM_CELL_PAYLOAD; /* i.e., 48 bytes */
+ flags = NS_TBD_AAL0;
+ scqe.word_2 = cpu_to_le32(NS_PRV_DMA(skb) + NS_AAL0_HEADER);
+ scqe.word_3 = cpu_to_le32(0x00000000);
+ if (*skb->data & 0x02) /* Payload type 1 - end of pdu */
+ flags |= NS_TBD_EOPDU;
+ scqe.word_4 =
+ cpu_to_le32(*((u32 *) skb->data) & ~NS_TBD_VC_MASK);
+ /* Force the VPI/VCI to be the same as in VCC struct */
+ scqe.word_4 |=
+ cpu_to_le32((((u32) vcc->
+ vpi) << NS_TBD_VPI_SHIFT | ((u32) vcc->
+ vci) <<
+ NS_TBD_VCI_SHIFT) & NS_TBD_VC_MASK);
+ }
+
+ if (vcc->qos.txtp.traffic_class == ATM_CBR) {
+ scqe.word_1 = ns_tbd_mkword_1_novbr(flags, (u32) buflen);
+ scq = ((vc_map *) vcc->dev_data)->scq;
+ } else {
+ scqe.word_1 =
+ ns_tbd_mkword_1(flags, (u32) 1, (u32) 1, (u32) buflen);
+ scq = card->scq0;
+ }
+
+ if (push_scqe(card, vc, scq, &scqe, skb) != 0) {
+ atomic_inc(&vcc->stats->tx_err);
+ dev_kfree_skb_any(skb);
+ return -EIO;
+ }
+ atomic_inc(&vcc->stats->tx);
+ return 0;
+}
-static void process_tsq(ns_dev *card)
+static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd,
+ struct sk_buff *skb)
{
- u32 scdi;
- scq_info *scq;
- ns_tsi *previous = NULL, *one_ahead, *two_ahead;
- int serviced_entries; /* flag indicating at least on entry was serviced */
-
- serviced_entries = 0;
-
- if (card->tsq.next == card->tsq.last)
- one_ahead = card->tsq.base;
- else
- one_ahead = card->tsq.next + 1;
-
- if (one_ahead == card->tsq.last)
- two_ahead = card->tsq.base;
- else
- two_ahead = one_ahead + 1;
-
- while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
- !ns_tsi_isempty(two_ahead))
- /* At most two empty, as stated in the 77201 errata */
- {
- serviced_entries = 1;
-
- /* Skip the one or two possible empty entries */
- while (ns_tsi_isempty(card->tsq.next)) {
- if (card->tsq.next == card->tsq.last)
- card->tsq.next = card->tsq.base;
- else
- card->tsq.next++;
- }
-
- if (!ns_tsi_tmrof(card->tsq.next))
- {
- scdi = ns_tsi_getscdindex(card->tsq.next);
- if (scdi == NS_TSI_SCDISVBR)
- scq = card->scq0;
- else
- {
- if (card->scd2vc[scdi] == NULL)
- {
- printk("nicstar%d: could not find VC from SCD index.\n",
- card->index);
- ns_tsi_init(card->tsq.next);
- return;
- }
- scq = card->scd2vc[scdi]->scq;
- }
- drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
- scq->full = 0;
- wake_up_interruptible(&(scq->scqfull_waitq));
- }
-
- ns_tsi_init(card->tsq.next);
- previous = card->tsq.next;
- if (card->tsq.next == card->tsq.last)
- card->tsq.next = card->tsq.base;
- else
- card->tsq.next++;
-
- if (card->tsq.next == card->tsq.last)
- one_ahead = card->tsq.base;
- else
- one_ahead = card->tsq.next + 1;
-
- if (one_ahead == card->tsq.last)
- two_ahead = card->tsq.base;
- else
- two_ahead = one_ahead + 1;
- }
-
- if (serviced_entries) {
- writel((((u32) previous) - ((u32) card->tsq.base)),
- card->membase + TSQH);
- }
+ unsigned long flags;
+ ns_scqe tsr;
+ u32 scdi, scqi;
+ int scq_is_vbr;
+ u32 data;
+ int index;
+
+ spin_lock_irqsave(&scq->lock, flags);
+ while (scq->tail == scq->next) {
+ if (in_interrupt()) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Error pushing TBD.\n", card->index);
+ return 1;
+ }
+
+ scq->full = 1;
+ spin_unlock_irqrestore(&scq->lock, flags);
+ interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+ SCQFULL_TIMEOUT);
+ spin_lock_irqsave(&scq->lock, flags);
+
+ if (scq->full) {
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Timeout pushing TBD.\n",
+ card->index);
+ return 1;
+ }
+ }
+ *scq->next = *tbd;
+ index = (int)(scq->next - scq->base);
+ scq->skb[index] = skb;
+ XPRINTK("nicstar%d: sending skb at 0x%p (pos %d).\n",
+ card->index, skb, index);
+ XPRINTK("nicstar%d: TBD written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+ card->index, le32_to_cpu(tbd->word_1), le32_to_cpu(tbd->word_2),
+ le32_to_cpu(tbd->word_3), le32_to_cpu(tbd->word_4),
+ scq->next);
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+
+ vc->tbd_count++;
+ if (scq->num_entries == VBR_SCQ_NUM_ENTRIES) {
+ scq->tbd_count++;
+ scq_is_vbr = 1;
+ } else
+ scq_is_vbr = 0;
+
+ if (vc->tbd_count >= MAX_TBD_PER_VC
+ || scq->tbd_count >= MAX_TBD_PER_SCQ) {
+ int has_run = 0;
+
+ while (scq->tail == scq->next) {
+ if (in_interrupt()) {
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+ spin_unlock_irqrestore(&scq->lock, flags);
+ printk("nicstar%d: Error pushing TSR.\n",
+ card->index);
+ return 0;
+ }
+
+ scq->full = 1;
+ if (has_run++)
+ break;
+ spin_unlock_irqrestore(&scq->lock, flags);
+ interruptible_sleep_on_timeout(&scq->scqfull_waitq,
+ SCQFULL_TIMEOUT);
+ spin_lock_irqsave(&scq->lock, flags);
+ }
+
+ if (!scq->full) {
+ tsr.word_1 = ns_tsr_mkword_1(NS_TSR_INTENABLE);
+ if (scq_is_vbr)
+ scdi = NS_TSR_SCDISVBR;
+ else
+ scdi = (vc->cbr_scd - NS_FRSCD) / NS_FRSCD_SIZE;
+ scqi = scq->next - scq->base;
+ tsr.word_2 = ns_tsr_mkword_2(scdi, scqi);
+ tsr.word_3 = 0x00000000;
+ tsr.word_4 = 0x00000000;
+
+ *scq->next = tsr;
+ index = (int)scqi;
+ scq->skb[index] = NULL;
+ XPRINTK
+ ("nicstar%d: TSR written:\n0x%x\n0x%x\n0x%x\n0x%x\n at 0x%p.\n",
+ card->index, le32_to_cpu(tsr.word_1),
+ le32_to_cpu(tsr.word_2), le32_to_cpu(tsr.word_3),
+ le32_to_cpu(tsr.word_4), scq->next);
+ if (scq->next == scq->last)
+ scq->next = scq->base;
+ else
+ scq->next++;
+ vc->tbd_count = 0;
+ scq->tbd_count = 0;
+ } else
+ PRINTK("nicstar%d: Timeout pushing TSR.\n",
+ card->index);
+ }
+ data = scq_virt_to_bus(scq, scq->next);
+ ns_write_sram(card, scq->scd, &data, 1);
+
+ spin_unlock_irqrestore(&scq->lock, flags);
+
+ return 0;
}
-
-
-static void drain_scq(ns_dev *card, scq_info *scq, int pos)
+static void process_tsq(ns_dev * card)
{
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- int i;
- unsigned long flags;
-
- XPRINTK("nicstar%d: drain_scq() called, scq at 0x%x, pos %d.\n",
- card->index, (u32) scq, pos);
- if (pos >= scq->num_entries)
- {
- printk("nicstar%d: Bad index on drain_scq().\n", card->index);
- return;
- }
-
- spin_lock_irqsave(&scq->lock, flags);
- i = (int) (scq->tail - scq->base);
- if (++i == scq->num_entries)
- i = 0;
- while (i != pos)
- {
- skb = scq->skb[i];
- XPRINTK("nicstar%d: freeing skb at 0x%x (index %d).\n",
- card->index, (u32) skb, i);
- if (skb != NULL)
- {
- vcc = ATM_SKB(skb)->vcc;
- if (vcc && vcc->pop != NULL) {
- vcc->pop(vcc, skb);
- } else {
- dev_kfree_skb_irq(skb);
- }
- scq->skb[i] = NULL;
- }
- if (++i == scq->num_entries)
- i = 0;
- }
- scq->tail = scq->base + pos;
- spin_unlock_irqrestore(&scq->lock, flags);
+ u32 scdi;
+ scq_info *scq;
+ ns_tsi *previous = NULL, *one_ahead, *two_ahead;
+ int serviced_entries; /* flag indicating at least on entry was serviced */
+
+ serviced_entries = 0;
+
+ if (card->tsq.next == card->tsq.last)
+ one_ahead = card->tsq.base;
+ else
+ one_ahead = card->tsq.next + 1;
+
+ if (one_ahead == card->tsq.last)
+ two_ahead = card->tsq.base;
+ else
+ two_ahead = one_ahead + 1;
+
+ while (!ns_tsi_isempty(card->tsq.next) || !ns_tsi_isempty(one_ahead) ||
+ !ns_tsi_isempty(two_ahead))
+ /* At most two empty, as stated in the 77201 errata */
+ {
+ serviced_entries = 1;
+
+ /* Skip the one or two possible empty entries */
+ while (ns_tsi_isempty(card->tsq.next)) {
+ if (card->tsq.next == card->tsq.last)
+ card->tsq.next = card->tsq.base;
+ else
+ card->tsq.next++;
+ }
+
+ if (!ns_tsi_tmrof(card->tsq.next)) {
+ scdi = ns_tsi_getscdindex(card->tsq.next);
+ if (scdi == NS_TSI_SCDISVBR)
+ scq = card->scq0;
+ else {
+ if (card->scd2vc[scdi] == NULL) {
+ printk
+ ("nicstar%d: could not find VC from SCD index.\n",
+ card->index);
+ ns_tsi_init(card->tsq.next);
+ return;
+ }
+ scq = card->scd2vc[scdi]->scq;
+ }
+ drain_scq(card, scq, ns_tsi_getscqpos(card->tsq.next));
+ scq->full = 0;
+ wake_up_interruptible(&(scq->scqfull_waitq));
+ }
+
+ ns_tsi_init(card->tsq.next);
+ previous = card->tsq.next;
+ if (card->tsq.next == card->tsq.last)
+ card->tsq.next = card->tsq.base;
+ else
+ card->tsq.next++;
+
+ if (card->tsq.next == card->tsq.last)
+ one_ahead = card->tsq.base;
+ else
+ one_ahead = card->tsq.next + 1;
+
+ if (one_ahead == card->tsq.last)
+ two_ahead = card->tsq.base;
+ else
+ two_ahead = one_ahead + 1;
+ }
+
+ if (serviced_entries)
+ writel(PTR_DIFF(previous, card->tsq.base),
+ card->membase + TSQH);
}
+static void drain_scq(ns_dev * card, scq_info * scq, int pos)
+{
+ struct atm_vcc *vcc;
+ struct sk_buff *skb;
+ int i;
+ unsigned long flags;
+
+ XPRINTK("nicstar%d: drain_scq() called, scq at 0x%p, pos %d.\n",
+ card->index, scq, pos);
+ if (pos >= scq->num_entries) {
+ printk("nicstar%d: Bad index on drain_scq().\n", card->index);
+ return;
+ }
+
+ spin_lock_irqsave(&scq->lock, flags);
+ i = (int)(scq->tail - scq->base);
+ if (++i == scq->num_entries)
+ i = 0;
+ while (i != pos) {
+ skb = scq->skb[i];
+ XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n",
+ card->index, skb, i);
+ if (skb != NULL) {
+ pci_unmap_single(card->pcidev,
+ NS_PRV_DMA(skb),
+ skb->len,
+ PCI_DMA_TODEVICE);
+ vcc = ATM_SKB(skb)->vcc;
+ if (vcc && vcc->pop != NULL) {
+ vcc->pop(vcc, skb);
+ } else {
+ dev_kfree_skb_irq(skb);
+ }
+ scq->skb[i] = NULL;
+ }
+ if (++i == scq->num_entries)
+ i = 0;
+ }
+ scq->tail = scq->base + pos;
+ spin_unlock_irqrestore(&scq->lock, flags);
+}
-
-static void process_rsq(ns_dev *card)
+static void process_rsq(ns_dev * card)
{
- ns_rsqe *previous;
-
- if (!ns_rsqe_valid(card->rsq.next))
- return;
- do {
- dequeue_rx(card, card->rsq.next);
- ns_rsqe_init(card->rsq.next);
- previous = card->rsq.next;
- if (card->rsq.next == card->rsq.last)
- card->rsq.next = card->rsq.base;
- else
- card->rsq.next++;
- } while (ns_rsqe_valid(card->rsq.next));
- writel((((u32) previous) - ((u32) card->rsq.base)),
- card->membase + RSQH);
+ ns_rsqe *previous;
+
+ if (!ns_rsqe_valid(card->rsq.next))
+ return;
+ do {
+ dequeue_rx(card, card->rsq.next);
+ ns_rsqe_init(card->rsq.next);
+ previous = card->rsq.next;
+ if (card->rsq.next == card->rsq.last)
+ card->rsq.next = card->rsq.base;
+ else
+ card->rsq.next++;
+ } while (ns_rsqe_valid(card->rsq.next));
+ writel(PTR_DIFF(previous, card->rsq.base), card->membase + RSQH);
}
+static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe)
+{
+ u32 vpi, vci;
+ vc_map *vc;
+ struct sk_buff *iovb;
+ struct iovec *iov;
+ struct atm_vcc *vcc;
+ struct sk_buff *skb;
+ unsigned short aal5_len;
+ int len;
+ u32 stat;
+ u32 id;
+
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ id = le32_to_cpu(rsqe->buffer_handle);
+ skb = idr_find(&card->idr, id);
+ if (!skb) {
+ RXPRINTK(KERN_ERR
+ "nicstar%d: idr_find() failed!\n", card->index);
+ return;
+ }
+ idr_remove(&card->idr, id);
+ pci_dma_sync_single_for_cpu(card->pcidev,
+ NS_PRV_DMA(skb),
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_single(card->pcidev,
+ NS_PRV_DMA(skb),
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ PCI_DMA_FROMDEVICE);
+ vpi = ns_rsqe_vpi(rsqe);
+ vci = ns_rsqe_vci(rsqe);
+ if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) {
+ printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
+ card->index, vpi, vci);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ vc = &(card->vcmap[vpi << card->vcibits | vci]);
+ if (!vc->rx) {
+ RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
+ card->index, vpi, vci);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ vcc = vc->rx_vcc;
+
+ if (vcc->qos.aal == ATM_AAL0) {
+ struct sk_buff *sb;
+ unsigned char *cell;
+ int i;
+
+ cell = skb->data;
+ for (i = ns_rsqe_cellcount(rsqe); i; i--) {
+ if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL) {
+ printk
+ ("nicstar%d: Can't allocate buffers for aal0.\n",
+ card->index);
+ atomic_add(i, &vcc->stats->rx_drop);
+ break;
+ }
+ if (!atm_charge(vcc, sb->truesize)) {
+ RXPRINTK
+ ("nicstar%d: atm_charge() dropped aal0 packets.\n",
+ card->index);
+ atomic_add(i - 1, &vcc->stats->rx_drop); /* already increased by 1 */
+ dev_kfree_skb_any(sb);
+ break;
+ }
+ /* Rebuild the header */
+ *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
+ (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
+ if (i == 1 && ns_rsqe_eopdu(rsqe))
+ *((u32 *) sb->data) |= 0x00000002;
+ skb_put(sb, NS_AAL0_HEADER);
+ memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
+ skb_put(sb, ATM_CELL_PAYLOAD);
+ ATM_SKB(sb)->vcc = vcc;
+ __net_timestamp(sb);
+ vcc->push(vcc, sb);
+ atomic_inc(&vcc->stats->rx);
+ cell += ATM_CELL_PAYLOAD;
+ }
+
+ recycle_rx_buf(card, skb);
+ return;
+ }
+
+ /* To reach this point, the AAL layer can only be AAL5 */
+
+ if ((iovb = vc->rx_iov) == NULL) {
+ iovb = skb_dequeue(&(card->iovpool.queue));
+ if (iovb == NULL) { /* No buffers in the queue */
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
+ if (iovb == NULL) {
+ printk("nicstar%d: Out of iovec buffers.\n",
+ card->index);
+ atomic_inc(&vcc->stats->rx_drop);
+ recycle_rx_buf(card, skb);
+ return;
+ }
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ } else if (--card->iovpool.count < card->iovnr.min) {
+ struct sk_buff *new_iovb;
+ if ((new_iovb =
+ alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL) {
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ skb_queue_tail(&card->iovpool.queue, new_iovb);
+ card->iovpool.count++;
+ }
+ }
+ vc->rx_iov = iovb;
+ NS_PRV_IOVCNT(iovb) = 0;
+ iovb->len = 0;
+ iovb->data = iovb->head;
+ skb_reset_tail_pointer(iovb);
+ /* IMPORTANT: a pointer to the sk_buff containing the small or large
+ buffer is stored as iovec base, NOT a pointer to the
+ small or large buffer itself. */
+ } else if (NS_PRV_IOVCNT(iovb) >= NS_MAX_IOVECS) {
+ printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_MAX_IOVECS);
+ NS_PRV_IOVCNT(iovb) = 0;
+ iovb->len = 0;
+ iovb->data = iovb->head;
+ skb_reset_tail_pointer(iovb);
+ }
+ iov = &((struct iovec *)iovb->data)[NS_PRV_IOVCNT(iovb)++];
+ iov->iov_base = (void *)skb;
+ iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
+ iovb->len += iov->iov_len;
+#ifdef EXTRA_DEBUG
+ if (NS_PRV_IOVCNT(iovb) == 1) {
+ if (NS_PRV_BUFTYPE(skb) != BUF_SM) {
+ printk
+ ("nicstar%d: Expected a small buffer, and this is not one.\n",
+ card->index);
+ which_list(card, skb);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_rx_buf(card, skb);
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+ } else { /* NS_PRV_IOVCNT(iovb) >= 2 */
+
+ if (NS_PRV_BUFTYPE(skb) != BUF_LG) {
+ printk
+ ("nicstar%d: Expected a large buffer, and this is not one.\n",
+ card->index);
+ which_list(card, skb);
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+ }
+#endif /* EXTRA_DEBUG */
-static void dequeue_rx(ns_dev *card, ns_rsqe *rsqe)
-{
- u32 vpi, vci;
- vc_map *vc;
- struct sk_buff *iovb;
- struct iovec *iov;
- struct atm_vcc *vcc;
- struct sk_buff *skb;
- unsigned short aal5_len;
- int len;
- u32 stat;
-
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- skb = (struct sk_buff *) le32_to_cpu(rsqe->buffer_handle);
- vpi = ns_rsqe_vpi(rsqe);
- vci = ns_rsqe_vci(rsqe);
- if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits)
- {
- printk("nicstar%d: SDU received for out-of-range vc %d.%d.\n",
- card->index, vpi, vci);
- recycle_rx_buf(card, skb);
- return;
- }
-
- vc = &(card->vcmap[vpi << card->vcibits | vci]);
- if (!vc->rx)
- {
- RXPRINTK("nicstar%d: SDU received on non-rx vc %d.%d.\n",
- card->index, vpi, vci);
- recycle_rx_buf(card, skb);
- return;
- }
-
- vcc = vc->rx_vcc;
-
- if (vcc->qos.aal == ATM_AAL0)
- {
- struct sk_buff *sb;
- unsigned char *cell;
- int i;
-
- cell = skb->data;
- for (i = ns_rsqe_cellcount(rsqe); i; i--)
- {
- if ((sb = dev_alloc_skb(NS_SMSKBSIZE)) == NULL)
- {
- printk("nicstar%d: Can't allocate buffers for aal0.\n",
- card->index);
- atomic_add(i,&vcc->stats->rx_drop);
- break;
- }
- if (!atm_charge(vcc, sb->truesize))
- {
- RXPRINTK("nicstar%d: atm_charge() dropped aal0 packets.\n",
- card->index);
- atomic_add(i-1,&vcc->stats->rx_drop); /* already increased by 1 */
- dev_kfree_skb_any(sb);
- break;
- }
- /* Rebuild the header */
- *((u32 *) sb->data) = le32_to_cpu(rsqe->word_1) << 4 |
- (ns_rsqe_clp(rsqe) ? 0x00000001 : 0x00000000);
- if (i == 1 && ns_rsqe_eopdu(rsqe))
- *((u32 *) sb->data) |= 0x00000002;
- skb_put(sb, NS_AAL0_HEADER);
- memcpy(skb_tail_pointer(sb), cell, ATM_CELL_PAYLOAD);
- skb_put(sb, ATM_CELL_PAYLOAD);
- ATM_SKB(sb)->vcc = vcc;
- __net_timestamp(sb);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- cell += ATM_CELL_PAYLOAD;
- }
-
- recycle_rx_buf(card, skb);
- return;
- }
-
- /* To reach this point, the AAL layer can only be AAL5 */
-
- if ((iovb = vc->rx_iov) == NULL)
- {
- iovb = skb_dequeue(&(card->iovpool.queue));
- if (iovb == NULL) /* No buffers in the queue */
- {
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC);
- if (iovb == NULL)
- {
- printk("nicstar%d: Out of iovec buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
- recycle_rx_buf(card, skb);
- return;
- }
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- }
- else
- if (--card->iovpool.count < card->iovnr.min)
- {
- struct sk_buff *new_iovb;
- if ((new_iovb = alloc_skb(NS_IOVBUFSIZE, GFP_ATOMIC)) != NULL)
- {
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->iovpool.queue, new_iovb);
- card->iovpool.count++;
- }
- }
- vc->rx_iov = iovb;
- NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->data = iovb->head;
- skb_reset_tail_pointer(iovb);
- NS_SKB(iovb)->vcc = vcc;
- /* IMPORTANT: a pointer to the sk_buff containing the small or large
- buffer is stored as iovec base, NOT a pointer to the
- small or large buffer itself. */
- }
- else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
- {
- printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
- NS_SKB(iovb)->iovcnt = 0;
- iovb->len = 0;
- iovb->data = iovb->head;
- skb_reset_tail_pointer(iovb);
- NS_SKB(iovb)->vcc = vcc;
- }
- iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
- iov->iov_base = (void *) skb;
- iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
- iovb->len += iov->iov_len;
-
- if (NS_SKB(iovb)->iovcnt == 1)
- {
- if (NS_SKB_CB(skb)->buf_type != BUF_SM)
- {
- printk("nicstar%d: Expected a small buffer, and this is not one.\n",
- card->index);
- which_list(card, skb);
- atomic_inc(&vcc->stats->rx_err);
- recycle_rx_buf(card, skb);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- }
- else /* NS_SKB(iovb)->iovcnt >= 2 */
- {
- if (NS_SKB_CB(skb)->buf_type != BUF_LG)
- {
- printk("nicstar%d: Expected a large buffer, and this is not one.\n",
- card->index);
- which_list(card, skb);
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- }
-
- if (ns_rsqe_eopdu(rsqe))
- {
- /* This works correctly regardless of the endianness of the host */
- unsigned char *L1L2 = (unsigned char *)((u32)skb->data +
- iov->iov_len - 6);
- aal5_len = L1L2[0] << 8 | L1L2[1];
- len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
- if (ns_rsqe_crcerr(rsqe) ||
- len + 8 > iovb->len || len + (47 + 8) < iovb->len)
- {
- printk("nicstar%d: AAL5 CRC error", card->index);
- if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
- printk(" - PDU size mismatch.\n");
- else
- printk(".\n");
- atomic_inc(&vcc->stats->rx_err);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
-
- /* By this point we (hopefully) have a complete SDU without errors. */
-
- if (NS_SKB(iovb)->iovcnt == 1) /* Just a small buffer */
- {
- /* skb points to a small buffer */
- if (!atm_charge(vcc, skb->truesize))
- {
- push_rxbufs(card, skb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- skb_put(skb, len);
- dequeue_sm_buf(card, skb);
+ if (ns_rsqe_eopdu(rsqe)) {
+ /* This works correctly regardless of the endianness of the host */
+ unsigned char *L1L2 = (unsigned char *)
+ (skb->data + iov->iov_len - 6);
+ aal5_len = L1L2[0] << 8 | L1L2[1];
+ len = (aal5_len == 0x0000) ? 0x10000 : aal5_len;
+ if (ns_rsqe_crcerr(rsqe) ||
+ len + 8 > iovb->len || len + (47 + 8) < iovb->len) {
+ printk("nicstar%d: AAL5 CRC error", card->index);
+ if (len + 8 > iovb->len || len + (47 + 8) < iovb->len)
+ printk(" - PDU size mismatch.\n");
+ else
+ printk(".\n");
+ atomic_inc(&vcc->stats->rx_err);
+ recycle_iovec_rx_bufs(card, (struct iovec *)iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ }
+
+ /* By this point we (hopefully) have a complete SDU without errors. */
+
+ if (NS_PRV_IOVCNT(iovb) == 1) { /* Just a small buffer */
+ /* skb points to a small buffer */
+ if (!atm_charge(vcc, skb->truesize)) {
+ push_rxbufs(card, skb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ skb_put(skb, len);
+ dequeue_sm_buf(card, skb);
#ifdef NS_USE_DESTRUCTORS
- skb->destructor = ns_sb_destructor;
+ skb->destructor = ns_sb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- ATM_SKB(skb)->vcc = vcc;
- __net_timestamp(skb);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- }
- }
- else if (NS_SKB(iovb)->iovcnt == 2) /* One small plus one large buffer */
- {
- struct sk_buff *sb;
-
- sb = (struct sk_buff *) (iov - 1)->iov_base;
- /* skb points to a large buffer */
-
- if (len <= NS_SMBUFSIZE)
- {
- if (!atm_charge(vcc, sb->truesize))
- {
- push_rxbufs(card, sb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- skb_put(sb, len);
- dequeue_sm_buf(card, sb);
+ ATM_SKB(skb)->vcc = vcc;
+ __net_timestamp(skb);
+ vcc->push(vcc, skb);
+ atomic_inc(&vcc->stats->rx);
+ }
+ } else if (NS_PRV_IOVCNT(iovb) == 2) { /* One small plus one large buffer */
+ struct sk_buff *sb;
+
+ sb = (struct sk_buff *)(iov - 1)->iov_base;
+ /* skb points to a large buffer */
+
+ if (len <= NS_SMBUFSIZE) {
+ if (!atm_charge(vcc, sb->truesize)) {
+ push_rxbufs(card, sb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ skb_put(sb, len);
+ dequeue_sm_buf(card, sb);
#ifdef NS_USE_DESTRUCTORS
- sb->destructor = ns_sb_destructor;
+ sb->destructor = ns_sb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- ATM_SKB(sb)->vcc = vcc;
- __net_timestamp(sb);
- vcc->push(vcc, sb);
- atomic_inc(&vcc->stats->rx);
- }
-
- push_rxbufs(card, skb);
-
- }
- else /* len > NS_SMBUFSIZE, the usual case */
- {
- if (!atm_charge(vcc, skb->truesize))
- {
- push_rxbufs(card, skb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- dequeue_lg_buf(card, skb);
+ ATM_SKB(sb)->vcc = vcc;
+ __net_timestamp(sb);
+ vcc->push(vcc, sb);
+ atomic_inc(&vcc->stats->rx);
+ }
+
+ push_rxbufs(card, skb);
+
+ } else { /* len > NS_SMBUFSIZE, the usual case */
+
+ if (!atm_charge(vcc, skb->truesize)) {
+ push_rxbufs(card, skb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ dequeue_lg_buf(card, skb);
#ifdef NS_USE_DESTRUCTORS
- skb->destructor = ns_lb_destructor;
+ skb->destructor = ns_lb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- skb_push(skb, NS_SMBUFSIZE);
- skb_copy_from_linear_data(sb, skb->data, NS_SMBUFSIZE);
- skb_put(skb, len - NS_SMBUFSIZE);
- ATM_SKB(skb)->vcc = vcc;
- __net_timestamp(skb);
- vcc->push(vcc, skb);
- atomic_inc(&vcc->stats->rx);
- }
-
- push_rxbufs(card, sb);
-
- }
-
- }
- else /* Must push a huge buffer */
- {
- struct sk_buff *hb, *sb, *lb;
- int remaining, tocopy;
- int j;
-
- hb = skb_dequeue(&(card->hbpool.queue));
- if (hb == NULL) /* No buffers in the queue */
- {
-
- hb = dev_alloc_skb(NS_HBUFSIZE);
- if (hb == NULL)
- {
- printk("nicstar%d: Out of huge buffers.\n", card->index);
- atomic_inc(&vcc->stats->rx_drop);
- recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
- NS_SKB(iovb)->iovcnt);
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- return;
- }
- else if (card->hbpool.count < card->hbnr.min)
- {
- struct sk_buff *new_hb;
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- }
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- }
- else
- if (--card->hbpool.count < card->hbnr.min)
- {
- struct sk_buff *new_hb;
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- if (card->hbpool.count < card->hbnr.min)
- {
- if ((new_hb = dev_alloc_skb(NS_HBUFSIZE)) != NULL)
- {
- NS_SKB_CB(new_hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, new_hb);
- card->hbpool.count++;
- }
- }
- }
-
- iov = (struct iovec *) iovb->data;
-
- if (!atm_charge(vcc, hb->truesize))
- {
- recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt);
- if (card->hbpool.count < card->hbnr.max)
- {
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
- else
- dev_kfree_skb_any(hb);
- atomic_inc(&vcc->stats->rx_drop);
- }
- else
- {
- /* Copy the small buffer to the huge buffer */
- sb = (struct sk_buff *) iov->iov_base;
- skb_copy_from_linear_data(sb, hb->data, iov->iov_len);
- skb_put(hb, iov->iov_len);
- remaining = len - iov->iov_len;
- iov++;
- /* Free the small buffer */
- push_rxbufs(card, sb);
-
- /* Copy all large buffers to the huge buffer and free them */
- for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
- {
- lb = (struct sk_buff *) iov->iov_base;
- tocopy = min_t(int, remaining, iov->iov_len);
- skb_copy_from_linear_data(lb, skb_tail_pointer(hb), tocopy);
- skb_put(hb, tocopy);
- iov++;
- remaining -= tocopy;
- push_rxbufs(card, lb);
- }
+ skb_push(skb, NS_SMBUFSIZE);
+ skb_copy_from_linear_data(sb, skb->data,
+ NS_SMBUFSIZE);
+ skb_put(skb, len - NS_SMBUFSIZE);
+ ATM_SKB(skb)->vcc = vcc;
+ __net_timestamp(skb);
+ vcc->push(vcc, skb);
+ atomic_inc(&vcc->stats->rx);
+ }
+
+ push_rxbufs(card, sb);
+
+ }
+
+ } else { /* Must push a huge buffer */
+
+ struct sk_buff *hb, *sb, *lb;
+ int remaining, tocopy;
+ int j;
+
+ hb = skb_dequeue(&(card->hbpool.queue));
+ if (hb == NULL) { /* No buffers in the queue */
+
+ hb = dev_alloc_skb(NS_HBUFSIZE);
+ if (hb == NULL) {
+ printk
+ ("nicstar%d: Out of huge buffers.\n",
+ card->index);
+ atomic_inc(&vcc->stats->rx_drop);
+ recycle_iovec_rx_bufs(card,
+ (struct iovec *)
+ iovb->data,
+ NS_PRV_IOVCNT(iovb));
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ return;
+ } else if (card->hbpool.count < card->hbnr.min) {
+ struct sk_buff *new_hb;
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) !=
+ NULL) {
+ skb_queue_tail(&card->hbpool.
+ queue, new_hb);
+ card->hbpool.count++;
+ }
+ }
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ } else if (--card->hbpool.count < card->hbnr.min) {
+ struct sk_buff *new_hb;
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue,
+ new_hb);
+ card->hbpool.count++;
+ }
+ if (card->hbpool.count < card->hbnr.min) {
+ if ((new_hb =
+ dev_alloc_skb(NS_HBUFSIZE)) !=
+ NULL) {
+ NS_PRV_BUFTYPE(new_hb) =
+ BUF_NONE;
+ skb_queue_tail(&card->hbpool.
+ queue, new_hb);
+ card->hbpool.count++;
+ }
+ }
+ }
+
+ iov = (struct iovec *)iovb->data;
+
+ if (!atm_charge(vcc, hb->truesize)) {
+ recycle_iovec_rx_bufs(card, iov,
+ NS_PRV_IOVCNT(iovb));
+ if (card->hbpool.count < card->hbnr.max) {
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ } else
+ dev_kfree_skb_any(hb);
+ atomic_inc(&vcc->stats->rx_drop);
+ } else {
+ /* Copy the small buffer to the huge buffer */
+ sb = (struct sk_buff *)iov->iov_base;
+ skb_copy_from_linear_data(sb, hb->data,
+ iov->iov_len);
+ skb_put(hb, iov->iov_len);
+ remaining = len - iov->iov_len;
+ iov++;
+ /* Free the small buffer */
+ push_rxbufs(card, sb);
+
+ /* Copy all large buffers to the huge buffer and free them */
+ for (j = 1; j < NS_PRV_IOVCNT(iovb); j++) {
+ lb = (struct sk_buff *)iov->iov_base;
+ tocopy =
+ min_t(int, remaining, iov->iov_len);
+ skb_copy_from_linear_data(lb,
+ skb_tail_pointer
+ (hb), tocopy);
+ skb_put(hb, tocopy);
+ iov++;
+ remaining -= tocopy;
+ push_rxbufs(card, lb);
+ }
#ifdef EXTRA_DEBUG
- if (remaining != 0 || hb->len != len)
- printk("nicstar%d: Huge buffer len mismatch.\n", card->index);
+ if (remaining != 0 || hb->len != len)
+ printk
+ ("nicstar%d: Huge buffer len mismatch.\n",
+ card->index);
#endif /* EXTRA_DEBUG */
- ATM_SKB(hb)->vcc = vcc;
+ ATM_SKB(hb)->vcc = vcc;
#ifdef NS_USE_DESTRUCTORS
- hb->destructor = ns_hb_destructor;
+ hb->destructor = ns_hb_destructor;
#endif /* NS_USE_DESTRUCTORS */
- __net_timestamp(hb);
- vcc->push(vcc, hb);
- atomic_inc(&vcc->stats->rx);
- }
- }
+ __net_timestamp(hb);
+ vcc->push(vcc, hb);
+ atomic_inc(&vcc->stats->rx);
+ }
+ }
- vc->rx_iov = NULL;
- recycle_iov_buf(card, iovb);
- }
+ vc->rx_iov = NULL;
+ recycle_iov_buf(card, iovb);
+ }
}
-
-
#ifdef NS_USE_DESTRUCTORS
static void ns_sb_destructor(struct sk_buff *sb)
{
- ns_dev *card;
- u32 stat;
-
- card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- do
- {
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- break;
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- } while (card->sbfqc < card->sbnr.min);
+ ns_dev *card;
+ u32 stat;
+
+ card = (ns_dev *) ATM_SKB(sb)->vcc->dev->dev_data;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ do {
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL)
+ break;
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ } while (card->sbfqc < card->sbnr.min);
}
-
-
static void ns_lb_destructor(struct sk_buff *lb)
{
- ns_dev *card;
- u32 stat;
-
- card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
- stat = readl(card->membase + STAT);
- card->sbfqc = ns_stat_sfbqc_get(stat);
- card->lbfqc = ns_stat_lfbqc_get(stat);
-
- do
- {
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- break;
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- } while (card->lbfqc < card->lbnr.min);
+ ns_dev *card;
+ u32 stat;
+
+ card = (ns_dev *) ATM_SKB(lb)->vcc->dev->dev_data;
+ stat = readl(card->membase + STAT);
+ card->sbfqc = ns_stat_sfbqc_get(stat);
+ card->lbfqc = ns_stat_lfbqc_get(stat);
+
+ do {
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL)
+ break;
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ } while (card->lbfqc < card->lbnr.min);
}
-
-
static void ns_hb_destructor(struct sk_buff *hb)
{
- ns_dev *card;
-
- card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
-
- while (card->hbpool.count < card->hbnr.init)
- {
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- break;
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- }
+ ns_dev *card;
+
+ card = (ns_dev *) ATM_SKB(hb)->vcc->dev->dev_data;
+
+ while (card->hbpool.count < card->hbnr.init) {
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL)
+ break;
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ }
}
#endif /* NS_USE_DESTRUCTORS */
-
-static void recycle_rx_buf(ns_dev *card, struct sk_buff *skb)
+static void recycle_rx_buf(ns_dev * card, struct sk_buff *skb)
{
- struct ns_skb_cb *cb = NS_SKB_CB(skb);
-
- if (unlikely(cb->buf_type == BUF_NONE)) {
- printk("nicstar%d: What kind of rx buffer is this?\n", card->index);
+ if (unlikely(NS_PRV_BUFTYPE(skb) == BUF_NONE)) {
+ printk("nicstar%d: What kind of rx buffer is this?\n",
+ card->index);
dev_kfree_skb_any(skb);
} else
push_rxbufs(card, skb);
}
-
-static void recycle_iovec_rx_bufs(ns_dev *card, struct iovec *iov, int count)
+static void recycle_iovec_rx_bufs(ns_dev * card, struct iovec *iov, int count)
{
while (count-- > 0)
- recycle_rx_buf(card, (struct sk_buff *) (iov++)->iov_base);
+ recycle_rx_buf(card, (struct sk_buff *)(iov++)->iov_base);
}
-
-static void recycle_iov_buf(ns_dev *card, struct sk_buff *iovb)
+static void recycle_iov_buf(ns_dev * card, struct sk_buff *iovb)
{
- if (card->iovpool.count < card->iovnr.max)
- {
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- }
- else
- dev_kfree_skb_any(iovb);
+ if (card->iovpool.count < card->iovnr.max) {
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ } else
+ dev_kfree_skb_any(iovb);
}
-
-
-static void dequeue_sm_buf(ns_dev *card, struct sk_buff *sb)
+static void dequeue_sm_buf(ns_dev * card, struct sk_buff *sb)
{
- skb_unlink(sb, &card->sbpool.queue);
+ skb_unlink(sb, &card->sbpool.queue);
#ifdef NS_USE_DESTRUCTORS
- if (card->sbfqc < card->sbnr.min)
+ if (card->sbfqc < card->sbnr.min)
#else
- if (card->sbfqc < card->sbnr.init)
- {
- struct sk_buff *new_sb;
- if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, new_sb);
- skb_reserve(new_sb, NS_AAL0_HEADER);
- push_rxbufs(card, new_sb);
- }
- }
- if (card->sbfqc < card->sbnr.init)
+ if (card->sbfqc < card->sbnr.init) {
+ struct sk_buff *new_sb;
+ if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, new_sb);
+ skb_reserve(new_sb, NS_AAL0_HEADER);
+ push_rxbufs(card, new_sb);
+ }
+ }
+ if (card->sbfqc < card->sbnr.init)
#endif /* NS_USE_DESTRUCTORS */
- {
- struct sk_buff *new_sb;
- if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, new_sb);
- skb_reserve(new_sb, NS_AAL0_HEADER);
- push_rxbufs(card, new_sb);
- }
- }
+ {
+ struct sk_buff *new_sb;
+ if ((new_sb = dev_alloc_skb(NS_SMSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, new_sb);
+ skb_reserve(new_sb, NS_AAL0_HEADER);
+ push_rxbufs(card, new_sb);
+ }
+ }
}
-
-
-static void dequeue_lg_buf(ns_dev *card, struct sk_buff *lb)
+static void dequeue_lg_buf(ns_dev * card, struct sk_buff *lb)
{
- skb_unlink(lb, &card->lbpool.queue);
+ skb_unlink(lb, &card->lbpool.queue);
#ifdef NS_USE_DESTRUCTORS
- if (card->lbfqc < card->lbnr.min)
+ if (card->lbfqc < card->lbnr.min)
#else
- if (card->lbfqc < card->lbnr.init)
- {
- struct sk_buff *new_lb;
- if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, new_lb);
- skb_reserve(new_lb, NS_SMBUFSIZE);
- push_rxbufs(card, new_lb);
- }
- }
- if (card->lbfqc < card->lbnr.init)
+ if (card->lbfqc < card->lbnr.init) {
+ struct sk_buff *new_lb;
+ if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, new_lb);
+ skb_reserve(new_lb, NS_SMBUFSIZE);
+ push_rxbufs(card, new_lb);
+ }
+ }
+ if (card->lbfqc < card->lbnr.init)
#endif /* NS_USE_DESTRUCTORS */
- {
- struct sk_buff *new_lb;
- if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL)
- {
- NS_SKB_CB(new_lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, new_lb);
- skb_reserve(new_lb, NS_SMBUFSIZE);
- push_rxbufs(card, new_lb);
- }
- }
+ {
+ struct sk_buff *new_lb;
+ if ((new_lb = dev_alloc_skb(NS_LGSKBSIZE)) != NULL) {
+ NS_PRV_BUFTYPE(new_lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, new_lb);
+ skb_reserve(new_lb, NS_SMBUFSIZE);
+ push_rxbufs(card, new_lb);
+ }
+ }
}
-
-
-static int ns_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
+static int ns_proc_read(struct atm_dev *dev, loff_t * pos, char *page)
{
- u32 stat;
- ns_dev *card;
- int left;
-
- left = (int) *pos;
- card = (ns_dev *) dev->dev_data;
- stat = readl(card->membase + STAT);
- if (!left--)
- return sprintf(page, "Pool count min init max \n");
- if (!left--)
- return sprintf(page, "Small %5d %5d %5d %5d \n",
- ns_stat_sfbqc_get(stat), card->sbnr.min, card->sbnr.init,
- card->sbnr.max);
- if (!left--)
- return sprintf(page, "Large %5d %5d %5d %5d \n",
- ns_stat_lfbqc_get(stat), card->lbnr.min, card->lbnr.init,
- card->lbnr.max);
- if (!left--)
- return sprintf(page, "Huge %5d %5d %5d %5d \n", card->hbpool.count,
- card->hbnr.min, card->hbnr.init, card->hbnr.max);
- if (!left--)
- return sprintf(page, "Iovec %5d %5d %5d %5d \n", card->iovpool.count,
- card->iovnr.min, card->iovnr.init, card->iovnr.max);
- if (!left--)
- {
- int retval;
- retval = sprintf(page, "Interrupt counter: %u \n", card->intcnt);
- card->intcnt = 0;
- return retval;
- }
+ u32 stat;
+ ns_dev *card;
+ int left;
+
+ left = (int)*pos;
+ card = (ns_dev *) dev->dev_data;
+ stat = readl(card->membase + STAT);
+ if (!left--)
+ return sprintf(page, "Pool count min init max \n");
+ if (!left--)
+ return sprintf(page, "Small %5d %5d %5d %5d \n",
+ ns_stat_sfbqc_get(stat), card->sbnr.min,
+ card->sbnr.init, card->sbnr.max);
+ if (!left--)
+ return sprintf(page, "Large %5d %5d %5d %5d \n",
+ ns_stat_lfbqc_get(stat), card->lbnr.min,
+ card->lbnr.init, card->lbnr.max);
+ if (!left--)
+ return sprintf(page, "Huge %5d %5d %5d %5d \n",
+ card->hbpool.count, card->hbnr.min,
+ card->hbnr.init, card->hbnr.max);
+ if (!left--)
+ return sprintf(page, "Iovec %5d %5d %5d %5d \n",
+ card->iovpool.count, card->iovnr.min,
+ card->iovnr.init, card->iovnr.max);
+ if (!left--) {
+ int retval;
+ retval =
+ sprintf(page, "Interrupt counter: %u \n", card->intcnt);
+ card->intcnt = 0;
+ return retval;
+ }
#if 0
- /* Dump 25.6 Mbps PHY registers */
- /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
- here just in case it's needed for debugging. */
- if (card->max_pcr == ATM_25_PCR && !left--)
- {
- u32 phy_regs[4];
- u32 i;
-
- for (i = 0; i < 4; i++)
- {
- while (CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200 | i, card->membase + CMD);
- while (CMD_BUSY(card));
- phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
- }
-
- return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
- phy_regs[0], phy_regs[1], phy_regs[2], phy_regs[3]);
- }
+ /* Dump 25.6 Mbps PHY registers */
+ /* Now there's a 25.6 Mbps PHY driver this code isn't needed. I left it
+ here just in case it's needed for debugging. */
+ if (card->max_pcr == ATM_25_PCR && !left--) {
+ u32 phy_regs[4];
+ u32 i;
+
+ for (i = 0; i < 4; i++) {
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200 | i,
+ card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ phy_regs[i] = readl(card->membase + DR0) & 0x000000FF;
+ }
+
+ return sprintf(page, "PHY regs: 0x%02X 0x%02X 0x%02X 0x%02X \n",
+ phy_regs[0], phy_regs[1], phy_regs[2],
+ phy_regs[3]);
+ }
#endif /* 0 - Dump 25.6 Mbps PHY registers */
#if 0
- /* Dump TST */
- if (left-- < NS_TST_NUM_ENTRIES)
- {
- if (card->tste2vc[left + 1] == NULL)
- return sprintf(page, "%5d - VBR/UBR \n", left + 1);
- else
- return sprintf(page, "%5d - %d %d \n", left + 1,
- card->tste2vc[left + 1]->tx_vcc->vpi,
- card->tste2vc[left + 1]->tx_vcc->vci);
- }
+ /* Dump TST */
+ if (left-- < NS_TST_NUM_ENTRIES) {
+ if (card->tste2vc[left + 1] == NULL)
+ return sprintf(page, "%5d - VBR/UBR \n", left + 1);
+ else
+ return sprintf(page, "%5d - %d %d \n", left + 1,
+ card->tste2vc[left + 1]->tx_vcc->vpi,
+ card->tste2vc[left + 1]->tx_vcc->vci);
+ }
#endif /* 0 */
- return 0;
+ return 0;
}
-
-
-static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg)
+static int ns_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg)
{
- ns_dev *card;
- pool_levels pl;
- long btype;
- unsigned long flags;
-
- card = dev->dev_data;
- switch (cmd)
- {
- case NS_GETPSTAT:
- if (get_user(pl.buftype, &((pool_levels __user *) arg)->buftype))
- return -EFAULT;
- switch (pl.buftype)
- {
- case NS_BUFTYPE_SMALL:
- pl.count = ns_stat_sfbqc_get(readl(card->membase + STAT));
- pl.level.min = card->sbnr.min;
- pl.level.init = card->sbnr.init;
- pl.level.max = card->sbnr.max;
- break;
-
- case NS_BUFTYPE_LARGE:
- pl.count = ns_stat_lfbqc_get(readl(card->membase + STAT));
- pl.level.min = card->lbnr.min;
- pl.level.init = card->lbnr.init;
- pl.level.max = card->lbnr.max;
- break;
-
- case NS_BUFTYPE_HUGE:
- pl.count = card->hbpool.count;
- pl.level.min = card->hbnr.min;
- pl.level.init = card->hbnr.init;
- pl.level.max = card->hbnr.max;
- break;
-
- case NS_BUFTYPE_IOVEC:
- pl.count = card->iovpool.count;
- pl.level.min = card->iovnr.min;
- pl.level.init = card->iovnr.init;
- pl.level.max = card->iovnr.max;
- break;
-
- default:
- return -ENOIOCTLCMD;
-
- }
- if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
- return (sizeof(pl));
- else
- return -EFAULT;
-
- case NS_SETBUFLEV:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
- return -EFAULT;
- if (pl.level.min >= pl.level.init || pl.level.init >= pl.level.max)
- return -EINVAL;
- if (pl.level.min == 0)
- return -EINVAL;
- switch (pl.buftype)
- {
- case NS_BUFTYPE_SMALL:
- if (pl.level.max > TOP_SB)
- return -EINVAL;
- card->sbnr.min = pl.level.min;
- card->sbnr.init = pl.level.init;
- card->sbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_LARGE:
- if (pl.level.max > TOP_LB)
- return -EINVAL;
- card->lbnr.min = pl.level.min;
- card->lbnr.init = pl.level.init;
- card->lbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_HUGE:
- if (pl.level.max > TOP_HB)
- return -EINVAL;
- card->hbnr.min = pl.level.min;
- card->hbnr.init = pl.level.init;
- card->hbnr.max = pl.level.max;
- break;
-
- case NS_BUFTYPE_IOVEC:
- if (pl.level.max > TOP_IOVB)
- return -EINVAL;
- card->iovnr.min = pl.level.min;
- card->iovnr.init = pl.level.init;
- card->iovnr.max = pl.level.max;
- break;
-
- default:
- return -EINVAL;
-
- }
- return 0;
-
- case NS_ADJBUFLEV:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- btype = (long) arg; /* a long is the same size as a pointer or bigger */
- switch (btype)
- {
- case NS_BUFTYPE_SMALL:
- while (card->sbfqc < card->sbnr.init)
- {
- struct sk_buff *sb;
-
- sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
- if (sb == NULL)
- return -ENOMEM;
- NS_SKB_CB(sb)->buf_type = BUF_SM;
- skb_queue_tail(&card->sbpool.queue, sb);
- skb_reserve(sb, NS_AAL0_HEADER);
- push_rxbufs(card, sb);
- }
- break;
-
- case NS_BUFTYPE_LARGE:
- while (card->lbfqc < card->lbnr.init)
- {
- struct sk_buff *lb;
-
- lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
- if (lb == NULL)
- return -ENOMEM;
- NS_SKB_CB(lb)->buf_type = BUF_LG;
- skb_queue_tail(&card->lbpool.queue, lb);
- skb_reserve(lb, NS_SMBUFSIZE);
- push_rxbufs(card, lb);
- }
- break;
-
- case NS_BUFTYPE_HUGE:
- while (card->hbpool.count > card->hbnr.init)
- {
- struct sk_buff *hb;
-
- spin_lock_irqsave(&card->int_lock, flags);
- hb = skb_dequeue(&card->hbpool.queue);
- card->hbpool.count--;
- spin_unlock_irqrestore(&card->int_lock, flags);
- if (hb == NULL)
- printk("nicstar%d: huge buffer count inconsistent.\n",
- card->index);
- else
- dev_kfree_skb_any(hb);
-
- }
- while (card->hbpool.count < card->hbnr.init)
- {
- struct sk_buff *hb;
-
- hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
- if (hb == NULL)
- return -ENOMEM;
- NS_SKB_CB(hb)->buf_type = BUF_NONE;
- spin_lock_irqsave(&card->int_lock, flags);
- skb_queue_tail(&card->hbpool.queue, hb);
- card->hbpool.count++;
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- break;
-
- case NS_BUFTYPE_IOVEC:
- while (card->iovpool.count > card->iovnr.init)
- {
- struct sk_buff *iovb;
-
- spin_lock_irqsave(&card->int_lock, flags);
- iovb = skb_dequeue(&card->iovpool.queue);
- card->iovpool.count--;
- spin_unlock_irqrestore(&card->int_lock, flags);
- if (iovb == NULL)
- printk("nicstar%d: iovec buffer count inconsistent.\n",
- card->index);
- else
- dev_kfree_skb_any(iovb);
-
- }
- while (card->iovpool.count < card->iovnr.init)
- {
- struct sk_buff *iovb;
-
- iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
- if (iovb == NULL)
- return -ENOMEM;
- NS_SKB_CB(iovb)->buf_type = BUF_NONE;
- spin_lock_irqsave(&card->int_lock, flags);
- skb_queue_tail(&card->iovpool.queue, iovb);
- card->iovpool.count++;
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- break;
-
- default:
- return -EINVAL;
-
- }
- return 0;
-
- default:
- if (dev->phy && dev->phy->ioctl) {
- return dev->phy->ioctl(dev, cmd, arg);
- }
- else {
- printk("nicstar%d: %s == NULL \n", card->index,
- dev->phy ? "dev->phy->ioctl" : "dev->phy");
- return -ENOIOCTLCMD;
- }
- }
+ ns_dev *card;
+ pool_levels pl;
+ long btype;
+ unsigned long flags;
+
+ card = dev->dev_data;
+ switch (cmd) {
+ case NS_GETPSTAT:
+ if (get_user
+ (pl.buftype, &((pool_levels __user *) arg)->buftype))
+ return -EFAULT;
+ switch (pl.buftype) {
+ case NS_BUFTYPE_SMALL:
+ pl.count =
+ ns_stat_sfbqc_get(readl(card->membase + STAT));
+ pl.level.min = card->sbnr.min;
+ pl.level.init = card->sbnr.init;
+ pl.level.max = card->sbnr.max;
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ pl.count =
+ ns_stat_lfbqc_get(readl(card->membase + STAT));
+ pl.level.min = card->lbnr.min;
+ pl.level.init = card->lbnr.init;
+ pl.level.max = card->lbnr.max;
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ pl.count = card->hbpool.count;
+ pl.level.min = card->hbnr.min;
+ pl.level.init = card->hbnr.init;
+ pl.level.max = card->hbnr.max;
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ pl.count = card->iovpool.count;
+ pl.level.min = card->iovnr.min;
+ pl.level.init = card->iovnr.init;
+ pl.level.max = card->iovnr.max;
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+
+ }
+ if (!copy_to_user((pool_levels __user *) arg, &pl, sizeof(pl)))
+ return (sizeof(pl));
+ else
+ return -EFAULT;
+
+ case NS_SETBUFLEV:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (copy_from_user(&pl, (pool_levels __user *) arg, sizeof(pl)))
+ return -EFAULT;
+ if (pl.level.min >= pl.level.init
+ || pl.level.init >= pl.level.max)
+ return -EINVAL;
+ if (pl.level.min == 0)
+ return -EINVAL;
+ switch (pl.buftype) {
+ case NS_BUFTYPE_SMALL:
+ if (pl.level.max > TOP_SB)
+ return -EINVAL;
+ card->sbnr.min = pl.level.min;
+ card->sbnr.init = pl.level.init;
+ card->sbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ if (pl.level.max > TOP_LB)
+ return -EINVAL;
+ card->lbnr.min = pl.level.min;
+ card->lbnr.init = pl.level.init;
+ card->lbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ if (pl.level.max > TOP_HB)
+ return -EINVAL;
+ card->hbnr.min = pl.level.min;
+ card->hbnr.init = pl.level.init;
+ card->hbnr.max = pl.level.max;
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ if (pl.level.max > TOP_IOVB)
+ return -EINVAL;
+ card->iovnr.min = pl.level.min;
+ card->iovnr.init = pl.level.init;
+ card->iovnr.max = pl.level.max;
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return 0;
+
+ case NS_ADJBUFLEV:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ btype = (long)arg; /* a long is the same size as a pointer or bigger */
+ switch (btype) {
+ case NS_BUFTYPE_SMALL:
+ while (card->sbfqc < card->sbnr.init) {
+ struct sk_buff *sb;
+
+ sb = __dev_alloc_skb(NS_SMSKBSIZE, GFP_KERNEL);
+ if (sb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(sb) = BUF_SM;
+ skb_queue_tail(&card->sbpool.queue, sb);
+ skb_reserve(sb, NS_AAL0_HEADER);
+ push_rxbufs(card, sb);
+ }
+ break;
+
+ case NS_BUFTYPE_LARGE:
+ while (card->lbfqc < card->lbnr.init) {
+ struct sk_buff *lb;
+
+ lb = __dev_alloc_skb(NS_LGSKBSIZE, GFP_KERNEL);
+ if (lb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(lb) = BUF_LG;
+ skb_queue_tail(&card->lbpool.queue, lb);
+ skb_reserve(lb, NS_SMBUFSIZE);
+ push_rxbufs(card, lb);
+ }
+ break;
+
+ case NS_BUFTYPE_HUGE:
+ while (card->hbpool.count > card->hbnr.init) {
+ struct sk_buff *hb;
+
+ spin_lock_irqsave(&card->int_lock, flags);
+ hb = skb_dequeue(&card->hbpool.queue);
+ card->hbpool.count--;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ if (hb == NULL)
+ printk
+ ("nicstar%d: huge buffer count inconsistent.\n",
+ card->index);
+ else
+ dev_kfree_skb_any(hb);
+
+ }
+ while (card->hbpool.count < card->hbnr.init) {
+ struct sk_buff *hb;
+
+ hb = __dev_alloc_skb(NS_HBUFSIZE, GFP_KERNEL);
+ if (hb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(hb) = BUF_NONE;
+ spin_lock_irqsave(&card->int_lock, flags);
+ skb_queue_tail(&card->hbpool.queue, hb);
+ card->hbpool.count++;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ break;
+
+ case NS_BUFTYPE_IOVEC:
+ while (card->iovpool.count > card->iovnr.init) {
+ struct sk_buff *iovb;
+
+ spin_lock_irqsave(&card->int_lock, flags);
+ iovb = skb_dequeue(&card->iovpool.queue);
+ card->iovpool.count--;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ if (iovb == NULL)
+ printk
+ ("nicstar%d: iovec buffer count inconsistent.\n",
+ card->index);
+ else
+ dev_kfree_skb_any(iovb);
+
+ }
+ while (card->iovpool.count < card->iovnr.init) {
+ struct sk_buff *iovb;
+
+ iovb = alloc_skb(NS_IOVBUFSIZE, GFP_KERNEL);
+ if (iovb == NULL)
+ return -ENOMEM;
+ NS_PRV_BUFTYPE(iovb) = BUF_NONE;
+ spin_lock_irqsave(&card->int_lock, flags);
+ skb_queue_tail(&card->iovpool.queue, iovb);
+ card->iovpool.count++;
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ return 0;
+
+ default:
+ if (dev->phy && dev->phy->ioctl) {
+ return dev->phy->ioctl(dev, cmd, arg);
+ } else {
+ printk("nicstar%d: %s == NULL \n", card->index,
+ dev->phy ? "dev->phy->ioctl" : "dev->phy");
+ return -ENOIOCTLCMD;
+ }
+ }
}
-
-static void which_list(ns_dev *card, struct sk_buff *skb)
+#ifdef EXTRA_DEBUG
+static void which_list(ns_dev * card, struct sk_buff *skb)
{
- printk("skb buf_type: 0x%08x\n", NS_SKB_CB(skb)->buf_type);
+ printk("skb buf_type: 0x%08x\n", NS_PRV_BUFTYPE(skb));
}
-
+#endif /* EXTRA_DEBUG */
static void ns_poll(unsigned long arg)
{
- int i;
- ns_dev *card;
- unsigned long flags;
- u32 stat_r, stat_w;
-
- PRINTK("nicstar: Entering ns_poll().\n");
- for (i = 0; i < num_cards; i++)
- {
- card = cards[i];
- if (spin_is_locked(&card->int_lock)) {
- /* Probably it isn't worth spinning */
- continue;
- }
- spin_lock_irqsave(&card->int_lock, flags);
-
- stat_w = 0;
- stat_r = readl(card->membase + STAT);
- if (stat_r & NS_STAT_TSIF)
- stat_w |= NS_STAT_TSIF;
- if (stat_r & NS_STAT_EOPDU)
- stat_w |= NS_STAT_EOPDU;
-
- process_tsq(card);
- process_rsq(card);
-
- writel(stat_w, card->membase + STAT);
- spin_unlock_irqrestore(&card->int_lock, flags);
- }
- mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
- PRINTK("nicstar: Leaving ns_poll().\n");
+ int i;
+ ns_dev *card;
+ unsigned long flags;
+ u32 stat_r, stat_w;
+
+ PRINTK("nicstar: Entering ns_poll().\n");
+ for (i = 0; i < num_cards; i++) {
+ card = cards[i];
+ if (spin_is_locked(&card->int_lock)) {
+ /* Probably it isn't worth spinning */
+ continue;
+ }
+ spin_lock_irqsave(&card->int_lock, flags);
+
+ stat_w = 0;
+ stat_r = readl(card->membase + STAT);
+ if (stat_r & NS_STAT_TSIF)
+ stat_w |= NS_STAT_TSIF;
+ if (stat_r & NS_STAT_EOPDU)
+ stat_w |= NS_STAT_EOPDU;
+
+ process_tsq(card);
+ process_rsq(card);
+
+ writel(stat_w, card->membase + STAT);
+ spin_unlock_irqrestore(&card->int_lock, flags);
+ }
+ mod_timer(&ns_timer, jiffies + NS_POLL_PERIOD);
+ PRINTK("nicstar: Leaving ns_poll().\n");
}
-
-
static int ns_parse_mac(char *mac, unsigned char *esi)
{
- int i, j;
- short byte1, byte0;
-
- if (mac == NULL || esi == NULL)
- return -1;
- j = 0;
- for (i = 0; i < 6; i++)
- {
- if ((byte1 = ns_h2i(mac[j++])) < 0)
- return -1;
- if ((byte0 = ns_h2i(mac[j++])) < 0)
- return -1;
- esi[i] = (unsigned char) (byte1 * 16 + byte0);
- if (i < 5)
- {
- if (mac[j++] != ':')
- return -1;
- }
- }
- return 0;
+ int i, j;
+ short byte1, byte0;
+
+ if (mac == NULL || esi == NULL)
+ return -1;
+ j = 0;
+ for (i = 0; i < 6; i++) {
+ if ((byte1 = ns_h2i(mac[j++])) < 0)
+ return -1;
+ if ((byte0 = ns_h2i(mac[j++])) < 0)
+ return -1;
+ esi[i] = (unsigned char)(byte1 * 16 + byte0);
+ if (i < 5) {
+ if (mac[j++] != ':')
+ return -1;
+ }
+ }
+ return 0;
}
-
-
static short ns_h2i(char c)
{
- if (c >= '0' && c <= '9')
- return (short) (c - '0');
- if (c >= 'A' && c <= 'F')
- return (short) (c - 'A' + 10);
- if (c >= 'a' && c <= 'f')
- return (short) (c - 'a' + 10);
- return -1;
+ if (c >= '0' && c <= '9')
+ return (short)(c - '0');
+ if (c >= 'A' && c <= 'F')
+ return (short)(c - 'A' + 10);
+ if (c >= 'a' && c <= 'f')
+ return (short)(c - 'a' + 10);
+ return -1;
}
-
-
static void ns_phy_put(struct atm_dev *dev, unsigned char value,
- unsigned long addr)
+ unsigned long addr)
{
- ns_dev *card;
- unsigned long flags;
-
- card = dev->dev_data;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel((unsigned long) value, card->membase + DR0);
- writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
- card->membase + CMD);
- spin_unlock_irqrestore(&card->res_lock, flags);
+ ns_dev *card;
+ unsigned long flags;
+
+ card = dev->dev_data;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel((u32) value, card->membase + DR0);
+ writel(NS_CMD_WRITE_UTILITY | 0x00000200 | (addr & 0x000000FF),
+ card->membase + CMD);
+ spin_unlock_irqrestore(&card->res_lock, flags);
}
-
-
static unsigned char ns_phy_get(struct atm_dev *dev, unsigned long addr)
{
- ns_dev *card;
- unsigned long flags;
- unsigned long data;
-
- card = dev->dev_data;
- spin_lock_irqsave(&card->res_lock, flags);
- while(CMD_BUSY(card));
- writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
- card->membase + CMD);
- while(CMD_BUSY(card));
- data = readl(card->membase + DR0) & 0x000000FF;
- spin_unlock_irqrestore(&card->res_lock, flags);
- return (unsigned char) data;
+ ns_dev *card;
+ unsigned long flags;
+ u32 data;
+
+ card = dev->dev_data;
+ spin_lock_irqsave(&card->res_lock, flags);
+ while (CMD_BUSY(card)) ;
+ writel(NS_CMD_READ_UTILITY | 0x00000200 | (addr & 0x000000FF),
+ card->membase + CMD);
+ while (CMD_BUSY(card)) ;
+ data = readl(card->membase + DR0) & 0x000000FF;
+ spin_unlock_irqrestore(&card->res_lock, flags);
+ return (unsigned char)data;
}
-
-
module_init(nicstar_init);
module_exit(nicstar_cleanup);
diff --git a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
index 6010e3daa6a2..9bc27ea5088e 100644
--- a/drivers/atm/nicstar.h
+++ b/drivers/atm/nicstar.h
@@ -1,5 +1,4 @@
-/******************************************************************************
- *
+/*
* nicstar.h
*
* Header file for the nicstar device driver.
@@ -8,29 +7,26 @@
* PowerPC support by Jay Talbott (jay_talbott@mcg.mot.com) April 1999
*
* (C) INESC 1998
- *
- ******************************************************************************/
-
+ */
#ifndef _LINUX_NICSTAR_H_
#define _LINUX_NICSTAR_H_
-
-/* Includes *******************************************************************/
+/* Includes */
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/idr.h>
#include <linux/uio.h>
#include <linux/skbuff.h>
#include <linux/atmdev.h>
#include <linux/atm_nicstar.h>
-
-/* Options ********************************************************************/
+/* Options */
#define NS_MAX_CARDS 4 /* Maximum number of NICStAR based cards
controlled by the device driver. Must
- be <= 5 */
+ be <= 5 */
#undef RCQ_SUPPORT /* Do not define this for now */
@@ -43,7 +39,7 @@
#define NS_VPIBITS 2 /* 0, 1, 2, or 8 */
#define NS_MAX_RCTSIZE 4096 /* Number of entries. 4096 or 16384.
- Define 4096 only if (all) your card(s)
+ Define 4096 only if (all) your card(s)
have 32K x 32bit SRAM, in which case
setting this to 16384 will just waste a
lot of memory.
@@ -51,33 +47,32 @@
128K x 32bit SRAM will limit the maximum
VCI. */
-/*#define NS_PCI_LATENCY 64*/ /* Must be a multiple of 32 */
+ /*#define NS_PCI_LATENCY 64*//* Must be a multiple of 32 */
/* Number of buffers initially allocated */
-#define NUM_SB 32 /* Must be even */
-#define NUM_LB 24 /* Must be even */
-#define NUM_HB 8 /* Pre-allocated huge buffers */
-#define NUM_IOVB 48 /* Iovec buffers */
+#define NUM_SB 32 /* Must be even */
+#define NUM_LB 24 /* Must be even */
+#define NUM_HB 8 /* Pre-allocated huge buffers */
+#define NUM_IOVB 48 /* Iovec buffers */
/* Lower level for count of buffers */
-#define MIN_SB 8 /* Must be even */
-#define MIN_LB 8 /* Must be even */
+#define MIN_SB 8 /* Must be even */
+#define MIN_LB 8 /* Must be even */
#define MIN_HB 6
#define MIN_IOVB 8
/* Upper level for count of buffers */
-#define MAX_SB 64 /* Must be even, <= 508 */
-#define MAX_LB 48 /* Must be even, <= 508 */
+#define MAX_SB 64 /* Must be even, <= 508 */
+#define MAX_LB 48 /* Must be even, <= 508 */
#define MAX_HB 10
#define MAX_IOVB 80
/* These are the absolute maximum allowed for the ioctl() */
-#define TOP_SB 256 /* Must be even, <= 508 */
-#define TOP_LB 128 /* Must be even, <= 508 */
+#define TOP_SB 256 /* Must be even, <= 508 */
+#define TOP_LB 128 /* Must be even, <= 508 */
#define TOP_HB 64
#define TOP_IOVB 256
-
#define MAX_TBD_PER_VC 1 /* Number of TBDs before a TSR */
#define MAX_TBD_PER_SCQ 10 /* Only meaningful for variable rate SCQs */
@@ -89,15 +84,12 @@
#define PCR_TOLERANCE (1.0001)
-
-
-/* ESI stuff ******************************************************************/
+/* ESI stuff */
#define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C
#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6
-
-/* #defines *******************************************************************/
+/* #defines */
#define NS_IOREMAP_SIZE 4096
@@ -123,22 +115,19 @@
#define NS_SMSKBSIZE (NS_SMBUFSIZE + NS_AAL0_HEADER)
#define NS_LGSKBSIZE (NS_SMBUFSIZE + NS_LGBUFSIZE)
+/* NICStAR structures located in host memory */
-/* NICStAR structures located in host memory **********************************/
-
-
-
-/* RSQ - Receive Status Queue
+/*
+ * RSQ - Receive Status Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct ns_rsqe
-{
- u32 word_1;
- u32 buffer_handle;
- u32 final_aal5_crc32;
- u32 word_4;
+typedef struct ns_rsqe {
+ u32 word_1;
+ u32 buffer_handle;
+ u32 final_aal5_crc32;
+ u32 word_4;
} ns_rsqe;
#define ns_rsqe_vpi(ns_rsqep) \
@@ -175,30 +164,27 @@ typedef struct ns_rsqe
#define ns_rsqe_cellcount(ns_rsqep) \
(le32_to_cpu((ns_rsqep)->word_4) & 0x000001FF)
#define ns_rsqe_init(ns_rsqep) \
- ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000))
+ ((ns_rsqep)->word_4 = cpu_to_le32(0x00000000))
#define NS_RSQ_NUM_ENTRIES (NS_RSQSIZE / 16)
#define NS_RSQ_ALIGNMENT NS_RSQSIZE
-
-
-/* RCQ - Raw Cell Queue
+/*
+ * RCQ - Raw Cell Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct cell_payload
-{
- u32 word[12];
+typedef struct cell_payload {
+ u32 word[12];
} cell_payload;
-typedef struct ns_rcqe
-{
- u32 word_1;
- u32 word_2;
- u32 word_3;
- u32 word_4;
- cell_payload payload;
+typedef struct ns_rcqe {
+ u32 word_1;
+ u32 word_2;
+ u32 word_3;
+ u32 word_4;
+ cell_payload payload;
} ns_rcqe;
#define NS_RCQE_SIZE 64 /* bytes */
@@ -210,28 +196,25 @@ typedef struct ns_rcqe
#define ns_rcqe_nextbufhandle(ns_rcqep) \
(le32_to_cpu((ns_rcqep)->word_2))
-
-
-/* SCQ - Segmentation Channel Queue
+/*
+ * SCQ - Segmentation Channel Queue
*
* Written by the device driver, read by the NICStAR.
*/
-typedef struct ns_scqe
-{
- u32 word_1;
- u32 word_2;
- u32 word_3;
- u32 word_4;
+typedef struct ns_scqe {
+ u32 word_1;
+ u32 word_2;
+ u32 word_3;
+ u32 word_4;
} ns_scqe;
/* NOTE: SCQ entries can be either a TBD (Transmit Buffer Descriptors)
- or TSR (Transmit Status Requests) */
+ or TSR (Transmit Status Requests) */
#define NS_SCQE_TYPE_TBD 0x00000000
#define NS_SCQE_TYPE_TSR 0x80000000
-
#define NS_TBD_EOPDU 0x40000000
#define NS_TBD_AAL0 0x00000000
#define NS_TBD_AAL34 0x04000000
@@ -253,10 +236,9 @@ typedef struct ns_scqe
#define ns_tbd_mkword_4(gfc, vpi, vci, pt, clp) \
(cpu_to_le32((gfc) << 28 | (vpi) << 20 | (vci) << 4 | (pt) << 1 | (clp)))
-
#define NS_TSR_INTENABLE 0x20000000
-#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */
+#define NS_TSR_SCDISVBR 0xFFFF /* Use as scdi for VBR SCD */
#define ns_tsr_mkword_1(flags) \
(cpu_to_le32(NS_SCQE_TYPE_TSR | (flags)))
@@ -273,22 +255,20 @@ typedef struct ns_scqe
#define NS_SCQE_SIZE 16
-
-
-/* TSQ - Transmit Status Queue
+/*
+ * TSQ - Transmit Status Queue
*
* Written by the NICStAR, read by the device driver.
*/
-typedef struct ns_tsi
-{
- u32 word_1;
- u32 word_2;
+typedef struct ns_tsi {
+ u32 word_1;
+ u32 word_2;
} ns_tsi;
/* NOTE: The first word can be a status word copied from the TSR which
- originated the TSI, or a timer overflow indicator. In this last
- case, the value of the first word is all zeroes. */
+ originated the TSI, or a timer overflow indicator. In this last
+ case, the value of the first word is all zeroes. */
#define NS_TSI_EMPTY 0x80000000
#define NS_TSI_TIMESTAMP_MASK 0x00FFFFFF
@@ -301,12 +281,10 @@ typedef struct ns_tsi
#define ns_tsi_init(ns_tsip) \
((ns_tsip)->word_2 = cpu_to_le32(NS_TSI_EMPTY))
-
#define NS_TSQSIZE 8192
#define NS_TSQ_NUM_ENTRIES 1024
#define NS_TSQ_ALIGNMENT 8192
-
#define NS_TSI_SCDISVBR NS_TSR_SCDISVBR
#define ns_tsi_tmrof(ns_tsip) \
@@ -316,26 +294,22 @@ typedef struct ns_tsi
#define ns_tsi_getscqpos(ns_tsip) \
(le32_to_cpu((ns_tsip)->word_1) & 0x00007FFF)
+/* NICStAR structures located in local SRAM */
-
-/* NICStAR structures located in local SRAM ***********************************/
-
-
-
-/* RCT - Receive Connection Table
+/*
+ * RCT - Receive Connection Table
*
* Written by both the NICStAR and the device driver.
*/
-typedef struct ns_rcte
-{
- u32 word_1;
- u32 buffer_handle;
- u32 dma_address;
- u32 aal5_crc32;
+typedef struct ns_rcte {
+ u32 word_1;
+ u32 buffer_handle;
+ u32 dma_address;
+ u32 aal5_crc32;
} ns_rcte;
-#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */
+#define NS_RCTE_BSFB 0x00200000 /* Rev. D only */
#define NS_RCTE_NZGFC 0x00100000
#define NS_RCTE_CONNECTOPEN 0x00080000
#define NS_RCTE_AALMASK 0x00070000
@@ -358,25 +332,21 @@ typedef struct ns_rcte
#define NS_RCT_ENTRY_SIZE 4 /* Number of dwords */
/* NOTE: We could make macros to contruct the first word of the RCTE,
- but that doesn't seem to make much sense... */
+ but that doesn't seem to make much sense... */
-
-
-/* FBD - Free Buffer Descriptor
+/*
+ * FBD - Free Buffer Descriptor
*
* Written by the device driver using via the command register.
*/
-typedef struct ns_fbd
-{
- u32 buffer_handle;
- u32 dma_address;
+typedef struct ns_fbd {
+ u32 buffer_handle;
+ u32 dma_address;
} ns_fbd;
-
-
-
-/* TST - Transmit Schedule Table
+/*
+ * TST - Transmit Schedule Table
*
* Written by the device driver.
*/
@@ -385,40 +355,38 @@ typedef u32 ns_tste;
#define NS_TST_OPCODE_MASK 0x60000000
-#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */
-#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */
+#define NS_TST_OPCODE_NULL 0x00000000 /* Insert null cell */
+#define NS_TST_OPCODE_FIXED 0x20000000 /* Cell from a fixed rate channel */
#define NS_TST_OPCODE_VARIABLE 0x40000000
-#define NS_TST_OPCODE_END 0x60000000 /* Jump */
+#define NS_TST_OPCODE_END 0x60000000 /* Jump */
#define ns_tste_make(opcode, sramad) (opcode | sramad)
/* NOTE:
- When the opcode is FIXED, sramad specifies the SRAM address of the
- SCD for that fixed rate channel.
+ SCD for that fixed rate channel.
- When the opcode is END, sramad specifies the SRAM address of the
- location of the next TST entry to read.
+ location of the next TST entry to read.
*/
-
-
-/* SCD - Segmentation Channel Descriptor
+/*
+ * SCD - Segmentation Channel Descriptor
*
* Written by both the device driver and the NICStAR
*/
-typedef struct ns_scd
-{
- u32 word_1;
- u32 word_2;
- u32 partial_aal5_crc;
- u32 reserved;
- ns_scqe cache_a;
- ns_scqe cache_b;
+typedef struct ns_scd {
+ u32 word_1;
+ u32 word_2;
+ u32 partial_aal5_crc;
+ u32 reserved;
+ ns_scqe cache_a;
+ ns_scqe cache_b;
} ns_scd;
-#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */
-#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */
+#define NS_SCD_BASE_MASK_VAR 0xFFFFE000 /* Variable rate */
+#define NS_SCD_BASE_MASK_FIX 0xFFFFFC00 /* Fixed rate */
#define NS_SCD_TAIL_MASK_VAR 0x00001FF0
#define NS_SCD_TAIL_MASK_FIX 0x000003F0
#define NS_SCD_HEAD_MASK_VAR 0x00001FF0
@@ -426,13 +394,9 @@ typedef struct ns_scd
#define NS_SCD_XMITFOREVER 0x02000000
/* NOTE: There are other fields in word 2 of the SCD, but as they should
- not be needed in the device driver they are not defined here. */
-
-
-
-
-/* NICStAR local SRAM memory map **********************************************/
+ not be needed in the device driver they are not defined here. */
+/* NICStAR local SRAM memory map */
#define NS_RCT 0x00000
#define NS_RCT_32_END 0x03FFF
@@ -455,100 +419,93 @@ typedef struct ns_scd
#define NS_LGFBQ 0x1FC00
#define NS_LGFBQ_END 0x1FFFF
-
-
-/* NISCtAR operation registers ************************************************/
-
+/* NISCtAR operation registers */
/* See Section 3.4 of `IDT77211 NICStAR User Manual' from www.idt.com */
-enum ns_regs
-{
- DR0 = 0x00, /* Data Register 0 R/W*/
- DR1 = 0x04, /* Data Register 1 W */
- DR2 = 0x08, /* Data Register 2 W */
- DR3 = 0x0C, /* Data Register 3 W */
- CMD = 0x10, /* Command W */
- CFG = 0x14, /* Configuration R/W */
- STAT = 0x18, /* Status R/W */
- RSQB = 0x1C, /* Receive Status Queue Base W */
- RSQT = 0x20, /* Receive Status Queue Tail R */
- RSQH = 0x24, /* Receive Status Queue Head W */
- CDC = 0x28, /* Cell Drop Counter R/clear */
- VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */
- ICC = 0x30, /* Invalid Cell Count R/clear */
- RAWCT = 0x34, /* Raw Cell Tail R */
- TMR = 0x38, /* Timer R */
- TSTB = 0x3C, /* Transmit Schedule Table Base R/W */
- TSQB = 0x40, /* Transmit Status Queue Base W */
- TSQT = 0x44, /* Transmit Status Queue Tail R */
- TSQH = 0x48, /* Transmit Status Queue Head W */
- GP = 0x4C, /* General Purpose R/W */
- VPM = 0x50 /* VPI/VCI Mask W */
+enum ns_regs {
+ DR0 = 0x00, /* Data Register 0 R/W */
+ DR1 = 0x04, /* Data Register 1 W */
+ DR2 = 0x08, /* Data Register 2 W */
+ DR3 = 0x0C, /* Data Register 3 W */
+ CMD = 0x10, /* Command W */
+ CFG = 0x14, /* Configuration R/W */
+ STAT = 0x18, /* Status R/W */
+ RSQB = 0x1C, /* Receive Status Queue Base W */
+ RSQT = 0x20, /* Receive Status Queue Tail R */
+ RSQH = 0x24, /* Receive Status Queue Head W */
+ CDC = 0x28, /* Cell Drop Counter R/clear */
+ VPEC = 0x2C, /* VPI/VCI Lookup Error Count R/clear */
+ ICC = 0x30, /* Invalid Cell Count R/clear */
+ RAWCT = 0x34, /* Raw Cell Tail R */
+ TMR = 0x38, /* Timer R */
+ TSTB = 0x3C, /* Transmit Schedule Table Base R/W */
+ TSQB = 0x40, /* Transmit Status Queue Base W */
+ TSQT = 0x44, /* Transmit Status Queue Tail R */
+ TSQH = 0x48, /* Transmit Status Queue Head W */
+ GP = 0x4C, /* General Purpose R/W */
+ VPM = 0x50 /* VPI/VCI Mask W */
};
-
-/* NICStAR commands issued to the CMD register ********************************/
-
+/* NICStAR commands issued to the CMD register */
/* Top 4 bits are command opcode, lower 28 are parameters. */
#define NS_CMD_NO_OPERATION 0x00000000
- /* params always 0 */
+ /* params always 0 */
#define NS_CMD_OPENCLOSE_CONNECTION 0x20000000
- /* b19{1=open,0=close} b18-2{SRAM addr} */
+ /* b19{1=open,0=close} b18-2{SRAM addr} */
#define NS_CMD_WRITE_SRAM 0x40000000
- /* b18-2{SRAM addr} b1-0{burst size} */
+ /* b18-2{SRAM addr} b1-0{burst size} */
#define NS_CMD_READ_SRAM 0x50000000
- /* b18-2{SRAM addr} */
+ /* b18-2{SRAM addr} */
#define NS_CMD_WRITE_FREEBUFQ 0x60000000
- /* b0{large buf indicator} */
+ /* b0{large buf indicator} */
#define NS_CMD_READ_UTILITY 0x80000000
- /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+ /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
#define NS_CMD_WRITE_UTILITY 0x90000000
- /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
+ /* b8{1=select UTL_CS1} b9{1=select UTL_CS0} b7-0{bus addr} */
#define NS_CMD_OPEN_CONNECTION (NS_CMD_OPENCLOSE_CONNECTION | 0x00080000)
#define NS_CMD_CLOSE_CONNECTION NS_CMD_OPENCLOSE_CONNECTION
-
-/* NICStAR configuration bits *************************************************/
-
-#define NS_CFG_SWRST 0x80000000 /* Software Reset */
-#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */
-#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */
-#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */
-#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue
- Interrupt Enable */
-#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */
-#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */
-#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */
-#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */
-#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */
-#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */
-#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt
- Handling */
-#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */
-#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full
- Interrupt Enable */
-#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */
-#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt
- Enable */
-#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */
-#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt
- Enable */
-#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt
- Enable */
-#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */
-#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full
- Interrupt Enable */
-#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */
+/* NICStAR configuration bits */
+
+#define NS_CFG_SWRST 0x80000000 /* Software Reset */
+#define NS_CFG_RXPATH 0x20000000 /* Receive Path Enable */
+#define NS_CFG_SMBUFSIZE_MASK 0x18000000 /* Small Receive Buffer Size */
+#define NS_CFG_LGBUFSIZE_MASK 0x06000000 /* Large Receive Buffer Size */
+#define NS_CFG_EFBIE 0x01000000 /* Empty Free Buffer Queue
+ Interrupt Enable */
+#define NS_CFG_RSQSIZE_MASK 0x00C00000 /* Receive Status Queue Size */
+#define NS_CFG_ICACCEPT 0x00200000 /* Invalid Cell Accept */
+#define NS_CFG_IGNOREGFC 0x00100000 /* Ignore General Flow Control */
+#define NS_CFG_VPIBITS_MASK 0x000C0000 /* VPI/VCI Bits Size Select */
+#define NS_CFG_RCTSIZE_MASK 0x00030000 /* Receive Connection Table Size */
+#define NS_CFG_VCERRACCEPT 0x00008000 /* VPI/VCI Error Cell Accept */
+#define NS_CFG_RXINT_MASK 0x00007000 /* End of Receive PDU Interrupt
+ Handling */
+#define NS_CFG_RAWIE 0x00000800 /* Raw Cell Qu' Interrupt Enable */
+#define NS_CFG_RSQAFIE 0x00000400 /* Receive Queue Almost Full
+ Interrupt Enable */
+#define NS_CFG_RXRM 0x00000200 /* Receive RM Cells */
+#define NS_CFG_TMRROIE 0x00000080 /* Timer Roll Over Interrupt
+ Enable */
+#define NS_CFG_TXEN 0x00000020 /* Transmit Operation Enable */
+#define NS_CFG_TXIE 0x00000010 /* Transmit Status Interrupt
+ Enable */
+#define NS_CFG_TXURIE 0x00000008 /* Transmit Under-run Interrupt
+ Enable */
+#define NS_CFG_UMODE 0x00000004 /* Utopia Mode (cell/byte) Select */
+#define NS_CFG_TSQFIE 0x00000002 /* Transmit Status Queue Full
+ Interrupt Enable */
+#define NS_CFG_PHYIE 0x00000001 /* PHY Interrupt Enable */
#define NS_CFG_SMBUFSIZE_48 0x00000000
#define NS_CFG_SMBUFSIZE_96 0x08000000
@@ -579,33 +536,29 @@ enum ns_regs
#define NS_CFG_RXINT_624US 0x00003000
#define NS_CFG_RXINT_899US 0x00004000
-
-/* NICStAR STATus bits ********************************************************/
-
-#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */
-#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */
-#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */
-#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */
-#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */
-#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */
-#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */
-#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */
-#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */
-#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */
-#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */
-#define NS_STAT_EOPDU 0x00000020 /* End of PDU */
-#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */
-#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */
-#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */
-#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */
+/* NICStAR STATus bits */
+
+#define NS_STAT_SFBQC_MASK 0xFF000000 /* hi 8 bits Small Buffer Queue Count */
+#define NS_STAT_LFBQC_MASK 0x00FF0000 /* hi 8 bits Large Buffer Queue Count */
+#define NS_STAT_TSIF 0x00008000 /* Transmit Status Queue Indicator */
+#define NS_STAT_TXICP 0x00004000 /* Transmit Incomplete PDU */
+#define NS_STAT_TSQF 0x00001000 /* Transmit Status Queue Full */
+#define NS_STAT_TMROF 0x00000800 /* Timer Overflow */
+#define NS_STAT_PHYI 0x00000400 /* PHY Device Interrupt */
+#define NS_STAT_CMDBZ 0x00000200 /* Command Busy */
+#define NS_STAT_SFBQF 0x00000100 /* Small Buffer Queue Full */
+#define NS_STAT_LFBQF 0x00000080 /* Large Buffer Queue Full */
+#define NS_STAT_RSQF 0x00000040 /* Receive Status Queue Full */
+#define NS_STAT_EOPDU 0x00000020 /* End of PDU */
+#define NS_STAT_RAWCF 0x00000010 /* Raw Cell Flag */
+#define NS_STAT_SFBQE 0x00000008 /* Small Buffer Queue Empty */
+#define NS_STAT_LFBQE 0x00000004 /* Large Buffer Queue Empty */
+#define NS_STAT_RSQAF 0x00000002 /* Receive Status Queue Almost Full */
#define ns_stat_sfbqc_get(stat) (((stat) & NS_STAT_SFBQC_MASK) >> 23)
#define ns_stat_lfbqc_get(stat) (((stat) & NS_STAT_LFBQC_MASK) >> 15)
-
-
-/* #defines which depend on other #defines ************************************/
-
+/* #defines which depend on other #defines */
#define NS_TST0 NS_TST_FRSCD
#define NS_TST1 (NS_TST_FRSCD + NS_TST_NUM_ENTRIES + 1)
@@ -672,8 +625,7 @@ enum ns_regs
#define NS_CFG_TSQFIE_OPT 0x00000000
#endif /* ENABLE_TSQFIE */
-
-/* PCI stuff ******************************************************************/
+/* PCI stuff */
#ifndef PCI_VENDOR_ID_IDT
#define PCI_VENDOR_ID_IDT 0x111D
@@ -683,138 +635,124 @@ enum ns_regs
#define PCI_DEVICE_ID_IDT_IDT77201 0x0001
#endif /* PCI_DEVICE_ID_IDT_IDT77201 */
+/* Device driver structures */
-
-/* Device driver structures ***************************************************/
-
-
-struct ns_skb_cb {
- u32 buf_type; /* BUF_SM/BUF_LG/BUF_NONE */
+struct ns_skb_prv {
+ u32 buf_type; /* BUF_SM/BUF_LG/BUF_NONE */
+ u32 dma;
+ int iovcnt;
};
-#define NS_SKB_CB(skb) ((struct ns_skb_cb *)((skb)->cb))
-
-typedef struct tsq_info
-{
- void *org;
- ns_tsi *base;
- ns_tsi *next;
- ns_tsi *last;
+#define NS_PRV_BUFTYPE(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->buf_type)
+#define NS_PRV_DMA(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->dma)
+#define NS_PRV_IOVCNT(skb) \
+ (((struct ns_skb_prv *)(ATM_SKB(skb)+1))->iovcnt)
+
+typedef struct tsq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_tsi *base;
+ ns_tsi *next;
+ ns_tsi *last;
} tsq_info;
-
-typedef struct scq_info
-{
- void *org;
- ns_scqe *base;
- ns_scqe *last;
- ns_scqe *next;
- volatile ns_scqe *tail; /* Not related to the nicstar register */
- unsigned num_entries;
- struct sk_buff **skb; /* Pointer to an array of pointers
- to the sk_buffs used for tx */
- u32 scd; /* SRAM address of the corresponding
- SCD */
- int tbd_count; /* Only meaningful on variable rate */
- wait_queue_head_t scqfull_waitq;
- volatile char full; /* SCQ full indicator */
- spinlock_t lock; /* SCQ spinlock */
+typedef struct scq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_scqe *base;
+ ns_scqe *last;
+ ns_scqe *next;
+ volatile ns_scqe *tail; /* Not related to the nicstar register */
+ unsigned num_entries;
+ struct sk_buff **skb; /* Pointer to an array of pointers
+ to the sk_buffs used for tx */
+ u32 scd; /* SRAM address of the corresponding
+ SCD */
+ int tbd_count; /* Only meaningful on variable rate */
+ wait_queue_head_t scqfull_waitq;
+ volatile char full; /* SCQ full indicator */
+ spinlock_t lock; /* SCQ spinlock */
} scq_info;
-
-
-typedef struct rsq_info
-{
- void *org;
- ns_rsqe *base;
- ns_rsqe *next;
- ns_rsqe *last;
+typedef struct rsq_info {
+ void *org;
+ dma_addr_t dma;
+ ns_rsqe *base;
+ ns_rsqe *next;
+ ns_rsqe *last;
} rsq_info;
-
-typedef struct skb_pool
-{
- volatile int count; /* number of buffers in the queue */
- struct sk_buff_head queue;
+typedef struct skb_pool {
+ volatile int count; /* number of buffers in the queue */
+ struct sk_buff_head queue;
} skb_pool;
/* NOTE: for small and large buffer pools, the count is not used, as the
actual value used for buffer management is the one read from the
card. */
-
-typedef struct vc_map
-{
- volatile unsigned int tx:1; /* TX vc? */
- volatile unsigned int rx:1; /* RX vc? */
- struct atm_vcc *tx_vcc, *rx_vcc;
- struct sk_buff *rx_iov; /* RX iovector skb */
- scq_info *scq; /* To keep track of the SCQ */
- u32 cbr_scd; /* SRAM address of the corresponding
- SCD. 0x00000000 for UBR/VBR/ABR */
- int tbd_count;
+typedef struct vc_map {
+ volatile unsigned int tx:1; /* TX vc? */
+ volatile unsigned int rx:1; /* RX vc? */
+ struct atm_vcc *tx_vcc, *rx_vcc;
+ struct sk_buff *rx_iov; /* RX iovector skb */
+ scq_info *scq; /* To keep track of the SCQ */
+ u32 cbr_scd; /* SRAM address of the corresponding
+ SCD. 0x00000000 for UBR/VBR/ABR */
+ int tbd_count;
} vc_map;
-
-struct ns_skb_data
-{
- struct atm_vcc *vcc;
- int iovcnt;
-};
-
-#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb))
-
-
-typedef struct ns_dev
-{
- int index; /* Card ID to the device driver */
- int sram_size; /* In k x 32bit words. 32 or 128 */
- void __iomem *membase; /* Card's memory base address */
- unsigned long max_pcr;
- int rct_size; /* Number of entries */
- int vpibits;
- int vcibits;
- struct pci_dev *pcidev;
- struct atm_dev *atmdev;
- tsq_info tsq;
- rsq_info rsq;
- scq_info *scq0, *scq1, *scq2; /* VBR SCQs */
- skb_pool sbpool; /* Small buffers */
- skb_pool lbpool; /* Large buffers */
- skb_pool hbpool; /* Pre-allocated huge buffers */
- skb_pool iovpool; /* iovector buffers */
- volatile int efbie; /* Empty free buf. queue int. enabled */
- volatile u32 tst_addr; /* SRAM address of the TST in use */
- volatile int tst_free_entries;
- vc_map vcmap[NS_MAX_RCTSIZE];
- vc_map *tste2vc[NS_TST_NUM_ENTRIES];
- vc_map *scd2vc[NS_FRSCD_NUM];
- buf_nr sbnr;
- buf_nr lbnr;
- buf_nr hbnr;
- buf_nr iovnr;
- int sbfqc;
- int lbfqc;
- u32 sm_handle;
- u32 sm_addr;
- u32 lg_handle;
- u32 lg_addr;
- struct sk_buff *rcbuf; /* Current raw cell buffer */
- u32 rawch; /* Raw cell queue head */
- unsigned intcnt; /* Interrupt counter */
- spinlock_t int_lock; /* Interrupt lock */
- spinlock_t res_lock; /* Card resource lock */
+typedef struct ns_dev {
+ int index; /* Card ID to the device driver */
+ int sram_size; /* In k x 32bit words. 32 or 128 */
+ void __iomem *membase; /* Card's memory base address */
+ unsigned long max_pcr;
+ int rct_size; /* Number of entries */
+ int vpibits;
+ int vcibits;
+ struct pci_dev *pcidev;
+ struct idr idr;
+ struct atm_dev *atmdev;
+ tsq_info tsq;
+ rsq_info rsq;
+ scq_info *scq0, *scq1, *scq2; /* VBR SCQs */
+ skb_pool sbpool; /* Small buffers */
+ skb_pool lbpool; /* Large buffers */
+ skb_pool hbpool; /* Pre-allocated huge buffers */
+ skb_pool iovpool; /* iovector buffers */
+ volatile int efbie; /* Empty free buf. queue int. enabled */
+ volatile u32 tst_addr; /* SRAM address of the TST in use */
+ volatile int tst_free_entries;
+ vc_map vcmap[NS_MAX_RCTSIZE];
+ vc_map *tste2vc[NS_TST_NUM_ENTRIES];
+ vc_map *scd2vc[NS_FRSCD_NUM];
+ buf_nr sbnr;
+ buf_nr lbnr;
+ buf_nr hbnr;
+ buf_nr iovnr;
+ int sbfqc;
+ int lbfqc;
+ struct sk_buff *sm_handle;
+ u32 sm_addr;
+ struct sk_buff *lg_handle;
+ u32 lg_addr;
+ struct sk_buff *rcbuf; /* Current raw cell buffer */
+ struct ns_rcqe *rawcell;
+ u32 rawch; /* Raw cell queue head */
+ unsigned intcnt; /* Interrupt counter */
+ spinlock_t int_lock; /* Interrupt lock */
+ spinlock_t res_lock; /* Card resource lock */
} ns_dev;
-
/* NOTE: Each tste2vc entry relates a given TST entry to the corresponding
- CBR vc. If the entry is not allocated, it must be NULL.
-
- There are two TSTs so the driver can modify them on the fly
- without stopping the transmission.
-
- scd2vc allows us to find out unused fixed rate SCDs, because
- they must have a NULL pointer here. */
+ CBR vc. If the entry is not allocated, it must be NULL.
+
+ There are two TSTs so the driver can modify them on the fly
+ without stopping the transmission.
+ scd2vc allows us to find out unused fixed rate SCDs, because
+ they must have a NULL pointer here. */
#endif /* _LINUX_NICSTAR_H_ */
diff --git a/drivers/atm/nicstarmac.c b/drivers/atm/nicstarmac.c
index 842e26c45557..f594526f8c6d 100644
--- a/drivers/atm/nicstarmac.c
+++ b/drivers/atm/nicstarmac.c
@@ -13,15 +13,15 @@ typedef void __iomem *virt_addr_t;
#define CYCLE_DELAY 5
-/* This was the original definition
+/*
+ This was the original definition
#define osp_MicroDelay(microsec) \
do { int _i = 4*microsec; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0)
*/
#define osp_MicroDelay(microsec) {unsigned long useconds = (microsec); \
udelay((useconds));}
-
-
-/* The following tables represent the timing diagrams found in
+/*
+ * The following tables represent the timing diagrams found in
* the Data Sheet for the Xicor X25020 EEProm. The #defines below
* represent the bits in the NICStAR's General Purpose register
* that must be toggled for the corresponding actions on the EEProm
@@ -31,86 +31,80 @@ typedef void __iomem *virt_addr_t;
/* Write Data To EEProm from SI line on rising edge of CLK */
/* Read Data From EEProm on falling edge of CLK */
-#define CS_HIGH 0x0002 /* Chip select high */
-#define CS_LOW 0x0000 /* Chip select low (active low)*/
-#define CLK_HIGH 0x0004 /* Clock high */
-#define CLK_LOW 0x0000 /* Clock low */
-#define SI_HIGH 0x0001 /* Serial input data high */
-#define SI_LOW 0x0000 /* Serial input data low */
+#define CS_HIGH 0x0002 /* Chip select high */
+#define CS_LOW 0x0000 /* Chip select low (active low) */
+#define CLK_HIGH 0x0004 /* Clock high */
+#define CLK_LOW 0x0000 /* Clock low */
+#define SI_HIGH 0x0001 /* Serial input data high */
+#define SI_LOW 0x0000 /* Serial input data low */
/* Read Status Register = 0000 0101b */
#if 0
-static u_int32_t rdsrtab[] =
-{
- CS_HIGH | CLK_HIGH,
- CS_LOW | CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH, /* 1 */
- CLK_LOW | SI_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH /* 1 */
+static u_int32_t rdsrtab[] = {
+ CS_HIGH | CLK_HIGH,
+ CS_LOW | CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH, /* 1 */
+ CLK_LOW | SI_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH /* 1 */
};
-#endif /* 0 */
-
+#endif /* 0 */
/* Read from EEPROM = 0000 0011b */
-static u_int32_t readtab[] =
-{
- /*
- CS_HIGH | CLK_HIGH,
- */
- CS_LOW | CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW,
- CLK_HIGH, /* 0 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH, /* 1 */
- CLK_LOW | SI_HIGH,
- CLK_HIGH | SI_HIGH /* 1 */
+static u_int32_t readtab[] = {
+ /*
+ CS_HIGH | CLK_HIGH,
+ */
+ CS_LOW | CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW,
+ CLK_HIGH, /* 0 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH, /* 1 */
+ CLK_LOW | SI_HIGH,
+ CLK_HIGH | SI_HIGH /* 1 */
};
-
/* Clock to read from/write to the eeprom */
-static u_int32_t clocktab[] =
-{
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW,
- CLK_HIGH,
- CLK_LOW
+static u_int32_t clocktab[] = {
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW,
+ CLK_HIGH,
+ CLK_LOW
};
-
#define NICSTAR_REG_WRITE(bs, reg, val) \
while ( readl(bs + STAT) & 0x0200 ) ; \
writel((val),(base)+(reg))
@@ -124,153 +118,131 @@ static u_int32_t clocktab[] =
* register.
*/
#if 0
-u_int32_t
-nicstar_read_eprom_status( virt_addr_t base )
+u_int32_t nicstar_read_eprom_status(virt_addr_t base)
{
- u_int32_t val;
- u_int32_t rbyte;
- int32_t i, j;
-
- /* Send read instruction */
- val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
-
- for (i=0; i<ARRAY_SIZE(rdsrtab); i++)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | rdsrtab[i]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- /* Done sending instruction - now pull data off of bit 16, MSB first */
- /* Data clocked out of eeprom on falling edge of clock */
-
- rbyte = 0;
- for (i=7, j=0; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- rbyte |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE)
- & 0x00010000) >> 16) << i);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
- osp_MicroDelay( CYCLE_DELAY );
- return rbyte;
+ u_int32_t val;
+ u_int32_t rbyte;
+ int32_t i, j;
+
+ /* Send read instruction */
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+
+ for (i = 0; i < ARRAY_SIZE(rdsrtab); i++) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | rdsrtab[i]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ /* Done sending instruction - now pull data off of bit 16, MSB first */
+ /* Data clocked out of eeprom on falling edge of clock */
+
+ rbyte = 0;
+ for (i = 7, j = 0; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ rbyte |= (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+ & 0x00010000) >> 16) << i);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+ osp_MicroDelay(CYCLE_DELAY);
+ return rbyte;
}
-#endif /* 0 */
-
+#endif /* 0 */
/*
* This routine will clock the Read_data function into the X2520
* eeprom, followed by the address to read from, through the NicSTaR's General
* Purpose register.
*/
-
-static u_int8_t
-read_eprom_byte(virt_addr_t base, u_int8_t offset)
+
+static u_int8_t read_eprom_byte(virt_addr_t base, u_int8_t offset)
{
- u_int32_t val = 0;
- int i,j=0;
- u_int8_t tempread = 0;
-
- val = NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE ) & 0xFFFFFFF0;
-
- /* Send READ instruction */
- for (i=0; i<ARRAY_SIZE(readtab); i++)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | readtab[i]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- /* Next, we need to send the byte address to read from */
- for (i=7; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++] | ((offset >> i) & 1) ) );
- osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++] | ((offset >> i) & 1) ) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- j = 0;
-
- /* Now, we can read data from the eeprom by clocking it in */
- for (i=7; i>=0; i--)
- {
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- tempread |= (((NICSTAR_REG_READ( base, NICSTAR_REG_GENERAL_PURPOSE )
- & 0x00010000) >> 16) << i);
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | clocktab[j++]) );
- osp_MicroDelay( CYCLE_DELAY );
- }
-
- NICSTAR_REG_WRITE( base, NICSTAR_REG_GENERAL_PURPOSE, 2 );
- osp_MicroDelay( CYCLE_DELAY );
- return tempread;
+ u_int32_t val = 0;
+ int i, j = 0;
+ u_int8_t tempread = 0;
+
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+
+ /* Send READ instruction */
+ for (i = 0; i < ARRAY_SIZE(readtab); i++) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | readtab[i]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ /* Next, we need to send the byte address to read from */
+ for (i = 7; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++] | ((offset >> i) & 1)));
+ osp_MicroDelay(CYCLE_DELAY);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++] | ((offset >> i) & 1)));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ j = 0;
+
+ /* Now, we can read data from the eeprom by clocking it in */
+ for (i = 7; i >= 0; i--) {
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ tempread |=
+ (((NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE)
+ & 0x00010000) >> 16) << i);
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | clocktab[j++]));
+ osp_MicroDelay(CYCLE_DELAY);
+ }
+
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE, 2);
+ osp_MicroDelay(CYCLE_DELAY);
+ return tempread;
}
-
-static void
-nicstar_init_eprom( virt_addr_t base )
+static void nicstar_init_eprom(virt_addr_t base)
{
- u_int32_t val;
+ u_int32_t val;
- /*
- * turn chip select off
- */
- val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
+ /*
+ * turn chip select off
+ */
+ val = NICSTAR_REG_READ(base, NICSTAR_REG_GENERAL_PURPOSE) & 0xFFFFFFF0;
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_HIGH));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_HIGH));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_LOW));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_LOW));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_HIGH));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_HIGH));
+ osp_MicroDelay(CYCLE_DELAY);
- NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
- (val | CS_HIGH | CLK_LOW));
- osp_MicroDelay( CYCLE_DELAY );
+ NICSTAR_REG_WRITE(base, NICSTAR_REG_GENERAL_PURPOSE,
+ (val | CS_HIGH | CLK_LOW));
+ osp_MicroDelay(CYCLE_DELAY);
}
-
/*
* This routine will be the interface to the ReadPromByte function
* above.
- */
+ */
static void
-nicstar_read_eprom(
- virt_addr_t base,
- u_int8_t prom_offset,
- u_int8_t *buffer,
- u_int32_t nbytes )
+nicstar_read_eprom(virt_addr_t base,
+ u_int8_t prom_offset, u_int8_t * buffer, u_int32_t nbytes)
{
- u_int i;
-
- for (i=0; i<nbytes; i++)
- {
- buffer[i] = read_eprom_byte( base, prom_offset );
- ++prom_offset;
- osp_MicroDelay( CYCLE_DELAY );
- }
-}
-
+ u_int i;
-/*
-void osp_MicroDelay(int x) {
-
+ for (i = 0; i < nbytes; i++) {
+ buffer[i] = read_eprom_byte(base, prom_offset);
+ ++prom_offset;
+ osp_MicroDelay(CYCLE_DELAY);
+ }
}
-*/
-
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 5674bd01d96d..b1e5c624b110 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -987,8 +987,12 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
}
sysminor = SYSMINOR(aoemajor, h->minor);
- if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
- printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
+ if (h->minor >= NPERSHELF) {
+ printk(KERN_INFO "aoe: e%ld.%d: AoE minor address too large\n",
+ aoemajor, (int) h->minor);
+ return;
+ } else if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
+ printk(KERN_INFO "aoe: e%ld.%d: AoE major address too large\n",
aoemajor, (int) h->minor);
return;
}
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 6081e81d5738..f1bf79d9bc0a 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -133,6 +133,28 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
return page;
}
+static void brd_free_page(struct brd_device *brd, sector_t sector)
+{
+ struct page *page;
+ pgoff_t idx;
+
+ spin_lock(&brd->brd_lock);
+ idx = sector >> PAGE_SECTORS_SHIFT;
+ page = radix_tree_delete(&brd->brd_pages, idx);
+ spin_unlock(&brd->brd_lock);
+ if (page)
+ __free_page(page);
+}
+
+static void brd_zero_page(struct brd_device *brd, sector_t sector)
+{
+ struct page *page;
+
+ page = brd_lookup_page(brd, sector);
+ if (page)
+ clear_highpage(page);
+}
+
/*
* Free all backing store pages and radix tree. This must only be called when
* there are no other users of the device.
@@ -189,6 +211,24 @@ static int copy_to_brd_setup(struct brd_device *brd, sector_t sector, size_t n)
return 0;
}
+static void discard_from_brd(struct brd_device *brd,
+ sector_t sector, size_t n)
+{
+ while (n >= PAGE_SIZE) {
+ /*
+ * Don't want to actually discard pages here because
+ * re-allocating the pages can result in writeback
+ * deadlocks under heavy load.
+ */
+ if (0)
+ brd_free_page(brd, sector);
+ else
+ brd_zero_page(brd, sector);
+ sector += PAGE_SIZE >> SECTOR_SHIFT;
+ n -= PAGE_SIZE;
+ }
+}
+
/*
* Copy n bytes from src to the brd starting at sector. Does not sleep.
*/
@@ -300,6 +340,12 @@ static int brd_make_request(struct request_queue *q, struct bio *bio)
get_capacity(bdev->bd_disk))
goto out;
+ if (unlikely(bio_rw_flagged(bio, BIO_RW_DISCARD))) {
+ err = 0;
+ discard_from_brd(brd, sector, bio->bi_size);
+ goto out;
+ }
+
rw = bio_rw(bio);
if (rw == READA)
rw = READ;
@@ -320,7 +366,7 @@ out:
}
#ifdef CONFIG_BLK_DEV_XIP
-static int brd_direct_access (struct block_device *bdev, sector_t sector,
+static int brd_direct_access(struct block_device *bdev, sector_t sector,
void **kaddr, unsigned long *pfn)
{
struct brd_device *brd = bdev->bd_disk->private_data;
@@ -437,6 +483,11 @@ static struct brd_device *brd_alloc(int i)
blk_queue_max_hw_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
+ brd->brd_queue->limits.discard_granularity = PAGE_SIZE;
+ brd->brd_queue->limits.max_discard_sectors = UINT_MAX;
+ brd->brd_queue->limits.discard_zeroes_data = 1;
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);
+
disk = brd->brd_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index e1d0e2cfec72..3381505c8a6c 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -188,11 +188,11 @@ scsi_cmd_free(ctlr_info_t *h, CommandList_struct *cmd)
sa = h->scsi_ctlr;
stk = &sa->cmd_stack;
+ stk->top++;
if (stk->top >= CMD_STACK_SIZE) {
printk("cciss: scsi_cmd_free called too many times.\n");
BUG();
}
- stk->top++;
stk->elem[stk->top] = (struct cciss_scsi_cmd_stack_elem_t *) cmd;
}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index e9654c8d5b62..485ed8c7d623 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -943,8 +943,7 @@ struct drbd_conf {
struct drbd_work resync_work,
unplug_work,
md_sync_work,
- delay_probe_work,
- uuid_work;
+ delay_probe_work;
struct timer_list resync_timer;
struct timer_list md_sync_timer;
struct timer_list delay_probe_timer;
@@ -1069,7 +1068,6 @@ struct drbd_conf {
struct timeval dps_time; /* delay-probes-start-time */
unsigned int dp_volume_last; /* send_cnt of last delay probe */
int c_sync_rate; /* current resync rate after delay_probe magic */
- atomic_t new_c_uuid;
};
static inline struct drbd_conf *minor_to_mdev(unsigned int minor)
@@ -1476,7 +1474,6 @@ extern int w_e_end_ov_req(struct drbd_conf *, struct drbd_work *, int);
extern int w_ov_finished(struct drbd_conf *, struct drbd_work *, int);
extern int w_resync_inactive(struct drbd_conf *, struct drbd_work *, int);
extern int w_resume_next_sg(struct drbd_conf *, struct drbd_work *, int);
-extern int w_io_error(struct drbd_conf *, struct drbd_work *, int);
extern int w_send_write_hint(struct drbd_conf *, struct drbd_work *, int);
extern int w_make_resync_request(struct drbd_conf *, struct drbd_work *, int);
extern int w_send_dblock(struct drbd_conf *, struct drbd_work *, int);
@@ -1542,7 +1539,7 @@ static inline void drbd_tcp_nodelay(struct socket *sock)
static inline void drbd_tcp_quickack(struct socket *sock)
{
- int __user val = 1;
+ int __user val = 2;
(void) drbd_setsockopt(sock, SOL_TCP, TCP_QUICKACK,
(char __user *)&val, sizeof(val));
}
@@ -1728,7 +1725,7 @@ static inline void __drbd_chk_io_error_(struct drbd_conf *mdev, int forcedetach,
switch (mdev->ldev->dc.on_io_error) {
case EP_PASS_ON:
if (!forcedetach) {
- if (printk_ratelimit())
+ if (__ratelimit(&drbd_ratelimit_state))
dev_err(DEV, "Local IO failed in %s."
"Passing error on...\n", where);
break;
@@ -2219,8 +2216,6 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev)
return 0;
if (test_bit(BITMAP_IO, &mdev->flags))
return 0;
- if (atomic_read(&mdev->new_c_uuid))
- return 0;
return 1;
}
@@ -2241,9 +2236,6 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int count)
* to avoid races with the reconnect code,
* we need to atomic_inc within the spinlock. */
- if (atomic_read(&mdev->new_c_uuid) && atomic_add_unless(&mdev->new_c_uuid, -1, 1))
- drbd_queue_work_front(&mdev->data.work, &mdev->uuid_work);
-
spin_lock_irq(&mdev->req_lock);
while (!__inc_ap_bio_cond(mdev)) {
prepare_to_wait(&mdev->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c
index be2d2da9cdba..6b077f93acc6 100644
--- a/drivers/block/drbd/drbd_main.c
+++ b/drivers/block/drbd/drbd_main.c
@@ -1215,18 +1215,17 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
ns.pdsk == D_OUTDATED)) {
if (get_ldev(mdev)) {
if ((ns.role == R_PRIMARY || ns.peer == R_PRIMARY) &&
- mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE &&
- !atomic_read(&mdev->new_c_uuid))
- atomic_set(&mdev->new_c_uuid, 2);
+ mdev->ldev->md.uuid[UI_BITMAP] == 0 && ns.disk >= D_UP_TO_DATE) {
+ drbd_uuid_new_current(mdev);
+ drbd_send_uuids(mdev);
+ }
put_ldev(mdev);
}
}
if (ns.pdsk < D_INCONSISTENT && get_ldev(mdev)) {
- /* Diskless peer becomes primary or got connected do diskless, primary peer. */
- if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0 &&
- !atomic_read(&mdev->new_c_uuid))
- atomic_set(&mdev->new_c_uuid, 2);
+ if (ns.peer == R_PRIMARY && mdev->ldev->md.uuid[UI_BITMAP] == 0)
+ drbd_uuid_new_current(mdev);
/* D_DISKLESS Peer becomes secondary */
if (os.peer == R_PRIMARY && ns.peer == R_SECONDARY)
@@ -1350,24 +1349,6 @@ static void after_state_ch(struct drbd_conf *mdev, union drbd_state os,
drbd_md_sync(mdev);
}
-static int w_new_current_uuid(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
- if (get_ldev(mdev)) {
- if (mdev->ldev->md.uuid[UI_BITMAP] == 0) {
- drbd_uuid_new_current(mdev);
- if (get_net_conf(mdev)) {
- drbd_send_uuids(mdev);
- put_net_conf(mdev);
- }
- drbd_md_sync(mdev);
- }
- put_ldev(mdev);
- }
- atomic_dec(&mdev->new_c_uuid);
- wake_up(&mdev->misc_wait);
-
- return 1;
-}
static int drbd_thread_setup(void *arg)
{
@@ -2291,9 +2272,9 @@ static int we_should_drop_the_connection(struct drbd_conf *mdev, struct socket *
* with page_count == 0 or PageSlab.
*/
static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
- int offset, size_t size)
+ int offset, size_t size, unsigned msg_flags)
{
- int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, 0);
+ int sent = drbd_send(mdev, mdev->data.socket, kmap(page) + offset, size, msg_flags);
kunmap(page);
if (sent == size)
mdev->send_cnt += size>>9;
@@ -2301,7 +2282,7 @@ static int _drbd_no_send_page(struct drbd_conf *mdev, struct page *page,
}
static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
- int offset, size_t size)
+ int offset, size_t size, unsigned msg_flags)
{
mm_segment_t oldfs = get_fs();
int sent, ok;
@@ -2314,14 +2295,15 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
* __page_cache_release a page that would actually still be referenced
* by someone, leading to some obscure delayed Oops somewhere else. */
if (disable_sendpage || (page_count(page) < 1) || PageSlab(page))
- return _drbd_no_send_page(mdev, page, offset, size);
+ return _drbd_no_send_page(mdev, page, offset, size, msg_flags);
+ msg_flags |= MSG_NOSIGNAL;
drbd_update_congested(mdev);
set_fs(KERNEL_DS);
do {
sent = mdev->data.socket->ops->sendpage(mdev->data.socket, page,
offset, len,
- MSG_NOSIGNAL);
+ msg_flags);
if (sent == -EAGAIN) {
if (we_should_drop_the_connection(mdev,
mdev->data.socket))
@@ -2350,9 +2332,11 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
{
struct bio_vec *bvec;
int i;
+ /* hint all but last page with MSG_MORE */
__bio_for_each_segment(bvec, bio, i, 0) {
if (!_drbd_no_send_page(mdev, bvec->bv_page,
- bvec->bv_offset, bvec->bv_len))
+ bvec->bv_offset, bvec->bv_len,
+ i == bio->bi_vcnt -1 ? 0 : MSG_MORE))
return 0;
}
return 1;
@@ -2362,12 +2346,13 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
{
struct bio_vec *bvec;
int i;
+ /* hint all but last page with MSG_MORE */
__bio_for_each_segment(bvec, bio, i, 0) {
if (!_drbd_send_page(mdev, bvec->bv_page,
- bvec->bv_offset, bvec->bv_len))
+ bvec->bv_offset, bvec->bv_len,
+ i == bio->bi_vcnt -1 ? 0 : MSG_MORE))
return 0;
}
-
return 1;
}
@@ -2375,9 +2360,11 @@ static int _drbd_send_zc_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e)
{
struct page *page = e->pages;
unsigned len = e->size;
+ /* hint all but last page with MSG_MORE */
page_chain_for_each(page) {
unsigned l = min_t(unsigned, len, PAGE_SIZE);
- if (!_drbd_send_page(mdev, page, 0, l))
+ if (!_drbd_send_page(mdev, page, 0, l,
+ page_chain_next(page) ? MSG_MORE : 0))
return 0;
len -= l;
}
@@ -2457,11 +2444,11 @@ int drbd_send_dblock(struct drbd_conf *mdev, struct drbd_request *req)
p.dp_flags = cpu_to_be32(dp_flags);
set_bit(UNPLUG_REMOTE, &mdev->flags);
ok = (sizeof(p) ==
- drbd_send(mdev, mdev->data.socket, &p, sizeof(p), MSG_MORE));
+ drbd_send(mdev, mdev->data.socket, &p, sizeof(p), dgs ? MSG_MORE : 0));
if (ok && dgs) {
dgb = mdev->int_dig_out;
drbd_csum_bio(mdev, mdev->integrity_w_tfm, req->master_bio, dgb);
- ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+ ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0);
}
if (ok) {
if (mdev->net_conf->wire_protocol == DRBD_PROT_A)
@@ -2510,11 +2497,11 @@ int drbd_send_block(struct drbd_conf *mdev, enum drbd_packets cmd,
return 0;
ok = sizeof(p) == drbd_send(mdev, mdev->data.socket, &p,
- sizeof(p), MSG_MORE);
+ sizeof(p), dgs ? MSG_MORE : 0);
if (ok && dgs) {
dgb = mdev->int_dig_out;
drbd_csum_ee(mdev, mdev->integrity_w_tfm, e, dgb);
- ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, MSG_MORE);
+ ok = drbd_send(mdev, mdev->data.socket, dgb, dgs, 0);
}
if (ok)
ok = _drbd_send_zc_ee(mdev, e);
@@ -2708,7 +2695,6 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
atomic_set(&mdev->net_cnt, 0);
atomic_set(&mdev->packet_seq, 0);
atomic_set(&mdev->pp_in_use, 0);
- atomic_set(&mdev->new_c_uuid, 0);
mutex_init(&mdev->md_io_mutex);
mutex_init(&mdev->data.mutex);
@@ -2739,14 +2725,12 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
INIT_LIST_HEAD(&mdev->bm_io_work.w.list);
INIT_LIST_HEAD(&mdev->delay_probes);
INIT_LIST_HEAD(&mdev->delay_probe_work.list);
- INIT_LIST_HEAD(&mdev->uuid_work.list);
mdev->resync_work.cb = w_resync_inactive;
mdev->unplug_work.cb = w_send_write_hint;
mdev->md_sync_work.cb = w_md_sync;
mdev->bm_io_work.w.cb = w_bitmap_io;
mdev->delay_probe_work.cb = w_delay_probes;
- mdev->uuid_work.cb = w_new_current_uuid;
init_timer(&mdev->resync_timer);
init_timer(&mdev->md_sync_timer);
init_timer(&mdev->delay_probe_timer);
@@ -3799,7 +3783,7 @@ _drbd_insert_fault(struct drbd_conf *mdev, unsigned int type)
if (ret) {
fault_count++;
- if (printk_ratelimit())
+ if (__ratelimit(&drbd_ratelimit_state))
dev_warn(DEV, "***Simulating %s failure\n",
_drbd_fault_str(type));
}
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index bc9ab7fb2cc7..dff48701b84d 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -42,7 +42,6 @@
#include <linux/unistd.h>
#include <linux/vmalloc.h>
#include <linux/random.h>
-#include <linux/mm.h>
#include <linux/string.h>
#include <linux/scatterlist.h>
#include "drbd_int.h"
@@ -571,6 +570,25 @@ static int drbd_recv(struct drbd_conf *mdev, void *buf, size_t size)
return rv;
}
+/* quoting tcp(7):
+ * On individual connections, the socket buffer size must be set prior to the
+ * listen(2) or connect(2) calls in order to have it take effect.
+ * This is our wrapper to do so.
+ */
+static void drbd_setbufsize(struct socket *sock, unsigned int snd,
+ unsigned int rcv)
+{
+ /* open coded SO_SNDBUF, SO_RCVBUF */
+ if (snd) {
+ sock->sk->sk_sndbuf = snd;
+ sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
+ }
+ if (rcv) {
+ sock->sk->sk_rcvbuf = rcv;
+ sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
+ }
+}
+
static struct socket *drbd_try_connect(struct drbd_conf *mdev)
{
const char *what;
@@ -592,6 +610,8 @@ static struct socket *drbd_try_connect(struct drbd_conf *mdev)
sock->sk->sk_rcvtimeo =
sock->sk->sk_sndtimeo = mdev->net_conf->try_connect_int*HZ;
+ drbd_setbufsize(sock, mdev->net_conf->sndbuf_size,
+ mdev->net_conf->rcvbuf_size);
/* explicitly bind to the configured IP as source IP
* for the outgoing connections.
@@ -670,6 +690,8 @@ static struct socket *drbd_wait_for_connect(struct drbd_conf *mdev)
s_listen->sk->sk_reuse = 1; /* SO_REUSEADDR */
s_listen->sk->sk_rcvtimeo = timeo;
s_listen->sk->sk_sndtimeo = timeo;
+ drbd_setbufsize(s_listen, mdev->net_conf->sndbuf_size,
+ mdev->net_conf->rcvbuf_size);
what = "bind before listen";
err = s_listen->ops->bind(s_listen,
@@ -856,16 +878,6 @@ retry:
sock->sk->sk_priority = TC_PRIO_INTERACTIVE_BULK;
msock->sk->sk_priority = TC_PRIO_INTERACTIVE;
- if (mdev->net_conf->sndbuf_size) {
- sock->sk->sk_sndbuf = mdev->net_conf->sndbuf_size;
- sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK;
- }
-
- if (mdev->net_conf->rcvbuf_size) {
- sock->sk->sk_rcvbuf = mdev->net_conf->rcvbuf_size;
- sock->sk->sk_userlocks |= SOCK_RCVBUF_LOCK;
- }
-
/* NOT YET ...
* sock->sk->sk_sndtimeo = mdev->net_conf->timeout*HZ/10;
* sock->sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
@@ -1154,17 +1166,6 @@ int drbd_submit_ee(struct drbd_conf *mdev, struct drbd_epoch_entry *e,
unsigned n_bios = 0;
unsigned nr_pages = (ds + PAGE_SIZE -1) >> PAGE_SHIFT;
- if (atomic_read(&mdev->new_c_uuid)) {
- if (atomic_add_unless(&mdev->new_c_uuid, -1, 1)) {
- drbd_uuid_new_current(mdev);
- drbd_md_sync(mdev);
-
- atomic_dec(&mdev->new_c_uuid);
- wake_up(&mdev->misc_wait);
- }
- wait_event(mdev->misc_wait, !atomic_read(&mdev->new_c_uuid));
- }
-
/* In most cases, we will only need one bio. But in case the lower
* level restrictions happen to be different at this offset on this
* side than those of the sending peer, we may need to submit the
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 3397f11d0ba9..654f1ef5cbb0 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -102,32 +102,7 @@ static void _req_is_done(struct drbd_conf *mdev, struct drbd_request *req, const
}
}
- /* if it was a local io error, we want to notify our
- * peer about that, and see if we need to
- * detach the disk and stuff.
- * to avoid allocating some special work
- * struct, reuse the request. */
-
- /* THINK
- * why do we do this not when we detect the error,
- * but delay it until it is "done", i.e. possibly
- * until the next barrier ack? */
-
- if (rw == WRITE &&
- ((s & RQ_LOCAL_MASK) && !(s & RQ_LOCAL_OK))) {
- if (!(req->w.list.next == LIST_POISON1 ||
- list_empty(&req->w.list))) {
- /* DEBUG ASSERT only; if this triggers, we
- * probably corrupt the worker list here */
- dev_err(DEV, "req->w.list.next = %p\n", req->w.list.next);
- dev_err(DEV, "req->w.list.prev = %p\n", req->w.list.prev);
- }
- req->w.cb = w_io_error;
- drbd_queue_work(&mdev->data.work, &req->w);
- /* drbd_req_free() is done in w_io_error */
- } else {
- drbd_req_free(req);
- }
+ drbd_req_free(req);
}
static void queue_barrier(struct drbd_conf *mdev)
@@ -453,9 +428,6 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
req->rq_state |= RQ_LOCAL_COMPLETED;
req->rq_state &= ~RQ_LOCAL_PENDING;
- dev_alert(DEV, "Local WRITE failed sec=%llus size=%u\n",
- (unsigned long long)req->sector, req->size);
- /* and now: check how to handle local io error. */
__drbd_chk_io_error(mdev, FALSE);
_req_may_be_done(req, m);
put_ldev(mdev);
@@ -475,22 +447,21 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
req->rq_state |= RQ_LOCAL_COMPLETED;
req->rq_state &= ~RQ_LOCAL_PENDING;
- dev_alert(DEV, "Local READ failed sec=%llus size=%u\n",
- (unsigned long long)req->sector, req->size);
- /* _req_mod(req,to_be_send); oops, recursion... */
D_ASSERT(!(req->rq_state & RQ_NET_MASK));
- req->rq_state |= RQ_NET_PENDING;
- inc_ap_pending(mdev);
__drbd_chk_io_error(mdev, FALSE);
put_ldev(mdev);
- /* NOTE: if we have no connection,
- * or know the peer has no good data either,
- * then we don't actually need to "queue_for_net_read",
- * but we do so anyways, since the drbd_io_error()
- * and the potential state change to "Diskless"
- * needs to be done from process context */
+ /* no point in retrying if there is no good remote data,
+ * or we have no connection. */
+ if (mdev->state.pdsk != D_UP_TO_DATE) {
+ _req_may_be_done(req, m);
+ break;
+ }
+
+ /* _req_mod(req,to_be_send); oops, recursion... */
+ req->rq_state |= RQ_NET_PENDING;
+ inc_ap_pending(mdev);
/* fall through: _req_mod(req,queue_for_net_read); */
case queue_for_net_read:
@@ -600,6 +571,9 @@ void __req_mod(struct drbd_request *req, enum drbd_req_event what,
_req_may_be_done(req, m);
break;
+ case read_retry_remote_canceled:
+ req->rq_state &= ~RQ_NET_QUEUED;
+ /* fall through, in case we raced with drbd_disconnect */
case connection_lost_while_pending:
/* transfer log cleanup after connection loss */
/* assert something? */
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 16119d7056cc..02d575d24518 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -91,6 +91,7 @@ enum drbd_req_event {
send_failed,
handed_over_to_network,
connection_lost_while_pending,
+ read_retry_remote_canceled,
recv_acked_by_peer,
write_acked_by_peer,
write_acked_by_peer_and_sis, /* and set_in_sync */
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c
index 727ff6339754..b623ceee2a4a 100644
--- a/drivers/block/drbd/drbd_worker.c
+++ b/drivers/block/drbd/drbd_worker.c
@@ -224,9 +224,6 @@ void drbd_endio_pri(struct bio *bio, int error)
enum drbd_req_event what;
int uptodate = bio_flagged(bio, BIO_UPTODATE);
- if (error)
- dev_warn(DEV, "p %s: error=%d\n",
- bio_data_dir(bio) == WRITE ? "write" : "read", error);
if (!error && !uptodate) {
dev_warn(DEV, "p %s: setting error to -EIO\n",
bio_data_dir(bio) == WRITE ? "write" : "read");
@@ -257,20 +254,6 @@ void drbd_endio_pri(struct bio *bio, int error)
complete_master_bio(mdev, &m);
}
-int w_io_error(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
-{
- struct drbd_request *req = container_of(w, struct drbd_request, w);
-
- /* NOTE: mdev->ldev can be NULL by the time we get here! */
- /* D_ASSERT(mdev->ldev->dc.on_io_error != EP_PASS_ON); */
-
- /* the only way this callback is scheduled is from _req_may_be_done,
- * when it is done and had a local write error, see comments there */
- drbd_req_free(req);
-
- return TRUE;
-}
-
int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
{
struct drbd_request *req = container_of(w, struct drbd_request, w);
@@ -280,12 +263,9 @@ int w_read_retry_remote(struct drbd_conf *mdev, struct drbd_work *w, int cancel)
* to give the disk the chance to relocate that block */
spin_lock_irq(&mdev->req_lock);
- if (cancel ||
- mdev->state.conn < C_CONNECTED ||
- mdev->state.pdsk <= D_INCONSISTENT) {
- _req_mod(req, send_canceled);
+ if (cancel || mdev->state.pdsk != D_UP_TO_DATE) {
+ _req_mod(req, read_retry_remote_canceled);
spin_unlock_irq(&mdev->req_lock);
- dev_alert(DEV, "WE ARE LOST. Local IO failure, no peer.\n");
return 1;
}
spin_unlock_irq(&mdev->req_lock);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 52f2d11bc7b9..ed6fb91123ab 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1159,8 +1159,10 @@ static struct of_device_id swim3_match[] =
static struct macio_driver swim3_driver =
{
- .name = "swim3",
- .match_table = swim3_match,
+ .driver = {
+ .name = "swim3",
+ .of_match_table = swim3_match,
+ },
.probe = swim3_attach,
#if 0
.suspend = swim3_suspend,
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 83fa09a836ca..258bc2ae2885 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -298,7 +298,9 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
err = virtio_config_val(vdev, VIRTIO_BLK_F_SEG_MAX,
offsetof(struct virtio_blk_config, seg_max),
&sg_elems);
- if (err)
+
+ /* We need at least one SG element, whatever they say. */
+ if (err || !sg_elems)
sg_elems = 1;
/* We need an extra sg elements at head and tail. */
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index f09fc0e2062d..7cfcc629a7fd 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1123,6 +1123,7 @@ source "drivers/s390/char/Kconfig"
config RAMOOPS
tristate "Log panic/oops to a RAM buffer"
+ depends on HAS_IOMEM
default n
help
This enables panic and oops messages to be logged to a circular
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 88d6eac69754..273cee1cc77b 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
+obj-$(CONFIG_HVC_TILE) += hvc_tile.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index e8ea6825822c..9344216183a4 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -1059,7 +1059,7 @@ static void intel_i9xx_setup_flush(void)
}
}
-static int intel_i915_configure(void)
+static int intel_i9xx_configure(void)
{
struct aper_size_info_fixed *current_size;
u32 temp;
@@ -1207,6 +1207,38 @@ static int intel_i9xx_fetch_size(void)
return 0;
}
+static int intel_i915_get_gtt_size(void)
+{
+ int size;
+
+ if (IS_G33) {
+ u16 gmch_ctrl;
+
+ /* G33's GTT size defined in gmch_ctrl */
+ pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
+ switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
+ case G33_PGETBL_SIZE_1M:
+ size = 1024;
+ break;
+ case G33_PGETBL_SIZE_2M:
+ size = 2048;
+ break;
+ default:
+ dev_info(&agp_bridge->dev->dev,
+ "unknown page table size 0x%x, assuming 512KB\n",
+ (gmch_ctrl & G33_PGETBL_SIZE_MASK));
+ size = 512;
+ }
+ } else {
+ /* On previous hardware, the GTT size was just what was
+ * required to map the aperture.
+ */
+ size = agp_bridge->driver->fetch_size();
+ }
+
+ return KB(size);
+}
+
/* The intel i915 automatically initializes the agp aperture during POST.
* Use the memory already set aside for in the GTT.
*/
@@ -1216,7 +1248,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
struct aper_size_info_fixed *size;
int num_entries;
u32 temp, temp2;
- int gtt_map_size = 256 * 1024;
+ int gtt_map_size;
size = agp_bridge->current_size;
page_order = size->page_order;
@@ -1226,8 +1258,8 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
- if (IS_G33)
- gtt_map_size = 1024 * 1024; /* 1M on G33 */
+ gtt_map_size = intel_i915_get_gtt_size();
+
intel_private.gtt = ioremap(temp2, gtt_map_size);
if (!intel_private.gtt)
return -ENOMEM;
@@ -1422,7 +1454,7 @@ static const struct agp_bridge_driver intel_915_driver = {
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
.needs_scratch_page = true,
- .configure = intel_i915_configure,
+ .configure = intel_i9xx_configure,
.fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.mask_memory = intel_i810_mask_memory,
@@ -1455,7 +1487,7 @@ static const struct agp_bridge_driver intel_i965_driver = {
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
.needs_scratch_page = true,
- .configure = intel_i915_configure,
+ .configure = intel_i9xx_configure,
.fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.mask_memory = intel_i965_mask_memory,
@@ -1488,7 +1520,7 @@ static const struct agp_bridge_driver intel_g33_driver = {
.size_type = FIXED_APER_SIZE,
.num_aperture_sizes = 4,
.needs_scratch_page = true,
- .configure = intel_i915_configure,
+ .configure = intel_i9xx_configure,
.fetch_size = intel_i9xx_fetch_size,
.cleanup = intel_i915_cleanup,
.mask_memory = intel_i965_mask_memory,
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 95db71360d24..f845a8f718b3 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -415,7 +415,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
bridge->gatt_table_real = (u32 *) table;
/* Need to clear out any dirty data still sitting in caches */
flush_dcache_range((unsigned long)table,
- (unsigned long)(table_end + PAGE_SIZE));
+ (unsigned long)table_end + 1);
bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG);
if (bridge->gatt_table == NULL)
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 5a80ad68ef22..7b01bc609de3 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -1149,7 +1149,7 @@ out_err:
* Note: If it is called early in the boot process, @val is stored and
* parsed later in hvc_iucv_init().
*/
-static int param_set_vmidfilter(const char *val, struct kernel_param *kp)
+static int param_set_vmidfilter(const char *val, const struct kernel_param *kp)
{
int rc;
@@ -1176,7 +1176,7 @@ static int param_set_vmidfilter(const char *val, struct kernel_param *kp)
* The function stores the filter as a comma-separated list of z/VM user IDs
* in @buffer. Typically, sysfs routines call this function for attr show.
*/
-static int param_get_vmidfilter(char *buffer, struct kernel_param *kp)
+static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp)
{
int rc;
size_t index, len;
@@ -1203,6 +1203,11 @@ static int param_get_vmidfilter(char *buffer, struct kernel_param *kp)
#define param_check_vmidfilter(name, p) __param_check(name, p, void)
+static struct kernel_param_ops param_ops_vmidfilter = {
+ .set = param_set_vmidfilter,
+ .get = param_get_vmidfilter,
+};
+
/**
* hvc_iucv_init() - z/VM IUCV HVC device driver initialization
*/
diff --git a/drivers/char/hvc_tile.c b/drivers/char/hvc_tile.c
new file mode 100644
index 000000000000..75715b32f22a
--- /dev/null
+++ b/drivers/char/hvc_tile.c
@@ -0,0 +1,67 @@
+/*
+ * %LINUX_LICENSE%
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Tilera TILE Processor hypervisor console
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+
+#include <hv/hypervisor.h>
+
+#include "hvc_console.h"
+
+static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count)
+{
+ return hv_console_write((HV_VirtAddr)buf, count);
+}
+
+static int hvc_tile_get_chars(uint32_t vt, char *buf, int count)
+{
+ int i, c;
+
+ for (i = 0; i < count; ++i) {
+ c = hv_console_read_if_ready();
+ if (c < 0)
+ break;
+ buf[i] = c;
+ }
+
+ return i;
+}
+
+static const struct hv_ops hvc_tile_get_put_ops = {
+ .get_chars = hvc_tile_get_chars,
+ .put_chars = hvc_tile_put_chars,
+};
+
+static int __init hvc_tile_console_init(void)
+{
+ extern void disable_early_printk(void);
+ hvc_instantiate(0, 0, &hvc_tile_get_put_ops);
+ add_preferred_console("hvc", 0, NULL);
+ disable_early_printk();
+ return 0;
+}
+console_initcall(hvc_tile_console_init);
+
+static int __init hvc_tile_init(void)
+{
+ hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128);
+ return 0;
+}
+device_initcall(hvc_tile_init);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 82bcdb262a3a..654d566ca57c 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -196,7 +196,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf);
*/
static int start_now;
-static int set_param_int(const char *val, struct kernel_param *kp)
+static int set_param_timeout(const char *val, const struct kernel_param *kp)
{
char *endp;
int l;
@@ -215,10 +215,11 @@ static int set_param_int(const char *val, struct kernel_param *kp)
return rv;
}
-static int get_param_int(char *buffer, struct kernel_param *kp)
-{
- return sprintf(buffer, "%i", *((int *)kp->arg));
-}
+static struct kernel_param_ops param_ops_timeout = {
+ .set = set_param_timeout,
+ .get = param_get_int,
+};
+#define param_check_timeout param_check_int
typedef int (*action_fn)(const char *intval, char *outval);
@@ -227,7 +228,7 @@ static int preaction_op(const char *inval, char *outval);
static int preop_op(const char *inval, char *outval);
static void check_parms(void);
-static int set_param_str(const char *val, struct kernel_param *kp)
+static int set_param_str(const char *val, const struct kernel_param *kp)
{
action_fn fn = (action_fn) kp->arg;
int rv = 0;
@@ -251,7 +252,7 @@ static int set_param_str(const char *val, struct kernel_param *kp)
return rv;
}
-static int get_param_str(char *buffer, struct kernel_param *kp)
+static int get_param_str(char *buffer, const struct kernel_param *kp)
{
action_fn fn = (action_fn) kp->arg;
int rv;
@@ -263,7 +264,7 @@ static int get_param_str(char *buffer, struct kernel_param *kp)
}
-static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp)
+static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp)
{
int rv = param_set_int(val, kp);
if (rv)
@@ -276,27 +277,38 @@ static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp)
return 0;
}
-module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int,
- &ifnum_to_use, 0644);
+static struct kernel_param_ops param_ops_wdog_ifnum = {
+ .set = set_param_wdog_ifnum,
+ .get = param_get_int,
+};
+
+#define param_check_wdog_ifnum param_check_int
+
+static struct kernel_param_ops param_ops_str = {
+ .set = set_param_str,
+ .get = get_param_str,
+};
+
+module_param(ifnum_to_use, wdog_ifnum, 0644);
MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog "
"timer. Setting to -1 defaults to the first registered "
"interface");
-module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644);
+module_param(timeout, timeout, 0644);
MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
-module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644);
+module_param(pretimeout, timeout, 0644);
MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
-module_param_call(action, set_param_str, get_param_str, action_op, 0644);
+module_param_cb(action, &param_ops_str, action_op, 0644);
MODULE_PARM_DESC(action, "Timeout action. One of: "
"reset, none, power_cycle, power_off.");
-module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644);
+module_param_cb(preaction, &param_ops_str, preaction_op, 0644);
MODULE_PARM_DESC(preaction, "Pretimeout action. One of: "
"pre_none, pre_smi, pre_nmi, pre_int.");
-module_param_call(preop, set_param_str, get_param_str, preop_op, 0644);
+module_param_cb(preop, &param_ops_str, preop_op, 0644);
MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: "
"preop_none, preop_panic, preop_give_data.");
diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c
index c4161d5e053d..e4089c432f15 100644
--- a/drivers/char/n_gsm.c
+++ b/drivers/char/n_gsm.c
@@ -904,9 +904,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
int len;
/* Priority ordering: We should do priority with RR of the groups */
int i = 1;
- unsigned long flags;
- spin_lock_irqsave(&gsm->tx_lock, flags);
while (i < NUM_DLCI) {
struct gsm_dlci *dlci;
@@ -927,7 +925,6 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
if (len == 0)
i++;
}
- spin_unlock_irqrestore(&gsm->tx_lock, flags);
}
/**
@@ -2230,12 +2227,16 @@ static int gsmld_open(struct tty_struct *tty)
static void gsmld_write_wakeup(struct tty_struct *tty)
{
struct gsm_mux *gsm = tty->disc_data;
+ unsigned long flags;
/* Queue poll */
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
gsm_data_kick(gsm);
- if (gsm->tx_bytes < TX_THRESH_LO)
+ if (gsm->tx_bytes < TX_THRESH_LO) {
+ spin_lock_irqsave(&gsm->tx_lock, flags);
gsm_dlci_data_sweep(gsm);
+ spin_unlock_irqrestore(&gsm->tx_lock, flags);
+ }
}
/**
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 5d15630a5830..d5a2e2f9287d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -717,7 +717,7 @@ int sysrq_toggle_support(int enable_mask)
sysrq_unregister_handler();
}
- return 0;
+ return was_enabled;
}
static int __sysrq_swap_key_ops(int key, struct sysrq_key_op *insert_op_p,
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 8c99bf1b5e9f..942a9826bd23 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -529,6 +529,10 @@ static bool will_write_block(struct port *port)
{
bool ret;
+ if (!port->guest_connected) {
+ /* Port got hot-unplugged. Let's exit. */
+ return false;
+ }
if (!port->host_connected)
return true;
@@ -1099,6 +1103,13 @@ static int remove_port(struct port *port)
{
struct port_buffer *buf;
+ if (port->guest_connected) {
+ port->guest_connected = false;
+ port->host_connected = false;
+ wake_up_interruptible(&port->waitqueue);
+ send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+ }
+
spin_lock_irq(&port->portdev->ports_lock);
list_del(&port->list);
spin_unlock_irq(&port->portdev->ports_lock);
@@ -1120,9 +1131,6 @@ static int remove_port(struct port *port)
hvc_remove(port->cons.hvc);
#endif
}
- if (port->guest_connected)
- send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
-
sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
device_destroy(pdrvdata.class, port->dev->devt);
cdev_del(&port->cdev);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 6aa10284104a..cb19dbc52136 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -1303,7 +1303,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (!perm)
goto eperm;
ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
- if (!ret)
+ if (ret)
+ ret = -EFAULT;
+ else
con_clear_unimap(vc, &ui);
break;
}
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index f6677cb19789..f3d3898898ed 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -412,18 +412,10 @@ static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
static int sh_cmt_clocksource_enable(struct clocksource *cs)
{
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
- int ret;
p->total_cycles = 0;
- ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
- if (ret)
- return ret;
-
- /* TODO: calculate good shift from rate and counter bit width */
- cs->shift = 0;
- cs->mult = clocksource_hz2mult(p->rate, cs->shift);
- return 0;
+ return sh_cmt_start(p, FLAG_CLOCKSOURCE);
}
static void sh_cmt_clocksource_disable(struct clocksource *cs)
@@ -450,8 +442,20 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
cs->resume = sh_cmt_clocksource_resume;
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ /* clk_get_rate() needs an enabled clock */
+ clk_enable(p->clk);
+ p->rate = clk_get_rate(p->clk) / (p->width == 16) ? 512 : 8;
+ clk_disable(p->clk);
+
+ /* TODO: calculate good shift from rate and counter bit width */
+ cs->shift = 10;
+ cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+
dev_info(&p->pdev->dev, "used as clock source\n");
+
clocksource_register(cs);
+
return 0;
}
diff --git a/drivers/clocksource/sh_tmu.c b/drivers/clocksource/sh_tmu.c
index 8e44e14ec4c2..de715901b82a 100644
--- a/drivers/clocksource/sh_tmu.c
+++ b/drivers/clocksource/sh_tmu.c
@@ -199,16 +199,8 @@ static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
static int sh_tmu_clocksource_enable(struct clocksource *cs)
{
struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
- int ret;
-
- ret = sh_tmu_enable(p);
- if (ret)
- return ret;
- /* TODO: calculate good shift from rate and counter bit width */
- cs->shift = 10;
- cs->mult = clocksource_hz2mult(p->rate, cs->shift);
- return 0;
+ return sh_tmu_enable(p);
}
static void sh_tmu_clocksource_disable(struct clocksource *cs)
@@ -228,6 +220,16 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
cs->disable = sh_tmu_clocksource_disable;
cs->mask = CLOCKSOURCE_MASK(32);
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
+
+ /* clk_get_rate() needs an enabled clock */
+ clk_enable(p->clk);
+ /* channel will be configured at parent clock / 4 */
+ p->rate = clk_get_rate(p->clk) / 4;
+ clk_disable(p->clk);
+ /* TODO: calculate good shift from rate and counter bit width */
+ cs->shift = 10;
+ cs->mult = clocksource_hz2mult(p->rate, cs->shift);
+
dev_info(&p->pdev->dev, "used as clock source\n");
clocksource_register(cs);
return 0;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 063b2184caf5..6ba37c10700d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -68,7 +68,7 @@ static DEFINE_PER_CPU(int, cpufreq_policy_cpu);
static DEFINE_PER_CPU(struct rw_semaphore, cpu_policy_rwsem);
#define lock_policy_rwsem(mode, cpu) \
-int lock_policy_rwsem_##mode \
+static int lock_policy_rwsem_##mode \
(int cpu) \
{ \
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu); \
@@ -83,26 +83,22 @@ int lock_policy_rwsem_##mode \
}
lock_policy_rwsem(read, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_read);
lock_policy_rwsem(write, cpu);
-EXPORT_SYMBOL_GPL(lock_policy_rwsem_write);
-void unlock_policy_rwsem_read(int cpu)
+static void unlock_policy_rwsem_read(int cpu)
{
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
BUG_ON(policy_cpu == -1);
up_read(&per_cpu(cpu_policy_rwsem, policy_cpu));
}
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_read);
-void unlock_policy_rwsem_write(int cpu)
+static void unlock_policy_rwsem_write(int cpu)
{
int policy_cpu = per_cpu(cpufreq_policy_cpu, cpu);
BUG_ON(policy_cpu == -1);
up_write(&per_cpu(cpu_policy_rwsem, policy_cpu));
}
-EXPORT_SYMBOL_GPL(unlock_policy_rwsem_write);
/* internal prototypes */
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index e1314212d8d4..7b5093664e49 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -459,6 +459,17 @@ static struct attribute_group dbs_attr_group_old = {
/************************** sysfs end ************************/
+static void dbs_freq_increase(struct cpufreq_policy *p, unsigned int freq)
+{
+ if (dbs_tuners_ins.powersave_bias)
+ freq = powersave_bias_target(p, freq, CPUFREQ_RELATION_H);
+ else if (p->cur == p->max)
+ return;
+
+ __cpufreq_driver_target(p, freq, dbs_tuners_ins.powersave_bias ?
+ CPUFREQ_RELATION_L : CPUFREQ_RELATION_H);
+}
+
static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{
unsigned int max_load_freq;
@@ -551,19 +562,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
/* Check for frequency increase */
if (max_load_freq > dbs_tuners_ins.up_threshold * policy->cur) {
- /* if we are already at full speed then break out early */
- if (!dbs_tuners_ins.powersave_bias) {
- if (policy->cur == policy->max)
- return;
-
- __cpufreq_driver_target(policy, policy->max,
- CPUFREQ_RELATION_H);
- } else {
- int freq = powersave_bias_target(policy, policy->max,
- CPUFREQ_RELATION_H);
- __cpufreq_driver_target(policy, freq,
- CPUFREQ_RELATION_L);
- }
+ dbs_freq_increase(policy, policy->max);
return;
}
@@ -610,7 +609,9 @@ static void do_dbs_timer(struct work_struct *work)
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- delay -= jiffies % delay;
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
+
mutex_lock(&dbs_info->timer_mutex);
/* Common NORMAL_SAMPLE setup */
@@ -635,7 +636,9 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
{
/* We want all CPUs to do sampling nearly on same jiffy */
int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
- delay -= jiffies % delay;
+
+ if (num_online_cpus() > 1)
+ delay -= jiffies % delay;
dbs_info->sample_type = DBS_NORMAL_SAMPLE;
INIT_DELAYED_WORK_DEFERRABLE(&dbs_info->work, do_dbs_timer);
diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c
index 9d65b371de64..983530ba04a7 100644
--- a/drivers/crypto/amcc/crypto4xx_core.c
+++ b/drivers/crypto/amcc/crypto4xx_core.c
@@ -1158,7 +1158,7 @@ static int __init crypto4xx_probe(struct of_device *ofdev,
struct device *dev = &ofdev->dev;
struct crypto4xx_core_device *core_dev;
- rc = of_address_to_resource(ofdev->node, 0, &res);
+ rc = of_address_to_resource(ofdev->dev.of_node, 0, &res);
if (rc)
return -ENODEV;
@@ -1215,13 +1215,13 @@ static int __init crypto4xx_probe(struct of_device *ofdev,
(unsigned long) dev);
/* Register for Crypto isr, Crypto Engine IRQ */
- core_dev->irq = irq_of_parse_and_map(ofdev->node, 0);
+ core_dev->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
rc = request_irq(core_dev->irq, crypto4xx_ce_interrupt_handler, 0,
core_dev->dev->name, dev);
if (rc)
goto err_request_irq;
- core_dev->dev->ce_base = of_iomap(ofdev->node, 0);
+ core_dev->dev->ce_base = of_iomap(ofdev->dev.of_node, 0);
if (!core_dev->dev->ce_base) {
dev_err(dev, "failed to of_iomap\n");
goto err_iomap;
diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c
index e095422b58dd..7d279e578df5 100644
--- a/drivers/crypto/mv_cesa.c
+++ b/drivers/crypto/mv_cesa.c
@@ -1055,20 +1055,20 @@ static int mv_probe(struct platform_device *pdev)
cp->queue_th = kthread_run(queue_manag, cp, "mv_crypto");
if (IS_ERR(cp->queue_th)) {
ret = PTR_ERR(cp->queue_th);
- goto err_thread;
+ goto err_unmap_sram;
}
ret = request_irq(irq, crypto_int, IRQF_DISABLED, dev_name(&pdev->dev),
cp);
if (ret)
- goto err_unmap_sram;
+ goto err_thread;
writel(SEC_INT_ACCEL0_DONE, cpg->reg + SEC_ACCEL_INT_MASK);
writel(SEC_CFG_STOP_DIG_ERR, cpg->reg + SEC_ACCEL_CFG);
ret = crypto_register_alg(&mv_aes_alg_ecb);
if (ret)
- goto err_reg;
+ goto err_irq;
ret = crypto_register_alg(&mv_aes_alg_cbc);
if (ret)
@@ -1091,9 +1091,9 @@ static int mv_probe(struct platform_device *pdev)
return 0;
err_unreg_ecb:
crypto_unregister_alg(&mv_aes_alg_ecb);
-err_thread:
+err_irq:
free_irq(irq, cp);
-err_reg:
+err_thread:
kthread_stop(cp->queue_th);
err_unmap_sram:
iounmap(cp->sram);
diff --git a/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c
index 8566be832f51..b99c38f23d61 100644
--- a/drivers/crypto/n2_core.c
+++ b/drivers/crypto/n2_core.c
@@ -239,86 +239,119 @@ static inline bool n2_should_run_async(struct spu_queue *qp, int this_len)
}
#endif
-struct n2_base_ctx {
- struct list_head list;
+struct n2_ahash_alg {
+ struct list_head entry;
+ const char *hash_zero;
+ const u32 *hash_init;
+ u8 hw_op_hashsz;
+ u8 digest_size;
+ u8 auth_type;
+ u8 hmac_type;
+ struct ahash_alg alg;
+};
+
+static inline struct n2_ahash_alg *n2_ahash_alg(struct crypto_tfm *tfm)
+{
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct ahash_alg *ahash_alg;
+
+ ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+ return container_of(ahash_alg, struct n2_ahash_alg, alg);
+}
+
+struct n2_hmac_alg {
+ const char *child_alg;
+ struct n2_ahash_alg derived;
};
-static void n2_base_ctx_init(struct n2_base_ctx *ctx)
+static inline struct n2_hmac_alg *n2_hmac_alg(struct crypto_tfm *tfm)
{
- INIT_LIST_HEAD(&ctx->list);
+ struct crypto_alg *alg = tfm->__crt_alg;
+ struct ahash_alg *ahash_alg;
+
+ ahash_alg = container_of(alg, struct ahash_alg, halg.base);
+
+ return container_of(ahash_alg, struct n2_hmac_alg, derived.alg);
}
struct n2_hash_ctx {
- struct n2_base_ctx base;
+ struct crypto_ahash *fallback_tfm;
+};
- struct crypto_ahash *fallback;
+#define N2_HASH_KEY_MAX 32 /* HW limit for all HMAC requests */
- /* These next three members must match the layout created by
- * crypto_init_shash_ops_async. This allows us to properly
- * plumb requests we can't do in hardware down to the fallback
- * operation, providing all of the data structures and layouts
- * expected by those paths.
- */
- struct ahash_request fallback_req;
- struct shash_desc fallback_desc;
+struct n2_hmac_ctx {
+ struct n2_hash_ctx base;
+
+ struct crypto_shash *child_shash;
+
+ int hash_key_len;
+ unsigned char hash_key[N2_HASH_KEY_MAX];
+};
+
+struct n2_hash_req_ctx {
union {
struct md5_state md5;
struct sha1_state sha1;
struct sha256_state sha256;
} u;
- unsigned char hash_key[64];
- unsigned char keyed_zero_hash[32];
+ struct ahash_request fallback_req;
};
static int n2_hash_async_init(struct ahash_request *req)
{
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback);
- ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- return crypto_ahash_init(&ctx->fallback_req);
+ return crypto_ahash_init(&rctx->fallback_req);
}
static int n2_hash_async_update(struct ahash_request *req)
{
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback);
- ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- ctx->fallback_req.nbytes = req->nbytes;
- ctx->fallback_req.src = req->src;
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
- return crypto_ahash_update(&ctx->fallback_req);
+ return crypto_ahash_update(&rctx->fallback_req);
}
static int n2_hash_async_final(struct ahash_request *req)
{
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback);
- ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- ctx->fallback_req.result = req->result;
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.result = req->result;
- return crypto_ahash_final(&ctx->fallback_req);
+ return crypto_ahash_final(&rctx->fallback_req);
}
static int n2_hash_async_finup(struct ahash_request *req)
{
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback);
- ctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- ctx->fallback_req.nbytes = req->nbytes;
- ctx->fallback_req.src = req->src;
- ctx->fallback_req.result = req->result;
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
- return crypto_ahash_finup(&ctx->fallback_req);
+ return crypto_ahash_finup(&rctx->fallback_req);
}
static int n2_hash_cra_init(struct crypto_tfm *tfm)
@@ -338,7 +371,10 @@ static int n2_hash_cra_init(struct crypto_tfm *tfm)
goto out;
}
- ctx->fallback = fallback_tfm;
+ crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) +
+ crypto_ahash_reqsize(fallback_tfm)));
+
+ ctx->fallback_tfm = fallback_tfm;
return 0;
out:
@@ -350,7 +386,95 @@ static void n2_hash_cra_exit(struct crypto_tfm *tfm)
struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
struct n2_hash_ctx *ctx = crypto_ahash_ctx(ahash);
- crypto_free_ahash(ctx->fallback);
+ crypto_free_ahash(ctx->fallback_tfm);
+}
+
+static int n2_hmac_cra_init(struct crypto_tfm *tfm)
+{
+ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+ struct n2_hmac_alg *n2alg = n2_hmac_alg(tfm);
+ struct crypto_ahash *fallback_tfm;
+ struct crypto_shash *child_shash;
+ int err;
+
+ fallback_tfm = crypto_alloc_ahash(fallback_driver_name, 0,
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback_tfm)) {
+ pr_warning("Fallback driver '%s' could not be loaded!\n",
+ fallback_driver_name);
+ err = PTR_ERR(fallback_tfm);
+ goto out;
+ }
+
+ child_shash = crypto_alloc_shash(n2alg->child_alg, 0, 0);
+ if (IS_ERR(child_shash)) {
+ pr_warning("Child shash '%s' could not be loaded!\n",
+ n2alg->child_alg);
+ err = PTR_ERR(child_shash);
+ goto out_free_fallback;
+ }
+
+ crypto_ahash_set_reqsize(ahash, (sizeof(struct n2_hash_req_ctx) +
+ crypto_ahash_reqsize(fallback_tfm)));
+
+ ctx->child_shash = child_shash;
+ ctx->base.fallback_tfm = fallback_tfm;
+ return 0;
+
+out_free_fallback:
+ crypto_free_ahash(fallback_tfm);
+
+out:
+ return err;
+}
+
+static void n2_hmac_cra_exit(struct crypto_tfm *tfm)
+{
+ struct crypto_ahash *ahash = __crypto_ahash_cast(tfm);
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(ahash);
+
+ crypto_free_ahash(ctx->base.fallback_tfm);
+ crypto_free_shash(ctx->child_shash);
+}
+
+static int n2_hmac_async_setkey(struct crypto_ahash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+ struct crypto_shash *child_shash = ctx->child_shash;
+ struct crypto_ahash *fallback_tfm;
+ struct {
+ struct shash_desc shash;
+ char ctx[crypto_shash_descsize(child_shash)];
+ } desc;
+ int err, bs, ds;
+
+ fallback_tfm = ctx->base.fallback_tfm;
+ err = crypto_ahash_setkey(fallback_tfm, key, keylen);
+ if (err)
+ return err;
+
+ desc.shash.tfm = child_shash;
+ desc.shash.flags = crypto_ahash_get_flags(tfm) &
+ CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ bs = crypto_shash_blocksize(child_shash);
+ ds = crypto_shash_digestsize(child_shash);
+ BUG_ON(ds > N2_HASH_KEY_MAX);
+ if (keylen > bs) {
+ err = crypto_shash_digest(&desc.shash, key, keylen,
+ ctx->hash_key);
+ if (err)
+ return err;
+ keylen = ds;
+ } else if (keylen <= N2_HASH_KEY_MAX)
+ memcpy(ctx->hash_key, key, keylen);
+
+ ctx->hash_key_len = keylen;
+
+ return err;
}
static unsigned long wait_for_tail(struct spu_queue *qp)
@@ -382,12 +506,12 @@ static unsigned long submit_and_wait_for_tail(struct spu_queue *qp,
return hv_ret;
}
-static int n2_hash_async_digest(struct ahash_request *req,
- unsigned int auth_type, unsigned int digest_size,
- unsigned int result_size, void *hash_loc)
+static int n2_do_async_digest(struct ahash_request *req,
+ unsigned int auth_type, unsigned int digest_size,
+ unsigned int result_size, void *hash_loc,
+ unsigned long auth_key, unsigned int auth_key_len)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
struct cwq_initial_entry *ent;
struct crypto_hash_walk walk;
struct spu_queue *qp;
@@ -399,18 +523,19 @@ static int n2_hash_async_digest(struct ahash_request *req,
* exceed 2^16.
*/
if (unlikely(req->nbytes > (1 << 16))) {
- ctx->fallback_req.base.tfm = crypto_ahash_tfm(ctx->fallback);
- ctx->fallback_req.base.flags =
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+ struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
+
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags =
req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
- ctx->fallback_req.nbytes = req->nbytes;
- ctx->fallback_req.src = req->src;
- ctx->fallback_req.result = req->result;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
- return crypto_ahash_digest(&ctx->fallback_req);
+ return crypto_ahash_digest(&rctx->fallback_req);
}
- n2_base_ctx_init(&ctx->base);
-
nbytes = crypto_hash_walk_first(req, &walk);
cpu = get_cpu();
@@ -425,13 +550,13 @@ static int n2_hash_async_digest(struct ahash_request *req,
*/
ent = qp->q + qp->tail;
- ent->control = control_word_base(nbytes, 0, 0,
+ ent->control = control_word_base(nbytes, auth_key_len, 0,
auth_type, digest_size,
false, true, false, false,
OPCODE_INPLACE_BIT |
OPCODE_AUTH_MAC);
ent->src_addr = __pa(walk.data);
- ent->auth_key_addr = 0UL;
+ ent->auth_key_addr = auth_key;
ent->auth_iv_addr = __pa(hash_loc);
ent->final_auth_state_addr = 0UL;
ent->enc_key_addr = 0UL;
@@ -470,118 +595,55 @@ out:
return err;
}
-static int n2_md5_async_digest(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- struct md5_state *m = &ctx->u.md5;
-
- if (unlikely(req->nbytes == 0)) {
- static const char md5_zero[MD5_DIGEST_SIZE] = {
- 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
- 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
- };
-
- memcpy(req->result, md5_zero, MD5_DIGEST_SIZE);
- return 0;
- }
- m->hash[0] = cpu_to_le32(0x67452301);
- m->hash[1] = cpu_to_le32(0xefcdab89);
- m->hash[2] = cpu_to_le32(0x98badcfe);
- m->hash[3] = cpu_to_le32(0x10325476);
-
- return n2_hash_async_digest(req, AUTH_TYPE_MD5,
- MD5_DIGEST_SIZE, MD5_DIGEST_SIZE,
- m->hash);
-}
-
-static int n2_sha1_async_digest(struct ahash_request *req)
+static int n2_hash_async_digest(struct ahash_request *req)
{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- struct sha1_state *s = &ctx->u.sha1;
+ struct n2_ahash_alg *n2alg = n2_ahash_alg(req->base.tfm);
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+ int ds;
+ ds = n2alg->digest_size;
if (unlikely(req->nbytes == 0)) {
- static const char sha1_zero[SHA1_DIGEST_SIZE] = {
- 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
- 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
- 0x07, 0x09
- };
-
- memcpy(req->result, sha1_zero, SHA1_DIGEST_SIZE);
+ memcpy(req->result, n2alg->hash_zero, ds);
return 0;
}
- s->state[0] = SHA1_H0;
- s->state[1] = SHA1_H1;
- s->state[2] = SHA1_H2;
- s->state[3] = SHA1_H3;
- s->state[4] = SHA1_H4;
+ memcpy(&rctx->u, n2alg->hash_init, n2alg->hw_op_hashsz);
- return n2_hash_async_digest(req, AUTH_TYPE_SHA1,
- SHA1_DIGEST_SIZE, SHA1_DIGEST_SIZE,
- s->state);
+ return n2_do_async_digest(req, n2alg->auth_type,
+ n2alg->hw_op_hashsz, ds,
+ &rctx->u, 0UL, 0);
}
-static int n2_sha256_async_digest(struct ahash_request *req)
+static int n2_hmac_async_digest(struct ahash_request *req)
{
+ struct n2_hmac_alg *n2alg = n2_hmac_alg(req->base.tfm);
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- struct sha256_state *s = &ctx->u.sha256;
+ struct n2_hmac_ctx *ctx = crypto_ahash_ctx(tfm);
+ int ds;
- if (req->nbytes == 0) {
- static const char sha256_zero[SHA256_DIGEST_SIZE] = {
- 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
- 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
- 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
- 0x1b, 0x78, 0x52, 0xb8, 0x55
- };
+ ds = n2alg->derived.digest_size;
+ if (unlikely(req->nbytes == 0) ||
+ unlikely(ctx->hash_key_len > N2_HASH_KEY_MAX)) {
+ struct n2_hash_req_ctx *rctx = ahash_request_ctx(req);
+ struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- memcpy(req->result, sha256_zero, SHA256_DIGEST_SIZE);
- return 0;
- }
- s->state[0] = SHA256_H0;
- s->state[1] = SHA256_H1;
- s->state[2] = SHA256_H2;
- s->state[3] = SHA256_H3;
- s->state[4] = SHA256_H4;
- s->state[5] = SHA256_H5;
- s->state[6] = SHA256_H6;
- s->state[7] = SHA256_H7;
-
- return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
- SHA256_DIGEST_SIZE, SHA256_DIGEST_SIZE,
- s->state);
-}
-
-static int n2_sha224_async_digest(struct ahash_request *req)
-{
- struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
- struct n2_hash_ctx *ctx = crypto_ahash_ctx(tfm);
- struct sha256_state *s = &ctx->u.sha256;
-
- if (req->nbytes == 0) {
- static const char sha224_zero[SHA224_DIGEST_SIZE] = {
- 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
- 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
- 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
- 0x2f
- };
+ ahash_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm);
+ rctx->fallback_req.base.flags =
+ req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;
+ rctx->fallback_req.nbytes = req->nbytes;
+ rctx->fallback_req.src = req->src;
+ rctx->fallback_req.result = req->result;
- memcpy(req->result, sha224_zero, SHA224_DIGEST_SIZE);
- return 0;
+ return crypto_ahash_digest(&rctx->fallback_req);
}
- s->state[0] = SHA224_H0;
- s->state[1] = SHA224_H1;
- s->state[2] = SHA224_H2;
- s->state[3] = SHA224_H3;
- s->state[4] = SHA224_H4;
- s->state[5] = SHA224_H5;
- s->state[6] = SHA224_H6;
- s->state[7] = SHA224_H7;
+ memcpy(&rctx->u, n2alg->derived.hash_init,
+ n2alg->derived.hw_op_hashsz);
- return n2_hash_async_digest(req, AUTH_TYPE_SHA256,
- SHA256_DIGEST_SIZE, SHA224_DIGEST_SIZE,
- s->state);
+ return n2_do_async_digest(req, n2alg->derived.hmac_type,
+ n2alg->derived.hw_op_hashsz, ds,
+ &rctx->u,
+ __pa(&ctx->hash_key),
+ ctx->hash_key_len);
}
struct n2_cipher_context {
@@ -1208,35 +1270,92 @@ static LIST_HEAD(cipher_algs);
struct n2_hash_tmpl {
const char *name;
- int (*digest)(struct ahash_request *req);
+ const char *hash_zero;
+ const u32 *hash_init;
+ u8 hw_op_hashsz;
u8 digest_size;
u8 block_size;
+ u8 auth_type;
+ u8 hmac_type;
+};
+
+static const char md5_zero[MD5_DIGEST_SIZE] = {
+ 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e,
+};
+static const u32 md5_init[MD5_HASH_WORDS] = {
+ cpu_to_le32(0x67452301),
+ cpu_to_le32(0xefcdab89),
+ cpu_to_le32(0x98badcfe),
+ cpu_to_le32(0x10325476),
+};
+static const char sha1_zero[SHA1_DIGEST_SIZE] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32,
+ 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8,
+ 0x07, 0x09
+};
+static const u32 sha1_init[SHA1_DIGEST_SIZE / 4] = {
+ SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4,
+};
+static const char sha256_zero[SHA256_DIGEST_SIZE] = {
+ 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a,
+ 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae,
+ 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99,
+ 0x1b, 0x78, 0x52, 0xb8, 0x55
+};
+static const u32 sha256_init[SHA256_DIGEST_SIZE / 4] = {
+ SHA256_H0, SHA256_H1, SHA256_H2, SHA256_H3,
+ SHA256_H4, SHA256_H5, SHA256_H6, SHA256_H7,
};
+static const char sha224_zero[SHA224_DIGEST_SIZE] = {
+ 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47,
+ 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2,
+ 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4,
+ 0x2f
+};
+static const u32 sha224_init[SHA256_DIGEST_SIZE / 4] = {
+ SHA224_H0, SHA224_H1, SHA224_H2, SHA224_H3,
+ SHA224_H4, SHA224_H5, SHA224_H6, SHA224_H7,
+};
+
static const struct n2_hash_tmpl hash_tmpls[] = {
{ .name = "md5",
- .digest = n2_md5_async_digest,
+ .hash_zero = md5_zero,
+ .hash_init = md5_init,
+ .auth_type = AUTH_TYPE_MD5,
+ .hmac_type = AUTH_TYPE_HMAC_MD5,
+ .hw_op_hashsz = MD5_DIGEST_SIZE,
.digest_size = MD5_DIGEST_SIZE,
.block_size = MD5_HMAC_BLOCK_SIZE },
{ .name = "sha1",
- .digest = n2_sha1_async_digest,
+ .hash_zero = sha1_zero,
+ .hash_init = sha1_init,
+ .auth_type = AUTH_TYPE_SHA1,
+ .hmac_type = AUTH_TYPE_HMAC_SHA1,
+ .hw_op_hashsz = SHA1_DIGEST_SIZE,
.digest_size = SHA1_DIGEST_SIZE,
.block_size = SHA1_BLOCK_SIZE },
{ .name = "sha256",
- .digest = n2_sha256_async_digest,
+ .hash_zero = sha256_zero,
+ .hash_init = sha256_init,
+ .auth_type = AUTH_TYPE_SHA256,
+ .hmac_type = AUTH_TYPE_HMAC_SHA256,
+ .hw_op_hashsz = SHA256_DIGEST_SIZE,
.digest_size = SHA256_DIGEST_SIZE,
.block_size = SHA256_BLOCK_SIZE },
{ .name = "sha224",
- .digest = n2_sha224_async_digest,
+ .hash_zero = sha224_zero,
+ .hash_init = sha224_init,
+ .auth_type = AUTH_TYPE_SHA256,
+ .hmac_type = AUTH_TYPE_RESERVED,
+ .hw_op_hashsz = SHA256_DIGEST_SIZE,
.digest_size = SHA224_DIGEST_SIZE,
.block_size = SHA224_BLOCK_SIZE },
};
#define NUM_HASH_TMPLS ARRAY_SIZE(hash_tmpls)
-struct n2_ahash_alg {
- struct list_head entry;
- struct ahash_alg alg;
-};
static LIST_HEAD(ahash_algs);
+static LIST_HEAD(hmac_algs);
static int algs_registered;
@@ -1244,12 +1363,18 @@ static void __n2_unregister_algs(void)
{
struct n2_cipher_alg *cipher, *cipher_tmp;
struct n2_ahash_alg *alg, *alg_tmp;
+ struct n2_hmac_alg *hmac, *hmac_tmp;
list_for_each_entry_safe(cipher, cipher_tmp, &cipher_algs, entry) {
crypto_unregister_alg(&cipher->alg);
list_del(&cipher->entry);
kfree(cipher);
}
+ list_for_each_entry_safe(hmac, hmac_tmp, &hmac_algs, derived.entry) {
+ crypto_unregister_ahash(&hmac->derived.alg);
+ list_del(&hmac->derived.entry);
+ kfree(hmac);
+ }
list_for_each_entry_safe(alg, alg_tmp, &ahash_algs, entry) {
crypto_unregister_ahash(&alg->alg);
list_del(&alg->entry);
@@ -1289,8 +1414,49 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl)
list_add(&p->entry, &cipher_algs);
err = crypto_register_alg(alg);
if (err) {
+ pr_err("%s alg registration failed\n", alg->cra_name);
list_del(&p->entry);
kfree(p);
+ } else {
+ pr_info("%s alg registered\n", alg->cra_name);
+ }
+ return err;
+}
+
+static int __devinit __n2_register_one_hmac(struct n2_ahash_alg *n2ahash)
+{
+ struct n2_hmac_alg *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct ahash_alg *ahash;
+ struct crypto_alg *base;
+ int err;
+
+ if (!p)
+ return -ENOMEM;
+
+ p->child_alg = n2ahash->alg.halg.base.cra_name;
+ memcpy(&p->derived, n2ahash, sizeof(struct n2_ahash_alg));
+ INIT_LIST_HEAD(&p->derived.entry);
+
+ ahash = &p->derived.alg;
+ ahash->digest = n2_hmac_async_digest;
+ ahash->setkey = n2_hmac_async_setkey;
+
+ base = &ahash->halg.base;
+ snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", p->child_alg);
+ snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "hmac-%s-n2", p->child_alg);
+
+ base->cra_ctxsize = sizeof(struct n2_hmac_ctx);
+ base->cra_init = n2_hmac_cra_init;
+ base->cra_exit = n2_hmac_cra_exit;
+
+ list_add(&p->derived.entry, &hmac_algs);
+ err = crypto_register_ahash(ahash);
+ if (err) {
+ pr_err("%s alg registration failed\n", base->cra_name);
+ list_del(&p->derived.entry);
+ kfree(p);
+ } else {
+ pr_info("%s alg registered\n", base->cra_name);
}
return err;
}
@@ -1306,12 +1472,19 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
if (!p)
return -ENOMEM;
+ p->hash_zero = tmpl->hash_zero;
+ p->hash_init = tmpl->hash_init;
+ p->auth_type = tmpl->auth_type;
+ p->hmac_type = tmpl->hmac_type;
+ p->hw_op_hashsz = tmpl->hw_op_hashsz;
+ p->digest_size = tmpl->digest_size;
+
ahash = &p->alg;
ahash->init = n2_hash_async_init;
ahash->update = n2_hash_async_update;
ahash->final = n2_hash_async_final;
ahash->finup = n2_hash_async_finup;
- ahash->digest = tmpl->digest;
+ ahash->digest = n2_hash_async_digest;
halg = &ahash->halg;
halg->digestsize = tmpl->digest_size;
@@ -1330,9 +1503,14 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl)
list_add(&p->entry, &ahash_algs);
err = crypto_register_ahash(ahash);
if (err) {
+ pr_err("%s alg registration failed\n", base->cra_name);
list_del(&p->entry);
kfree(p);
+ } else {
+ pr_info("%s alg registered\n", base->cra_name);
}
+ if (!err && p->hmac_type != AUTH_TYPE_RESERVED)
+ err = __n2_register_one_hmac(p);
return err;
}
@@ -1398,7 +1576,7 @@ static int find_devino_index(struct of_device *dev, struct spu_mdesc_info *ip,
intr = ip->ino_table[i].intr;
- dev_intrs = of_get_property(dev->node, "interrupts", NULL);
+ dev_intrs = of_get_property(dev->dev.of_node, "interrupts", NULL);
if (!dev_intrs)
return -ENODEV;
@@ -1449,7 +1627,7 @@ static int queue_cache_init(void)
{
if (!queue_cache[HV_NCS_QTYPE_MAU - 1])
queue_cache[HV_NCS_QTYPE_MAU - 1] =
- kmem_cache_create("cwq_queue",
+ kmem_cache_create("mau_queue",
(MAU_NUM_ENTRIES *
MAU_ENTRY_SIZE),
MAU_ENTRY_SIZE, 0, NULL);
@@ -1574,7 +1752,7 @@ static int spu_mdesc_walk_arcs(struct mdesc_handle *mdesc,
id = mdesc_get_property(mdesc, tgt, "id", NULL);
if (table[*id] != NULL) {
dev_err(&dev->dev, "%s: SPU cpu slot already set.\n",
- dev->node->full_name);
+ dev->dev.of_node->full_name);
return -EINVAL;
}
cpu_set(*id, p->sharing);
@@ -1595,7 +1773,7 @@ static int handle_exec_unit(struct spu_mdesc_info *ip, struct list_head *list,
p = kzalloc(sizeof(struct spu_queue), GFP_KERNEL);
if (!p) {
dev_err(&dev->dev, "%s: Could not allocate SPU queue.\n",
- dev->node->full_name);
+ dev->dev.of_node->full_name);
return -ENOMEM;
}
@@ -1684,7 +1862,7 @@ static int __devinit grab_mdesc_irq_props(struct mdesc_handle *mdesc,
const unsigned int *reg;
u64 node;
- reg = of_get_property(dev->node, "reg", NULL);
+ reg = of_get_property(dev->dev.of_node, "reg", NULL);
if (!reg)
return -ENODEV;
@@ -1836,7 +2014,7 @@ static int __devinit n2_crypto_probe(struct of_device *dev,
n2_spu_driver_version();
- full_name = dev->node->full_name;
+ full_name = dev->dev.of_node->full_name;
pr_info("Found N2CP at %s\n", full_name);
np = alloc_n2cp();
@@ -1948,7 +2126,7 @@ static int __devinit n2_mau_probe(struct of_device *dev,
n2_spu_driver_version();
- full_name = dev->node->full_name;
+ full_name = dev->dev.of_node->full_name;
pr_info("Found NCP at %s\n", full_name);
mp = alloc_ncp();
@@ -2034,8 +2212,11 @@ static struct of_device_id n2_crypto_match[] = {
MODULE_DEVICE_TABLE(of, n2_crypto_match);
static struct of_platform_driver n2_crypto_driver = {
- .name = "n2cp",
- .match_table = n2_crypto_match,
+ .driver = {
+ .name = "n2cp",
+ .owner = THIS_MODULE,
+ .of_match_table = n2_crypto_match,
+ },
.probe = n2_crypto_probe,
.remove = __devexit_p(n2_crypto_remove),
};
@@ -2055,8 +2236,11 @@ static struct of_device_id n2_mau_match[] = {
MODULE_DEVICE_TABLE(of, n2_mau_match);
static struct of_platform_driver n2_mau_driver = {
- .name = "ncp",
- .match_table = n2_mau_match,
+ .driver = {
+ .name = "ncp",
+ .owner = THIS_MODULE,
+ .of_match_table = n2_mau_match,
+ },
.probe = n2_mau_probe,
.remove = __devexit_p(n2_mau_remove),
};
diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c
index 8b034337793f..7d1485676886 100644
--- a/drivers/crypto/omap-sham.c
+++ b/drivers/crypto/omap-sham.c
@@ -15,7 +15,6 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
-#include <linux/version.h>
#include <linux/err.h>
#include <linux/device.h>
#include <linux/module.h>
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 9e01e96fee94..8344375dc015 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -128,7 +128,7 @@ config TXX9_DMAC
config SH_DMAE
tristate "Renesas SuperH DMAC support"
- depends on SUPERH && SH_DMA
+ depends on (SUPERH && SH_DMA) || (ARM && ARCH_SHMOBILE)
depends on !SH_DMA_API
select DMA_ENGINE
help
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 201e6e19c344..14a8c0f1698e 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -630,7 +630,7 @@ mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
static int __devinit mpc_dma_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dn = op->node;
+ struct device_node *dn = op->dev.of_node;
struct device *dev = &op->dev;
struct dma_device *dma;
struct mpc_dma *mdma;
@@ -771,12 +771,12 @@ static struct of_device_id mpc_dma_match[] = {
};
static struct of_platform_driver mpc_dma_driver = {
- .match_table = mpc_dma_match,
.probe = mpc_dma_probe,
.remove = __devexit_p(mpc_dma_remove),
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mpc_dma_match,
},
};
diff --git a/drivers/dma/ppc4xx/adma.c b/drivers/dma/ppc4xx/adma.c
index fa98abe4686f..5a22ca6927e5 100644
--- a/drivers/dma/ppc4xx/adma.c
+++ b/drivers/dma/ppc4xx/adma.c
@@ -4394,7 +4394,7 @@ static void ppc440spe_adma_release_irqs(struct ppc440spe_adma_device *adev,
static int __devinit ppc440spe_adma_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct resource res;
struct ppc440spe_adma_device *adev;
struct ppc440spe_adma_chan *chan;
@@ -4626,7 +4626,7 @@ out:
static int __devexit ppc440spe_adma_remove(struct of_device *ofdev)
{
struct ppc440spe_adma_device *adev = dev_get_drvdata(&ofdev->dev);
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct resource res;
struct dma_chan *chan, *_chan;
struct ppc_dma_chan_ref *ref, *_ref;
diff --git a/drivers/dma/shdma.c b/drivers/dma/shdma.c
index a2a519fd2a24..fb64cf36ba61 100644
--- a/drivers/dma/shdma.c
+++ b/drivers/dma/shdma.c
@@ -816,7 +816,7 @@ static irqreturn_t sh_dmae_interrupt(int irq, void *data)
return ret;
}
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
static irqreturn_t sh_dmae_err(int irq, void *data)
{
struct sh_dmae_device *shdev = (struct sh_dmae_device *)data;
@@ -1057,7 +1057,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
/* Default transfer size of 32 bytes requires 32-byte alignment */
shdev->common.copy_align = LOG2_DEFAULT_XFER_SIZE;
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
if (!chanirq_res)
@@ -1082,7 +1082,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
#else
chanirq_res = errirq_res;
-#endif /* CONFIG_CPU_SH4 */
+#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */
if (chanirq_res->start == chanirq_res->end &&
!platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
@@ -1129,7 +1129,7 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
chan_probe_err:
sh_dmae_chan_remove(shdev);
eirqres:
-#if defined(CONFIG_CPU_SH4)
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
free_irq(errirq, shdev);
eirq_err:
#endif
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 55c9c59b3f71..e1ceaf6a1c50 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -39,14 +39,6 @@ config EDAC_DEBUG
there're four debug levels (x=0,1,2,3 from low to high).
Usually you should select 'N'.
-config EDAC_DEBUG_VERBOSE
- bool "More verbose debugging"
- depends on EDAC_DEBUG
- help
- This option makes debugging information more verbose.
- Source file name and line number where debugging message
- printed will be added to debugging message.
-
config EDAC_DECODE_MCE
tristate "Decode MCEs in human-readable form (only on AMD for now)"
depends on CPU_SUP_AMD && X86_MCE
@@ -69,6 +61,9 @@ config EDAC_MM_EDAC
occurred so that a particular failing memory module can be
replaced. If unsure, select 'Y'.
+config EDAC_MCE
+ bool
+
config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
@@ -166,6 +161,16 @@ config EDAC_I5400
Support for error detection and correction the Intel
i5400 MCH chipset (Seaburg).
+config EDAC_I7CORE
+ tristate "Intel i7 Core (Nehalem) processors"
+ depends on EDAC_MM_EDAC && PCI && X86
+ select EDAC_MCE
+ help
+ Support for error detection and correction the Intel
+ i7 Core (Nehalem) Integrated Memory Controller that exists on
+ newer processors like i7 Core, i7 Core Extreme, Xeon 35xx
+ and Xeon 55xx processors.
+
config EDAC_I82860
tristate "Intel 82860"
depends on EDAC_MM_EDAC && PCI && X86_32
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index bc5dc232a0fb..ca6b1bb24ccc 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
+obj-$(CONFIG_EDAC_MCE) += edac_mce.o
edac_core-objs := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
edac_core-objs += edac_module.o edac_device_sysfs.o
@@ -23,6 +24,7 @@ obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
obj-$(CONFIG_EDAC_I5000) += i5000_edac.o
obj-$(CONFIG_EDAC_I5100) += i5100_edac.o
obj-$(CONFIG_EDAC_I5400) += i5400_edac.o
+obj-$(CONFIG_EDAC_I7CORE) += i7core_edac.o
obj-$(CONFIG_EDAC_E7XXX) += e7xxx_edac.o
obj-$(CONFIG_EDAC_E752X) += e752x_edac.o
obj-$(CONFIG_EDAC_I82443BXGX) += i82443bxgx_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index cf17dbb8014f..c3b647dc2ee9 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -160,7 +160,7 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
return 0;
}
-static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
{
struct amd64_pvt *pvt = mci->pvt_info;
u32 min_scrubrate = 0x0;
@@ -178,10 +178,10 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 *bandwidth)
default:
amd64_printk(KERN_ERR, "Unsupported family!\n");
- break;
+ return -EINVAL;
}
- return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, *bandwidth,
- min_scrubrate);
+ return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, bandwidth,
+ min_scrubrate);
}
static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
@@ -888,6 +888,8 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
return;
}
+ debugf1("F3x180 (ECC symb.): %s\n", (pvt->x8_syndromes ? "x8" : "x4"));
+
/* Only if NOT ganged does dclr1 have valid info */
if (!dct_ganging_enabled(pvt))
amd64_dump_dramcfg_low(pvt->dclr1, 1);
@@ -1430,7 +1432,7 @@ static inline u64 f10_get_base_addr_offset(u64 sys_addr, int hi_range_sel,
u64 chan_off;
if (hi_range_sel) {
- if (!(dct_sel_base_addr & 0xFFFFF800) &&
+ if (!(dct_sel_base_addr & 0xFFFF0000) &&
hole_valid && (sys_addr >= 0x100000000ULL))
chan_off = hole_off << 16;
else
@@ -1955,124 +1957,19 @@ static int map_err_sym_to_channel(int err_sym, int sym_size)
static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
{
struct amd64_pvt *pvt = mci->pvt_info;
- u32 value = 0;
- int err_sym = 0;
-
- amd64_read_pci_cfg(pvt->misc_f3_ctl, 0x180, &value);
+ int err_sym = 0, sym_size = 0;
- /* F3x180[EccSymbolSize]=1, x8 symbols */
- if (boot_cpu_data.x86 == 0x10 &&
- boot_cpu_data.x86_model > 7 &&
- value & BIT(25)) {
+ if (pvt->x8_syndromes) {
+ sym_size = 8;
err_sym = decode_syndrome(syndrome, x8_vectors,
ARRAY_SIZE(x8_vectors), 8);
- return map_err_sym_to_channel(err_sym, 8);
} else {
+ sym_size = 4;
err_sym = decode_syndrome(syndrome, x4_vectors,
ARRAY_SIZE(x4_vectors), 4);
- return map_err_sym_to_channel(err_sym, 4);
}
-}
-
-/*
- * Check for valid error in the NB Status High register. If so, proceed to read
- * NB Status Low, NB Address Low and NB Address High registers and store data
- * into error structure.
- *
- * Returns:
- * - 1: if hardware regs contains valid error info
- * - 0: if no valid error is indicated
- */
-static int amd64_get_error_info_regs(struct mem_ctl_info *mci,
- struct err_regs *regs)
-{
- struct amd64_pvt *pvt;
- struct pci_dev *misc_f3_ctl;
-
- pvt = mci->pvt_info;
- misc_f3_ctl = pvt->misc_f3_ctl;
-
- if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSH, &regs->nbsh))
- return 0;
-
- if (!(regs->nbsh & K8_NBSH_VALID_BIT))
- return 0;
-
- /* valid error, read remaining error information registers */
- if (amd64_read_pci_cfg(misc_f3_ctl, K8_NBSL, &regs->nbsl) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAL, &regs->nbeal) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBEAH, &regs->nbeah) ||
- amd64_read_pci_cfg(misc_f3_ctl, K8_NBCFG, &regs->nbcfg))
- return 0;
- return 1;
-}
-
-/*
- * This function is called to retrieve the error data from hardware and store it
- * in the info structure.
- *
- * Returns:
- * - 1: if a valid error is found
- * - 0: if no error is found
- */
-static int amd64_get_error_info(struct mem_ctl_info *mci,
- struct err_regs *info)
-{
- struct amd64_pvt *pvt;
- struct err_regs regs;
-
- pvt = mci->pvt_info;
-
- if (!amd64_get_error_info_regs(mci, info))
- return 0;
-
- /*
- * Here's the problem with the K8's EDAC reporting: There are four
- * registers which report pieces of error information. They are shared
- * between CEs and UEs. Furthermore, contrary to what is stated in the
- * BKDG, the overflow bit is never used! Every error always updates the
- * reporting registers.
- *
- * Can you see the race condition? All four error reporting registers
- * must be read before a new error updates them! There is no way to read
- * all four registers atomically. The best than can be done is to detect
- * that a race has occured and then report the error without any kind of
- * precision.
- *
- * What is still positive is that errors are still reported and thus
- * problems can still be detected - just not localized because the
- * syndrome and address are spread out across registers.
- *
- * Grrrrr!!!!! Here's hoping that AMD fixes this in some future K8 rev.
- * UEs and CEs should have separate register sets with proper overflow
- * bits that are used! At very least the problem can be fixed by
- * honoring the ErrValid bit in 'nbsh' and not updating registers - just
- * set the overflow bit - unless the current error is CE and the new
- * error is UE which would be the only situation for overwriting the
- * current values.
- */
-
- regs = *info;
-
- /* Use info from the second read - most current */
- if (unlikely(!amd64_get_error_info_regs(mci, info)))
- return 0;
-
- /* clear the error bits in hardware */
- pci_write_bits32(pvt->misc_f3_ctl, K8_NBSH, 0, K8_NBSH_VALID_BIT);
-
- /* Check for the possible race condition */
- if ((regs.nbsh != info->nbsh) ||
- (regs.nbsl != info->nbsl) ||
- (regs.nbeah != info->nbeah) ||
- (regs.nbeal != info->nbeal)) {
- amd64_mc_printk(mci, KERN_WARNING,
- "hardware STATUS read access race condition "
- "detected!\n");
- return 0;
- }
- return 1;
+ return map_err_sym_to_channel(err_sym, sym_size);
}
/*
@@ -2199,20 +2096,6 @@ void amd64_decode_bus_error(int node_id, struct err_regs *regs)
}
/*
- * The main polling 'check' function, called FROM the edac core to perform the
- * error checking and if an error is encountered, error processing.
- */
-static void amd64_check(struct mem_ctl_info *mci)
-{
- struct err_regs regs;
-
- if (amd64_get_error_info(mci, &regs)) {
- struct amd64_pvt *pvt = mci->pvt_info;
- amd_decode_nb_mce(pvt->mc_node_id, &regs, 1);
- }
-}
-
-/*
* Input:
* 1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
* 2) AMD Family index value
@@ -2284,6 +2167,7 @@ static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
static void amd64_read_mc_registers(struct amd64_pvt *pvt)
{
u64 msr_val;
+ u32 tmp;
int dram;
/*
@@ -2353,6 +2237,17 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
}
+
+ amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
+
+ /* F3x180[EccSymbolSize]=1, x8 symbols */
+ if (boot_cpu_data.x86 == 0x10 &&
+ boot_cpu_data.x86_model > 7 &&
+ tmp & BIT(25))
+ pvt->x8_syndromes = true;
+ else
+ pvt->x8_syndromes = false;
+
amd64_dump_misc_regs(pvt);
}
@@ -2739,9 +2634,6 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
mci->dev_name = pci_name(pvt->dram_f2_ctl);
mci->ctl_page_to_phys = NULL;
- /* IMPORTANT: Set the polling 'check' function in this module */
- mci->edac_check = amd64_check;
-
/* memory scrubber interface */
mci->set_sdram_scrub_rate = amd64_set_scrub_rate;
mci->get_sdram_scrub_rate = amd64_get_scrub_rate;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 0d4bf5638243..b46061e7b45d 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -244,44 +244,17 @@
#define F10_DCTL_SEL_LOW 0x110
-
-#define dct_sel_baseaddr(pvt) \
- ((pvt->dram_ctl_select_low) & 0xFFFFF800)
-
-#define dct_sel_interleave_addr(pvt) \
- (((pvt->dram_ctl_select_low) >> 6) & 0x3)
-
-enum {
- F10_DCTL_SEL_LOW_DctSelHiRngEn = BIT(0),
- F10_DCTL_SEL_LOW_DctSelIntLvEn = BIT(2),
- F10_DCTL_SEL_LOW_DctGangEn = BIT(4),
- F10_DCTL_SEL_LOW_DctDatIntLv = BIT(5),
- F10_DCTL_SEL_LOW_DramEnable = BIT(8),
- F10_DCTL_SEL_LOW_MemCleared = BIT(10),
-};
-
-#define dct_high_range_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelHiRngEn)
-
-#define dct_interleave_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctSelIntLvEn)
-
-#define dct_ganging_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctGangEn)
-
-#define dct_data_intlv_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DctDatIntLv)
-
-#define dct_dram_enabled(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_DramEnable)
-
-#define dct_memory_cleared(pvt) \
- (pvt->dram_ctl_select_low & F10_DCTL_SEL_LOW_MemCleared)
-
+#define dct_sel_baseaddr(pvt) ((pvt->dram_ctl_select_low) & 0xFFFFF800)
+#define dct_sel_interleave_addr(pvt) (((pvt->dram_ctl_select_low) >> 6) & 0x3)
+#define dct_high_range_enabled(pvt) (pvt->dram_ctl_select_low & BIT(0))
+#define dct_interleave_enabled(pvt) (pvt->dram_ctl_select_low & BIT(2))
+#define dct_ganging_enabled(pvt) (pvt->dram_ctl_select_low & BIT(4))
+#define dct_data_intlv_enabled(pvt) (pvt->dram_ctl_select_low & BIT(5))
+#define dct_dram_enabled(pvt) (pvt->dram_ctl_select_low & BIT(8))
+#define dct_memory_cleared(pvt) (pvt->dram_ctl_select_low & BIT(10))
#define F10_DCTL_SEL_HIGH 0x114
-
/*
* Function 3 - Misc Control
*/
@@ -382,6 +355,8 @@ enum {
#define K8_NBCAP_SECDED BIT(3)
#define K8_NBCAP_DCT_DUAL BIT(0)
+#define EXT_NB_MCA_CFG 0x180
+
/* MSRs */
#define K8_MSR_MCGCTL_NBE BIT(4)
@@ -471,6 +446,8 @@ struct amd64_pvt {
u32 dram_ctl_select_high; /* DRAM Controller Select High Reg */
u32 online_spare; /* On-Line spare Reg */
+ bool x8_syndromes;
+
/* temp storage for when input is received from sysfs */
struct err_regs ctl_error_info;
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index ae3f80c54198..073f5a06d238 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -958,7 +958,7 @@ static void e752x_check(struct mem_ctl_info *mci)
}
/* Program byte/sec bandwidth scrub rate to hardware */
-static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
+static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 new_bw)
{
const struct scrubrate *scrubrates;
struct e752x_pvt *pvt = (struct e752x_pvt *) mci->pvt_info;
@@ -975,7 +975,7 @@ static int set_sdram_scrub_rate(struct mem_ctl_info *mci, u32 *new_bw)
* desired rate and program the cooresponding register value.
*/
for (i = 0; scrubrates[i].bandwidth != SDRATE_EOT; i++)
- if (scrubrates[i].bandwidth >= *new_bw)
+ if (scrubrates[i].bandwidth >= new_bw)
break;
if (scrubrates[i].bandwidth == SDRATE_EOT)
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index 001b2e797fb3..ce7146677e9b 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -49,21 +49,15 @@
#define edac_printk(level, prefix, fmt, arg...) \
printk(level "EDAC " prefix ": " fmt, ##arg)
-#define edac_printk_verbose(level, prefix, fmt, arg...) \
- printk(level "EDAC " prefix ": " "in %s, line at %d: " fmt, \
- __FILE__, __LINE__, ##arg)
-
#define edac_mc_printk(mci, level, fmt, arg...) \
printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg)
#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \
printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg)
-/* edac_device printk */
#define edac_device_printk(ctl, level, fmt, arg...) \
printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg)
-/* edac_pci printk */
#define edac_pci_printk(ctl, level, fmt, arg...) \
printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg)
@@ -76,21 +70,12 @@
extern int edac_debug_level;
extern const char *edac_mem_types[];
-#ifndef CONFIG_EDAC_DEBUG_VERBOSE
#define edac_debug_printk(level, fmt, arg...) \
do { \
if (level <= edac_debug_level) \
edac_printk(KERN_DEBUG, EDAC_DEBUG, \
"%s: " fmt, __func__, ##arg); \
} while (0)
-#else /* CONFIG_EDAC_DEBUG_VERBOSE */
-#define edac_debug_printk(level, fmt, arg...) \
- do { \
- if (level <= edac_debug_level) \
- edac_printk_verbose(KERN_DEBUG, EDAC_DEBUG, fmt, \
- ##arg); \
- } while (0)
-#endif
#define debugf0( ... ) edac_debug_printk(0, __VA_ARGS__ )
#define debugf1( ... ) edac_debug_printk(1, __VA_ARGS__ )
@@ -341,12 +326,30 @@ struct csrow_info {
struct channel_info *channels;
};
+struct mcidev_sysfs_group {
+ const char *name; /* group name */
+ struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */
+};
+
+struct mcidev_sysfs_group_kobj {
+ struct list_head list; /* list for all instances within a mc */
+
+ struct kobject kobj; /* kobj for the group */
+
+ struct mcidev_sysfs_group *grp; /* group description table */
+ struct mem_ctl_info *mci; /* the parent */
+};
+
/* mcidev_sysfs_attribute structure
* used for driver sysfs attributes and in mem_ctl_info
* sysfs top level entries
*/
struct mcidev_sysfs_attribute {
- struct attribute attr;
+ /* It should use either attr or grp */
+ struct attribute attr;
+ struct mcidev_sysfs_group *grp; /* Points to a group of attributes */
+
+ /* Ops for show/store values at the attribute - not used on group */
ssize_t (*show)(struct mem_ctl_info *,char *);
ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
};
@@ -375,7 +378,7 @@ struct mem_ctl_info {
internal representation and configures whatever else needs
to be configured.
*/
- int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 * bw);
+ int (*set_sdram_scrub_rate) (struct mem_ctl_info * mci, u32 bw);
/* Get the current sdram memory scrub rate from the internal
representation and converts it to the closest matching
@@ -424,6 +427,9 @@ struct mem_ctl_info {
/* edac sysfs device control */
struct kobject edac_mci_kobj;
+ /* list for all grp instances within a mc */
+ struct list_head grp_kobj_list;
+
/* Additional top controller level attributes, but specified
* by the low level driver.
*
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 418b65f1a1da..8aad94d10c0c 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -124,19 +124,6 @@ static const char *edac_caps[] = {
[EDAC_S16ECD16ED] = "S16ECD16ED"
};
-
-
-static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
-{
- int *value = (int *)ptr;
-
- if (isdigit(*buffer))
- *value = simple_strtoul(buffer, NULL, 0);
-
- return count;
-}
-
-
/* EDAC sysfs CSROW data structures and methods
*/
@@ -450,53 +437,54 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
/* memory scrubbing */
static ssize_t mci_sdram_scrub_rate_store(struct mem_ctl_info *mci,
- const char *data, size_t count)
+ const char *data, size_t count)
{
- u32 bandwidth = -1;
+ unsigned long bandwidth = 0;
+ int err;
- if (mci->set_sdram_scrub_rate) {
+ if (!mci->set_sdram_scrub_rate) {
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "Memory scrub rate setting not implemented!\n");
+ return -EINVAL;
+ }
- memctrl_int_store(&bandwidth, data, count);
+ if (strict_strtoul(data, 10, &bandwidth) < 0)
+ return -EINVAL;
- if (!(*mci->set_sdram_scrub_rate) (mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set successfully, applied: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate set FAILED, could not apply: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
- edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'set'control is not implemented!\n");
+ err = mci->set_sdram_scrub_rate(mci, (u32)bandwidth);
+ if (err) {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Failed setting scrub rate to %lu\n", bandwidth);
+ return -EINVAL;
+ }
+ else {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Scrub rate set to: %lu\n", bandwidth);
+ return count;
}
- return count;
}
static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
{
- u32 bandwidth = -1;
-
- if (mci->get_sdram_scrub_rate) {
- if (!(*mci->get_sdram_scrub_rate) (mci, &bandwidth)) {
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate successfully, fetched: %d\n",
- bandwidth);
- } else {
- /* FIXME: error codes maybe? */
- edac_printk(KERN_DEBUG, EDAC_MC,
- "Scrub rate fetch FAILED, got: %d\n",
- bandwidth);
- }
- } else {
- /* FIXME: produce "not implemented" ERROR for user-side. */
+ u32 bandwidth = 0;
+ int err;
+
+ if (!mci->get_sdram_scrub_rate) {
edac_printk(KERN_WARNING, EDAC_MC,
- "Memory scrubbing 'get' control is not implemented\n");
+ "Memory scrub rate reading not implemented\n");
+ return -EINVAL;
+ }
+
+ err = mci->get_sdram_scrub_rate(mci, &bandwidth);
+ if (err) {
+ edac_printk(KERN_DEBUG, EDAC_MC, "Error reading scrub rate\n");
+ return err;
+ }
+ else {
+ edac_printk(KERN_DEBUG, EDAC_MC,
+ "Read scrub rate: %d\n", bandwidth);
+ return sprintf(data, "%d\n", bandwidth);
}
- return sprintf(data, "%d\n", bandwidth);
}
/* default attribute files for the MCI object */
@@ -557,6 +545,8 @@ static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
if (mcidev_attr->show)
return mcidev_attr->show(mem_ctl_info, buffer);
@@ -569,6 +559,8 @@ static ssize_t mcidev_store(struct kobject *kobj, struct attribute *attr,
struct mem_ctl_info *mem_ctl_info = to_mci(kobj);
struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
if (mcidev_attr->store)
return mcidev_attr->store(mem_ctl_info, buffer, count);
@@ -726,28 +718,118 @@ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci)
#define EDAC_DEVICE_SYMLINK "device"
+#define grp_to_mci(k) (container_of(k, struct mcidev_sysfs_group_kobj, kobj)->mci)
+
+/* MCI show/store functions for top most object */
+static ssize_t inst_grp_show(struct kobject *kobj, struct attribute *attr,
+ char *buffer)
+{
+ struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+ if (mcidev_attr->show)
+ return mcidev_attr->show(mem_ctl_info, buffer);
+
+ return -EIO;
+}
+
+static ssize_t inst_grp_store(struct kobject *kobj, struct attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct mem_ctl_info *mem_ctl_info = grp_to_mci(kobj);
+ struct mcidev_sysfs_attribute *mcidev_attr = to_mcidev_attr(attr);
+
+ debugf1("%s() mem_ctl_info %p\n", __func__, mem_ctl_info);
+
+ if (mcidev_attr->store)
+ return mcidev_attr->store(mem_ctl_info, buffer, count);
+
+ return -EIO;
+}
+
+/* No memory to release for this kobj */
+static void edac_inst_grp_release(struct kobject *kobj)
+{
+ struct mcidev_sysfs_group_kobj *grp;
+ struct mem_ctl_info *mci;
+
+ debugf1("%s()\n", __func__);
+
+ grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj);
+ mci = grp->mci;
+
+ kobject_put(&mci->edac_mci_kobj);
+}
+
+/* Intermediate show/store table */
+static struct sysfs_ops inst_grp_ops = {
+ .show = inst_grp_show,
+ .store = inst_grp_store
+};
+
+/* the kobj_type instance for a instance group */
+static struct kobj_type ktype_inst_grp = {
+ .release = edac_inst_grp_release,
+ .sysfs_ops = &inst_grp_ops,
+};
+
+
/*
* edac_create_mci_instance_attributes
- * create MC driver specific attributes at the topmost level
- * directory of this mci instance.
+ * create MC driver specific attributes bellow an specified kobj
+ * This routine calls itself recursively, in order to create an entire
+ * object tree.
*/
-static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
+static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci,
+ struct mcidev_sysfs_attribute *sysfs_attrib,
+ struct kobject *kobj)
{
int err;
- struct mcidev_sysfs_attribute *sysfs_attrib;
- /* point to the start of the array and iterate over it
- * adding each attribute listed to this mci instance's kobject
- */
- sysfs_attrib = mci->mc_driver_sysfs_attributes;
+ debugf1("%s()\n", __func__);
+
+ while (sysfs_attrib) {
+ if (sysfs_attrib->grp) {
+ struct mcidev_sysfs_group_kobj *grp_kobj;
+
+ grp_kobj = kzalloc(sizeof(*grp_kobj), GFP_KERNEL);
+ if (!grp_kobj)
+ return -ENOMEM;
+
+ list_add_tail(&grp_kobj->list, &mci->grp_kobj_list);
+
+ grp_kobj->grp = sysfs_attrib->grp;
+ grp_kobj->mci = mci;
+
+ debugf0("%s() grp %s, mci %p\n", __func__,
+ sysfs_attrib->grp->name, mci);
+
+ err = kobject_init_and_add(&grp_kobj->kobj,
+ &ktype_inst_grp,
+ &mci->edac_mci_kobj,
+ sysfs_attrib->grp->name);
+ if (err)
+ return err;
+
+ err = edac_create_mci_instance_attributes(mci,
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj);
+
+ if (err)
+ return err;
+ } else if (sysfs_attrib->attr.name) {
+ debugf0("%s() file %s\n", __func__,
+ sysfs_attrib->attr.name);
+
+ err = sysfs_create_file(kobj, &sysfs_attrib->attr);
+ } else
+ break;
- while (sysfs_attrib && sysfs_attrib->attr.name) {
- err = sysfs_create_file(&mci->edac_mci_kobj,
- (struct attribute*) sysfs_attrib);
if (err) {
return err;
}
-
sysfs_attrib++;
}
@@ -759,21 +841,44 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci)
* remove MC driver specific attributes at the topmost level
* directory of this mci instance.
*/
-static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci)
+static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
+ struct mcidev_sysfs_attribute *sysfs_attrib,
+ struct kobject *kobj, int count)
{
- struct mcidev_sysfs_attribute *sysfs_attrib;
+ struct mcidev_sysfs_group_kobj *grp_kobj, *tmp;
- /* point to the start of the array and iterate over it
- * adding each attribute listed to this mci instance's kobject
- */
- sysfs_attrib = mci->mc_driver_sysfs_attributes;
+ debugf1("%s()\n", __func__);
- /* loop if there are attributes and until we hit a NULL entry */
- while (sysfs_attrib && sysfs_attrib->attr.name) {
- sysfs_remove_file(&mci->edac_mci_kobj,
- (struct attribute *) sysfs_attrib);
+ /*
+ * loop if there are attributes and until we hit a NULL entry
+ * Remove first all the atributes
+ */
+ while (sysfs_attrib) {
+ if (sysfs_attrib->grp) {
+ list_for_each_entry(grp_kobj, &mci->grp_kobj_list,
+ list)
+ if (grp_kobj->grp == sysfs_attrib->grp)
+ edac_remove_mci_instance_attributes(mci,
+ grp_kobj->grp->mcidev_attr,
+ &grp_kobj->kobj, count + 1);
+ } else if (sysfs_attrib->attr.name) {
+ debugf0("%s() file %s\n", __func__,
+ sysfs_attrib->attr.name);
+ sysfs_remove_file(kobj, &sysfs_attrib->attr);
+ } else
+ break;
sysfs_attrib++;
}
+
+ /*
+ * Now that all attributes got removed, it is save to remove all groups
+ */
+ if (!count)
+ list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list,
+ list) {
+ debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name);
+ kobject_put(&grp_kobj->kobj);
+ }
}
@@ -794,6 +899,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s() idx=%d\n", __func__, mci->mc_idx);
+ INIT_LIST_HEAD(&mci->grp_kobj_list);
+
/* create a symlink for the device */
err = sysfs_create_link(kobj_mci, &mci->dev->kobj,
EDAC_DEVICE_SYMLINK);
@@ -806,7 +913,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
* then create them now for the driver.
*/
if (mci->mc_driver_sysfs_attributes) {
- err = edac_create_mci_instance_attributes(mci);
+ err = edac_create_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes,
+ &mci->edac_mci_kobj);
if (err) {
debugf1("%s() failure to create mci attributes\n",
__func__);
@@ -841,7 +950,8 @@ fail1:
}
/* remove the mci instance's attributes, if any */
- edac_remove_mci_instance_attributes(mci);
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes, &mci->edac_mci_kobj, 0);
/* remove the symlink */
sysfs_remove_link(kobj_mci, EDAC_DEVICE_SYMLINK);
@@ -875,8 +985,9 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
debugf0("%s() remove_mci_instance\n", __func__);
/* remove this mci instance's attribtes */
- edac_remove_mci_instance_attributes(mci);
-
+ edac_remove_mci_instance_attributes(mci,
+ mci->mc_driver_sysfs_attributes,
+ &mci->edac_mci_kobj, 0);
debugf0("%s() unregister this mci kobj\n", __func__);
/* unregister this instance's kobject */
diff --git a/drivers/edac/edac_mce.c b/drivers/edac/edac_mce.c
new file mode 100644
index 000000000000..9ccdc5b140e7
--- /dev/null
+++ b/drivers/edac/edac_mce.c
@@ -0,0 +1,61 @@
+/* Provides edac interface to mcelog events
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2.
+ *
+ * Copyright (c) 2009 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ */
+
+#include <linux/module.h>
+#include <linux/edac_mce.h>
+#include <asm/mce.h>
+
+int edac_mce_enabled;
+EXPORT_SYMBOL_GPL(edac_mce_enabled);
+
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(edac_mce_list);
+static DEFINE_MUTEX(edac_mce_lock);
+
+int edac_mce_register(struct edac_mce *edac_mce)
+{
+ mutex_lock(&edac_mce_lock);
+ list_add_tail(&edac_mce->list, &edac_mce_list);
+ mutex_unlock(&edac_mce_lock);
+ return 0;
+}
+EXPORT_SYMBOL(edac_mce_register);
+
+void edac_mce_unregister(struct edac_mce *edac_mce)
+{
+ mutex_lock(&edac_mce_lock);
+ list_del(&edac_mce->list);
+ mutex_unlock(&edac_mce_lock);
+}
+EXPORT_SYMBOL(edac_mce_unregister);
+
+int edac_mce_parse(struct mce *mce)
+{
+ struct edac_mce *edac_mce;
+
+ list_for_each_entry(edac_mce, &edac_mce_list, list) {
+ if (edac_mce->check_error(edac_mce->priv, mce))
+ return 1;
+ }
+
+ /* Nobody queued the error */
+ return 0;
+}
+EXPORT_SYMBOL_GPL(edac_mce_parse);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("EDAC Driver for mcelog captured errors");
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 97e64bcdbc06..bae9351e9473 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -133,7 +133,7 @@ static void amd_decode_dc_mce(u64 mc0_status)
u32 ec = mc0_status & 0xffff;
u32 xec = (mc0_status >> 16) & 0xf;
- pr_emerg(" Data Cache Error");
+ pr_emerg("Data Cache Error");
if (xec == 1 && TLB_ERROR(ec))
pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -176,7 +176,7 @@ static void amd_decode_ic_mce(u64 mc1_status)
u32 ec = mc1_status & 0xffff;
u32 xec = (mc1_status >> 16) & 0xf;
- pr_emerg(" Instruction Cache Error");
+ pr_emerg("Instruction Cache Error");
if (xec == 1 && TLB_ERROR(ec))
pr_cont(": %s TLB multimatch.\n", LL_MSG(ec));
@@ -233,7 +233,7 @@ static void amd_decode_bu_mce(u64 mc2_status)
u32 ec = mc2_status & 0xffff;
u32 xec = (mc2_status >> 16) & 0xf;
- pr_emerg(" Bus Unit Error");
+ pr_emerg("Bus Unit Error");
if (xec == 0x1)
pr_cont(" in the write data buffers.\n");
@@ -275,7 +275,7 @@ static void amd_decode_ls_mce(u64 mc3_status)
u32 ec = mc3_status & 0xffff;
u32 xec = (mc3_status >> 16) & 0xf;
- pr_emerg(" Load Store Error");
+ pr_emerg("Load Store Error");
if (xec == 0x0) {
u8 rrrr = (ec >> 4) & 0xf;
@@ -304,7 +304,7 @@ void amd_decode_nb_mce(int node_id, struct err_regs *regs, int handle_errors)
if (TLB_ERROR(ec) && !report_gart_errors)
return;
- pr_emerg(" Northbridge Error, node %d", node_id);
+ pr_emerg("Northbridge Error, node %d", node_id);
/*
* F10h, revD can disable ErrCpu[3:0] so check that first and also the
@@ -342,13 +342,13 @@ static void amd_decode_fr_mce(u64 mc5_status)
static inline void amd_decode_err_code(unsigned int ec)
{
if (TLB_ERROR(ec)) {
- pr_emerg(" Transaction: %s, Cache Level %s\n",
+ pr_emerg("Transaction: %s, Cache Level %s\n",
TT_MSG(ec), LL_MSG(ec));
} else if (MEM_ERROR(ec)) {
- pr_emerg(" Transaction: %s, Type: %s, Cache Level: %s",
+ pr_emerg("Transaction: %s, Type: %s, Cache Level: %s",
RRRR_MSG(ec), TT_MSG(ec), LL_MSG(ec));
} else if (BUS_ERROR(ec)) {
- pr_emerg(" Transaction type: %s(%s), %s, Cache Level: %s, "
+ pr_emerg("Transaction type: %s(%s), %s, Cache Level: %s, "
"Participating Processor: %s\n",
RRRR_MSG(ec), II_MSG(ec), TO_MSG(ec), LL_MSG(ec),
PP_MSG(ec));
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index ee9753cf362c..f459a6c0886b 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -589,14 +589,13 @@ static void i5100_refresh_scrubbing(struct work_struct *work)
/*
* The bandwidth is based on experimentation, feel free to refine it.
*/
-static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
- u32 *bandwidth)
+static int i5100_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
{
struct i5100_priv *priv = mci->pvt_info;
u32 dw;
pci_read_config_dword(priv->mc, I5100_MC, &dw);
- if (*bandwidth) {
+ if (bandwidth) {
priv->scrub_enable = 1;
dw |= I5100_MC_SCRBEN_MASK;
schedule_delayed_work(&(priv->i5100_scrubbing),
@@ -610,7 +609,7 @@ static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
pci_read_config_dword(priv->mc, I5100_MC, &dw);
- *bandwidth = 5900000 * i5100_mc_scrben(dw);
+ bandwidth = 5900000 * i5100_mc_scrben(dw);
return 0;
}
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
new file mode 100644
index 000000000000..6b8b7b41ec5f
--- /dev/null
+++ b/drivers/edac/i7core_edac.c
@@ -0,0 +1,2078 @@
+/* Intel i7 core/Nehalem Memory Controller kernel module
+ *
+ * This driver supports yhe memory controllers found on the Intel
+ * processor families i7core, i7core 7xx/8xx, i5core, Xeon 35xx,
+ * Xeon 55xx and Xeon 56xx also known as Nehalem, Nehalem-EP, Lynnfield
+ * and Westmere-EP.
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2 only.
+ *
+ * Copyright (c) 2009-2010 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ *
+ * Forked and adapted from the i5400_edac driver
+ *
+ * Based on the following public Intel datasheets:
+ * Intel Core i7 Processor Extreme Edition and Intel Core i7 Processor
+ * Datasheet, Volume 2:
+ * http://download.intel.com/design/processor/datashts/320835.pdf
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/edac.h>
+#include <linux/mmzone.h>
+#include <linux/edac_mce.h>
+#include <linux/smp.h>
+#include <asm/processor.h>
+
+#include "edac_core.h"
+
+/*
+ * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core
+ * registers start at bus 255, and are not reported by BIOS.
+ * We currently find devices with only 2 sockets. In order to support more QPI
+ * Quick Path Interconnect, just increment this number.
+ */
+#define MAX_SOCKET_BUSES 2
+
+
+/*
+ * Alter this version for the module when modifications are made
+ */
+#define I7CORE_REVISION " Ver: 1.0.0 " __DATE__
+#define EDAC_MOD_STR "i7core_edac"
+
+/*
+ * Debug macros
+ */
+#define i7core_printk(level, fmt, arg...) \
+ edac_printk(level, "i7core", fmt, ##arg)
+
+#define i7core_mc_printk(mci, level, fmt, arg...) \
+ edac_mc_chipset_printk(mci, level, "i7core", fmt, ##arg)
+
+/*
+ * i7core Memory Controller Registers
+ */
+
+ /* OFFSETS for Device 0 Function 0 */
+
+#define MC_CFG_CONTROL 0x90
+
+ /* OFFSETS for Device 3 Function 0 */
+
+#define MC_CONTROL 0x48
+#define MC_STATUS 0x4c
+#define MC_MAX_DOD 0x64
+
+/*
+ * OFFSETS for Device 3 Function 4, as inicated on Xeon 5500 datasheet:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+
+#define MC_TEST_ERR_RCV1 0x60
+ #define DIMM2_COR_ERR(r) ((r) & 0x7fff)
+
+#define MC_TEST_ERR_RCV0 0x64
+ #define DIMM1_COR_ERR(r) (((r) >> 16) & 0x7fff)
+ #define DIMM0_COR_ERR(r) ((r) & 0x7fff)
+
+/* OFFSETS for Device 3 Function 2, as inicated on Xeon 5500 datasheet */
+#define MC_COR_ECC_CNT_0 0x80
+#define MC_COR_ECC_CNT_1 0x84
+#define MC_COR_ECC_CNT_2 0x88
+#define MC_COR_ECC_CNT_3 0x8c
+#define MC_COR_ECC_CNT_4 0x90
+#define MC_COR_ECC_CNT_5 0x94
+
+#define DIMM_TOP_COR_ERR(r) (((r) >> 16) & 0x7fff)
+#define DIMM_BOT_COR_ERR(r) ((r) & 0x7fff)
+
+
+ /* OFFSETS for Devices 4,5 and 6 Function 0 */
+
+#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
+ #define THREE_DIMMS_PRESENT (1 << 24)
+ #define SINGLE_QUAD_RANK_PRESENT (1 << 23)
+ #define QUAD_RANK_PRESENT (1 << 22)
+ #define REGISTERED_DIMM (1 << 15)
+
+#define MC_CHANNEL_MAPPER 0x60
+ #define RDLCH(r, ch) ((((r) >> (3 + (ch * 6))) & 0x07) - 1)
+ #define WRLCH(r, ch) ((((r) >> (ch * 6)) & 0x07) - 1)
+
+#define MC_CHANNEL_RANK_PRESENT 0x7c
+ #define RANK_PRESENT_MASK 0xffff
+
+#define MC_CHANNEL_ADDR_MATCH 0xf0
+#define MC_CHANNEL_ERROR_MASK 0xf8
+#define MC_CHANNEL_ERROR_INJECT 0xfc
+ #define INJECT_ADDR_PARITY 0x10
+ #define INJECT_ECC 0x08
+ #define MASK_CACHELINE 0x06
+ #define MASK_FULL_CACHELINE 0x06
+ #define MASK_MSB32_CACHELINE 0x04
+ #define MASK_LSB32_CACHELINE 0x02
+ #define NO_MASK_CACHELINE 0x00
+ #define REPEAT_EN 0x01
+
+ /* OFFSETS for Devices 4,5 and 6 Function 1 */
+
+#define MC_DOD_CH_DIMM0 0x48
+#define MC_DOD_CH_DIMM1 0x4c
+#define MC_DOD_CH_DIMM2 0x50
+ #define RANKOFFSET_MASK ((1 << 12) | (1 << 11) | (1 << 10))
+ #define RANKOFFSET(x) ((x & RANKOFFSET_MASK) >> 10)
+ #define DIMM_PRESENT_MASK (1 << 9)
+ #define DIMM_PRESENT(x) (((x) & DIMM_PRESENT_MASK) >> 9)
+ #define MC_DOD_NUMBANK_MASK ((1 << 8) | (1 << 7))
+ #define MC_DOD_NUMBANK(x) (((x) & MC_DOD_NUMBANK_MASK) >> 7)
+ #define MC_DOD_NUMRANK_MASK ((1 << 6) | (1 << 5))
+ #define MC_DOD_NUMRANK(x) (((x) & MC_DOD_NUMRANK_MASK) >> 5)
+ #define MC_DOD_NUMROW_MASK ((1 << 4) | (1 << 3) | (1 << 2))
+ #define MC_DOD_NUMROW(x) (((x) & MC_DOD_NUMROW_MASK) >> 2)
+ #define MC_DOD_NUMCOL_MASK 3
+ #define MC_DOD_NUMCOL(x) ((x) & MC_DOD_NUMCOL_MASK)
+
+#define MC_RANK_PRESENT 0x7c
+
+#define MC_SAG_CH_0 0x80
+#define MC_SAG_CH_1 0x84
+#define MC_SAG_CH_2 0x88
+#define MC_SAG_CH_3 0x8c
+#define MC_SAG_CH_4 0x90
+#define MC_SAG_CH_5 0x94
+#define MC_SAG_CH_6 0x98
+#define MC_SAG_CH_7 0x9c
+
+#define MC_RIR_LIMIT_CH_0 0x40
+#define MC_RIR_LIMIT_CH_1 0x44
+#define MC_RIR_LIMIT_CH_2 0x48
+#define MC_RIR_LIMIT_CH_3 0x4C
+#define MC_RIR_LIMIT_CH_4 0x50
+#define MC_RIR_LIMIT_CH_5 0x54
+#define MC_RIR_LIMIT_CH_6 0x58
+#define MC_RIR_LIMIT_CH_7 0x5C
+#define MC_RIR_LIMIT_MASK ((1 << 10) - 1)
+
+#define MC_RIR_WAY_CH 0x80
+ #define MC_RIR_WAY_OFFSET_MASK (((1 << 14) - 1) & ~0x7)
+ #define MC_RIR_WAY_RANK_MASK 0x7
+
+/*
+ * i7core structs
+ */
+
+#define NUM_CHANS 3
+#define MAX_DIMMS 3 /* Max DIMMS per channel */
+#define MAX_MCR_FUNC 4
+#define MAX_CHAN_FUNC 3
+
+struct i7core_info {
+ u32 mc_control;
+ u32 mc_status;
+ u32 max_dod;
+ u32 ch_map;
+};
+
+
+struct i7core_inject {
+ int enable;
+
+ u32 section;
+ u32 type;
+ u32 eccmask;
+
+ /* Error address mask */
+ int channel, dimm, rank, bank, page, col;
+};
+
+struct i7core_channel {
+ u32 ranks;
+ u32 dimms;
+};
+
+struct pci_id_descr {
+ int dev;
+ int func;
+ int dev_id;
+ int optional;
+};
+
+struct pci_id_table {
+ struct pci_id_descr *descr;
+ int n_devs;
+};
+
+struct i7core_dev {
+ struct list_head list;
+ u8 socket;
+ struct pci_dev **pdev;
+ int n_devs;
+ struct mem_ctl_info *mci;
+};
+
+struct i7core_pvt {
+ struct pci_dev *pci_noncore;
+ struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1];
+ struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1];
+
+ struct i7core_dev *i7core_dev;
+
+ struct i7core_info info;
+ struct i7core_inject inject;
+ struct i7core_channel channel[NUM_CHANS];
+
+ int channels; /* Number of active channels */
+
+ int ce_count_available;
+ int csrow_map[NUM_CHANS][MAX_DIMMS];
+
+ /* ECC corrected errors counts per udimm */
+ unsigned long udimm_ce_count[MAX_DIMMS];
+ int udimm_last_ce_count[MAX_DIMMS];
+ /* ECC corrected errors counts per rdimm */
+ unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS];
+ int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS];
+
+ unsigned int is_registered;
+
+ /* mcelog glue */
+ struct edac_mce edac_mce;
+
+ /* Fifo double buffers */
+ struct mce mce_entry[MCE_LOG_LEN];
+ struct mce mce_outentry[MCE_LOG_LEN];
+
+ /* Fifo in/out counters */
+ unsigned mce_in, mce_out;
+
+ /* Count indicator to show errors not got */
+ unsigned mce_overrun;
+};
+
+/* Static vars */
+static LIST_HEAD(i7core_edac_list);
+static DEFINE_MUTEX(i7core_edac_lock);
+
+#define PCI_DESCR(device, function, device_id) \
+ .dev = (device), \
+ .func = (function), \
+ .dev_id = (device_id)
+
+struct pci_id_descr pci_dev_descr_i7core_nehalem[] = {
+ /* Memory controller */
+ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) },
+ { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) },
+ /* Exists only for RDIMM */
+ { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 },
+ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) },
+
+ /* Channel 0 */
+ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) },
+ { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) },
+ { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) },
+ { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) },
+
+ /* Channel 1 */
+ { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) },
+ { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) },
+ { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) },
+ { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) },
+
+ /* Channel 2 */
+ { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) },
+ { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) },
+ { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) },
+ { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) },
+
+ /* Generic Non-core registers */
+ /*
+ * This is the PCI device on i7core and on Xeon 35xx (8086:2c41)
+ * On Xeon 55xx, however, it has a different id (8086:2c40). So,
+ * the probing code needs to test for the other address in case of
+ * failure of this one
+ */
+ { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) },
+
+};
+
+struct pci_id_descr pci_dev_descr_lynnfield[] = {
+ { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) },
+ { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) },
+ { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) },
+
+ { PCI_DESCR( 4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL) },
+ { PCI_DESCR( 4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR) },
+ { PCI_DESCR( 4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK) },
+ { PCI_DESCR( 4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC) },
+
+ { PCI_DESCR( 5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL) },
+ { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) },
+ { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) },
+ { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) },
+
+ /*
+ * This is the PCI device has an alternate address on some
+ * processors like Core i7 860
+ */
+ { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) },
+};
+
+struct pci_id_descr pci_dev_descr_i7core_westmere[] = {
+ /* Memory controller */
+ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) },
+ { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) },
+ /* Exists only for RDIMM */
+ { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2), .optional = 1 },
+ { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2) },
+
+ /* Channel 0 */
+ { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2) },
+ { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2) },
+ { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2) },
+ { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2) },
+
+ /* Channel 1 */
+ { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2) },
+ { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2) },
+ { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2) },
+ { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2) },
+
+ /* Channel 2 */
+ { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2) },
+ { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) },
+ { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) },
+ { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) },
+
+ /* Generic Non-core registers */
+ { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) },
+
+};
+
+#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) }
+struct pci_id_table pci_dev_table[] = {
+ PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem),
+ PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield),
+ PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere),
+};
+
+/*
+ * pci_device_id table for which devices we are looking for
+ */
+static const struct pci_device_id i7core_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_X58_HUB_MGMT)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0)},
+ {0,} /* 0 terminated list. */
+};
+
+static struct edac_pci_ctl_info *i7core_pci;
+
+/****************************************************************************
+ Anciliary status routines
+ ****************************************************************************/
+
+ /* MC_CONTROL bits */
+#define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch)))
+#define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1))
+
+ /* MC_STATUS bits */
+#define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 4))
+#define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch))
+
+ /* MC_MAX_DOD read functions */
+static inline int numdimms(u32 dimms)
+{
+ return (dimms & 0x3) + 1;
+}
+
+static inline int numrank(u32 rank)
+{
+ static int ranks[4] = { 1, 2, 4, -EINVAL };
+
+ return ranks[rank & 0x3];
+}
+
+static inline int numbank(u32 bank)
+{
+ static int banks[4] = { 4, 8, 16, -EINVAL };
+
+ return banks[bank & 0x3];
+}
+
+static inline int numrow(u32 row)
+{
+ static int rows[8] = {
+ 1 << 12, 1 << 13, 1 << 14, 1 << 15,
+ 1 << 16, -EINVAL, -EINVAL, -EINVAL,
+ };
+
+ return rows[row & 0x7];
+}
+
+static inline int numcol(u32 col)
+{
+ static int cols[8] = {
+ 1 << 10, 1 << 11, 1 << 12, -EINVAL,
+ };
+ return cols[col & 0x3];
+}
+
+static struct i7core_dev *get_i7core_dev(u8 socket)
+{
+ struct i7core_dev *i7core_dev;
+
+ list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+ if (i7core_dev->socket == socket)
+ return i7core_dev;
+ }
+
+ return NULL;
+}
+
+/****************************************************************************
+ Memory check routines
+ ****************************************************************************/
+static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
+ unsigned func)
+{
+ struct i7core_dev *i7core_dev = get_i7core_dev(socket);
+ int i;
+
+ if (!i7core_dev)
+ return NULL;
+
+ for (i = 0; i < i7core_dev->n_devs; i++) {
+ if (!i7core_dev->pdev[i])
+ continue;
+
+ if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
+ PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
+ return i7core_dev->pdev[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * i7core_get_active_channels() - gets the number of channels and csrows
+ * @socket: Quick Path Interconnect socket
+ * @channels: Number of channels that will be returned
+ * @csrows: Number of csrows found
+ *
+ * Since EDAC core needs to know in advance the number of available channels
+ * and csrows, in order to allocate memory for csrows/channels, it is needed
+ * to run two similar steps. At the first step, implemented on this function,
+ * it checks the number of csrows/channels present at one socket.
+ * this is used in order to properly allocate the size of mci components.
+ *
+ * It should be noticed that none of the current available datasheets explain
+ * or even mention how csrows are seen by the memory controller. So, we need
+ * to add a fake description for csrows.
+ * So, this driver is attributing one DIMM memory for one csrow.
+ */
+static int i7core_get_active_channels(u8 socket, unsigned *channels,
+ unsigned *csrows)
+{
+ struct pci_dev *pdev = NULL;
+ int i, j;
+ u32 status, control;
+
+ *channels = 0;
+ *csrows = 0;
+
+ pdev = get_pdev_slot_func(socket, 3, 0);
+ if (!pdev) {
+ i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n",
+ socket);
+ return -ENODEV;
+ }
+
+ /* Device 3 function 0 reads */
+ pci_read_config_dword(pdev, MC_STATUS, &status);
+ pci_read_config_dword(pdev, MC_CONTROL, &control);
+
+ for (i = 0; i < NUM_CHANS; i++) {
+ u32 dimm_dod[3];
+ /* Check if the channel is active */
+ if (!(control & (1 << (8 + i))))
+ continue;
+
+ /* Check if the channel is disabled */
+ if (status & (1 << i))
+ continue;
+
+ pdev = get_pdev_slot_func(socket, i + 4, 1);
+ if (!pdev) {
+ i7core_printk(KERN_ERR, "Couldn't find socket %d "
+ "fn %d.%d!!!\n",
+ socket, i + 4, 1);
+ return -ENODEV;
+ }
+ /* Devices 4-6 function 1 */
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM0, &dimm_dod[0]);
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM1, &dimm_dod[1]);
+ pci_read_config_dword(pdev,
+ MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+ (*channels)++;
+
+ for (j = 0; j < 3; j++) {
+ if (!DIMM_PRESENT(dimm_dod[j]))
+ continue;
+ (*csrows)++;
+ }
+ }
+
+ debugf0("Number of active channels on socket %d: %d\n",
+ socket, *channels);
+
+ return 0;
+}
+
+static int get_dimm_config(struct mem_ctl_info *mci, int *csrow)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ struct csrow_info *csr;
+ struct pci_dev *pdev;
+ int i, j;
+ unsigned long last_page = 0;
+ enum edac_type mode;
+ enum mem_type mtype;
+
+ /* Get data from the MC register, function 0 */
+ pdev = pvt->pci_mcr[0];
+ if (!pdev)
+ return -ENODEV;
+
+ /* Device 3 function 0 reads */
+ pci_read_config_dword(pdev, MC_CONTROL, &pvt->info.mc_control);
+ pci_read_config_dword(pdev, MC_STATUS, &pvt->info.mc_status);
+ pci_read_config_dword(pdev, MC_MAX_DOD, &pvt->info.max_dod);
+ pci_read_config_dword(pdev, MC_CHANNEL_MAPPER, &pvt->info.ch_map);
+
+ debugf0("QPI %d control=0x%08x status=0x%08x dod=0x%08x map=0x%08x\n",
+ pvt->i7core_dev->socket, pvt->info.mc_control, pvt->info.mc_status,
+ pvt->info.max_dod, pvt->info.ch_map);
+
+ if (ECC_ENABLED(pvt)) {
+ debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt) ? 8 : 4);
+ if (ECCx8(pvt))
+ mode = EDAC_S8ECD8ED;
+ else
+ mode = EDAC_S4ECD4ED;
+ } else {
+ debugf0("ECC disabled\n");
+ mode = EDAC_NONE;
+ }
+
+ /* FIXME: need to handle the error codes */
+ debugf0("DOD Max limits: DIMMS: %d, %d-ranked, %d-banked "
+ "x%x x 0x%x\n",
+ numdimms(pvt->info.max_dod),
+ numrank(pvt->info.max_dod >> 2),
+ numbank(pvt->info.max_dod >> 4),
+ numrow(pvt->info.max_dod >> 6),
+ numcol(pvt->info.max_dod >> 9));
+
+ for (i = 0; i < NUM_CHANS; i++) {
+ u32 data, dimm_dod[3], value[8];
+
+ if (!pvt->pci_ch[i][0])
+ continue;
+
+ if (!CH_ACTIVE(pvt, i)) {
+ debugf0("Channel %i is not active\n", i);
+ continue;
+ }
+ if (CH_DISABLED(pvt, i)) {
+ debugf0("Channel %i is disabled\n", i);
+ continue;
+ }
+
+ /* Devices 4-6 function 0 */
+ pci_read_config_dword(pvt->pci_ch[i][0],
+ MC_CHANNEL_DIMM_INIT_PARAMS, &data);
+
+ pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ?
+ 4 : 2;
+
+ if (data & REGISTERED_DIMM)
+ mtype = MEM_RDDR3;
+ else
+ mtype = MEM_DDR3;
+#if 0
+ if (data & THREE_DIMMS_PRESENT)
+ pvt->channel[i].dimms = 3;
+ else if (data & SINGLE_QUAD_RANK_PRESENT)
+ pvt->channel[i].dimms = 1;
+ else
+ pvt->channel[i].dimms = 2;
+#endif
+
+ /* Devices 4-6 function 1 */
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM0, &dimm_dod[0]);
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM1, &dimm_dod[1]);
+ pci_read_config_dword(pvt->pci_ch[i][1],
+ MC_DOD_CH_DIMM2, &dimm_dod[2]);
+
+ debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
+ "%d ranks, %cDIMMs\n",
+ i,
+ RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
+ data,
+ pvt->channel[i].ranks,
+ (data & REGISTERED_DIMM) ? 'R' : 'U');
+
+ for (j = 0; j < 3; j++) {
+ u32 banks, ranks, rows, cols;
+ u32 size, npages;
+
+ if (!DIMM_PRESENT(dimm_dod[j]))
+ continue;
+
+ banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
+ ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
+ rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
+ cols = numcol(MC_DOD_NUMCOL(dimm_dod[j]));
+
+ /* DDR3 has 8 I/O banks */
+ size = (rows * cols * banks * ranks) >> (20 - 3);
+
+ pvt->channel[i].dimms++;
+
+ debugf0("\tdimm %d %d Mb offset: %x, "
+ "bank: %d, rank: %d, row: %#x, col: %#x\n",
+ j, size,
+ RANKOFFSET(dimm_dod[j]),
+ banks, ranks, rows, cols);
+
+#if PAGE_SHIFT > 20
+ npages = size >> (PAGE_SHIFT - 20);
+#else
+ npages = size << (20 - PAGE_SHIFT);
+#endif
+
+ csr = &mci->csrows[*csrow];
+ csr->first_page = last_page + 1;
+ last_page += npages;
+ csr->last_page = last_page;
+ csr->nr_pages = npages;
+
+ csr->page_mask = 0;
+ csr->grain = 8;
+ csr->csrow_idx = *csrow;
+ csr->nr_channels = 1;
+
+ csr->channels[0].chan_idx = i;
+ csr->channels[0].ce_count = 0;
+
+ pvt->csrow_map[i][j] = *csrow;
+
+ switch (banks) {
+ case 4:
+ csr->dtype = DEV_X4;
+ break;
+ case 8:
+ csr->dtype = DEV_X8;
+ break;
+ case 16:
+ csr->dtype = DEV_X16;
+ break;
+ default:
+ csr->dtype = DEV_UNKNOWN;
+ }
+
+ csr->edac_mode = mode;
+ csr->mtype = mtype;
+
+ (*csrow)++;
+ }
+
+ pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
+ pci_read_config_dword(pdev, MC_SAG_CH_1, &value[1]);
+ pci_read_config_dword(pdev, MC_SAG_CH_2, &value[2]);
+ pci_read_config_dword(pdev, MC_SAG_CH_3, &value[3]);
+ pci_read_config_dword(pdev, MC_SAG_CH_4, &value[4]);
+ pci_read_config_dword(pdev, MC_SAG_CH_5, &value[5]);
+ pci_read_config_dword(pdev, MC_SAG_CH_6, &value[6]);
+ pci_read_config_dword(pdev, MC_SAG_CH_7, &value[7]);
+ debugf1("\t[%i] DIVBY3\tREMOVED\tOFFSET\n", i);
+ for (j = 0; j < 8; j++)
+ debugf1("\t\t%#x\t%#x\t%#x\n",
+ (value[j] >> 27) & 0x1,
+ (value[j] >> 24) & 0x7,
+ (value[j] && ((1 << 24) - 1)));
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Error insertion routines
+ ****************************************************************************/
+
+/* The i7core has independent error injection features per channel.
+ However, to have a simpler code, we don't allow enabling error injection
+ on more than one channel.
+ Also, since a change at an inject parameter will be applied only at enable,
+ we're disabling error injection on all write calls to the sysfs nodes that
+ controls the error code injection.
+ */
+static int disable_inject(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ pvt->inject.enable = 0;
+
+ if (!pvt->pci_ch[pvt->inject.channel][0])
+ return -ENODEV;
+
+ pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, 0);
+
+ return 0;
+}
+
+/*
+ * i7core inject inject.section
+ *
+ * accept and store error injection inject.section value
+ * bit 0 - refers to the lower 32-byte half cacheline
+ * bit 1 - refers to the upper 32-byte half cacheline
+ */
+static ssize_t i7core_inject_section_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if ((rc < 0) || (value > 3))
+ return -EIO;
+
+ pvt->inject.section = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_section_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.section);
+}
+
+/*
+ * i7core inject.type
+ *
+ * accept and store error injection inject.section value
+ * bit 0 - repeat enable - Enable error repetition
+ * bit 1 - inject ECC error
+ * bit 2 - inject parity error
+ */
+static ssize_t i7core_inject_type_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if ((rc < 0) || (value > 7))
+ return -EIO;
+
+ pvt->inject.type = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_type_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.type);
+}
+
+/*
+ * i7core_inject_inject.eccmask_store
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ * Any bits set to a 1 will flip the corresponding ECC bit
+ * Correctable errors can be injected by flipping 1 bit or the bits within
+ * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ * uncorrectable error to be injected.
+ */
+static ssize_t i7core_inject_eccmask_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ unsigned long value;
+ int rc;
+
+ if (pvt->inject.enable)
+ disable_inject(mci);
+
+ rc = strict_strtoul(data, 10, &value);
+ if (rc < 0)
+ return -EIO;
+
+ pvt->inject.eccmask = (u32) value;
+ return count;
+}
+
+static ssize_t i7core_inject_eccmask_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ return sprintf(data, "0x%08x\n", pvt->inject.eccmask);
+}
+
+/*
+ * i7core_addrmatch
+ *
+ * The type of error (UE/CE) will depend on the inject.eccmask value:
+ * Any bits set to a 1 will flip the corresponding ECC bit
+ * Correctable errors can be injected by flipping 1 bit or the bits within
+ * a symbol pair (2 consecutive aligned 8-bit pairs - i.e. 7:0 and 15:8 or
+ * 23:16 and 31:24). Flipping bits in two symbol pairs will cause an
+ * uncorrectable error to be injected.
+ */
+
+#define DECLARE_ADDR_MATCH(param, limit) \
+static ssize_t i7core_inject_store_##param( \
+ struct mem_ctl_info *mci, \
+ const char *data, size_t count) \
+{ \
+ struct i7core_pvt *pvt; \
+ long value; \
+ int rc; \
+ \
+ debugf1("%s()\n", __func__); \
+ pvt = mci->pvt_info; \
+ \
+ if (pvt->inject.enable) \
+ disable_inject(mci); \
+ \
+ if (!strcasecmp(data, "any") || !strcasecmp(data, "any\n"))\
+ value = -1; \
+ else { \
+ rc = strict_strtoul(data, 10, &value); \
+ if ((rc < 0) || (value >= limit)) \
+ return -EIO; \
+ } \
+ \
+ pvt->inject.param = value; \
+ \
+ return count; \
+} \
+ \
+static ssize_t i7core_inject_show_##param( \
+ struct mem_ctl_info *mci, \
+ char *data) \
+{ \
+ struct i7core_pvt *pvt; \
+ \
+ pvt = mci->pvt_info; \
+ debugf1("%s() pvt=%p\n", __func__, pvt); \
+ if (pvt->inject.param < 0) \
+ return sprintf(data, "any\n"); \
+ else \
+ return sprintf(data, "%d\n", pvt->inject.param);\
+}
+
+#define ATTR_ADDR_MATCH(param) \
+ { \
+ .attr = { \
+ .name = #param, \
+ .mode = (S_IRUGO | S_IWUSR) \
+ }, \
+ .show = i7core_inject_show_##param, \
+ .store = i7core_inject_store_##param, \
+ }
+
+DECLARE_ADDR_MATCH(channel, 3);
+DECLARE_ADDR_MATCH(dimm, 3);
+DECLARE_ADDR_MATCH(rank, 4);
+DECLARE_ADDR_MATCH(bank, 32);
+DECLARE_ADDR_MATCH(page, 0x10000);
+DECLARE_ADDR_MATCH(col, 0x4000);
+
+static int write_and_test(struct pci_dev *dev, int where, u32 val)
+{
+ u32 read;
+ int count;
+
+ debugf0("setting pci %02x:%02x.%x reg=%02x value=%08x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ where, val);
+
+ for (count = 0; count < 10; count++) {
+ if (count)
+ msleep(100);
+ pci_write_config_dword(dev, where, val);
+ pci_read_config_dword(dev, where, &read);
+
+ if (read == val)
+ return 0;
+ }
+
+ i7core_printk(KERN_ERR, "Error during set pci %02x:%02x.%x reg=%02x "
+ "write=%08x. Read=%08x\n",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ where, val, read);
+
+ return -EINVAL;
+}
+
+/*
+ * This routine prepares the Memory Controller for error injection.
+ * The error will be injected when some process tries to write to the
+ * memory that matches the given criteria.
+ * The criteria can be set in terms of a mask where dimm, rank, bank, page
+ * and col can be specified.
+ * A -1 value for any of the mask items will make the MCU to ignore
+ * that matching criteria for error injection.
+ *
+ * It should be noticed that the error will only happen after a write operation
+ * on a memory that matches the condition. if REPEAT_EN is not enabled at
+ * inject mask, then it will produce just one error. Otherwise, it will repeat
+ * until the injectmask would be cleaned.
+ *
+ * FIXME: This routine assumes that MAXNUMDIMMS value of MC_MAX_DOD
+ * is reliable enough to check if the MC is using the
+ * three channels. However, this is not clear at the datasheet.
+ */
+static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
+ const char *data, size_t count)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 injectmask;
+ u64 mask = 0;
+ int rc;
+ long enable;
+
+ if (!pvt->pci_ch[pvt->inject.channel][0])
+ return 0;
+
+ rc = strict_strtoul(data, 10, &enable);
+ if ((rc < 0))
+ return 0;
+
+ if (enable) {
+ pvt->inject.enable = 1;
+ } else {
+ disable_inject(mci);
+ return count;
+ }
+
+ /* Sets pvt->inject.dimm mask */
+ if (pvt->inject.dimm < 0)
+ mask |= 1LL << 41;
+ else {
+ if (pvt->channel[pvt->inject.channel].dimms > 2)
+ mask |= (pvt->inject.dimm & 0x3LL) << 35;
+ else
+ mask |= (pvt->inject.dimm & 0x1LL) << 36;
+ }
+
+ /* Sets pvt->inject.rank mask */
+ if (pvt->inject.rank < 0)
+ mask |= 1LL << 40;
+ else {
+ if (pvt->channel[pvt->inject.channel].dimms > 2)
+ mask |= (pvt->inject.rank & 0x1LL) << 34;
+ else
+ mask |= (pvt->inject.rank & 0x3LL) << 34;
+ }
+
+ /* Sets pvt->inject.bank mask */
+ if (pvt->inject.bank < 0)
+ mask |= 1LL << 39;
+ else
+ mask |= (pvt->inject.bank & 0x15LL) << 30;
+
+ /* Sets pvt->inject.page mask */
+ if (pvt->inject.page < 0)
+ mask |= 1LL << 38;
+ else
+ mask |= (pvt->inject.page & 0xffff) << 14;
+
+ /* Sets pvt->inject.column mask */
+ if (pvt->inject.col < 0)
+ mask |= 1LL << 37;
+ else
+ mask |= (pvt->inject.col & 0x3fff);
+
+ /*
+ * bit 0: REPEAT_EN
+ * bits 1-2: MASK_HALF_CACHELINE
+ * bit 3: INJECT_ECC
+ * bit 4: INJECT_ADDR_PARITY
+ */
+
+ injectmask = (pvt->inject.type & 1) |
+ (pvt->inject.section & 0x3) << 1 |
+ (pvt->inject.type & 0x6) << (3 - 1);
+
+ /* Unlock writes to registers - this register is write only */
+ pci_write_config_dword(pvt->pci_noncore,
+ MC_CFG_CONTROL, 0x2);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ADDR_MATCH, mask);
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask);
+
+ write_and_test(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, injectmask);
+
+ /*
+ * This is something undocumented, based on my tests
+ * Without writing 8 to this register, errors aren't injected. Not sure
+ * why.
+ */
+ pci_write_config_dword(pvt->pci_noncore,
+ MC_CFG_CONTROL, 8);
+
+ debugf0("Error inject addr match 0x%016llx, ecc 0x%08x,"
+ " inject 0x%08x\n",
+ mask, pvt->inject.eccmask, injectmask);
+
+
+ return count;
+}
+
+static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci,
+ char *data)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 injectmask;
+
+ if (!pvt->pci_ch[pvt->inject.channel][0])
+ return 0;
+
+ pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0],
+ MC_CHANNEL_ERROR_INJECT, &injectmask);
+
+ debugf0("Inject error read: 0x%018x\n", injectmask);
+
+ if (injectmask & 0x0c)
+ pvt->inject.enable = 1;
+
+ return sprintf(data, "%d\n", pvt->inject.enable);
+}
+
+#define DECLARE_COUNTER(param) \
+static ssize_t i7core_show_counter_##param( \
+ struct mem_ctl_info *mci, \
+ char *data) \
+{ \
+ struct i7core_pvt *pvt = mci->pvt_info; \
+ \
+ debugf1("%s() \n", __func__); \
+ if (!pvt->ce_count_available || (pvt->is_registered)) \
+ return sprintf(data, "data unavailable\n"); \
+ return sprintf(data, "%lu\n", \
+ pvt->udimm_ce_count[param]); \
+}
+
+#define ATTR_COUNTER(param) \
+ { \
+ .attr = { \
+ .name = __stringify(udimm##param), \
+ .mode = (S_IRUGO | S_IWUSR) \
+ }, \
+ .show = i7core_show_counter_##param \
+ }
+
+DECLARE_COUNTER(0);
+DECLARE_COUNTER(1);
+DECLARE_COUNTER(2);
+
+/*
+ * Sysfs struct
+ */
+
+
+static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = {
+ ATTR_ADDR_MATCH(channel),
+ ATTR_ADDR_MATCH(dimm),
+ ATTR_ADDR_MATCH(rank),
+ ATTR_ADDR_MATCH(bank),
+ ATTR_ADDR_MATCH(page),
+ ATTR_ADDR_MATCH(col),
+ { .attr = { .name = NULL } }
+};
+
+static struct mcidev_sysfs_group i7core_inject_addrmatch = {
+ .name = "inject_addrmatch",
+ .mcidev_attr = i7core_addrmatch_attrs,
+};
+
+static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = {
+ ATTR_COUNTER(0),
+ ATTR_COUNTER(1),
+ ATTR_COUNTER(2),
+};
+
+static struct mcidev_sysfs_group i7core_udimm_counters = {
+ .name = "all_channel_counts",
+ .mcidev_attr = i7core_udimm_counters_attrs,
+};
+
+static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = {
+ {
+ .attr = {
+ .name = "inject_section",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_section_show,
+ .store = i7core_inject_section_store,
+ }, {
+ .attr = {
+ .name = "inject_type",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_type_show,
+ .store = i7core_inject_type_store,
+ }, {
+ .attr = {
+ .name = "inject_eccmask",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_eccmask_show,
+ .store = i7core_inject_eccmask_store,
+ }, {
+ .grp = &i7core_inject_addrmatch,
+ }, {
+ .attr = {
+ .name = "inject_enable",
+ .mode = (S_IRUGO | S_IWUSR)
+ },
+ .show = i7core_inject_enable_show,
+ .store = i7core_inject_enable_store,
+ },
+ { .attr = { .name = NULL } }, /* Reserved for udimm counters */
+ { .attr = { .name = NULL } }
+};
+
+/****************************************************************************
+ Device initialization routines: put/get, init/exit
+ ****************************************************************************/
+
+/*
+ * i7core_put_devices 'put' all the devices that we have
+ * reserved via 'get'
+ */
+static void i7core_put_devices(struct i7core_dev *i7core_dev)
+{
+ int i;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+ for (i = 0; i < i7core_dev->n_devs; i++) {
+ struct pci_dev *pdev = i7core_dev->pdev[i];
+ if (!pdev)
+ continue;
+ debugf0("Removing dev %02x:%02x.%d\n",
+ pdev->bus->number,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+ pci_dev_put(pdev);
+ }
+ kfree(i7core_dev->pdev);
+ list_del(&i7core_dev->list);
+ kfree(i7core_dev);
+}
+
+static void i7core_put_all_devices(void)
+{
+ struct i7core_dev *i7core_dev, *tmp;
+
+ list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list)
+ i7core_put_devices(i7core_dev);
+}
+
+static void __init i7core_xeon_pci_fixup(struct pci_id_table *table)
+{
+ struct pci_dev *pdev = NULL;
+ int i;
+ /*
+ * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses
+ * aren't announced by acpi. So, we need to use a legacy scan probing
+ * to detect them
+ */
+ while (table && table->descr) {
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, table->descr[0].dev_id, NULL);
+ if (unlikely(!pdev)) {
+ for (i = 0; i < MAX_SOCKET_BUSES; i++)
+ pcibios_scan_specific_bus(255-i);
+ }
+ table++;
+ }
+}
+
+/*
+ * i7core_get_devices Find and perform 'get' operation on the MCH's
+ * device/functions we want to reference for this driver
+ *
+ * Need to 'get' device 16 func 1 and func 2
+ */
+int i7core_get_onedevice(struct pci_dev **prev, int devno,
+ struct pci_id_descr *dev_descr, unsigned n_devs)
+{
+ struct i7core_dev *i7core_dev;
+
+ struct pci_dev *pdev = NULL;
+ u8 bus = 0;
+ u8 socket = 0;
+
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ dev_descr->dev_id, *prev);
+
+ /*
+ * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs
+ * is at addr 8086:2c40, instead of 8086:2c41. So, we need
+ * to probe for the alternate address in case of failure
+ */
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev)
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev);
+
+ if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev)
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT,
+ *prev);
+
+ if (!pdev) {
+ if (*prev) {
+ *prev = pdev;
+ return 0;
+ }
+
+ if (dev_descr->optional)
+ return 0;
+
+ if (devno == 0)
+ return -ENODEV;
+
+ i7core_printk(KERN_ERR,
+ "Device not found: dev %02x.%d PCI ID %04x:%04x\n",
+ dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+ /* End of list, leave */
+ return -ENODEV;
+ }
+ bus = pdev->bus->number;
+
+ if (bus == 0x3f)
+ socket = 0;
+ else
+ socket = 255 - bus;
+
+ i7core_dev = get_i7core_dev(socket);
+ if (!i7core_dev) {
+ i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL);
+ if (!i7core_dev)
+ return -ENOMEM;
+ i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs,
+ GFP_KERNEL);
+ if (!i7core_dev->pdev) {
+ kfree(i7core_dev);
+ return -ENOMEM;
+ }
+ i7core_dev->socket = socket;
+ i7core_dev->n_devs = n_devs;
+ list_add_tail(&i7core_dev->list, &i7core_edac_list);
+ }
+
+ if (i7core_dev->pdev[devno]) {
+ i7core_printk(KERN_ERR,
+ "Duplicated device for "
+ "dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ bus, dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+
+ i7core_dev->pdev[devno] = pdev;
+
+ /* Sanity check */
+ if (unlikely(PCI_SLOT(pdev->devfn) != dev_descr->dev ||
+ PCI_FUNC(pdev->devfn) != dev_descr->func)) {
+ i7core_printk(KERN_ERR,
+ "Device PCI ID %04x:%04x "
+ "has dev %02x:%02x.%d instead of dev %02x:%02x.%d\n",
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id,
+ bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ bus, dev_descr->dev, dev_descr->func);
+ return -ENODEV;
+ }
+
+ /* Be sure that the device is enabled */
+ if (unlikely(pci_enable_device(pdev) < 0)) {
+ i7core_printk(KERN_ERR,
+ "Couldn't enable "
+ "dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ bus, dev_descr->dev, dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+ return -ENODEV;
+ }
+
+ debugf0("Detected socket %d dev %02x:%02x.%d PCI ID %04x:%04x\n",
+ socket, bus, dev_descr->dev,
+ dev_descr->func,
+ PCI_VENDOR_ID_INTEL, dev_descr->dev_id);
+
+ *prev = pdev;
+
+ return 0;
+}
+
+static int i7core_get_devices(struct pci_id_table *table)
+{
+ int i, rc;
+ struct pci_dev *pdev = NULL;
+ struct pci_id_descr *dev_descr;
+
+ while (table && table->descr) {
+ dev_descr = table->descr;
+ for (i = 0; i < table->n_devs; i++) {
+ pdev = NULL;
+ do {
+ rc = i7core_get_onedevice(&pdev, i, &dev_descr[i],
+ table->n_devs);
+ if (rc < 0) {
+ if (i == 0) {
+ i = table->n_devs;
+ break;
+ }
+ i7core_put_all_devices();
+ return -ENODEV;
+ }
+ } while (pdev);
+ }
+ table++;
+ }
+
+ return 0;
+ return 0;
+}
+
+static int mci_bind_devs(struct mem_ctl_info *mci,
+ struct i7core_dev *i7core_dev)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev;
+ int i, func, slot;
+
+ /* Associates i7core_dev and mci for future usage */
+ pvt->i7core_dev = i7core_dev;
+ i7core_dev->mci = mci;
+
+ pvt->is_registered = 0;
+ for (i = 0; i < i7core_dev->n_devs; i++) {
+ pdev = i7core_dev->pdev[i];
+ if (!pdev)
+ continue;
+
+ func = PCI_FUNC(pdev->devfn);
+ slot = PCI_SLOT(pdev->devfn);
+ if (slot == 3) {
+ if (unlikely(func > MAX_MCR_FUNC))
+ goto error;
+ pvt->pci_mcr[func] = pdev;
+ } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) {
+ if (unlikely(func > MAX_CHAN_FUNC))
+ goto error;
+ pvt->pci_ch[slot - 4][func] = pdev;
+ } else if (!slot && !func)
+ pvt->pci_noncore = pdev;
+ else
+ goto error;
+
+ debugf0("Associated fn %d.%d, dev = %p, socket %d\n",
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ pdev, i7core_dev->socket);
+
+ if (PCI_SLOT(pdev->devfn) == 3 &&
+ PCI_FUNC(pdev->devfn) == 2)
+ pvt->is_registered = 1;
+ }
+
+ /*
+ * Add extra nodes to count errors on udimm
+ * For registered memory, this is not needed, since the counters
+ * are already displayed at the standard locations
+ */
+ if (!pvt->is_registered)
+ i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp =
+ &i7core_udimm_counters;
+
+ return 0;
+
+error:
+ i7core_printk(KERN_ERR, "Device %d, function %d "
+ "is out of the expected range\n",
+ slot, func);
+ return -EINVAL;
+}
+
+/****************************************************************************
+ Error check routines
+ ****************************************************************************/
+static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
+ int chan, int dimm, int add)
+{
+ char *msg;
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int row = pvt->csrow_map[chan][dimm], i;
+
+ for (i = 0; i < add; i++) {
+ msg = kasprintf(GFP_KERNEL, "Corrected error "
+ "(Socket=%d channel=%d dimm=%d)",
+ pvt->i7core_dev->socket, chan, dimm);
+
+ edac_mc_handle_fbd_ce(mci, row, 0, msg);
+ kfree (msg);
+ }
+}
+
+static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
+ int chan, int new0, int new1, int new2)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int add0 = 0, add1 = 0, add2 = 0;
+ /* Updates CE counters if it is not the first time here */
+ if (pvt->ce_count_available) {
+ /* Updates CE counters */
+
+ add2 = new2 - pvt->rdimm_last_ce_count[chan][2];
+ add1 = new1 - pvt->rdimm_last_ce_count[chan][1];
+ add0 = new0 - pvt->rdimm_last_ce_count[chan][0];
+
+ if (add2 < 0)
+ add2 += 0x7fff;
+ pvt->rdimm_ce_count[chan][2] += add2;
+
+ if (add1 < 0)
+ add1 += 0x7fff;
+ pvt->rdimm_ce_count[chan][1] += add1;
+
+ if (add0 < 0)
+ add0 += 0x7fff;
+ pvt->rdimm_ce_count[chan][0] += add0;
+ } else
+ pvt->ce_count_available = 1;
+
+ /* Store the new values */
+ pvt->rdimm_last_ce_count[chan][2] = new2;
+ pvt->rdimm_last_ce_count[chan][1] = new1;
+ pvt->rdimm_last_ce_count[chan][0] = new0;
+
+ /*updated the edac core */
+ if (add0 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 0, add0);
+ if (add1 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 1, add1);
+ if (add2 != 0)
+ i7core_rdimm_update_csrow(mci, chan, 2, add2);
+
+}
+
+static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 rcv[3][2];
+ int i, new0, new1, new2;
+
+ /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0,
+ &rcv[0][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1,
+ &rcv[0][1]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2,
+ &rcv[1][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3,
+ &rcv[1][1]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4,
+ &rcv[2][0]);
+ pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5,
+ &rcv[2][1]);
+ for (i = 0 ; i < 3; i++) {
+ debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n",
+ (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]);
+ /*if the channel has 3 dimms*/
+ if (pvt->channel[i].dimms > 2) {
+ new0 = DIMM_BOT_COR_ERR(rcv[i][0]);
+ new1 = DIMM_TOP_COR_ERR(rcv[i][0]);
+ new2 = DIMM_BOT_COR_ERR(rcv[i][1]);
+ } else {
+ new0 = DIMM_TOP_COR_ERR(rcv[i][0]) +
+ DIMM_BOT_COR_ERR(rcv[i][0]);
+ new1 = DIMM_TOP_COR_ERR(rcv[i][1]) +
+ DIMM_BOT_COR_ERR(rcv[i][1]);
+ new2 = 0;
+ }
+
+ i7core_rdimm_update_ce_count(mci, i, new0, new1, new2);
+ }
+}
+
+/* This function is based on the device 3 function 4 registers as described on:
+ * Intel Xeon Processor 5500 Series Datasheet Volume 2
+ * http://www.intel.com/Assets/PDF/datasheet/321322.pdf
+ * also available at:
+ * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf
+ */
+static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ u32 rcv1, rcv0;
+ int new0, new1, new2;
+
+ if (!pvt->pci_mcr[4]) {
+ debugf0("%s MCR registers not found\n", __func__);
+ return;
+ }
+
+ /* Corrected test errors */
+ pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1);
+ pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0);
+
+ /* Store the new values */
+ new2 = DIMM2_COR_ERR(rcv1);
+ new1 = DIMM1_COR_ERR(rcv0);
+ new0 = DIMM0_COR_ERR(rcv0);
+
+ /* Updates CE counters if it is not the first time here */
+ if (pvt->ce_count_available) {
+ /* Updates CE counters */
+ int add0, add1, add2;
+
+ add2 = new2 - pvt->udimm_last_ce_count[2];
+ add1 = new1 - pvt->udimm_last_ce_count[1];
+ add0 = new0 - pvt->udimm_last_ce_count[0];
+
+ if (add2 < 0)
+ add2 += 0x7fff;
+ pvt->udimm_ce_count[2] += add2;
+
+ if (add1 < 0)
+ add1 += 0x7fff;
+ pvt->udimm_ce_count[1] += add1;
+
+ if (add0 < 0)
+ add0 += 0x7fff;
+ pvt->udimm_ce_count[0] += add0;
+
+ if (add0 | add1 | add2)
+ i7core_printk(KERN_ERR, "New Corrected error(s): "
+ "dimm0: +%d, dimm1: +%d, dimm2 +%d\n",
+ add0, add1, add2);
+ } else
+ pvt->ce_count_available = 1;
+
+ /* Store the new values */
+ pvt->udimm_last_ce_count[2] = new2;
+ pvt->udimm_last_ce_count[1] = new1;
+ pvt->udimm_last_ce_count[0] = new0;
+}
+
+/*
+ * According with tables E-11 and E-12 of chapter E.3.3 of Intel 64 and IA-32
+ * Architectures Software Developer’s Manual Volume 3B.
+ * Nehalem are defined as family 0x06, model 0x1a
+ *
+ * The MCA registers used here are the following ones:
+ * struct mce field MCA Register
+ * m->status MSR_IA32_MC8_STATUS
+ * m->addr MSR_IA32_MC8_ADDR
+ * m->misc MSR_IA32_MC8_MISC
+ * In the case of Nehalem, the error information is masked at .status and .misc
+ * fields
+ */
+static void i7core_mce_output_error(struct mem_ctl_info *mci,
+ struct mce *m)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ char *type, *optype, *err, *msg;
+ unsigned long error = m->status & 0x1ff0000l;
+ u32 optypenum = (m->status >> 4) & 0x07;
+ u32 core_err_cnt = (m->status >> 38) && 0x7fff;
+ u32 dimm = (m->misc >> 16) & 0x3;
+ u32 channel = (m->misc >> 18) & 0x3;
+ u32 syndrome = m->misc >> 32;
+ u32 errnum = find_first_bit(&error, 32);
+ int csrow;
+
+ if (m->mcgstatus & 1)
+ type = "FATAL";
+ else
+ type = "NON_FATAL";
+
+ switch (optypenum) {
+ case 0:
+ optype = "generic undef request";
+ break;
+ case 1:
+ optype = "read error";
+ break;
+ case 2:
+ optype = "write error";
+ break;
+ case 3:
+ optype = "addr/cmd error";
+ break;
+ case 4:
+ optype = "scrubbing error";
+ break;
+ default:
+ optype = "reserved";
+ break;
+ }
+
+ switch (errnum) {
+ case 16:
+ err = "read ECC error";
+ break;
+ case 17:
+ err = "RAS ECC error";
+ break;
+ case 18:
+ err = "write parity error";
+ break;
+ case 19:
+ err = "redundacy loss";
+ break;
+ case 20:
+ err = "reserved";
+ break;
+ case 21:
+ err = "memory range error";
+ break;
+ case 22:
+ err = "RTID out of range";
+ break;
+ case 23:
+ err = "address parity error";
+ break;
+ case 24:
+ err = "byte enable parity error";
+ break;
+ default:
+ err = "unknown";
+ }
+
+ /* FIXME: should convert addr into bank and rank information */
+ msg = kasprintf(GFP_ATOMIC,
+ "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, "
+ "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n",
+ type, (long long) m->addr, m->cpu, dimm, channel,
+ syndrome, core_err_cnt, (long long)m->status,
+ (long long)m->misc, optype, err);
+
+ debugf0("%s", msg);
+
+ csrow = pvt->csrow_map[channel][dimm];
+
+ /* Call the helper to output message */
+ if (m->mcgstatus & 1)
+ edac_mc_handle_fbd_ue(mci, csrow, 0,
+ 0 /* FIXME: should be channel here */, msg);
+ else if (!pvt->is_registered)
+ edac_mc_handle_fbd_ce(mci, csrow,
+ 0 /* FIXME: should be channel here */, msg);
+
+ kfree(msg);
+}
+
+/*
+ * i7core_check_error Retrieve and process errors reported by the
+ * hardware. Called by the Core module.
+ */
+static void i7core_check_error(struct mem_ctl_info *mci)
+{
+ struct i7core_pvt *pvt = mci->pvt_info;
+ int i;
+ unsigned count = 0;
+ struct mce *m;
+
+ /*
+ * MCE first step: Copy all mce errors into a temporary buffer
+ * We use a double buffering here, to reduce the risk of
+ * loosing an error.
+ */
+ smp_rmb();
+ count = (pvt->mce_out + MCE_LOG_LEN - pvt->mce_in)
+ % MCE_LOG_LEN;
+ if (!count)
+ goto check_ce_error;
+
+ m = pvt->mce_outentry;
+ if (pvt->mce_in + count > MCE_LOG_LEN) {
+ unsigned l = MCE_LOG_LEN - pvt->mce_in;
+
+ memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * l);
+ smp_wmb();
+ pvt->mce_in = 0;
+ count -= l;
+ m += l;
+ }
+ memcpy(m, &pvt->mce_entry[pvt->mce_in], sizeof(*m) * count);
+ smp_wmb();
+ pvt->mce_in += count;
+
+ smp_rmb();
+ if (pvt->mce_overrun) {
+ i7core_printk(KERN_ERR, "Lost %d memory errors\n",
+ pvt->mce_overrun);
+ smp_wmb();
+ pvt->mce_overrun = 0;
+ }
+
+ /*
+ * MCE second step: parse errors and display
+ */
+ for (i = 0; i < count; i++)
+ i7core_mce_output_error(mci, &pvt->mce_outentry[i]);
+
+ /*
+ * Now, let's increment CE error counts
+ */
+check_ce_error:
+ if (!pvt->is_registered)
+ i7core_udimm_check_mc_ecc_err(mci);
+ else
+ i7core_rdimm_check_mc_ecc_err(mci);
+}
+
+/*
+ * i7core_mce_check_error Replicates mcelog routine to get errors
+ * This routine simply queues mcelog errors, and
+ * return. The error itself should be handled later
+ * by i7core_check_error.
+ * WARNING: As this routine should be called at NMI time, extra care should
+ * be taken to avoid deadlocks, and to be as fast as possible.
+ */
+static int i7core_mce_check_error(void *priv, struct mce *mce)
+{
+ struct mem_ctl_info *mci = priv;
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ /*
+ * Just let mcelog handle it if the error is
+ * outside the memory controller
+ */
+ if (((mce->status & 0xffff) >> 7) != 1)
+ return 0;
+
+ /* Bank 8 registers are the only ones that we know how to handle */
+ if (mce->bank != 8)
+ return 0;
+
+#ifdef CONFIG_SMP
+ /* Only handle if it is the right mc controller */
+ if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket)
+ return 0;
+#endif
+
+ smp_rmb();
+ if ((pvt->mce_out + 1) % MCE_LOG_LEN == pvt->mce_in) {
+ smp_wmb();
+ pvt->mce_overrun++;
+ return 0;
+ }
+
+ /* Copy memory error at the ringbuffer */
+ memcpy(&pvt->mce_entry[pvt->mce_out], mce, sizeof(*mce));
+ smp_wmb();
+ pvt->mce_out = (pvt->mce_out + 1) % MCE_LOG_LEN;
+
+ /* Handle fatal errors immediately */
+ if (mce->mcgstatus & 1)
+ i7core_check_error(mci);
+
+ /* Advice mcelog that the error were handled */
+ return 1;
+}
+
+static int i7core_register_mci(struct i7core_dev *i7core_dev,
+ int num_channels, int num_csrows)
+{
+ struct mem_ctl_info *mci;
+ struct i7core_pvt *pvt;
+ int csrow = 0;
+ int rc;
+
+ /* allocate a new MC control structure */
+ mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels,
+ i7core_dev->socket);
+ if (unlikely(!mci))
+ return -ENOMEM;
+
+ debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci);
+
+ /* record ptr to the generic device */
+ mci->dev = &i7core_dev->pdev[0]->dev;
+
+ pvt = mci->pvt_info;
+ memset(pvt, 0, sizeof(*pvt));
+
+ /*
+ * FIXME: how to handle RDDR3 at MCI level? It is possible to have
+ * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different
+ * memory channels
+ */
+ mci->mtype_cap = MEM_FLAG_DDR3;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE;
+ mci->edac_cap = EDAC_FLAG_NONE;
+ mci->mod_name = "i7core_edac.c";
+ mci->mod_ver = I7CORE_REVISION;
+ mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d",
+ i7core_dev->socket);
+ mci->dev_name = pci_name(i7core_dev->pdev[0]);
+ mci->ctl_page_to_phys = NULL;
+ mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs;
+ /* Set the function pointer to an actual operation function */
+ mci->edac_check = i7core_check_error;
+
+ /* Store pci devices at mci for faster access */
+ rc = mci_bind_devs(mci, i7core_dev);
+ if (unlikely(rc < 0))
+ goto fail;
+
+ /* Get dimm basic config */
+ get_dimm_config(mci, &csrow);
+
+ /* add this new MC control structure to EDAC's list of MCs */
+ if (unlikely(edac_mc_add_mc(mci))) {
+ debugf0("MC: " __FILE__
+ ": %s(): failed edac_mc_add_mc()\n", __func__);
+ /* FIXME: perhaps some code should go here that disables error
+ * reporting if we just enabled it
+ */
+
+ rc = -EINVAL;
+ goto fail;
+ }
+
+ /* allocating generic PCI control info */
+ i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev,
+ EDAC_MOD_STR);
+ if (unlikely(!i7core_pci)) {
+ printk(KERN_WARNING
+ "%s(): Unable to create PCI control\n",
+ __func__);
+ printk(KERN_WARNING
+ "%s(): PCI error report via EDAC not setup\n",
+ __func__);
+ }
+
+ /* Default error mask is any memory */
+ pvt->inject.channel = 0;
+ pvt->inject.dimm = -1;
+ pvt->inject.rank = -1;
+ pvt->inject.bank = -1;
+ pvt->inject.page = -1;
+ pvt->inject.col = -1;
+
+ /* Registers on edac_mce in order to receive memory errors */
+ pvt->edac_mce.priv = mci;
+ pvt->edac_mce.check_error = i7core_mce_check_error;
+
+ rc = edac_mce_register(&pvt->edac_mce);
+ if (unlikely(rc < 0)) {
+ debugf0("MC: " __FILE__
+ ": %s(): failed edac_mce_register()\n", __func__);
+ }
+
+fail:
+ if (rc < 0)
+ edac_mc_free(mci);
+ return rc;
+}
+
+/*
+ * i7core_probe Probe for ONE instance of device to see if it is
+ * present.
+ * return:
+ * 0 for FOUND a device
+ * < 0 for error code
+ */
+static int __devinit i7core_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int dev_idx = id->driver_data;
+ int rc;
+ struct i7core_dev *i7core_dev;
+
+ /*
+ * All memory controllers are allocated at the first pass.
+ */
+ if (unlikely(dev_idx >= 1))
+ return -EINVAL;
+
+ /* get the pci devices we want to reserve for our use */
+ mutex_lock(&i7core_edac_lock);
+
+ rc = i7core_get_devices(pci_dev_table);
+ if (unlikely(rc < 0))
+ goto fail0;
+
+ list_for_each_entry(i7core_dev, &i7core_edac_list, list) {
+ int channels;
+ int csrows;
+
+ /* Check the number of active and not disabled channels */
+ rc = i7core_get_active_channels(i7core_dev->socket,
+ &channels, &csrows);
+ if (unlikely(rc < 0))
+ goto fail1;
+
+ rc = i7core_register_mci(i7core_dev, channels, csrows);
+ if (unlikely(rc < 0))
+ goto fail1;
+ }
+
+ i7core_printk(KERN_INFO, "Driver loaded.\n");
+
+ mutex_unlock(&i7core_edac_lock);
+ return 0;
+
+fail1:
+ i7core_put_all_devices();
+fail0:
+ mutex_unlock(&i7core_edac_lock);
+ return rc;
+}
+
+/*
+ * i7core_remove destructor for one instance of device
+ *
+ */
+static void __devexit i7core_remove(struct pci_dev *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct i7core_dev *i7core_dev, *tmp;
+
+ debugf0(__FILE__ ": %s()\n", __func__);
+
+ if (i7core_pci)
+ edac_pci_release_generic_ctl(i7core_pci);
+
+ /*
+ * we have a trouble here: pdev value for removal will be wrong, since
+ * it will point to the X58 register used to detect that the machine
+ * is a Nehalem or upper design. However, due to the way several PCI
+ * devices are grouped together to provide MC functionality, we need
+ * to use a different method for releasing the devices
+ */
+
+ mutex_lock(&i7core_edac_lock);
+ list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) {
+ mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev);
+ if (mci) {
+ struct i7core_pvt *pvt = mci->pvt_info;
+
+ i7core_dev = pvt->i7core_dev;
+ edac_mce_unregister(&pvt->edac_mce);
+ kfree(mci->ctl_name);
+ edac_mc_free(mci);
+ i7core_put_devices(i7core_dev);
+ } else {
+ i7core_printk(KERN_ERR,
+ "Couldn't find mci for socket %d\n",
+ i7core_dev->socket);
+ }
+ }
+ mutex_unlock(&i7core_edac_lock);
+}
+
+MODULE_DEVICE_TABLE(pci, i7core_pci_tbl);
+
+/*
+ * i7core_driver pci_driver structure for this module
+ *
+ */
+static struct pci_driver i7core_driver = {
+ .name = "i7core_edac",
+ .probe = i7core_probe,
+ .remove = __devexit_p(i7core_remove),
+ .id_table = i7core_pci_tbl,
+};
+
+/*
+ * i7core_init Module entry function
+ * Try to initialize this module for its devices
+ */
+static int __init i7core_init(void)
+{
+ int pci_rc;
+
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
+ i7core_xeon_pci_fixup(pci_dev_table);
+
+ pci_rc = pci_register_driver(&i7core_driver);
+
+ if (pci_rc >= 0)
+ return 0;
+
+ i7core_printk(KERN_ERR, "Failed to register device with error %d.\n",
+ pci_rc);
+
+ return pci_rc;
+}
+
+/*
+ * i7core_exit() Module exit function
+ * Unregister the driver
+ */
+static void __exit i7core_exit(void)
+{
+ debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ pci_unregister_driver(&i7core_driver);
+}
+
+module_init(i7core_init);
+module_exit(i7core_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("MC Driver for Intel i7 Core memory controllers - "
+ I7CORE_REVISION);
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 6c1886b497ff..52ca09bf4726 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -229,7 +229,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
pdata->edac_idx = edac_pci_idx++;
- res = of_address_to_resource(op->node, 0, &r);
+ res = of_address_to_resource(op->dev.of_node, 0, &r);
if (res) {
printk(KERN_ERR "%s: Unable to get resource for "
"PCI err regs\n", __func__);
@@ -274,7 +274,7 @@ static int __devinit mpc85xx_pci_err_probe(struct of_device *op,
}
if (edac_op_state == EDAC_OPSTATE_INT) {
- pdata->irq = irq_of_parse_and_map(op->node, 0);
+ pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr, IRQF_DISABLED,
"[EDAC] PCI err", pci);
@@ -529,7 +529,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op,
edac_dev->ctl_name = pdata->name;
edac_dev->dev_name = pdata->name;
- res = of_address_to_resource(op->node, 0, &r);
+ res = of_address_to_resource(op->dev.of_node, 0, &r);
if (res) {
printk(KERN_ERR "%s: Unable to get resource for "
"L2 err regs\n", __func__);
@@ -576,7 +576,7 @@ static int __devinit mpc85xx_l2_err_probe(struct of_device *op,
}
if (edac_op_state == EDAC_OPSTATE_INT) {
- pdata->irq = irq_of_parse_and_map(op->node, 0);
+ pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_l2_isr, IRQF_DISABLED,
"[EDAC] L2 err", edac_dev);
@@ -978,7 +978,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
mci->ctl_name = pdata->name;
mci->dev_name = pdata->name;
- res = of_address_to_resource(op->node, 0, &r);
+ res = of_address_to_resource(op->dev.of_node, 0, &r);
if (res) {
printk(KERN_ERR "%s: Unable to get resource for MC err regs\n",
__func__);
@@ -1052,7 +1052,7 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_SBE, 0x10000);
/* register interrupts */
- pdata->irq = irq_of_parse_and_map(op->node, 0);
+ pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_mc_isr,
IRQF_DISABLED | IRQF_SHARED,
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 9d6f6783328c..e78839e89a06 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -1022,7 +1022,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
int status = 0;
const u32 memcheck = (mcopt1 & SDRAM_MCOPT1_MCHK_MASK);
struct ppc4xx_edac_pdata *pdata = NULL;
- const struct device_node *np = op->node;
+ const struct device_node *np = op->dev.of_node;
if (match == NULL)
return -EINVAL;
@@ -1113,7 +1113,7 @@ ppc4xx_edac_register_irq(struct of_device *op, struct mem_ctl_info *mci)
int status = 0;
int ded_irq, sec_irq;
struct ppc4xx_edac_pdata *pdata = mci->pvt_info;
- struct device_node *np = op->node;
+ struct device_node *np = op->dev.of_node;
ded_irq = irq_of_parse_and_map(np, INTMAP_ECCDED_INDEX);
sec_irq = irq_of_parse_and_map(np, INTMAP_ECCSEC_INDEX);
@@ -1243,7 +1243,7 @@ ppc4xx_edac_probe(struct of_device *op, const struct of_device_id *match)
int status = 0;
u32 mcopt1, memcheck;
dcr_host_t dcr_host;
- const struct device_node *np = op->node;
+ const struct device_node *np = op->dev.of_node;
struct mem_ctl_info *mci = NULL;
static int ppc4xx_edac_instance;
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 9dcb30466ec0..371713ff0266 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -231,7 +231,7 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay)
static void fw_card_bm_work(struct work_struct *work)
{
struct fw_card *card = container_of(work, struct fw_card, work.work);
- struct fw_device *root_device;
+ struct fw_device *root_device, *irm_device;
struct fw_node *root_node;
unsigned long flags;
int root_id, new_root_id, irm_id, local_id;
@@ -239,6 +239,7 @@ static void fw_card_bm_work(struct work_struct *work)
bool do_reset = false;
bool root_device_is_running;
bool root_device_is_cmc;
+ bool irm_is_1394_1995_only;
spin_lock_irqsave(&card->lock, flags);
@@ -248,12 +249,18 @@ static void fw_card_bm_work(struct work_struct *work)
}
generation = card->generation;
+
root_node = card->root_node;
fw_node_get(root_node);
root_device = root_node->data;
root_device_is_running = root_device &&
atomic_read(&root_device->state) == FW_DEVICE_RUNNING;
root_device_is_cmc = root_device && root_device->cmc;
+
+ irm_device = card->irm_node->data;
+ irm_is_1394_1995_only = irm_device && irm_device->config_rom &&
+ (irm_device->config_rom[2] & 0x000000f0) == 0;
+
root_id = root_node->node_id;
irm_id = card->irm_node->node_id;
local_id = card->local_node->node_id;
@@ -276,8 +283,15 @@ static void fw_card_bm_work(struct work_struct *work)
if (!card->irm_node->link_on) {
new_root_id = local_id;
- fw_notify("IRM has link off, making local node (%02x) root.\n",
- new_root_id);
+ fw_notify("%s, making local node (%02x) root.\n",
+ "IRM has link off", new_root_id);
+ goto pick_me;
+ }
+
+ if (irm_is_1394_1995_only) {
+ new_root_id = local_id;
+ fw_notify("%s, making local node (%02x) root.\n",
+ "IRM is not 1394a compliant", new_root_id);
goto pick_me;
}
@@ -316,8 +330,8 @@ static void fw_card_bm_work(struct work_struct *work)
* root, and thus, IRM.
*/
new_root_id = local_id;
- fw_notify("BM lock failed, making local node (%02x) root.\n",
- new_root_id);
+ fw_notify("%s, making local node (%02x) root.\n",
+ "BM lock failed", new_root_id);
goto pick_me;
}
} else if (card->bm_generation != generation) {
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1b03ba1d0834..a6c670b8ce52 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -122,8 +122,17 @@ config ISCSI_IBFT_FIND
is necessary for iSCSI Boot Firmware Table Attributes module to work
properly.
+config ISCSI_BOOT_SYSFS
+ tristate "iSCSI Boot Sysfs Interface"
+ default n
+ help
+ This option enables support for exposing iSCSI boot information
+ via sysfs to userspace. If you wish to export this information,
+ say Y. Otherwise, say N.
+
config ISCSI_IBFT
tristate "iSCSI Boot Firmware Table Attributes module"
+ select ISCSI_BOOT_SYSFS
depends on ISCSI_IBFT_FIND
default n
help
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 1c3c17343dbe..5fe7e1662922 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -10,4 +10,5 @@ obj-$(CONFIG_DCDBAS) += dcdbas.o
obj-$(CONFIG_DMIID) += dmi-id.o
obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
+obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
diff --git a/drivers/firmware/iscsi_boot_sysfs.c b/drivers/firmware/iscsi_boot_sysfs.c
new file mode 100644
index 000000000000..df6bff7366cf
--- /dev/null
+++ b/drivers/firmware/iscsi_boot_sysfs.c
@@ -0,0 +1,481 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/capability.h>
+#include <linux/iscsi_boot_sysfs.h>
+
+
+MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>");
+MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information");
+MODULE_LICENSE("GPL");
+/*
+ * The kobject and attribute structures.
+ */
+struct iscsi_boot_attr {
+ struct attribute attr;
+ int type;
+ ssize_t (*show) (void *data, int type, char *buf);
+};
+
+/*
+ * The routine called for all sysfs attributes.
+ */
+static ssize_t iscsi_boot_show_attribute(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+ struct iscsi_boot_attr *boot_attr =
+ container_of(attr, struct iscsi_boot_attr, attr);
+ ssize_t ret = -EIO;
+ char *str = buf;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (boot_kobj->show)
+ ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str);
+ return ret;
+}
+
+static const struct sysfs_ops iscsi_boot_attr_ops = {
+ .show = iscsi_boot_show_attribute,
+};
+
+static void iscsi_boot_kobj_release(struct kobject *kobj)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ kfree(boot_kobj->data);
+ kfree(boot_kobj);
+}
+
+static struct kobj_type iscsi_boot_ktype = {
+ .release = iscsi_boot_kobj_release,
+ .sysfs_ops = &iscsi_boot_attr_ops,
+};
+
+#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \
+static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \
+ .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \
+ .type = attr_type, \
+}
+
+/* Target attrs */
+iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX);
+iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS);
+iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR);
+iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT);
+iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN);
+iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE);
+iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC);
+iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME);
+iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET);
+iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+
+static struct attribute *target_attrs[] = {
+ &iscsi_boot_attr_tgt_index.attr,
+ &iscsi_boot_attr_tgt_flags.attr,
+ &iscsi_boot_attr_tgt_ip.attr,
+ &iscsi_boot_attr_tgt_port.attr,
+ &iscsi_boot_attr_tgt_lun.attr,
+ &iscsi_boot_attr_tgt_chap.attr,
+ &iscsi_boot_attr_tgt_nic.attr,
+ &iscsi_boot_attr_tgt_name.attr,
+ &iscsi_boot_attr_tgt_chap_name.attr,
+ &iscsi_boot_attr_tgt_chap_secret.attr,
+ &iscsi_boot_attr_tgt_chap_rev_name.attr,
+ &iscsi_boot_attr_tgt_chap_rev_secret.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_tgt_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_INDEX);
+ else if (attr == &iscsi_boot_attr_tgt_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_FLAGS);
+ else if (attr == &iscsi_boot_attr_tgt_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_tgt_port.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_PORT);
+ else if (attr == &iscsi_boot_attr_tgt_lun.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_LUN);
+ else if (attr == &iscsi_boot_attr_tgt_chap.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_TYPE);
+ else if (attr == &iscsi_boot_attr_tgt_nic.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NIC_ASSOC);
+ else if (attr == &iscsi_boot_attr_tgt_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_CHAP_SECRET);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME);
+ else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_target_attr_group = {
+ .attrs = target_attrs,
+ .is_visible = iscsi_boot_tgt_attr_is_visible,
+};
+
+/* Ethernet attrs */
+iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX);
+iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS);
+iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR);
+iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK);
+iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN);
+iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY);
+iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS);
+iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP);
+iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN);
+iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC);
+iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME);
+
+static struct attribute *ethernet_attrs[] = {
+ &iscsi_boot_attr_eth_index.attr,
+ &iscsi_boot_attr_eth_flags.attr,
+ &iscsi_boot_attr_eth_ip.attr,
+ &iscsi_boot_attr_eth_subnet.attr,
+ &iscsi_boot_attr_eth_origin.attr,
+ &iscsi_boot_attr_eth_gateway.attr,
+ &iscsi_boot_attr_eth_primary_dns.attr,
+ &iscsi_boot_attr_eth_secondary_dns.attr,
+ &iscsi_boot_attr_eth_dhcp.attr,
+ &iscsi_boot_attr_eth_vlan.attr,
+ &iscsi_boot_attr_eth_mac.attr,
+ &iscsi_boot_attr_eth_hostname.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_eth_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_INDEX);
+ else if (attr == &iscsi_boot_attr_eth_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_FLAGS);
+ else if (attr == &iscsi_boot_attr_eth_ip.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_IP_ADDR);
+ else if (attr == &iscsi_boot_attr_eth_subnet.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SUBNET_MASK);
+ else if (attr == &iscsi_boot_attr_eth_origin.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_ORIGIN);
+ else if (attr == &iscsi_boot_attr_eth_gateway.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_GATEWAY);
+ else if (attr == &iscsi_boot_attr_eth_primary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_PRIMARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_SECONDARY_DNS);
+ else if (attr == &iscsi_boot_attr_eth_dhcp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_DHCP);
+ else if (attr == &iscsi_boot_attr_eth_vlan.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_VLAN);
+ else if (attr == &iscsi_boot_attr_eth_mac.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_MAC);
+ else if (attr == &iscsi_boot_attr_eth_hostname.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_ETH_HOSTNAME);
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_ethernet_attr_group = {
+ .attrs = ethernet_attrs,
+ .is_visible = iscsi_boot_eth_attr_is_visible,
+};
+
+/* Initiator attrs */
+iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX);
+iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS);
+iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER);
+iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER);
+iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME);
+
+static struct attribute *initiator_attrs[] = {
+ &iscsi_boot_attr_ini_index.attr,
+ &iscsi_boot_attr_ini_flags.attr,
+ &iscsi_boot_attr_ini_isns.attr,
+ &iscsi_boot_attr_ini_slp.attr,
+ &iscsi_boot_attr_ini_primary_radius.attr,
+ &iscsi_boot_attr_ini_secondary_radius.attr,
+ &iscsi_boot_attr_ini_name.attr,
+ NULL
+};
+
+static mode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int i)
+{
+ struct iscsi_boot_kobj *boot_kobj =
+ container_of(kobj, struct iscsi_boot_kobj, kobj);
+
+ if (attr == &iscsi_boot_attr_ini_index.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INDEX);
+ if (attr == &iscsi_boot_attr_ini_flags.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_FLAGS);
+ if (attr == &iscsi_boot_attr_ini_isns.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_ISNS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_slp.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SLP_SERVER);
+ if (attr == &iscsi_boot_attr_ini_primary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_secondary_radius.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER);
+ if (attr == &iscsi_boot_attr_ini_name.attr)
+ return boot_kobj->is_visible(boot_kobj->data,
+ ISCSI_BOOT_INI_INITIATOR_NAME);
+
+ return 0;
+}
+
+static struct attribute_group iscsi_boot_initiator_attr_group = {
+ .attrs = initiator_attrs,
+ .is_visible = iscsi_boot_ini_attr_is_visible,
+};
+
+static struct iscsi_boot_kobj *
+iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset,
+ struct attribute_group *attr_group,
+ const char *name, int index, void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ struct iscsi_boot_kobj *boot_kobj;
+
+ boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL);
+ if (!boot_kobj)
+ return NULL;
+ INIT_LIST_HEAD(&boot_kobj->list);
+
+ boot_kobj->kobj.kset = boot_kset->kset;
+ if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype,
+ NULL, name, index)) {
+ kfree(boot_kobj);
+ return NULL;
+ }
+ boot_kobj->data = data;
+ boot_kobj->show = show;
+ boot_kobj->is_visible = is_visible;
+
+ if (sysfs_create_group(&boot_kobj->kobj, attr_group)) {
+ /*
+ * We do not want to free this because the caller
+ * will assume that since the creation call failed
+ * the boot kobj was not setup and the normal release
+ * path is not being run.
+ */
+ boot_kobj->data = NULL;
+ kobject_put(&boot_kobj->kobj);
+ return NULL;
+ }
+ boot_kobj->attr_group = attr_group;
+
+ kobject_uevent(&boot_kobj->kobj, KOBJ_ADD);
+ /* Nothing broke so lets add it to the list. */
+ list_add_tail(&boot_kobj->list, &boot_kset->kobj_list);
+ return boot_kobj;
+}
+
+static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj)
+{
+ list_del(&boot_kobj->list);
+ sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group);
+ kobject_put(&boot_kobj->kobj);
+}
+
+/**
+ * iscsi_boot_create_target() - create boot target sysfs dir
+ * @boot_kset: boot kset
+ * @index: the target id
+ * @data: driver specific data for target
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the target kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group,
+ "target%d", index, data, show, is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_target);
+
+/**
+ * iscsi_boot_create_initiator() - create boot initiator sysfs dir
+ * @boot_kset: boot kset
+ * @index: the initiator id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the initiator kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_initiator_attr_group,
+ "initiator", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator);
+
+/**
+ * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir
+ * @boot_kset: boot kset
+ * @index: the ethernet device id
+ * @data: driver specific data
+ * @show: attr show function
+ * @is_visible: attr visibility function
+ *
+ * Note: The boot sysfs lib will free the data passed in for the caller
+ * when all refs to the ethernet kobject have been released.
+ */
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type))
+{
+ return iscsi_boot_create_kobj(boot_kset,
+ &iscsi_boot_ethernet_attr_group,
+ "ethernet%d", index, data, show,
+ is_visible);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet);
+
+/**
+ * iscsi_boot_create_kset() - creates root sysfs tree
+ * @set_name: name of root dir
+ */
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name)
+{
+ struct iscsi_boot_kset *boot_kset;
+
+ boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL);
+ if (!boot_kset)
+ return NULL;
+
+ boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj);
+ if (!boot_kset->kset) {
+ kfree(boot_kset);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&boot_kset->kobj_list);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_kset);
+
+/**
+ * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host
+ * @hostno: host number of scsi host
+ */
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno)
+{
+ struct iscsi_boot_kset *boot_kset;
+ char *set_name;
+
+ set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno);
+ if (!set_name)
+ return NULL;
+
+ boot_kset = iscsi_boot_create_kset(set_name);
+ kfree(set_name);
+ return boot_kset;
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset);
+
+/**
+ * iscsi_boot_destroy_kset() - destroy kset and kobjects under it
+ * @boot_kset: boot kset
+ *
+ * This will remove the kset and kobjects and attrs under it.
+ */
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset)
+{
+ struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+
+ list_for_each_entry_safe(boot_kobj, tmp_kobj,
+ &boot_kset->kobj_list, list)
+ iscsi_boot_remove_kobj(boot_kobj);
+
+ kset_unregister(boot_kset->kset);
+}
+EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset);
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index ed2801c378de..4f04ec0410a0 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2007-2010 Red Hat, Inc.
* by Peter Jones <pjones@redhat.com>
* Copyright 2008 IBM, Inc.
* by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -19,6 +19,9 @@
*
* Changelog:
*
+ * 06 Jan 2010 - Peter Jones <pjones@redhat.com>
+ * New changelog entries are in the git log from now on. Not here.
+ *
* 14 Mar 2008 - Konrad Rzeszutek <ketuzsezr@darnok.org>
* Updated comments and copyrights. (v0.4.9)
*
@@ -78,9 +81,11 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_boot_sysfs.h>
-#define IBFT_ISCSI_VERSION "0.4.9"
-#define IBFT_ISCSI_DATE "2008-Mar-14"
+#define IBFT_ISCSI_VERSION "0.5.0"
+#define IBFT_ISCSI_DATE "2010-Feb-25"
MODULE_AUTHOR("Peter Jones <pjones@redhat.com> and \
Konrad Rzeszutek <ketuzsezr@darnok.org>");
@@ -166,108 +171,20 @@ enum ibft_id {
};
/*
- * We do not support the other types, hence the usage of NULL.
- * This maps to the enum ibft_id.
- */
-static const char *ibft_id_names[] =
- {NULL, NULL, "initiator", "ethernet%d", "target%d", NULL, NULL};
-
-/*
- * The text attributes names for each of the kobjects.
-*/
-enum ibft_eth_properties_enum {
- ibft_eth_index,
- ibft_eth_flags,
- ibft_eth_ip_addr,
- ibft_eth_subnet_mask,
- ibft_eth_origin,
- ibft_eth_gateway,
- ibft_eth_primary_dns,
- ibft_eth_secondary_dns,
- ibft_eth_dhcp,
- ibft_eth_vlan,
- ibft_eth_mac,
- /* ibft_eth_pci_bdf - this is replaced by link to the device itself. */
- ibft_eth_hostname,
- ibft_eth_end_marker,
-};
-
-static const char *ibft_eth_properties[] =
- {"index", "flags", "ip-addr", "subnet-mask", "origin", "gateway",
- "primary-dns", "secondary-dns", "dhcp", "vlan", "mac", "hostname",
- NULL};
-
-enum ibft_tgt_properties_enum {
- ibft_tgt_index,
- ibft_tgt_flags,
- ibft_tgt_ip_addr,
- ibft_tgt_port,
- ibft_tgt_lun,
- ibft_tgt_chap_type,
- ibft_tgt_nic_assoc,
- ibft_tgt_name,
- ibft_tgt_chap_name,
- ibft_tgt_chap_secret,
- ibft_tgt_rev_chap_name,
- ibft_tgt_rev_chap_secret,
- ibft_tgt_end_marker,
-};
-
-static const char *ibft_tgt_properties[] =
- {"index", "flags", "ip-addr", "port", "lun", "chap-type", "nic-assoc",
- "target-name", "chap-name", "chap-secret", "rev-chap-name",
- "rev-chap-name-secret", NULL};
-
-enum ibft_initiator_properties_enum {
- ibft_init_index,
- ibft_init_flags,
- ibft_init_isns_server,
- ibft_init_slp_server,
- ibft_init_pri_radius_server,
- ibft_init_sec_radius_server,
- ibft_init_initiator_name,
- ibft_init_end_marker,
-};
-
-static const char *ibft_initiator_properties[] =
- {"index", "flags", "isns-server", "slp-server", "pri-radius-server",
- "sec-radius-server", "initiator-name", NULL};
-
-/*
* The kobject and attribute structures.
*/
struct ibft_kobject {
- struct ibft_table_header *header;
+ struct acpi_table_ibft *header;
union {
struct ibft_initiator *initiator;
struct ibft_nic *nic;
struct ibft_tgt *tgt;
struct ibft_hdr *hdr;
};
- struct kobject kobj;
- struct list_head node;
};
-struct ibft_attribute {
- struct attribute attr;
- ssize_t (*show) (struct ibft_kobject *entry,
- struct ibft_attribute *attr, char *buf);
- union {
- struct ibft_initiator *initiator;
- struct ibft_nic *nic;
- struct ibft_tgt *tgt;
- struct ibft_hdr *hdr;
- };
- struct kobject *kobj;
- int type; /* The enum of the type. This can be any value of:
- ibft_eth_properties_enum, ibft_tgt_properties_enum,
- or ibft_initiator_properties_enum. */
- struct list_head node;
-};
-
-static LIST_HEAD(ibft_attr_list);
-static LIST_HEAD(ibft_kobject_list);
+static struct iscsi_boot_kset *boot_kset;
static const char nulls[16];
@@ -306,35 +223,27 @@ static ssize_t sprintf_string(char *str, int len, char *buf)
static int ibft_verify_hdr(char *t, struct ibft_hdr *hdr, int id, int length)
{
if (hdr->id != id) {
- printk(KERN_ERR "iBFT error: We expected the " \
+ printk(KERN_ERR "iBFT error: We expected the %s " \
"field header.id to have %d but " \
- "found %d instead!\n", id, hdr->id);
+ "found %d instead!\n", t, id, hdr->id);
return -ENODEV;
}
if (hdr->length != length) {
- printk(KERN_ERR "iBFT error: We expected the " \
+ printk(KERN_ERR "iBFT error: We expected the %s " \
"field header.length to have %d but " \
- "found %d instead!\n", length, hdr->length);
+ "found %d instead!\n", t, length, hdr->length);
return -ENODEV;
}
return 0;
}
-static void ibft_release(struct kobject *kobj)
-{
- struct ibft_kobject *ibft =
- container_of(kobj, struct ibft_kobject, kobj);
- kfree(ibft);
-}
-
/*
* Routines for parsing the iBFT data to be human readable.
*/
-static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_initiator(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_initiator *initiator = entry->initiator;
void *ibft_loc = entry->header;
char *str = buf;
@@ -342,26 +251,26 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
if (!initiator)
return 0;
- switch (attr->type) {
- case ibft_init_index:
+ switch (type) {
+ case ISCSI_BOOT_INI_INDEX:
str += sprintf(str, "%d\n", initiator->hdr.index);
break;
- case ibft_init_flags:
+ case ISCSI_BOOT_INI_FLAGS:
str += sprintf(str, "%d\n", initiator->hdr.flags);
break;
- case ibft_init_isns_server:
+ case ISCSI_BOOT_INI_ISNS_SERVER:
str += sprintf_ipaddr(str, initiator->isns_server);
break;
- case ibft_init_slp_server:
+ case ISCSI_BOOT_INI_SLP_SERVER:
str += sprintf_ipaddr(str, initiator->slp_server);
break;
- case ibft_init_pri_radius_server:
+ case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->pri_radius_server);
break;
- case ibft_init_sec_radius_server:
+ case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
str += sprintf_ipaddr(str, initiator->sec_radius_server);
break;
- case ibft_init_initiator_name:
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
str += sprintf_string(str, initiator->initiator_name_len,
(char *)ibft_loc +
initiator->initiator_name_off);
@@ -373,10 +282,9 @@ static ssize_t ibft_attr_show_initiator(struct ibft_kobject *entry,
return str - buf;
}
-static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_nic(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_nic *nic = entry->nic;
void *ibft_loc = entry->header;
char *str = buf;
@@ -385,42 +293,42 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
if (!nic)
return 0;
- switch (attr->type) {
- case ibft_eth_index:
+ switch (type) {
+ case ISCSI_BOOT_ETH_INDEX:
str += sprintf(str, "%d\n", nic->hdr.index);
break;
- case ibft_eth_flags:
+ case ISCSI_BOOT_ETH_FLAGS:
str += sprintf(str, "%d\n", nic->hdr.flags);
break;
- case ibft_eth_ip_addr:
+ case ISCSI_BOOT_ETH_IP_ADDR:
str += sprintf_ipaddr(str, nic->ip_addr);
break;
- case ibft_eth_subnet_mask:
+ case ISCSI_BOOT_ETH_SUBNET_MASK:
val = cpu_to_be32(~((1 << (32-nic->subnet_mask_prefix))-1));
str += sprintf(str, "%pI4", &val);
break;
- case ibft_eth_origin:
+ case ISCSI_BOOT_ETH_ORIGIN:
str += sprintf(str, "%d\n", nic->origin);
break;
- case ibft_eth_gateway:
+ case ISCSI_BOOT_ETH_GATEWAY:
str += sprintf_ipaddr(str, nic->gateway);
break;
- case ibft_eth_primary_dns:
+ case ISCSI_BOOT_ETH_PRIMARY_DNS:
str += sprintf_ipaddr(str, nic->primary_dns);
break;
- case ibft_eth_secondary_dns:
+ case ISCSI_BOOT_ETH_SECONDARY_DNS:
str += sprintf_ipaddr(str, nic->secondary_dns);
break;
- case ibft_eth_dhcp:
+ case ISCSI_BOOT_ETH_DHCP:
str += sprintf_ipaddr(str, nic->dhcp);
break;
- case ibft_eth_vlan:
+ case ISCSI_BOOT_ETH_VLAN:
str += sprintf(str, "%d\n", nic->vlan);
break;
- case ibft_eth_mac:
+ case ISCSI_BOOT_ETH_MAC:
str += sprintf(str, "%pM\n", nic->mac);
break;
- case ibft_eth_hostname:
+ case ISCSI_BOOT_ETH_HOSTNAME:
str += sprintf_string(str, nic->hostname_len,
(char *)ibft_loc + nic->hostname_off);
break;
@@ -431,10 +339,9 @@ static ssize_t ibft_attr_show_nic(struct ibft_kobject *entry,
return str - buf;
};
-static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
- struct ibft_attribute *attr,
- char *buf)
+static ssize_t ibft_attr_show_target(void *data, int type, char *buf)
{
+ struct ibft_kobject *entry = data;
struct ibft_tgt *tgt = entry->tgt;
void *ibft_loc = entry->header;
char *str = buf;
@@ -443,48 +350,48 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
if (!tgt)
return 0;
- switch (attr->type) {
- case ibft_tgt_index:
+ switch (type) {
+ case ISCSI_BOOT_TGT_INDEX:
str += sprintf(str, "%d\n", tgt->hdr.index);
break;
- case ibft_tgt_flags:
+ case ISCSI_BOOT_TGT_FLAGS:
str += sprintf(str, "%d\n", tgt->hdr.flags);
break;
- case ibft_tgt_ip_addr:
+ case ISCSI_BOOT_TGT_IP_ADDR:
str += sprintf_ipaddr(str, tgt->ip_addr);
break;
- case ibft_tgt_port:
+ case ISCSI_BOOT_TGT_PORT:
str += sprintf(str, "%d\n", tgt->port);
break;
- case ibft_tgt_lun:
+ case ISCSI_BOOT_TGT_LUN:
for (i = 0; i < 8; i++)
str += sprintf(str, "%x", (u8)tgt->lun[i]);
str += sprintf(str, "\n");
break;
- case ibft_tgt_nic_assoc:
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
str += sprintf(str, "%d\n", tgt->nic_assoc);
break;
- case ibft_tgt_chap_type:
+ case ISCSI_BOOT_TGT_CHAP_TYPE:
str += sprintf(str, "%d\n", tgt->chap_type);
break;
- case ibft_tgt_name:
+ case ISCSI_BOOT_TGT_NAME:
str += sprintf_string(str, tgt->tgt_name_len,
(char *)ibft_loc + tgt->tgt_name_off);
break;
- case ibft_tgt_chap_name:
+ case ISCSI_BOOT_TGT_CHAP_NAME:
str += sprintf_string(str, tgt->chap_name_len,
(char *)ibft_loc + tgt->chap_name_off);
break;
- case ibft_tgt_chap_secret:
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
str += sprintf_string(str, tgt->chap_secret_len,
(char *)ibft_loc + tgt->chap_secret_off);
break;
- case ibft_tgt_rev_chap_name:
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
str += sprintf_string(str, tgt->rev_chap_name_len,
(char *)ibft_loc +
tgt->rev_chap_name_off);
break;
- case ibft_tgt_rev_chap_secret:
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
str += sprintf_string(str, tgt->rev_chap_secret_len,
(char *)ibft_loc +
tgt->rev_chap_secret_off);
@@ -496,52 +403,19 @@ static ssize_t ibft_attr_show_target(struct ibft_kobject *entry,
return str - buf;
}
-/*
- * The routine called for all sysfs attributes.
- */
-static ssize_t ibft_show_attribute(struct kobject *kobj,
- struct attribute *attr,
- char *buf)
-{
- struct ibft_kobject *dev =
- container_of(kobj, struct ibft_kobject, kobj);
- struct ibft_attribute *ibft_attr =
- container_of(attr, struct ibft_attribute, attr);
- ssize_t ret = -EIO;
- char *str = buf;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (ibft_attr->show)
- ret = ibft_attr->show(dev, ibft_attr, str);
-
- return ret;
-}
-
-static const struct sysfs_ops ibft_attr_ops = {
- .show = ibft_show_attribute,
-};
-
-static struct kobj_type ibft_ktype = {
- .release = ibft_release,
- .sysfs_ops = &ibft_attr_ops,
-};
-
-static struct kset *ibft_kset;
-
static int __init ibft_check_device(void)
{
int len;
u8 *pos;
u8 csum = 0;
- len = ibft_addr->length;
+ len = ibft_addr->header.length;
/* Sanity checking of iBFT. */
- if (ibft_addr->revision != 1) {
+ if (ibft_addr->header.revision != 1) {
printk(KERN_ERR "iBFT module supports only revision 1, " \
- "while this is %d.\n", ibft_addr->revision);
+ "while this is %d.\n",
+ ibft_addr->header.revision);
return -ENOENT;
}
for (pos = (u8 *)ibft_addr; pos < (u8 *)ibft_addr + len; pos++)
@@ -556,12 +430,149 @@ static int __init ibft_check_device(void)
}
/*
+ * Helper routiners to check to determine if the entry is valid
+ * in the proper iBFT structure.
+ */
+static mode_t ibft_check_nic_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_nic *nic = entry->nic;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_ETH_INDEX:
+ case ISCSI_BOOT_ETH_FLAGS:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_IP_ADDR:
+ if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_SUBNET_MASK:
+ if (nic->subnet_mask_prefix)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_ORIGIN:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_GATEWAY:
+ if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_PRIMARY_DNS:
+ if (memcmp(nic->primary_dns, nulls,
+ sizeof(nic->primary_dns)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_SECONDARY_DNS:
+ if (memcmp(nic->secondary_dns, nulls,
+ sizeof(nic->secondary_dns)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_DHCP:
+ if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_VLAN:
+ case ISCSI_BOOT_ETH_MAC:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_ETH_HOSTNAME:
+ if (nic->hostname_off)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static mode_t __init ibft_check_tgt_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_tgt *tgt = entry->tgt;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_TGT_INDEX:
+ case ISCSI_BOOT_TGT_FLAGS:
+ case ISCSI_BOOT_TGT_IP_ADDR:
+ case ISCSI_BOOT_TGT_PORT:
+ case ISCSI_BOOT_TGT_LUN:
+ case ISCSI_BOOT_TGT_NIC_ASSOC:
+ case ISCSI_BOOT_TGT_CHAP_TYPE:
+ rc = S_IRUGO;
+ case ISCSI_BOOT_TGT_NAME:
+ if (tgt->tgt_name_len)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_TGT_CHAP_NAME:
+ case ISCSI_BOOT_TGT_CHAP_SECRET:
+ if (tgt->chap_name_len)
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_TGT_REV_CHAP_NAME:
+ case ISCSI_BOOT_TGT_REV_CHAP_SECRET:
+ if (tgt->rev_chap_name_len)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static mode_t __init ibft_check_initiator_for(void *data, int type)
+{
+ struct ibft_kobject *entry = data;
+ struct ibft_initiator *init = entry->initiator;
+ mode_t rc = 0;
+
+ switch (type) {
+ case ISCSI_BOOT_INI_INDEX:
+ case ISCSI_BOOT_INI_FLAGS:
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_ISNS_SERVER:
+ if (memcmp(init->isns_server, nulls,
+ sizeof(init->isns_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_SLP_SERVER:
+ if (memcmp(init->slp_server, nulls,
+ sizeof(init->slp_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_PRI_RADIUS_SERVER:
+ if (memcmp(init->pri_radius_server, nulls,
+ sizeof(init->pri_radius_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_SEC_RADIUS_SERVER:
+ if (memcmp(init->sec_radius_server, nulls,
+ sizeof(init->sec_radius_server)))
+ rc = S_IRUGO;
+ break;
+ case ISCSI_BOOT_INI_INITIATOR_NAME:
+ if (init->initiator_name_len)
+ rc = S_IRUGO;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/*
* Helper function for ibft_register_kobjects.
*/
-static int __init ibft_create_kobject(struct ibft_table_header *header,
- struct ibft_hdr *hdr,
- struct list_head *list)
+static int __init ibft_create_kobject(struct acpi_table_ibft *header,
+ struct ibft_hdr *hdr)
{
+ struct iscsi_boot_kobj *boot_kobj = NULL;
struct ibft_kobject *ibft_kobj = NULL;
struct ibft_nic *nic = (struct ibft_nic *)hdr;
struct pci_dev *pci_dev;
@@ -578,14 +589,47 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
case id_initiator:
rc = ibft_verify_hdr("initiator", hdr, id_initiator,
sizeof(*ibft_kobj->initiator));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_initiator(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_initiator,
+ ibft_check_initiator_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_nic:
rc = ibft_verify_hdr("ethernet", hdr, id_nic,
sizeof(*ibft_kobj->nic));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_ethernet(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_nic,
+ ibft_check_nic_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_target:
rc = ibft_verify_hdr("target", hdr, id_target,
sizeof(*ibft_kobj->tgt));
+ if (rc)
+ break;
+
+ boot_kobj = iscsi_boot_create_target(boot_kset, hdr->index,
+ ibft_kobj,
+ ibft_attr_show_target,
+ ibft_check_tgt_for);
+ if (!boot_kobj) {
+ rc = -ENOMEM;
+ goto free_ibft_obj;
+ }
break;
case id_reserved:
case id_control:
@@ -596,29 +640,17 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
default:
printk(KERN_ERR "iBFT has unknown structure type (%d). " \
"Report this bug to %.6s!\n", hdr->id,
- header->oem_id);
+ header->header.oem_id);
rc = 1;
break;
}
if (rc) {
/* Skip adding this kobject, but exit with non-fatal error. */
- kfree(ibft_kobj);
- goto out_invalid_struct;
+ rc = 0;
+ goto free_ibft_obj;
}
- ibft_kobj->kobj.kset = ibft_kset;
-
- rc = kobject_init_and_add(&ibft_kobj->kobj, &ibft_ktype,
- NULL, ibft_id_names[hdr->id], hdr->index);
-
- if (rc) {
- kfree(ibft_kobj);
- goto out;
- }
-
- kobject_uevent(&ibft_kobj->kobj, KOBJ_ADD);
-
if (hdr->id == id_nic) {
/*
* We don't search for the device in other domains than
@@ -629,19 +661,16 @@ static int __init ibft_create_kobject(struct ibft_table_header *header,
pci_dev = pci_get_bus_and_slot((nic->pci_bdf & 0xff00) >> 8,
(nic->pci_bdf & 0xff));
if (pci_dev) {
- rc = sysfs_create_link(&ibft_kobj->kobj,
+ rc = sysfs_create_link(&boot_kobj->kobj,
&pci_dev->dev.kobj, "device");
pci_dev_put(pci_dev);
}
}
+ return 0;
- /* Nothing broke so lets add it to the list. */
- list_add_tail(&ibft_kobj->node, list);
-out:
+free_ibft_obj:
+ kfree(ibft_kobj);
return rc;
-out_invalid_struct:
- /* Unsupported structs are skipped. */
- return 0;
}
/*
@@ -649,8 +678,7 @@ out_invalid_struct:
* found add them on the passed-in list. We do not support the other
* fields at this point, so they are skipped.
*/
-static int __init ibft_register_kobjects(struct ibft_table_header *header,
- struct list_head *list)
+static int __init ibft_register_kobjects(struct acpi_table_ibft *header)
{
struct ibft_control *control = NULL;
void *ptr, *end;
@@ -660,7 +688,7 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
control = (void *)header + sizeof(*header);
end = (void *)control + control->hdr.length;
- eot_offset = (void *)header + header->length - (void *)control;
+ eot_offset = (void *)header + header->header.length - (void *)control;
rc = ibft_verify_hdr("control", (struct ibft_hdr *)control, id_control,
sizeof(*control));
@@ -672,10 +700,10 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
}
for (ptr = &control->initiator_off; ptr < end; ptr += sizeof(u16)) {
offset = *(u16 *)ptr;
- if (offset && offset < header->length && offset < eot_offset) {
+ if (offset && offset < header->header.length &&
+ offset < eot_offset) {
rc = ibft_create_kobject(header,
- (void *)header + offset,
- list);
+ (void *)header + offset);
if (rc)
break;
}
@@ -684,240 +712,28 @@ static int __init ibft_register_kobjects(struct ibft_table_header *header,
return rc;
}
-static void ibft_unregister(struct list_head *attr_list,
- struct list_head *kobj_list)
+static void ibft_unregister(void)
{
- struct ibft_kobject *data = NULL, *n;
- struct ibft_attribute *attr = NULL, *m;
-
- list_for_each_entry_safe(attr, m, attr_list, node) {
- sysfs_remove_file(attr->kobj, &attr->attr);
- list_del(&attr->node);
- kfree(attr);
+ struct iscsi_boot_kobj *boot_kobj, *tmp_kobj;
+ struct ibft_kobject *ibft_kobj;
+
+ list_for_each_entry_safe(boot_kobj, tmp_kobj,
+ &boot_kset->kobj_list, list) {
+ ibft_kobj = boot_kobj->data;
+ if (ibft_kobj->hdr->id == id_nic)
+ sysfs_remove_link(&boot_kobj->kobj, "device");
};
- list_del_init(attr_list);
-
- list_for_each_entry_safe(data, n, kobj_list, node) {
- list_del(&data->node);
- if (data->hdr->id == id_nic)
- sysfs_remove_link(&data->kobj, "device");
- kobject_put(&data->kobj);
- };
- list_del_init(kobj_list);
}
-static int __init ibft_create_attribute(struct ibft_kobject *kobj_data,
- int type,
- const char *name,
- ssize_t (*show)(struct ibft_kobject *,
- struct ibft_attribute*,
- char *buf),
- struct list_head *list)
+static void ibft_cleanup(void)
{
- struct ibft_attribute *attr = NULL;
- struct ibft_hdr *hdr = kobj_data->hdr;
-
- attr = kmalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr)
- return -ENOMEM;
-
- attr->attr.name = name;
- attr->attr.mode = S_IRUSR;
-
- attr->hdr = hdr;
- attr->show = show;
- attr->kobj = &kobj_data->kobj;
- attr->type = type;
-
- list_add_tail(&attr->node, list);
-
- return 0;
-}
-
-/*
- * Helper routiners to check to determine if the entry is valid
- * in the proper iBFT structure.
- */
-static int __init ibft_check_nic_for(struct ibft_nic *nic, int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_eth_index:
- case ibft_eth_flags:
- rc = 1;
- break;
- case ibft_eth_ip_addr:
- if (memcmp(nic->ip_addr, nulls, sizeof(nic->ip_addr)))
- rc = 1;
- break;
- case ibft_eth_subnet_mask:
- if (nic->subnet_mask_prefix)
- rc = 1;
- break;
- case ibft_eth_origin:
- rc = 1;
- break;
- case ibft_eth_gateway:
- if (memcmp(nic->gateway, nulls, sizeof(nic->gateway)))
- rc = 1;
- break;
- case ibft_eth_primary_dns:
- if (memcmp(nic->primary_dns, nulls,
- sizeof(nic->primary_dns)))
- rc = 1;
- break;
- case ibft_eth_secondary_dns:
- if (memcmp(nic->secondary_dns, nulls,
- sizeof(nic->secondary_dns)))
- rc = 1;
- break;
- case ibft_eth_dhcp:
- if (memcmp(nic->dhcp, nulls, sizeof(nic->dhcp)))
- rc = 1;
- break;
- case ibft_eth_vlan:
- case ibft_eth_mac:
- rc = 1;
- break;
- case ibft_eth_hostname:
- if (nic->hostname_off)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
+ ibft_unregister();
+ iscsi_boot_destroy_kset(boot_kset);
}
-static int __init ibft_check_tgt_for(struct ibft_tgt *tgt, int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_tgt_index:
- case ibft_tgt_flags:
- case ibft_tgt_ip_addr:
- case ibft_tgt_port:
- case ibft_tgt_lun:
- case ibft_tgt_nic_assoc:
- case ibft_tgt_chap_type:
- rc = 1;
- case ibft_tgt_name:
- if (tgt->tgt_name_len)
- rc = 1;
- break;
- case ibft_tgt_chap_name:
- case ibft_tgt_chap_secret:
- if (tgt->chap_name_len)
- rc = 1;
- break;
- case ibft_tgt_rev_chap_name:
- case ibft_tgt_rev_chap_secret:
- if (tgt->rev_chap_name_len)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-static int __init ibft_check_initiator_for(struct ibft_initiator *init,
- int entry)
-{
- int rc = 0;
-
- switch (entry) {
- case ibft_init_index:
- case ibft_init_flags:
- rc = 1;
- break;
- case ibft_init_isns_server:
- if (memcmp(init->isns_server, nulls,
- sizeof(init->isns_server)))
- rc = 1;
- break;
- case ibft_init_slp_server:
- if (memcmp(init->slp_server, nulls,
- sizeof(init->slp_server)))
- rc = 1;
- break;
- case ibft_init_pri_radius_server:
- if (memcmp(init->pri_radius_server, nulls,
- sizeof(init->pri_radius_server)))
- rc = 1;
- break;
- case ibft_init_sec_radius_server:
- if (memcmp(init->sec_radius_server, nulls,
- sizeof(init->sec_radius_server)))
- rc = 1;
- break;
- case ibft_init_initiator_name:
- if (init->initiator_name_len)
- rc = 1;
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-/*
- * Register the attributes for all of the kobjects.
- */
-static int __init ibft_register_attributes(struct list_head *kobject_list,
- struct list_head *attr_list)
+static void __exit ibft_exit(void)
{
- int rc = 0, i = 0;
- struct ibft_kobject *data = NULL;
- struct ibft_attribute *attr = NULL, *m;
-
- list_for_each_entry(data, kobject_list, node) {
- switch (data->hdr->id) {
- case id_nic:
- for (i = 0; i < ibft_eth_end_marker && !rc; i++)
- if (ibft_check_nic_for(data->nic, i))
- rc = ibft_create_attribute(data, i,
- ibft_eth_properties[i],
- ibft_attr_show_nic, attr_list);
- break;
- case id_target:
- for (i = 0; i < ibft_tgt_end_marker && !rc; i++)
- if (ibft_check_tgt_for(data->tgt, i))
- rc = ibft_create_attribute(data, i,
- ibft_tgt_properties[i],
- ibft_attr_show_target,
- attr_list);
- break;
- case id_initiator:
- for (i = 0; i < ibft_init_end_marker && !rc; i++)
- if (ibft_check_initiator_for(
- data->initiator, i))
- rc = ibft_create_attribute(data, i,
- ibft_initiator_properties[i],
- ibft_attr_show_initiator,
- attr_list);
- break;
- default:
- break;
- }
- if (rc)
- break;
- }
- list_for_each_entry_safe(attr, m, attr_list, node) {
- rc = sysfs_create_file(attr->kobj, &attr->attr);
- if (rc) {
- list_del(&attr->node);
- kfree(attr);
- break;
- }
- }
-
- return rc;
+ ibft_cleanup();
}
/*
@@ -927,26 +743,20 @@ static int __init ibft_init(void)
{
int rc = 0;
- ibft_kset = kset_create_and_add("ibft", NULL, firmware_kobj);
- if (!ibft_kset)
- return -ENOMEM;
-
if (ibft_addr) {
printk(KERN_INFO "iBFT detected at 0x%llx.\n",
(u64)isa_virt_to_bus(ibft_addr));
rc = ibft_check_device();
if (rc)
- goto out_firmware_unregister;
+ return rc;
- /* Scan the IBFT for data and register the kobjects. */
- rc = ibft_register_kobjects(ibft_addr, &ibft_kobject_list);
- if (rc)
- goto out_free;
+ boot_kset = iscsi_boot_create_kset("ibft");
+ if (!boot_kset)
+ return -ENOMEM;
- /* Register the attributes */
- rc = ibft_register_attributes(&ibft_kobject_list,
- &ibft_attr_list);
+ /* Scan the IBFT for data and register the kobjects. */
+ rc = ibft_register_kobjects(ibft_addr);
if (rc)
goto out_free;
} else
@@ -955,17 +765,9 @@ static int __init ibft_init(void)
return 0;
out_free:
- ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
-out_firmware_unregister:
- kset_unregister(ibft_kset);
+ ibft_cleanup();
return rc;
}
-static void __exit ibft_exit(void)
-{
- ibft_unregister(&ibft_attr_list, &ibft_kobject_list);
- kset_unregister(ibft_kset);
-}
-
module_init(ibft_init);
module_exit(ibft_exit);
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d6470ef36e4a..2192456dfd68 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Red Hat, Inc.
+ * Copyright 2007-2010 Red Hat, Inc.
* by Peter Jones <pjones@redhat.com>
* Copyright 2007 IBM, Inc.
* by Konrad Rzeszutek <konradr@linux.vnet.ibm.com>
@@ -22,6 +22,7 @@
#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/device.h>
+#include <linux/efi.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/limits.h>
@@ -30,13 +31,15 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/iscsi_ibft.h>
#include <asm/mmzone.h>
/*
* Physical location of iSCSI Boot Format Table.
*/
-struct ibft_table_header *ibft_addr;
+struct acpi_table_ibft *ibft_addr;
EXPORT_SYMBOL_GPL(ibft_addr);
#define IBFT_SIGN "iBFT"
@@ -46,19 +49,20 @@ EXPORT_SYMBOL_GPL(ibft_addr);
#define VGA_MEM 0xA0000 /* VGA buffer */
#define VGA_SIZE 0x20000 /* 128kB */
+#ifdef CONFIG_ACPI
+static int __init acpi_find_ibft(struct acpi_table_header *header)
+{
+ ibft_addr = (struct acpi_table_ibft *)header;
+ return 0;
+}
+#endif /* CONFIG_ACPI */
-/*
- * Routine used to find the iSCSI Boot Format Table. The logical
- * kernel address is set in the ibft_addr global variable.
- */
-unsigned long __init find_ibft_region(unsigned long *sizep)
+static int __init find_ibft_in_mem(void)
{
unsigned long pos;
unsigned int len = 0;
void *virt;
- ibft_addr = NULL;
-
for (pos = IBFT_START; pos < IBFT_END; pos += 16) {
/* The table can't be inside the VGA BIOS reserved space,
* so skip that area */
@@ -72,14 +76,42 @@ unsigned long __init find_ibft_region(unsigned long *sizep)
/* if the length of the table extends past 1M,
* the table cannot be valid. */
if (pos + len <= (IBFT_END-1)) {
- ibft_addr = (struct ibft_table_header *)virt;
+ ibft_addr = (struct acpi_table_ibft *)virt;
break;
}
}
}
+ return len;
+}
+/*
+ * Routine used to find the iSCSI Boot Format Table. The logical
+ * kernel address is set in the ibft_addr global variable.
+ */
+unsigned long __init find_ibft_region(unsigned long *sizep)
+{
+
+ ibft_addr = NULL;
+
+#ifdef CONFIG_ACPI
+ /*
+ * One spec says "IBFT", the other says "iBFT". We have to check
+ * for both.
+ */
+ if (!ibft_addr)
+ acpi_table_parse(ACPI_SIG_IBFT, acpi_find_ibft);
+ if (!ibft_addr)
+ acpi_table_parse(IBFT_SIGN, acpi_find_ibft);
+#endif /* CONFIG_ACPI */
+
+ /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will
+ * only use ACPI for this */
+
+ if (!ibft_addr && !efi_enabled)
+ find_ibft_in_mem();
+
if (ibft_addr) {
- *sizep = PAGE_ALIGN(len);
- return pos;
+ *sizep = PAGE_ALIGN(ibft_addr->header.length);
+ return (u64)isa_virt_to_bus(ibft_addr);
}
*sizep = 0;
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 764401951041..9b2a54117c91 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -860,19 +860,24 @@ static void output_poll_execute(struct slow_work *work)
}
}
-void drm_kms_helper_poll_init(struct drm_device *dev)
+void drm_kms_helper_poll_disable(struct drm_device *dev)
+{
+ if (!dev->mode_config.poll_enabled)
+ return;
+ delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
+}
+EXPORT_SYMBOL(drm_kms_helper_poll_disable);
+
+void drm_kms_helper_poll_enable(struct drm_device *dev)
{
- struct drm_connector *connector;
bool poll = false;
+ struct drm_connector *connector;
int ret;
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->polled)
poll = true;
}
- slow_work_register_user(THIS_MODULE);
- delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
- &output_poll_ops);
if (poll) {
ret = delayed_slow_work_enqueue(&dev->mode_config.output_poll_slow_work, DRM_OUTPUT_POLL_PERIOD);
@@ -880,11 +885,22 @@ void drm_kms_helper_poll_init(struct drm_device *dev)
DRM_ERROR("delayed enqueue failed %d\n", ret);
}
}
+EXPORT_SYMBOL(drm_kms_helper_poll_enable);
+
+void drm_kms_helper_poll_init(struct drm_device *dev)
+{
+ slow_work_register_user(THIS_MODULE);
+ delayed_slow_work_init(&dev->mode_config.output_poll_slow_work,
+ &output_poll_ops);
+ dev->mode_config.poll_enabled = true;
+
+ drm_kms_helper_poll_enable(dev);
+}
EXPORT_SYMBOL(drm_kms_helper_poll_init);
void drm_kms_helper_poll_fini(struct drm_device *dev)
{
- delayed_slow_work_cancel(&dev->mode_config.output_poll_slow_work);
+ drm_kms_helper_poll_disable(dev);
slow_work_unregister_user(THIS_MODULE);
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 95639017bdbe..da78f2c0d909 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -22,6 +22,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
intel_fb.o \
intel_tv.o \
intel_dvo.o \
+ intel_ringbuffer.o \
intel_overlay.o \
dvo_ch7xxx.o \
dvo_ch7017.o \
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 322070c0c631..52510ad8b25d 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -77,7 +77,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data)
case ACTIVE_LIST:
seq_printf(m, "Active:\n");
lock = &dev_priv->mm.active_list_lock;
- head = &dev_priv->mm.active_list;
+ head = &dev_priv->render_ring.active_list;
break;
case INACTIVE_LIST:
seq_printf(m, "Inactive:\n");
@@ -129,7 +129,8 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
struct drm_i915_gem_request *gem_request;
seq_printf(m, "Request:\n");
- list_for_each_entry(gem_request, &dev_priv->mm.request_list, list) {
+ list_for_each_entry(gem_request, &dev_priv->render_ring.request_list,
+ list) {
seq_printf(m, " %d @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
@@ -143,9 +144,9 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->hw_status_page != NULL) {
+ if (dev_priv->render_ring.status_page.page_addr != NULL) {
seq_printf(m, "Current sequence: %d\n",
- i915_get_gem_seqno(dev));
+ i915_get_gem_seqno(dev, &dev_priv->render_ring));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
@@ -195,9 +196,9 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
}
seq_printf(m, "Interrupts received: %d\n",
atomic_read(&dev_priv->irq_received));
- if (dev_priv->hw_status_page != NULL) {
+ if (dev_priv->render_ring.status_page.page_addr != NULL) {
seq_printf(m, "Current sequence: %d\n",
- i915_get_gem_seqno(dev));
+ i915_get_gem_seqno(dev, &dev_priv->render_ring));
} else {
seq_printf(m, "Current sequence: hws uninitialized\n");
}
@@ -251,7 +252,7 @@ static int i915_hws_info(struct seq_file *m, void *data)
int i;
volatile u32 *hws;
- hws = (volatile u32 *)dev_priv->hw_status_page;
+ hws = (volatile u32 *)dev_priv->render_ring.status_page.page_addr;
if (hws == NULL)
return 0;
@@ -287,7 +288,8 @@ static int i915_batchbuffer_info(struct seq_file *m, void *data)
spin_lock(&dev_priv->mm.active_list_lock);
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
+ list_for_each_entry(obj_priv, &dev_priv->render_ring.active_list,
+ list) {
obj = &obj_priv->base;
if (obj->read_domains & I915_GEM_DOMAIN_COMMAND) {
ret = i915_gem_object_get_pages(obj, 0);
@@ -317,14 +319,14 @@ static int i915_ringbuffer_data(struct seq_file *m, void *data)
u8 *virt;
uint32_t *ptr, off;
- if (!dev_priv->ring.ring_obj) {
+ if (!dev_priv->render_ring.gem_object) {
seq_printf(m, "No ringbuffer setup\n");
return 0;
}
- virt = dev_priv->ring.virtual_start;
+ virt = dev_priv->render_ring.virtual_start;
- for (off = 0; off < dev_priv->ring.Size; off += 4) {
+ for (off = 0; off < dev_priv->render_ring.size; off += 4) {
ptr = (uint32_t *)(virt + off);
seq_printf(m, "%08x : %08x\n", off, *ptr);
}
@@ -344,7 +346,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data)
seq_printf(m, "RingHead : %08x\n", head);
seq_printf(m, "RingTail : %08x\n", tail);
- seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size);
+ seq_printf(m, "RingSize : %08lx\n", dev_priv->render_ring.size);
seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD));
return 0;
@@ -489,11 +491,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u16 rgvswctl = I915_READ16(MEMSWCTL);
+ u16 rgvstat = I915_READ16(MEMSTAT_ILK);
- seq_printf(m, "Last command: 0x%01x\n", (rgvswctl >> 13) & 0x3);
- seq_printf(m, "Command status: %d\n", (rgvswctl >> 12) & 1);
- seq_printf(m, "P%d DELAY 0x%02x\n", (rgvswctl >> 8) & 0xf,
- rgvswctl & 0x3f);
+ seq_printf(m, "Requested P-state: %d\n", (rgvswctl >> 8) & 0xf);
+ seq_printf(m, "Requested VID: %d\n", rgvswctl & 0x3f);
+ seq_printf(m, "Current VID: %d\n", (rgvstat & MEMSTAT_VID_MASK) >>
+ MEMSTAT_VID_SHIFT);
+ seq_printf(m, "Current P-state: %d\n",
+ (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT);
return 0;
}
@@ -508,7 +513,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused)
for (i = 0; i < 16; i++) {
delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
- seq_printf(m, "P%02dVIDFREQ: 0x%08x\n", i, delayfreq);
+ seq_printf(m, "P%02dVIDFREQ: 0x%08x (VID: %d)\n", i, delayfreq,
+ (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT);
}
return 0;
@@ -541,6 +547,8 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
u32 rgvmodectl = I915_READ(MEMMODECTL);
+ u32 rstdbyctl = I915_READ(MCHBAR_RENDER_STANDBY);
+ u16 crstandvid = I915_READ16(CRSTANDVID);
seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
"yes" : "no");
@@ -555,9 +563,13 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
rgvmodectl & MEMMODE_RCLK_GATE ? "yes" : "no");
seq_printf(m, "Starting frequency: P%d\n",
(rgvmodectl & MEMMODE_FSTART_MASK) >> MEMMODE_FSTART_SHIFT);
- seq_printf(m, "Max frequency: P%d\n",
+ seq_printf(m, "Max P-state: P%d\n",
(rgvmodectl & MEMMODE_FMAX_MASK) >> MEMMODE_FMAX_SHIFT);
- seq_printf(m, "Min frequency: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
+ seq_printf(m, "Min P-state: P%d\n", (rgvmodectl & MEMMODE_FMIN_MASK));
+ seq_printf(m, "RS1 VID: %d\n", (crstandvid & 0x3f));
+ seq_printf(m, "RS2 VID: %d\n", ((crstandvid >> 8) & 0x3f));
+ seq_printf(m, "Render standby enabled: %s\n",
+ (rstdbyctl & RCX_SW_EXIT) ? "no" : "yes");
return 0;
}
@@ -621,6 +633,36 @@ static int i915_sr_status(struct seq_file *m, void *unused)
return 0;
}
+static int i915_emon_status(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ unsigned long temp, chipset, gfx;
+
+ temp = i915_mch_val(dev_priv);
+ chipset = i915_chipset_val(dev_priv);
+ gfx = i915_gfx_val(dev_priv);
+
+ seq_printf(m, "GMCH temp: %ld\n", temp);
+ seq_printf(m, "Chipset power: %ld\n", chipset);
+ seq_printf(m, "GFX power: %ld\n", gfx);
+ seq_printf(m, "Total power: %ld\n", chipset + gfx);
+
+ return 0;
+}
+
+static int i915_gfxec(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *) m->private;
+ struct drm_device *dev = node->minor->dev;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+
+ seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4));
+
+ return 0;
+}
+
static int
i915_wedged_open(struct inode *inode,
struct file *filp)
@@ -743,6 +785,8 @@ static struct drm_info_list i915_debugfs_list[] = {
{"i915_delayfreq_table", i915_delayfreq_table, 0},
{"i915_inttoext_table", i915_inttoext_table, 0},
{"i915_drpc_info", i915_drpc_info, 0},
+ {"i915_emon_status", i915_emon_status, 0},
+ {"i915_gfxec", i915_gfxec, 0},
{"i915_fbc_status", i915_fbc_status, 0},
{"i915_sr_status", i915_sr_status, 0},
};
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 2a6b5de5ae5d..b2ebf02e4f8a 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -40,84 +40,6 @@
#include <linux/vga_switcheroo.h>
#include <linux/slab.h>
-/* Really want an OS-independent resettable timer. Would like to have
- * this loop run for (eg) 3 sec, but have the timer reset every time
- * the head pointer changes, so that EBUSY only happens if the ring
- * actually stalls for (eg) 3 seconds.
- */
-int i915_wait_ring(struct drm_device * dev, int n, const char *caller)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
- u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
- u32 last_acthd = I915_READ(acthd_reg);
- u32 acthd;
- u32 last_head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- int i;
-
- trace_i915_ring_wait_begin (dev);
-
- for (i = 0; i < 100000; i++) {
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- acthd = I915_READ(acthd_reg);
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
- if (ring->space >= n) {
- trace_i915_ring_wait_end (dev);
- return 0;
- }
-
- if (dev->primary->master) {
- struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- if (master_priv->sarea_priv)
- master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
- }
-
-
- if (ring->head != last_head)
- i = 0;
- if (acthd != last_acthd)
- i = 0;
-
- last_head = ring->head;
- last_acthd = acthd;
- msleep_interruptible(10);
-
- }
-
- trace_i915_ring_wait_end (dev);
- return -EBUSY;
-}
-
-/* As a ringbuffer is only allowed to wrap between instructions, fill
- * the tail with NOOPs.
- */
-int i915_wrap_ring(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- volatile unsigned int *virt;
- int rem;
-
- rem = dev_priv->ring.Size - dev_priv->ring.tail;
- if (dev_priv->ring.space < rem) {
- int ret = i915_wait_ring(dev, rem, __func__);
- if (ret)
- return ret;
- }
- dev_priv->ring.space -= rem;
-
- virt = (unsigned int *)
- (dev_priv->ring.virtual_start + dev_priv->ring.tail);
- rem /= 4;
- while (rem--)
- *virt++ = MI_NOOP;
-
- dev_priv->ring.tail = 0;
-
- return 0;
-}
-
/**
* Sets up the hardware status page for devices that need a physical address
* in the register.
@@ -133,10 +55,11 @@ static int i915_init_phys_hws(struct drm_device *dev)
DRM_ERROR("Can not allocate hardware status page\n");
return -ENOMEM;
}
- dev_priv->hw_status_page = dev_priv->status_page_dmah->vaddr;
+ dev_priv->render_ring.status_page.page_addr
+ = dev_priv->status_page_dmah->vaddr;
dev_priv->dma_status_page = dev_priv->status_page_dmah->busaddr;
- memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
+ memset(dev_priv->render_ring.status_page.page_addr, 0, PAGE_SIZE);
if (IS_I965G(dev))
dev_priv->dma_status_page |= (dev_priv->dma_status_page >> 28) &
@@ -159,8 +82,8 @@ static void i915_free_hws(struct drm_device *dev)
dev_priv->status_page_dmah = NULL;
}
- if (dev_priv->status_gfx_addr) {
- dev_priv->status_gfx_addr = 0;
+ if (dev_priv->render_ring.status_page.gfx_addr) {
+ dev_priv->render_ring.status_page.gfx_addr = 0;
drm_core_ioremapfree(&dev_priv->hws_map, dev);
}
@@ -172,7 +95,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv;
- drm_i915_ring_buffer_t *ring = &(dev_priv->ring);
+ struct intel_ring_buffer *ring = &dev_priv->render_ring;
/*
* We should never lose context on the ring with modesetting
@@ -185,7 +108,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
ring->space = ring->head - (ring->tail + 8);
if (ring->space < 0)
- ring->space += ring->Size;
+ ring->space += ring->size;
if (!dev->primary->master)
return;
@@ -205,12 +128,9 @@ static int i915_dma_cleanup(struct drm_device * dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
- if (dev_priv->ring.virtual_start) {
- drm_core_ioremapfree(&dev_priv->ring.map, dev);
- dev_priv->ring.virtual_start = NULL;
- dev_priv->ring.map.handle = NULL;
- dev_priv->ring.map.size = 0;
- }
+ intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
+ if (HAS_BSD(dev))
+ intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
/* Clear the HWS virtual address at teardown */
if (I915_NEED_GFX_HWS(dev))
@@ -233,24 +153,24 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
if (init->ring_size != 0) {
- if (dev_priv->ring.ring_obj != NULL) {
+ if (dev_priv->render_ring.gem_object != NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("Client tried to initialize ringbuffer in "
"GEM mode\n");
return -EINVAL;
}
- dev_priv->ring.Size = init->ring_size;
+ dev_priv->render_ring.size = init->ring_size;
- dev_priv->ring.map.offset = init->ring_start;
- dev_priv->ring.map.size = init->ring_size;
- dev_priv->ring.map.type = 0;
- dev_priv->ring.map.flags = 0;
- dev_priv->ring.map.mtrr = 0;
+ dev_priv->render_ring.map.offset = init->ring_start;
+ dev_priv->render_ring.map.size = init->ring_size;
+ dev_priv->render_ring.map.type = 0;
+ dev_priv->render_ring.map.flags = 0;
+ dev_priv->render_ring.map.mtrr = 0;
- drm_core_ioremap_wc(&dev_priv->ring.map, dev);
+ drm_core_ioremap_wc(&dev_priv->render_ring.map, dev);
- if (dev_priv->ring.map.handle == NULL) {
+ if (dev_priv->render_ring.map.handle == NULL) {
i915_dma_cleanup(dev);
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
@@ -258,7 +178,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
}
}
- dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+ dev_priv->render_ring.virtual_start = dev_priv->render_ring.map.handle;
dev_priv->cpp = init->cpp;
dev_priv->back_offset = init->back_offset;
@@ -278,26 +198,29 @@ static int i915_dma_resume(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct intel_ring_buffer *ring;
DRM_DEBUG_DRIVER("%s\n", __func__);
- if (dev_priv->ring.map.handle == NULL) {
+ ring = &dev_priv->render_ring;
+
+ if (ring->map.handle == NULL) {
DRM_ERROR("can not ioremap virtual address for"
" ring buffer\n");
return -ENOMEM;
}
/* Program Hardware Status Page */
- if (!dev_priv->hw_status_page) {
+ if (!ring->status_page.page_addr) {
DRM_ERROR("Can not find hardware status page\n");
return -EINVAL;
}
DRM_DEBUG_DRIVER("hw status page @ %p\n",
- dev_priv->hw_status_page);
-
- if (dev_priv->status_gfx_addr != 0)
- I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
+ ring->status_page.page_addr);
+ if (ring->status_page.gfx_addr != 0)
+ ring->setup_status_page(dev, ring);
else
I915_WRITE(HWS_PGA, dev_priv->dma_status_page);
+
DRM_DEBUG_DRIVER("Enabled hardware status page\n");
return 0;
@@ -407,9 +330,8 @@ static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
{
drm_i915_private_t *dev_priv = dev->dev_private;
int i;
- RING_LOCALS;
- if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
+ if ((dwords+1) * sizeof(int) >= dev_priv->render_ring.size - 8)
return -EINVAL;
BEGIN_LP_RING((dwords+1)&~1);
@@ -442,9 +364,7 @@ i915_emit_box(struct drm_device *dev,
struct drm_clip_rect *boxes,
int i, int DR1, int DR4)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_clip_rect box = boxes[i];
- RING_LOCALS;
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
DRM_ERROR("Bad box %d,%d..%d,%d\n",
@@ -481,7 +401,6 @@ static void i915_emit_breadcrumb(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- RING_LOCALS;
dev_priv->counter++;
if (dev_priv->counter > 0x7FFFFFFFUL)
@@ -535,10 +454,8 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
drm_i915_batchbuffer_t * batch,
struct drm_clip_rect *cliprects)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
int nbox = batch->num_cliprects;
int i = 0, count;
- RING_LOCALS;
if ((batch->start | batch->used) & 0x7) {
DRM_ERROR("alignment");
@@ -587,7 +504,6 @@ static int i915_dispatch_flip(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv =
dev->primary->master->driver_priv;
- RING_LOCALS;
if (!master_priv->sarea_priv)
return -EINVAL;
@@ -640,7 +556,8 @@ static int i915_quiescent(struct drm_device * dev)
drm_i915_private_t *dev_priv = dev->dev_private;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
+ return intel_wait_ring_buffer(dev, &dev_priv->render_ring,
+ dev_priv->render_ring.size - 8);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
@@ -827,6 +744,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
/* depends on GEM */
value = dev_priv->has_gem;
break;
+ case I915_PARAM_HAS_BSD:
+ value = HAS_BSD(dev);
+ break;
default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param);
@@ -882,6 +802,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
{
drm_i915_private_t *dev_priv = dev->dev_private;
drm_i915_hws_addr_t *hws = data;
+ struct intel_ring_buffer *ring = &dev_priv->render_ring;
if (!I915_NEED_GFX_HWS(dev))
return -EINVAL;
@@ -898,7 +819,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
DRM_DEBUG_DRIVER("set status page addr 0x%08x\n", (u32)hws->addr);
- dev_priv->status_gfx_addr = hws->addr & (0x1ffff<<12);
+ ring->status_page.gfx_addr = hws->addr & (0x1ffff<<12);
dev_priv->hws_map.offset = dev->agp->base + hws->addr;
dev_priv->hws_map.size = 4*1024;
@@ -909,19 +830,19 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
drm_core_ioremap_wc(&dev_priv->hws_map, dev);
if (dev_priv->hws_map.handle == NULL) {
i915_dma_cleanup(dev);
- dev_priv->status_gfx_addr = 0;
+ ring->status_page.gfx_addr = 0;
DRM_ERROR("can not ioremap virtual address for"
" G33 hw status page\n");
return -ENOMEM;
}
- dev_priv->hw_status_page = dev_priv->hws_map.handle;
+ ring->status_page.page_addr = dev_priv->hws_map.handle;
+ memset(ring->status_page.page_addr, 0, PAGE_SIZE);
+ I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
- memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
DRM_DEBUG_DRIVER("load hws HWS_PGA with gfx mem 0x%x\n",
- dev_priv->status_gfx_addr);
+ ring->status_page.gfx_addr);
DRM_DEBUG_DRIVER("load hws at %p\n",
- dev_priv->hw_status_page);
+ ring->status_page.page_addr);
return 0;
}
@@ -1399,12 +1320,14 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_
struct drm_device *dev = pci_get_drvdata(pdev);
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
- printk(KERN_INFO "i915: switched off\n");
+ printk(KERN_INFO "i915: switched on\n");
/* i915 resume handler doesn't set to D0 */
pci_set_power_state(dev->pdev, PCI_D0);
i915_resume(dev);
+ drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_ERR "i915: switched off\n");
+ drm_kms_helper_poll_disable(dev);
i915_suspend(dev, pmm);
}
}
@@ -1539,14 +1462,11 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
master->driver_priv = NULL;
}
-static void i915_get_mem_freq(struct drm_device *dev)
+static void i915_pineview_get_mem_freq(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 tmp;
- if (!IS_PINEVIEW(dev))
- return;
-
tmp = I915_READ(CLKCFG);
switch (tmp & CLKCFG_FSB_MASK) {
@@ -1575,8 +1495,525 @@ static void i915_get_mem_freq(struct drm_device *dev)
dev_priv->mem_freq = 800;
break;
}
+
+ /* detect pineview DDR3 setting */
+ tmp = I915_READ(CSHRDDR3CTL);
+ dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
+}
+
+static void i915_ironlake_get_mem_freq(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u16 ddrpll, csipll;
+
+ ddrpll = I915_READ16(DDRMPLL1);
+ csipll = I915_READ16(CSIPLL0);
+
+ switch (ddrpll & 0xff) {
+ case 0xc:
+ dev_priv->mem_freq = 800;
+ break;
+ case 0x10:
+ dev_priv->mem_freq = 1066;
+ break;
+ case 0x14:
+ dev_priv->mem_freq = 1333;
+ break;
+ case 0x18:
+ dev_priv->mem_freq = 1600;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("unknown memory frequency 0x%02x\n",
+ ddrpll & 0xff);
+ dev_priv->mem_freq = 0;
+ break;
+ }
+
+ dev_priv->r_t = dev_priv->mem_freq;
+
+ switch (csipll & 0x3ff) {
+ case 0x00c:
+ dev_priv->fsb_freq = 3200;
+ break;
+ case 0x00e:
+ dev_priv->fsb_freq = 3733;
+ break;
+ case 0x010:
+ dev_priv->fsb_freq = 4266;
+ break;
+ case 0x012:
+ dev_priv->fsb_freq = 4800;
+ break;
+ case 0x014:
+ dev_priv->fsb_freq = 5333;
+ break;
+ case 0x016:
+ dev_priv->fsb_freq = 5866;
+ break;
+ case 0x018:
+ dev_priv->fsb_freq = 6400;
+ break;
+ default:
+ DRM_DEBUG_DRIVER("unknown fsb frequency 0x%04x\n",
+ csipll & 0x3ff);
+ dev_priv->fsb_freq = 0;
+ break;
+ }
+
+ if (dev_priv->fsb_freq == 3200) {
+ dev_priv->c_m = 0;
+ } else if (dev_priv->fsb_freq > 3200 && dev_priv->fsb_freq <= 4800) {
+ dev_priv->c_m = 1;
+ } else {
+ dev_priv->c_m = 2;
+ }
+}
+
+struct v_table {
+ u8 vid;
+ unsigned long vd; /* in .1 mil */
+ unsigned long vm; /* in .1 mil */
+ u8 pvid;
+};
+
+static struct v_table v_table[] = {
+ { 0, 16125, 15000, 0x7f, },
+ { 1, 16000, 14875, 0x7e, },
+ { 2, 15875, 14750, 0x7d, },
+ { 3, 15750, 14625, 0x7c, },
+ { 4, 15625, 14500, 0x7b, },
+ { 5, 15500, 14375, 0x7a, },
+ { 6, 15375, 14250, 0x79, },
+ { 7, 15250, 14125, 0x78, },
+ { 8, 15125, 14000, 0x77, },
+ { 9, 15000, 13875, 0x76, },
+ { 10, 14875, 13750, 0x75, },
+ { 11, 14750, 13625, 0x74, },
+ { 12, 14625, 13500, 0x73, },
+ { 13, 14500, 13375, 0x72, },
+ { 14, 14375, 13250, 0x71, },
+ { 15, 14250, 13125, 0x70, },
+ { 16, 14125, 13000, 0x6f, },
+ { 17, 14000, 12875, 0x6e, },
+ { 18, 13875, 12750, 0x6d, },
+ { 19, 13750, 12625, 0x6c, },
+ { 20, 13625, 12500, 0x6b, },
+ { 21, 13500, 12375, 0x6a, },
+ { 22, 13375, 12250, 0x69, },
+ { 23, 13250, 12125, 0x68, },
+ { 24, 13125, 12000, 0x67, },
+ { 25, 13000, 11875, 0x66, },
+ { 26, 12875, 11750, 0x65, },
+ { 27, 12750, 11625, 0x64, },
+ { 28, 12625, 11500, 0x63, },
+ { 29, 12500, 11375, 0x62, },
+ { 30, 12375, 11250, 0x61, },
+ { 31, 12250, 11125, 0x60, },
+ { 32, 12125, 11000, 0x5f, },
+ { 33, 12000, 10875, 0x5e, },
+ { 34, 11875, 10750, 0x5d, },
+ { 35, 11750, 10625, 0x5c, },
+ { 36, 11625, 10500, 0x5b, },
+ { 37, 11500, 10375, 0x5a, },
+ { 38, 11375, 10250, 0x59, },
+ { 39, 11250, 10125, 0x58, },
+ { 40, 11125, 10000, 0x57, },
+ { 41, 11000, 9875, 0x56, },
+ { 42, 10875, 9750, 0x55, },
+ { 43, 10750, 9625, 0x54, },
+ { 44, 10625, 9500, 0x53, },
+ { 45, 10500, 9375, 0x52, },
+ { 46, 10375, 9250, 0x51, },
+ { 47, 10250, 9125, 0x50, },
+ { 48, 10125, 9000, 0x4f, },
+ { 49, 10000, 8875, 0x4e, },
+ { 50, 9875, 8750, 0x4d, },
+ { 51, 9750, 8625, 0x4c, },
+ { 52, 9625, 8500, 0x4b, },
+ { 53, 9500, 8375, 0x4a, },
+ { 54, 9375, 8250, 0x49, },
+ { 55, 9250, 8125, 0x48, },
+ { 56, 9125, 8000, 0x47, },
+ { 57, 9000, 7875, 0x46, },
+ { 58, 8875, 7750, 0x45, },
+ { 59, 8750, 7625, 0x44, },
+ { 60, 8625, 7500, 0x43, },
+ { 61, 8500, 7375, 0x42, },
+ { 62, 8375, 7250, 0x41, },
+ { 63, 8250, 7125, 0x40, },
+ { 64, 8125, 7000, 0x3f, },
+ { 65, 8000, 6875, 0x3e, },
+ { 66, 7875, 6750, 0x3d, },
+ { 67, 7750, 6625, 0x3c, },
+ { 68, 7625, 6500, 0x3b, },
+ { 69, 7500, 6375, 0x3a, },
+ { 70, 7375, 6250, 0x39, },
+ { 71, 7250, 6125, 0x38, },
+ { 72, 7125, 6000, 0x37, },
+ { 73, 7000, 5875, 0x36, },
+ { 74, 6875, 5750, 0x35, },
+ { 75, 6750, 5625, 0x34, },
+ { 76, 6625, 5500, 0x33, },
+ { 77, 6500, 5375, 0x32, },
+ { 78, 6375, 5250, 0x31, },
+ { 79, 6250, 5125, 0x30, },
+ { 80, 6125, 5000, 0x2f, },
+ { 81, 6000, 4875, 0x2e, },
+ { 82, 5875, 4750, 0x2d, },
+ { 83, 5750, 4625, 0x2c, },
+ { 84, 5625, 4500, 0x2b, },
+ { 85, 5500, 4375, 0x2a, },
+ { 86, 5375, 4250, 0x29, },
+ { 87, 5250, 4125, 0x28, },
+ { 88, 5125, 4000, 0x27, },
+ { 89, 5000, 3875, 0x26, },
+ { 90, 4875, 3750, 0x25, },
+ { 91, 4750, 3625, 0x24, },
+ { 92, 4625, 3500, 0x23, },
+ { 93, 4500, 3375, 0x22, },
+ { 94, 4375, 3250, 0x21, },
+ { 95, 4250, 3125, 0x20, },
+ { 96, 4125, 3000, 0x1f, },
+ { 97, 4125, 3000, 0x1e, },
+ { 98, 4125, 3000, 0x1d, },
+ { 99, 4125, 3000, 0x1c, },
+ { 100, 4125, 3000, 0x1b, },
+ { 101, 4125, 3000, 0x1a, },
+ { 102, 4125, 3000, 0x19, },
+ { 103, 4125, 3000, 0x18, },
+ { 104, 4125, 3000, 0x17, },
+ { 105, 4125, 3000, 0x16, },
+ { 106, 4125, 3000, 0x15, },
+ { 107, 4125, 3000, 0x14, },
+ { 108, 4125, 3000, 0x13, },
+ { 109, 4125, 3000, 0x12, },
+ { 110, 4125, 3000, 0x11, },
+ { 111, 4125, 3000, 0x10, },
+ { 112, 4125, 3000, 0x0f, },
+ { 113, 4125, 3000, 0x0e, },
+ { 114, 4125, 3000, 0x0d, },
+ { 115, 4125, 3000, 0x0c, },
+ { 116, 4125, 3000, 0x0b, },
+ { 117, 4125, 3000, 0x0a, },
+ { 118, 4125, 3000, 0x09, },
+ { 119, 4125, 3000, 0x08, },
+ { 120, 1125, 0, 0x07, },
+ { 121, 1000, 0, 0x06, },
+ { 122, 875, 0, 0x05, },
+ { 123, 750, 0, 0x04, },
+ { 124, 625, 0, 0x03, },
+ { 125, 500, 0, 0x02, },
+ { 126, 375, 0, 0x01, },
+ { 127, 0, 0, 0x00, },
+};
+
+struct cparams {
+ int i;
+ int t;
+ int m;
+ int c;
+};
+
+static struct cparams cparams[] = {
+ { 1, 1333, 301, 28664 },
+ { 1, 1066, 294, 24460 },
+ { 1, 800, 294, 25192 },
+ { 0, 1333, 276, 27605 },
+ { 0, 1066, 276, 27605 },
+ { 0, 800, 231, 23784 },
+};
+
+unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
+{
+ u64 total_count, diff, ret;
+ u32 count1, count2, count3, m = 0, c = 0;
+ unsigned long now = jiffies_to_msecs(jiffies), diff1;
+ int i;
+
+ diff1 = now - dev_priv->last_time1;
+
+ count1 = I915_READ(DMIEC);
+ count2 = I915_READ(DDREC);
+ count3 = I915_READ(CSIEC);
+
+ total_count = count1 + count2 + count3;
+
+ /* FIXME: handle per-counter overflow */
+ if (total_count < dev_priv->last_count1) {
+ diff = ~0UL - dev_priv->last_count1;
+ diff += total_count;
+ } else {
+ diff = total_count - dev_priv->last_count1;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(cparams); i++) {
+ if (cparams[i].i == dev_priv->c_m &&
+ cparams[i].t == dev_priv->r_t) {
+ m = cparams[i].m;
+ c = cparams[i].c;
+ break;
+ }
+ }
+
+ div_u64(diff, diff1);
+ ret = ((m * diff) + c);
+ div_u64(ret, 10);
+
+ dev_priv->last_count1 = total_count;
+ dev_priv->last_time1 = now;
+
+ return ret;
+}
+
+unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
+{
+ unsigned long m, x, b;
+ u32 tsfs;
+
+ tsfs = I915_READ(TSFS);
+
+ m = ((tsfs & TSFS_SLOPE_MASK) >> TSFS_SLOPE_SHIFT);
+ x = I915_READ8(TR1);
+
+ b = tsfs & TSFS_INTR_MASK;
+
+ return ((m * x) / 127) - b;
+}
+
+static unsigned long pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
+{
+ unsigned long val = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(v_table); i++) {
+ if (v_table[i].pvid == pxvid) {
+ if (IS_MOBILE(dev_priv->dev))
+ val = v_table[i].vm;
+ else
+ val = v_table[i].vd;
+ }
+ }
+
+ return val;
+}
+
+void i915_update_gfx_val(struct drm_i915_private *dev_priv)
+{
+ struct timespec now, diff1;
+ u64 diff;
+ unsigned long diffms;
+ u32 count;
+
+ getrawmonotonic(&now);
+ diff1 = timespec_sub(now, dev_priv->last_time2);
+
+ /* Don't divide by 0 */
+ diffms = diff1.tv_sec * 1000 + diff1.tv_nsec / 1000000;
+ if (!diffms)
+ return;
+
+ count = I915_READ(GFXEC);
+
+ if (count < dev_priv->last_count2) {
+ diff = ~0UL - dev_priv->last_count2;
+ diff += count;
+ } else {
+ diff = count - dev_priv->last_count2;
+ }
+
+ dev_priv->last_count2 = count;
+ dev_priv->last_time2 = now;
+
+ /* More magic constants... */
+ diff = diff * 1181;
+ div_u64(diff, diffms * 10);
+ dev_priv->gfx_power = diff;
}
+unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
+{
+ unsigned long t, corr, state1, corr2, state2;
+ u32 pxvid, ext_v;
+
+ pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->cur_delay * 4));
+ pxvid = (pxvid >> 24) & 0x7f;
+ ext_v = pvid_to_extvid(dev_priv, pxvid);
+
+ state1 = ext_v;
+
+ t = i915_mch_val(dev_priv);
+
+ /* Revel in the empirically derived constants */
+
+ /* Correction factor in 1/100000 units */
+ if (t > 80)
+ corr = ((t * 2349) + 135940);
+ else if (t >= 50)
+ corr = ((t * 964) + 29317);
+ else /* < 50 */
+ corr = ((t * 301) + 1004);
+
+ corr = corr * ((150142 * state1) / 10000 - 78642);
+ corr /= 100000;
+ corr2 = (corr * dev_priv->corr);
+
+ state2 = (corr2 * state1) / 10000;
+ state2 /= 100; /* convert to mW */
+
+ i915_update_gfx_val(dev_priv);
+
+ return dev_priv->gfx_power + state2;
+}
+
+/* Global for IPS driver to get at the current i915 device */
+static struct drm_i915_private *i915_mch_dev;
+/*
+ * Lock protecting IPS related data structures
+ * - i915_mch_dev
+ * - dev_priv->max_delay
+ * - dev_priv->min_delay
+ * - dev_priv->fmax
+ * - dev_priv->gpu_busy
+ */
+DEFINE_SPINLOCK(mchdev_lock);
+
+/**
+ * i915_read_mch_val - return value for IPS use
+ *
+ * Calculate and return a value for the IPS driver to use when deciding whether
+ * we have thermal and power headroom to increase CPU or GPU power budget.
+ */
+unsigned long i915_read_mch_val(void)
+{
+ struct drm_i915_private *dev_priv;
+ unsigned long chipset_val, graphics_val, ret = 0;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev)
+ goto out_unlock;
+ dev_priv = i915_mch_dev;
+
+ chipset_val = i915_chipset_val(dev_priv);
+ graphics_val = i915_gfx_val(dev_priv);
+
+ ret = chipset_val + graphics_val;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_read_mch_val);
+
+/**
+ * i915_gpu_raise - raise GPU frequency limit
+ *
+ * Raise the limit; IPS indicates we have thermal headroom.
+ */
+bool i915_gpu_raise(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ if (dev_priv->max_delay > dev_priv->fmax)
+ dev_priv->max_delay--;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_raise);
+
+/**
+ * i915_gpu_lower - lower GPU frequency limit
+ *
+ * IPS indicates we're close to a thermal limit, so throttle back the GPU
+ * frequency maximum.
+ */
+bool i915_gpu_lower(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ if (dev_priv->max_delay < dev_priv->min_delay)
+ dev_priv->max_delay++;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_lower);
+
+/**
+ * i915_gpu_busy - indicate GPU business to IPS
+ *
+ * Tell the IPS driver whether or not the GPU is busy.
+ */
+bool i915_gpu_busy(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = false;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev)
+ goto out_unlock;
+ dev_priv = i915_mch_dev;
+
+ ret = dev_priv->busy;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_busy);
+
+/**
+ * i915_gpu_turbo_disable - disable graphics turbo
+ *
+ * Disable graphics turbo by resetting the max frequency and setting the
+ * current frequency to the default.
+ */
+bool i915_gpu_turbo_disable(void)
+{
+ struct drm_i915_private *dev_priv;
+ bool ret = true;
+
+ spin_lock(&mchdev_lock);
+ if (!i915_mch_dev) {
+ ret = false;
+ goto out_unlock;
+ }
+ dev_priv = i915_mch_dev;
+
+ dev_priv->max_delay = dev_priv->fstart;
+
+ if (!ironlake_set_drps(dev_priv->dev, dev_priv->fstart))
+ ret = false;
+
+out_unlock:
+ spin_unlock(&mchdev_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(i915_gpu_turbo_disable);
+
/**
* i915_driver_load - setup chip and create an initial config
* @dev: DRM device
@@ -1594,7 +2031,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
resource_size_t base, size;
int ret = 0, mmio_bar;
uint32_t agp_size, prealloc_size, prealloc_start;
-
/* i915 has 4 more counters */
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
@@ -1672,6 +2108,13 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
dev_priv->has_gem = 0;
}
+ if (dev_priv->has_gem == 0 &&
+ drm_core_check_feature(dev, DRIVER_MODESET)) {
+ DRM_ERROR("kernel modesetting requires GEM, disabling driver.\n");
+ ret = -ENODEV;
+ goto out_iomapfree;
+ }
+
dev->driver->get_vblank_counter = i915_get_vblank_counter;
dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
if (IS_G4X(dev) || IS_IRONLAKE(dev) || IS_GEN6(dev)) {
@@ -1691,7 +2134,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_workqueue_free;
}
- i915_get_mem_freq(dev);
+ if (IS_PINEVIEW(dev))
+ i915_pineview_get_mem_freq(dev);
+ else if (IS_IRONLAKE(dev))
+ i915_ironlake_get_mem_freq(dev);
/* On the 945G/GM, the chipset reports the MSI capability on the
* integrated graphics even though the support isn't actually there
@@ -1709,7 +2155,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->user_irq_lock);
spin_lock_init(&dev_priv->error_lock);
- dev_priv->user_irq_refcount = 0;
dev_priv->trace_irq_seqno = 0;
ret = drm_vblank_init(dev, I915_NUM_PIPE);
@@ -1738,6 +2183,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
setup_timer(&dev_priv->hangcheck_timer, i915_hangcheck_elapsed,
(unsigned long) dev);
+
+ spin_lock(&mchdev_lock);
+ i915_mch_dev = dev_priv;
+ dev_priv->mchdev_lock = &mchdev_lock;
+ spin_unlock(&mchdev_lock);
+
return 0;
out_workqueue_free:
@@ -1759,6 +2210,10 @@ int i915_driver_unload(struct drm_device *dev)
i915_destroy_error_state(dev);
+ spin_lock(&mchdev_lock);
+ i915_mch_dev = NULL;
+ spin_unlock(&mchdev_lock);
+
destroy_workqueue(dev_priv->wq);
del_timer_sync(&dev_priv->hangcheck_timer);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 5c51e45ab68d..423dc90c1e20 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -60,95 +60,95 @@ extern int intel_agp_enabled;
.subdevice = PCI_ANY_ID, \
.driver_data = (unsigned long) info }
-const static struct intel_device_info intel_i830_info = {
+static const struct intel_device_info intel_i830_info = {
.is_i8xx = 1, .is_mobile = 1, .cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_845g_info = {
+static const struct intel_device_info intel_845g_info = {
.is_i8xx = 1,
};
-const static struct intel_device_info intel_i85x_info = {
+static const struct intel_device_info intel_i85x_info = {
.is_i8xx = 1, .is_i85x = 1, .is_mobile = 1,
.cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_i865g_info = {
+static const struct intel_device_info intel_i865g_info = {
.is_i8xx = 1,
};
-const static struct intel_device_info intel_i915g_info = {
+static const struct intel_device_info intel_i915g_info = {
.is_i915g = 1, .is_i9xx = 1, .cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_i915gm_info = {
+static const struct intel_device_info intel_i915gm_info = {
.is_i9xx = 1, .is_mobile = 1,
.cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_i945g_info = {
+static const struct intel_device_info intel_i945g_info = {
.is_i9xx = 1, .has_hotplug = 1, .cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_i945gm_info = {
+static const struct intel_device_info intel_i945gm_info = {
.is_i945gm = 1, .is_i9xx = 1, .is_mobile = 1,
.has_hotplug = 1, .cursor_needs_physical = 1,
};
-const static struct intel_device_info intel_i965g_info = {
+static const struct intel_device_info intel_i965g_info = {
.is_i965g = 1, .is_i9xx = 1, .has_hotplug = 1,
};
-const static struct intel_device_info intel_i965gm_info = {
+static const struct intel_device_info intel_i965gm_info = {
.is_i965g = 1, .is_mobile = 1, .is_i965gm = 1, .is_i9xx = 1,
.is_mobile = 1, .has_fbc = 1, .has_rc6 = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_g33_info = {
+static const struct intel_device_info intel_g33_info = {
.is_g33 = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_g45_info = {
+static const struct intel_device_info intel_g45_info = {
.is_i965g = 1, .is_g4x = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_pipe_cxsr = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_gm45_info = {
+static const struct intel_device_info intel_gm45_info = {
.is_i965g = 1, .is_mobile = 1, .is_g4x = 1, .is_i9xx = 1,
.is_mobile = 1, .need_gfx_hws = 1, .has_fbc = 1, .has_rc6 = 1,
.has_pipe_cxsr = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_pineview_info = {
+static const struct intel_device_info intel_pineview_info = {
.is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .is_i9xx = 1,
.need_gfx_hws = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_ironlake_d_info = {
+static const struct intel_device_info intel_ironlake_d_info = {
.is_ironlake = 1, .is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_pipe_cxsr = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_ironlake_m_info = {
+static const struct intel_device_info intel_ironlake_m_info = {
.is_ironlake = 1, .is_mobile = 1, .is_i965g = 1, .is_i9xx = 1,
.need_gfx_hws = 1, .has_rc6 = 1,
.has_hotplug = 1,
};
-const static struct intel_device_info intel_sandybridge_d_info = {
+static const struct intel_device_info intel_sandybridge_d_info = {
.is_i965g = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_hotplug = 1, .is_gen6 = 1,
};
-const static struct intel_device_info intel_sandybridge_m_info = {
+static const struct intel_device_info intel_sandybridge_m_info = {
.is_i965g = 1, .is_mobile = 1, .is_i9xx = 1, .need_gfx_hws = 1,
.has_hotplug = 1, .is_gen6 = 1,
};
-const static struct pci_device_id pciidlist[] = {
+static const struct pci_device_id pciidlist[] = {
INTEL_VGA_DEVICE(0x3577, &intel_i830_info),
INTEL_VGA_DEVICE(0x2562, &intel_845g_info),
INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),
@@ -340,7 +340,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
/*
* Clear request list
*/
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev, &dev_priv->render_ring);
if (need_display)
i915_save_display(dev);
@@ -370,6 +370,7 @@ int i965_reset(struct drm_device *dev, u8 flags)
}
} else {
DRM_ERROR("Error occurred. Don't know how to reset this chip.\n");
+ mutex_unlock(&dev->struct_mutex);
return -ENODEV;
}
@@ -388,33 +389,10 @@ int i965_reset(struct drm_device *dev, u8 flags)
* switched away).
*/
if (drm_core_check_feature(dev, DRIVER_MODESET) ||
- !dev_priv->mm.suspended) {
- drm_i915_ring_buffer_t *ring = &dev_priv->ring;
- struct drm_gem_object *obj = ring->ring_obj;
- struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ !dev_priv->mm.suspended) {
+ struct intel_ring_buffer *ring = &dev_priv->render_ring;
dev_priv->mm.suspended = 0;
-
- /* Stop the ring if it's running. */
- I915_WRITE(PRB0_CTL, 0);
- I915_WRITE(PRB0_TAIL, 0);
- I915_WRITE(PRB0_HEAD, 0);
-
- /* Initialize the ring. */
- I915_WRITE(PRB0_START, obj_priv->gtt_offset);
- I915_WRITE(PRB0_CTL,
- ((obj->size - 4096) & RING_NR_PAGES) |
- RING_NO_REPORT |
- RING_VALID);
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_kernel_lost_context(dev);
- else {
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
- }
-
+ ring->init(dev, ring);
mutex_unlock(&dev->struct_mutex);
drm_irq_uninstall(dev);
drm_irq_install(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7f797ef1ab39..9ed8ecd95801 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -32,6 +32,7 @@
#include "i915_reg.h"
#include "intel_bios.h"
+#include "intel_ringbuffer.h"
#include <linux/io-mapping.h>
/* General customization:
@@ -55,6 +56,8 @@ enum plane {
#define I915_NUM_PIPE 2
+#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
+
/* Interface history:
*
* 1.1: Original.
@@ -89,16 +92,6 @@ struct drm_i915_gem_phys_object {
struct drm_gem_object *cur_obj;
};
-typedef struct _drm_i915_ring_buffer {
- unsigned long Size;
- u8 *virtual_start;
- int head;
- int tail;
- int space;
- drm_local_map_t map;
- struct drm_gem_object *ring_obj;
-} drm_i915_ring_buffer_t;
-
struct mem_block {
struct mem_block *next;
struct mem_block *prev;
@@ -241,17 +234,15 @@ typedef struct drm_i915_private {
void __iomem *regs;
struct pci_dev *bridge_dev;
- drm_i915_ring_buffer_t ring;
+ struct intel_ring_buffer render_ring;
+ struct intel_ring_buffer bsd_ring;
drm_dma_handle_t *status_page_dmah;
- void *hw_status_page;
void *seqno_page;
dma_addr_t dma_status_page;
uint32_t counter;
- unsigned int status_gfx_addr;
unsigned int seqno_gfx_addr;
drm_local_map_t hws_map;
- struct drm_gem_object *hws_obj;
struct drm_gem_object *seqno_obj;
struct drm_gem_object *pwrctx;
@@ -267,8 +258,6 @@ typedef struct drm_i915_private {
atomic_t irq_received;
/** Protects user_irq_refcount and irq_mask_reg */
spinlock_t user_irq_lock;
- /** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */
- int user_irq_refcount;
u32 trace_irq_seqno;
/** Cached value of IMR to avoid reads in updating the bitfield */
u32 irq_mask_reg;
@@ -334,7 +323,7 @@ typedef struct drm_i915_private {
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
- unsigned int fsb_freq, mem_freq;
+ unsigned int fsb_freq, mem_freq, is_ddr3;
spinlock_t error_lock;
struct drm_i915_error_state *first_error;
@@ -514,18 +503,7 @@ typedef struct drm_i915_private {
*/
struct list_head shrink_list;
- /**
- * List of objects currently involved in rendering from the
- * ringbuffer.
- *
- * Includes buffers having the contents of their GPU caches
- * flushed, not necessarily primitives. last_rendering_seqno
- * represents when the rendering involved will be completed.
- *
- * A reference is held on the buffer while on this list.
- */
spinlock_t active_list_lock;
- struct list_head active_list;
/**
* List of objects which are not in the ringbuffer but which
@@ -563,12 +541,6 @@ typedef struct drm_i915_private {
struct list_head fence_list;
/**
- * List of breadcrumbs associated with GPU requests currently
- * outstanding.
- */
- struct list_head request_list;
-
- /**
* We leave the user IRQ off as much as possible,
* but this means that requests will finish and never
* be retired once the system goes idle. Set a timer to
@@ -644,6 +616,18 @@ typedef struct drm_i915_private {
u8 cur_delay;
u8 min_delay;
u8 max_delay;
+ u8 fmax;
+ u8 fstart;
+
+ u64 last_count1;
+ unsigned long last_time1;
+ u64 last_count2;
+ struct timespec last_time2;
+ unsigned long gfx_power;
+ int c_m;
+ int r_t;
+ u8 corr;
+ spinlock_t *mchdev_lock;
enum no_fbc_reason no_fbc_reason;
@@ -671,19 +655,64 @@ struct drm_i915_gem_object {
* (has pending rendering), and is not set if it's on inactive (ready
* to be unbound).
*/
- int active;
+ unsigned int active : 1;
/**
* This is set if the object has been written to since last bound
* to the GTT
*/
- int dirty;
+ unsigned int dirty : 1;
+
+ /**
+ * Fence register bits (if any) for this object. Will be set
+ * as needed when mapped into the GTT.
+ * Protected by dev->struct_mutex.
+ *
+ * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE)
+ */
+ int fence_reg : 5;
+
+ /**
+ * Used for checking the object doesn't appear more than once
+ * in an execbuffer object list.
+ */
+ unsigned int in_execbuffer : 1;
+
+ /**
+ * Advice: are the backing pages purgeable?
+ */
+ unsigned int madv : 2;
+
+ /**
+ * Refcount for the pages array. With the current locking scheme, there
+ * are at most two concurrent users: Binding a bo to the gtt and
+ * pwrite/pread using physical addresses. So two bits for a maximum
+ * of two users are enough.
+ */
+ unsigned int pages_refcount : 2;
+#define DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT 0x3
+
+ /**
+ * Current tiling mode for the object.
+ */
+ unsigned int tiling_mode : 2;
+
+ /** How many users have pinned this object in GTT space. The following
+ * users can each hold at most one reference: pwrite/pread, pin_ioctl
+ * (via user_pin_count), execbuffer (objects are not allowed multiple
+ * times for the same batchbuffer), and the framebuffer code. When
+ * switching/pageflipping, the framebuffer code has at most two buffers
+ * pinned per crtc.
+ *
+ * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
+ * bits with absolutely no headroom. So use 4 bits. */
+ int pin_count : 4;
+#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
/** AGP memory structure for our GTT binding. */
DRM_AGP_MEM *agp_mem;
struct page **pages;
- int pages_refcount;
/**
* Current offset of the object in GTT space.
@@ -692,26 +721,18 @@ struct drm_i915_gem_object {
*/
uint32_t gtt_offset;
+ /* Which ring is refering to is this object */
+ struct intel_ring_buffer *ring;
+
/**
* Fake offset for use by mmap(2)
*/
uint64_t mmap_offset;
- /**
- * Fence register bits (if any) for this object. Will be set
- * as needed when mapped into the GTT.
- * Protected by dev->struct_mutex.
- */
- int fence_reg;
-
- /** How many users have pinned this object in GTT space */
- int pin_count;
-
/** Breadcrumb of last rendering to the buffer. */
uint32_t last_rendering_seqno;
- /** Current tiling mode for the object. */
- uint32_t tiling_mode;
+ /** Current tiling stride for the object, if it's tiled. */
uint32_t stride;
/** Record of address bit 17 of each page at last unbind. */
@@ -734,17 +755,6 @@ struct drm_i915_gem_object {
struct drm_i915_gem_phys_object *phys_obj;
/**
- * Used for checking the object doesn't appear more than once
- * in an execbuffer object list.
- */
- int in_execbuffer;
-
- /**
- * Advice: are the backing pages purgeable?
- */
- int madv;
-
- /**
* Number of crtcs where this object is currently the fb, but
* will be page flipped away on the next vblank. When it
* reaches 0, dev_priv->pending_flip_queue will be woken up.
@@ -765,6 +775,9 @@ struct drm_i915_gem_object {
* an emission time with seqnos for tracking how far ahead of the GPU we are.
*/
struct drm_i915_gem_request {
+ /** On Which ring this request was generated */
+ struct intel_ring_buffer *ring;
+
/** GEM sequence number associated with this request. */
uint32_t seqno;
@@ -821,6 +834,11 @@ extern int i915_emit_box(struct drm_device *dev,
struct drm_clip_rect *boxes,
int i, int DR1, int DR4);
extern int i965_reset(struct drm_device *dev, u8 flags);
+extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv);
+extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
+extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
+extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
+
/* i915_irq.c */
void i915_hangcheck_elapsed(unsigned long data);
@@ -829,9 +847,7 @@ extern int i915_irq_emit(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-void i915_user_irq_get(struct drm_device *dev);
void i915_trace_irq_get(struct drm_device *dev, u32 seqno);
-void i915_user_irq_put(struct drm_device *dev);
extern void i915_enable_interrupt (struct drm_device *dev);
extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
@@ -849,6 +865,11 @@ extern u32 gm45_get_vblank_counter(struct drm_device *dev, int crtc);
extern int i915_vblank_swap(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern void i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask);
+extern void i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask);
+extern void ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv,
+ u32 mask);
+extern void ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv,
+ u32 mask);
void
i915_enable_pipestat(drm_i915_private_t *dev_priv, int pipe, u32 mask);
@@ -922,11 +943,13 @@ void i915_gem_object_unpin(struct drm_gem_object *obj);
int i915_gem_object_unbind(struct drm_gem_object *obj);
void i915_gem_release_mmap(struct drm_gem_object *obj);
void i915_gem_lastclose(struct drm_device *dev);
-uint32_t i915_get_gem_seqno(struct drm_device *dev);
+uint32_t i915_get_gem_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
bool i915_seqno_passed(uint32_t seq1, uint32_t seq2);
int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
-void i915_gem_retire_requests(struct drm_device *dev);
+void i915_gem_retire_requests(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
void i915_gem_retire_work_handler(struct work_struct *work);
void i915_gem_clflush_object(struct drm_gem_object *obj);
int i915_gem_object_set_domain(struct drm_gem_object *obj,
@@ -937,9 +960,13 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
unsigned long end);
int i915_gem_idle(struct drm_device *dev);
-uint32_t i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
- uint32_t flush_domains);
-int i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible);
+uint32_t i915_add_request(struct drm_device *dev,
+ struct drm_file *file_priv,
+ uint32_t flush_domains,
+ struct intel_ring_buffer *ring);
+int i915_do_wait_request(struct drm_device *dev,
+ uint32_t seqno, int interruptible,
+ struct intel_ring_buffer *ring);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
int write);
@@ -1015,7 +1042,7 @@ extern void g4x_disable_fbc(struct drm_device *dev);
extern void intel_disable_fbc(struct drm_device *dev);
extern void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval);
extern bool intel_fbc_enabled(struct drm_device *dev);
-
+extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_detect_pch (struct drm_device *dev);
extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
@@ -1026,7 +1053,8 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
* has access to the ring.
*/
#define RING_LOCK_TEST_WITH_RETURN(dev, file_priv) do { \
- if (((drm_i915_private_t *)dev->dev_private)->ring.ring_obj == NULL) \
+ if (((drm_i915_private_t *)dev->dev_private)->render_ring.gem_object \
+ == NULL) \
LOCK_TEST_WITH_RETURN(dev, file_priv); \
} while (0)
@@ -1039,35 +1067,31 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
#define I915_WRITE64(reg, val) writeq(val, dev_priv->regs + (reg))
#define I915_READ64(reg) readq(dev_priv->regs + (reg))
#define POSTING_READ(reg) (void)I915_READ(reg)
+#define POSTING_READ16(reg) (void)I915_READ16(reg)
#define I915_VERBOSE 0
-#define RING_LOCALS volatile unsigned int *ring_virt__;
-
-#define BEGIN_LP_RING(n) do { \
- int bytes__ = 4*(n); \
- if (I915_VERBOSE) DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
- /* a wrap must occur between instructions so pad beforehand */ \
- if (unlikely (dev_priv->ring.tail + bytes__ > dev_priv->ring.Size)) \
- i915_wrap_ring(dev); \
- if (unlikely (dev_priv->ring.space < bytes__)) \
- i915_wait_ring(dev, bytes__, __func__); \
- ring_virt__ = (unsigned int *) \
- (dev_priv->ring.virtual_start + dev_priv->ring.tail); \
- dev_priv->ring.tail += bytes__; \
- dev_priv->ring.tail &= dev_priv->ring.Size - 1; \
- dev_priv->ring.space -= bytes__; \
+#define BEGIN_LP_RING(n) do { \
+ drm_i915_private_t *dev_priv = dev->dev_private; \
+ if (I915_VERBOSE) \
+ DRM_DEBUG(" BEGIN_LP_RING %x\n", (int)(n)); \
+ intel_ring_begin(dev, &dev_priv->render_ring, 4*(n)); \
} while (0)
-#define OUT_RING(n) do { \
- if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *ring_virt__++ = (n); \
+
+#define OUT_RING(x) do { \
+ drm_i915_private_t *dev_priv = dev->dev_private; \
+ if (I915_VERBOSE) \
+ DRM_DEBUG(" OUT_RING %x\n", (int)(x)); \
+ intel_ring_emit(dev, &dev_priv->render_ring, x); \
} while (0)
#define ADVANCE_LP_RING() do { \
+ drm_i915_private_t *dev_priv = dev->dev_private; \
if (I915_VERBOSE) \
- DRM_DEBUG("ADVANCE_LP_RING %x\n", dev_priv->ring.tail); \
- I915_WRITE(PRB0_TAIL, dev_priv->ring.tail); \
+ DRM_DEBUG("ADVANCE_LP_RING %x\n", \
+ dev_priv->render_ring.tail); \
+ intel_ring_advance(dev, &dev_priv->render_ring); \
} while(0)
/**
@@ -1085,14 +1109,12 @@ extern int intel_trans_dp_port_sel (struct drm_crtc *crtc);
*
* The area from dword 0x20 to 0x3ff is available for driver usage.
*/
-#define READ_HWSP(dev_priv, reg) (((volatile u32*)(dev_priv->hw_status_page))[reg])
+#define READ_HWSP(dev_priv, reg) (((volatile u32 *)\
+ (dev_priv->render_ring.status_page.page_addr))[reg])
#define READ_BREADCRUMB(dev_priv) READ_HWSP(dev_priv, I915_BREADCRUMB_INDEX)
#define I915_GEM_HWS_INDEX 0x20
#define I915_BREADCRUMB_INDEX 0x21
-extern int i915_wrap_ring(struct drm_device * dev);
-extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
-
#define INTEL_INFO(dev) (((struct drm_i915_private *) (dev)->dev_private)->info)
#define IS_I830(dev) ((dev)->pci_device == 0x3577)
@@ -1138,6 +1160,7 @@ extern int i915_wait_ring(struct drm_device * dev, int n, const char *caller);
(dev)->pci_device == 0x2A42 || \
(dev)->pci_device == 0x2E42)
+#define HAS_BSD(dev) (IS_IRONLAKE(dev) || IS_G4X(dev))
#define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 112699f71fa4..9ded3dae6c87 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -35,8 +35,6 @@
#include <linux/swap.h>
#include <linux/pci.h>
-#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
-
static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
@@ -169,7 +167,7 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_gem_object *obj)
obj_priv->tiling_mode != I915_TILING_NONE;
}
-static inline int
+static inline void
slow_shmem_copy(struct page *dst_page,
int dst_offset,
struct page *src_page,
@@ -178,25 +176,16 @@ slow_shmem_copy(struct page *dst_page,
{
char *dst_vaddr, *src_vaddr;
- dst_vaddr = kmap_atomic(dst_page, KM_USER0);
- if (dst_vaddr == NULL)
- return -ENOMEM;
-
- src_vaddr = kmap_atomic(src_page, KM_USER1);
- if (src_vaddr == NULL) {
- kunmap_atomic(dst_vaddr, KM_USER0);
- return -ENOMEM;
- }
+ dst_vaddr = kmap(dst_page);
+ src_vaddr = kmap(src_page);
memcpy(dst_vaddr + dst_offset, src_vaddr + src_offset, length);
- kunmap_atomic(src_vaddr, KM_USER1);
- kunmap_atomic(dst_vaddr, KM_USER0);
-
- return 0;
+ kunmap(src_page);
+ kunmap(dst_page);
}
-static inline int
+static inline void
slow_shmem_bit17_copy(struct page *gpu_page,
int gpu_offset,
struct page *cpu_page,
@@ -216,15 +205,8 @@ slow_shmem_bit17_copy(struct page *gpu_page,
cpu_page, cpu_offset, length);
}
- gpu_vaddr = kmap_atomic(gpu_page, KM_USER0);
- if (gpu_vaddr == NULL)
- return -ENOMEM;
-
- cpu_vaddr = kmap_atomic(cpu_page, KM_USER1);
- if (cpu_vaddr == NULL) {
- kunmap_atomic(gpu_vaddr, KM_USER0);
- return -ENOMEM;
- }
+ gpu_vaddr = kmap(gpu_page);
+ cpu_vaddr = kmap(cpu_page);
/* Copy the data, XORing A6 with A17 (1). The user already knows he's
* XORing with the other bits (A9 for Y, A9 and A10 for X)
@@ -248,10 +230,8 @@ slow_shmem_bit17_copy(struct page *gpu_page,
length -= this_length;
}
- kunmap_atomic(cpu_vaddr, KM_USER1);
- kunmap_atomic(gpu_vaddr, KM_USER0);
-
- return 0;
+ kunmap(cpu_page);
+ kunmap(gpu_page);
}
/**
@@ -427,21 +407,19 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj,
page_length = PAGE_SIZE - data_page_offset;
if (do_bit17_swizzling) {
- ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
- shmem_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length,
- 1);
- } else {
- ret = slow_shmem_copy(user_pages[data_page_index],
- data_page_offset,
- obj_priv->pages[shmem_page_index],
+ slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
shmem_page_offset,
- page_length);
+ user_pages[data_page_index],
+ data_page_offset,
+ page_length,
+ 1);
+ } else {
+ slow_shmem_copy(user_pages[data_page_index],
+ data_page_offset,
+ obj_priv->pages[shmem_page_index],
+ shmem_page_offset,
+ page_length);
}
- if (ret)
- goto fail_put_pages;
remain -= page_length;
data_ptr += page_length;
@@ -531,25 +509,24 @@ fast_user_write(struct io_mapping *mapping,
* page faults
*/
-static inline int
+static inline void
slow_kernel_write(struct io_mapping *mapping,
loff_t gtt_base, int gtt_offset,
struct page *user_page, int user_offset,
int length)
{
- char *src_vaddr, *dst_vaddr;
- unsigned long unwritten;
+ char __iomem *dst_vaddr;
+ char *src_vaddr;
- dst_vaddr = io_mapping_map_atomic_wc(mapping, gtt_base);
- src_vaddr = kmap_atomic(user_page, KM_USER1);
- unwritten = __copy_from_user_inatomic_nocache(dst_vaddr + gtt_offset,
- src_vaddr + user_offset,
- length);
- kunmap_atomic(src_vaddr, KM_USER1);
- io_mapping_unmap_atomic(dst_vaddr);
- if (unwritten)
- return -EFAULT;
- return 0;
+ dst_vaddr = io_mapping_map_wc(mapping, gtt_base);
+ src_vaddr = kmap(user_page);
+
+ memcpy_toio(dst_vaddr + gtt_offset,
+ src_vaddr + user_offset,
+ length);
+
+ kunmap(user_page);
+ io_mapping_unmap(dst_vaddr);
}
static inline int
@@ -722,18 +699,11 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
if ((data_page_offset + page_length) > PAGE_SIZE)
page_length = PAGE_SIZE - data_page_offset;
- ret = slow_kernel_write(dev_priv->mm.gtt_mapping,
- gtt_page_base, gtt_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length);
-
- /* If we get a fault while copying data, then (presumably) our
- * source page isn't available. Return the error and we'll
- * retry in the slow path.
- */
- if (ret)
- goto out_unpin_object;
+ slow_kernel_write(dev_priv->mm.gtt_mapping,
+ gtt_page_base, gtt_page_offset,
+ user_pages[data_page_index],
+ data_page_offset,
+ page_length);
remain -= page_length;
offset += page_length;
@@ -902,21 +872,19 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj,
page_length = PAGE_SIZE - data_page_offset;
if (do_bit17_swizzling) {
- ret = slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
- shmem_page_offset,
- user_pages[data_page_index],
- data_page_offset,
- page_length,
- 0);
- } else {
- ret = slow_shmem_copy(obj_priv->pages[shmem_page_index],
+ slow_shmem_bit17_copy(obj_priv->pages[shmem_page_index],
shmem_page_offset,
user_pages[data_page_index],
data_page_offset,
- page_length);
+ page_length,
+ 0);
+ } else {
+ slow_shmem_copy(obj_priv->pages[shmem_page_index],
+ shmem_page_offset,
+ user_pages[data_page_index],
+ data_page_offset,
+ page_length);
}
- if (ret)
- goto fail_put_pages;
remain -= page_length;
data_ptr += page_length;
@@ -973,7 +941,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
if (obj_priv->phys_obj)
ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
else if (obj_priv->tiling_mode == I915_TILING_NONE &&
- dev->gtt_total != 0) {
+ dev->gtt_total != 0 &&
+ obj->write_domain != I915_GEM_DOMAIN_CPU) {
ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
if (ret == -EFAULT) {
ret = i915_gem_gtt_pwrite_slow(dev, obj, args,
@@ -1484,11 +1453,14 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
}
static void
-i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno)
+i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno,
+ struct intel_ring_buffer *ring)
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
+ BUG_ON(ring == NULL);
+ obj_priv->ring = ring;
/* Add a reference if we're newly entering the active list. */
if (!obj_priv->active) {
@@ -1497,8 +1469,7 @@ i915_gem_object_move_to_active(struct drm_gem_object *obj, uint32_t seqno)
}
/* Move from whatever list we were on to the tail of execution. */
spin_lock(&dev_priv->mm.active_list_lock);
- list_move_tail(&obj_priv->list,
- &dev_priv->mm.active_list);
+ list_move_tail(&obj_priv->list, &ring->active_list);
spin_unlock(&dev_priv->mm.active_list_lock);
obj_priv->last_rendering_seqno = seqno;
}
@@ -1551,6 +1522,7 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
BUG_ON(!list_empty(&obj_priv->gpu_write_list));
obj_priv->last_rendering_seqno = 0;
+ obj_priv->ring = NULL;
if (obj_priv->active) {
obj_priv->active = 0;
drm_gem_object_unreference(obj);
@@ -1560,7 +1532,8 @@ i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
static void
i915_gem_process_flushing_list(struct drm_device *dev,
- uint32_t flush_domains, uint32_t seqno)
+ uint32_t flush_domains, uint32_t seqno,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv, *next;
@@ -1571,12 +1544,13 @@ i915_gem_process_flushing_list(struct drm_device *dev,
struct drm_gem_object *obj = &obj_priv->base;
if ((obj->write_domain & flush_domains) ==
- obj->write_domain) {
+ obj->write_domain &&
+ obj_priv->ring->ring_flag == ring->ring_flag) {
uint32_t old_write_domain = obj->write_domain;
obj->write_domain = 0;
list_del_init(&obj_priv->gpu_write_list);
- i915_gem_object_move_to_active(obj, seqno);
+ i915_gem_object_move_to_active(obj, seqno, ring);
/* update the fence lru list */
if (obj_priv->fence_reg != I915_FENCE_REG_NONE) {
@@ -1593,31 +1567,15 @@ i915_gem_process_flushing_list(struct drm_device *dev,
}
}
-#define PIPE_CONTROL_FLUSH(addr) \
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
- PIPE_CONTROL_DEPTH_STALL); \
- OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
- OUT_RING(0); \
- OUT_RING(0); \
-
-/**
- * Creates a new sequence number, emitting a write of it to the status page
- * plus an interrupt, which will trigger i915_user_interrupt_handler.
- *
- * Must be called with struct_lock held.
- *
- * Returned sequence numbers are nonzero on success.
- */
uint32_t
i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
- uint32_t flush_domains)
+ uint32_t flush_domains, struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_file_private *i915_file_priv = NULL;
struct drm_i915_gem_request *request;
uint32_t seqno;
int was_empty;
- RING_LOCALS;
if (file_priv != NULL)
i915_file_priv = file_priv->driver_priv;
@@ -1626,62 +1584,14 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
if (request == NULL)
return 0;
- /* Grab the seqno we're going to make this request be, and bump the
- * next (skipping 0 so it can be the reserved no-seqno value).
- */
- seqno = dev_priv->mm.next_gem_seqno;
- dev_priv->mm.next_gem_seqno++;
- if (dev_priv->mm.next_gem_seqno == 0)
- dev_priv->mm.next_gem_seqno++;
-
- if (HAS_PIPE_CONTROL(dev)) {
- u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
-
- /*
- * Workaround qword write incoherence by flushing the
- * PIPE_NOTIFY buffers out to memory before requesting
- * an interrupt.
- */
- BEGIN_LP_RING(32);
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
- PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
- OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
- OUT_RING(seqno);
- OUT_RING(0);
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128; /* write to separate cachelines */
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- scratch_addr += 128;
- PIPE_CONTROL_FLUSH(scratch_addr);
- OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
- PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
- PIPE_CONTROL_NOTIFY);
- OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
- OUT_RING(seqno);
- OUT_RING(0);
- ADVANCE_LP_RING();
- } else {
- BEGIN_LP_RING(4);
- OUT_RING(MI_STORE_DWORD_INDEX);
- OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- OUT_RING(seqno);
-
- OUT_RING(MI_USER_INTERRUPT);
- ADVANCE_LP_RING();
- }
-
- DRM_DEBUG_DRIVER("%d\n", seqno);
+ seqno = ring->add_request(dev, ring, file_priv, flush_domains);
request->seqno = seqno;
+ request->ring = ring;
request->emitted_jiffies = jiffies;
- was_empty = list_empty(&dev_priv->mm.request_list);
- list_add_tail(&request->list, &dev_priv->mm.request_list);
+ was_empty = list_empty(&ring->request_list);
+ list_add_tail(&request->list, &ring->request_list);
+
if (i915_file_priv) {
list_add_tail(&request->client_list,
&i915_file_priv->mm.request_list);
@@ -1693,7 +1603,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
* domain we're flushing with our flush.
*/
if (flush_domains != 0)
- i915_gem_process_flushing_list(dev, flush_domains, seqno);
+ i915_gem_process_flushing_list(dev, flush_domains, seqno, ring);
if (!dev_priv->mm.suspended) {
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
@@ -1710,20 +1620,16 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv,
* before signalling the CPU
*/
static uint32_t
-i915_retire_commands(struct drm_device *dev)
+i915_retire_commands(struct drm_device *dev, struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
uint32_t flush_domains = 0;
- RING_LOCALS;
/* The sampler always gets flushed on i965 (sigh) */
if (IS_I965G(dev))
flush_domains |= I915_GEM_DOMAIN_SAMPLER;
- BEGIN_LP_RING(2);
- OUT_RING(cmd);
- OUT_RING(0); /* noop */
- ADVANCE_LP_RING();
+
+ ring->flush(dev, ring,
+ I915_GEM_DOMAIN_COMMAND, flush_domains);
return flush_domains;
}
@@ -1743,11 +1649,11 @@ i915_gem_retire_request(struct drm_device *dev,
* by the ringbuffer to the flushing/inactive lists as appropriate.
*/
spin_lock(&dev_priv->mm.active_list_lock);
- while (!list_empty(&dev_priv->mm.active_list)) {
+ while (!list_empty(&request->ring->active_list)) {
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
- obj_priv = list_first_entry(&dev_priv->mm.active_list,
+ obj_priv = list_first_entry(&request->ring->active_list,
struct drm_i915_gem_object,
list);
obj = &obj_priv->base;
@@ -1794,35 +1700,33 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
}
uint32_t
-i915_get_gem_seqno(struct drm_device *dev)
+i915_get_gem_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
- drm_i915_private_t *dev_priv = dev->dev_private;
-
- if (HAS_PIPE_CONTROL(dev))
- return ((volatile u32 *)(dev_priv->seqno_page))[0];
- else
- return READ_HWSP(dev_priv, I915_GEM_HWS_INDEX);
+ return ring->get_gem_seqno(dev, ring);
}
/**
* This function clears the request list as sequence numbers are passed.
*/
void
-i915_gem_retire_requests(struct drm_device *dev)
+i915_gem_retire_requests(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
- if (!dev_priv->hw_status_page || list_empty(&dev_priv->mm.request_list))
+ if (!ring->status_page.page_addr
+ || list_empty(&ring->request_list))
return;
- seqno = i915_get_gem_seqno(dev);
+ seqno = i915_get_gem_seqno(dev, ring);
- while (!list_empty(&dev_priv->mm.request_list)) {
+ while (!list_empty(&ring->request_list)) {
struct drm_i915_gem_request *request;
uint32_t retiring_seqno;
- request = list_first_entry(&dev_priv->mm.request_list,
+ request = list_first_entry(&ring->request_list,
struct drm_i915_gem_request,
list);
retiring_seqno = request->seqno;
@@ -1840,7 +1744,8 @@ i915_gem_retire_requests(struct drm_device *dev)
if (unlikely (dev_priv->trace_irq_seqno &&
i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
- i915_user_irq_put(dev);
+
+ ring->user_irq_put(dev, ring);
dev_priv->trace_irq_seqno = 0;
}
}
@@ -1856,15 +1761,22 @@ i915_gem_retire_work_handler(struct work_struct *work)
dev = dev_priv->dev;
mutex_lock(&dev->struct_mutex);
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev, &dev_priv->render_ring);
+
+ if (HAS_BSD(dev))
+ i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
+
if (!dev_priv->mm.suspended &&
- !list_empty(&dev_priv->mm.request_list))
+ (!list_empty(&dev_priv->render_ring.request_list) ||
+ (HAS_BSD(dev) &&
+ !list_empty(&dev_priv->bsd_ring.request_list))))
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, HZ);
mutex_unlock(&dev->struct_mutex);
}
int
-i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
+i915_do_wait_request(struct drm_device *dev, uint32_t seqno,
+ int interruptible, struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 ier;
@@ -1875,7 +1787,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
if (atomic_read(&dev_priv->mm.wedged))
return -EIO;
- if (!i915_seqno_passed(i915_get_gem_seqno(dev), seqno)) {
+ if (!i915_seqno_passed(ring->get_gem_seqno(dev, ring), seqno)) {
if (HAS_PCH_SPLIT(dev))
ier = I915_READ(DEIER) | I915_READ(GTIER);
else
@@ -1889,19 +1801,21 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
trace_i915_gem_request_wait_begin(dev, seqno);
- dev_priv->mm.waiting_gem_seqno = seqno;
- i915_user_irq_get(dev);
+ ring->waiting_gem_seqno = seqno;
+ ring->user_irq_get(dev, ring);
if (interruptible)
- ret = wait_event_interruptible(dev_priv->irq_queue,
- i915_seqno_passed(i915_get_gem_seqno(dev), seqno) ||
- atomic_read(&dev_priv->mm.wedged));
+ ret = wait_event_interruptible(ring->irq_queue,
+ i915_seqno_passed(
+ ring->get_gem_seqno(dev, ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
else
- wait_event(dev_priv->irq_queue,
- i915_seqno_passed(i915_get_gem_seqno(dev), seqno) ||
- atomic_read(&dev_priv->mm.wedged));
+ wait_event(ring->irq_queue,
+ i915_seqno_passed(
+ ring->get_gem_seqno(dev, ring), seqno)
+ || atomic_read(&dev_priv->mm.wedged));
- i915_user_irq_put(dev);
- dev_priv->mm.waiting_gem_seqno = 0;
+ ring->user_irq_put(dev, ring);
+ ring->waiting_gem_seqno = 0;
trace_i915_gem_request_wait_end(dev, seqno);
}
@@ -1910,7 +1824,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
if (ret && ret != -ERESTARTSYS)
DRM_ERROR("%s returns %d (awaiting %d at %d)\n",
- __func__, ret, seqno, i915_get_gem_seqno(dev));
+ __func__, ret, seqno, ring->get_gem_seqno(dev, ring));
/* Directly dispatch request retiring. While we have the work queue
* to handle this, the waiter on a request often wants an associated
@@ -1918,7 +1832,7 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
* a separate wait queue to handle that.
*/
if (ret == 0)
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev, ring);
return ret;
}
@@ -1928,9 +1842,10 @@ i915_do_wait_request(struct drm_device *dev, uint32_t seqno, int interruptible)
* request and object lists appropriately for that event.
*/
static int
-i915_wait_request(struct drm_device *dev, uint32_t seqno)
+i915_wait_request(struct drm_device *dev, uint32_t seqno,
+ struct intel_ring_buffer *ring)
{
- return i915_do_wait_request(dev, seqno, 1);
+ return i915_do_wait_request(dev, seqno, 1, ring);
}
static void
@@ -1939,71 +1854,29 @@ i915_gem_flush(struct drm_device *dev,
uint32_t flush_domains)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- uint32_t cmd;
- RING_LOCALS;
-
-#if WATCH_EXEC
- DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
- invalidate_domains, flush_domains);
-#endif
- trace_i915_gem_request_flush(dev, dev_priv->mm.next_gem_seqno,
- invalidate_domains, flush_domains);
-
if (flush_domains & I915_GEM_DOMAIN_CPU)
drm_agp_chipset_flush(dev);
+ dev_priv->render_ring.flush(dev, &dev_priv->render_ring,
+ invalidate_domains,
+ flush_domains);
+
+ if (HAS_BSD(dev))
+ dev_priv->bsd_ring.flush(dev, &dev_priv->bsd_ring,
+ invalidate_domains,
+ flush_domains);
+}
- if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
- /*
- * read/write caches:
- *
- * I915_GEM_DOMAIN_RENDER is always invalidated, but is
- * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is
- * also flushed at 2d versus 3d pipeline switches.
- *
- * read-only caches:
- *
- * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
- * MI_READ_FLUSH is set, and is always flushed on 965.
- *
- * I915_GEM_DOMAIN_COMMAND may not exist?
- *
- * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
- * invalidated when MI_EXE_FLUSH is set.
- *
- * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
- * invalidated with every MI_FLUSH.
- *
- * TLBs:
- *
- * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
- * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
- * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
- * are flushed at any MI_FLUSH.
- */
-
- cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
- if ((invalidate_domains|flush_domains) &
- I915_GEM_DOMAIN_RENDER)
- cmd &= ~MI_NO_WRITE_FLUSH;
- if (!IS_I965G(dev)) {
- /*
- * On the 965, the sampler cache always gets flushed
- * and this bit is reserved.
- */
- if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
- cmd |= MI_READ_FLUSH;
- }
- if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
- cmd |= MI_EXE_FLUSH;
-
-#if WATCH_EXEC
- DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
-#endif
- BEGIN_LP_RING(2);
- OUT_RING(cmd);
- OUT_RING(MI_NOOP);
- ADVANCE_LP_RING();
- }
+static void
+i915_gem_flush_ring(struct drm_device *dev,
+ uint32_t invalidate_domains,
+ uint32_t flush_domains,
+ struct intel_ring_buffer *ring)
+{
+ if (flush_domains & I915_GEM_DOMAIN_CPU)
+ drm_agp_chipset_flush(dev);
+ ring->flush(dev, ring,
+ invalidate_domains,
+ flush_domains);
}
/**
@@ -2030,7 +1903,8 @@ i915_gem_object_wait_rendering(struct drm_gem_object *obj)
DRM_INFO("%s: object %p wait for seqno %08x\n",
__func__, obj, obj_priv->last_rendering_seqno);
#endif
- ret = i915_wait_request(dev, obj_priv->last_rendering_seqno);
+ ret = i915_wait_request(dev,
+ obj_priv->last_rendering_seqno, obj_priv->ring);
if (ret != 0)
return ret;
}
@@ -2146,11 +2020,14 @@ i915_gpu_idle(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
bool lists_empty;
- uint32_t seqno;
+ uint32_t seqno1, seqno2;
+ int ret;
spin_lock(&dev_priv->mm.active_list_lock);
- lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->mm.active_list);
+ lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
+ list_empty(&dev_priv->render_ring.active_list) &&
+ (!HAS_BSD(dev) ||
+ list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty)
@@ -2158,11 +2035,25 @@ i915_gpu_idle(struct drm_device *dev)
/* Flush everything onto the inactive list. */
i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
- seqno = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS);
- if (seqno == 0)
+ seqno1 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
+ &dev_priv->render_ring);
+ if (seqno1 == 0)
return -ENOMEM;
+ ret = i915_wait_request(dev, seqno1, &dev_priv->render_ring);
+
+ if (HAS_BSD(dev)) {
+ seqno2 = i915_add_request(dev, NULL, I915_GEM_GPU_DOMAINS,
+ &dev_priv->bsd_ring);
+ if (seqno2 == 0)
+ return -ENOMEM;
+
+ ret = i915_wait_request(dev, seqno2, &dev_priv->bsd_ring);
+ if (ret)
+ return ret;
+ }
+
- return i915_wait_request(dev, seqno);
+ return ret;
}
static int
@@ -2175,7 +2066,9 @@ i915_gem_evict_everything(struct drm_device *dev)
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->mm.active_list));
+ list_empty(&dev_priv->render_ring.active_list) &&
+ (!HAS_BSD(dev)
+ || list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
if (lists_empty)
@@ -2195,7 +2088,9 @@ i915_gem_evict_everything(struct drm_device *dev)
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->mm.active_list));
+ list_empty(&dev_priv->render_ring.active_list) &&
+ (!HAS_BSD(dev)
+ || list_empty(&dev_priv->bsd_ring.active_list)));
spin_unlock(&dev_priv->mm.active_list_lock);
BUG_ON(!lists_empty);
@@ -2209,8 +2104,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
struct drm_gem_object *obj;
int ret;
+ struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
+ struct intel_ring_buffer *bsd_ring = &dev_priv->bsd_ring;
for (;;) {
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev, render_ring);
+
+ if (HAS_BSD(dev))
+ i915_gem_retire_requests(dev, bsd_ring);
/* If there's an inactive buffer available now, grab it
* and be done.
@@ -2234,14 +2134,30 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
* things, wait for the next to finish and hopefully leave us
* a buffer to evict.
*/
- if (!list_empty(&dev_priv->mm.request_list)) {
+ if (!list_empty(&render_ring->request_list)) {
+ struct drm_i915_gem_request *request;
+
+ request = list_first_entry(&render_ring->request_list,
+ struct drm_i915_gem_request,
+ list);
+
+ ret = i915_wait_request(dev,
+ request->seqno, request->ring);
+ if (ret)
+ return ret;
+
+ continue;
+ }
+
+ if (HAS_BSD(dev) && !list_empty(&bsd_ring->request_list)) {
struct drm_i915_gem_request *request;
- request = list_first_entry(&dev_priv->mm.request_list,
+ request = list_first_entry(&bsd_ring->request_list,
struct drm_i915_gem_request,
list);
- ret = i915_wait_request(dev, request->seqno);
+ ret = i915_wait_request(dev,
+ request->seqno, request->ring);
if (ret)
return ret;
@@ -2268,10 +2184,13 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
if (obj != NULL) {
uint32_t seqno;
- i915_gem_flush(dev,
+ i915_gem_flush_ring(dev,
+ obj->write_domain,
obj->write_domain,
- obj->write_domain);
- seqno = i915_add_request(dev, NULL, obj->write_domain);
+ obj_priv->ring);
+ seqno = i915_add_request(dev, NULL,
+ obj->write_domain,
+ obj_priv->ring);
if (seqno == 0)
return -ENOMEM;
continue;
@@ -2299,6 +2218,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
struct inode *inode;
struct page *page;
+ BUG_ON(obj_priv->pages_refcount
+ == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT);
+
if (obj_priv->pages_refcount++ != 0)
return 0;
@@ -2697,6 +2619,14 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
return -EINVAL;
}
+ /* If the object is bigger than the entire aperture, reject it early
+ * before evicting everything in a vain attempt to find space.
+ */
+ if (obj->size > dev->gtt_total) {
+ DRM_ERROR("Attempting to bind an object larger than the aperture\n");
+ return -E2BIG;
+ }
+
search_free:
free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
obj->size, alignment, 0);
@@ -2807,6 +2737,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
{
struct drm_device *dev = obj->dev;
uint32_t old_write_domain;
+ struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
if ((obj->write_domain & I915_GEM_GPU_DOMAINS) == 0)
return;
@@ -2814,7 +2745,7 @@ i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj)
/* Queue the GPU write cache flushing we need. */
old_write_domain = obj->write_domain;
i915_gem_flush(dev, 0, obj->write_domain);
- (void) i915_add_request(dev, NULL, obj->write_domain);
+ (void) i915_add_request(dev, NULL, obj->write_domain, obj_priv->ring);
BUG_ON(obj->write_domain);
trace_i915_gem_object_change_domain(obj,
@@ -2954,23 +2885,24 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
DRM_INFO("%s: object %p wait for seqno %08x\n",
__func__, obj, obj_priv->last_rendering_seqno);
#endif
- ret = i915_do_wait_request(dev, obj_priv->last_rendering_seqno, 0);
+ ret = i915_do_wait_request(dev,
+ obj_priv->last_rendering_seqno,
+ 0,
+ obj_priv->ring);
if (ret != 0)
return ret;
}
+ i915_gem_object_flush_cpu_write_domain(obj);
+
old_write_domain = obj->write_domain;
old_read_domains = obj->read_domains;
- obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
- i915_gem_object_flush_cpu_write_domain(obj);
-
/* It should now be out of any other write domains, and we can update
* the domain values for our changes.
*/
BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
- obj->read_domains |= I915_GEM_DOMAIN_GTT;
+ obj->read_domains = I915_GEM_DOMAIN_GTT;
obj->write_domain = I915_GEM_DOMAIN_GTT;
obj_priv->dirty = 1;
@@ -3354,9 +3286,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
obj_priv->tiling_mode != I915_TILING_NONE;
/* Check fence reg constraints and rebind if necessary */
- if (need_fence && !i915_gem_object_fence_offset_ok(obj,
- obj_priv->tiling_mode))
- i915_gem_object_unbind(obj);
+ if (need_fence &&
+ !i915_gem_object_fence_offset_ok(obj,
+ obj_priv->tiling_mode)) {
+ ret = i915_gem_object_unbind(obj);
+ if (ret)
+ return ret;
+ }
/* Choose the GTT offset for our buffer and put it there. */
ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
@@ -3370,9 +3306,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
if (need_fence) {
ret = i915_gem_object_get_fence_reg(obj);
if (ret != 0) {
- if (ret != -EBUSY && ret != -ERESTARTSYS)
- DRM_ERROR("Failure to install fence: %d\n",
- ret);
i915_gem_object_unpin(obj);
return ret;
}
@@ -3545,62 +3478,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
return 0;
}
-/** Dispatch a batchbuffer to the ring
- */
-static int
-i915_dispatch_gem_execbuffer(struct drm_device *dev,
- struct drm_i915_gem_execbuffer2 *exec,
- struct drm_clip_rect *cliprects,
- uint64_t exec_offset)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- int nbox = exec->num_cliprects;
- int i = 0, count;
- uint32_t exec_start, exec_len;
- RING_LOCALS;
-
- exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
- exec_len = (uint32_t) exec->batch_len;
-
- trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1);
-
- count = nbox ? nbox : 1;
-
- for (i = 0; i < count; i++) {
- if (i < nbox) {
- int ret = i915_emit_box(dev, cliprects, i,
- exec->DR1, exec->DR4);
- if (ret)
- return ret;
- }
-
- if (IS_I830(dev) || IS_845G(dev)) {
- BEGIN_LP_RING(4);
- OUT_RING(MI_BATCH_BUFFER);
- OUT_RING(exec_start | MI_BATCH_NON_SECURE);
- OUT_RING(exec_start + exec_len - 4);
- OUT_RING(0);
- ADVANCE_LP_RING();
- } else {
- BEGIN_LP_RING(2);
- if (IS_I965G(dev)) {
- OUT_RING(MI_BATCH_BUFFER_START |
- (2 << 6) |
- MI_BATCH_NON_SECURE_I965);
- OUT_RING(exec_start);
- } else {
- OUT_RING(MI_BATCH_BUFFER_START |
- (2 << 6));
- OUT_RING(exec_start | MI_BATCH_NON_SECURE);
- }
- ADVANCE_LP_RING();
- }
- }
-
- /* XXX breadcrumb */
- return 0;
-}
-
/* Throttle our rendering by waiting until the ring has completed our requests
* emitted over 20 msec ago.
*
@@ -3629,7 +3506,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file_priv)
if (time_after_eq(request->emitted_jiffies, recent_enough))
break;
- ret = i915_wait_request(dev, request->seqno);
+ ret = i915_wait_request(dev, request->seqno, request->ring);
if (ret != 0)
break;
}
@@ -3786,10 +3663,22 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
uint32_t seqno, flush_domains, reloc_index;
int pin_tries, flips;
+ struct intel_ring_buffer *ring = NULL;
+
#if WATCH_EXEC
DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
(int) args->buffers_ptr, args->buffer_count, args->batch_len);
#endif
+ if (args->flags & I915_EXEC_BSD) {
+ if (!HAS_BSD(dev)) {
+ DRM_ERROR("execbuf with wrong flag\n");
+ return -EINVAL;
+ }
+ ring = &dev_priv->bsd_ring;
+ } else {
+ ring = &dev_priv->render_ring;
+ }
+
if (args->buffer_count < 1) {
DRM_ERROR("execbuf with %d buffers\n", args->buffer_count);
@@ -3902,11 +3791,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
if (ret != -ENOSPC || pin_tries >= 1) {
if (ret != -ERESTARTSYS) {
unsigned long long total_size = 0;
- for (i = 0; i < args->buffer_count; i++)
+ int num_fences = 0;
+ for (i = 0; i < args->buffer_count; i++) {
+ obj_priv = object_list[i]->driver_private;
+
total_size += object_list[i]->size;
- DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes: %d\n",
+ num_fences +=
+ exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE &&
+ obj_priv->tiling_mode != I915_TILING_NONE;
+ }
+ DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n",
pinned+1, args->buffer_count,
- total_size, ret);
+ total_size, num_fences,
+ ret);
DRM_ERROR("%d objects [%d pinned], "
"%d object bytes [%d pinned], "
"%d/%d gtt bytes\n",
@@ -3976,9 +3873,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
i915_gem_flush(dev,
dev->invalidate_domains,
dev->flush_domains);
- if (dev->flush_domains & I915_GEM_GPU_DOMAINS)
+ if (dev->flush_domains & I915_GEM_GPU_DOMAINS) {
(void)i915_add_request(dev, file_priv,
- dev->flush_domains);
+ dev->flush_domains,
+ &dev_priv->render_ring);
+
+ if (HAS_BSD(dev))
+ (void)i915_add_request(dev, file_priv,
+ dev->flush_domains,
+ &dev_priv->bsd_ring);
+ }
}
for (i = 0; i < args->buffer_count; i++) {
@@ -4015,7 +3919,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
#endif
/* Exec the batchbuffer */
- ret = i915_dispatch_gem_execbuffer(dev, args, cliprects, exec_offset);
+ ret = ring->dispatch_gem_execbuffer(dev, ring, args,
+ cliprects, exec_offset);
if (ret) {
DRM_ERROR("dispatch failed %d\n", ret);
goto err;
@@ -4025,7 +3930,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* Ensure that the commands in the batch buffer are
* finished before the interrupt fires
*/
- flush_domains = i915_retire_commands(dev);
+ flush_domains = i915_retire_commands(dev, ring);
i915_verify_inactive(dev, __FILE__, __LINE__);
@@ -4036,12 +3941,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
* *some* interrupts representing completion of buffers that we can
* wait on when trying to clear up gtt space).
*/
- seqno = i915_add_request(dev, file_priv, flush_domains);
+ seqno = i915_add_request(dev, file_priv, flush_domains, ring);
BUG_ON(seqno == 0);
for (i = 0; i < args->buffer_count; i++) {
struct drm_gem_object *obj = object_list[i];
+ obj_priv = to_intel_bo(obj);
- i915_gem_object_move_to_active(obj, seqno);
+ i915_gem_object_move_to_active(obj, seqno, ring);
#if WATCH_LRU
DRM_INFO("%s: move to exec list %p\n", __func__, obj);
#endif
@@ -4153,7 +4059,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
exec2.DR4 = args->DR4;
exec2.num_cliprects = args->num_cliprects;
exec2.cliprects_ptr = args->cliprects_ptr;
- exec2.flags = 0;
+ exec2.flags = I915_EXEC_RENDER;
ret = i915_gem_do_execbuffer(dev, data, file_priv, &exec2, exec2_list);
if (!ret) {
@@ -4239,7 +4145,20 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
int ret;
+ BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+
i915_verify_inactive(dev, __FILE__, __LINE__);
+
+ if (obj_priv->gtt_space != NULL) {
+ if (alignment == 0)
+ alignment = i915_gem_get_gtt_alignment(obj);
+ if (obj_priv->gtt_offset & (alignment - 1)) {
+ ret = i915_gem_object_unbind(obj);
+ if (ret)
+ return ret;
+ }
+ }
+
if (obj_priv->gtt_space == NULL) {
ret = i915_gem_object_bind_to_gtt(obj, alignment);
if (ret)
@@ -4392,6 +4311,7 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_i915_gem_busy *args = data;
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
+ drm_i915_private_t *dev_priv = dev->dev_private;
obj = drm_gem_object_lookup(dev, file_priv, args->handle);
if (obj == NULL) {
@@ -4406,7 +4326,10 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
* actually unmasked, and our working set ends up being larger than
* required.
*/
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(dev, &dev_priv->render_ring);
+
+ if (HAS_BSD(dev))
+ i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
obj_priv = to_intel_bo(obj);
/* Don't count being on the flushing list against the object being
@@ -4573,7 +4496,10 @@ i915_gem_idle(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
- if (dev_priv->mm.suspended || dev_priv->ring.ring_obj == NULL) {
+ if (dev_priv->mm.suspended ||
+ (dev_priv->render_ring.gem_object == NULL) ||
+ (HAS_BSD(dev) &&
+ dev_priv->bsd_ring.gem_object == NULL)) {
mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -4654,71 +4580,6 @@ err:
return ret;
}
-static int
-i915_gem_init_hws(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
- int ret;
-
- /* If we need a physical address for the status page, it's already
- * initialized at driver load time.
- */
- if (!I915_NEED_GFX_HWS(dev))
- return 0;
-
- obj = i915_gem_alloc_object(dev, 4096);
- if (obj == NULL) {
- DRM_ERROR("Failed to allocate status page\n");
- ret = -ENOMEM;
- goto err;
- }
- obj_priv = to_intel_bo(obj);
- obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
-
- ret = i915_gem_object_pin(obj, 4096);
- if (ret != 0) {
- drm_gem_object_unreference(obj);
- goto err_unref;
- }
-
- dev_priv->status_gfx_addr = obj_priv->gtt_offset;
-
- dev_priv->hw_status_page = kmap(obj_priv->pages[0]);
- if (dev_priv->hw_status_page == NULL) {
- DRM_ERROR("Failed to map status page.\n");
- memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
- ret = -EINVAL;
- goto err_unpin;
- }
-
- if (HAS_PIPE_CONTROL(dev)) {
- ret = i915_gem_init_pipe_control(dev);
- if (ret)
- goto err_unpin;
- }
-
- dev_priv->hws_obj = obj;
- memset(dev_priv->hw_status_page, 0, PAGE_SIZE);
- if (IS_GEN6(dev)) {
- I915_WRITE(HWS_PGA_GEN6, dev_priv->status_gfx_addr);
- I915_READ(HWS_PGA_GEN6); /* posting read */
- } else {
- I915_WRITE(HWS_PGA, dev_priv->status_gfx_addr);
- I915_READ(HWS_PGA); /* posting read */
- }
- DRM_DEBUG_DRIVER("hws offset: 0x%08x\n", dev_priv->status_gfx_addr);
-
- return 0;
-
-err_unpin:
- i915_gem_object_unpin(obj);
-err_unref:
- drm_gem_object_unreference(obj);
-err:
- return 0;
-}
static void
i915_gem_cleanup_pipe_control(struct drm_device *dev)
@@ -4737,146 +4598,46 @@ i915_gem_cleanup_pipe_control(struct drm_device *dev)
dev_priv->seqno_page = NULL;
}
-static void
-i915_gem_cleanup_hws(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
-
- if (dev_priv->hws_obj == NULL)
- return;
-
- obj = dev_priv->hws_obj;
- obj_priv = to_intel_bo(obj);
-
- kunmap(obj_priv->pages[0]);
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- dev_priv->hws_obj = NULL;
-
- memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
- dev_priv->hw_status_page = NULL;
-
- if (HAS_PIPE_CONTROL(dev))
- i915_gem_cleanup_pipe_control(dev);
-
- /* Write high address into HWS_PGA when disabling. */
- I915_WRITE(HWS_PGA, 0x1ffff000);
-}
-
int
i915_gem_init_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- struct drm_gem_object *obj;
- struct drm_i915_gem_object *obj_priv;
- drm_i915_ring_buffer_t *ring = &dev_priv->ring;
int ret;
- u32 head;
-
- ret = i915_gem_init_hws(dev);
- if (ret != 0)
- return ret;
- obj = i915_gem_alloc_object(dev, 128 * 1024);
- if (obj == NULL) {
- DRM_ERROR("Failed to allocate ringbuffer\n");
- i915_gem_cleanup_hws(dev);
- return -ENOMEM;
- }
- obj_priv = to_intel_bo(obj);
+ dev_priv->render_ring = render_ring;
- ret = i915_gem_object_pin(obj, 4096);
- if (ret != 0) {
- drm_gem_object_unreference(obj);
- i915_gem_cleanup_hws(dev);
- return ret;
+ if (!I915_NEED_GFX_HWS(dev)) {
+ dev_priv->render_ring.status_page.page_addr
+ = dev_priv->status_page_dmah->vaddr;
+ memset(dev_priv->render_ring.status_page.page_addr,
+ 0, PAGE_SIZE);
}
- /* Set up the kernel mapping for the ring. */
- ring->Size = obj->size;
-
- ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
- ring->map.size = obj->size;
- ring->map.type = 0;
- ring->map.flags = 0;
- ring->map.mtrr = 0;
-
- drm_core_ioremap_wc(&ring->map, dev);
- if (ring->map.handle == NULL) {
- DRM_ERROR("Failed to map ringbuffer.\n");
- memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
- i915_gem_object_unpin(obj);
- drm_gem_object_unreference(obj);
- i915_gem_cleanup_hws(dev);
- return -EINVAL;
- }
- ring->ring_obj = obj;
- ring->virtual_start = ring->map.handle;
-
- /* Stop the ring if it's running. */
- I915_WRITE(PRB0_CTL, 0);
- I915_WRITE(PRB0_TAIL, 0);
- I915_WRITE(PRB0_HEAD, 0);
-
- /* Initialize the ring. */
- I915_WRITE(PRB0_START, obj_priv->gtt_offset);
- head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
-
- /* G45 ring initialization fails to reset head to zero */
- if (head != 0) {
- DRM_ERROR("Ring head not reset to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- I915_READ(PRB0_CTL),
- I915_READ(PRB0_HEAD),
- I915_READ(PRB0_TAIL),
- I915_READ(PRB0_START));
- I915_WRITE(PRB0_HEAD, 0);
-
- DRM_ERROR("Ring head forced to zero "
- "ctl %08x head %08x tail %08x start %08x\n",
- I915_READ(PRB0_CTL),
- I915_READ(PRB0_HEAD),
- I915_READ(PRB0_TAIL),
- I915_READ(PRB0_START));
- }
-
- I915_WRITE(PRB0_CTL,
- ((obj->size - 4096) & RING_NR_PAGES) |
- RING_NO_REPORT |
- RING_VALID);
-
- head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
-
- /* If the head is still not zero, the ring is dead */
- if (head != 0) {
- DRM_ERROR("Ring initialization failed "
- "ctl %08x head %08x tail %08x start %08x\n",
- I915_READ(PRB0_CTL),
- I915_READ(PRB0_HEAD),
- I915_READ(PRB0_TAIL),
- I915_READ(PRB0_START));
- return -EIO;
+ if (HAS_PIPE_CONTROL(dev)) {
+ ret = i915_gem_init_pipe_control(dev);
+ if (ret)
+ return ret;
}
- /* Update our cache of the ring state */
- if (!drm_core_check_feature(dev, DRIVER_MODESET))
- i915_kernel_lost_context(dev);
- else {
- ring->head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring->tail = I915_READ(PRB0_TAIL) & TAIL_ADDR;
- ring->space = ring->head - (ring->tail + 8);
- if (ring->space < 0)
- ring->space += ring->Size;
- }
+ ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
+ if (ret)
+ goto cleanup_pipe_control;
- if (IS_I9XX(dev) && !IS_GEN3(dev)) {
- I915_WRITE(MI_MODE,
- (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH);
+ if (HAS_BSD(dev)) {
+ dev_priv->bsd_ring = bsd_ring;
+ ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+ if (ret)
+ goto cleanup_render_ring;
}
return 0;
+
+cleanup_render_ring:
+ intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
+cleanup_pipe_control:
+ if (HAS_PIPE_CONTROL(dev))
+ i915_gem_cleanup_pipe_control(dev);
+ return ret;
}
void
@@ -4884,17 +4645,11 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- if (dev_priv->ring.ring_obj == NULL)
- return;
-
- drm_core_ioremapfree(&dev_priv->ring.map, dev);
-
- i915_gem_object_unpin(dev_priv->ring.ring_obj);
- drm_gem_object_unreference(dev_priv->ring.ring_obj);
- dev_priv->ring.ring_obj = NULL;
- memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
-
- i915_gem_cleanup_hws(dev);
+ intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
+ if (HAS_BSD(dev))
+ intel_cleanup_ring_buffer(dev, &dev_priv->bsd_ring);
+ if (HAS_PIPE_CONTROL(dev))
+ i915_gem_cleanup_pipe_control(dev);
}
int
@@ -4922,12 +4677,14 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
}
spin_lock(&dev_priv->mm.active_list_lock);
- BUG_ON(!list_empty(&dev_priv->mm.active_list));
+ BUG_ON(!list_empty(&dev_priv->render_ring.active_list));
+ BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.active_list));
spin_unlock(&dev_priv->mm.active_list_lock);
BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
- BUG_ON(!list_empty(&dev_priv->mm.request_list));
+ BUG_ON(!list_empty(&dev_priv->render_ring.request_list));
+ BUG_ON(HAS_BSD(dev) && !list_empty(&dev_priv->bsd_ring.request_list));
mutex_unlock(&dev->struct_mutex);
drm_irq_install(dev);
@@ -4966,18 +4723,20 @@ i915_gem_load(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
spin_lock_init(&dev_priv->mm.active_list_lock);
- INIT_LIST_HEAD(&dev_priv->mm.active_list);
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
- INIT_LIST_HEAD(&dev_priv->mm.request_list);
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
+ INIT_LIST_HEAD(&dev_priv->render_ring.active_list);
+ INIT_LIST_HEAD(&dev_priv->render_ring.request_list);
+ if (HAS_BSD(dev)) {
+ INIT_LIST_HEAD(&dev_priv->bsd_ring.active_list);
+ INIT_LIST_HEAD(&dev_priv->bsd_ring.request_list);
+ }
for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list);
INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
i915_gem_retire_work_handler);
- dev_priv->mm.next_gem_seqno = 1;
-
spin_lock(&shrink_list_lock);
list_add(&dev_priv->mm.shrink_list, &shrink_list);
spin_unlock(&shrink_list_lock);
@@ -5209,7 +4968,9 @@ i915_gpu_is_active(struct drm_device *dev)
spin_lock(&dev_priv->mm.active_list_lock);
lists_empty = list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->mm.active_list);
+ list_empty(&dev_priv->render_ring.active_list);
+ if (HAS_BSD(dev))
+ lists_empty &= list_empty(&dev_priv->bsd_ring.active_list);
spin_unlock(&dev_priv->mm.active_list_lock);
return !lists_empty;
@@ -5254,8 +5015,10 @@ rescan:
continue;
spin_unlock(&shrink_list_lock);
+ i915_gem_retire_requests(dev, &dev_priv->render_ring);
- i915_gem_retire_requests(dev);
+ if (HAS_BSD(dev))
+ i915_gem_retire_requests(dev, &dev_priv->bsd_ring);
list_for_each_entry_safe(obj_priv, next_obj,
&dev_priv->mm.inactive_list,
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8c3f0802686d..2479be001e40 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -53,7 +53,7 @@
I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
/** Interrupts that we mask and unmask at runtime. */
-#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT)
+#define I915_INTERRUPT_ENABLE_VAR (I915_USER_INTERRUPT | I915_BSD_USER_INTERRUPT)
#define I915_PIPE_VBLANK_STATUS (PIPE_START_VBLANK_INTERRUPT_STATUS |\
PIPE_VBLANK_INTERRUPT_STATUS)
@@ -74,7 +74,7 @@ ironlake_enable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
}
}
-static inline void
+void
ironlake_disable_graphics_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->gt_irq_mask_reg & mask) != mask) {
@@ -115,7 +115,7 @@ i915_enable_irq(drm_i915_private_t *dev_priv, u32 mask)
}
}
-static inline void
+void
i915_disable_irq(drm_i915_private_t *dev_priv, u32 mask)
{
if ((dev_priv->irq_mask_reg & mask) != mask) {
@@ -278,10 +278,9 @@ static void i915_handle_rps_change(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 busy_up, busy_down, max_avg, min_avg;
- u16 rgvswctl;
u8 new_delay = dev_priv->cur_delay;
- I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS) & ~MEMINT_EVAL_CHG);
+ I915_WRITE16(MEMINTRSTS, MEMINT_EVAL_CHG);
busy_up = I915_READ(RCPREVBSYTUPAVG);
busy_down = I915_READ(RCPREVBSYTDNAVG);
max_avg = I915_READ(RCBMAXAVG);
@@ -300,27 +299,8 @@ static void i915_handle_rps_change(struct drm_device *dev)
new_delay = dev_priv->min_delay;
}
- DRM_DEBUG("rps change requested: %d -> %d\n",
- dev_priv->cur_delay, new_delay);
-
- rgvswctl = I915_READ(MEMSWCTL);
- if (rgvswctl & MEMCTL_CMD_STS) {
- DRM_ERROR("gpu busy, RCS change rejected\n");
- return; /* still busy with another command */
- }
-
- /* Program the new state */
- rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
- (new_delay << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
- I915_WRITE(MEMSWCTL, rgvswctl);
- POSTING_READ(MEMSWCTL);
-
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE(MEMSWCTL, rgvswctl);
-
- dev_priv->cur_delay = new_delay;
-
- DRM_DEBUG("rps changed\n");
+ if (ironlake_set_drps(dev, new_delay))
+ dev_priv->cur_delay = new_delay;
return;
}
@@ -331,6 +311,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
int ret = IRQ_NONE;
u32 de_iir, gt_iir, de_ier, pch_iir;
struct drm_i915_master_private *master_priv;
+ struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
/* disable master interrupt before clearing iir */
de_ier = I915_READ(DEIER);
@@ -354,13 +335,16 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
}
if (gt_iir & GT_PIPE_NOTIFY) {
- u32 seqno = i915_get_gem_seqno(dev);
- dev_priv->mm.irq_gem_seqno = seqno;
+ u32 seqno = render_ring->get_gem_seqno(dev, render_ring);
+ render_ring->irq_gem_seqno = seqno;
trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->irq_queue);
+ DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
}
+ if (gt_iir & GT_BSD_USER_INTERRUPT)
+ DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+
if (de_iir & DE_GSE)
ironlake_opregion_gse_intr(dev);
@@ -388,7 +372,7 @@ irqreturn_t ironlake_irq_handler(struct drm_device *dev)
}
if (de_iir & DE_PCU_EVENT) {
- I915_WRITE(MEMINTRSTS, I915_READ(MEMINTRSTS));
+ I915_WRITE16(MEMINTRSTS, I915_READ(MEMINTRSTS));
i915_handle_rps_change(dev);
}
@@ -536,17 +520,18 @@ i915_ringbuffer_last_batch(struct drm_device *dev)
*/
bbaddr = 0;
head = I915_READ(PRB0_HEAD) & HEAD_ADDR;
- ring = (u32 *)(dev_priv->ring.virtual_start + head);
+ ring = (u32 *)(dev_priv->render_ring.virtual_start + head);
- while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
+ while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
bbaddr = i915_get_bbaddr(dev, ring);
if (bbaddr)
break;
}
if (bbaddr == 0) {
- ring = (u32 *)(dev_priv->ring.virtual_start + dev_priv->ring.Size);
- while (--ring >= (u32 *)dev_priv->ring.virtual_start) {
+ ring = (u32 *)(dev_priv->render_ring.virtual_start
+ + dev_priv->render_ring.size);
+ while (--ring >= (u32 *)dev_priv->render_ring.virtual_start) {
bbaddr = i915_get_bbaddr(dev, ring);
if (bbaddr)
break;
@@ -587,7 +572,7 @@ static void i915_capture_error_state(struct drm_device *dev)
return;
}
- error->seqno = i915_get_gem_seqno(dev);
+ error->seqno = i915_get_gem_seqno(dev, &dev_priv->render_ring);
error->eir = I915_READ(EIR);
error->pgtbl_er = I915_READ(PGTBL_ER);
error->pipeastat = I915_READ(PIPEASTAT);
@@ -615,7 +600,9 @@ static void i915_capture_error_state(struct drm_device *dev)
batchbuffer[0] = NULL;
batchbuffer[1] = NULL;
count = 0;
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
+ list_for_each_entry(obj_priv,
+ &dev_priv->render_ring.active_list, list) {
+
struct drm_gem_object *obj = &obj_priv->base;
if (batchbuffer[0] == NULL &&
@@ -639,7 +626,8 @@ static void i915_capture_error_state(struct drm_device *dev)
error->batchbuffer[1] = i915_error_object_create(dev, batchbuffer[1]);
/* Record the ringbuffer */
- error->ringbuffer = i915_error_object_create(dev, dev_priv->ring.ring_obj);
+ error->ringbuffer = i915_error_object_create(dev,
+ dev_priv->render_ring.gem_object);
/* Record buffers on the active list. */
error->active_bo = NULL;
@@ -651,7 +639,8 @@ static void i915_capture_error_state(struct drm_device *dev)
if (error->active_bo) {
int i = 0;
- list_for_each_entry(obj_priv, &dev_priv->mm.active_list, list) {
+ list_for_each_entry(obj_priv,
+ &dev_priv->render_ring.active_list, list) {
struct drm_gem_object *obj = &obj_priv->base;
error->active_bo[i].size = obj->size;
@@ -703,24 +692,13 @@ void i915_destroy_error_state(struct drm_device *dev)
i915_error_state_free(dev, error);
}
-/**
- * i915_handle_error - handle an error interrupt
- * @dev: drm device
- *
- * Do some basic checking of regsiter state at error interrupt time and
- * dump it to the syslog. Also call i915_capture_error_state() to make
- * sure we get a record and make it available in debugfs. Fire a uevent
- * so userspace knows something bad happened (should trigger collection
- * of a ring dump etc.).
- */
-static void i915_handle_error(struct drm_device *dev, bool wedged)
+static void i915_report_and_clear_eir(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 eir = I915_READ(EIR);
- u32 pipea_stats = I915_READ(PIPEASTAT);
- u32 pipeb_stats = I915_READ(PIPEBSTAT);
- i915_capture_error_state(dev);
+ if (!eir)
+ return;
printk(KERN_ERR "render error detected, EIR: 0x%08x\n",
eir);
@@ -766,6 +744,9 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
}
if (eir & I915_ERROR_MEMORY_REFRESH) {
+ u32 pipea_stats = I915_READ(PIPEASTAT);
+ u32 pipeb_stats = I915_READ(PIPEBSTAT);
+
printk(KERN_ERR "memory refresh error\n");
printk(KERN_ERR "PIPEASTAT: 0x%08x\n",
pipea_stats);
@@ -822,6 +803,24 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
I915_WRITE(EMR, I915_READ(EMR) | eir);
I915_WRITE(IIR, I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT);
}
+}
+
+/**
+ * i915_handle_error - handle an error interrupt
+ * @dev: drm device
+ *
+ * Do some basic checking of regsiter state at error interrupt time and
+ * dump it to the syslog. Also call i915_capture_error_state() to make
+ * sure we get a record and make it available in debugfs. Fire a uevent
+ * so userspace knows something bad happened (should trigger collection
+ * of a ring dump etc.).
+ */
+static void i915_handle_error(struct drm_device *dev, bool wedged)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ i915_capture_error_state(dev);
+ i915_report_and_clear_eir(dev);
if (wedged) {
atomic_set(&dev_priv->mm.wedged, 1);
@@ -829,7 +828,7 @@ static void i915_handle_error(struct drm_device *dev, bool wedged)
/*
* Wakeup waiting processes so they don't hang
*/
- DRM_WAKEUP(&dev_priv->irq_queue);
+ DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
}
queue_work(dev_priv->wq, &dev_priv->error_work);
@@ -848,6 +847,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
unsigned long irqflags;
int irq_received;
int ret = IRQ_NONE;
+ struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
atomic_inc(&dev_priv->irq_received);
@@ -928,14 +928,18 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
}
if (iir & I915_USER_INTERRUPT) {
- u32 seqno = i915_get_gem_seqno(dev);
- dev_priv->mm.irq_gem_seqno = seqno;
+ u32 seqno =
+ render_ring->get_gem_seqno(dev, render_ring);
+ render_ring->irq_gem_seqno = seqno;
trace_i915_gem_request_complete(dev, seqno);
- DRM_WAKEUP(&dev_priv->irq_queue);
+ DRM_WAKEUP(&dev_priv->render_ring.irq_queue);
dev_priv->hangcheck_count = 0;
mod_timer(&dev_priv->hangcheck_timer, jiffies + DRM_I915_HANGCHECK_PERIOD);
}
+ if (HAS_BSD(dev) && (iir & I915_BSD_USER_INTERRUPT))
+ DRM_WAKEUP(&dev_priv->bsd_ring.irq_queue);
+
if (iir & I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT)
intel_prepare_page_flip(dev, 0);
@@ -984,7 +988,6 @@ static int i915_emit_irq(struct drm_device * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
- RING_LOCALS;
i915_kernel_lost_context(dev);
@@ -1006,43 +1009,13 @@ static int i915_emit_irq(struct drm_device * dev)
return dev_priv->counter;
}
-void i915_user_irq_get(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long irqflags;
-
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- if (dev->irq_enabled && (++dev_priv->user_irq_refcount == 1)) {
- if (HAS_PCH_SPLIT(dev))
- ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
- else
- i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
- }
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
-}
-
-void i915_user_irq_put(struct drm_device *dev)
-{
- drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- unsigned long irqflags;
-
- spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
- BUG_ON(dev->irq_enabled && dev_priv->user_irq_refcount <= 0);
- if (dev->irq_enabled && (--dev_priv->user_irq_refcount == 0)) {
- if (HAS_PCH_SPLIT(dev))
- ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
- else
- i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
- }
- spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
-}
-
void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
if (dev_priv->trace_irq_seqno == 0)
- i915_user_irq_get(dev);
+ render_ring->user_irq_get(dev, render_ring);
dev_priv->trace_irq_seqno = seqno;
}
@@ -1052,6 +1025,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
int ret = 0;
+ struct intel_ring_buffer *render_ring = &dev_priv->render_ring;
DRM_DEBUG_DRIVER("irq_nr=%d breadcrumb=%d\n", irq_nr,
READ_BREADCRUMB(dev_priv));
@@ -1065,10 +1039,10 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
if (master_priv->sarea_priv)
master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
- i915_user_irq_get(dev);
- DRM_WAIT_ON(ret, dev_priv->irq_queue, 3 * DRM_HZ,
+ render_ring->user_irq_get(dev, render_ring);
+ DRM_WAIT_ON(ret, dev_priv->render_ring.irq_queue, 3 * DRM_HZ,
READ_BREADCRUMB(dev_priv) >= irq_nr);
- i915_user_irq_put(dev);
+ render_ring->user_irq_put(dev, render_ring);
if (ret == -EBUSY) {
DRM_ERROR("EBUSY -- rec: %d emitted: %d\n",
@@ -1087,7 +1061,7 @@ int i915_irq_emit(struct drm_device *dev, void *data,
drm_i915_irq_emit_t *emit = data;
int result;
- if (!dev_priv || !dev_priv->ring.virtual_start) {
+ if (!dev_priv || !dev_priv->render_ring.virtual_start) {
DRM_ERROR("called with no initialization\n");
return -EINVAL;
}
@@ -1233,9 +1207,12 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
return -EINVAL;
}
-struct drm_i915_gem_request *i915_get_tail_request(struct drm_device *dev) {
+struct drm_i915_gem_request *
+i915_get_tail_request(struct drm_device *dev)
+{
drm_i915_private_t *dev_priv = dev->dev_private;
- return list_entry(dev_priv->mm.request_list.prev, struct drm_i915_gem_request, list);
+ return list_entry(dev_priv->render_ring.request_list.prev,
+ struct drm_i915_gem_request, list);
}
/**
@@ -1260,8 +1237,10 @@ void i915_hangcheck_elapsed(unsigned long data)
acthd = I915_READ(ACTHD_I965);
/* If all work is done then ACTHD clearly hasn't advanced. */
- if (list_empty(&dev_priv->mm.request_list) ||
- i915_seqno_passed(i915_get_gem_seqno(dev), i915_get_tail_request(dev)->seqno)) {
+ if (list_empty(&dev_priv->render_ring.request_list) ||
+ i915_seqno_passed(i915_get_gem_seqno(dev,
+ &dev_priv->render_ring),
+ i915_get_tail_request(dev)->seqno)) {
dev_priv->hangcheck_count = 0;
return;
}
@@ -1314,7 +1293,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
/* enable kind of interrupts always enabled */
u32 display_mask = DE_MASTER_IRQ_CONTROL | DE_GSE | DE_PCH_EVENT |
DE_PLANEA_FLIP_DONE | DE_PLANEB_FLIP_DONE;
- u32 render_mask = GT_PIPE_NOTIFY;
+ u32 render_mask = GT_PIPE_NOTIFY | GT_BSD_USER_INTERRUPT;
u32 hotplug_mask = SDE_CRT_HOTPLUG | SDE_PORTB_HOTPLUG |
SDE_PORTC_HOTPLUG | SDE_PORTD_HOTPLUG;
@@ -1328,7 +1307,7 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
(void) I915_READ(DEIER);
/* user interrupt should be enabled, but masked initial */
- dev_priv->gt_irq_mask_reg = 0xffffffff;
+ dev_priv->gt_irq_mask_reg = ~render_mask;
dev_priv->gt_irq_enable_reg = render_mask;
I915_WRITE(GTIIR, I915_READ(GTIIR));
@@ -1391,7 +1370,10 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
u32 enable_mask = I915_INTERRUPT_ENABLE_FIX | I915_INTERRUPT_ENABLE_VAR;
u32 error_mask;
- DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
+ DRM_INIT_WAITQUEUE(&dev_priv->render_ring.irq_queue);
+
+ if (HAS_BSD(dev))
+ DRM_INIT_WAITQUEUE(&dev_priv->bsd_ring.irq_queue);
dev_priv->vblank_pipe = DRM_I915_VBLANK_PIPE_A | DRM_I915_VBLANK_PIPE_B;
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index f3e39cc46f0d..64b0a3afd92b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -334,6 +334,7 @@
#define I915_DEBUG_INTERRUPT (1<<2)
#define I915_USER_INTERRUPT (1<<1)
#define I915_ASLE_INTERRUPT (1<<0)
+#define I915_BSD_USER_INTERRUPT (1<<25)
#define EIR 0x020b0
#define EMR 0x020b4
#define ESR 0x020b8
@@ -368,6 +369,36 @@
#define BB_ADDR 0x02140 /* 8 bytes */
#define GFX_FLSH_CNTL 0x02170 /* 915+ only */
+/* GEN6 interrupt control */
+#define GEN6_RENDER_HWSTAM 0x2098
+#define GEN6_RENDER_IMR 0x20a8
+#define GEN6_RENDER_CONTEXT_SWITCH_INTERRUPT (1 << 8)
+#define GEN6_RENDER_PPGTT_PAGE_FAULT (1 << 7)
+#define GEN6_RENDER TIMEOUT_COUNTER_EXPIRED (1 << 6)
+#define GEN6_RENDER_L3_PARITY_ERROR (1 << 5)
+#define GEN6_RENDER_PIPE_CONTROL_NOTIFY_INTERRUPT (1 << 4)
+#define GEN6_RENDER_COMMAND_PARSER_MASTER_ERROR (1 << 3)
+#define GEN6_RENDER_SYNC_STATUS (1 << 2)
+#define GEN6_RENDER_DEBUG_INTERRUPT (1 << 1)
+#define GEN6_RENDER_USER_INTERRUPT (1 << 0)
+
+#define GEN6_BLITTER_HWSTAM 0x22098
+#define GEN6_BLITTER_IMR 0x220a8
+#define GEN6_BLITTER_MI_FLUSH_DW_NOTIFY_INTERRUPT (1 << 26)
+#define GEN6_BLITTER_COMMAND_PARSER_MASTER_ERROR (1 << 25)
+#define GEN6_BLITTER_SYNC_STATUS (1 << 24)
+#define GEN6_BLITTER_USER_INTERRUPT (1 << 22)
+/*
+ * BSD (bit stream decoder instruction and interrupt control register defines
+ * (G4X and Ironlake only)
+ */
+
+#define BSD_RING_TAIL 0x04030
+#define BSD_RING_HEAD 0x04034
+#define BSD_RING_START 0x04038
+#define BSD_RING_CTL 0x0403c
+#define BSD_RING_ACTHD 0x04074
+#define BSD_HWS_PGA 0x04080
/*
* Framebuffer compression (915+ only)
@@ -805,6 +836,10 @@
#define DCC_CHANNEL_XOR_DISABLE (1 << 10)
#define DCC_CHANNEL_XOR_BIT_17 (1 << 9)
+/** Pineview MCH register contains DDR3 setting */
+#define CSHRDDR3CTL 0x101a8
+#define CSHRDDR3CTL_DDR3 (1 << 2)
+
/** 965 MCH register controlling DRAM channel configuration */
#define C0DRB3 0x10206
#define C1DRB3 0x10606
@@ -826,6 +861,12 @@
#define CLKCFG_MEM_800 (3 << 4)
#define CLKCFG_MEM_MASK (7 << 4)
+#define TR1 0x11006
+#define TSFS 0x11020
+#define TSFS_SLOPE_MASK 0x0000ff00
+#define TSFS_SLOPE_SHIFT 8
+#define TSFS_INTR_MASK 0x000000ff
+
#define CRSTANDVID 0x11100
#define PXVFREQ_BASE 0x11110 /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */
#define PXVFREQ_PX_MASK 0x7f000000
@@ -964,6 +1005,41 @@
#define MEMSTAT_SRC_CTL_STDBY 3
#define RCPREVBSYTUPAVG 0x113b8
#define RCPREVBSYTDNAVG 0x113bc
+#define SDEW 0x1124c
+#define CSIEW0 0x11250
+#define CSIEW1 0x11254
+#define CSIEW2 0x11258
+#define PEW 0x1125c
+#define DEW 0x11270
+#define MCHAFE 0x112c0
+#define CSIEC 0x112e0
+#define DMIEC 0x112e4
+#define DDREC 0x112e8
+#define PEG0EC 0x112ec
+#define PEG1EC 0x112f0
+#define GFXEC 0x112f4
+#define RPPREVBSYTUPAVG 0x113b8
+#define RPPREVBSYTDNAVG 0x113bc
+#define ECR 0x11600
+#define ECR_GPFE (1<<31)
+#define ECR_IMONE (1<<30)
+#define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */
+#define OGW0 0x11608
+#define OGW1 0x1160c
+#define EG0 0x11610
+#define EG1 0x11614
+#define EG2 0x11618
+#define EG3 0x1161c
+#define EG4 0x11620
+#define EG5 0x11624
+#define EG6 0x11628
+#define EG7 0x1162c
+#define PXW 0x11664
+#define PXWL 0x11680
+#define LCFUSE02 0x116c0
+#define LCFUSE_HIV_MASK 0x000000ff
+#define CSIPLL0 0x12c10
+#define DDRMPLL1 0X12c20
#define PEG_BAND_GAP_DATA 0x14d68
/*
@@ -1055,7 +1131,6 @@
#define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2)
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
-#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f
#define PORT_HOTPLUG_STAT 0x61114
#define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
@@ -2355,6 +2430,8 @@
#define GT_PIPE_NOTIFY (1 << 4)
#define GT_SYNC_STATUS (1 << 2)
#define GT_USER_INTERRUPT (1 << 0)
+#define GT_BSD_USER_INTERRUPT (1 << 5)
+
#define GTISR 0x44010
#define GTIMR 0x44014
@@ -2690,6 +2767,9 @@
#define SDVO_ENCODING (0)
#define TMDS_ENCODING (2 << 10)
#define NULL_PACKET_VSYNC_ENABLE (1 << 9)
+/* CPT */
+#define HDMI_MODE_SELECT (1 << 9)
+#define DVI_MODE_SELECT (0)
#define SDVOB_BORDER_ENABLE (1 << 7)
#define AUDIO_ENABLE (1 << 6)
#define VSYNC_ACTIVE_HIGH (1 << 4)
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 9e4c45f68d6e..fab21760dd57 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -53,23 +53,6 @@ TRACE_EVENT(i915_gem_object_bind,
__entry->obj, __entry->gtt_offset)
);
-TRACE_EVENT(i915_gem_object_clflush,
-
- TP_PROTO(struct drm_gem_object *obj),
-
- TP_ARGS(obj),
-
- TP_STRUCT__entry(
- __field(struct drm_gem_object *, obj)
- ),
-
- TP_fast_assign(
- __entry->obj = obj;
- ),
-
- TP_printk("obj=%p", __entry->obj)
-);
-
TRACE_EVENT(i915_gem_object_change_domain,
TP_PROTO(struct drm_gem_object *obj, uint32_t old_read_domains, uint32_t old_write_domain),
@@ -132,6 +115,13 @@ DECLARE_EVENT_CLASS(i915_gem_object,
TP_printk("obj=%p", __entry->obj)
);
+DEFINE_EVENT(i915_gem_object, i915_gem_object_clflush,
+
+ TP_PROTO(struct drm_gem_object *obj),
+
+ TP_ARGS(obj)
+);
+
DEFINE_EVENT(i915_gem_object, i915_gem_object_unbind,
TP_PROTO(struct drm_gem_object *obj),
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 4c748d8f73d6..96f75d7f6633 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -95,6 +95,16 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
panel_fixed_mode->clock = dvo_timing->clock * 10;
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
+ if (dvo_timing->hsync_positive)
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+ else
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_NHSYNC;
+
+ if (dvo_timing->vsync_positive)
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+ else
+ panel_fixed_mode->flags |= DRM_MODE_FLAG_NVSYNC;
+
/* Some VBTs have bogus h/vtotal values */
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index e16ac5a28c3c..22ff38455731 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -217,7 +217,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 hotplug_en;
+ u32 hotplug_en, orig, stat;
+ bool ret = false;
int i, tries = 0;
if (HAS_PCH_SPLIT(dev))
@@ -232,8 +233,8 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
tries = 2;
else
tries = 1;
- hotplug_en = I915_READ(PORT_HOTPLUG_EN);
- hotplug_en &= CRT_FORCE_HOTPLUG_MASK;
+ hotplug_en = orig = I915_READ(PORT_HOTPLUG_EN);
+ hotplug_en &= CRT_HOTPLUG_MASK;
hotplug_en |= CRT_HOTPLUG_FORCE_DETECT;
if (IS_G4X(dev))
@@ -255,11 +256,17 @@ static bool intel_crt_detect_hotplug(struct drm_connector *connector)
} while (time_after(timeout, jiffies));
}
- if ((I915_READ(PORT_HOTPLUG_STAT) & CRT_HOTPLUG_MONITOR_MASK) !=
- CRT_HOTPLUG_MONITOR_NONE)
- return true;
+ stat = I915_READ(PORT_HOTPLUG_STAT);
+ if ((stat & CRT_HOTPLUG_MONITOR_MASK) != CRT_HOTPLUG_MONITOR_NONE)
+ ret = true;
+
+ /* clear the interrupt we just generated, if any */
+ I915_WRITE(PORT_HOTPLUG_STAT, CRT_HOTPLUG_INT_STATUS);
- return false;
+ /* and put the bits back */
+ I915_WRITE(PORT_HOTPLUG_EN, orig);
+
+ return ret;
}
static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
@@ -569,7 +576,7 @@ void intel_crt_init(struct drm_device *dev)
(1 << INTEL_ANALOG_CLONE_BIT) |
(1 << INTEL_SDVO_LVDS_CLONE_BIT);
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
- connector->interlace_allowed = 0;
+ connector->interlace_allowed = 1;
connector->doublescan_allowed = 0;
drm_encoder_helper_add(&intel_encoder->enc, &intel_crt_helper_funcs);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f469a84cacfd..04e1bb499ff8 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1029,19 +1029,28 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
void i8xx_disable_fbc(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
u32 fbc_ctl;
if (!I915_HAS_FBC(dev))
return;
+ if (!(I915_READ(FBC_CONTROL) & FBC_CTL_EN))
+ return; /* Already off, just return */
+
/* Disable compression */
fbc_ctl = I915_READ(FBC_CONTROL);
fbc_ctl &= ~FBC_CTL_EN;
I915_WRITE(FBC_CONTROL, fbc_ctl);
/* Wait for compressing bit to clear */
- while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING)
- ; /* nothing */
+ while (I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) {
+ if (time_after(jiffies, timeout)) {
+ DRM_DEBUG_DRIVER("FBC idle timed out\n");
+ break;
+ }
+ ; /* do nothing */
+ }
intel_wait_for_vblank(dev);
@@ -1239,10 +1248,11 @@ static void intel_update_fbc(struct drm_crtc *crtc,
return;
out_disable:
- DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
/* Multiple disables should be harmless */
- if (intel_fbc_enabled(dev))
+ if (intel_fbc_enabled(dev)) {
+ DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
intel_disable_fbc(dev);
+ }
}
static int
@@ -1386,7 +1396,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
Start = obj_priv->gtt_offset;
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
- DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+ DRM_DEBUG_KMS("Writing base %08lX %08lX %d %d %d\n",
+ Start, Offset, x, y, crtc->fb->pitch);
I915_WRITE(dspstride, crtc->fb->pitch);
if (IS_I965G(dev)) {
I915_WRITE(dspbase, Offset);
@@ -2345,6 +2356,8 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
if (mode->clock * 3 > 27000 * 4)
return MODE_CLOCK_HIGH;
}
+
+ drm_mode_set_crtcinfo(adjusted_mode, 0);
return true;
}
@@ -2629,6 +2642,7 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
struct cxsr_latency {
int is_desktop;
+ int is_ddr3;
unsigned long fsb_freq;
unsigned long mem_freq;
unsigned long display_sr;
@@ -2638,33 +2652,45 @@ struct cxsr_latency {
};
static struct cxsr_latency cxsr_latency_table[] = {
- {1, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
- {1, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
- {1, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
-
- {1, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
- {1, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
- {1, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
-
- {1, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
- {1, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
- {1, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
-
- {0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
- {0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
- {0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
-
- {0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
- {0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
- {0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
-
- {0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
- {0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
- {0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
+ {1, 0, 800, 400, 3382, 33382, 3983, 33983}, /* DDR2-400 SC */
+ {1, 0, 800, 667, 3354, 33354, 3807, 33807}, /* DDR2-667 SC */
+ {1, 0, 800, 800, 3347, 33347, 3763, 33763}, /* DDR2-800 SC */
+ {1, 1, 800, 667, 6420, 36420, 6873, 36873}, /* DDR3-667 SC */
+ {1, 1, 800, 800, 5902, 35902, 6318, 36318}, /* DDR3-800 SC */
+
+ {1, 0, 667, 400, 3400, 33400, 4021, 34021}, /* DDR2-400 SC */
+ {1, 0, 667, 667, 3372, 33372, 3845, 33845}, /* DDR2-667 SC */
+ {1, 0, 667, 800, 3386, 33386, 3822, 33822}, /* DDR2-800 SC */
+ {1, 1, 667, 667, 6438, 36438, 6911, 36911}, /* DDR3-667 SC */
+ {1, 1, 667, 800, 5941, 35941, 6377, 36377}, /* DDR3-800 SC */
+
+ {1, 0, 400, 400, 3472, 33472, 4173, 34173}, /* DDR2-400 SC */
+ {1, 0, 400, 667, 3443, 33443, 3996, 33996}, /* DDR2-667 SC */
+ {1, 0, 400, 800, 3430, 33430, 3946, 33946}, /* DDR2-800 SC */
+ {1, 1, 400, 667, 6509, 36509, 7062, 37062}, /* DDR3-667 SC */
+ {1, 1, 400, 800, 5985, 35985, 6501, 36501}, /* DDR3-800 SC */
+
+ {0, 0, 800, 400, 3438, 33438, 4065, 34065}, /* DDR2-400 SC */
+ {0, 0, 800, 667, 3410, 33410, 3889, 33889}, /* DDR2-667 SC */
+ {0, 0, 800, 800, 3403, 33403, 3845, 33845}, /* DDR2-800 SC */
+ {0, 1, 800, 667, 6476, 36476, 6955, 36955}, /* DDR3-667 SC */
+ {0, 1, 800, 800, 5958, 35958, 6400, 36400}, /* DDR3-800 SC */
+
+ {0, 0, 667, 400, 3456, 33456, 4103, 34106}, /* DDR2-400 SC */
+ {0, 0, 667, 667, 3428, 33428, 3927, 33927}, /* DDR2-667 SC */
+ {0, 0, 667, 800, 3443, 33443, 3905, 33905}, /* DDR2-800 SC */
+ {0, 1, 667, 667, 6494, 36494, 6993, 36993}, /* DDR3-667 SC */
+ {0, 1, 667, 800, 5998, 35998, 6460, 36460}, /* DDR3-800 SC */
+
+ {0, 0, 400, 400, 3528, 33528, 4255, 34255}, /* DDR2-400 SC */
+ {0, 0, 400, 667, 3500, 33500, 4079, 34079}, /* DDR2-667 SC */
+ {0, 0, 400, 800, 3487, 33487, 4029, 34029}, /* DDR2-800 SC */
+ {0, 1, 400, 667, 6566, 36566, 7145, 37145}, /* DDR3-667 SC */
+ {0, 1, 400, 800, 6042, 36042, 6584, 36584}, /* DDR3-800 SC */
};
-static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
- int mem)
+static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int is_ddr3,
+ int fsb, int mem)
{
int i;
struct cxsr_latency *latency;
@@ -2675,6 +2701,7 @@ static struct cxsr_latency *intel_get_cxsr_latency(int is_desktop, int fsb,
for (i = 0; i < ARRAY_SIZE(cxsr_latency_table); i++) {
latency = &cxsr_latency_table[i];
if (is_desktop == latency->is_desktop &&
+ is_ddr3 == latency->is_ddr3 &&
fsb == latency->fsb_freq && mem == latency->mem_freq)
return latency;
}
@@ -2789,8 +2816,8 @@ static void pineview_update_wm(struct drm_device *dev, int planea_clock,
struct cxsr_latency *latency;
int sr_clock;
- latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->fsb_freq,
- dev_priv->mem_freq);
+ latency = intel_get_cxsr_latency(IS_PINEVIEW_G(dev), dev_priv->is_ddr3,
+ dev_priv->fsb_freq, dev_priv->mem_freq);
if (!latency) {
DRM_DEBUG_KMS("Unknown FSB/MEM found, disable CxSR\n");
pineview_disable_cxsr(dev);
@@ -3772,6 +3799,18 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
}
}
+ if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+ pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+ /* the chip adds 2 halflines automatically */
+ adjusted_mode->crtc_vdisplay -= 1;
+ adjusted_mode->crtc_vtotal -= 1;
+ adjusted_mode->crtc_vblank_start -= 1;
+ adjusted_mode->crtc_vblank_end -= 1;
+ adjusted_mode->crtc_vsync_end -= 1;
+ adjusted_mode->crtc_vsync_start -= 1;
+ } else
+ pipeconf &= ~PIPECONF_INTERLACE_W_FIELD_INDICATION; /* progressive */
+
I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
((adjusted_mode->crtc_htotal - 1) << 16));
I915_WRITE(hblank_reg, (adjusted_mode->crtc_hblank_start - 1) |
@@ -3934,6 +3973,13 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
DRM_ERROR("failed to pin cursor bo\n");
goto fail_locked;
}
+
+ ret = i915_gem_object_set_to_gtt_domain(bo, 0);
+ if (ret) {
+ DRM_ERROR("failed to move cursor bo into the GTT\n");
+ goto fail_unpin;
+ }
+
addr = obj_priv->gtt_offset;
} else {
ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
@@ -3977,6 +4023,8 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
intel_crtc->cursor_bo = bo;
return 0;
+fail_unpin:
+ i915_gem_object_unpin(bo);
fail_locked:
mutex_unlock(&dev->struct_mutex);
fail:
@@ -4436,6 +4484,8 @@ static void intel_idle_update(struct work_struct *work)
mutex_lock(&dev->struct_mutex);
+ i915_update_gfx_val(dev_priv);
+
if (IS_I945G(dev) || IS_I945GM(dev)) {
DRM_DEBUG_DRIVER("enable memory self refresh on 945\n");
I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
@@ -4564,12 +4614,6 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
spin_lock_irqsave(&dev->event_lock, flags);
work = intel_crtc->unpin_work;
if (work == NULL || !work->pending) {
- if (work && !work->pending) {
- obj_priv = to_intel_bo(work->pending_flip_obj);
- DRM_DEBUG_DRIVER("flip finish: %p (%d) not pending?\n",
- obj_priv,
- atomic_read(&obj_priv->pending_flip));
- }
spin_unlock_irqrestore(&dev->event_lock, flags);
return;
}
@@ -4629,14 +4673,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
unsigned long flags;
int pipesrc_reg = (intel_crtc->pipe == 0) ? PIPEASRC : PIPEBSRC;
int ret, pipesrc;
- RING_LOCALS;
work = kzalloc(sizeof *work, GFP_KERNEL);
if (work == NULL)
return -ENOMEM;
- mutex_lock(&dev->struct_mutex);
-
work->event = event;
work->dev = crtc->dev;
intel_fb = to_intel_framebuffer(crtc->fb);
@@ -4646,10 +4687,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
/* We borrow the event spin lock for protecting unpin_work */
spin_lock_irqsave(&dev->event_lock, flags);
if (intel_crtc->unpin_work) {
- DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(work);
- mutex_unlock(&dev->struct_mutex);
+
+ DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
return -EBUSY;
}
intel_crtc->unpin_work = work;
@@ -4658,13 +4699,19 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
intel_fb = to_intel_framebuffer(fb);
obj = intel_fb->obj;
+ mutex_lock(&dev->struct_mutex);
ret = intel_pin_and_fence_fb_obj(dev, obj);
if (ret != 0) {
- DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
- to_intel_bo(obj));
- kfree(work);
- intel_crtc->unpin_work = NULL;
mutex_unlock(&dev->struct_mutex);
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ intel_crtc->unpin_work = NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ kfree(work);
+
+ DRM_DEBUG_DRIVER("flip queue: %p pin & fence failed\n",
+ to_intel_bo(obj));
return ret;
}
@@ -5023,10 +5070,32 @@ err_unref:
return NULL;
}
+bool ironlake_set_drps(struct drm_device *dev, u8 val)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u16 rgvswctl;
+
+ rgvswctl = I915_READ16(MEMSWCTL);
+ if (rgvswctl & MEMCTL_CMD_STS) {
+ DRM_DEBUG("gpu busy, RCS change rejected\n");
+ return false; /* still busy with another command */
+ }
+
+ rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
+ (val << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+ POSTING_READ16(MEMSWCTL);
+
+ rgvswctl |= MEMCTL_CMD_STS;
+ I915_WRITE16(MEMSWCTL, rgvswctl);
+
+ return true;
+}
+
void ironlake_enable_drps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 rgvmodectl = I915_READ(MEMMODECTL), rgvswctl;
+ u32 rgvmodectl = I915_READ(MEMMODECTL);
u8 fmax, fmin, fstart, vstart;
int i = 0;
@@ -5045,13 +5114,21 @@ void ironlake_enable_drps(struct drm_device *dev)
fmin = (rgvmodectl & MEMMODE_FMIN_MASK);
fstart = (rgvmodectl & MEMMODE_FSTART_MASK) >>
MEMMODE_FSTART_SHIFT;
+ fstart = fmax;
+
vstart = (I915_READ(PXVFREQ_BASE + (fstart * 4)) & PXVFREQ_PX_MASK) >>
PXVFREQ_PX_SHIFT;
- dev_priv->max_delay = fstart; /* can't go to fmax w/o IPS */
+ dev_priv->fmax = fstart; /* IPS callback will increase this */
+ dev_priv->fstart = fstart;
+
+ dev_priv->max_delay = fmax;
dev_priv->min_delay = fmin;
dev_priv->cur_delay = fstart;
+ DRM_DEBUG_DRIVER("fmax: %d, fmin: %d, fstart: %d\n", fmax, fmin,
+ fstart);
+
I915_WRITE(MEMINTREN, MEMINT_CX_SUPR_EN | MEMINT_EVAL_CHG_EN);
/*
@@ -5073,20 +5150,19 @@ void ironlake_enable_drps(struct drm_device *dev)
}
msleep(1);
- rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
- (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
- I915_WRITE(MEMSWCTL, rgvswctl);
- POSTING_READ(MEMSWCTL);
+ ironlake_set_drps(dev, fstart);
- rgvswctl |= MEMCTL_CMD_STS;
- I915_WRITE(MEMSWCTL, rgvswctl);
+ dev_priv->last_count1 = I915_READ(0x112e4) + I915_READ(0x112e8) +
+ I915_READ(0x112e0);
+ dev_priv->last_time1 = jiffies_to_msecs(jiffies);
+ dev_priv->last_count2 = I915_READ(0x112f4);
+ getrawmonotonic(&dev_priv->last_time2);
}
void ironlake_disable_drps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- u32 rgvswctl;
- u8 fstart;
+ u16 rgvswctl = I915_READ16(MEMSWCTL);
/* Ack interrupts, disable EFC interrupt */
I915_WRITE(MEMINTREN, I915_READ(MEMINTREN) & ~MEMINT_EVAL_CHG_EN);
@@ -5096,11 +5172,7 @@ void ironlake_disable_drps(struct drm_device *dev)
I915_WRITE(DEIMR, I915_READ(DEIMR) | DE_PCU_EVENT);
/* Go back to the starting frequency */
- fstart = (I915_READ(MEMMODECTL) & MEMMODE_FSTART_MASK) >>
- MEMMODE_FSTART_SHIFT;
- rgvswctl = (MEMCTL_CMD_CHFREQ << MEMCTL_CMD_SHIFT) |
- (fstart << MEMCTL_FREQ_SHIFT) | MEMCTL_SFCAVM;
- I915_WRITE(MEMSWCTL, rgvswctl);
+ ironlake_set_drps(dev, dev_priv->fstart);
msleep(1);
rgvswctl |= MEMCTL_CMD_STS;
I915_WRITE(MEMSWCTL, rgvswctl);
@@ -5108,6 +5180,92 @@ void ironlake_disable_drps(struct drm_device *dev)
}
+static unsigned long intel_pxfreq(u32 vidfreq)
+{
+ unsigned long freq;
+ int div = (vidfreq & 0x3f0000) >> 16;
+ int post = (vidfreq & 0x3000) >> 12;
+ int pre = (vidfreq & 0x7);
+
+ if (!pre)
+ return 0;
+
+ freq = ((div * 133333) / ((1<<post) * pre));
+
+ return freq;
+}
+
+void intel_init_emon(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 lcfuse;
+ u8 pxw[16];
+ int i;
+
+ /* Disable to program */
+ I915_WRITE(ECR, 0);
+ POSTING_READ(ECR);
+
+ /* Program energy weights for various events */
+ I915_WRITE(SDEW, 0x15040d00);
+ I915_WRITE(CSIEW0, 0x007f0000);
+ I915_WRITE(CSIEW1, 0x1e220004);
+ I915_WRITE(CSIEW2, 0x04000004);
+
+ for (i = 0; i < 5; i++)
+ I915_WRITE(PEW + (i * 4), 0);
+ for (i = 0; i < 3; i++)
+ I915_WRITE(DEW + (i * 4), 0);
+
+ /* Program P-state weights to account for frequency power adjustment */
+ for (i = 0; i < 16; i++) {
+ u32 pxvidfreq = I915_READ(PXVFREQ_BASE + (i * 4));
+ unsigned long freq = intel_pxfreq(pxvidfreq);
+ unsigned long vid = (pxvidfreq & PXVFREQ_PX_MASK) >>
+ PXVFREQ_PX_SHIFT;
+ unsigned long val;
+
+ val = vid * vid;
+ val *= (freq / 1000);
+ val *= 255;
+ val /= (127*127*900);
+ if (val > 0xff)
+ DRM_ERROR("bad pxval: %ld\n", val);
+ pxw[i] = val;
+ }
+ /* Render standby states get 0 weight */
+ pxw[14] = 0;
+ pxw[15] = 0;
+
+ for (i = 0; i < 4; i++) {
+ u32 val = (pxw[i*4] << 24) | (pxw[(i*4)+1] << 16) |
+ (pxw[(i*4)+2] << 8) | (pxw[(i*4)+3]);
+ I915_WRITE(PXW + (i * 4), val);
+ }
+
+ /* Adjust magic regs to magic values (more experimental results) */
+ I915_WRITE(OGW0, 0);
+ I915_WRITE(OGW1, 0);
+ I915_WRITE(EG0, 0x00007f00);
+ I915_WRITE(EG1, 0x0000000e);
+ I915_WRITE(EG2, 0x000e0000);
+ I915_WRITE(EG3, 0x68000300);
+ I915_WRITE(EG4, 0x42000000);
+ I915_WRITE(EG5, 0x00140031);
+ I915_WRITE(EG6, 0);
+ I915_WRITE(EG7, 0);
+
+ for (i = 0; i < 8; i++)
+ I915_WRITE(PXWL + (i * 4), 0);
+
+ /* Enable PMON + select events */
+ I915_WRITE(ECR, 0x80000019);
+
+ lcfuse = I915_READ(LCFUSE02);
+
+ dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
+}
+
void intel_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5277,11 +5435,13 @@ static void intel_init_display(struct drm_device *dev)
dev_priv->display.update_wm = NULL;
} else if (IS_PINEVIEW(dev)) {
if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev),
+ dev_priv->is_ddr3,
dev_priv->fsb_freq,
dev_priv->mem_freq)) {
DRM_INFO("failed to find known CxSR latency "
- "(found fsb freq %d, mem freq %d), "
+ "(found ddr%s fsb freq %d, mem freq %d), "
"disabling CxSR\n",
+ (dev_priv->is_ddr3 == 1) ? "3": "2",
dev_priv->fsb_freq, dev_priv->mem_freq);
/* Disable CxSR and never update its watermark again */
pineview_disable_cxsr(dev);
@@ -5354,8 +5514,10 @@ void intel_modeset_init(struct drm_device *dev)
intel_init_clock_gating(dev);
- if (IS_IRONLAKE_M(dev))
+ if (IS_IRONLAKE_M(dev)) {
ironlake_enable_drps(dev);
+ intel_init_emon(dev);
+ }
INIT_WORK(&dev_priv->idle_work, intel_idle_update);
setup_timer(&dev_priv->idle_timer, intel_gpu_idle_timer,
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 6b1c9a27c27a..49b54f05d3cf 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -576,7 +576,7 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct intel_encoder *intel_encoder;
struct intel_dp_priv *dp_priv;
- if (!encoder || encoder->crtc != crtc)
+ if (encoder->crtc != crtc)
continue;
intel_encoder = enc_to_intel_encoder(encoder);
@@ -675,10 +675,9 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
dp_priv->link_configuration[1] = dp_priv->lane_count;
/*
- * Check for DPCD version > 1.1,
- * enable enahanced frame stuff in that case
+ * Check for DPCD version > 1.1 and enhanced framing support
*/
- if (dp_priv->dpcd[0] >= 0x11) {
+ if (dp_priv->dpcd[0] >= 0x11 && (dp_priv->dpcd[2] & DP_ENHANCED_FRAME_CAP)) {
dp_priv->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
dp_priv->DP |= DP_ENHANCED_FRAMING;
}
@@ -1208,6 +1207,8 @@ ironlake_dp_detect(struct drm_connector *connector)
if (dp_priv->dpcd[0] != 0)
status = connector_status_connected;
}
+ DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", dp_priv->dpcd[0],
+ dp_priv->dpcd[1], dp_priv->dpcd[2], dp_priv->dpcd[3]);
return status;
}
@@ -1352,7 +1353,7 @@ intel_trans_dp_port_sel (struct drm_crtc *crtc)
struct intel_encoder *intel_encoder = NULL;
list_for_each_entry(encoder, &mode_config->encoder_list, head) {
- if (!encoder || encoder->crtc != crtc)
+ if (encoder->crtc != crtc)
continue;
intel_encoder = enc_to_intel_encoder(encoder);
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 6f53cf7fbc50..f8c76e64bb77 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -105,7 +105,11 @@ static int intelfb_create(struct intel_fbdev *ifbdev,
}
/* Flush everything out, we'll be doing GTT only from now on */
- i915_gem_object_set_to_gtt_domain(fbo, 1);
+ ret = i915_gem_object_set_to_gtt_domain(fbo, 1);
+ if (ret) {
+ DRM_ERROR("failed to bind fb: %d.\n", ret);
+ goto out_unpin;
+ }
info = framebuffer_alloc(0, device);
if (!info) {
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 65727f0a79a3..83bd764b000e 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -59,8 +59,11 @@ static void intel_hdmi_mode_set(struct drm_encoder *encoder,
SDVO_VSYNC_ACTIVE_HIGH |
SDVO_HSYNC_ACTIVE_HIGH;
- if (hdmi_priv->has_hdmi_sink)
+ if (hdmi_priv->has_hdmi_sink) {
sdvox |= SDVO_AUDIO_ENABLE;
+ if (HAS_PCH_CPT(dev))
+ sdvox |= HDMI_MODE_SELECT;
+ }
if (intel_crtc->pipe == 1) {
if (HAS_PCH_CPT(dev))
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index b0e17b06eb6e..d7ad5139d17c 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -211,9 +211,8 @@ static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay)
static int intel_overlay_on(struct intel_overlay *overlay)
{
struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
- RING_LOCALS;
+ drm_i915_private_t *dev_priv = dev->dev_private;
BUG_ON(overlay->active);
@@ -227,11 +226,13 @@ static int intel_overlay_on(struct intel_overlay *overlay)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
- ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
+ ret = i915_do_wait_request(dev,
+ overlay->last_flip_req, 1, &dev_priv->render_ring);
if (ret != 0)
return ret;
@@ -248,7 +249,6 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
drm_i915_private_t *dev_priv = dev->dev_private;
u32 flip_addr = overlay->flip_addr;
u32 tmp;
- RING_LOCALS;
BUG_ON(!overlay->active);
@@ -265,7 +265,8 @@ static void intel_overlay_continue(struct intel_overlay *overlay,
OUT_RING(flip_addr);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
}
static int intel_overlay_wait_flip(struct intel_overlay *overlay)
@@ -274,10 +275,10 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay)
drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
u32 tmp;
- RING_LOCALS;
if (overlay->last_flip_req != 0) {
- ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
+ ret = i915_do_wait_request(dev, overlay->last_flip_req,
+ 1, &dev_priv->render_ring);
if (ret == 0) {
overlay->last_flip_req = 0;
@@ -296,11 +297,13 @@ static int intel_overlay_wait_flip(struct intel_overlay *overlay)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
- ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
+ ret = i915_do_wait_request(dev, overlay->last_flip_req,
+ 1, &dev_priv->render_ring);
if (ret != 0)
return ret;
@@ -314,9 +317,8 @@ static int intel_overlay_off(struct intel_overlay *overlay)
{
u32 flip_addr = overlay->flip_addr;
struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_private_t *dev_priv = dev->dev_private;
int ret;
- RING_LOCALS;
BUG_ON(!overlay->active);
@@ -336,11 +338,13 @@ static int intel_overlay_off(struct intel_overlay *overlay)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
- ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
+ ret = i915_do_wait_request(dev, overlay->last_flip_req,
+ 1, &dev_priv->render_ring);
if (ret != 0)
return ret;
@@ -354,11 +358,13 @@ static int intel_overlay_off(struct intel_overlay *overlay)
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
- ret = i915_do_wait_request(dev, overlay->last_flip_req, 1);
+ ret = i915_do_wait_request(dev, overlay->last_flip_req,
+ 1, &dev_priv->render_ring);
if (ret != 0)
return ret;
@@ -390,22 +396,23 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
int interruptible)
{
struct drm_device *dev = overlay->dev;
- drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_gem_object *obj;
+ drm_i915_private_t *dev_priv = dev->dev_private;
u32 flip_addr;
int ret;
- RING_LOCALS;
if (overlay->hw_wedged == HW_WEDGED)
return -EIO;
if (overlay->last_flip_req == 0) {
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req =
+ i915_add_request(dev, NULL, 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
}
- ret = i915_do_wait_request(dev, overlay->last_flip_req, interruptible);
+ ret = i915_do_wait_request(dev, overlay->last_flip_req,
+ interruptible, &dev_priv->render_ring);
if (ret != 0)
return ret;
@@ -429,12 +436,13 @@ int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay,
OUT_RING(MI_NOOP);
ADVANCE_LP_RING();
- overlay->last_flip_req = i915_add_request(dev, NULL, 0);
+ overlay->last_flip_req = i915_add_request(dev, NULL,
+ 0, &dev_priv->render_ring);
if (overlay->last_flip_req == 0)
return -ENOMEM;
ret = i915_do_wait_request(dev, overlay->last_flip_req,
- interruptible);
+ interruptible, &dev_priv->render_ring);
if (ret != 0)
return ret;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
new file mode 100644
index 000000000000..cea4f1a8709e
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -0,0 +1,849 @@
+/*
+ * Copyright © 2008-2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ * Zou Nan hai <nanhai.zou@intel.com>
+ * Xiang Hai hao<haihao.xiang@intel.com>
+ *
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drv.h"
+#include "i915_drm.h"
+#include "i915_trace.h"
+
+static void
+render_ring_flush(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+#if WATCH_EXEC
+ DRM_INFO("%s: invalidate %08x flush %08x\n", __func__,
+ invalidate_domains, flush_domains);
+#endif
+ u32 cmd;
+ trace_i915_gem_request_flush(dev, ring->next_seqno,
+ invalidate_domains, flush_domains);
+
+ if ((invalidate_domains | flush_domains) & I915_GEM_GPU_DOMAINS) {
+ /*
+ * read/write caches:
+ *
+ * I915_GEM_DOMAIN_RENDER is always invalidated, but is
+ * only flushed if MI_NO_WRITE_FLUSH is unset. On 965, it is
+ * also flushed at 2d versus 3d pipeline switches.
+ *
+ * read-only caches:
+ *
+ * I915_GEM_DOMAIN_SAMPLER is flushed on pre-965 if
+ * MI_READ_FLUSH is set, and is always flushed on 965.
+ *
+ * I915_GEM_DOMAIN_COMMAND may not exist?
+ *
+ * I915_GEM_DOMAIN_INSTRUCTION, which exists on 965, is
+ * invalidated when MI_EXE_FLUSH is set.
+ *
+ * I915_GEM_DOMAIN_VERTEX, which exists on 965, is
+ * invalidated with every MI_FLUSH.
+ *
+ * TLBs:
+ *
+ * On 965, TLBs associated with I915_GEM_DOMAIN_COMMAND
+ * and I915_GEM_DOMAIN_CPU in are invalidated at PTE write and
+ * I915_GEM_DOMAIN_RENDER and I915_GEM_DOMAIN_SAMPLER
+ * are flushed at any MI_FLUSH.
+ */
+
+ cmd = MI_FLUSH | MI_NO_WRITE_FLUSH;
+ if ((invalidate_domains|flush_domains) &
+ I915_GEM_DOMAIN_RENDER)
+ cmd &= ~MI_NO_WRITE_FLUSH;
+ if (!IS_I965G(dev)) {
+ /*
+ * On the 965, the sampler cache always gets flushed
+ * and this bit is reserved.
+ */
+ if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER)
+ cmd |= MI_READ_FLUSH;
+ }
+ if (invalidate_domains & I915_GEM_DOMAIN_INSTRUCTION)
+ cmd |= MI_EXE_FLUSH;
+
+#if WATCH_EXEC
+ DRM_INFO("%s: queue flush %08x to ring\n", __func__, cmd);
+#endif
+ intel_ring_begin(dev, ring, 8);
+ intel_ring_emit(dev, ring, cmd);
+ intel_ring_emit(dev, ring, MI_NOOP);
+ intel_ring_advance(dev, ring);
+ }
+}
+
+static unsigned int render_ring_get_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(PRB0_HEAD) & HEAD_ADDR;
+}
+
+static unsigned int render_ring_get_tail(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(PRB0_TAIL) & TAIL_ADDR;
+}
+
+static unsigned int render_ring_get_active_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 acthd_reg = IS_I965G(dev) ? ACTHD_I965 : ACTHD;
+
+ return I915_READ(acthd_reg);
+}
+
+static void render_ring_advance_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ I915_WRITE(PRB0_TAIL, ring->tail);
+}
+
+static int init_ring_common(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ u32 head;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj_priv;
+ obj_priv = to_intel_bo(ring->gem_object);
+
+ /* Stop the ring if it's running. */
+ I915_WRITE(ring->regs.ctl, 0);
+ I915_WRITE(ring->regs.head, 0);
+ I915_WRITE(ring->regs.tail, 0);
+
+ /* Initialize the ring. */
+ I915_WRITE(ring->regs.start, obj_priv->gtt_offset);
+ head = ring->get_head(dev, ring);
+
+ /* G45 ring initialization fails to reset head to zero */
+ if (head != 0) {
+ DRM_ERROR("%s head not reset to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ(ring->regs.ctl),
+ I915_READ(ring->regs.head),
+ I915_READ(ring->regs.tail),
+ I915_READ(ring->regs.start));
+
+ I915_WRITE(ring->regs.head, 0);
+
+ DRM_ERROR("%s head forced to zero "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ(ring->regs.ctl),
+ I915_READ(ring->regs.head),
+ I915_READ(ring->regs.tail),
+ I915_READ(ring->regs.start));
+ }
+
+ I915_WRITE(ring->regs.ctl,
+ ((ring->gem_object->size - PAGE_SIZE) & RING_NR_PAGES)
+ | RING_NO_REPORT | RING_VALID);
+
+ head = I915_READ(ring->regs.head) & HEAD_ADDR;
+ /* If the head is still not zero, the ring is dead */
+ if (head != 0) {
+ DRM_ERROR("%s initialization failed "
+ "ctl %08x head %08x tail %08x start %08x\n",
+ ring->name,
+ I915_READ(ring->regs.ctl),
+ I915_READ(ring->regs.head),
+ I915_READ(ring->regs.tail),
+ I915_READ(ring->regs.start));
+ return -EIO;
+ }
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ i915_kernel_lost_context(dev);
+ else {
+ ring->head = ring->get_head(dev, ring);
+ ring->tail = ring->get_tail(dev, ring);
+ ring->space = ring->head - (ring->tail + 8);
+ if (ring->space < 0)
+ ring->space += ring->size;
+ }
+ return 0;
+}
+
+static int init_render_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int ret = init_ring_common(dev, ring);
+ if (IS_I9XX(dev) && !IS_GEN3(dev)) {
+ I915_WRITE(MI_MODE,
+ (VS_TIMER_DISPATCH) << 16 | VS_TIMER_DISPATCH);
+ }
+ return ret;
+}
+
+#define PIPE_CONTROL_FLUSH(addr) \
+do { \
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE | \
+ PIPE_CONTROL_DEPTH_STALL | 2); \
+ OUT_RING(addr | PIPE_CONTROL_GLOBAL_GTT); \
+ OUT_RING(0); \
+ OUT_RING(0); \
+} while (0)
+
+/**
+ * Creates a new sequence number, emitting a write of it to the status page
+ * plus an interrupt, which will trigger i915_user_interrupt_handler.
+ *
+ * Must be called with struct_lock held.
+ *
+ * Returned sequence numbers are nonzero on success.
+ */
+static u32
+render_ring_add_request(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_file *file_priv,
+ u32 flush_domains)
+{
+ u32 seqno;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ seqno = intel_ring_get_seqno(dev, ring);
+
+ if (IS_GEN6(dev)) {
+ BEGIN_LP_RING(6);
+ OUT_RING(GFX_OP_PIPE_CONTROL | 3);
+ OUT_RING(PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_IS_FLUSH |
+ PIPE_CONTROL_NOTIFY);
+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+ OUT_RING(seqno);
+ OUT_RING(0);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else if (HAS_PIPE_CONTROL(dev)) {
+ u32 scratch_addr = dev_priv->seqno_gfx_addr + 128;
+
+ /*
+ * Workaround qword write incoherence by flushing the
+ * PIPE_NOTIFY buffers out to memory before requesting
+ * an interrupt.
+ */
+ BEGIN_LP_RING(32);
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH);
+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+ OUT_RING(seqno);
+ OUT_RING(0);
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128; /* write to separate cachelines */
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ scratch_addr += 128;
+ PIPE_CONTROL_FLUSH(scratch_addr);
+ OUT_RING(GFX_OP_PIPE_CONTROL | PIPE_CONTROL_QW_WRITE |
+ PIPE_CONTROL_WC_FLUSH | PIPE_CONTROL_TC_FLUSH |
+ PIPE_CONTROL_NOTIFY);
+ OUT_RING(dev_priv->seqno_gfx_addr | PIPE_CONTROL_GLOBAL_GTT);
+ OUT_RING(seqno);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(4);
+ OUT_RING(MI_STORE_DWORD_INDEX);
+ OUT_RING(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ OUT_RING(seqno);
+
+ OUT_RING(MI_USER_INTERRUPT);
+ ADVANCE_LP_RING();
+ }
+ return seqno;
+}
+
+static u32
+render_ring_get_gem_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ if (HAS_PIPE_CONTROL(dev))
+ return ((volatile u32 *)(dev_priv->seqno_page))[0];
+ else
+ return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void
+render_ring_get_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ if (dev->irq_enabled && (++ring->user_irq_refcount == 1)) {
+ if (HAS_PCH_SPLIT(dev))
+ ironlake_enable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
+ else
+ i915_enable_irq(dev_priv, I915_USER_INTERRUPT);
+ }
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+}
+
+static void
+render_ring_put_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&dev_priv->user_irq_lock, irqflags);
+ BUG_ON(dev->irq_enabled && ring->user_irq_refcount <= 0);
+ if (dev->irq_enabled && (--ring->user_irq_refcount == 0)) {
+ if (HAS_PCH_SPLIT(dev))
+ ironlake_disable_graphics_irq(dev_priv, GT_PIPE_NOTIFY);
+ else
+ i915_disable_irq(dev_priv, I915_USER_INTERRUPT);
+ }
+ spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
+}
+
+static void render_setup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ if (IS_GEN6(dev)) {
+ I915_WRITE(HWS_PGA_GEN6, ring->status_page.gfx_addr);
+ I915_READ(HWS_PGA_GEN6); /* posting read */
+ } else {
+ I915_WRITE(HWS_PGA, ring->status_page.gfx_addr);
+ I915_READ(HWS_PGA); /* posting read */
+ }
+
+}
+
+void
+bsd_ring_flush(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains)
+{
+ intel_ring_begin(dev, ring, 8);
+ intel_ring_emit(dev, ring, MI_FLUSH);
+ intel_ring_emit(dev, ring, MI_NOOP);
+ intel_ring_advance(dev, ring);
+}
+
+static inline unsigned int bsd_ring_get_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(BSD_RING_HEAD) & HEAD_ADDR;
+}
+
+static inline unsigned int bsd_ring_get_tail(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(BSD_RING_TAIL) & TAIL_ADDR;
+}
+
+static inline unsigned int bsd_ring_get_active_head(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ return I915_READ(BSD_RING_ACTHD);
+}
+
+static inline void bsd_ring_advance_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ I915_WRITE(BSD_RING_TAIL, ring->tail);
+}
+
+static int init_bsd_ring(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ return init_ring_common(dev, ring);
+}
+
+static u32
+bsd_ring_add_request(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_file *file_priv,
+ u32 flush_domains)
+{
+ u32 seqno;
+ seqno = intel_ring_get_seqno(dev, ring);
+ intel_ring_begin(dev, ring, 4);
+ intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX);
+ intel_ring_emit(dev, ring,
+ I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
+ intel_ring_emit(dev, ring, seqno);
+ intel_ring_emit(dev, ring, MI_USER_INTERRUPT);
+ intel_ring_advance(dev, ring);
+
+ DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno);
+
+ return seqno;
+}
+
+static void bsd_setup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ I915_WRITE(BSD_HWS_PGA, ring->status_page.gfx_addr);
+ I915_READ(BSD_HWS_PGA);
+}
+
+static void
+bsd_ring_get_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ /* do nothing */
+}
+static void
+bsd_ring_put_user_irq(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ /* do nothing */
+}
+
+static u32
+bsd_ring_get_gem_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static int
+bsd_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
+{
+ uint32_t exec_start;
+ exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+ intel_ring_begin(dev, ring, 2);
+ intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START |
+ (2 << 6) | MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(dev, ring, exec_start);
+ intel_ring_advance(dev, ring);
+ return 0;
+}
+
+
+static int
+render_ring_dispatch_gem_execbuffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ int nbox = exec->num_cliprects;
+ int i = 0, count;
+ uint32_t exec_start, exec_len;
+ exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
+ exec_len = (uint32_t) exec->batch_len;
+
+ trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1);
+
+ count = nbox ? nbox : 1;
+
+ for (i = 0; i < count; i++) {
+ if (i < nbox) {
+ int ret = i915_emit_box(dev, cliprects, i,
+ exec->DR1, exec->DR4);
+ if (ret)
+ return ret;
+ }
+
+ if (IS_I830(dev) || IS_845G(dev)) {
+ intel_ring_begin(dev, ring, 4);
+ intel_ring_emit(dev, ring, MI_BATCH_BUFFER);
+ intel_ring_emit(dev, ring,
+ exec_start | MI_BATCH_NON_SECURE);
+ intel_ring_emit(dev, ring, exec_start + exec_len - 4);
+ intel_ring_emit(dev, ring, 0);
+ } else {
+ intel_ring_begin(dev, ring, 4);
+ if (IS_I965G(dev)) {
+ intel_ring_emit(dev, ring,
+ MI_BATCH_BUFFER_START | (2 << 6)
+ | MI_BATCH_NON_SECURE_I965);
+ intel_ring_emit(dev, ring, exec_start);
+ } else {
+ intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START
+ | (2 << 6));
+ intel_ring_emit(dev, ring, exec_start |
+ MI_BATCH_NON_SECURE);
+ }
+ }
+ intel_ring_advance(dev, ring);
+ }
+
+ /* XXX breadcrumb */
+ return 0;
+}
+
+static void cleanup_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+
+ obj = ring->status_page.obj;
+ if (obj == NULL)
+ return;
+ obj_priv = to_intel_bo(obj);
+
+ kunmap(obj_priv->pages[0]);
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
+ ring->status_page.obj = NULL;
+
+ memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+}
+
+static int init_status_page(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct drm_gem_object *obj;
+ struct drm_i915_gem_object *obj_priv;
+ int ret;
+
+ obj = i915_gem_alloc_object(dev, 4096);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate status page\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ obj_priv = to_intel_bo(obj);
+ obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
+
+ ret = i915_gem_object_pin(obj, 4096);
+ if (ret != 0) {
+ goto err_unref;
+ }
+
+ ring->status_page.gfx_addr = obj_priv->gtt_offset;
+ ring->status_page.page_addr = kmap(obj_priv->pages[0]);
+ if (ring->status_page.page_addr == NULL) {
+ memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+ goto err_unpin;
+ }
+ ring->status_page.obj = obj;
+ memset(ring->status_page.page_addr, 0, PAGE_SIZE);
+
+ ring->setup_status_page(dev, ring);
+ DRM_DEBUG_DRIVER("%s hws offset: 0x%08x\n",
+ ring->name, ring->status_page.gfx_addr);
+
+ return 0;
+
+err_unpin:
+ i915_gem_object_unpin(obj);
+err_unref:
+ drm_gem_object_unreference(obj);
+err:
+ return ret;
+}
+
+
+int intel_init_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ int ret;
+ struct drm_i915_gem_object *obj_priv;
+ struct drm_gem_object *obj;
+ ring->dev = dev;
+
+ if (I915_NEED_GFX_HWS(dev)) {
+ ret = init_status_page(dev, ring);
+ if (ret)
+ return ret;
+ }
+
+ obj = i915_gem_alloc_object(dev, ring->size);
+ if (obj == NULL) {
+ DRM_ERROR("Failed to allocate ringbuffer\n");
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ ring->gem_object = obj;
+
+ ret = i915_gem_object_pin(obj, ring->alignment);
+ if (ret != 0) {
+ drm_gem_object_unreference(obj);
+ goto cleanup;
+ }
+
+ obj_priv = to_intel_bo(obj);
+ ring->map.size = ring->size;
+ ring->map.offset = dev->agp->base + obj_priv->gtt_offset;
+ ring->map.type = 0;
+ ring->map.flags = 0;
+ ring->map.mtrr = 0;
+
+ drm_core_ioremap_wc(&ring->map, dev);
+ if (ring->map.handle == NULL) {
+ DRM_ERROR("Failed to map ringbuffer.\n");
+ i915_gem_object_unpin(obj);
+ drm_gem_object_unreference(obj);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ ring->virtual_start = ring->map.handle;
+ ret = ring->init(dev, ring);
+ if (ret != 0) {
+ intel_cleanup_ring_buffer(dev, ring);
+ return ret;
+ }
+
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
+ i915_kernel_lost_context(dev);
+ else {
+ ring->head = ring->get_head(dev, ring);
+ ring->tail = ring->get_tail(dev, ring);
+ ring->space = ring->head - (ring->tail + 8);
+ if (ring->space < 0)
+ ring->space += ring->size;
+ }
+ INIT_LIST_HEAD(&ring->active_list);
+ INIT_LIST_HEAD(&ring->request_list);
+ return ret;
+cleanup:
+ cleanup_status_page(dev, ring);
+ return ret;
+}
+
+void intel_cleanup_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ if (ring->gem_object == NULL)
+ return;
+
+ drm_core_ioremapfree(&ring->map, dev);
+
+ i915_gem_object_unpin(ring->gem_object);
+ drm_gem_object_unreference(ring->gem_object);
+ ring->gem_object = NULL;
+ cleanup_status_page(dev, ring);
+}
+
+int intel_wrap_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ unsigned int *virt;
+ int rem;
+ rem = ring->size - ring->tail;
+
+ if (ring->space < rem) {
+ int ret = intel_wait_ring_buffer(dev, ring, rem);
+ if (ret)
+ return ret;
+ }
+
+ virt = (unsigned int *)(ring->virtual_start + ring->tail);
+ rem /= 4;
+ while (rem--)
+ *virt++ = MI_NOOP;
+
+ ring->tail = 0;
+
+ return 0;
+}
+
+int intel_wait_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring, int n)
+{
+ unsigned long end;
+
+ trace_i915_ring_wait_begin (dev);
+ end = jiffies + 3 * HZ;
+ do {
+ ring->head = ring->get_head(dev, ring);
+ ring->space = ring->head - (ring->tail + 8);
+ if (ring->space < 0)
+ ring->space += ring->size;
+ if (ring->space >= n) {
+ trace_i915_ring_wait_end (dev);
+ return 0;
+ }
+
+ if (dev->primary->master) {
+ struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
+ if (master_priv->sarea_priv)
+ master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
+ }
+
+ yield();
+ } while (!time_after(jiffies, end));
+ trace_i915_ring_wait_end (dev);
+ return -EBUSY;
+}
+
+void intel_ring_begin(struct drm_device *dev,
+ struct intel_ring_buffer *ring, int n)
+{
+ if (unlikely(ring->tail + n > ring->size))
+ intel_wrap_ring_buffer(dev, ring);
+ if (unlikely(ring->space < n))
+ intel_wait_ring_buffer(dev, ring, n);
+}
+
+void intel_ring_emit(struct drm_device *dev,
+ struct intel_ring_buffer *ring, unsigned int data)
+{
+ unsigned int *virt = ring->virtual_start + ring->tail;
+ *virt = data;
+ ring->tail += 4;
+ ring->tail &= ring->size - 1;
+ ring->space -= 4;
+}
+
+void intel_ring_advance(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ ring->advance_ring(dev, ring);
+}
+
+void intel_fill_struct(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ void *data,
+ unsigned int len)
+{
+ unsigned int *virt = ring->virtual_start + ring->tail;
+ BUG_ON((len&~(4-1)) != 0);
+ intel_ring_begin(dev, ring, len);
+ memcpy(virt, data, len);
+ ring->tail += len;
+ ring->tail &= ring->size - 1;
+ ring->space -= len;
+ intel_ring_advance(dev, ring);
+}
+
+u32 intel_ring_get_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring)
+{
+ u32 seqno;
+ seqno = ring->next_seqno;
+
+ /* reserve 0 for non-seqno */
+ if (++ring->next_seqno == 0)
+ ring->next_seqno = 1;
+ return seqno;
+}
+
+struct intel_ring_buffer render_ring = {
+ .name = "render ring",
+ .regs = {
+ .ctl = PRB0_CTL,
+ .head = PRB0_HEAD,
+ .tail = PRB0_TAIL,
+ .start = PRB0_START
+ },
+ .ring_flag = I915_EXEC_RENDER,
+ .size = 32 * PAGE_SIZE,
+ .alignment = PAGE_SIZE,
+ .virtual_start = NULL,
+ .dev = NULL,
+ .gem_object = NULL,
+ .head = 0,
+ .tail = 0,
+ .space = 0,
+ .next_seqno = 1,
+ .user_irq_refcount = 0,
+ .irq_gem_seqno = 0,
+ .waiting_gem_seqno = 0,
+ .setup_status_page = render_setup_status_page,
+ .init = init_render_ring,
+ .get_head = render_ring_get_head,
+ .get_tail = render_ring_get_tail,
+ .get_active_head = render_ring_get_active_head,
+ .advance_ring = render_ring_advance_ring,
+ .flush = render_ring_flush,
+ .add_request = render_ring_add_request,
+ .get_gem_seqno = render_ring_get_gem_seqno,
+ .user_irq_get = render_ring_get_user_irq,
+ .user_irq_put = render_ring_put_user_irq,
+ .dispatch_gem_execbuffer = render_ring_dispatch_gem_execbuffer,
+ .status_page = {NULL, 0, NULL},
+ .map = {0,}
+};
+
+/* ring buffer for bit-stream decoder */
+
+struct intel_ring_buffer bsd_ring = {
+ .name = "bsd ring",
+ .regs = {
+ .ctl = BSD_RING_CTL,
+ .head = BSD_RING_HEAD,
+ .tail = BSD_RING_TAIL,
+ .start = BSD_RING_START
+ },
+ .ring_flag = I915_EXEC_BSD,
+ .size = 32 * PAGE_SIZE,
+ .alignment = PAGE_SIZE,
+ .virtual_start = NULL,
+ .dev = NULL,
+ .gem_object = NULL,
+ .head = 0,
+ .tail = 0,
+ .space = 0,
+ .next_seqno = 1,
+ .user_irq_refcount = 0,
+ .irq_gem_seqno = 0,
+ .waiting_gem_seqno = 0,
+ .setup_status_page = bsd_setup_status_page,
+ .init = init_bsd_ring,
+ .get_head = bsd_ring_get_head,
+ .get_tail = bsd_ring_get_tail,
+ .get_active_head = bsd_ring_get_active_head,
+ .advance_ring = bsd_ring_advance_ring,
+ .flush = bsd_ring_flush,
+ .add_request = bsd_ring_add_request,
+ .get_gem_seqno = bsd_ring_get_gem_seqno,
+ .user_irq_get = bsd_ring_get_user_irq,
+ .user_irq_put = bsd_ring_put_user_irq,
+ .dispatch_gem_execbuffer = bsd_ring_dispatch_gem_execbuffer,
+ .status_page = {NULL, 0, NULL},
+ .map = {0,}
+};
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
new file mode 100644
index 000000000000..d5568d3766de
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -0,0 +1,124 @@
+#ifndef _INTEL_RINGBUFFER_H_
+#define _INTEL_RINGBUFFER_H_
+
+struct intel_hw_status_page {
+ void *page_addr;
+ unsigned int gfx_addr;
+ struct drm_gem_object *obj;
+};
+
+struct drm_i915_gem_execbuffer2;
+struct intel_ring_buffer {
+ const char *name;
+ struct ring_regs {
+ u32 ctl;
+ u32 head;
+ u32 tail;
+ u32 start;
+ } regs;
+ unsigned int ring_flag;
+ unsigned long size;
+ unsigned int alignment;
+ void *virtual_start;
+ struct drm_device *dev;
+ struct drm_gem_object *gem_object;
+
+ unsigned int head;
+ unsigned int tail;
+ unsigned int space;
+ u32 next_seqno;
+ struct intel_hw_status_page status_page;
+
+ u32 irq_gem_seqno; /* last seq seem at irq time */
+ u32 waiting_gem_seqno;
+ int user_irq_refcount;
+ void (*user_irq_get)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ void (*user_irq_put)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ void (*setup_status_page)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+
+ int (*init)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+
+ unsigned int (*get_head)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ unsigned int (*get_tail)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ unsigned int (*get_active_head)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ void (*advance_ring)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ void (*flush)(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ u32 invalidate_domains,
+ u32 flush_domains);
+ u32 (*add_request)(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_file *file_priv,
+ u32 flush_domains);
+ u32 (*get_gem_seqno)(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+ int (*dispatch_gem_execbuffer)(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ struct drm_i915_gem_execbuffer2 *exec,
+ struct drm_clip_rect *cliprects,
+ uint64_t exec_offset);
+
+ /**
+ * List of objects currently involved in rendering from the
+ * ringbuffer.
+ *
+ * Includes buffers having the contents of their GPU caches
+ * flushed, not necessarily primitives. last_rendering_seqno
+ * represents when the rendering involved will be completed.
+ *
+ * A reference is held on the buffer while on this list.
+ */
+ struct list_head active_list;
+
+ /**
+ * List of breadcrumbs associated with GPU requests currently
+ * outstanding.
+ */
+ struct list_head request_list;
+
+ wait_queue_head_t irq_queue;
+ drm_local_map_t map;
+};
+
+static inline u32
+intel_read_status_page(struct intel_ring_buffer *ring,
+ int reg)
+{
+ u32 *regs = ring->status_page.page_addr;
+ return regs[reg];
+}
+
+int intel_init_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+void intel_cleanup_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+int intel_wait_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring, int n);
+int intel_wrap_ring_buffer(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+void intel_ring_begin(struct drm_device *dev,
+ struct intel_ring_buffer *ring, int n);
+void intel_ring_emit(struct drm_device *dev,
+ struct intel_ring_buffer *ring, u32 data);
+void intel_fill_struct(struct drm_device *dev,
+ struct intel_ring_buffer *ring,
+ void *data,
+ unsigned int len);
+void intel_ring_advance(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+
+u32 intel_ring_get_seqno(struct drm_device *dev,
+ struct intel_ring_buffer *ring);
+
+extern struct intel_ring_buffer render_ring;
+extern struct intel_ring_buffer bsd_ring;
+
+#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index aba72c489a2f..76993ac16cc1 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1479,7 +1479,7 @@ intel_find_analog_connector(struct drm_device *dev)
intel_encoder = enc_to_intel_encoder(encoder);
if (intel_encoder->type == INTEL_OUTPUT_ANALOG) {
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
- if (connector && encoder == intel_attached_encoder(connector))
+ if (encoder == intel_attached_encoder(connector))
return connector;
}
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index e13f6af0037a..d4bcca8a5133 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -34,7 +34,7 @@
static struct nouveau_dsm_priv {
bool dsm_detected;
acpi_handle dhandle;
- acpi_handle dsm_handle;
+ acpi_handle rom_handle;
} nouveau_dsm_priv;
static const char nouveau_dsm_muid[] = {
@@ -107,9 +107,9 @@ static int nouveau_dsm_set_discrete_state(acpi_handle handle, enum vga_switchero
static int nouveau_dsm_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD)
- return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_STAMINA);
+ return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_STAMINA);
else
- return nouveau_dsm_switch_mux(nouveau_dsm_priv.dsm_handle, NOUVEAU_DSM_LED_SPEED);
+ return nouveau_dsm_switch_mux(nouveau_dsm_priv.dhandle, NOUVEAU_DSM_LED_SPEED);
}
static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
@@ -118,7 +118,7 @@ static int nouveau_dsm_power_state(enum vga_switcheroo_client_id id,
if (id == VGA_SWITCHEROO_IGD)
return 0;
- return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dsm_handle, state);
+ return nouveau_dsm_set_discrete_state(nouveau_dsm_priv.dhandle, state);
}
static int nouveau_dsm_init(void)
@@ -151,18 +151,18 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
if (!dhandle)
return false;
+
status = acpi_get_handle(dhandle, "_DSM", &nvidia_handle);
if (ACPI_FAILURE(status)) {
return false;
}
- ret= nouveau_dsm(nvidia_handle, NOUVEAU_DSM_SUPPORTED,
- NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
+ ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
+ NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
if (ret < 0)
return false;
nouveau_dsm_priv.dhandle = dhandle;
- nouveau_dsm_priv.dsm_handle = nvidia_handle;
return true;
}
@@ -173,6 +173,7 @@ static bool nouveau_dsm_detect(void)
struct pci_dev *pdev = NULL;
int has_dsm = 0;
int vga_count = 0;
+
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
vga_count++;
@@ -180,7 +181,7 @@ static bool nouveau_dsm_detect(void)
}
if (vga_count == 2 && has_dsm) {
- acpi_get_name(nouveau_dsm_priv.dsm_handle, ACPI_FULL_PATHNAME, &buffer);
+ acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
acpi_method_name);
nouveau_dsm_priv.dsm_detected = true;
@@ -204,3 +205,57 @@ void nouveau_unregister_dsm_handler(void)
{
vga_switcheroo_unregister_handler();
}
+
+/* retrieve the ROM in 4k blocks */
+static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
+ int offset, int len)
+{
+ acpi_status status;
+ union acpi_object rom_arg_elements[2], *obj;
+ struct acpi_object_list rom_arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL};
+
+ rom_arg.count = 2;
+ rom_arg.pointer = &rom_arg_elements[0];
+
+ rom_arg_elements[0].type = ACPI_TYPE_INTEGER;
+ rom_arg_elements[0].integer.value = offset;
+
+ rom_arg_elements[1].type = ACPI_TYPE_INTEGER;
+ rom_arg_elements[1].integer.value = len;
+
+ status = acpi_evaluate_object(rom_handle, NULL, &rom_arg, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_INFO "failed to evaluate ROM got %s\n", acpi_format_exception(status));
+ return -ENODEV;
+ }
+ obj = (union acpi_object *)buffer.pointer;
+ memcpy(bios+offset, obj->buffer.pointer, len);
+ kfree(buffer.pointer);
+ return len;
+}
+
+bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
+{
+ acpi_status status;
+ acpi_handle dhandle, rom_handle;
+
+ if (!nouveau_dsm_priv.dsm_detected)
+ return false;
+
+ dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
+ if (!dhandle)
+ return false;
+
+ status = acpi_get_handle(dhandle, "_ROM", &rom_handle);
+ if (ACPI_FAILURE(status))
+ return false;
+
+ nouveau_dsm_priv.rom_handle = rom_handle;
+ return true;
+}
+
+int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
+{
+ return nouveau_rom_call(nouveau_dsm_priv.rom_handle, bios, offset, len);
+}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index e7e69ccce5c9..9ba2deaadcc7 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -178,6 +178,25 @@ out:
pci_disable_rom(dev->pdev);
}
+static void load_vbios_acpi(struct drm_device *dev, uint8_t *data)
+{
+ int i;
+ int ret;
+ int size = 64 * 1024;
+
+ if (!nouveau_acpi_rom_supported(dev->pdev))
+ return;
+
+ for (i = 0; i < (size / ROM_BIOS_PAGE); i++) {
+ ret = nouveau_acpi_get_bios_chunk(data,
+ (i * ROM_BIOS_PAGE),
+ ROM_BIOS_PAGE);
+ if (ret <= 0)
+ break;
+ }
+ return;
+}
+
struct methods {
const char desc[8];
void (*loadbios)(struct drm_device *, uint8_t *);
@@ -191,6 +210,7 @@ static struct methods nv04_methods[] = {
};
static struct methods nv50_methods[] = {
+ { "ACPI", load_vbios_acpi, true },
{ "PRAMIN", load_vbios_pramin, true },
{ "PROM", load_vbios_prom, false },
{ "PCIROM", load_vbios_pci, true },
@@ -2807,7 +2827,10 @@ init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec)
BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry);
- nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
+ BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n",
+ offset, gpio->tag, gpio->state_default);
+ if (bios->execute)
+ nv50_gpio_set(bios->dev, gpio->tag, gpio->state_default);
/* The NVIDIA binary driver doesn't appear to actually do
* any of this, my VBIOS does however.
@@ -5533,12 +5556,6 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
entry->bus = (conn >> 16) & 0xf;
entry->location = (conn >> 20) & 0x3;
entry->or = (conn >> 24) & 0xf;
- /*
- * Normal entries consist of a single bit, but dual link has the
- * next most significant bit set too
- */
- entry->duallink_possible =
- ((1 << (ffs(entry->or) - 1)) * 3 == entry->or);
switch (entry->type) {
case OUTPUT_ANALOG:
@@ -5622,6 +5639,16 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
break;
}
+ if (dcb->version < 0x40) {
+ /* Normal entries consist of a single bit, but dual link has
+ * the next most significant bit set too
+ */
+ entry->duallink_possible =
+ ((1 << (ffs(entry->or) - 1)) * 3 == entry->or);
+ } else {
+ entry->duallink_possible = (entry->sorconf.link == 3);
+ }
+
/* unsure what DCB version introduces this, 3.0? */
if (conf & 0x100000)
entry->i2c_upper_default = true;
@@ -6205,6 +6232,30 @@ nouveau_bios_i2c_devices_takedown(struct drm_device *dev)
nouveau_i2c_fini(dev, entry);
}
+static bool
+nouveau_bios_posted(struct drm_device *dev)
+{
+ struct drm_nouveau_private *dev_priv = dev->dev_private;
+ bool was_locked;
+ unsigned htotal;
+
+ if (dev_priv->chipset >= NV_50) {
+ if (NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
+ NVReadVgaCrtc(dev, 0, 0x1a) == 0)
+ return false;
+ return true;
+ }
+
+ was_locked = NVLockVgaCrtcs(dev, false);
+ htotal = NVReadVgaCrtc(dev, 0, 0x06);
+ htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x01) << 8;
+ htotal |= (NVReadVgaCrtc(dev, 0, 0x07) & 0x20) << 4;
+ htotal |= (NVReadVgaCrtc(dev, 0, 0x25) & 0x01) << 10;
+ htotal |= (NVReadVgaCrtc(dev, 0, 0x41) & 0x01) << 11;
+ NVLockVgaCrtcs(dev, was_locked);
+ return (htotal != 0);
+}
+
int
nouveau_bios_init(struct drm_device *dev)
{
@@ -6239,11 +6290,9 @@ nouveau_bios_init(struct drm_device *dev)
bios->execute = false;
/* ... unless card isn't POSTed already */
- if (dev_priv->card_type >= NV_10 &&
- NVReadVgaCrtc(dev, 0, 0x00) == 0 &&
- NVReadVgaCrtc(dev, 0, 0x1a) == 0) {
+ if (!nouveau_bios_posted(dev)) {
NV_INFO(dev, "Adaptor not initialised\n");
- if (dev_priv->card_type < NV_50) {
+ if (dev_priv->card_type < NV_40) {
NV_ERROR(dev, "Unable to POST this chipset\n");
return -ENODEV;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 266b0ff441af..149ed224c3cb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -432,24 +432,27 @@ nouveau_connector_set_property(struct drm_connector *connector,
}
static struct drm_display_mode *
-nouveau_connector_native_mode(struct nouveau_connector *connector)
+nouveau_connector_native_mode(struct drm_connector *connector)
{
- struct drm_device *dev = connector->base.dev;
+ struct drm_connector_helper_funcs *helper = connector->helper_private;
+ struct nouveau_connector *nv_connector = nouveau_connector(connector);
+ struct drm_device *dev = connector->dev;
struct drm_display_mode *mode, *largest = NULL;
int high_w = 0, high_h = 0, high_v = 0;
- /* Use preferred mode if there is one.. */
- list_for_each_entry(mode, &connector->base.probed_modes, head) {
+ list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {
+ if (helper->mode_valid(connector, mode) != MODE_OK)
+ continue;
+
+ /* Use preferred mode if there is one.. */
if (mode->type & DRM_MODE_TYPE_PREFERRED) {
NV_DEBUG_KMS(dev, "native mode from preferred\n");
return drm_mode_duplicate(dev, mode);
}
- }
- /* Otherwise, take the resolution with the largest width, then height,
- * then vertical refresh
- */
- list_for_each_entry(mode, &connector->base.probed_modes, head) {
+ /* Otherwise, take the resolution with the largest width, then
+ * height, then vertical refresh
+ */
if (mode->hdisplay < high_w)
continue;
@@ -553,7 +556,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
*/
if (!nv_connector->native_mode)
nv_connector->native_mode =
- nouveau_connector_native_mode(nv_connector);
+ nouveau_connector_native_mode(connector);
if (ret == 0 && nv_connector->native_mode) {
struct drm_display_mode *mode;
@@ -584,9 +587,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
switch (nv_encoder->dcb->type) {
case OUTPUT_LVDS:
- BUG_ON(!nv_connector->native_mode);
- if (mode->hdisplay > nv_connector->native_mode->hdisplay ||
- mode->vdisplay > nv_connector->native_mode->vdisplay)
+ if (nv_connector->native_mode &&
+ (mode->hdisplay > nv_connector->native_mode->hdisplay ||
+ mode->vdisplay > nv_connector->native_mode->vdisplay))
return MODE_PANEL;
min_clock = 0;
@@ -594,8 +597,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector,
break;
case OUTPUT_TMDS:
if ((dev_priv->card_type >= NV_50 && !nouveau_duallink) ||
- (dev_priv->card_type < NV_50 &&
- !nv_encoder->dcb->duallink_possible))
+ !nv_encoder->dcb->duallink_possible)
max_clock = 165000;
else
max_clock = 330000;
@@ -729,7 +731,7 @@ nouveau_connector_create_lvds(struct drm_device *dev,
if (ret == 0)
goto out;
nv_connector->detected_encoder = nv_encoder;
- nv_connector->native_mode = nouveau_connector_native_mode(nv_connector);
+ nv_connector->native_mode = nouveau_connector_native_mode(connector);
list_for_each_entry_safe(mode, temp, &connector->probed_modes, head)
drm_mode_remove(connector, mode);
diff --git a/drivers/gpu/drm/nouveau/nouveau_crtc.h b/drivers/gpu/drm/nouveau/nouveau_crtc.h
index 49fa7b2d257e..cb1ce2a09162 100644
--- a/drivers/gpu/drm/nouveau/nouveau_crtc.h
+++ b/drivers/gpu/drm/nouveau/nouveau_crtc.h
@@ -40,6 +40,8 @@ struct nouveau_crtc {
int sharpness;
int last_dpms;
+ int cursor_saved_x, cursor_saved_y;
+
struct {
int cpp;
bool blanked;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c
index c6079e36669d..273770432298 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.c
@@ -175,6 +175,13 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
nouveau_bo_unpin(nouveau_fb->nvbo);
}
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+ nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+ }
+
NV_INFO(dev, "Evicting buffers...\n");
ttm_bo_evict_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
@@ -314,12 +321,34 @@ nouveau_pci_resume(struct pci_dev *pdev)
nouveau_bo_pin(nouveau_fb->nvbo, TTM_PL_FLAG_VRAM);
}
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+ int ret;
+
+ ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM);
+ if (!ret)
+ ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
+ if (ret)
+ NV_ERROR(dev, "Could not pin/map cursor.\n");
+ }
+
if (dev_priv->card_type < NV_50) {
nv04_display_restore(dev);
NVLockVgaCrtcs(dev, false);
} else
nv50_display_init(dev);
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
+
+ nv_crtc->cursor.set_offset(nv_crtc,
+ nv_crtc->cursor.nvbo->bo.offset -
+ dev_priv->vm_vram_base);
+
+ nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
+ nv_crtc->cursor_saved_y);
+ }
+
/* Force CLUT to get re-loaded during modeset */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h
index 5b134438effe..c69719106489 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drv.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drv.h
@@ -851,12 +851,17 @@ extern int nouveau_dma_init(struct nouveau_channel *);
extern int nouveau_dma_wait(struct nouveau_channel *, int slots, int size);
/* nouveau_acpi.c */
+#define ROM_BIOS_PAGE 4096
#if defined(CONFIG_ACPI)
void nouveau_register_dsm_handler(void);
void nouveau_unregister_dsm_handler(void);
+int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
+bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
#else
static inline void nouveau_register_dsm_handler(void) {}
static inline void nouveau_unregister_dsm_handler(void) {}
+static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; }
+static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; }
#endif
/* nouveau_backlight.c */
diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c
index 775a7017af64..c1fd42b0dad1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_mem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_mem.c
@@ -540,7 +540,8 @@ nouveau_mem_detect(struct drm_device *dev)
dev_priv->vram_size = nv_rd32(dev, NV04_FIFO_DATA);
dev_priv->vram_size &= NV10_FIFO_DATA_RAM_AMOUNT_MB_MASK;
if (dev_priv->chipset == 0xaa || dev_priv->chipset == 0xac)
- dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10) << 12;
+ dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10);
+ dev_priv->vram_sys_base <<= 12;
}
NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20));
diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
index e632339c323e..147e59c40151 100644
--- a/drivers/gpu/drm/nouveau/nouveau_state.c
+++ b/drivers/gpu/drm/nouveau/nouveau_state.c
@@ -376,12 +376,15 @@ out_err:
static void nouveau_switcheroo_set_state(struct pci_dev *pdev,
enum vga_switcheroo_state state)
{
+ struct drm_device *dev = pci_get_drvdata(pdev);
pm_message_t pmm = { .event = PM_EVENT_SUSPEND };
if (state == VGA_SWITCHEROO_ON) {
printk(KERN_ERR "VGA switcheroo: switched nouveau on\n");
nouveau_pci_resume(pdev);
+ drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_ERR "VGA switcheroo: switched nouveau off\n");
+ drm_kms_helper_poll_disable(dev);
nouveau_pci_suspend(pdev, pmm);
}
}
@@ -913,6 +916,9 @@ int nouveau_ioctl_getparam(struct drm_device *dev, void *data,
case NOUVEAU_GETPARAM_VM_VRAM_BASE:
getparam->value = dev_priv->vm_vram_base;
break;
+ case NOUVEAU_GETPARAM_PTIMER_TIME:
+ getparam->value = dev_priv->engine.timer.read(dev);
+ break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
/* NV40 and NV50 versions are quite different, but register
* address is the same. User is supposed to know the card
diff --git a/drivers/gpu/drm/nouveau/nv04_cursor.c b/drivers/gpu/drm/nouveau/nv04_cursor.c
index 89a91b9d8b25..aaf3de3bc816 100644
--- a/drivers/gpu/drm/nouveau/nv04_cursor.c
+++ b/drivers/gpu/drm/nouveau/nv04_cursor.c
@@ -20,6 +20,7 @@ nv04_cursor_hide(struct nouveau_crtc *nv_crtc, bool update)
static void
nv04_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
{
+ nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y;
NVWriteRAMDAC(nv_crtc->base.dev, nv_crtc->index,
NV_PRAMDAC_CU_START_POS,
XLATE(y, 0, NV_PRAMDAC_CU_START_POS_Y) |
diff --git a/drivers/gpu/drm/nouveau/nv50_cursor.c b/drivers/gpu/drm/nouveau/nv50_cursor.c
index 753e723adb3a..03ad7ab14f09 100644
--- a/drivers/gpu/drm/nouveau/nv50_cursor.c
+++ b/drivers/gpu/drm/nouveau/nv50_cursor.c
@@ -107,6 +107,7 @@ nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y)
{
struct drm_device *dev = nv_crtc->base.dev;
+ nv_crtc->cursor_saved_x = x; nv_crtc->cursor_saved_y = y;
nv_wr32(dev, NV50_PDISPLAY_CURSOR_USER_POS(nv_crtc->index),
((y & 0xFFFF) << 16) | (x & 0xFFFF));
/* Needed to make the cursor move. */
diff --git a/drivers/gpu/drm/nouveau/nv50_sor.c b/drivers/gpu/drm/nouveau/nv50_sor.c
index b11eaf9c5c7c..812778db76ac 100644
--- a/drivers/gpu/drm/nouveau/nv50_sor.c
+++ b/drivers/gpu/drm/nouveau/nv50_sor.c
@@ -274,7 +274,6 @@ static const struct drm_encoder_funcs nv50_sor_encoder_funcs = {
int
nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
{
- struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_encoder *nv_encoder = NULL;
struct drm_encoder *encoder;
bool dum;
@@ -324,11 +323,7 @@ nv50_sor_create(struct drm_device *dev, struct dcb_entry *entry)
int or = nv_encoder->or, link = !(entry->dpconf.sor.link & 1);
uint32_t tmp;
- if (dev_priv->chipset < 0x90 ||
- dev_priv->chipset == 0x92 || dev_priv->chipset == 0xa0)
- tmp = nv_rd32(dev, NV50_PDISPLAY_SOR_MODE_CTRL_C(or));
- else
- tmp = nv_rd32(dev, NV90_PDISPLAY_SOR_MODE_CTRL_C(or));
+ tmp = nv_rd32(dev, 0x61c700 + (or * 0x800));
switch ((tmp & 0x00000f00) >> 8) {
case 8:
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 3c91312dea9a..84b1f2729d43 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -33,6 +33,9 @@ $(obj)/rs600_reg_safe.h: $(src)/reg_srcs/rs600 $(obj)/mkregtable
$(obj)/r600_reg_safe.h: $(src)/reg_srcs/r600 $(obj)/mkregtable
$(call if_changed,mkregtable)
+$(obj)/evergreen_reg_safe.h: $(src)/reg_srcs/evergreen $(obj)/mkregtable
+ $(call if_changed,mkregtable)
+
$(obj)/r100.o: $(obj)/r100_reg_safe.h $(obj)/rn50_reg_safe.h
$(obj)/r200.o: $(obj)/r200_reg_safe.h
@@ -47,6 +50,8 @@ $(obj)/rs600.o: $(obj)/rs600_reg_safe.h
$(obj)/r600_cs.o: $(obj)/r600_reg_safe.h
+$(obj)/evergreen_cs.o: $(obj)/evergreen_reg_safe.h
+
radeon-y := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o \
radeon_irq.o r300_cmdbuf.o r600_cp.o
# add KMS driver
@@ -60,7 +65,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \
r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \
r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \
- evergreen.o
+ evergreen.o evergreen_cs.o
radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 8c8e4d3cbaa3..0440c0939bdd 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -41,7 +41,12 @@ void evergreen_fini(struct radeon_device *rdev);
void evergreen_pm_misc(struct radeon_device *rdev)
{
+ int requested_index = rdev->pm.requested_power_state_index;
+ struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
+ struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
+ if ((voltage->type == VOLTAGE_SW) && voltage->voltage)
+ radeon_atom_set_voltage(rdev, voltage->voltage);
}
void evergreen_pm_prepare(struct radeon_device *rdev)
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
new file mode 100644
index 000000000000..64516b950891
--- /dev/null
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -0,0 +1,1356 @@
+/*
+ * Copyright 2010 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#include "drmP.h"
+#include "radeon.h"
+#include "evergreend.h"
+#include "evergreen_reg_safe.h"
+
+static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
+ struct radeon_cs_reloc **cs_reloc);
+
+struct evergreen_cs_track {
+ u32 group_size;
+ u32 nbanks;
+ u32 npipes;
+ /* value we track */
+ u32 nsamples;
+ u32 cb_color_base_last[12];
+ struct radeon_bo *cb_color_bo[12];
+ u32 cb_color_bo_offset[12];
+ struct radeon_bo *cb_color_fmask_bo[8];
+ struct radeon_bo *cb_color_cmask_bo[8];
+ u32 cb_color_info[12];
+ u32 cb_color_view[12];
+ u32 cb_color_pitch_idx[12];
+ u32 cb_color_slice_idx[12];
+ u32 cb_color_dim_idx[12];
+ u32 cb_color_dim[12];
+ u32 cb_color_pitch[12];
+ u32 cb_color_slice[12];
+ u32 cb_color_cmask_slice[8];
+ u32 cb_color_fmask_slice[8];
+ u32 cb_target_mask;
+ u32 cb_shader_mask;
+ u32 vgt_strmout_config;
+ u32 vgt_strmout_buffer_config;
+ u32 db_depth_control;
+ u32 db_depth_view;
+ u32 db_depth_size;
+ u32 db_depth_size_idx;
+ u32 db_z_info;
+ u32 db_z_idx;
+ u32 db_z_read_offset;
+ u32 db_z_write_offset;
+ struct radeon_bo *db_z_read_bo;
+ struct radeon_bo *db_z_write_bo;
+ u32 db_s_info;
+ u32 db_s_idx;
+ u32 db_s_read_offset;
+ u32 db_s_write_offset;
+ struct radeon_bo *db_s_read_bo;
+ struct radeon_bo *db_s_write_bo;
+};
+
+static void evergreen_cs_track_init(struct evergreen_cs_track *track)
+{
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ track->cb_color_fmask_bo[i] = NULL;
+ track->cb_color_cmask_bo[i] = NULL;
+ track->cb_color_cmask_slice[i] = 0;
+ track->cb_color_fmask_slice[i] = 0;
+ }
+
+ for (i = 0; i < 12; i++) {
+ track->cb_color_base_last[i] = 0;
+ track->cb_color_bo[i] = NULL;
+ track->cb_color_bo_offset[i] = 0xFFFFFFFF;
+ track->cb_color_info[i] = 0;
+ track->cb_color_view[i] = 0;
+ track->cb_color_pitch_idx[i] = 0;
+ track->cb_color_slice_idx[i] = 0;
+ track->cb_color_dim[i] = 0;
+ track->cb_color_pitch[i] = 0;
+ track->cb_color_slice[i] = 0;
+ track->cb_color_dim[i] = 0;
+ }
+ track->cb_target_mask = 0xFFFFFFFF;
+ track->cb_shader_mask = 0xFFFFFFFF;
+
+ track->db_depth_view = 0xFFFFC000;
+ track->db_depth_size = 0xFFFFFFFF;
+ track->db_depth_size_idx = 0;
+ track->db_depth_control = 0xFFFFFFFF;
+ track->db_z_info = 0xFFFFFFFF;
+ track->db_z_idx = 0xFFFFFFFF;
+ track->db_z_read_offset = 0xFFFFFFFF;
+ track->db_z_write_offset = 0xFFFFFFFF;
+ track->db_z_read_bo = NULL;
+ track->db_z_write_bo = NULL;
+ track->db_s_info = 0xFFFFFFFF;
+ track->db_s_idx = 0xFFFFFFFF;
+ track->db_s_read_offset = 0xFFFFFFFF;
+ track->db_s_write_offset = 0xFFFFFFFF;
+ track->db_s_read_bo = NULL;
+ track->db_s_write_bo = NULL;
+}
+
+static inline int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, int i)
+{
+ /* XXX fill in */
+ return 0;
+}
+
+static int evergreen_cs_track_check(struct radeon_cs_parser *p)
+{
+ struct evergreen_cs_track *track = p->track;
+
+ /* we don't support stream out buffer yet */
+ if (track->vgt_strmout_config || track->vgt_strmout_buffer_config) {
+ dev_warn(p->dev, "this kernel doesn't support SMX output buffer\n");
+ return -EINVAL;
+ }
+
+ /* XXX fill in */
+ return 0;
+}
+
+/**
+ * evergreen_cs_packet_parse() - parse cp packet and point ib index to next packet
+ * @parser: parser structure holding parsing context.
+ * @pkt: where to store packet informations
+ *
+ * Assume that chunk_ib_index is properly set. Will return -EINVAL
+ * if packet is bigger than remaining ib size. or if packets is unknown.
+ **/
+int evergreen_cs_packet_parse(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt,
+ unsigned idx)
+{
+ struct radeon_cs_chunk *ib_chunk = &p->chunks[p->chunk_ib_idx];
+ uint32_t header;
+
+ if (idx >= ib_chunk->length_dw) {
+ DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
+ idx, ib_chunk->length_dw);
+ return -EINVAL;
+ }
+ header = radeon_get_ib_value(p, idx);
+ pkt->idx = idx;
+ pkt->type = CP_PACKET_GET_TYPE(header);
+ pkt->count = CP_PACKET_GET_COUNT(header);
+ pkt->one_reg_wr = 0;
+ switch (pkt->type) {
+ case PACKET_TYPE0:
+ pkt->reg = CP_PACKET0_GET_REG(header);
+ break;
+ case PACKET_TYPE3:
+ pkt->opcode = CP_PACKET3_GET_OPCODE(header);
+ break;
+ case PACKET_TYPE2:
+ pkt->count = -1;
+ break;
+ default:
+ DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
+ return -EINVAL;
+ }
+ if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
+ DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
+ pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * evergreen_cs_packet_next_reloc() - parse next packet which should be reloc packet3
+ * @parser: parser structure holding parsing context.
+ * @data: pointer to relocation data
+ * @offset_start: starting offset
+ * @offset_mask: offset mask (to align start offset on)
+ * @reloc: reloc informations
+ *
+ * Check next packet is relocation packet3, do bo validation and compute
+ * GPU offset using the provided start.
+ **/
+static int evergreen_cs_packet_next_reloc(struct radeon_cs_parser *p,
+ struct radeon_cs_reloc **cs_reloc)
+{
+ struct radeon_cs_chunk *relocs_chunk;
+ struct radeon_cs_packet p3reloc;
+ unsigned idx;
+ int r;
+
+ if (p->chunk_relocs_idx == -1) {
+ DRM_ERROR("No relocation chunk !\n");
+ return -EINVAL;
+ }
+ *cs_reloc = NULL;
+ relocs_chunk = &p->chunks[p->chunk_relocs_idx];
+ r = evergreen_cs_packet_parse(p, &p3reloc, p->idx);
+ if (r) {
+ return r;
+ }
+ p->idx += p3reloc.count + 2;
+ if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
+ DRM_ERROR("No packet3 for relocation for packet at %d.\n",
+ p3reloc.idx);
+ return -EINVAL;
+ }
+ idx = radeon_get_ib_value(p, p3reloc.idx + 1);
+ if (idx >= relocs_chunk->length_dw) {
+ DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
+ idx, relocs_chunk->length_dw);
+ return -EINVAL;
+ }
+ /* FIXME: we assume reloc size is 4 dwords */
+ *cs_reloc = p->relocs_ptr[(idx / 4)];
+ return 0;
+}
+
+/**
+ * evergreen_cs_packet_next_is_pkt3_nop() - test if next packet is packet3 nop for reloc
+ * @parser: parser structure holding parsing context.
+ *
+ * Check next packet is relocation packet3, do bo validation and compute
+ * GPU offset using the provided start.
+ **/
+static inline int evergreen_cs_packet_next_is_pkt3_nop(struct radeon_cs_parser *p)
+{
+ struct radeon_cs_packet p3reloc;
+ int r;
+
+ r = evergreen_cs_packet_parse(p, &p3reloc, p->idx);
+ if (r) {
+ return 0;
+ }
+ if (p3reloc.type != PACKET_TYPE3 || p3reloc.opcode != PACKET3_NOP) {
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * evergreen_cs_packet_next_vline() - parse userspace VLINE packet
+ * @parser: parser structure holding parsing context.
+ *
+ * Userspace sends a special sequence for VLINE waits.
+ * PACKET0 - VLINE_START_END + value
+ * PACKET3 - WAIT_REG_MEM poll vline status reg
+ * RELOC (P3) - crtc_id in reloc.
+ *
+ * This function parses this and relocates the VLINE START END
+ * and WAIT_REG_MEM packets to the correct crtc.
+ * It also detects a switched off crtc and nulls out the
+ * wait in that case.
+ */
+static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p)
+{
+ struct drm_mode_object *obj;
+ struct drm_crtc *crtc;
+ struct radeon_crtc *radeon_crtc;
+ struct radeon_cs_packet p3reloc, wait_reg_mem;
+ int crtc_id;
+ int r;
+ uint32_t header, h_idx, reg, wait_reg_mem_info;
+ volatile uint32_t *ib;
+
+ ib = p->ib->ptr;
+
+ /* parse the WAIT_REG_MEM */
+ r = evergreen_cs_packet_parse(p, &wait_reg_mem, p->idx);
+ if (r)
+ return r;
+
+ /* check its a WAIT_REG_MEM */
+ if (wait_reg_mem.type != PACKET_TYPE3 ||
+ wait_reg_mem.opcode != PACKET3_WAIT_REG_MEM) {
+ DRM_ERROR("vline wait missing WAIT_REG_MEM segment\n");
+ r = -EINVAL;
+ return r;
+ }
+
+ wait_reg_mem_info = radeon_get_ib_value(p, wait_reg_mem.idx + 1);
+ /* bit 4 is reg (0) or mem (1) */
+ if (wait_reg_mem_info & 0x10) {
+ DRM_ERROR("vline WAIT_REG_MEM waiting on MEM rather than REG\n");
+ r = -EINVAL;
+ return r;
+ }
+ /* waiting for value to be equal */
+ if ((wait_reg_mem_info & 0x7) != 0x3) {
+ DRM_ERROR("vline WAIT_REG_MEM function not equal\n");
+ r = -EINVAL;
+ return r;
+ }
+ if ((radeon_get_ib_value(p, wait_reg_mem.idx + 2) << 2) != EVERGREEN_VLINE_STATUS) {
+ DRM_ERROR("vline WAIT_REG_MEM bad reg\n");
+ r = -EINVAL;
+ return r;
+ }
+
+ if (radeon_get_ib_value(p, wait_reg_mem.idx + 5) != EVERGREEN_VLINE_STAT) {
+ DRM_ERROR("vline WAIT_REG_MEM bad bit mask\n");
+ r = -EINVAL;
+ return r;
+ }
+
+ /* jump over the NOP */
+ r = evergreen_cs_packet_parse(p, &p3reloc, p->idx + wait_reg_mem.count + 2);
+ if (r)
+ return r;
+
+ h_idx = p->idx - 2;
+ p->idx += wait_reg_mem.count + 2;
+ p->idx += p3reloc.count + 2;
+
+ header = radeon_get_ib_value(p, h_idx);
+ crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
+ reg = CP_PACKET0_GET_REG(header);
+ mutex_lock(&p->rdev->ddev->mode_config.mutex);
+ obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
+ if (!obj) {
+ DRM_ERROR("cannot find crtc %d\n", crtc_id);
+ r = -EINVAL;
+ goto out;
+ }
+ crtc = obj_to_crtc(obj);
+ radeon_crtc = to_radeon_crtc(crtc);
+ crtc_id = radeon_crtc->crtc_id;
+
+ if (!crtc->enabled) {
+ /* if the CRTC isn't enabled - we need to nop out the WAIT_REG_MEM */
+ ib[h_idx + 2] = PACKET2(0);
+ ib[h_idx + 3] = PACKET2(0);
+ ib[h_idx + 4] = PACKET2(0);
+ ib[h_idx + 5] = PACKET2(0);
+ ib[h_idx + 6] = PACKET2(0);
+ ib[h_idx + 7] = PACKET2(0);
+ ib[h_idx + 8] = PACKET2(0);
+ } else {
+ switch (reg) {
+ case EVERGREEN_VLINE_START_END:
+ header &= ~R600_CP_PACKET0_REG_MASK;
+ header |= (EVERGREEN_VLINE_START_END + radeon_crtc->crtc_offset) >> 2;
+ ib[h_idx] = header;
+ ib[h_idx + 4] = (EVERGREEN_VLINE_STATUS + radeon_crtc->crtc_offset) >> 2;
+ break;
+ default:
+ DRM_ERROR("unknown crtc reloc\n");
+ r = -EINVAL;
+ goto out;
+ }
+ }
+out:
+ mutex_unlock(&p->rdev->ddev->mode_config.mutex);
+ return r;
+}
+
+static int evergreen_packet0_check(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt,
+ unsigned idx, unsigned reg)
+{
+ int r;
+
+ switch (reg) {
+ case EVERGREEN_VLINE_START_END:
+ r = evergreen_cs_packet_parse_vline(p);
+ if (r) {
+ DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
+ idx, reg);
+ return r;
+ }
+ break;
+ default:
+ printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n",
+ reg, idx);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt)
+{
+ unsigned reg, i;
+ unsigned idx;
+ int r;
+
+ idx = pkt->idx + 1;
+ reg = pkt->reg;
+ for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
+ r = evergreen_packet0_check(p, pkt, idx, reg);
+ if (r) {
+ return r;
+ }
+ }
+ return 0;
+}
+
+/**
+ * evergreen_cs_check_reg() - check if register is authorized or not
+ * @parser: parser structure holding parsing context
+ * @reg: register we are testing
+ * @idx: index into the cs buffer
+ *
+ * This function will test against evergreen_reg_safe_bm and return 0
+ * if register is safe. If register is not flag as safe this function
+ * will test it against a list of register needind special handling.
+ */
+static inline int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
+{
+ struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track;
+ struct radeon_cs_reloc *reloc;
+ u32 last_reg = ARRAY_SIZE(evergreen_reg_safe_bm);
+ u32 m, i, tmp, *ib;
+ int r;
+
+ i = (reg >> 7);
+ if (i > last_reg) {
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return -EINVAL;
+ }
+ m = 1 << ((reg >> 2) & 31);
+ if (!(evergreen_reg_safe_bm[i] & m))
+ return 0;
+ ib = p->ib->ptr;
+ switch (reg) {
+ /* force following reg to 0 in an attemp to disable out buffer
+ * which will need us to better understand how it works to perform
+ * security check on it (Jerome)
+ */
+ case SQ_ESGS_RING_SIZE:
+ case SQ_GSVS_RING_SIZE:
+ case SQ_ESTMP_RING_SIZE:
+ case SQ_GSTMP_RING_SIZE:
+ case SQ_HSTMP_RING_SIZE:
+ case SQ_LSTMP_RING_SIZE:
+ case SQ_PSTMP_RING_SIZE:
+ case SQ_VSTMP_RING_SIZE:
+ case SQ_ESGS_RING_ITEMSIZE:
+ case SQ_ESTMP_RING_ITEMSIZE:
+ case SQ_GSTMP_RING_ITEMSIZE:
+ case SQ_GSVS_RING_ITEMSIZE:
+ case SQ_GS_VERT_ITEMSIZE:
+ case SQ_GS_VERT_ITEMSIZE_1:
+ case SQ_GS_VERT_ITEMSIZE_2:
+ case SQ_GS_VERT_ITEMSIZE_3:
+ case SQ_GSVS_RING_OFFSET_1:
+ case SQ_GSVS_RING_OFFSET_2:
+ case SQ_GSVS_RING_OFFSET_3:
+ case SQ_HSTMP_RING_ITEMSIZE:
+ case SQ_LSTMP_RING_ITEMSIZE:
+ case SQ_PSTMP_RING_ITEMSIZE:
+ case SQ_VSTMP_RING_ITEMSIZE:
+ case VGT_TF_RING_SIZE:
+ /* get value to populate the IB don't remove */
+ tmp =radeon_get_ib_value(p, idx);
+ ib[idx] = 0;
+ break;
+ case DB_DEPTH_CONTROL:
+ track->db_depth_control = radeon_get_ib_value(p, idx);
+ break;
+ case DB_Z_INFO:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_z_info = radeon_get_ib_value(p, idx);
+ ib[idx] &= ~Z_ARRAY_MODE(0xf);
+ track->db_z_info &= ~Z_ARRAY_MODE(0xf);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ ib[idx] |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ track->db_z_info |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ } else {
+ ib[idx] |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ track->db_z_info |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ }
+ break;
+ case DB_STENCIL_INFO:
+ track->db_s_info = radeon_get_ib_value(p, idx);
+ break;
+ case DB_DEPTH_VIEW:
+ track->db_depth_view = radeon_get_ib_value(p, idx);
+ break;
+ case DB_DEPTH_SIZE:
+ track->db_depth_size = radeon_get_ib_value(p, idx);
+ track->db_depth_size_idx = idx;
+ break;
+ case DB_Z_READ_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_z_read_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->db_z_read_bo = reloc->robj;
+ break;
+ case DB_Z_WRITE_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_z_write_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->db_z_write_bo = reloc->robj;
+ break;
+ case DB_STENCIL_READ_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_s_read_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->db_s_read_bo = reloc->robj;
+ break;
+ case DB_STENCIL_WRITE_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ track->db_s_write_offset = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->db_s_write_bo = reloc->robj;
+ break;
+ case VGT_STRMOUT_CONFIG:
+ track->vgt_strmout_config = radeon_get_ib_value(p, idx);
+ break;
+ case VGT_STRMOUT_BUFFER_CONFIG:
+ track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx);
+ break;
+ case CB_TARGET_MASK:
+ track->cb_target_mask = radeon_get_ib_value(p, idx);
+ break;
+ case CB_SHADER_MASK:
+ track->cb_shader_mask = radeon_get_ib_value(p, idx);
+ break;
+ case PA_SC_AA_CONFIG:
+ tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK;
+ track->nsamples = 1 << tmp;
+ break;
+ case CB_COLOR0_VIEW:
+ case CB_COLOR1_VIEW:
+ case CB_COLOR2_VIEW:
+ case CB_COLOR3_VIEW:
+ case CB_COLOR4_VIEW:
+ case CB_COLOR5_VIEW:
+ case CB_COLOR6_VIEW:
+ case CB_COLOR7_VIEW:
+ tmp = (reg - CB_COLOR0_VIEW) / 0x3c;
+ track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+ break;
+ case CB_COLOR8_VIEW:
+ case CB_COLOR9_VIEW:
+ case CB_COLOR10_VIEW:
+ case CB_COLOR11_VIEW:
+ tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8;
+ track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
+ break;
+ case CB_COLOR0_INFO:
+ case CB_COLOR1_INFO:
+ case CB_COLOR2_INFO:
+ case CB_COLOR3_INFO:
+ case CB_COLOR4_INFO:
+ case CB_COLOR5_INFO:
+ case CB_COLOR6_INFO:
+ case CB_COLOR7_INFO:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - CB_COLOR0_INFO) / 0x3c;
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ }
+ break;
+ case CB_COLOR8_INFO:
+ case CB_COLOR9_INFO:
+ case CB_COLOR10_INFO:
+ case CB_COLOR11_INFO:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8;
+ track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+ ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+ ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ }
+ break;
+ case CB_COLOR0_PITCH:
+ case CB_COLOR1_PITCH:
+ case CB_COLOR2_PITCH:
+ case CB_COLOR3_PITCH:
+ case CB_COLOR4_PITCH:
+ case CB_COLOR5_PITCH:
+ case CB_COLOR6_PITCH:
+ case CB_COLOR7_PITCH:
+ tmp = (reg - CB_COLOR0_PITCH) / 0x3c;
+ track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_pitch_idx[tmp] = idx;
+ break;
+ case CB_COLOR8_PITCH:
+ case CB_COLOR9_PITCH:
+ case CB_COLOR10_PITCH:
+ case CB_COLOR11_PITCH:
+ tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8;
+ track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_pitch_idx[tmp] = idx;
+ break;
+ case CB_COLOR0_SLICE:
+ case CB_COLOR1_SLICE:
+ case CB_COLOR2_SLICE:
+ case CB_COLOR3_SLICE:
+ case CB_COLOR4_SLICE:
+ case CB_COLOR5_SLICE:
+ case CB_COLOR6_SLICE:
+ case CB_COLOR7_SLICE:
+ tmp = (reg - CB_COLOR0_SLICE) / 0x3c;
+ track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_slice_idx[tmp] = idx;
+ break;
+ case CB_COLOR8_SLICE:
+ case CB_COLOR9_SLICE:
+ case CB_COLOR10_SLICE:
+ case CB_COLOR11_SLICE:
+ tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8;
+ track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_slice_idx[tmp] = idx;
+ break;
+ case CB_COLOR0_ATTRIB:
+ case CB_COLOR1_ATTRIB:
+ case CB_COLOR2_ATTRIB:
+ case CB_COLOR3_ATTRIB:
+ case CB_COLOR4_ATTRIB:
+ case CB_COLOR5_ATTRIB:
+ case CB_COLOR6_ATTRIB:
+ case CB_COLOR7_ATTRIB:
+ case CB_COLOR8_ATTRIB:
+ case CB_COLOR9_ATTRIB:
+ case CB_COLOR10_ATTRIB:
+ case CB_COLOR11_ATTRIB:
+ break;
+ case CB_COLOR0_DIM:
+ case CB_COLOR1_DIM:
+ case CB_COLOR2_DIM:
+ case CB_COLOR3_DIM:
+ case CB_COLOR4_DIM:
+ case CB_COLOR5_DIM:
+ case CB_COLOR6_DIM:
+ case CB_COLOR7_DIM:
+ tmp = (reg - CB_COLOR0_DIM) / 0x3c;
+ track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_dim_idx[tmp] = idx;
+ break;
+ case CB_COLOR8_DIM:
+ case CB_COLOR9_DIM:
+ case CB_COLOR10_DIM:
+ case CB_COLOR11_DIM:
+ tmp = ((reg - CB_COLOR8_DIM) / 0x1c) + 8;
+ track->cb_color_dim[tmp] = radeon_get_ib_value(p, idx);
+ track->cb_color_dim_idx[tmp] = idx;
+ break;
+ case CB_COLOR0_FMASK:
+ case CB_COLOR1_FMASK:
+ case CB_COLOR2_FMASK:
+ case CB_COLOR3_FMASK:
+ case CB_COLOR4_FMASK:
+ case CB_COLOR5_FMASK:
+ case CB_COLOR6_FMASK:
+ case CB_COLOR7_FMASK:
+ tmp = (reg - CB_COLOR0_FMASK) / 0x3c;
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_fmask_bo[tmp] = reloc->robj;
+ break;
+ case CB_COLOR0_CMASK:
+ case CB_COLOR1_CMASK:
+ case CB_COLOR2_CMASK:
+ case CB_COLOR3_CMASK:
+ case CB_COLOR4_CMASK:
+ case CB_COLOR5_CMASK:
+ case CB_COLOR6_CMASK:
+ case CB_COLOR7_CMASK:
+ tmp = (reg - CB_COLOR0_CMASK) / 0x3c;
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_cmask_bo[tmp] = reloc->robj;
+ break;
+ case CB_COLOR0_FMASK_SLICE:
+ case CB_COLOR1_FMASK_SLICE:
+ case CB_COLOR2_FMASK_SLICE:
+ case CB_COLOR3_FMASK_SLICE:
+ case CB_COLOR4_FMASK_SLICE:
+ case CB_COLOR5_FMASK_SLICE:
+ case CB_COLOR6_FMASK_SLICE:
+ case CB_COLOR7_FMASK_SLICE:
+ tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c;
+ track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx);
+ break;
+ case CB_COLOR0_CMASK_SLICE:
+ case CB_COLOR1_CMASK_SLICE:
+ case CB_COLOR2_CMASK_SLICE:
+ case CB_COLOR3_CMASK_SLICE:
+ case CB_COLOR4_CMASK_SLICE:
+ case CB_COLOR5_CMASK_SLICE:
+ case CB_COLOR6_CMASK_SLICE:
+ case CB_COLOR7_CMASK_SLICE:
+ tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c;
+ track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx);
+ break;
+ case CB_COLOR0_BASE:
+ case CB_COLOR1_BASE:
+ case CB_COLOR2_BASE:
+ case CB_COLOR3_BASE:
+ case CB_COLOR4_BASE:
+ case CB_COLOR5_BASE:
+ case CB_COLOR6_BASE:
+ case CB_COLOR7_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = (reg - CB_COLOR0_BASE) / 0x3c;
+ track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_base_last[tmp] = ib[idx];
+ track->cb_color_bo[tmp] = reloc->robj;
+ break;
+ case CB_COLOR8_BASE:
+ case CB_COLOR9_BASE:
+ case CB_COLOR10_BASE:
+ case CB_COLOR11_BASE:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;
+ track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ track->cb_color_base_last[tmp] = ib[idx];
+ track->cb_color_bo[tmp] = reloc->robj;
+ break;
+ case CB_IMMED0_BASE:
+ case CB_IMMED1_BASE:
+ case CB_IMMED2_BASE:
+ case CB_IMMED3_BASE:
+ case CB_IMMED4_BASE:
+ case CB_IMMED5_BASE:
+ case CB_IMMED6_BASE:
+ case CB_IMMED7_BASE:
+ case CB_IMMED8_BASE:
+ case CB_IMMED9_BASE:
+ case CB_IMMED10_BASE:
+ case CB_IMMED11_BASE:
+ case DB_HTILE_DATA_BASE:
+ case SQ_PGM_START_FS:
+ case SQ_PGM_START_ES:
+ case SQ_PGM_START_VS:
+ case SQ_PGM_START_GS:
+ case SQ_PGM_START_PS:
+ case SQ_PGM_START_HS:
+ case SQ_PGM_START_LS:
+ case GDS_ADDR_BASE:
+ case SQ_CONST_MEM_BASE:
+ case SQ_ALU_CONST_CACHE_GS_0:
+ case SQ_ALU_CONST_CACHE_GS_1:
+ case SQ_ALU_CONST_CACHE_GS_2:
+ case SQ_ALU_CONST_CACHE_GS_3:
+ case SQ_ALU_CONST_CACHE_GS_4:
+ case SQ_ALU_CONST_CACHE_GS_5:
+ case SQ_ALU_CONST_CACHE_GS_6:
+ case SQ_ALU_CONST_CACHE_GS_7:
+ case SQ_ALU_CONST_CACHE_GS_8:
+ case SQ_ALU_CONST_CACHE_GS_9:
+ case SQ_ALU_CONST_CACHE_GS_10:
+ case SQ_ALU_CONST_CACHE_GS_11:
+ case SQ_ALU_CONST_CACHE_GS_12:
+ case SQ_ALU_CONST_CACHE_GS_13:
+ case SQ_ALU_CONST_CACHE_GS_14:
+ case SQ_ALU_CONST_CACHE_GS_15:
+ case SQ_ALU_CONST_CACHE_PS_0:
+ case SQ_ALU_CONST_CACHE_PS_1:
+ case SQ_ALU_CONST_CACHE_PS_2:
+ case SQ_ALU_CONST_CACHE_PS_3:
+ case SQ_ALU_CONST_CACHE_PS_4:
+ case SQ_ALU_CONST_CACHE_PS_5:
+ case SQ_ALU_CONST_CACHE_PS_6:
+ case SQ_ALU_CONST_CACHE_PS_7:
+ case SQ_ALU_CONST_CACHE_PS_8:
+ case SQ_ALU_CONST_CACHE_PS_9:
+ case SQ_ALU_CONST_CACHE_PS_10:
+ case SQ_ALU_CONST_CACHE_PS_11:
+ case SQ_ALU_CONST_CACHE_PS_12:
+ case SQ_ALU_CONST_CACHE_PS_13:
+ case SQ_ALU_CONST_CACHE_PS_14:
+ case SQ_ALU_CONST_CACHE_PS_15:
+ case SQ_ALU_CONST_CACHE_VS_0:
+ case SQ_ALU_CONST_CACHE_VS_1:
+ case SQ_ALU_CONST_CACHE_VS_2:
+ case SQ_ALU_CONST_CACHE_VS_3:
+ case SQ_ALU_CONST_CACHE_VS_4:
+ case SQ_ALU_CONST_CACHE_VS_5:
+ case SQ_ALU_CONST_CACHE_VS_6:
+ case SQ_ALU_CONST_CACHE_VS_7:
+ case SQ_ALU_CONST_CACHE_VS_8:
+ case SQ_ALU_CONST_CACHE_VS_9:
+ case SQ_ALU_CONST_CACHE_VS_10:
+ case SQ_ALU_CONST_CACHE_VS_11:
+ case SQ_ALU_CONST_CACHE_VS_12:
+ case SQ_ALU_CONST_CACHE_VS_13:
+ case SQ_ALU_CONST_CACHE_VS_14:
+ case SQ_ALU_CONST_CACHE_VS_15:
+ case SQ_ALU_CONST_CACHE_HS_0:
+ case SQ_ALU_CONST_CACHE_HS_1:
+ case SQ_ALU_CONST_CACHE_HS_2:
+ case SQ_ALU_CONST_CACHE_HS_3:
+ case SQ_ALU_CONST_CACHE_HS_4:
+ case SQ_ALU_CONST_CACHE_HS_5:
+ case SQ_ALU_CONST_CACHE_HS_6:
+ case SQ_ALU_CONST_CACHE_HS_7:
+ case SQ_ALU_CONST_CACHE_HS_8:
+ case SQ_ALU_CONST_CACHE_HS_9:
+ case SQ_ALU_CONST_CACHE_HS_10:
+ case SQ_ALU_CONST_CACHE_HS_11:
+ case SQ_ALU_CONST_CACHE_HS_12:
+ case SQ_ALU_CONST_CACHE_HS_13:
+ case SQ_ALU_CONST_CACHE_HS_14:
+ case SQ_ALU_CONST_CACHE_HS_15:
+ case SQ_ALU_CONST_CACHE_LS_0:
+ case SQ_ALU_CONST_CACHE_LS_1:
+ case SQ_ALU_CONST_CACHE_LS_2:
+ case SQ_ALU_CONST_CACHE_LS_3:
+ case SQ_ALU_CONST_CACHE_LS_4:
+ case SQ_ALU_CONST_CACHE_LS_5:
+ case SQ_ALU_CONST_CACHE_LS_6:
+ case SQ_ALU_CONST_CACHE_LS_7:
+ case SQ_ALU_CONST_CACHE_LS_8:
+ case SQ_ALU_CONST_CACHE_LS_9:
+ case SQ_ALU_CONST_CACHE_LS_10:
+ case SQ_ALU_CONST_CACHE_LS_11:
+ case SQ_ALU_CONST_CACHE_LS_12:
+ case SQ_ALU_CONST_CACHE_LS_13:
+ case SQ_ALU_CONST_CACHE_LS_14:
+ case SQ_ALU_CONST_CACHE_LS_15:
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ dev_warn(p->dev, "bad SET_CONTEXT_REG "
+ "0x%04X\n", reg);
+ return -EINVAL;
+ }
+ ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ break;
+ default:
+ dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * evergreen_check_texture_resource() - check if register is authorized or not
+ * @p: parser structure holding parsing context
+ * @idx: index into the cs buffer
+ * @texture: texture's bo structure
+ * @mipmap: mipmap's bo structure
+ *
+ * This function will check that the resource has valid field and that
+ * the texture and mipmap bo object are big enough to cover this resource.
+ */
+static inline int evergreen_check_texture_resource(struct radeon_cs_parser *p, u32 idx,
+ struct radeon_bo *texture,
+ struct radeon_bo *mipmap)
+{
+ /* XXX fill in */
+ return 0;
+}
+
+static int evergreen_packet3_check(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt)
+{
+ struct radeon_cs_reloc *reloc;
+ struct evergreen_cs_track *track;
+ volatile u32 *ib;
+ unsigned idx;
+ unsigned i;
+ unsigned start_reg, end_reg, reg;
+ int r;
+ u32 idx_value;
+
+ track = (struct evergreen_cs_track *)p->track;
+ ib = p->ib->ptr;
+ idx = pkt->idx + 1;
+ idx_value = radeon_get_ib_value(p, idx);
+
+ switch (pkt->opcode) {
+ case PACKET3_CONTEXT_CONTROL:
+ if (pkt->count != 1) {
+ DRM_ERROR("bad CONTEXT_CONTROL\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_INDEX_TYPE:
+ case PACKET3_NUM_INSTANCES:
+ case PACKET3_CLEAR_STATE:
+ if (pkt->count) {
+ DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_INDEX_BASE:
+ if (pkt->count != 1) {
+ DRM_ERROR("bad INDEX_BASE\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad INDEX_BASE\n");
+ return -EINVAL;
+ }
+ ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX:
+ if (pkt->count != 3) {
+ DRM_ERROR("bad DRAW_INDEX\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad DRAW_INDEX\n");
+ return -EINVAL;
+ }
+ ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+1] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_2:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad DRAW_INDEX_2\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad DRAW_INDEX_2\n");
+ return -EINVAL;
+ }
+ ib[idx+1] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_AUTO:
+ if (pkt->count != 1) {
+ DRM_ERROR("bad DRAW_INDEX_AUTO\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_MULTI_AUTO:
+ if (pkt->count != 2) {
+ DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_IMMD:
+ if (pkt->count < 2) {
+ DRM_ERROR("bad DRAW_INDEX_IMMD\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_OFFSET:
+ if (pkt->count != 2) {
+ DRM_ERROR("bad DRAW_INDEX_OFFSET\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_DRAW_INDEX_OFFSET_2:
+ if (pkt->count != 3) {
+ DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ case PACKET3_WAIT_REG_MEM:
+ if (pkt->count != 5) {
+ DRM_ERROR("bad WAIT_REG_MEM\n");
+ return -EINVAL;
+ }
+ /* bit 4 is reg (0) or mem (1) */
+ if (idx_value & 0x10) {
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad WAIT_REG_MEM\n");
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ break;
+ case PACKET3_SURFACE_SYNC:
+ if (pkt->count != 3) {
+ DRM_ERROR("bad SURFACE_SYNC\n");
+ return -EINVAL;
+ }
+ /* 0xffffffff/0x0 is flush all cache flag */
+ if (radeon_get_ib_value(p, idx + 1) != 0xffffffff ||
+ radeon_get_ib_value(p, idx + 2) != 0) {
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad SURFACE_SYNC\n");
+ return -EINVAL;
+ }
+ ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ }
+ break;
+ case PACKET3_EVENT_WRITE:
+ if (pkt->count != 2 && pkt->count != 0) {
+ DRM_ERROR("bad EVENT_WRITE\n");
+ return -EINVAL;
+ }
+ if (pkt->count) {
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad EVENT_WRITE\n");
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ }
+ break;
+ case PACKET3_EVENT_WRITE_EOP:
+ if (pkt->count != 4) {
+ DRM_ERROR("bad EVENT_WRITE_EOP\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad EVENT_WRITE_EOP\n");
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ break;
+ case PACKET3_EVENT_WRITE_EOS:
+ if (pkt->count != 3) {
+ DRM_ERROR("bad EVENT_WRITE_EOS\n");
+ return -EINVAL;
+ }
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad EVENT_WRITE_EOS\n");
+ return -EINVAL;
+ }
+ ib[idx+1] += (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+ ib[idx+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ break;
+ case PACKET3_SET_CONFIG_REG:
+ start_reg = (idx_value << 2) + PACKET3_SET_CONFIG_REG_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_CONFIG_REG_START) ||
+ (start_reg >= PACKET3_SET_CONFIG_REG_END) ||
+ (end_reg >= PACKET3_SET_CONFIG_REG_END)) {
+ DRM_ERROR("bad PACKET3_SET_CONFIG_REG\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < pkt->count; i++) {
+ reg = start_reg + (4 * i);
+ r = evergreen_cs_check_reg(p, reg, idx+1+i);
+ if (r)
+ return r;
+ }
+ break;
+ case PACKET3_SET_CONTEXT_REG:
+ start_reg = (idx_value << 2) + PACKET3_SET_CONTEXT_REG_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_CONTEXT_REG_START) ||
+ (start_reg >= PACKET3_SET_CONTEXT_REG_END) ||
+ (end_reg >= PACKET3_SET_CONTEXT_REG_END)) {
+ DRM_ERROR("bad PACKET3_SET_CONTEXT_REG\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < pkt->count; i++) {
+ reg = start_reg + (4 * i);
+ r = evergreen_cs_check_reg(p, reg, idx+1+i);
+ if (r)
+ return r;
+ }
+ break;
+ case PACKET3_SET_RESOURCE:
+ if (pkt->count % 8) {
+ DRM_ERROR("bad SET_RESOURCE\n");
+ return -EINVAL;
+ }
+ start_reg = (idx_value << 2) + PACKET3_SET_RESOURCE_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_RESOURCE_START) ||
+ (start_reg >= PACKET3_SET_RESOURCE_END) ||
+ (end_reg >= PACKET3_SET_RESOURCE_END)) {
+ DRM_ERROR("bad SET_RESOURCE\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < (pkt->count / 8); i++) {
+ struct radeon_bo *texture, *mipmap;
+ u32 size, offset;
+
+ switch (G__SQ_CONSTANT_TYPE(radeon_get_ib_value(p, idx+1+(i*8)+7))) {
+ case SQ_TEX_VTX_VALID_TEXTURE:
+ /* tex base */
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad SET_RESOURCE (tex)\n");
+ return -EINVAL;
+ }
+ ib[idx+1+(i*8)+3] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+ ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_2D_TILED_THIN1);
+ else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+ ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_1D_TILED_THIN1);
+ texture = reloc->robj;
+ /* tex mip base */
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad SET_RESOURCE (tex)\n");
+ return -EINVAL;
+ }
+ ib[idx+1+(i*8)+4] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+ mipmap = reloc->robj;
+ r = evergreen_check_texture_resource(p, idx+1+(i*8),
+ texture, mipmap);
+ if (r)
+ return r;
+ break;
+ case SQ_TEX_VTX_VALID_BUFFER:
+ /* vtx base */
+ r = evergreen_cs_packet_next_reloc(p, &reloc);
+ if (r) {
+ DRM_ERROR("bad SET_RESOURCE (vtx)\n");
+ return -EINVAL;
+ }
+ offset = radeon_get_ib_value(p, idx+1+(i*8)+0);
+ size = radeon_get_ib_value(p, idx+1+(i*8)+1);
+ if (p->rdev && (size + offset) > radeon_bo_size(reloc->robj)) {
+ /* force size to size of the buffer */
+ dev_warn(p->dev, "vbo resource seems too big for the bo\n");
+ ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj);
+ }
+ ib[idx+1+(i*8)+0] += (u32)((reloc->lobj.gpu_offset) & 0xffffffff);
+ ib[idx+1+(i*8)+2] += upper_32_bits(reloc->lobj.gpu_offset) & 0xff;
+ break;
+ case SQ_TEX_VTX_INVALID_TEXTURE:
+ case SQ_TEX_VTX_INVALID_BUFFER:
+ default:
+ DRM_ERROR("bad SET_RESOURCE\n");
+ return -EINVAL;
+ }
+ }
+ break;
+ case PACKET3_SET_ALU_CONST:
+ /* XXX fix me ALU const buffers only */
+ break;
+ case PACKET3_SET_BOOL_CONST:
+ start_reg = (idx_value << 2) + PACKET3_SET_BOOL_CONST_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_BOOL_CONST_START) ||
+ (start_reg >= PACKET3_SET_BOOL_CONST_END) ||
+ (end_reg >= PACKET3_SET_BOOL_CONST_END)) {
+ DRM_ERROR("bad SET_BOOL_CONST\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_SET_LOOP_CONST:
+ start_reg = (idx_value << 2) + PACKET3_SET_LOOP_CONST_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_LOOP_CONST_START) ||
+ (start_reg >= PACKET3_SET_LOOP_CONST_END) ||
+ (end_reg >= PACKET3_SET_LOOP_CONST_END)) {
+ DRM_ERROR("bad SET_LOOP_CONST\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_SET_CTL_CONST:
+ start_reg = (idx_value << 2) + PACKET3_SET_CTL_CONST_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_CTL_CONST_START) ||
+ (start_reg >= PACKET3_SET_CTL_CONST_END) ||
+ (end_reg >= PACKET3_SET_CTL_CONST_END)) {
+ DRM_ERROR("bad SET_CTL_CONST\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_SET_SAMPLER:
+ if (pkt->count % 3) {
+ DRM_ERROR("bad SET_SAMPLER\n");
+ return -EINVAL;
+ }
+ start_reg = (idx_value << 2) + PACKET3_SET_SAMPLER_START;
+ end_reg = 4 * pkt->count + start_reg - 4;
+ if ((start_reg < PACKET3_SET_SAMPLER_START) ||
+ (start_reg >= PACKET3_SET_SAMPLER_END) ||
+ (end_reg >= PACKET3_SET_SAMPLER_END)) {
+ DRM_ERROR("bad SET_SAMPLER\n");
+ return -EINVAL;
+ }
+ break;
+ case PACKET3_NOP:
+ break;
+ default:
+ DRM_ERROR("Packet3 opcode %x not supported\n", pkt->opcode);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int evergreen_cs_parse(struct radeon_cs_parser *p)
+{
+ struct radeon_cs_packet pkt;
+ struct evergreen_cs_track *track;
+ int r;
+
+ if (p->track == NULL) {
+ /* initialize tracker, we are in kms */
+ track = kzalloc(sizeof(*track), GFP_KERNEL);
+ if (track == NULL)
+ return -ENOMEM;
+ evergreen_cs_track_init(track);
+ track->npipes = p->rdev->config.evergreen.tiling_npipes;
+ track->nbanks = p->rdev->config.evergreen.tiling_nbanks;
+ track->group_size = p->rdev->config.evergreen.tiling_group_size;
+ p->track = track;
+ }
+ do {
+ r = evergreen_cs_packet_parse(p, &pkt, p->idx);
+ if (r) {
+ kfree(p->track);
+ p->track = NULL;
+ return r;
+ }
+ p->idx += pkt.count + 2;
+ switch (pkt.type) {
+ case PACKET_TYPE0:
+ r = evergreen_cs_parse_packet0(p, &pkt);
+ break;
+ case PACKET_TYPE2:
+ break;
+ case PACKET_TYPE3:
+ r = evergreen_packet3_check(p, &pkt);
+ break;
+ default:
+ DRM_ERROR("Unknown packet type %d !\n", pkt.type);
+ kfree(p->track);
+ p->track = NULL;
+ return -EINVAL;
+ }
+ if (r) {
+ kfree(p->track);
+ p->track = NULL;
+ return r;
+ }
+ } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw);
+#if 0
+ for (r = 0; r < p->ib->length_dw; r++) {
+ printk(KERN_INFO "%05d 0x%08X\n", r, p->ib->ptr[r]);
+ mdelay(1);
+ }
+#endif
+ kfree(p->track);
+ p->track = NULL;
+ return 0;
+}
+
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index af86af836f13..e028c1cd9d9b 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -151,6 +151,9 @@
#define EVERGREEN_DATA_FORMAT 0x6b00
# define EVERGREEN_INTERLEAVE_EN (1 << 0)
#define EVERGREEN_DESKTOP_HEIGHT 0x6b04
+#define EVERGREEN_VLINE_START_END 0x6b08
+#define EVERGREEN_VLINE_STATUS 0x6bb8
+# define EVERGREEN_VLINE_STAT (1 << 12)
#define EVERGREEN_VIEWPORT_START 0x6d70
#define EVERGREEN_VIEWPORT_SIZE 0x6d74
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index 93e9e17ad54a..79683f6b4452 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -218,6 +218,8 @@
#define CLIP_VTX_REORDER_ENA (1 << 0)
#define NUM_CLIP_SEQ(x) ((x) << 1)
#define PA_SC_AA_CONFIG 0x28C04
+#define MSAA_NUM_SAMPLES_SHIFT 0
+#define MSAA_NUM_SAMPLES_MASK 0x3
#define PA_SC_CLIPRECT_RULE 0x2820C
#define PA_SC_EDGERULE 0x28230
#define PA_SC_FIFO_SIZE 0x8BCC
@@ -553,4 +555,466 @@
# define DC_HPDx_RX_INT_TIMER(x) ((x) << 16)
# define DC_HPDx_EN (1 << 28)
+/*
+ * PM4
+ */
+#define PACKET_TYPE0 0
+#define PACKET_TYPE1 1
+#define PACKET_TYPE2 2
+#define PACKET_TYPE3 3
+
+#define CP_PACKET_GET_TYPE(h) (((h) >> 30) & 3)
+#define CP_PACKET_GET_COUNT(h) (((h) >> 16) & 0x3FFF)
+#define CP_PACKET0_GET_REG(h) (((h) & 0xFFFF) << 2)
+#define CP_PACKET3_GET_OPCODE(h) (((h) >> 8) & 0xFF)
+#define PACKET0(reg, n) ((PACKET_TYPE0 << 30) | \
+ (((reg) >> 2) & 0xFFFF) | \
+ ((n) & 0x3FFF) << 16)
+#define CP_PACKET2 0x80000000
+#define PACKET2_PAD_SHIFT 0
+#define PACKET2_PAD_MASK (0x3fffffff << 0)
+
+#define PACKET2(v) (CP_PACKET2 | REG_SET(PACKET2_PAD, (v)))
+
+#define PACKET3(op, n) ((PACKET_TYPE3 << 30) | \
+ (((op) & 0xFF) << 8) | \
+ ((n) & 0x3FFF) << 16)
+
+/* Packet 3 types */
+#define PACKET3_NOP 0x10
+#define PACKET3_SET_BASE 0x11
+#define PACKET3_CLEAR_STATE 0x12
+#define PACKET3_INDIRECT_BUFFER_SIZE 0x13
+#define PACKET3_DISPATCH_DIRECT 0x15
+#define PACKET3_DISPATCH_INDIRECT 0x16
+#define PACKET3_INDIRECT_BUFFER_END 0x17
+#define PACKET3_SET_PREDICATION 0x20
+#define PACKET3_REG_RMW 0x21
+#define PACKET3_COND_EXEC 0x22
+#define PACKET3_PRED_EXEC 0x23
+#define PACKET3_DRAW_INDIRECT 0x24
+#define PACKET3_DRAW_INDEX_INDIRECT 0x25
+#define PACKET3_INDEX_BASE 0x26
+#define PACKET3_DRAW_INDEX_2 0x27
+#define PACKET3_CONTEXT_CONTROL 0x28
+#define PACKET3_DRAW_INDEX_OFFSET 0x29
+#define PACKET3_INDEX_TYPE 0x2A
+#define PACKET3_DRAW_INDEX 0x2B
+#define PACKET3_DRAW_INDEX_AUTO 0x2D
+#define PACKET3_DRAW_INDEX_IMMD 0x2E
+#define PACKET3_NUM_INSTANCES 0x2F
+#define PACKET3_DRAW_INDEX_MULTI_AUTO 0x30
+#define PACKET3_STRMOUT_BUFFER_UPDATE 0x34
+#define PACKET3_DRAW_INDEX_OFFSET_2 0x35
+#define PACKET3_DRAW_INDEX_MULTI_ELEMENT 0x36
+#define PACKET3_MEM_SEMAPHORE 0x39
+#define PACKET3_MPEG_INDEX 0x3A
+#define PACKET3_WAIT_REG_MEM 0x3C
+#define PACKET3_MEM_WRITE 0x3D
+#define PACKET3_INDIRECT_BUFFER 0x32
+#define PACKET3_SURFACE_SYNC 0x43
+# define PACKET3_CB0_DEST_BASE_ENA (1 << 6)
+# define PACKET3_CB1_DEST_BASE_ENA (1 << 7)
+# define PACKET3_CB2_DEST_BASE_ENA (1 << 8)
+# define PACKET3_CB3_DEST_BASE_ENA (1 << 9)
+# define PACKET3_CB4_DEST_BASE_ENA (1 << 10)
+# define PACKET3_CB5_DEST_BASE_ENA (1 << 11)
+# define PACKET3_CB6_DEST_BASE_ENA (1 << 12)
+# define PACKET3_CB7_DEST_BASE_ENA (1 << 13)
+# define PACKET3_DB_DEST_BASE_ENA (1 << 14)
+# define PACKET3_CB8_DEST_BASE_ENA (1 << 15)
+# define PACKET3_CB9_DEST_BASE_ENA (1 << 16)
+# define PACKET3_CB10_DEST_BASE_ENA (1 << 17)
+# define PACKET3_CB11_DEST_BASE_ENA (1 << 17)
+# define PACKET3_FULL_CACHE_ENA (1 << 20)
+# define PACKET3_TC_ACTION_ENA (1 << 23)
+# define PACKET3_VC_ACTION_ENA (1 << 24)
+# define PACKET3_CB_ACTION_ENA (1 << 25)
+# define PACKET3_DB_ACTION_ENA (1 << 26)
+# define PACKET3_SH_ACTION_ENA (1 << 27)
+# define PACKET3_SMX_ACTION_ENA (1 << 28)
+#define PACKET3_ME_INITIALIZE 0x44
+#define PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
+#define PACKET3_COND_WRITE 0x45
+#define PACKET3_EVENT_WRITE 0x46
+#define PACKET3_EVENT_WRITE_EOP 0x47
+#define PACKET3_EVENT_WRITE_EOS 0x48
+#define PACKET3_PREAMBLE_CNTL 0x4A
+#define PACKET3_RB_OFFSET 0x4B
+#define PACKET3_ALU_PS_CONST_BUFFER_COPY 0x4C
+#define PACKET3_ALU_VS_CONST_BUFFER_COPY 0x4D
+#define PACKET3_ALU_PS_CONST_UPDATE 0x4E
+#define PACKET3_ALU_VS_CONST_UPDATE 0x4F
+#define PACKET3_ONE_REG_WRITE 0x57
+#define PACKET3_SET_CONFIG_REG 0x68
+#define PACKET3_SET_CONFIG_REG_START 0x00008000
+#define PACKET3_SET_CONFIG_REG_END 0x0000ac00
+#define PACKET3_SET_CONTEXT_REG 0x69
+#define PACKET3_SET_CONTEXT_REG_START 0x00028000
+#define PACKET3_SET_CONTEXT_REG_END 0x00029000
+#define PACKET3_SET_ALU_CONST 0x6A
+/* alu const buffers only; no reg file */
+#define PACKET3_SET_BOOL_CONST 0x6B
+#define PACKET3_SET_BOOL_CONST_START 0x0003a500
+#define PACKET3_SET_BOOL_CONST_END 0x0003a518
+#define PACKET3_SET_LOOP_CONST 0x6C
+#define PACKET3_SET_LOOP_CONST_START 0x0003a200
+#define PACKET3_SET_LOOP_CONST_END 0x0003a500
+#define PACKET3_SET_RESOURCE 0x6D
+#define PACKET3_SET_RESOURCE_START 0x00030000
+#define PACKET3_SET_RESOURCE_END 0x00038000
+#define PACKET3_SET_SAMPLER 0x6E
+#define PACKET3_SET_SAMPLER_START 0x0003c000
+#define PACKET3_SET_SAMPLER_END 0x0003c600
+#define PACKET3_SET_CTL_CONST 0x6F
+#define PACKET3_SET_CTL_CONST_START 0x0003cff0
+#define PACKET3_SET_CTL_CONST_END 0x0003ff0c
+#define PACKET3_SET_RESOURCE_OFFSET 0x70
+#define PACKET3_SET_ALU_CONST_VS 0x71
+#define PACKET3_SET_ALU_CONST_DI 0x72
+#define PACKET3_SET_CONTEXT_REG_INDIRECT 0x73
+#define PACKET3_SET_RESOURCE_INDIRECT 0x74
+#define PACKET3_SET_APPEND_CNT 0x75
+
+#define SQ_RESOURCE_CONSTANT_WORD7_0 0x3001c
+#define S__SQ_CONSTANT_TYPE(x) (((x) & 3) << 30)
+#define G__SQ_CONSTANT_TYPE(x) (((x) >> 30) & 3)
+#define SQ_TEX_VTX_INVALID_TEXTURE 0x0
+#define SQ_TEX_VTX_INVALID_BUFFER 0x1
+#define SQ_TEX_VTX_VALID_TEXTURE 0x2
+#define SQ_TEX_VTX_VALID_BUFFER 0x3
+
+#define SQ_CONST_MEM_BASE 0x8df8
+
+#define SQ_ESGS_RING_SIZE 0x8c44
+#define SQ_GSVS_RING_SIZE 0x8c4c
+#define SQ_ESTMP_RING_SIZE 0x8c54
+#define SQ_GSTMP_RING_SIZE 0x8c5c
+#define SQ_VSTMP_RING_SIZE 0x8c64
+#define SQ_PSTMP_RING_SIZE 0x8c6c
+#define SQ_LSTMP_RING_SIZE 0x8e14
+#define SQ_HSTMP_RING_SIZE 0x8e1c
+#define VGT_TF_RING_SIZE 0x8988
+
+#define SQ_ESGS_RING_ITEMSIZE 0x28900
+#define SQ_GSVS_RING_ITEMSIZE 0x28904
+#define SQ_ESTMP_RING_ITEMSIZE 0x28908
+#define SQ_GSTMP_RING_ITEMSIZE 0x2890c
+#define SQ_VSTMP_RING_ITEMSIZE 0x28910
+#define SQ_PSTMP_RING_ITEMSIZE 0x28914
+#define SQ_LSTMP_RING_ITEMSIZE 0x28830
+#define SQ_HSTMP_RING_ITEMSIZE 0x28834
+
+#define SQ_GS_VERT_ITEMSIZE 0x2891c
+#define SQ_GS_VERT_ITEMSIZE_1 0x28920
+#define SQ_GS_VERT_ITEMSIZE_2 0x28924
+#define SQ_GS_VERT_ITEMSIZE_3 0x28928
+#define SQ_GSVS_RING_OFFSET_1 0x2892c
+#define SQ_GSVS_RING_OFFSET_2 0x28930
+#define SQ_GSVS_RING_OFFSET_3 0x28934
+
+#define SQ_ALU_CONST_CACHE_PS_0 0x28940
+#define SQ_ALU_CONST_CACHE_PS_1 0x28944
+#define SQ_ALU_CONST_CACHE_PS_2 0x28948
+#define SQ_ALU_CONST_CACHE_PS_3 0x2894c
+#define SQ_ALU_CONST_CACHE_PS_4 0x28950
+#define SQ_ALU_CONST_CACHE_PS_5 0x28954
+#define SQ_ALU_CONST_CACHE_PS_6 0x28958
+#define SQ_ALU_CONST_CACHE_PS_7 0x2895c
+#define SQ_ALU_CONST_CACHE_PS_8 0x28960
+#define SQ_ALU_CONST_CACHE_PS_9 0x28964
+#define SQ_ALU_CONST_CACHE_PS_10 0x28968
+#define SQ_ALU_CONST_CACHE_PS_11 0x2896c
+#define SQ_ALU_CONST_CACHE_PS_12 0x28970
+#define SQ_ALU_CONST_CACHE_PS_13 0x28974
+#define SQ_ALU_CONST_CACHE_PS_14 0x28978
+#define SQ_ALU_CONST_CACHE_PS_15 0x2897c
+#define SQ_ALU_CONST_CACHE_VS_0 0x28980
+#define SQ_ALU_CONST_CACHE_VS_1 0x28984
+#define SQ_ALU_CONST_CACHE_VS_2 0x28988
+#define SQ_ALU_CONST_CACHE_VS_3 0x2898c
+#define SQ_ALU_CONST_CACHE_VS_4 0x28990
+#define SQ_ALU_CONST_CACHE_VS_5 0x28994
+#define SQ_ALU_CONST_CACHE_VS_6 0x28998
+#define SQ_ALU_CONST_CACHE_VS_7 0x2899c
+#define SQ_ALU_CONST_CACHE_VS_8 0x289a0
+#define SQ_ALU_CONST_CACHE_VS_9 0x289a4
+#define SQ_ALU_CONST_CACHE_VS_10 0x289a8
+#define SQ_ALU_CONST_CACHE_VS_11 0x289ac
+#define SQ_ALU_CONST_CACHE_VS_12 0x289b0
+#define SQ_ALU_CONST_CACHE_VS_13 0x289b4
+#define SQ_ALU_CONST_CACHE_VS_14 0x289b8
+#define SQ_ALU_CONST_CACHE_VS_15 0x289bc
+#define SQ_ALU_CONST_CACHE_GS_0 0x289c0
+#define SQ_ALU_CONST_CACHE_GS_1 0x289c4
+#define SQ_ALU_CONST_CACHE_GS_2 0x289c8
+#define SQ_ALU_CONST_CACHE_GS_3 0x289cc
+#define SQ_ALU_CONST_CACHE_GS_4 0x289d0
+#define SQ_ALU_CONST_CACHE_GS_5 0x289d4
+#define SQ_ALU_CONST_CACHE_GS_6 0x289d8
+#define SQ_ALU_CONST_CACHE_GS_7 0x289dc
+#define SQ_ALU_CONST_CACHE_GS_8 0x289e0
+#define SQ_ALU_CONST_CACHE_GS_9 0x289e4
+#define SQ_ALU_CONST_CACHE_GS_10 0x289e8
+#define SQ_ALU_CONST_CACHE_GS_11 0x289ec
+#define SQ_ALU_CONST_CACHE_GS_12 0x289f0
+#define SQ_ALU_CONST_CACHE_GS_13 0x289f4
+#define SQ_ALU_CONST_CACHE_GS_14 0x289f8
+#define SQ_ALU_CONST_CACHE_GS_15 0x289fc
+#define SQ_ALU_CONST_CACHE_HS_0 0x28f00
+#define SQ_ALU_CONST_CACHE_HS_1 0x28f04
+#define SQ_ALU_CONST_CACHE_HS_2 0x28f08
+#define SQ_ALU_CONST_CACHE_HS_3 0x28f0c
+#define SQ_ALU_CONST_CACHE_HS_4 0x28f10
+#define SQ_ALU_CONST_CACHE_HS_5 0x28f14
+#define SQ_ALU_CONST_CACHE_HS_6 0x28f18
+#define SQ_ALU_CONST_CACHE_HS_7 0x28f1c
+#define SQ_ALU_CONST_CACHE_HS_8 0x28f20
+#define SQ_ALU_CONST_CACHE_HS_9 0x28f24
+#define SQ_ALU_CONST_CACHE_HS_10 0x28f28
+#define SQ_ALU_CONST_CACHE_HS_11 0x28f2c
+#define SQ_ALU_CONST_CACHE_HS_12 0x28f30
+#define SQ_ALU_CONST_CACHE_HS_13 0x28f34
+#define SQ_ALU_CONST_CACHE_HS_14 0x28f38
+#define SQ_ALU_CONST_CACHE_HS_15 0x28f3c
+#define SQ_ALU_CONST_CACHE_LS_0 0x28f40
+#define SQ_ALU_CONST_CACHE_LS_1 0x28f44
+#define SQ_ALU_CONST_CACHE_LS_2 0x28f48
+#define SQ_ALU_CONST_CACHE_LS_3 0x28f4c
+#define SQ_ALU_CONST_CACHE_LS_4 0x28f50
+#define SQ_ALU_CONST_CACHE_LS_5 0x28f54
+#define SQ_ALU_CONST_CACHE_LS_6 0x28f58
+#define SQ_ALU_CONST_CACHE_LS_7 0x28f5c
+#define SQ_ALU_CONST_CACHE_LS_8 0x28f60
+#define SQ_ALU_CONST_CACHE_LS_9 0x28f64
+#define SQ_ALU_CONST_CACHE_LS_10 0x28f68
+#define SQ_ALU_CONST_CACHE_LS_11 0x28f6c
+#define SQ_ALU_CONST_CACHE_LS_12 0x28f70
+#define SQ_ALU_CONST_CACHE_LS_13 0x28f74
+#define SQ_ALU_CONST_CACHE_LS_14 0x28f78
+#define SQ_ALU_CONST_CACHE_LS_15 0x28f7c
+
+#define DB_DEPTH_CONTROL 0x28800
+#define DB_DEPTH_VIEW 0x28008
+#define DB_HTILE_DATA_BASE 0x28014
+#define DB_Z_INFO 0x28040
+# define Z_ARRAY_MODE(x) ((x) << 4)
+#define DB_STENCIL_INFO 0x28044
+#define DB_Z_READ_BASE 0x28048
+#define DB_STENCIL_READ_BASE 0x2804c
+#define DB_Z_WRITE_BASE 0x28050
+#define DB_STENCIL_WRITE_BASE 0x28054
+#define DB_DEPTH_SIZE 0x28058
+
+#define SQ_PGM_START_PS 0x28840
+#define SQ_PGM_START_VS 0x2885c
+#define SQ_PGM_START_GS 0x28874
+#define SQ_PGM_START_ES 0x2888c
+#define SQ_PGM_START_FS 0x288a4
+#define SQ_PGM_START_HS 0x288b8
+#define SQ_PGM_START_LS 0x288d0
+
+#define VGT_STRMOUT_CONFIG 0x28b94
+#define VGT_STRMOUT_BUFFER_CONFIG 0x28b98
+
+#define CB_TARGET_MASK 0x28238
+#define CB_SHADER_MASK 0x2823c
+
+#define GDS_ADDR_BASE 0x28720
+
+#define CB_IMMED0_BASE 0x28b9c
+#define CB_IMMED1_BASE 0x28ba0
+#define CB_IMMED2_BASE 0x28ba4
+#define CB_IMMED3_BASE 0x28ba8
+#define CB_IMMED4_BASE 0x28bac
+#define CB_IMMED5_BASE 0x28bb0
+#define CB_IMMED6_BASE 0x28bb4
+#define CB_IMMED7_BASE 0x28bb8
+#define CB_IMMED8_BASE 0x28bbc
+#define CB_IMMED9_BASE 0x28bc0
+#define CB_IMMED10_BASE 0x28bc4
+#define CB_IMMED11_BASE 0x28bc8
+
+/* all 12 CB blocks have these regs */
+#define CB_COLOR0_BASE 0x28c60
+#define CB_COLOR0_PITCH 0x28c64
+#define CB_COLOR0_SLICE 0x28c68
+#define CB_COLOR0_VIEW 0x28c6c
+#define CB_COLOR0_INFO 0x28c70
+# define CB_ARRAY_MODE(x) ((x) << 8)
+# define ARRAY_LINEAR_GENERAL 0
+# define ARRAY_LINEAR_ALIGNED 1
+# define ARRAY_1D_TILED_THIN1 2
+# define ARRAY_2D_TILED_THIN1 4
+#define CB_COLOR0_ATTRIB 0x28c74
+#define CB_COLOR0_DIM 0x28c78
+/* only CB0-7 blocks have these regs */
+#define CB_COLOR0_CMASK 0x28c7c
+#define CB_COLOR0_CMASK_SLICE 0x28c80
+#define CB_COLOR0_FMASK 0x28c84
+#define CB_COLOR0_FMASK_SLICE 0x28c88
+#define CB_COLOR0_CLEAR_WORD0 0x28c8c
+#define CB_COLOR0_CLEAR_WORD1 0x28c90
+#define CB_COLOR0_CLEAR_WORD2 0x28c94
+#define CB_COLOR0_CLEAR_WORD3 0x28c98
+
+#define CB_COLOR1_BASE 0x28c9c
+#define CB_COLOR2_BASE 0x28cd8
+#define CB_COLOR3_BASE 0x28d14
+#define CB_COLOR4_BASE 0x28d50
+#define CB_COLOR5_BASE 0x28d8c
+#define CB_COLOR6_BASE 0x28dc8
+#define CB_COLOR7_BASE 0x28e04
+#define CB_COLOR8_BASE 0x28e40
+#define CB_COLOR9_BASE 0x28e5c
+#define CB_COLOR10_BASE 0x28e78
+#define CB_COLOR11_BASE 0x28e94
+
+#define CB_COLOR1_PITCH 0x28ca0
+#define CB_COLOR2_PITCH 0x28cdc
+#define CB_COLOR3_PITCH 0x28d18
+#define CB_COLOR4_PITCH 0x28d54
+#define CB_COLOR5_PITCH 0x28d90
+#define CB_COLOR6_PITCH 0x28dcc
+#define CB_COLOR7_PITCH 0x28e08
+#define CB_COLOR8_PITCH 0x28e44
+#define CB_COLOR9_PITCH 0x28e60
+#define CB_COLOR10_PITCH 0x28e7c
+#define CB_COLOR11_PITCH 0x28e98
+
+#define CB_COLOR1_SLICE 0x28ca4
+#define CB_COLOR2_SLICE 0x28ce0
+#define CB_COLOR3_SLICE 0x28d1c
+#define CB_COLOR4_SLICE 0x28d58
+#define CB_COLOR5_SLICE 0x28d94
+#define CB_COLOR6_SLICE 0x28dd0
+#define CB_COLOR7_SLICE 0x28e0c
+#define CB_COLOR8_SLICE 0x28e48
+#define CB_COLOR9_SLICE 0x28e64
+#define CB_COLOR10_SLICE 0x28e80
+#define CB_COLOR11_SLICE 0x28e9c
+
+#define CB_COLOR1_VIEW 0x28ca8
+#define CB_COLOR2_VIEW 0x28ce4
+#define CB_COLOR3_VIEW 0x28d20
+#define CB_COLOR4_VIEW 0x28d5c
+#define CB_COLOR5_VIEW 0x28d98
+#define CB_COLOR6_VIEW 0x28dd4
+#define CB_COLOR7_VIEW 0x28e10
+#define CB_COLOR8_VIEW 0x28e4c
+#define CB_COLOR9_VIEW 0x28e68
+#define CB_COLOR10_VIEW 0x28e84
+#define CB_COLOR11_VIEW 0x28ea0
+
+#define CB_COLOR1_INFO 0x28cac
+#define CB_COLOR2_INFO 0x28ce8
+#define CB_COLOR3_INFO 0x28d24
+#define CB_COLOR4_INFO 0x28d60
+#define CB_COLOR5_INFO 0x28d9c
+#define CB_COLOR6_INFO 0x28dd8
+#define CB_COLOR7_INFO 0x28e14
+#define CB_COLOR8_INFO 0x28e50
+#define CB_COLOR9_INFO 0x28e6c
+#define CB_COLOR10_INFO 0x28e88
+#define CB_COLOR11_INFO 0x28ea4
+
+#define CB_COLOR1_ATTRIB 0x28cb0
+#define CB_COLOR2_ATTRIB 0x28cec
+#define CB_COLOR3_ATTRIB 0x28d28
+#define CB_COLOR4_ATTRIB 0x28d64
+#define CB_COLOR5_ATTRIB 0x28da0
+#define CB_COLOR6_ATTRIB 0x28ddc
+#define CB_COLOR7_ATTRIB 0x28e18
+#define CB_COLOR8_ATTRIB 0x28e54
+#define CB_COLOR9_ATTRIB 0x28e70
+#define CB_COLOR10_ATTRIB 0x28e8c
+#define CB_COLOR11_ATTRIB 0x28ea8
+
+#define CB_COLOR1_DIM 0x28cb4
+#define CB_COLOR2_DIM 0x28cf0
+#define CB_COLOR3_DIM 0x28d2c
+#define CB_COLOR4_DIM 0x28d68
+#define CB_COLOR5_DIM 0x28da4
+#define CB_COLOR6_DIM 0x28de0
+#define CB_COLOR7_DIM 0x28e1c
+#define CB_COLOR8_DIM 0x28e58
+#define CB_COLOR9_DIM 0x28e74
+#define CB_COLOR10_DIM 0x28e90
+#define CB_COLOR11_DIM 0x28eac
+
+#define CB_COLOR1_CMASK 0x28cb8
+#define CB_COLOR2_CMASK 0x28cf4
+#define CB_COLOR3_CMASK 0x28d30
+#define CB_COLOR4_CMASK 0x28d6c
+#define CB_COLOR5_CMASK 0x28da8
+#define CB_COLOR6_CMASK 0x28de4
+#define CB_COLOR7_CMASK 0x28e20
+
+#define CB_COLOR1_CMASK_SLICE 0x28cbc
+#define CB_COLOR2_CMASK_SLICE 0x28cf8
+#define CB_COLOR3_CMASK_SLICE 0x28d34
+#define CB_COLOR4_CMASK_SLICE 0x28d70
+#define CB_COLOR5_CMASK_SLICE 0x28dac
+#define CB_COLOR6_CMASK_SLICE 0x28de8
+#define CB_COLOR7_CMASK_SLICE 0x28e24
+
+#define CB_COLOR1_FMASK 0x28cc0
+#define CB_COLOR2_FMASK 0x28cfc
+#define CB_COLOR3_FMASK 0x28d38
+#define CB_COLOR4_FMASK 0x28d74
+#define CB_COLOR5_FMASK 0x28db0
+#define CB_COLOR6_FMASK 0x28dec
+#define CB_COLOR7_FMASK 0x28e28
+
+#define CB_COLOR1_FMASK_SLICE 0x28cc4
+#define CB_COLOR2_FMASK_SLICE 0x28d00
+#define CB_COLOR3_FMASK_SLICE 0x28d3c
+#define CB_COLOR4_FMASK_SLICE 0x28d78
+#define CB_COLOR5_FMASK_SLICE 0x28db4
+#define CB_COLOR6_FMASK_SLICE 0x28df0
+#define CB_COLOR7_FMASK_SLICE 0x28e2c
+
+#define CB_COLOR1_CLEAR_WORD0 0x28cc8
+#define CB_COLOR2_CLEAR_WORD0 0x28d04
+#define CB_COLOR3_CLEAR_WORD0 0x28d40
+#define CB_COLOR4_CLEAR_WORD0 0x28d7c
+#define CB_COLOR5_CLEAR_WORD0 0x28db8
+#define CB_COLOR6_CLEAR_WORD0 0x28df4
+#define CB_COLOR7_CLEAR_WORD0 0x28e30
+
+#define CB_COLOR1_CLEAR_WORD1 0x28ccc
+#define CB_COLOR2_CLEAR_WORD1 0x28d08
+#define CB_COLOR3_CLEAR_WORD1 0x28d44
+#define CB_COLOR4_CLEAR_WORD1 0x28d80
+#define CB_COLOR5_CLEAR_WORD1 0x28dbc
+#define CB_COLOR6_CLEAR_WORD1 0x28df8
+#define CB_COLOR7_CLEAR_WORD1 0x28e34
+
+#define CB_COLOR1_CLEAR_WORD2 0x28cd0
+#define CB_COLOR2_CLEAR_WORD2 0x28d0c
+#define CB_COLOR3_CLEAR_WORD2 0x28d48
+#define CB_COLOR4_CLEAR_WORD2 0x28d84
+#define CB_COLOR5_CLEAR_WORD2 0x28dc0
+#define CB_COLOR6_CLEAR_WORD2 0x28dfc
+#define CB_COLOR7_CLEAR_WORD2 0x28e38
+
+#define CB_COLOR1_CLEAR_WORD3 0x28cd4
+#define CB_COLOR2_CLEAR_WORD3 0x28d10
+#define CB_COLOR3_CLEAR_WORD3 0x28d4c
+#define CB_COLOR4_CLEAR_WORD3 0x28d88
+#define CB_COLOR5_CLEAR_WORD3 0x28dc4
+#define CB_COLOR6_CLEAR_WORD3 0x28e00
+#define CB_COLOR7_CLEAR_WORD3 0x28e3c
+
+#define SQ_TEX_RESOURCE_WORD0_0 0x30000
+#define SQ_TEX_RESOURCE_WORD1_0 0x30004
+# define TEX_ARRAY_MODE(x) ((x) << 28)
+#define SQ_TEX_RESOURCE_WORD2_0 0x30008
+#define SQ_TEX_RESOURCE_WORD3_0 0x3000C
+#define SQ_TEX_RESOURCE_WORD4_0 0x30010
+#define SQ_TEX_RESOURCE_WORD5_0 0x30014
+#define SQ_TEX_RESOURCE_WORD6_0 0x30018
+#define SQ_TEX_RESOURCE_WORD7_0 0x3001c
+
+
#endif
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 44e96a2ae25a..e14f59748e65 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -475,6 +475,12 @@ void r600_pm_init_profile(struct radeon_device *rdev)
void r600_pm_misc(struct radeon_device *rdev)
{
+ int requested_index = rdev->pm.requested_power_state_index;
+ struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
+ struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
+
+ if ((voltage->type == VOLTAGE_SW) && voltage->voltage)
+ radeon_atom_set_voltage(rdev, voltage->voltage);
}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 669feb689bfc..5f96fe871b3f 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -176,6 +176,7 @@ void radeon_pm_suspend(struct radeon_device *rdev);
void radeon_pm_resume(struct radeon_device *rdev);
void radeon_combios_get_power_modes(struct radeon_device *rdev);
void radeon_atombios_get_power_modes(struct radeon_device *rdev);
+void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level);
/*
* Fences.
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index e57df08d4aeb..87f7e2cc52d4 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -724,8 +724,8 @@ static struct radeon_asic evergreen_asic = {
.irq_set = &evergreen_irq_set,
.irq_process = &evergreen_irq_process,
.get_vblank_counter = &evergreen_get_vblank_counter,
- .fence_ring_emit = NULL,
- .cs_parse = NULL,
+ .fence_ring_emit = &r600_fence_ring_emit,
+ .cs_parse = &evergreen_cs_parse,
.copy_blit = NULL,
.copy_dma = NULL,
.copy = NULL,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 5c40a3dfaca2..c0bbaa64157a 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -314,6 +314,7 @@ void evergreen_hpd_set_polarity(struct radeon_device *rdev,
u32 evergreen_get_vblank_counter(struct radeon_device *rdev, int crtc);
int evergreen_irq_set(struct radeon_device *rdev);
int evergreen_irq_process(struct radeon_device *rdev);
+extern int evergreen_cs_parse(struct radeon_cs_parser *p);
extern void evergreen_pm_misc(struct radeon_device *rdev);
extern void evergreen_pm_prepare(struct radeon_device *rdev);
extern void evergreen_pm_finish(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 24ea683f7cf5..4305cd55d0ac 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -1538,7 +1538,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].pcie_lanes =
power_info->info.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
@@ -1605,7 +1606,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo);
misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
@@ -1679,7 +1681,8 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes;
misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo);
misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2);
- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) {
+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) ||
+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) {
rdev->pm.power_state[state_index].clock_info[0].voltage.type =
VOLTAGE_GPIO;
rdev->pm.power_state[state_index].clock_info[0].voltage.gpio =
@@ -1755,9 +1758,22 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.power_state[state_index].misc2 = 0;
}
} else {
+ int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
+ uint8_t fw_frev, fw_crev;
+ uint16_t fw_data_offset, vddc = 0;
+ union firmware_info *firmware_info;
+ ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController;
+
+ if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL,
+ &fw_frev, &fw_crev, &fw_data_offset)) {
+ firmware_info =
+ (union firmware_info *)(mode_info->atom_context->bios +
+ fw_data_offset);
+ vddc = firmware_info->info_14.usBootUpVDDCVoltage;
+ }
+
/* add the i2c bus for thermal/fan chip */
/* no support for internal controller yet */
- ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController;
if (controller->ucType > 0) {
if ((controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) ||
(controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) ||
@@ -1904,6 +1920,16 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
rdev->pm.default_power_state_index = state_index;
rdev->pm.power_state[state_index].default_clock_mode =
&rdev->pm.power_state[state_index].clock_info[mode_index - 1];
+ /* patch the table values with the default slck/mclk from firmware info */
+ for (j = 0; j < mode_index; j++) {
+ rdev->pm.power_state[state_index].clock_info[j].mclk =
+ rdev->clock.default_mclk;
+ rdev->pm.power_state[state_index].clock_info[j].sclk =
+ rdev->clock.default_sclk;
+ if (vddc)
+ rdev->pm.power_state[state_index].clock_info[j].voltage.voltage =
+ vddc;
+ }
}
state_index++;
}
@@ -1998,6 +2024,42 @@ void radeon_atom_set_memory_clock(struct radeon_device *rdev,
atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
}
+union set_voltage {
+ struct _SET_VOLTAGE_PS_ALLOCATION alloc;
+ struct _SET_VOLTAGE_PARAMETERS v1;
+ struct _SET_VOLTAGE_PARAMETERS_V2 v2;
+};
+
+void radeon_atom_set_voltage(struct radeon_device *rdev, u16 level)
+{
+ union set_voltage args;
+ int index = GetIndexIntoMasterTable(COMMAND, SetVoltage);
+ u8 frev, crev, volt_index = level;
+
+ if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev))
+ return;
+
+ switch (crev) {
+ case 1:
+ args.v1.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC;
+ args.v1.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_ALL_SOURCE;
+ args.v1.ucVoltageIndex = volt_index;
+ break;
+ case 2:
+ args.v2.ucVoltageType = SET_VOLTAGE_TYPE_ASIC_VDDC;
+ args.v2.ucVoltageMode = SET_ASIC_VOLTAGE_MODE_SET_VOLTAGE;
+ args.v2.usVoltageLevel = cpu_to_le16(level);
+ break;
+ default:
+ DRM_ERROR("Unknown table version %d, %d\n", frev, crev);
+ return;
+ }
+
+ atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+}
+
+
+
void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 7b5e10d3e9c9..102c744eaf5a 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -2454,7 +2454,12 @@ default_mode:
rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk;
rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk;
rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[0];
- rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
+ if ((state_index > 0) &&
+ (rdev->pm.power_state[0].clock_info[0].voltage.type = VOLTAGE_GPIO))
+ rdev->pm.power_state[state_index].clock_info[0].voltage =
+ rdev->pm.power_state[0].clock_info[0].voltage;
+ else
+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE;
rdev->pm.power_state[state_index].pcie_lanes = 16;
rdev->pm.power_state[state_index].flags = 0;
rdev->pm.default_power_state_index = state_index;
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index fdc3fdf78acb..f10faed21567 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -546,8 +546,10 @@ static void radeon_switcheroo_set_state(struct pci_dev *pdev, enum vga_switchero
/* don't suspend or resume card normally */
rdev->powered_down = false;
radeon_resume_kms(dev);
+ drm_kms_helper_poll_enable(dev);
} else {
printk(KERN_INFO "radeon: switched off\n");
+ drm_kms_helper_poll_disable(dev);
radeon_suspend_kms(dev, pmm);
/* don't suspend or resume card normally */
rdev->powered_down = true;
@@ -711,6 +713,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
{
struct radeon_device *rdev;
struct drm_crtc *crtc;
+ struct drm_connector *connector;
int r;
if (dev == NULL || dev->dev_private == NULL) {
@@ -723,6 +726,12 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
if (rdev->powered_down)
return 0;
+
+ /* turn off display hw */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+ }
+
/* unpin the front buffers */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index a8d162c6f829..02281269a881 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -151,6 +151,7 @@ static void radeon_sync_with_vblank(struct radeon_device *rdev)
static void radeon_set_power_state(struct radeon_device *rdev)
{
u32 sclk, mclk;
+ bool misc_after = false;
if ((rdev->pm.requested_clock_mode_index == rdev->pm.current_clock_mode_index) &&
(rdev->pm.requested_power_state_index == rdev->pm.current_power_state_index))
@@ -167,55 +168,47 @@ static void radeon_set_power_state(struct radeon_device *rdev)
if (mclk > rdev->clock.default_mclk)
mclk = rdev->clock.default_mclk;
- /* voltage, pcie lanes, etc.*/
- radeon_pm_misc(rdev);
+ /* upvolt before raising clocks, downvolt after lowering clocks */
+ if (sclk < rdev->pm.current_sclk)
+ misc_after = true;
- if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
- radeon_sync_with_vblank(rdev);
+ radeon_sync_with_vblank(rdev);
+ if (rdev->pm.pm_method == PM_METHOD_DYNPM) {
if (!radeon_pm_in_vbl(rdev))
return;
+ }
- radeon_pm_prepare(rdev);
- /* set engine clock */
- if (sclk != rdev->pm.current_sclk) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_engine_clock(rdev, sclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_sclk = sclk;
- DRM_DEBUG("Setting: e: %d\n", sclk);
- }
+ radeon_pm_prepare(rdev);
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_pm_debug_check_in_vbl(rdev, false);
- radeon_set_memory_clock(rdev, mclk);
- radeon_pm_debug_check_in_vbl(rdev, true);
- rdev->pm.current_mclk = mclk;
- DRM_DEBUG("Setting: m: %d\n", mclk);
- }
- radeon_pm_finish(rdev);
- } else {
- /* set engine clock */
- if (sclk != rdev->pm.current_sclk) {
- radeon_sync_with_vblank(rdev);
- radeon_pm_prepare(rdev);
- radeon_set_engine_clock(rdev, sclk);
- radeon_pm_finish(rdev);
- rdev->pm.current_sclk = sclk;
- DRM_DEBUG("Setting: e: %d\n", sclk);
- }
- /* set memory clock */
- if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
- radeon_sync_with_vblank(rdev);
- radeon_pm_prepare(rdev);
- radeon_set_memory_clock(rdev, mclk);
- radeon_pm_finish(rdev);
- rdev->pm.current_mclk = mclk;
- DRM_DEBUG("Setting: m: %d\n", mclk);
- }
+ if (!misc_after)
+ /* voltage, pcie lanes, etc.*/
+ radeon_pm_misc(rdev);
+
+ /* set engine clock */
+ if (sclk != rdev->pm.current_sclk) {
+ radeon_pm_debug_check_in_vbl(rdev, false);
+ radeon_set_engine_clock(rdev, sclk);
+ radeon_pm_debug_check_in_vbl(rdev, true);
+ rdev->pm.current_sclk = sclk;
+ DRM_DEBUG("Setting: e: %d\n", sclk);
+ }
+
+ /* set memory clock */
+ if (rdev->asic->set_memory_clock && (mclk != rdev->pm.current_mclk)) {
+ radeon_pm_debug_check_in_vbl(rdev, false);
+ radeon_set_memory_clock(rdev, mclk);
+ radeon_pm_debug_check_in_vbl(rdev, true);
+ rdev->pm.current_mclk = mclk;
+ DRM_DEBUG("Setting: m: %d\n", mclk);
}
+ if (misc_after)
+ /* voltage, pcie lanes, etc.*/
+ radeon_pm_misc(rdev);
+
+ radeon_pm_finish(rdev);
+
rdev->pm.current_power_state_index = rdev->pm.requested_power_state_index;
rdev->pm.current_clock_mode_index = rdev->pm.requested_clock_mode_index;
} else
diff --git a/drivers/gpu/drm/radeon/reg_srcs/evergreen b/drivers/gpu/drm/radeon/reg_srcs/evergreen
new file mode 100644
index 000000000000..b5c757f68d3c
--- /dev/null
+++ b/drivers/gpu/drm/radeon/reg_srcs/evergreen
@@ -0,0 +1,611 @@
+evergreen 0x9400
+0x00008040 WAIT_UNTIL
+0x00008044 WAIT_UNTIL_POLL_CNTL
+0x00008048 WAIT_UNTIL_POLL_MASK
+0x0000804c WAIT_UNTIL_POLL_REFDATA
+0x000088B0 VGT_VTX_VECT_EJECT_REG
+0x000088C4 VGT_CACHE_INVALIDATION
+0x000088D4 VGT_GS_VERTEX_REUSE
+0x00008958 VGT_PRIMITIVE_TYPE
+0x0000895C VGT_INDEX_TYPE
+0x00008970 VGT_NUM_INDICES
+0x00008974 VGT_NUM_INSTANCES
+0x00008990 VGT_COMPUTE_DIM_X
+0x00008994 VGT_COMPUTE_DIM_Y
+0x00008998 VGT_COMPUTE_DIM_Z
+0x0000899C VGT_COMPUTE_START_X
+0x000089A0 VGT_COMPUTE_START_Y
+0x000089A4 VGT_COMPUTE_START_Z
+0x000089AC VGT_COMPUTE_THREAD_GOURP_SIZE
+0x00008A14 PA_CL_ENHANCE
+0x00008A60 PA_SC_LINE_STIPPLE_VALUE
+0x00008B10 PA_SC_LINE_STIPPLE_STATE
+0x00008BF0 PA_SC_ENHANCE
+0x00008D8C SQ_DYN_GPR_CNTL_PS_FLUSH_REQ
+0x00008C00 SQ_CONFIG
+0x00008C04 SQ_GPR_RESOURCE_MGMT_1
+0x00008C08 SQ_GPR_RESOURCE_MGMT_2
+0x00008C0C SQ_GPR_RESOURCE_MGMT_3
+0x00008C10 SQ_GLOBAL_GPR_RESOURCE_MGMT_1
+0x00008C14 SQ_GLOBAL_GPR_RESOURCE_MGMT_2
+0x00008C18 SQ_THREAD_RESOURCE_MGMT
+0x00008C1C SQ_THREAD_RESOURCE_MGMT_2
+0x00008C20 SQ_STACK_RESOURCE_MGMT_1
+0x00008C24 SQ_STACK_RESOURCE_MGMT_2
+0x00008C28 SQ_STACK_RESOURCE_MGMT_3
+0x00008DF8 SQ_CONST_MEM_BASE
+0x00008E48 SQ_EX_ALLOC_TABLE_SLOTS
+0x00009100 SPI_CONFIG_CNTL
+0x0000913C SPI_CONFIG_CNTL_1
+0x00009700 VC_CNTL
+0x00009714 VC_ENHANCE
+0x00009830 DB_DEBUG
+0x00009834 DB_DEBUG2
+0x00009838 DB_DEBUG3
+0x0000983C DB_DEBUG4
+0x00009854 DB_WATERMARKS
+0x0000A400 TD_PS_BORDER_COLOR_INDEX
+0x0000A404 TD_PS_BORDER_COLOR_RED
+0x0000A408 TD_PS_BORDER_COLOR_GREEN
+0x0000A40C TD_PS_BORDER_COLOR_BLUE
+0x0000A410 TD_PS_BORDER_COLOR_ALPHA
+0x0000A414 TD_VS_BORDER_COLOR_INDEX
+0x0000A418 TD_VS_BORDER_COLOR_RED
+0x0000A41C TD_VS_BORDER_COLOR_GREEN
+0x0000A420 TD_VS_BORDER_COLOR_BLUE
+0x0000A424 TD_VS_BORDER_COLOR_ALPHA
+0x0000A428 TD_GS_BORDER_COLOR_INDEX
+0x0000A42C TD_GS_BORDER_COLOR_RED
+0x0000A430 TD_GS_BORDER_COLOR_GREEN
+0x0000A434 TD_GS_BORDER_COLOR_BLUE
+0x0000A438 TD_GS_BORDER_COLOR_ALPHA
+0x0000A43C TD_HS_BORDER_COLOR_INDEX
+0x0000A440 TD_HS_BORDER_COLOR_RED
+0x0000A444 TD_HS_BORDER_COLOR_GREEN
+0x0000A448 TD_HS_BORDER_COLOR_BLUE
+0x0000A44C TD_HS_BORDER_COLOR_ALPHA
+0x0000A450 TD_LS_BORDER_COLOR_INDEX
+0x0000A454 TD_LS_BORDER_COLOR_RED
+0x0000A458 TD_LS_BORDER_COLOR_GREEN
+0x0000A45C TD_LS_BORDER_COLOR_BLUE
+0x0000A460 TD_LS_BORDER_COLOR_ALPHA
+0x0000A464 TD_CS_BORDER_COLOR_INDEX
+0x0000A468 TD_CS_BORDER_COLOR_RED
+0x0000A46C TD_CS_BORDER_COLOR_GREEN
+0x0000A470 TD_CS_BORDER_COLOR_BLUE
+0x0000A474 TD_CS_BORDER_COLOR_ALPHA
+0x00028000 DB_RENDER_CONTROL
+0x00028004 DB_COUNT_CONTROL
+0x0002800C DB_RENDER_OVERRIDE
+0x00028010 DB_RENDER_OVERRIDE2
+0x00028028 DB_STENCIL_CLEAR
+0x0002802C DB_DEPTH_CLEAR
+0x00028034 PA_SC_SCREEN_SCISSOR_BR
+0x00028030 PA_SC_SCREEN_SCISSOR_TL
+0x0002805C DB_DEPTH_SLICE
+0x00028140 SQ_ALU_CONST_BUFFER_SIZE_PS_0
+0x00028144 SQ_ALU_CONST_BUFFER_SIZE_PS_1
+0x00028148 SQ_ALU_CONST_BUFFER_SIZE_PS_2
+0x0002814C SQ_ALU_CONST_BUFFER_SIZE_PS_3
+0x00028150 SQ_ALU_CONST_BUFFER_SIZE_PS_4
+0x00028154 SQ_ALU_CONST_BUFFER_SIZE_PS_5
+0x00028158 SQ_ALU_CONST_BUFFER_SIZE_PS_6
+0x0002815C SQ_ALU_CONST_BUFFER_SIZE_PS_7
+0x00028160 SQ_ALU_CONST_BUFFER_SIZE_PS_8
+0x00028164 SQ_ALU_CONST_BUFFER_SIZE_PS_9
+0x00028168 SQ_ALU_CONST_BUFFER_SIZE_PS_10
+0x0002816C SQ_ALU_CONST_BUFFER_SIZE_PS_11
+0x00028170 SQ_ALU_CONST_BUFFER_SIZE_PS_12
+0x00028174 SQ_ALU_CONST_BUFFER_SIZE_PS_13
+0x00028178 SQ_ALU_CONST_BUFFER_SIZE_PS_14
+0x0002817C SQ_ALU_CONST_BUFFER_SIZE_PS_15
+0x00028180 SQ_ALU_CONST_BUFFER_SIZE_VS_0
+0x00028184 SQ_ALU_CONST_BUFFER_SIZE_VS_1
+0x00028188 SQ_ALU_CONST_BUFFER_SIZE_VS_2
+0x0002818C SQ_ALU_CONST_BUFFER_SIZE_VS_3
+0x00028190 SQ_ALU_CONST_BUFFER_SIZE_VS_4
+0x00028194 SQ_ALU_CONST_BUFFER_SIZE_VS_5
+0x00028198 SQ_ALU_CONST_BUFFER_SIZE_VS_6
+0x0002819C SQ_ALU_CONST_BUFFER_SIZE_VS_7
+0x000281A0 SQ_ALU_CONST_BUFFER_SIZE_VS_8
+0x000281A4 SQ_ALU_CONST_BUFFER_SIZE_VS_9
+0x000281A8 SQ_ALU_CONST_BUFFER_SIZE_VS_10
+0x000281AC SQ_ALU_CONST_BUFFER_SIZE_VS_11
+0x000281B0 SQ_ALU_CONST_BUFFER_SIZE_VS_12
+0x000281B4 SQ_ALU_CONST_BUFFER_SIZE_VS_13
+0x000281B8 SQ_ALU_CONST_BUFFER_SIZE_VS_14
+0x000281BC SQ_ALU_CONST_BUFFER_SIZE_VS_15
+0x000281C0 SQ_ALU_CONST_BUFFER_SIZE_GS_0
+0x000281C4 SQ_ALU_CONST_BUFFER_SIZE_GS_1
+0x000281C8 SQ_ALU_CONST_BUFFER_SIZE_GS_2
+0x000281CC SQ_ALU_CONST_BUFFER_SIZE_GS_3
+0x000281D0 SQ_ALU_CONST_BUFFER_SIZE_GS_4
+0x000281D4 SQ_ALU_CONST_BUFFER_SIZE_GS_5
+0x000281D8 SQ_ALU_CONST_BUFFER_SIZE_GS_6
+0x000281DC SQ_ALU_CONST_BUFFER_SIZE_GS_7
+0x000281E0 SQ_ALU_CONST_BUFFER_SIZE_GS_8
+0x000281E4 SQ_ALU_CONST_BUFFER_SIZE_GS_9
+0x000281E8 SQ_ALU_CONST_BUFFER_SIZE_GS_10
+0x000281EC SQ_ALU_CONST_BUFFER_SIZE_GS_11
+0x000281F0 SQ_ALU_CONST_BUFFER_SIZE_GS_12
+0x000281F4 SQ_ALU_CONST_BUFFER_SIZE_GS_13
+0x000281F8 SQ_ALU_CONST_BUFFER_SIZE_GS_14
+0x000281FC SQ_ALU_CONST_BUFFER_SIZE_GS_15
+0x00028200 PA_SC_WINDOW_OFFSET
+0x00028204 PA_SC_WINDOW_SCISSOR_TL
+0x00028208 PA_SC_WINDOW_SCISSOR_BR
+0x0002820C PA_SC_CLIPRECT_RULE
+0x00028210 PA_SC_CLIPRECT_0_TL
+0x00028214 PA_SC_CLIPRECT_0_BR
+0x00028218 PA_SC_CLIPRECT_1_TL
+0x0002821C PA_SC_CLIPRECT_1_BR
+0x00028220 PA_SC_CLIPRECT_2_TL
+0x00028224 PA_SC_CLIPRECT_2_BR
+0x00028228 PA_SC_CLIPRECT_3_TL
+0x0002822C PA_SC_CLIPRECT_3_BR
+0x00028230 PA_SC_EDGERULE
+0x00028234 PA_SU_HARDWARE_SCREEN_OFFSET
+0x00028240 PA_SC_GENERIC_SCISSOR_TL
+0x00028244 PA_SC_GENERIC_SCISSOR_BR
+0x00028250 PA_SC_VPORT_SCISSOR_0_TL
+0x00028254 PA_SC_VPORT_SCISSOR_0_BR
+0x00028258 PA_SC_VPORT_SCISSOR_1_TL
+0x0002825C PA_SC_VPORT_SCISSOR_1_BR
+0x00028260 PA_SC_VPORT_SCISSOR_2_TL
+0x00028264 PA_SC_VPORT_SCISSOR_2_BR
+0x00028268 PA_SC_VPORT_SCISSOR_3_TL
+0x0002826C PA_SC_VPORT_SCISSOR_3_BR
+0x00028270 PA_SC_VPORT_SCISSOR_4_TL
+0x00028274 PA_SC_VPORT_SCISSOR_4_BR
+0x00028278 PA_SC_VPORT_SCISSOR_5_TL
+0x0002827C PA_SC_VPORT_SCISSOR_5_BR
+0x00028280 PA_SC_VPORT_SCISSOR_6_TL
+0x00028284 PA_SC_VPORT_SCISSOR_6_BR
+0x00028288 PA_SC_VPORT_SCISSOR_7_TL
+0x0002828C PA_SC_VPORT_SCISSOR_7_BR
+0x00028290 PA_SC_VPORT_SCISSOR_8_TL
+0x00028294 PA_SC_VPORT_SCISSOR_8_BR
+0x00028298 PA_SC_VPORT_SCISSOR_9_TL
+0x0002829C PA_SC_VPORT_SCISSOR_9_BR
+0x000282A0 PA_SC_VPORT_SCISSOR_10_TL
+0x000282A4 PA_SC_VPORT_SCISSOR_10_BR
+0x000282A8 PA_SC_VPORT_SCISSOR_11_TL
+0x000282AC PA_SC_VPORT_SCISSOR_11_BR
+0x000282B0 PA_SC_VPORT_SCISSOR_12_TL
+0x000282B4 PA_SC_VPORT_SCISSOR_12_BR
+0x000282B8 PA_SC_VPORT_SCISSOR_13_TL
+0x000282BC PA_SC_VPORT_SCISSOR_13_BR
+0x000282C0 PA_SC_VPORT_SCISSOR_14_TL
+0x000282C4 PA_SC_VPORT_SCISSOR_14_BR
+0x000282C8 PA_SC_VPORT_SCISSOR_15_TL
+0x000282CC PA_SC_VPORT_SCISSOR_15_BR
+0x000282D0 PA_SC_VPORT_ZMIN_0
+0x000282D4 PA_SC_VPORT_ZMAX_0
+0x000282D8 PA_SC_VPORT_ZMIN_1
+0x000282DC PA_SC_VPORT_ZMAX_1
+0x000282E0 PA_SC_VPORT_ZMIN_2
+0x000282E4 PA_SC_VPORT_ZMAX_2
+0x000282E8 PA_SC_VPORT_ZMIN_3
+0x000282EC PA_SC_VPORT_ZMAX_3
+0x000282F0 PA_SC_VPORT_ZMIN_4
+0x000282F4 PA_SC_VPORT_ZMAX_4
+0x000282F8 PA_SC_VPORT_ZMIN_5
+0x000282FC PA_SC_VPORT_ZMAX_5
+0x00028300 PA_SC_VPORT_ZMIN_6
+0x00028304 PA_SC_VPORT_ZMAX_6
+0x00028308 PA_SC_VPORT_ZMIN_7
+0x0002830C PA_SC_VPORT_ZMAX_7
+0x00028310 PA_SC_VPORT_ZMIN_8
+0x00028314 PA_SC_VPORT_ZMAX_8
+0x00028318 PA_SC_VPORT_ZMIN_9
+0x0002831C PA_SC_VPORT_ZMAX_9
+0x00028320 PA_SC_VPORT_ZMIN_10
+0x00028324 PA_SC_VPORT_ZMAX_10
+0x00028328 PA_SC_VPORT_ZMIN_11
+0x0002832C PA_SC_VPORT_ZMAX_11
+0x00028330 PA_SC_VPORT_ZMIN_12
+0x00028334 PA_SC_VPORT_ZMAX_12
+0x00028338 PA_SC_VPORT_ZMIN_13
+0x0002833C PA_SC_VPORT_ZMAX_13
+0x00028340 PA_SC_VPORT_ZMIN_14
+0x00028344 PA_SC_VPORT_ZMAX_14
+0x00028348 PA_SC_VPORT_ZMIN_15
+0x0002834C PA_SC_VPORT_ZMAX_15
+0x00028350 SX_MISC
+0x00028380 SQ_VTX_SEMANTIC_0
+0x00028384 SQ_VTX_SEMANTIC_1
+0x00028388 SQ_VTX_SEMANTIC_2
+0x0002838C SQ_VTX_SEMANTIC_3
+0x00028390 SQ_VTX_SEMANTIC_4
+0x00028394 SQ_VTX_SEMANTIC_5
+0x00028398 SQ_VTX_SEMANTIC_6
+0x0002839C SQ_VTX_SEMANTIC_7
+0x000283A0 SQ_VTX_SEMANTIC_8
+0x000283A4 SQ_VTX_SEMANTIC_9
+0x000283A8 SQ_VTX_SEMANTIC_10
+0x000283AC SQ_VTX_SEMANTIC_11
+0x000283B0 SQ_VTX_SEMANTIC_12
+0x000283B4 SQ_VTX_SEMANTIC_13
+0x000283B8 SQ_VTX_SEMANTIC_14
+0x000283BC SQ_VTX_SEMANTIC_15
+0x000283C0 SQ_VTX_SEMANTIC_16
+0x000283C4 SQ_VTX_SEMANTIC_17
+0x000283C8 SQ_VTX_SEMANTIC_18
+0x000283CC SQ_VTX_SEMANTIC_19
+0x000283D0 SQ_VTX_SEMANTIC_20
+0x000283D4 SQ_VTX_SEMANTIC_21
+0x000283D8 SQ_VTX_SEMANTIC_22
+0x000283DC SQ_VTX_SEMANTIC_23
+0x000283E0 SQ_VTX_SEMANTIC_24
+0x000283E4 SQ_VTX_SEMANTIC_25
+0x000283E8 SQ_VTX_SEMANTIC_26
+0x000283EC SQ_VTX_SEMANTIC_27
+0x000283F0 SQ_VTX_SEMANTIC_28
+0x000283F4 SQ_VTX_SEMANTIC_29
+0x000283F8 SQ_VTX_SEMANTIC_30
+0x000283FC SQ_VTX_SEMANTIC_31
+0x00028400 VGT_MAX_VTX_INDX
+0x00028404 VGT_MIN_VTX_INDX
+0x00028408 VGT_INDX_OFFSET
+0x0002840C VGT_MULTI_PRIM_IB_RESET_INDX
+0x00028410 SX_ALPHA_TEST_CONTROL
+0x00028414 CB_BLEND_RED
+0x00028418 CB_BLEND_GREEN
+0x0002841C CB_BLEND_BLUE
+0x00028420 CB_BLEND_ALPHA
+0x00028430 DB_STENCILREFMASK
+0x00028434 DB_STENCILREFMASK_BF
+0x00028438 SX_ALPHA_REF
+0x0002843C PA_CL_VPORT_XSCALE_0
+0x00028440 PA_CL_VPORT_XOFFSET_0
+0x00028444 PA_CL_VPORT_YSCALE_0
+0x00028448 PA_CL_VPORT_YOFFSET_0
+0x0002844C PA_CL_VPORT_ZSCALE_0
+0x00028450 PA_CL_VPORT_ZOFFSET_0
+0x00028454 PA_CL_VPORT_XSCALE_1
+0x00028458 PA_CL_VPORT_XOFFSET_1
+0x0002845C PA_CL_VPORT_YSCALE_1
+0x00028460 PA_CL_VPORT_YOFFSET_1
+0x00028464 PA_CL_VPORT_ZSCALE_1
+0x00028468 PA_CL_VPORT_ZOFFSET_1
+0x0002846C PA_CL_VPORT_XSCALE_2
+0x00028470 PA_CL_VPORT_XOFFSET_2
+0x00028474 PA_CL_VPORT_YSCALE_2
+0x00028478 PA_CL_VPORT_YOFFSET_2
+0x0002847C PA_CL_VPORT_ZSCALE_2
+0x00028480 PA_CL_VPORT_ZOFFSET_2
+0x00028484 PA_CL_VPORT_XSCALE_3
+0x00028488 PA_CL_VPORT_XOFFSET_3
+0x0002848C PA_CL_VPORT_YSCALE_3
+0x00028490 PA_CL_VPORT_YOFFSET_3
+0x00028494 PA_CL_VPORT_ZSCALE_3
+0x00028498 PA_CL_VPORT_ZOFFSET_3
+0x0002849C PA_CL_VPORT_XSCALE_4
+0x000284A0 PA_CL_VPORT_XOFFSET_4
+0x000284A4 PA_CL_VPORT_YSCALE_4
+0x000284A8 PA_CL_VPORT_YOFFSET_4
+0x000284AC PA_CL_VPORT_ZSCALE_4
+0x000284B0 PA_CL_VPORT_ZOFFSET_4
+0x000284B4 PA_CL_VPORT_XSCALE_5
+0x000284B8 PA_CL_VPORT_XOFFSET_5
+0x000284BC PA_CL_VPORT_YSCALE_5
+0x000284C0 PA_CL_VPORT_YOFFSET_5
+0x000284C4 PA_CL_VPORT_ZSCALE_5
+0x000284C8 PA_CL_VPORT_ZOFFSET_5
+0x000284CC PA_CL_VPORT_XSCALE_6
+0x000284D0 PA_CL_VPORT_XOFFSET_6
+0x000284D4 PA_CL_VPORT_YSCALE_6
+0x000284D8 PA_CL_VPORT_YOFFSET_6
+0x000284DC PA_CL_VPORT_ZSCALE_6
+0x000284E0 PA_CL_VPORT_ZOFFSET_6
+0x000284E4 PA_CL_VPORT_XSCALE_7
+0x000284E8 PA_CL_VPORT_XOFFSET_7
+0x000284EC PA_CL_VPORT_YSCALE_7
+0x000284F0 PA_CL_VPORT_YOFFSET_7
+0x000284F4 PA_CL_VPORT_ZSCALE_7
+0x000284F8 PA_CL_VPORT_ZOFFSET_7
+0x000284FC PA_CL_VPORT_XSCALE_8
+0x00028500 PA_CL_VPORT_XOFFSET_8
+0x00028504 PA_CL_VPORT_YSCALE_8
+0x00028508 PA_CL_VPORT_YOFFSET_8
+0x0002850C PA_CL_VPORT_ZSCALE_8
+0x00028510 PA_CL_VPORT_ZOFFSET_8
+0x00028514 PA_CL_VPORT_XSCALE_9
+0x00028518 PA_CL_VPORT_XOFFSET_9
+0x0002851C PA_CL_VPORT_YSCALE_9
+0x00028520 PA_CL_VPORT_YOFFSET_9
+0x00028524 PA_CL_VPORT_ZSCALE_9
+0x00028528 PA_CL_VPORT_ZOFFSET_9
+0x0002852C PA_CL_VPORT_XSCALE_10
+0x00028530 PA_CL_VPORT_XOFFSET_10
+0x00028534 PA_CL_VPORT_YSCALE_10
+0x00028538 PA_CL_VPORT_YOFFSET_10
+0x0002853C PA_CL_VPORT_ZSCALE_10
+0x00028540 PA_CL_VPORT_ZOFFSET_10
+0x00028544 PA_CL_VPORT_XSCALE_11
+0x00028548 PA_CL_VPORT_XOFFSET_11
+0x0002854C PA_CL_VPORT_YSCALE_11
+0x00028550 PA_CL_VPORT_YOFFSET_11
+0x00028554 PA_CL_VPORT_ZSCALE_11
+0x00028558 PA_CL_VPORT_ZOFFSET_11
+0x0002855C PA_CL_VPORT_XSCALE_12
+0x00028560 PA_CL_VPORT_XOFFSET_12
+0x00028564 PA_CL_VPORT_YSCALE_12
+0x00028568 PA_CL_VPORT_YOFFSET_12
+0x0002856C PA_CL_VPORT_ZSCALE_12
+0x00028570 PA_CL_VPORT_ZOFFSET_12
+0x00028574 PA_CL_VPORT_XSCALE_13
+0x00028578 PA_CL_VPORT_XOFFSET_13
+0x0002857C PA_CL_VPORT_YSCALE_13
+0x00028580 PA_CL_VPORT_YOFFSET_13
+0x00028584 PA_CL_VPORT_ZSCALE_13
+0x00028588 PA_CL_VPORT_ZOFFSET_13
+0x0002858C PA_CL_VPORT_XSCALE_14
+0x00028590 PA_CL_VPORT_XOFFSET_14
+0x00028594 PA_CL_VPORT_YSCALE_14
+0x00028598 PA_CL_VPORT_YOFFSET_14
+0x0002859C PA_CL_VPORT_ZSCALE_14
+0x000285A0 PA_CL_VPORT_ZOFFSET_14
+0x000285A4 PA_CL_VPORT_XSCALE_15
+0x000285A8 PA_CL_VPORT_XOFFSET_15
+0x000285AC PA_CL_VPORT_YSCALE_15
+0x000285B0 PA_CL_VPORT_YOFFSET_15
+0x000285B4 PA_CL_VPORT_ZSCALE_15
+0x000285B8 PA_CL_VPORT_ZOFFSET_15
+0x000285BC PA_CL_UCP_0_X
+0x000285C0 PA_CL_UCP_0_Y
+0x000285C4 PA_CL_UCP_0_Z
+0x000285C8 PA_CL_UCP_0_W
+0x000285CC PA_CL_UCP_1_X
+0x000285D0 PA_CL_UCP_1_Y
+0x000285D4 PA_CL_UCP_1_Z
+0x000285D8 PA_CL_UCP_1_W
+0x000285DC PA_CL_UCP_2_X
+0x000285E0 PA_CL_UCP_2_Y
+0x000285E4 PA_CL_UCP_2_Z
+0x000285E8 PA_CL_UCP_2_W
+0x000285EC PA_CL_UCP_3_X
+0x000285F0 PA_CL_UCP_3_Y
+0x000285F4 PA_CL_UCP_3_Z
+0x000285F8 PA_CL_UCP_3_W
+0x000285FC PA_CL_UCP_4_X
+0x00028600 PA_CL_UCP_4_Y
+0x00028604 PA_CL_UCP_4_Z
+0x00028608 PA_CL_UCP_4_W
+0x0002860C PA_CL_UCP_5_X
+0x00028610 PA_CL_UCP_5_Y
+0x00028614 PA_CL_UCP_5_Z
+0x00028618 PA_CL_UCP_5_W
+0x0002861C SPI_VS_OUT_ID_0
+0x00028620 SPI_VS_OUT_ID_1
+0x00028624 SPI_VS_OUT_ID_2
+0x00028628 SPI_VS_OUT_ID_3
+0x0002862C SPI_VS_OUT_ID_4
+0x00028630 SPI_VS_OUT_ID_5
+0x00028634 SPI_VS_OUT_ID_6
+0x00028638 SPI_VS_OUT_ID_7
+0x0002863C SPI_VS_OUT_ID_8
+0x00028640 SPI_VS_OUT_ID_9
+0x00028644 SPI_PS_INPUT_CNTL_0
+0x00028648 SPI_PS_INPUT_CNTL_1
+0x0002864C SPI_PS_INPUT_CNTL_2
+0x00028650 SPI_PS_INPUT_CNTL_3
+0x00028654 SPI_PS_INPUT_CNTL_4
+0x00028658 SPI_PS_INPUT_CNTL_5
+0x0002865C SPI_PS_INPUT_CNTL_6
+0x00028660 SPI_PS_INPUT_CNTL_7
+0x00028664 SPI_PS_INPUT_CNTL_8
+0x00028668 SPI_PS_INPUT_CNTL_9
+0x0002866C SPI_PS_INPUT_CNTL_10
+0x00028670 SPI_PS_INPUT_CNTL_11
+0x00028674 SPI_PS_INPUT_CNTL_12
+0x00028678 SPI_PS_INPUT_CNTL_13
+0x0002867C SPI_PS_INPUT_CNTL_14
+0x00028680 SPI_PS_INPUT_CNTL_15
+0x00028684 SPI_PS_INPUT_CNTL_16
+0x00028688 SPI_PS_INPUT_CNTL_17
+0x0002868C SPI_PS_INPUT_CNTL_18
+0x00028690 SPI_PS_INPUT_CNTL_19
+0x00028694 SPI_PS_INPUT_CNTL_20
+0x00028698 SPI_PS_INPUT_CNTL_21
+0x0002869C SPI_PS_INPUT_CNTL_22
+0x000286A0 SPI_PS_INPUT_CNTL_23
+0x000286A4 SPI_PS_INPUT_CNTL_24
+0x000286A8 SPI_PS_INPUT_CNTL_25
+0x000286AC SPI_PS_INPUT_CNTL_26
+0x000286B0 SPI_PS_INPUT_CNTL_27
+0x000286B4 SPI_PS_INPUT_CNTL_28
+0x000286B8 SPI_PS_INPUT_CNTL_29
+0x000286BC SPI_PS_INPUT_CNTL_30
+0x000286C0 SPI_PS_INPUT_CNTL_31
+0x000286C4 SPI_VS_OUT_CONFIG
+0x000286C8 SPI_THREAD_GROUPING
+0x000286CC SPI_PS_IN_CONTROL_0
+0x000286D0 SPI_PS_IN_CONTROL_1
+0x000286D4 SPI_INTERP_CONTROL_0
+0x000286D8 SPI_INPUT_Z
+0x000286DC SPI_FOG_CNTL
+0x000286E0 SPI_BARYC_CNTL
+0x000286E4 SPI_PS_IN_CONTROL_2
+0x000286E8 SPI_COMPUTE_INPUT_CNTL
+0x000286EC SPI_COMPUTE_NUM_THREAD_X
+0x000286F0 SPI_COMPUTE_NUM_THREAD_Y
+0x000286F4 SPI_COMPUTE_NUM_THREAD_Z
+0x000286F8 GDS_ADDR_SIZE
+0x00028780 CB_BLEND0_CONTROL
+0x00028784 CB_BLEND1_CONTROL
+0x00028788 CB_BLEND2_CONTROL
+0x0002878C CB_BLEND3_CONTROL
+0x00028790 CB_BLEND4_CONTROL
+0x00028794 CB_BLEND5_CONTROL
+0x00028798 CB_BLEND6_CONTROL
+0x0002879C CB_BLEND7_CONTROL
+0x000287CC CS_COPY_STATE
+0x000287D0 GFX_COPY_STATE
+0x000287D4 PA_CL_POINT_X_RAD
+0x000287D8 PA_CL_POINT_Y_RAD
+0x000287DC PA_CL_POINT_SIZE
+0x000287E0 PA_CL_POINT_CULL_RAD
+0x00028808 CB_COLOR_CONTROL
+0x0002880C DB_SHADER_CONTROL
+0x00028810 PA_CL_CLIP_CNTL
+0x00028814 PA_SU_SC_MODE_CNTL
+0x00028818 PA_CL_VTE_CNTL
+0x0002881C PA_CL_VS_OUT_CNTL
+0x00028820 PA_CL_NANINF_CNTL
+0x00028824 PA_SU_LINE_STIPPLE_CNTL
+0x00028828 PA_SU_LINE_STIPPLE_SCALE
+0x0002882C PA_SU_PRIM_FILTER_CNTL
+0x00028838 SQ_DYN_GPR_RESOURCE_LIMIT_1
+0x00028844 SQ_PGM_RESOURCES_PS
+0x00028848 SQ_PGM_RESOURCES_2_PS
+0x0002884C SQ_PGM_EXPORTS_PS
+0x0002885C SQ_PGM_RESOURCES_VS
+0x00028860 SQ_PGM_RESOURCES_2_VS
+0x00028878 SQ_PGM_RESOURCES_GS
+0x0002887C SQ_PGM_RESOURCES_2_GS
+0x00028890 SQ_PGM_RESOURCES_ES
+0x00028894 SQ_PGM_RESOURCES_2_ES
+0x000288A8 SQ_PGM_RESOURCES_FS
+0x000288BC SQ_PGM_RESOURCES_HS
+0x000288C0 SQ_PGM_RESOURCES_2_HS
+0x000288D0 SQ_PGM_RESOURCES_LS
+0x000288D4 SQ_PGM_RESOURCES_2_LS
+0x000288E8 SQ_LDS_ALLOC
+0x000288EC SQ_LDS_ALLOC_PS
+0x000288F0 SQ_VTX_SEMANTIC_CLEAR
+0x00028A00 PA_SU_POINT_SIZE
+0x00028A04 PA_SU_POINT_MINMAX
+0x00028A08 PA_SU_LINE_CNTL
+0x00028A0C PA_SC_LINE_STIPPLE
+0x00028A10 VGT_OUTPUT_PATH_CNTL
+0x00028A14 VGT_HOS_CNTL
+0x00028A18 VGT_HOS_MAX_TESS_LEVEL
+0x00028A1C VGT_HOS_MIN_TESS_LEVEL
+0x00028A20 VGT_HOS_REUSE_DEPTH
+0x00028A24 VGT_GROUP_PRIM_TYPE
+0x00028A28 VGT_GROUP_FIRST_DECR
+0x00028A2C VGT_GROUP_DECR
+0x00028A30 VGT_GROUP_VECT_0_CNTL
+0x00028A34 VGT_GROUP_VECT_1_CNTL
+0x00028A38 VGT_GROUP_VECT_0_FMT_CNTL
+0x00028A3C VGT_GROUP_VECT_1_FMT_CNTL
+0x00028A40 VGT_GS_MODE
+0x00028A48 PA_SC_MODE_CNTL_0
+0x00028A4C PA_SC_MODE_CNTL_1
+0x00028A50 VGT_ENHANCE
+0x00028A54 VGT_GS_PER_ES
+0x00028A58 VGT_ES_PER_GS
+0x00028A5C VGT_GS_PER_VS
+0x00028A6C VGT_GS_OUT_PRIM_TYPE
+0x00028A84 VGT_PRIMITIVEID_EN
+0x00028A94 VGT_MULTI_PRIM_IB_RESET_EN
+0x00028AA0 VGT_INSTANCE_STEP_RATE_0
+0x00028AA4 VGT_INSTANCE_STEP_RATE_1
+0x00028AB4 VGT_REUSE_OFF
+0x00028AB8 VGT_VTX_CNT_EN
+0x00028ABC DB_HTILE_SURFACE
+0x00028AC0 DB_SRESULTS_COMPARE_STATE0
+0x00028AC4 DB_SRESULTS_COMPARE_STATE1
+0x00028AC8 DB_PRELOAD_CONTROL
+0x00028B38 VGT_GS_MAX_VERT_OUT
+0x00028B54 VGT_SHADER_STAGES_EN
+0x00028B58 VGT_LS_HS_CONFIG
+0x00028B5C VGT_LS_SIZE
+0x00028B60 VGT_HS_SIZE
+0x00028B64 VGT_LS_HS_ALLOC
+0x00028B68 VGT_HS_PATCH_CONST
+0x00028B6C VGT_TF_PARAM
+0x00028B70 DB_ALPHA_TO_MASK
+0x00028B74 VGT_DISPATCH_INITIATOR
+0x00028B78 PA_SU_POLY_OFFSET_DB_FMT_CNTL
+0x00028B7C PA_SU_POLY_OFFSET_CLAMP
+0x00028B80 PA_SU_POLY_OFFSET_FRONT_SCALE
+0x00028B84 PA_SU_POLY_OFFSET_FRONT_OFFSET
+0x00028B88 PA_SU_POLY_OFFSET_BACK_SCALE
+0x00028B8C PA_SU_POLY_OFFSET_BACK_OFFSET
+0x00028B74 VGT_GS_INSTANCE_CNT
+0x00028C00 PA_SC_LINE_CNTL
+0x00028C08 PA_SU_VTX_CNTL
+0x00028C0C PA_CL_GB_VERT_CLIP_ADJ
+0x00028C10 PA_CL_GB_VERT_DISC_ADJ
+0x00028C14 PA_CL_GB_HORZ_CLIP_ADJ
+0x00028C18 PA_CL_GB_HORZ_DISC_ADJ
+0x00028C1C PA_SC_AA_SAMPLE_LOCS_0
+0x00028C20 PA_SC_AA_SAMPLE_LOCS_1
+0x00028C24 PA_SC_AA_SAMPLE_LOCS_2
+0x00028C28 PA_SC_AA_SAMPLE_LOCS_3
+0x00028C2C PA_SC_AA_SAMPLE_LOCS_4
+0x00028C30 PA_SC_AA_SAMPLE_LOCS_5
+0x00028C34 PA_SC_AA_SAMPLE_LOCS_6
+0x00028C38 PA_SC_AA_SAMPLE_LOCS_7
+0x00028C3C PA_SC_AA_MASK
+0x00028C8C CB_COLOR0_CLEAR_WORD0
+0x00028C90 CB_COLOR0_CLEAR_WORD1
+0x00028C94 CB_COLOR0_CLEAR_WORD2
+0x00028C98 CB_COLOR0_CLEAR_WORD3
+0x00028CC8 CB_COLOR1_CLEAR_WORD0
+0x00028CCC CB_COLOR1_CLEAR_WORD1
+0x00028CD0 CB_COLOR1_CLEAR_WORD2
+0x00028CD4 CB_COLOR1_CLEAR_WORD3
+0x00028D04 CB_COLOR2_CLEAR_WORD0
+0x00028D08 CB_COLOR2_CLEAR_WORD1
+0x00028D0C CB_COLOR2_CLEAR_WORD2
+0x00028D10 CB_COLOR2_CLEAR_WORD3
+0x00028D40 CB_COLOR3_CLEAR_WORD0
+0x00028D44 CB_COLOR3_CLEAR_WORD1
+0x00028D48 CB_COLOR3_CLEAR_WORD2
+0x00028D4C CB_COLOR3_CLEAR_WORD3
+0x00028D7C CB_COLOR4_CLEAR_WORD0
+0x00028D80 CB_COLOR4_CLEAR_WORD1
+0x00028D84 CB_COLOR4_CLEAR_WORD2
+0x00028D88 CB_COLOR4_CLEAR_WORD3
+0x00028DB8 CB_COLOR5_CLEAR_WORD0
+0x00028DBC CB_COLOR5_CLEAR_WORD1
+0x00028DC0 CB_COLOR5_CLEAR_WORD2
+0x00028DC4 CB_COLOR5_CLEAR_WORD3
+0x00028DF4 CB_COLOR6_CLEAR_WORD0
+0x00028DF8 CB_COLOR6_CLEAR_WORD1
+0x00028DFC CB_COLOR6_CLEAR_WORD2
+0x00028E00 CB_COLOR6_CLEAR_WORD3
+0x00028E30 CB_COLOR7_CLEAR_WORD0
+0x00028E34 CB_COLOR7_CLEAR_WORD1
+0x00028E38 CB_COLOR7_CLEAR_WORD2
+0x00028E3C CB_COLOR7_CLEAR_WORD3
+0x00028F80 SQ_ALU_CONST_BUFFER_SIZE_HS_0
+0x00028F84 SQ_ALU_CONST_BUFFER_SIZE_HS_1
+0x00028F88 SQ_ALU_CONST_BUFFER_SIZE_HS_2
+0x00028F8C SQ_ALU_CONST_BUFFER_SIZE_HS_3
+0x00028F90 SQ_ALU_CONST_BUFFER_SIZE_HS_4
+0x00028F94 SQ_ALU_CONST_BUFFER_SIZE_HS_5
+0x00028F98 SQ_ALU_CONST_BUFFER_SIZE_HS_6
+0x00028F9C SQ_ALU_CONST_BUFFER_SIZE_HS_7
+0x00028FA0 SQ_ALU_CONST_BUFFER_SIZE_HS_8
+0x00028FA4 SQ_ALU_CONST_BUFFER_SIZE_HS_9
+0x00028FA8 SQ_ALU_CONST_BUFFER_SIZE_HS_10
+0x00028FAC SQ_ALU_CONST_BUFFER_SIZE_HS_11
+0x00028FB0 SQ_ALU_CONST_BUFFER_SIZE_HS_12
+0x00028FB4 SQ_ALU_CONST_BUFFER_SIZE_HS_13
+0x00028FB8 SQ_ALU_CONST_BUFFER_SIZE_HS_14
+0x00028FBC SQ_ALU_CONST_BUFFER_SIZE_HS_15
+0x00028FC0 SQ_ALU_CONST_BUFFER_SIZE_LS_0
+0x00028FC4 SQ_ALU_CONST_BUFFER_SIZE_LS_1
+0x00028FC8 SQ_ALU_CONST_BUFFER_SIZE_LS_2
+0x00028FCC SQ_ALU_CONST_BUFFER_SIZE_LS_3
+0x00028FD0 SQ_ALU_CONST_BUFFER_SIZE_LS_4
+0x00028FD4 SQ_ALU_CONST_BUFFER_SIZE_LS_5
+0x00028FD8 SQ_ALU_CONST_BUFFER_SIZE_LS_6
+0x00028FDC SQ_ALU_CONST_BUFFER_SIZE_LS_7
+0x00028FE0 SQ_ALU_CONST_BUFFER_SIZE_LS_8
+0x00028FE4 SQ_ALU_CONST_BUFFER_SIZE_LS_9
+0x00028FE8 SQ_ALU_CONST_BUFFER_SIZE_LS_10
+0x00028FEC SQ_ALU_CONST_BUFFER_SIZE_LS_11
+0x00028FF0 SQ_ALU_CONST_BUFFER_SIZE_LS_12
+0x00028FF4 SQ_ALU_CONST_BUFFER_SIZE_LS_13
+0x00028FF8 SQ_ALU_CONST_BUFFER_SIZE_LS_14
+0x00028FFC SQ_ALU_CONST_BUFFER_SIZE_LS_15
+0x0003CFF0 SQ_VTX_BASE_VTX_LOC
+0x0003CFF4 SQ_VTX_START_INST_LOC
+0x0003FF00 SQ_TEX_SAMPLER_CLEAR
+0x0003FF04 SQ_TEX_RESOURCE_CLEAR
+0x0003FF08 SQ_LOOP_BOOL_CLEAR
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 79887cac5b54..7bb4c3e52f3b 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -74,7 +74,8 @@ void rs600_pm_misc(struct radeon_device *rdev)
if (voltage->delay)
udelay(voltage->delay);
}
- }
+ } else if (voltage->type == VOLTAGE_VDDC)
+ radeon_atom_set_voltage(rdev, voltage->vddc_id);
dyn_pwrmgt_sclk_length = RREG32_PLL(DYN_PWRMGT_SCLK_LENGTH);
dyn_pwrmgt_sclk_length &= ~REDUCED_POWER_SCLK_HILEN(0xf);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 253f24aec031..33952da65340 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -44,7 +44,12 @@ void rv770_fini(struct radeon_device *rdev);
void rv770_pm_misc(struct radeon_device *rdev)
{
+ int requested_index = rdev->pm.requested_power_state_index;
+ struct radeon_power_state *ps = &rdev->pm.power_state[requested_index];
+ struct radeon_voltage *voltage = &ps->clock_info[0].voltage;
+ if ((voltage->type == VOLTAGE_SW) && voltage->voltage)
+ radeon_atom_set_voltage(rdev, voltage->voltage);
}
/*
diff --git a/drivers/gpu/drm/ttm/ttm_page_alloc.c b/drivers/gpu/drm/ttm/ttm_page_alloc.c
index 0d9a42c2394f..ef910694bd63 100644
--- a/drivers/gpu/drm/ttm/ttm_page_alloc.c
+++ b/drivers/gpu/drm/ttm/ttm_page_alloc.c
@@ -77,7 +77,7 @@ struct ttm_page_pool {
/**
* Limits for the pool. They are handled without locks because only place where
* they may change is in sysfs store. They won't have immediate effect anyway
- * so forcing serialiazation to access them is pointless.
+ * so forcing serialization to access them is pointless.
*/
struct ttm_pool_opts {
@@ -165,16 +165,18 @@ static ssize_t ttm_pool_store(struct kobject *kobj,
m->options.small = val;
else if (attr == &ttm_page_pool_alloc_size) {
if (val > NUM_PAGES_TO_ALLOC*8) {
- printk(KERN_ERR "[ttm] Setting allocation size to %lu "
- "is not allowed. Recomended size is "
- "%lu\n",
- NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7),
- NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
+ printk(KERN_ERR TTM_PFX
+ "Setting allocation size to %lu "
+ "is not allowed. Recommended size is "
+ "%lu\n",
+ NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 7),
+ NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
return size;
} else if (val > NUM_PAGES_TO_ALLOC) {
- printk(KERN_WARNING "[ttm] Setting allocation size to "
- "larger than %lu is not recomended.\n",
- NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
+ printk(KERN_WARNING TTM_PFX
+ "Setting allocation size to "
+ "larger than %lu is not recommended.\n",
+ NUM_PAGES_TO_ALLOC*(PAGE_SIZE >> 10));
}
m->options.alloc_size = val;
}
@@ -277,7 +279,7 @@ static void ttm_pages_put(struct page *pages[], unsigned npages)
{
unsigned i;
if (set_pages_array_wb(pages, npages))
- printk(KERN_ERR "[ttm] Failed to set %d pages to wb!\n",
+ printk(KERN_ERR TTM_PFX "Failed to set %d pages to wb!\n",
npages);
for (i = 0; i < npages; ++i)
__free_page(pages[i]);
@@ -313,7 +315,8 @@ static int ttm_page_pool_free(struct ttm_page_pool *pool, unsigned nr_free)
pages_to_free = kmalloc(npages_to_free * sizeof(struct page *),
GFP_KERNEL);
if (!pages_to_free) {
- printk(KERN_ERR "Failed to allocate memory for pool free operation.\n");
+ printk(KERN_ERR TTM_PFX
+ "Failed to allocate memory for pool free operation.\n");
return 0;
}
@@ -390,7 +393,7 @@ static int ttm_pool_get_num_unused_pages(void)
}
/**
- * Calback for mm to request pool to reduce number of page held.
+ * Callback for mm to request pool to reduce number of page held.
*/
static int ttm_pool_mm_shrink(int shrink_pages, gfp_t gfp_mask)
{
@@ -433,14 +436,16 @@ static int ttm_set_pages_caching(struct page **pages,
case tt_uncached:
r = set_pages_array_uc(pages, cpages);
if (r)
- printk(KERN_ERR "[ttm] Failed to set %d pages to uc!\n",
- cpages);
+ printk(KERN_ERR TTM_PFX
+ "Failed to set %d pages to uc!\n",
+ cpages);
break;
case tt_wc:
r = set_pages_array_wc(pages, cpages);
if (r)
- printk(KERN_ERR "[ttm] Failed to set %d pages to wc!\n",
- cpages);
+ printk(KERN_ERR TTM_PFX
+ "Failed to set %d pages to wc!\n",
+ cpages);
break;
default:
break;
@@ -458,7 +463,7 @@ static void ttm_handle_caching_state_failure(struct list_head *pages,
struct page **failed_pages, unsigned cpages)
{
unsigned i;
- /* Failed pages has to be reed */
+ /* Failed pages have to be freed */
for (i = 0; i < cpages; ++i) {
list_del(&failed_pages[i]->lru);
__free_page(failed_pages[i]);
@@ -485,7 +490,8 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags,
caching_array = kmalloc(max_cpages*sizeof(struct page *), GFP_KERNEL);
if (!caching_array) {
- printk(KERN_ERR "[ttm] unable to allocate table for new pages.");
+ printk(KERN_ERR TTM_PFX
+ "Unable to allocate table for new pages.");
return -ENOMEM;
}
@@ -493,12 +499,13 @@ static int ttm_alloc_new_pages(struct list_head *pages, int gfp_flags,
p = alloc_page(gfp_flags);
if (!p) {
- printk(KERN_ERR "[ttm] unable to get page %u\n", i);
+ printk(KERN_ERR TTM_PFX "Unable to get page %u.\n", i);
/* store already allocated pages in the pool after
* setting the caching state */
if (cpages) {
- r = ttm_set_pages_caching(caching_array, cstate, cpages);
+ r = ttm_set_pages_caching(caching_array,
+ cstate, cpages);
if (r)
ttm_handle_caching_state_failure(pages,
ttm_flags, cstate,
@@ -590,7 +597,8 @@ static void ttm_page_pool_fill_locked(struct ttm_page_pool *pool,
++pool->nrefills;
pool->npages += alloc_size;
} else {
- printk(KERN_ERR "[ttm] Failed to fill pool (%p).", pool);
+ printk(KERN_ERR TTM_PFX
+ "Failed to fill pool (%p).", pool);
/* If we have any pages left put them to the pool. */
list_for_each_entry(p, &pool->list, lru) {
++cpages;
@@ -671,13 +679,14 @@ int ttm_get_pages(struct list_head *pages, int flags,
if (flags & TTM_PAGE_FLAG_DMA32)
gfp_flags |= GFP_DMA32;
else
- gfp_flags |= __GFP_HIGHMEM;
+ gfp_flags |= GFP_HIGHUSER;
for (r = 0; r < count; ++r) {
p = alloc_page(gfp_flags);
if (!p) {
- printk(KERN_ERR "[ttm] unable to allocate page.");
+ printk(KERN_ERR TTM_PFX
+ "Unable to allocate page.");
return -ENOMEM;
}
@@ -709,8 +718,9 @@ int ttm_get_pages(struct list_head *pages, int flags,
if (r) {
/* If there is any pages in the list put them back to
* the pool. */
- printk(KERN_ERR "[ttm] Failed to allocate extra pages "
- "for large request.");
+ printk(KERN_ERR TTM_PFX
+ "Failed to allocate extra pages "
+ "for large request.");
ttm_put_pages(pages, 0, flags, cstate);
return r;
}
@@ -778,7 +788,7 @@ int ttm_page_alloc_init(struct ttm_mem_global *glob, unsigned max_pages)
if (atomic_add_return(1, &_manager.page_alloc_inited) > 1)
return 0;
- printk(KERN_INFO "[ttm] Initializing pool allocator.\n");
+ printk(KERN_INFO TTM_PFX "Initializing pool allocator.\n");
ttm_page_pool_init_locked(&_manager.wc_pool, GFP_HIGHUSER, "wc");
@@ -813,7 +823,7 @@ void ttm_page_alloc_fini()
if (atomic_sub_return(1, &_manager.page_alloc_inited) > 0)
return;
- printk(KERN_INFO "[ttm] Finilizing pool allocator.\n");
+ printk(KERN_INFO TTM_PFX "Finalizing pool allocator.\n");
ttm_pool_mm_shrink_fini(&_manager);
for (i = 0; i < NUM_POOLS; ++i)
diff --git a/drivers/gpu/drm/vmwgfx/Makefile b/drivers/gpu/drm/vmwgfx/Makefile
index 1a3cb6816d1c..4505e17df3f5 100644
--- a/drivers/gpu/drm/vmwgfx/Makefile
+++ b/drivers/gpu/drm/vmwgfx/Makefile
@@ -4,6 +4,6 @@ ccflags-y := -Iinclude/drm
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
- vmwgfx_overlay.o
+ vmwgfx_overlay.o vmwgfx_fence.o
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 0c9c0811f42d..b793c8c9acb3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -88,6 +88,9 @@
#define DRM_IOCTL_VMW_FENCE_WAIT \
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \
struct drm_vmw_fence_wait_arg)
+#define DRM_IOCTL_VMW_UPDATE_LAYOUT \
+ DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \
+ struct drm_vmw_update_layout_arg)
/**
@@ -135,7 +138,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FIFO_DEBUG, vmw_fifo_debug_ioctl,
DRM_AUTH | DRM_ROOT_ONLY | DRM_MASTER | DRM_UNLOCKED),
VMW_IOCTL_DEF(DRM_IOCTL_VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
- DRM_AUTH | DRM_UNLOCKED)
+ DRM_AUTH | DRM_UNLOCKED),
+ VMW_IOCTL_DEF(DRM_IOCTL_VMW_UPDATE_LAYOUT, vmw_kms_update_layout_ioctl,
+ DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED)
};
static struct pci_device_id vmw_pci_id_list[] = {
@@ -318,6 +323,15 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_err3;
}
+ /* Need mmio memory to check for fifo pitchlock cap. */
+ if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) &&
+ !(dev_priv->capabilities & SVGA_CAP_PITCHLOCK) &&
+ !vmw_fifo_have_pitchlock(dev_priv)) {
+ ret = -ENOSYS;
+ DRM_ERROR("Hardware has no pitchlock\n");
+ goto out_err4;
+ }
+
dev_priv->tdev = ttm_object_device_init
(dev_priv->mem_global_ref.object, 12);
@@ -399,8 +413,6 @@ static int vmw_driver_unload(struct drm_device *dev)
{
struct vmw_private *dev_priv = vmw_priv(dev);
- DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n");
-
unregister_pm_notifier(&dev_priv->pm_nb);
vmw_fb_close(dev_priv);
@@ -546,7 +558,6 @@ static int vmw_master_create(struct drm_device *dev,
{
struct vmw_master *vmaster;
- DRM_INFO("Master create.\n");
vmaster = kzalloc(sizeof(*vmaster), GFP_KERNEL);
if (unlikely(vmaster == NULL))
return -ENOMEM;
@@ -563,7 +574,6 @@ static void vmw_master_destroy(struct drm_device *dev,
{
struct vmw_master *vmaster = vmw_master(master);
- DRM_INFO("Master destroy.\n");
master->driver_priv = NULL;
kfree(vmaster);
}
@@ -579,8 +589,6 @@ static int vmw_master_set(struct drm_device *dev,
struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret = 0;
- DRM_INFO("Master set.\n");
-
if (active) {
BUG_ON(active != &dev_priv->fbdev_master);
ret = ttm_vt_lock(&active->lock, false, vmw_fp->tfile);
@@ -622,8 +630,6 @@ static void vmw_master_drop(struct drm_device *dev,
struct vmw_master *vmaster = vmw_master(file_priv->master);
int ret;
- DRM_INFO("Master drop.\n");
-
/**
* Make sure the master doesn't disappear while we have
* it locked.
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index 356dc935ec13..eaad52095339 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -41,12 +41,13 @@
#define VMWGFX_DRIVER_DATE "20100209"
#define VMWGFX_DRIVER_MAJOR 1
-#define VMWGFX_DRIVER_MINOR 0
+#define VMWGFX_DRIVER_MINOR 2
#define VMWGFX_DRIVER_PATCHLEVEL 0
#define VMWGFX_FILE_PAGE_OFFSET 0x00100000
#define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
#define VMWGFX_MAX_RELOCATIONS 2048
#define VMWGFX_MAX_GMRS 2048
+#define VMWGFX_MAX_DISPLAYS 16
struct vmw_fpriv {
struct drm_master *locked_master;
@@ -102,6 +103,13 @@ struct vmw_surface {
struct vmw_cursor_snooper snooper;
};
+struct vmw_fence_queue {
+ struct list_head head;
+ struct timespec lag;
+ struct timespec lag_time;
+ spinlock_t lock;
+};
+
struct vmw_fifo_state {
unsigned long reserved_size;
__le32 *dynamic_buffer;
@@ -115,6 +123,7 @@ struct vmw_fifo_state {
uint32_t capabilities;
struct mutex fifo_mutex;
struct rw_semaphore rwsem;
+ struct vmw_fence_queue fence_queue;
};
struct vmw_relocation {
@@ -144,6 +153,14 @@ struct vmw_master {
struct ttm_lock lock;
};
+struct vmw_vga_topology_state {
+ uint32_t width;
+ uint32_t height;
+ uint32_t primary;
+ uint32_t pos_x;
+ uint32_t pos_y;
+};
+
struct vmw_private {
struct ttm_bo_device bdev;
struct ttm_bo_global_ref bo_global_ref;
@@ -171,14 +188,19 @@ struct vmw_private {
* VGA registers.
*/
+ struct vmw_vga_topology_state vga_save[VMWGFX_MAX_DISPLAYS];
uint32_t vga_width;
uint32_t vga_height;
uint32_t vga_depth;
uint32_t vga_bpp;
uint32_t vga_pseudo;
uint32_t vga_red_mask;
- uint32_t vga_blue_mask;
uint32_t vga_green_mask;
+ uint32_t vga_blue_mask;
+ uint32_t vga_bpl;
+ uint32_t vga_pitchlock;
+
+ uint32_t num_displays;
/*
* Framebuffer info.
@@ -393,6 +415,7 @@ extern int vmw_fifo_send_fence(struct vmw_private *dev_priv,
extern void vmw_fifo_ping_host(struct vmw_private *dev_priv, uint32_t reason);
extern int vmw_fifo_mmap(struct file *filp, struct vm_area_struct *vma);
extern bool vmw_fifo_have_3d(struct vmw_private *dev_priv);
+extern bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv);
/**
* TTM glue - vmwgfx_ttm_glue.c
@@ -441,6 +464,23 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv,
uint32_t sequence,
bool interruptible,
unsigned long timeout);
+extern void vmw_update_sequence(struct vmw_private *dev_priv,
+ struct vmw_fifo_state *fifo_state);
+
+
+/**
+ * Rudimentary fence objects currently used only for throttling -
+ * vmwgfx_fence.c
+ */
+
+extern void vmw_fence_queue_init(struct vmw_fence_queue *queue);
+extern void vmw_fence_queue_takedown(struct vmw_fence_queue *queue);
+extern int vmw_fence_push(struct vmw_fence_queue *queue,
+ uint32_t sequence);
+extern int vmw_fence_pull(struct vmw_fence_queue *queue,
+ uint32_t signaled_sequence);
+extern int vmw_wait_lag(struct vmw_private *dev_priv,
+ struct vmw_fence_queue *queue, uint32_t us);
/**
* Kernel framebuffer - vmwgfx_fb.c
@@ -466,6 +506,11 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf,
struct ttm_object_file *tfile,
struct ttm_buffer_object *bo,
SVGA3dCmdHeader *header);
+void vmw_kms_write_svga(struct vmw_private *vmw_priv,
+ unsigned width, unsigned height, unsigned pitch,
+ unsigned bbp, unsigned depth);
+int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/**
* Overlay control - vmwgfx_overlay.c
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
index dbd36b8910cf..bdd67cf83315 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
@@ -669,6 +669,15 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
goto out_err;
vmw_apply_relocations(sw_context);
+
+ if (arg->throttle_us) {
+ ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.fence_queue,
+ arg->throttle_us);
+
+ if (unlikely(ret != 0))
+ goto out_err;
+ }
+
vmw_fifo_commit(dev_priv, arg->command_size);
ret = vmw_fifo_send_fence(dev_priv, &sequence);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
index 7421aaad8d09..b0866f04ec76 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
@@ -132,16 +132,14 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
return -EINVAL;
}
- /* without multimon its hard to resize */
- if (!(vmw_priv->capabilities & SVGA_CAP_MULTIMON) &&
- (var->xres != par->max_width ||
- var->yres != par->max_height)) {
- DRM_ERROR("Tried to resize, but we don't have multimon\n");
+ if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) &&
+ (var->xoffset != 0 || var->yoffset != 0)) {
+ DRM_ERROR("Can not handle panning without display topology\n");
return -EINVAL;
}
- if (var->xres > par->max_width ||
- var->yres > par->max_height) {
+ if ((var->xoffset + var->xres) > par->max_width ||
+ (var->yoffset + var->yres) > par->max_height) {
DRM_ERROR("Requested geom can not fit in framebuffer\n");
return -EINVAL;
}
@@ -154,27 +152,11 @@ static int vmw_fb_set_par(struct fb_info *info)
struct vmw_fb_par *par = info->par;
struct vmw_private *vmw_priv = par->vmw_priv;
- if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
- vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
-
- vmw_write(vmw_priv, SVGA_REG_ENABLE, 1);
- vmw_write(vmw_priv, SVGA_REG_WIDTH, par->max_width);
- vmw_write(vmw_priv, SVGA_REG_HEIGHT, par->max_height);
- vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, par->bpp);
- vmw_write(vmw_priv, SVGA_REG_DEPTH, par->depth);
- vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
- vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
- vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
-
+ vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
+ info->fix.line_length,
+ par->bpp, par->depth);
+ if (vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY) {
/* TODO check if pitch and offset changes */
-
vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
@@ -183,13 +165,13 @@ static int vmw_fb_set_par(struct fb_info *info)
vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres);
vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
- } else {
- vmw_write(vmw_priv, SVGA_REG_WIDTH, info->var.xres);
- vmw_write(vmw_priv, SVGA_REG_HEIGHT, info->var.yres);
-
- /* TODO check if pitch and offset changes */
}
+ /* This is really helpful since if this fails the user
+ * can probably not see anything on the screen.
+ */
+ WARN_ON(vmw_read(vmw_priv, SVGA_REG_FB_OFFSET) != 0);
+
return 0;
}
@@ -416,48 +398,23 @@ int vmw_fb_init(struct vmw_private *vmw_priv)
unsigned fb_bbp, fb_depth, fb_offset, fb_pitch, fb_size;
int ret;
+ /* XXX These shouldn't be hardcoded. */
initial_width = 800;
initial_height = 600;
fb_bbp = 32;
fb_depth = 24;
- if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
- fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
- fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
- } else {
- fb_width = min(vmw_priv->fb_max_width, initial_width);
- fb_height = min(vmw_priv->fb_max_height, initial_height);
- }
+ /* XXX As shouldn't these be as well. */
+ fb_width = min(vmw_priv->fb_max_width, (unsigned)2048);
+ fb_height = min(vmw_priv->fb_max_height, (unsigned)2048);
initial_width = min(fb_width, initial_width);
initial_height = min(fb_height, initial_height);
- vmw_write(vmw_priv, SVGA_REG_WIDTH, fb_width);
- vmw_write(vmw_priv, SVGA_REG_HEIGHT, fb_height);
- vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, fb_bbp);
- vmw_write(vmw_priv, SVGA_REG_DEPTH, fb_depth);
- vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
- vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
- vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
-
- fb_size = vmw_read(vmw_priv, SVGA_REG_FB_SIZE);
+ fb_pitch = fb_width * fb_bbp / 8;
+ fb_size = fb_pitch * fb_height;
fb_offset = vmw_read(vmw_priv, SVGA_REG_FB_OFFSET);
- fb_pitch = vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE);
-
- DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_WIDTH));
- DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_MAX_HEIGHT));
- DRM_DEBUG("width %u\n", vmw_read(vmw_priv, SVGA_REG_WIDTH));
- DRM_DEBUG("height %u\n", vmw_read(vmw_priv, SVGA_REG_HEIGHT));
- DRM_DEBUG("bpp %u\n", vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL));
- DRM_DEBUG("depth %u\n", vmw_read(vmw_priv, SVGA_REG_DEPTH));
- DRM_DEBUG("bpl %u\n", vmw_read(vmw_priv, SVGA_REG_BYTES_PER_LINE));
- DRM_DEBUG("r mask %08x\n", vmw_read(vmw_priv, SVGA_REG_RED_MASK));
- DRM_DEBUG("g mask %08x\n", vmw_read(vmw_priv, SVGA_REG_GREEN_MASK));
- DRM_DEBUG("b mask %08x\n", vmw_read(vmw_priv, SVGA_REG_BLUE_MASK));
- DRM_DEBUG("fb_offset 0x%08x\n", fb_offset);
- DRM_DEBUG("fb_pitch %u\n", fb_pitch);
- DRM_DEBUG("fb_size %u kiB\n", fb_size / 1024);
info = framebuffer_alloc(sizeof(*par), device);
if (!info)
@@ -659,6 +616,10 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *vmw_priv,
goto err_unlock;
ret = ttm_bo_validate(bo, &ne_placement, false, false, false);
+
+ /* Could probably bug on */
+ WARN_ON(bo->offset != 0);
+
ttm_bo_unreserve(bo);
err_unlock:
ttm_write_unlock(&vmw_priv->active_master->lock);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
new file mode 100644
index 000000000000..61eacc1b5ca3
--- /dev/null
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -0,0 +1,173 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2010 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#include "vmwgfx_drv.h"
+
+struct vmw_fence {
+ struct list_head head;
+ uint32_t sequence;
+ struct timespec submitted;
+};
+
+void vmw_fence_queue_init(struct vmw_fence_queue *queue)
+{
+ INIT_LIST_HEAD(&queue->head);
+ queue->lag = ns_to_timespec(0);
+ getrawmonotonic(&queue->lag_time);
+ spin_lock_init(&queue->lock);
+}
+
+void vmw_fence_queue_takedown(struct vmw_fence_queue *queue)
+{
+ struct vmw_fence *fence, *next;
+
+ spin_lock(&queue->lock);
+ list_for_each_entry_safe(fence, next, &queue->head, head) {
+ kfree(fence);
+ }
+ spin_unlock(&queue->lock);
+}
+
+int vmw_fence_push(struct vmw_fence_queue *queue,
+ uint32_t sequence)
+{
+ struct vmw_fence *fence = kmalloc(sizeof(*fence), GFP_KERNEL);
+
+ if (unlikely(!fence))
+ return -ENOMEM;
+
+ fence->sequence = sequence;
+ getrawmonotonic(&fence->submitted);
+ spin_lock(&queue->lock);
+ list_add_tail(&fence->head, &queue->head);
+ spin_unlock(&queue->lock);
+
+ return 0;
+}
+
+int vmw_fence_pull(struct vmw_fence_queue *queue,
+ uint32_t signaled_sequence)
+{
+ struct vmw_fence *fence, *next;
+ struct timespec now;
+ bool updated = false;
+
+ spin_lock(&queue->lock);
+ getrawmonotonic(&now);
+
+ if (list_empty(&queue->head)) {
+ queue->lag = ns_to_timespec(0);
+ queue->lag_time = now;
+ updated = true;
+ goto out_unlock;
+ }
+
+ list_for_each_entry_safe(fence, next, &queue->head, head) {
+ if (signaled_sequence - fence->sequence > (1 << 30))
+ continue;
+
+ queue->lag = timespec_sub(now, fence->submitted);
+ queue->lag_time = now;
+ updated = true;
+ list_del(&fence->head);
+ kfree(fence);
+ }
+
+out_unlock:
+ spin_unlock(&queue->lock);
+
+ return (updated) ? 0 : -EBUSY;
+}
+
+static struct timespec vmw_timespec_add(struct timespec t1,
+ struct timespec t2)
+{
+ t1.tv_sec += t2.tv_sec;
+ t1.tv_nsec += t2.tv_nsec;
+ if (t1.tv_nsec >= 1000000000L) {
+ t1.tv_sec += 1;
+ t1.tv_nsec -= 1000000000L;
+ }
+
+ return t1;
+}
+
+static struct timespec vmw_fifo_lag(struct vmw_fence_queue *queue)
+{
+ struct timespec now;
+
+ spin_lock(&queue->lock);
+ getrawmonotonic(&now);
+ queue->lag = vmw_timespec_add(queue->lag,
+ timespec_sub(now, queue->lag_time));
+ queue->lag_time = now;
+ spin_unlock(&queue->lock);
+ return queue->lag;
+}
+
+
+static bool vmw_lag_lt(struct vmw_fence_queue *queue,
+ uint32_t us)
+{
+ struct timespec lag, cond;
+
+ cond = ns_to_timespec((s64) us * 1000);
+ lag = vmw_fifo_lag(queue);
+ return (timespec_compare(&lag, &cond) < 1);
+}
+
+int vmw_wait_lag(struct vmw_private *dev_priv,
+ struct vmw_fence_queue *queue, uint32_t us)
+{
+ struct vmw_fence *fence;
+ uint32_t sequence;
+ int ret;
+
+ while (!vmw_lag_lt(queue, us)) {
+ spin_lock(&queue->lock);
+ if (list_empty(&queue->head))
+ sequence = atomic_read(&dev_priv->fence_seq);
+ else {
+ fence = list_first_entry(&queue->head,
+ struct vmw_fence, head);
+ sequence = fence->sequence;
+ }
+ spin_unlock(&queue->lock);
+
+ ret = vmw_wait_fence(dev_priv, false, sequence, true,
+ 3*HZ);
+
+ if (unlikely(ret != 0))
+ return ret;
+
+ (void) vmw_fence_pull(queue, sequence);
+ }
+ return 0;
+}
+
+
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index 39d43a01d846..e6a1eb7ea954 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -34,6 +34,9 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
uint32_t fifo_min, hwversion;
+ if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
+ return false;
+
fifo_min = ioread32(fifo_mem + SVGA_FIFO_MIN);
if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int))
return false;
@@ -48,6 +51,21 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
return true;
}
+bool vmw_fifo_have_pitchlock(struct vmw_private *dev_priv)
+{
+ __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+ uint32_t caps;
+
+ if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
+ return false;
+
+ caps = ioread32(fifo_mem + SVGA_FIFO_CAPABILITIES);
+ if (caps & SVGA_FIFO_CAP_PITCHLOCK)
+ return true;
+
+ return false;
+}
+
int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
{
__le32 __iomem *fifo_mem = dev_priv->mmio_virt;
@@ -120,7 +138,7 @@ int vmw_fifo_init(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
atomic_set(&dev_priv->fence_seq, dev_priv->last_read_sequence);
iowrite32(dev_priv->last_read_sequence, fifo_mem + SVGA_FIFO_FENCE);
-
+ vmw_fence_queue_init(&fifo->fence_queue);
return vmw_fifo_send_fence(dev_priv, &dummy);
out_err:
vfree(fifo->static_buffer);
@@ -159,6 +177,7 @@ void vmw_fifo_release(struct vmw_private *dev_priv, struct vmw_fifo_state *fifo)
dev_priv->enable_state);
mutex_unlock(&dev_priv->hw_mutex);
+ vmw_fence_queue_takedown(&fifo->fence_queue);
if (likely(fifo->last_buffer != NULL)) {
vfree(fifo->last_buffer);
@@ -484,6 +503,8 @@ int vmw_fifo_send_fence(struct vmw_private *dev_priv, uint32_t *sequence)
fifo_state->last_buffer_add = true;
vmw_fifo_commit(dev_priv, bytes);
fifo_state->last_buffer_add = false;
+ (void) vmw_fence_push(&fifo_state->fence_queue, *sequence);
+ vmw_update_sequence(dev_priv, fifo_state);
out_err:
return ret;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
index 4d7cb5393860..e92298a6a383 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
@@ -64,22 +64,33 @@ static bool vmw_fifo_idle(struct vmw_private *dev_priv, uint32_t sequence)
return (busy == 0);
}
+void vmw_update_sequence(struct vmw_private *dev_priv,
+ struct vmw_fifo_state *fifo_state)
+{
+ __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+
+ uint32_t sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+
+ if (dev_priv->last_read_sequence != sequence) {
+ dev_priv->last_read_sequence = sequence;
+ vmw_fence_pull(&fifo_state->fence_queue, sequence);
+ }
+}
bool vmw_fence_signaled(struct vmw_private *dev_priv,
uint32_t sequence)
{
- __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
struct vmw_fifo_state *fifo_state;
bool ret;
if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP))
return true;
- dev_priv->last_read_sequence = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+ fifo_state = &dev_priv->fifo;
+ vmw_update_sequence(dev_priv, fifo_state);
if (likely(dev_priv->last_read_sequence - sequence < VMW_FENCE_WRAP))
return true;
- fifo_state = &dev_priv->fifo;
if (!(fifo_state->capabilities & SVGA_FIFO_CAP_FENCE) &&
vmw_fifo_idle(dev_priv, sequence))
return true;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index bbc7c4c30bc7..f1d626112415 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -30,6 +30,8 @@
/* Might need a hrtimer here? */
#define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
+static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb);
+static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb);
void vmw_display_unit_cleanup(struct vmw_display_unit *du)
{
@@ -326,6 +328,7 @@ int vmw_framebuffer_create_handle(struct drm_framebuffer *fb,
struct vmw_framebuffer_surface {
struct vmw_framebuffer base;
struct vmw_surface *surface;
+ struct vmw_dma_buffer *buffer;
struct delayed_work d_work;
struct mutex work_lock;
bool present_fs;
@@ -500,8 +503,8 @@ int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
vfbs->base.base.depth = 24;
vfbs->base.base.width = width;
vfbs->base.base.height = height;
- vfbs->base.pin = NULL;
- vfbs->base.unpin = NULL;
+ vfbs->base.pin = &vmw_surface_dmabuf_pin;
+ vfbs->base.unpin = &vmw_surface_dmabuf_unpin;
vfbs->surface = surface;
mutex_init(&vfbs->work_lock);
INIT_DELAYED_WORK(&vfbs->d_work, &vmw_framebuffer_present_fs_callback);
@@ -589,6 +592,40 @@ static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
.create_handle = vmw_framebuffer_create_handle,
};
+static int vmw_surface_dmabuf_pin(struct vmw_framebuffer *vfb)
+{
+ struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
+ struct vmw_framebuffer_surface *vfbs =
+ vmw_framebuffer_to_vfbs(&vfb->base);
+ unsigned long size = vfbs->base.base.pitch * vfbs->base.base.height;
+ int ret;
+
+ vfbs->buffer = kzalloc(sizeof(*vfbs->buffer), GFP_KERNEL);
+ if (unlikely(vfbs->buffer == NULL))
+ return -ENOMEM;
+
+ vmw_overlay_pause_all(dev_priv);
+ ret = vmw_dmabuf_init(dev_priv, vfbs->buffer, size,
+ &vmw_vram_ne_placement,
+ false, &vmw_dmabuf_bo_free);
+ vmw_overlay_resume_all(dev_priv);
+
+ return ret;
+}
+
+static int vmw_surface_dmabuf_unpin(struct vmw_framebuffer *vfb)
+{
+ struct ttm_buffer_object *bo;
+ struct vmw_framebuffer_surface *vfbs =
+ vmw_framebuffer_to_vfbs(&vfb->base);
+
+ bo = &vfbs->buffer->base;
+ ttm_bo_unref(&bo);
+ vfbs->buffer = NULL;
+
+ return 0;
+}
+
static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
{
struct vmw_private *dev_priv = vmw_priv(vfb->base.dev);
@@ -596,33 +633,15 @@ static int vmw_framebuffer_dmabuf_pin(struct vmw_framebuffer *vfb)
vmw_framebuffer_to_vfbd(&vfb->base);
int ret;
+
vmw_overlay_pause_all(dev_priv);
ret = vmw_dmabuf_to_start_of_vram(dev_priv, vfbd->buffer);
- if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
- vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
-
- vmw_write(dev_priv, SVGA_REG_ENABLE, 1);
- vmw_write(dev_priv, SVGA_REG_WIDTH, vfb->base.width);
- vmw_write(dev_priv, SVGA_REG_HEIGHT, vfb->base.height);
- vmw_write(dev_priv, SVGA_REG_BITS_PER_PIXEL, vfb->base.bits_per_pixel);
- vmw_write(dev_priv, SVGA_REG_DEPTH, vfb->base.depth);
- vmw_write(dev_priv, SVGA_REG_RED_MASK, 0x00ff0000);
- vmw_write(dev_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
- vmw_write(dev_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
- } else
- WARN_ON(true);
-
vmw_overlay_resume_all(dev_priv);
+ WARN_ON(ret != 0);
+
return 0;
}
@@ -668,7 +687,7 @@ int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
/* XXX get the first 3 from the surface info */
vfbd->base.base.bits_per_pixel = 32;
- vfbd->base.base.pitch = width * 32 / 4;
+ vfbd->base.base.pitch = width * vfbd->base.base.bits_per_pixel / 8;
vfbd->base.base.depth = 24;
vfbd->base.base.width = width;
vfbd->base.base.height = height;
@@ -765,8 +784,9 @@ int vmw_kms_init(struct vmw_private *dev_priv)
dev->mode_config.funcs = &vmw_kms_funcs;
dev->mode_config.min_width = 1;
dev->mode_config.min_height = 1;
- dev->mode_config.max_width = dev_priv->fb_max_width;
- dev->mode_config.max_height = dev_priv->fb_max_height;
+ /* assumed largest fb size */
+ dev->mode_config.max_width = 8192;
+ dev->mode_config.max_height = 8192;
ret = vmw_kms_init_legacy_display_system(dev_priv);
@@ -826,49 +846,140 @@ out:
return ret;
}
+void vmw_kms_write_svga(struct vmw_private *vmw_priv,
+ unsigned width, unsigned height, unsigned pitch,
+ unsigned bbp, unsigned depth)
+{
+ if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
+ vmw_write(vmw_priv, SVGA_REG_PITCHLOCK, pitch);
+ else if (vmw_fifo_have_pitchlock(vmw_priv))
+ iowrite32(pitch, vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
+ vmw_write(vmw_priv, SVGA_REG_WIDTH, width);
+ vmw_write(vmw_priv, SVGA_REG_HEIGHT, height);
+ vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, bbp);
+ vmw_write(vmw_priv, SVGA_REG_DEPTH, depth);
+ vmw_write(vmw_priv, SVGA_REG_RED_MASK, 0x00ff0000);
+ vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, 0x0000ff00);
+ vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, 0x000000ff);
+}
+
int vmw_kms_save_vga(struct vmw_private *vmw_priv)
{
- /*
- * setup a single multimon monitor with the size
- * of 0x0, this stops the UI from resizing when we
- * change the framebuffer size
- */
- if (vmw_priv->capabilities & SVGA_CAP_MULTIMON) {
- vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 1);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, true);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
- vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
- }
+ struct vmw_vga_topology_state *save;
+ uint32_t i;
vmw_priv->vga_width = vmw_read(vmw_priv, SVGA_REG_WIDTH);
vmw_priv->vga_height = vmw_read(vmw_priv, SVGA_REG_HEIGHT);
- vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL);
vmw_priv->vga_depth = vmw_read(vmw_priv, SVGA_REG_DEPTH);
+ vmw_priv->vga_bpp = vmw_read(vmw_priv, SVGA_REG_BITS_PER_PIXEL);
vmw_priv->vga_pseudo = vmw_read(vmw_priv, SVGA_REG_PSEUDOCOLOR);
vmw_priv->vga_red_mask = vmw_read(vmw_priv, SVGA_REG_RED_MASK);
- vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK);
vmw_priv->vga_blue_mask = vmw_read(vmw_priv, SVGA_REG_BLUE_MASK);
+ vmw_priv->vga_green_mask = vmw_read(vmw_priv, SVGA_REG_GREEN_MASK);
+ if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
+ vmw_priv->vga_pitchlock =
+ vmw_read(vmw_priv, SVGA_REG_PITCHLOCK);
+ else if (vmw_fifo_have_pitchlock(vmw_priv))
+ vmw_priv->vga_pitchlock = ioread32(vmw_priv->mmio_virt +
+ SVGA_FIFO_PITCHLOCK);
+
+ if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
+ return 0;
+ vmw_priv->num_displays = vmw_read(vmw_priv,
+ SVGA_REG_NUM_GUEST_DISPLAYS);
+
+ for (i = 0; i < vmw_priv->num_displays; ++i) {
+ save = &vmw_priv->vga_save[i];
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
+ save->primary = vmw_read(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY);
+ save->pos_x = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_X);
+ save->pos_y = vmw_read(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y);
+ save->width = vmw_read(vmw_priv, SVGA_REG_DISPLAY_WIDTH);
+ save->height = vmw_read(vmw_priv, SVGA_REG_DISPLAY_HEIGHT);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+ }
return 0;
}
int vmw_kms_restore_vga(struct vmw_private *vmw_priv)
{
+ struct vmw_vga_topology_state *save;
+ uint32_t i;
+
vmw_write(vmw_priv, SVGA_REG_WIDTH, vmw_priv->vga_width);
vmw_write(vmw_priv, SVGA_REG_HEIGHT, vmw_priv->vga_height);
- vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp);
vmw_write(vmw_priv, SVGA_REG_DEPTH, vmw_priv->vga_depth);
+ vmw_write(vmw_priv, SVGA_REG_BITS_PER_PIXEL, vmw_priv->vga_bpp);
vmw_write(vmw_priv, SVGA_REG_PSEUDOCOLOR, vmw_priv->vga_pseudo);
vmw_write(vmw_priv, SVGA_REG_RED_MASK, vmw_priv->vga_red_mask);
vmw_write(vmw_priv, SVGA_REG_GREEN_MASK, vmw_priv->vga_green_mask);
vmw_write(vmw_priv, SVGA_REG_BLUE_MASK, vmw_priv->vga_blue_mask);
+ if (vmw_priv->capabilities & SVGA_CAP_PITCHLOCK)
+ vmw_write(vmw_priv, SVGA_REG_PITCHLOCK,
+ vmw_priv->vga_pitchlock);
+ else if (vmw_fifo_have_pitchlock(vmw_priv))
+ iowrite32(vmw_priv->vga_pitchlock,
+ vmw_priv->mmio_virt + SVGA_FIFO_PITCHLOCK);
+
+ if (!(vmw_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY))
+ return 0;
- /* TODO check for multimon */
- vmw_write(vmw_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0);
+ for (i = 0; i < vmw_priv->num_displays; ++i) {
+ save = &vmw_priv->vga_save[i];
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, i);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_IS_PRIMARY, save->primary);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_X, save->pos_x);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, save->pos_y);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, save->width);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, save->height);
+ vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+ }
return 0;
}
+
+int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv)
+{
+ struct vmw_private *dev_priv = vmw_priv(dev);
+ struct drm_vmw_update_layout_arg *arg =
+ (struct drm_vmw_update_layout_arg *)data;
+ struct vmw_master *vmaster = vmw_master(file_priv->master);
+ void __user *user_rects;
+ struct drm_vmw_rect *rects;
+ unsigned rects_size;
+ int ret;
+
+ ret = ttm_read_lock(&vmaster->lock, true);
+ if (unlikely(ret != 0))
+ return ret;
+
+ if (!arg->num_outputs) {
+ struct drm_vmw_rect def_rect = {0, 0, 800, 600};
+ vmw_kms_ldu_update_layout(dev_priv, 1, &def_rect);
+ goto out_unlock;
+ }
+
+ rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect);
+ rects = kzalloc(rects_size, GFP_KERNEL);
+ if (unlikely(!rects)) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ user_rects = (void __user *)(unsigned long)arg->rects;
+ ret = copy_from_user(rects, user_rects, rects_size);
+ if (unlikely(ret != 0)) {
+ DRM_ERROR("Failed to get rects.\n");
+ goto out_free;
+ }
+
+ vmw_kms_ldu_update_layout(dev_priv, arg->num_outputs, rects);
+
+out_free:
+ kfree(rects);
+out_unlock:
+ ttm_read_unlock(&vmaster->lock);
+ return ret;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 8b95249f0531..8a398a0339b6 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -94,9 +94,11 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
/*
- * Legacy display unit functions - vmwgfx_ldu.h
+ * Legacy display unit functions - vmwgfx_ldu.c
*/
int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv);
int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv);
+int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
+ struct drm_vmw_rect *rects);
#endif
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index 90891593bf6c..cfaf690a5b2f 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -38,6 +38,7 @@ struct vmw_legacy_display {
struct list_head active;
unsigned num_active;
+ unsigned last_num_active;
struct vmw_framebuffer *fb;
};
@@ -48,9 +49,12 @@ struct vmw_legacy_display {
struct vmw_legacy_display_unit {
struct vmw_display_unit base;
- struct list_head active;
+ unsigned pref_width;
+ unsigned pref_height;
+ bool pref_active;
+ struct drm_display_mode *pref_mode;
- unsigned unit;
+ struct list_head active;
};
static void vmw_ldu_destroy(struct vmw_legacy_display_unit *ldu)
@@ -88,23 +92,44 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
{
struct vmw_legacy_display *lds = dev_priv->ldu_priv;
struct vmw_legacy_display_unit *entry;
- struct drm_crtc *crtc;
+ struct drm_framebuffer *fb = NULL;
+ struct drm_crtc *crtc = NULL;
int i = 0;
- /* to stop the screen from changing size on resize */
- vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, 0);
- for (i = 0; i < lds->num_active; i++) {
- vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, i);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_IS_PRIMARY, !i);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_X, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_POSITION_Y, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_WIDTH, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_HEIGHT, 0);
- vmw_write(dev_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
+ /* If there is no display topology the host just assumes
+ * that the guest will set the same layout as the host.
+ */
+ if (!(dev_priv->capabilities & SVGA_CAP_DISPLAY_TOPOLOGY)) {
+ int w = 0, h = 0;
+ list_for_each_entry(entry, &lds->active, active) {
+ crtc = &entry->base.crtc;
+ w = max(w, crtc->x + crtc->mode.hdisplay);
+ h = max(h, crtc->y + crtc->mode.vdisplay);
+ i++;
+ }
+
+ if (crtc == NULL)
+ return 0;
+ fb = entry->base.crtc.fb;
+
+ vmw_kms_write_svga(dev_priv, w, h, fb->pitch,
+ fb->bits_per_pixel, fb->depth);
+
+ return 0;
}
- /* Now set the mode */
- vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS, lds->num_active);
+ if (!list_empty(&lds->active)) {
+ entry = list_entry(lds->active.next, typeof(*entry), active);
+ fb = entry->base.crtc.fb;
+
+ vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitch,
+ fb->bits_per_pixel, fb->depth);
+ }
+
+ /* Make sure we always show something. */
+ vmw_write(dev_priv, SVGA_REG_NUM_GUEST_DISPLAYS,
+ lds->num_active ? lds->num_active : 1);
+
i = 0;
list_for_each_entry(entry, &lds->active, active) {
crtc = &entry->base.crtc;
@@ -120,6 +145,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
i++;
}
+ BUG_ON(i != lds->num_active);
+
+ lds->last_num_active = lds->num_active;
+
return 0;
}
@@ -130,6 +159,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv,
if (list_empty(&ldu->active))
return 0;
+ /* Must init otherwise list_empty(&ldu->active) will not work. */
list_del_init(&ldu->active);
if (--(ld->num_active) == 0) {
BUG_ON(!ld->fb);
@@ -149,24 +179,29 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv,
struct vmw_legacy_display_unit *entry;
struct list_head *at;
+ BUG_ON(!ld->num_active && ld->fb);
+ if (vfb != ld->fb) {
+ if (ld->fb && ld->fb->unpin)
+ ld->fb->unpin(ld->fb);
+ if (vfb->pin)
+ vfb->pin(vfb);
+ ld->fb = vfb;
+ }
+
if (!list_empty(&ldu->active))
return 0;
at = &ld->active;
list_for_each_entry(entry, &ld->active, active) {
- if (entry->unit > ldu->unit)
+ if (entry->base.unit > ldu->base.unit)
break;
at = &entry->active;
}
list_add(&ldu->active, at);
- if (ld->num_active++ == 0) {
- BUG_ON(ld->fb);
- if (vfb->pin)
- vfb->pin(vfb);
- ld->fb = vfb;
- }
+
+ ld->num_active++;
return 0;
}
@@ -208,6 +243,8 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
/* ldu only supports one fb active at the time */
if (dev_priv->ldu_priv->fb && vfb &&
+ !(dev_priv->ldu_priv->num_active == 1 &&
+ !list_empty(&ldu->active)) &&
dev_priv->ldu_priv->fb != vfb) {
DRM_ERROR("Multiple framebuffers not supported\n");
return -EINVAL;
@@ -300,8 +337,7 @@ static void vmw_ldu_connector_restore(struct drm_connector *connector)
static enum drm_connector_status
vmw_ldu_connector_detect(struct drm_connector *connector)
{
- /* XXX vmwctrl should control connection status */
- if (vmw_connector_to_ldu(connector)->base.unit == 0)
+ if (vmw_connector_to_ldu(connector)->pref_active)
return connector_status_connected;
return connector_status_disconnected;
}
@@ -312,10 +348,9 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = {
752, 800, 0, 480, 489, 492, 525, 0,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) },
/* 800x600@60Hz */
- { DRM_MODE("800x600",
- DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
- 40000, 800, 840, 968, 1056, 0, 600, 601, 605, 628,
- 0, DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
+ { DRM_MODE("800x600", DRM_MODE_TYPE_DRIVER, 40000, 800, 840,
+ 968, 1056, 0, 600, 601, 605, 628, 0,
+ DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC) },
/* 1024x768@60Hz */
{ DRM_MODE("1024x768", DRM_MODE_TYPE_DRIVER, 65000, 1024, 1048,
1184, 1344, 0, 768, 771, 777, 806, 0,
@@ -387,10 +422,34 @@ static struct drm_display_mode vmw_ldu_connector_builtin[] = {
static int vmw_ldu_connector_fill_modes(struct drm_connector *connector,
uint32_t max_width, uint32_t max_height)
{
+ struct vmw_legacy_display_unit *ldu = vmw_connector_to_ldu(connector);
struct drm_device *dev = connector->dev;
struct drm_display_mode *mode = NULL;
+ struct drm_display_mode prefmode = { DRM_MODE("preferred",
+ DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC)
+ };
int i;
+ /* Add preferred mode */
+ {
+ mode = drm_mode_duplicate(dev, &prefmode);
+ if (!mode)
+ return 0;
+ mode->hdisplay = ldu->pref_width;
+ mode->vdisplay = ldu->pref_height;
+ mode->vrefresh = drm_mode_vrefresh(mode);
+ drm_mode_probed_add(connector, mode);
+
+ if (ldu->pref_mode) {
+ list_del_init(&ldu->pref_mode->head);
+ drm_mode_destroy(dev, ldu->pref_mode);
+ }
+
+ ldu->pref_mode = mode;
+ }
+
for (i = 0; vmw_ldu_connector_builtin[i].type != 0; i++) {
if (vmw_ldu_connector_builtin[i].hdisplay > max_width ||
vmw_ldu_connector_builtin[i].vdisplay > max_height)
@@ -443,18 +502,21 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
if (!ldu)
return -ENOMEM;
- ldu->unit = unit;
+ ldu->base.unit = unit;
crtc = &ldu->base.crtc;
encoder = &ldu->base.encoder;
connector = &ldu->base.connector;
+ INIT_LIST_HEAD(&ldu->active);
+
+ ldu->pref_active = (unit == 0);
+ ldu->pref_width = 800;
+ ldu->pref_height = 600;
+ ldu->pref_mode = NULL;
+
drm_connector_init(dev, connector, &vmw_legacy_connector_funcs,
DRM_MODE_CONNECTOR_LVDS);
- /* Initial status */
- if (unit == 0)
- connector->status = connector_status_connected;
- else
- connector->status = connector_status_disconnected;
+ connector->status = vmw_ldu_connector_detect(connector);
drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs,
DRM_MODE_ENCODER_LVDS);
@@ -462,8 +524,6 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit)
encoder->possible_crtcs = (1 << unit);
encoder->possible_clones = 0;
- INIT_LIST_HEAD(&ldu->active);
-
drm_crtc_init(dev, crtc, &vmw_legacy_crtc_funcs);
drm_connector_attach_property(connector,
@@ -487,18 +547,22 @@ int vmw_kms_init_legacy_display_system(struct vmw_private *dev_priv)
INIT_LIST_HEAD(&dev_priv->ldu_priv->active);
dev_priv->ldu_priv->num_active = 0;
+ dev_priv->ldu_priv->last_num_active = 0;
dev_priv->ldu_priv->fb = NULL;
drm_mode_create_dirty_info_property(dev_priv->dev);
vmw_ldu_init(dev_priv, 0);
- vmw_ldu_init(dev_priv, 1);
- vmw_ldu_init(dev_priv, 2);
- vmw_ldu_init(dev_priv, 3);
- vmw_ldu_init(dev_priv, 4);
- vmw_ldu_init(dev_priv, 5);
- vmw_ldu_init(dev_priv, 6);
- vmw_ldu_init(dev_priv, 7);
+ /* for old hardware without multimon only enable one display */
+ if (dev_priv->capabilities & SVGA_CAP_MULTIMON) {
+ vmw_ldu_init(dev_priv, 1);
+ vmw_ldu_init(dev_priv, 2);
+ vmw_ldu_init(dev_priv, 3);
+ vmw_ldu_init(dev_priv, 4);
+ vmw_ldu_init(dev_priv, 5);
+ vmw_ldu_init(dev_priv, 6);
+ vmw_ldu_init(dev_priv, 7);
+ }
return 0;
}
@@ -514,3 +578,42 @@ int vmw_kms_close_legacy_display_system(struct vmw_private *dev_priv)
return 0;
}
+
+int vmw_kms_ldu_update_layout(struct vmw_private *dev_priv, unsigned num,
+ struct drm_vmw_rect *rects)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct vmw_legacy_display_unit *ldu;
+ struct drm_connector *con;
+ int i;
+
+ mutex_lock(&dev->mode_config.mutex);
+
+#if 0
+ DRM_INFO("%s: new layout ", __func__);
+ for (i = 0; i < (int)num; i++)
+ DRM_INFO("(%i, %i %ux%u) ", rects[i].x, rects[i].y,
+ rects[i].w, rects[i].h);
+ DRM_INFO("\n");
+#else
+ (void)i;
+#endif
+
+ list_for_each_entry(con, &dev->mode_config.connector_list, head) {
+ ldu = vmw_connector_to_ldu(con);
+ if (num > ldu->base.unit) {
+ ldu->pref_width = rects[ldu->base.unit].w;
+ ldu->pref_height = rects[ldu->base.unit].h;
+ ldu->pref_active = true;
+ } else {
+ ldu->pref_width = 800;
+ ldu->pref_height = 600;
+ ldu->pref_active = false;
+ }
+ con->status = vmw_ldu_connector_detect(con);
+ }
+
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
index ad566c85b075..df2036ed18d5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_overlay.c
@@ -358,6 +358,8 @@ static int vmw_overlay_update_stream(struct vmw_private *dev_priv,
if (stream->buf != buf)
stream->buf = vmw_dmabuf_reference(buf);
stream->saved = *arg;
+ /* stream is no longer stopped/paused */
+ stream->paused = false;
return 0;
}
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 441e38c95a85..b87569e96b16 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -1,12 +1,32 @@
/*
- * vgaarb.c
+ * vgaarb.c: Implements the VGA arbitration. For details refer to
+ * Documentation/vgaarbiter.txt
+ *
*
* (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com>
* (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org>
*
- * Implements the VGA arbitration. For details refer to
- * Documentation/vgaarbiter.txt
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS
+ * IN THE SOFTWARE.
+ *
*/
#include <linux/module.h>
@@ -155,8 +175,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
(vgadev->decodes & VGA_RSRC_LEGACY_MEM))
rsrc |= VGA_RSRC_LEGACY_MEM;
- pr_devel("%s: %d\n", __func__, rsrc);
- pr_devel("%s: owns: %d\n", __func__, vgadev->owns);
+ pr_debug("%s: %d\n", __func__, rsrc);
+ pr_debug("%s: owns: %d\n", __func__, vgadev->owns);
/* Check what resources we need to acquire */
wants = rsrc & ~vgadev->owns;
@@ -268,7 +288,7 @@ static void __vga_put(struct vga_device *vgadev, unsigned int rsrc)
{
unsigned int old_locks = vgadev->locks;
- pr_devel("%s\n", __func__);
+ pr_debug("%s\n", __func__);
/* Update our counters, and account for equivalent legacy resources
* if we decode them
@@ -575,6 +595,7 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
else
vga_decode_count--;
}
+ pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count);
}
void __vga_set_legacy_decoding(struct pci_dev *pdev, unsigned int decodes, bool userspace)
@@ -831,7 +852,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
curr_pos += 5;
remaining -= 5;
- pr_devel("client 0x%p called 'lock'\n", priv);
+ pr_debug("client 0x%p called 'lock'\n", priv);
if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) {
ret_val = -EPROTO;
@@ -867,7 +888,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
curr_pos += 7;
remaining -= 7;
- pr_devel("client 0x%p called 'unlock'\n", priv);
+ pr_debug("client 0x%p called 'unlock'\n", priv);
if (strncmp(curr_pos, "all", 3) == 0)
io_state = VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM;
@@ -917,7 +938,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
curr_pos += 8;
remaining -= 8;
- pr_devel("client 0x%p called 'trylock'\n", priv);
+ pr_debug("client 0x%p called 'trylock'\n", priv);
if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) {
ret_val = -EPROTO;
@@ -961,7 +982,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
curr_pos += 7;
remaining -= 7;
- pr_devel("client 0x%p called 'target'\n", priv);
+ pr_debug("client 0x%p called 'target'\n", priv);
/* if target is default */
if (!strncmp(curr_pos, "default", 7))
pdev = pci_dev_get(vga_default_device());
@@ -971,11 +992,11 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
ret_val = -EPROTO;
goto done;
}
- pr_devel("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos,
+ pr_debug("vgaarb: %s ==> %x:%x:%x.%x\n", curr_pos,
domain, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
pbus = pci_find_bus(domain, bus);
- pr_devel("vgaarb: pbus %p\n", pbus);
+ pr_debug("vgaarb: pbus %p\n", pbus);
if (pbus == NULL) {
pr_err("vgaarb: invalid PCI domain and/or bus address %x:%x\n",
domain, bus);
@@ -983,7 +1004,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
goto done;
}
pdev = pci_get_slot(pbus, devfn);
- pr_devel("vgaarb: pdev %p\n", pdev);
+ pr_debug("vgaarb: pdev %p\n", pdev);
if (!pdev) {
pr_err("vgaarb: invalid PCI address %x:%x\n",
bus, devfn);
@@ -993,7 +1014,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
}
vgadev = vgadev_find(pdev);
- pr_devel("vgaarb: vgadev %p\n", vgadev);
+ pr_debug("vgaarb: vgadev %p\n", vgadev);
if (vgadev == NULL) {
pr_err("vgaarb: this pci device is not a vga device\n");
pci_dev_put(pdev);
@@ -1029,7 +1050,7 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf,
} else if (strncmp(curr_pos, "decodes ", 8) == 0) {
curr_pos += 8;
remaining -= 8;
- pr_devel("vgaarb: client 0x%p called 'decodes'\n", priv);
+ pr_debug("vgaarb: client 0x%p called 'decodes'\n", priv);
if (!vga_str_to_iostate(curr_pos, remaining, &io_state)) {
ret_val = -EPROTO;
@@ -1058,7 +1079,7 @@ static unsigned int vga_arb_fpoll(struct file *file, poll_table * wait)
{
struct vga_arb_private *priv = file->private_data;
- pr_devel("%s\n", __func__);
+ pr_debug("%s\n", __func__);
if (priv == NULL)
return -ENODEV;
@@ -1071,7 +1092,7 @@ static int vga_arb_open(struct inode *inode, struct file *file)
struct vga_arb_private *priv;
unsigned long flags;
- pr_devel("%s\n", __func__);
+ pr_debug("%s\n", __func__);
priv = kmalloc(sizeof(struct vga_arb_private), GFP_KERNEL);
if (priv == NULL)
@@ -1101,7 +1122,7 @@ static int vga_arb_release(struct inode *inode, struct file *file)
unsigned long flags;
int i;
- pr_devel("%s\n", __func__);
+ pr_debug("%s\n", __func__);
if (priv == NULL)
return -ENODEV;
@@ -1112,7 +1133,7 @@ static int vga_arb_release(struct inode *inode, struct file *file)
uc = &priv->cards[i];
if (uc->pdev == NULL)
continue;
- pr_devel("uc->io_cnt == %d, uc->mem_cnt == %d\n",
+ pr_debug("uc->io_cnt == %d, uc->mem_cnt == %d\n",
uc->io_cnt, uc->mem_cnt);
while (uc->io_cnt--)
vga_put(uc->pdev, VGA_RSRC_LEGACY_IO);
@@ -1165,7 +1186,7 @@ static int pci_notify(struct notifier_block *nb, unsigned long action,
struct pci_dev *pdev = to_pci_dev(dev);
bool notify = false;
- pr_devel("%s\n", __func__);
+ pr_debug("%s\n", __func__);
/* For now we're only intereted in devices added and removed. I didn't
* test this thing here, so someone needs to double check for the
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 132278fa6240..434099369058 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -358,6 +358,7 @@ config HID_ROCCAT
config HID_ROCCAT_KONE
tristate "Roccat Kone Mouse support"
depends on USB_HID
+ select HID_ROCCAT
---help---
Support for Roccat Kone mouse.
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index aa0f7dcabcd7..4959d96cd174 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1337,6 +1337,15 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
@@ -1760,7 +1769,8 @@ int hid_add_device(struct hid_device *hdev)
/* we need to kill them here, otherwise they will stay allocated to
* wait for coming driver */
- if (!(hdev->quirks & HID_QUIRK_NO_IGNORE) && hid_ignore(hdev))
+ if (!(hdev->quirks & HID_QUIRK_NO_IGNORE)
+ && (hid_ignore(hdev) || (hdev->quirks & HID_QUIRK_IGNORE)))
return -ENODEV;
/* XXX hack, any other cleaner solution after the driver core
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 6af77ed0b555..5c42ffe55d4a 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -34,7 +34,7 @@
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
#define USB_DEVICE_ID_ACECAD_302 0x0008
-#define USB_VENDOR_ID_ADS_TECH 0x06e1
+#define USB_VENDOR_ID_ADS_TECH 0x06e1
#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
#define USB_VENDOR_ID_AFATECH 0x15a4
@@ -198,7 +198,7 @@
#define USB_VENDOR_ID_ETT 0x0664
#define USB_DEVICE_ID_TC5UH 0x0309
-#define USB_VENDOR_ID_EZKEY 0x0518
+#define USB_VENDOR_ID_EZKEY 0x0518
#define USB_DEVICE_ID_BTC_8193 0x0002
#define USB_VENDOR_ID_GAMERON 0x0810
@@ -390,7 +390,16 @@
#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003
#define USB_VENDOR_ID_NTRIG 0x1b96
-#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0002
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0003
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3 0x0004
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4 0x0005
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5 0x0006
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6 0x0007
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7 0x0008
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8 0x0009
+#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9 0x000A
#define USB_VENDOR_ID_ONTRAK 0x0a07
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index f10d56a15f21..4c4a79c760a2 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -30,6 +30,10 @@ static bool emulate_scroll_wheel = true;
module_param(emulate_scroll_wheel, bool, 0644);
MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel");
+static bool scroll_acceleration = false;
+module_param(scroll_acceleration, bool, 0644);
+MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events");
+
static bool report_touches = true;
module_param(report_touches, bool, 0644);
MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)");
@@ -160,10 +164,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
msc->touches[id].size = misc & 63;
/* If requested, emulate a scroll wheel by detecting small
- * vertical touch motions along the middle of the mouse.
+ * vertical touch motions.
*/
- if (emulate_scroll_wheel &&
- middle_button_start < x && x < middle_button_stop) {
+ if (emulate_scroll_wheel) {
static const int accel_profile[] = {
256, 228, 192, 160, 128, 96, 64, 32,
};
@@ -178,7 +181,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
switch (tdata[7] & TOUCH_STATE_MASK) {
case TOUCH_STATE_START:
msc->touches[id].scroll_y = y;
- msc->scroll_accel = min_t(int, msc->scroll_accel + 1,
+ if (scroll_acceleration)
+ msc->scroll_accel = min_t(int,
+ msc->scroll_accel + 1,
ARRAY_SIZE(accel_profile) - 1);
break;
case TOUCH_STATE_DRAG:
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index 17f2dc04f883..0ab1df9d68ab 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -22,11 +22,6 @@
* Is it possible to remove and reinstall the urb in raw-event- or any
* other handler, or to defer this action to be executed somewhere else?
*
- * TODO implement notification mechanism for overlong macro execution
- * If user wants to execute an overlong macro only the names of macroset
- * and macro are given. Should userland tap hidraw or is there an
- * additional streaming mechanism?
- *
* TODO is it possible to overwrite group for sysfs attributes via udev?
*/
@@ -626,12 +621,12 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
* This file is used by userland software to find devices that are handled by
* this driver. This provides a consistent way for actual and older kernels
* where this driver replaced usbhid instead of generic-usb.
- * Driver capabilities are determined by version number.
+ * Driver capabilities are determined by returned number.
*/
-static ssize_t kone_sysfs_show_driver_version(struct device *dev,
+static ssize_t kone_sysfs_show_abi_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n");
+ return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_ABI_VERSION "\n");
}
/*
@@ -671,8 +666,8 @@ static DEVICE_ATTR(startup_profile, 0660,
kone_sysfs_show_startup_profile,
kone_sysfs_set_startup_profile);
-static DEVICE_ATTR(kone_driver_version, 0440,
- kone_sysfs_show_driver_version, NULL);
+static DEVICE_ATTR(kone_abi_version, 0440,
+ kone_sysfs_show_abi_version, NULL);
static struct attribute *kone_attributes[] = {
&dev_attr_actual_dpi.attr,
@@ -681,7 +676,7 @@ static struct attribute *kone_attributes[] = {
&dev_attr_firmware_version.attr,
&dev_attr_tcu.attr,
&dev_attr_startup_profile.attr,
- &dev_attr_kone_driver_version.attr,
+ &dev_attr_kone_abi_version.attr,
NULL
};
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 003e6f81c195..71b14fa40dce 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -14,7 +14,7 @@
#include <linux/types.h>
-#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1"
+#define ROCCAT_KONE_ABI_VERSION "1"
#pragma pack(push)
#pragma pack(1)
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index e05d48edb66f..f6e80c7ca61e 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -168,7 +168,7 @@ static int roccat_open(struct inode *inode, struct file *file)
printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
minor);
error = -ENODEV;
- goto exit_unlock;
+ goto exit_err;
}
if (!device->open++) {
@@ -178,7 +178,7 @@ static int roccat_open(struct inode *inode, struct file *file)
PM_HINT_FULLON);
if (error < 0) {
--device->open;
- goto exit_unlock;
+ goto exit_err;
}
}
error = device->hid->ll_driver->open(device->hid);
@@ -187,7 +187,7 @@ static int roccat_open(struct inode *inode, struct file *file)
device->hid->ll_driver->power(device->hid,
PM_HINT_NORMAL);
--device->open;
- goto exit_unlock;
+ goto exit_err;
}
}
@@ -202,6 +202,9 @@ exit_unlock:
mutex_unlock(&device->readers_lock);
mutex_unlock(&devices_lock);
return error;
+exit_err:
+ kfree(reader);
+ goto exit_unlock;
}
static int roccat_release(struct inode *inode, struct file *file)
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
index d8aae0c1fa7e..09e864e9f79d 100644
--- a/drivers/hid/hid-roccat.h
+++ b/drivers/hid/hid-roccat.h
@@ -15,7 +15,7 @@
#include <linux/hid.h>
#include <linux/types.h>
-#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE)
+#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE)
int roccat_connect(struct hid_device *hid);
void roccat_disconnect(int minor);
int roccat_report_event(int minor, u8 const *data, int len);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 3ccd47850677..47d70c523d93 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -46,7 +46,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
{
struct hidraw_list *list = file->private_data;
int ret = 0, len;
- char *report;
DECLARE_WAITQUEUE(wait, current);
mutex_lock(&list->read_mutex);
@@ -84,7 +83,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
if (ret)
goto out;
- report = list->buffer[list->tail].value;
len = list->buffer[list->tail].len > count ?
count : list->buffer[list->tail].len;
diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c
index 4086c7257f91..f13c843a2964 100644
--- a/drivers/hwmon/adt7411.c
+++ b/drivers/hwmon/adt7411.c
@@ -316,7 +316,6 @@ static int __devinit adt7411_probe(struct i2c_client *client,
exit_remove:
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
exit_free:
- i2c_set_clientdata(client, NULL);
kfree(data);
return ret;
}
@@ -327,7 +326,6 @@ static int __devexit adt7411_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/asc7621.c b/drivers/hwmon/asc7621.c
index 0f388adc6187..3b973f30b1f6 100644
--- a/drivers/hwmon/asc7621.c
+++ b/drivers/hwmon/asc7621.c
@@ -1141,7 +1141,6 @@ exit_remove:
&(asc7621_params[i].sda.dev_attr));
}
- i2c_set_clientdata(client, NULL);
kfree(data);
return err;
}
@@ -1196,7 +1195,6 @@ static int asc7621_remove(struct i2c_client *client)
&(asc7621_params[i].sda.dev_attr));
}
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/emc1403.c b/drivers/hwmon/emc1403.c
index 0e4b5642638d..5b58b20dead1 100644
--- a/drivers/hwmon/emc1403.c
+++ b/drivers/hwmon/emc1403.c
@@ -89,6 +89,35 @@ static ssize_t store_temp(struct device *dev,
return count;
}
+static ssize_t store_bit(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct thermal_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute_2 *sda = to_sensor_dev_attr_2(attr);
+ unsigned long val;
+ int retval;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+ retval = i2c_smbus_read_byte_data(client, sda->nr);
+ if (retval < 0)
+ goto fail;
+
+ retval &= ~sda->index;
+ if (val)
+ retval |= sda->index;
+
+ retval = i2c_smbus_write_byte_data(client, sda->index, retval);
+ if (retval == 0)
+ retval = count;
+fail:
+ mutex_unlock(&data->mutex);
+ return retval;
+}
+
static ssize_t show_hyst(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -200,6 +229,9 @@ static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO,
static SENSOR_DEVICE_ATTR(temp3_crit_hyst, S_IRUGO | S_IWUSR,
show_hyst, store_hyst, 0x1A);
+static SENSOR_DEVICE_ATTR_2(power_state, S_IRUGO | S_IWUSR,
+ show_bit, store_bit, 0x03, 0x40);
+
static struct attribute *mid_att_thermal[] = {
&sensor_dev_attr_temp1_min.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
@@ -225,6 +257,7 @@ static struct attribute *mid_att_thermal[] = {
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_power_state.dev_attr.attr,
NULL
};
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index bad2cf3ef4a4..0f58ecc5334d 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -662,7 +662,6 @@ exit_remove:
sysfs_remove_group(&client->dev.kobj, &f75375_group);
exit_free:
kfree(data);
- i2c_set_clientdata(client, NULL);
return err;
}
@@ -672,7 +671,6 @@ static int f75375_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &f75375_group);
kfree(data);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c
index 09ea12e0a551..1f63d1a3af5e 100644
--- a/drivers/hwmon/g760a.c
+++ b/drivers/hwmon/g760a.c
@@ -236,7 +236,6 @@ error_hwmon_device_register:
sysfs_remove_group(&client->dev.kobj, &g760a_group);
error_sysfs_create_group:
kfree(data);
- i2c_set_clientdata(client, NULL);
return err;
}
@@ -247,7 +246,6 @@ static int g760a_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &g760a_group);
kfree(data);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c
index 099a2138cdf6..da5a2404cd3e 100644
--- a/drivers/hwmon/k10temp.c
+++ b/drivers/hwmon/k10temp.c
@@ -112,11 +112,21 @@ static bool __devinit has_erratum_319(struct pci_dev *pdev)
if (pkg_type != CPUID_PKGTYPE_AM2R2_AM3)
return false;
- /* Differentiate between AM2+ (bad) and AM3 (good) */
+ /* DDR3 memory implies socket AM3, which is good */
pci_bus_read_config_dword(pdev->bus,
PCI_DEVFN(PCI_SLOT(pdev->devfn), 2),
REG_DCT0_CONFIG_HIGH, &reg_dram_cfg);
- return !(reg_dram_cfg & DDR3_MODE);
+ if (reg_dram_cfg & DDR3_MODE)
+ return false;
+
+ /*
+ * Unfortunately it is possible to run a socket AM3 CPU with DDR2
+ * memory. We blacklist all the cores which do exist in socket AM2+
+ * format. It still isn't perfect, as RB-C2 cores exist in both AM2+
+ * and AM3 formats, but that's the best we can do.
+ */
+ return boot_cpu_data.x86_model < 4 ||
+ (boot_cpu_data.x86_model == 4 && boot_cpu_data.x86_mask <= 2);
}
static int __devinit k10temp_probe(struct pci_dev *pdev,
diff --git a/drivers/hwmon/lm73.c b/drivers/hwmon/lm73.c
index 4d1b76bc8148..29b9030d42c3 100644
--- a/drivers/hwmon/lm73.c
+++ b/drivers/hwmon/lm73.c
@@ -136,7 +136,6 @@ static int lm73_remove(struct i2c_client *client)
hwmon_device_unregister(hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm73_group);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 56463428a419..ab5b87a81677 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -192,7 +192,6 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
exit_remove:
sysfs_remove_group(&client->dev.kobj, &lm75_group);
exit_free:
- i2c_set_clientdata(client, NULL);
kfree(data);
return status;
}
@@ -204,7 +203,6 @@ static int lm75_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm75_group);
lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}
@@ -282,10 +280,49 @@ static int lm75_detect(struct i2c_client *new_client,
return 0;
}
+#ifdef CONFIG_PM
+static int lm75_suspend(struct device *dev)
+{
+ int status;
+ struct i2c_client *client = to_i2c_client(dev);
+ status = lm75_read_value(client, LM75_REG_CONF);
+ if (status < 0) {
+ dev_dbg(&client->dev, "Can't read config? %d\n", status);
+ return status;
+ }
+ status = status | LM75_SHUTDOWN;
+ lm75_write_value(client, LM75_REG_CONF, status);
+ return 0;
+}
+
+static int lm75_resume(struct device *dev)
+{
+ int status;
+ struct i2c_client *client = to_i2c_client(dev);
+ status = lm75_read_value(client, LM75_REG_CONF);
+ if (status < 0) {
+ dev_dbg(&client->dev, "Can't read config? %d\n", status);
+ return status;
+ }
+ status = status & ~LM75_SHUTDOWN;
+ lm75_write_value(client, LM75_REG_CONF, status);
+ return 0;
+}
+
+static const struct dev_pm_ops lm75_dev_pm_ops = {
+ .suspend = lm75_suspend,
+ .resume = lm75_resume,
+};
+#define LM75_DEV_PM_OPS (&lm75_dev_pm_ops)
+#else
+#define LM75_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
static struct i2c_driver lm75_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
.name = "lm75",
+ .pm = LM75_DEV_PM_OPS,
},
.probe = lm75_probe,
.remove = lm75_remove,
diff --git a/drivers/hwmon/lm75.h b/drivers/hwmon/lm75.h
index 7c93454bb4e3..e547a3eb4de3 100644
--- a/drivers/hwmon/lm75.h
+++ b/drivers/hwmon/lm75.h
@@ -30,6 +30,7 @@
/* straight from the datasheet */
#define LM75_TEMP_MIN (-55000)
#define LM75_TEMP_MAX 125000
+#define LM75_SHUTDOWN 0x01
/* TEMP: 0.001C/bit (-55C to +125C)
REG: (0.5C/bit, two's complement) << 7 */
diff --git a/drivers/hwmon/lm95241.c b/drivers/hwmon/lm95241.c
index 8fc8eb8cba47..94741d42112d 100644
--- a/drivers/hwmon/lm95241.c
+++ b/drivers/hwmon/lm95241.c
@@ -399,7 +399,6 @@ static int lm95241_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &lm95241_group);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
}
diff --git a/drivers/hwmon/ltc4245.c b/drivers/hwmon/ltc4245.c
index 21d201befc2c..659308329308 100644
--- a/drivers/hwmon/ltc4245.c
+++ b/drivers/hwmon/ltc4245.c
@@ -21,6 +21,7 @@
#include <linux/i2c.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/i2c/ltc4245.h>
/* Here are names of the chip's registers (a.k.a. commands) */
enum ltc4245_cmd {
@@ -60,8 +61,72 @@ struct ltc4245_data {
/* Voltage registers */
u8 vregs[0x0d];
+
+ /* GPIO ADC registers */
+ bool use_extra_gpios;
+ int gpios[3];
};
+/*
+ * Update the readings from the GPIO pins. If the driver has been configured to
+ * sample all GPIO's as analog voltages, a round-robin sampling method is used.
+ * Otherwise, only the configured GPIO pin is sampled.
+ *
+ * LOCKING: must hold data->update_lock
+ */
+static void ltc4245_update_gpios(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc4245_data *data = i2c_get_clientdata(client);
+ u8 gpio_curr, gpio_next, gpio_reg;
+ int i;
+
+ /* no extra gpio support, we're basically done */
+ if (!data->use_extra_gpios) {
+ data->gpios[0] = data->vregs[LTC4245_GPIOADC - 0x10];
+ return;
+ }
+
+ /*
+ * If the last reading was too long ago, then we mark all old GPIO
+ * readings as stale by setting them to -EAGAIN
+ */
+ if (time_after(jiffies, data->last_updated + 5 * HZ)) {
+ dev_dbg(&client->dev, "Marking GPIOs invalid\n");
+ for (i = 0; i < ARRAY_SIZE(data->gpios); i++)
+ data->gpios[i] = -EAGAIN;
+ }
+
+ /*
+ * Get the current GPIO pin
+ *
+ * The datasheet calls these GPIO[1-3], but we'll calculate the zero
+ * based array index instead, and call them GPIO[0-2]. This is much
+ * easier to think about.
+ */
+ gpio_curr = (data->cregs[LTC4245_GPIO] & 0xc0) >> 6;
+ if (gpio_curr > 0)
+ gpio_curr -= 1;
+
+ /* Read the GPIO voltage from the GPIOADC register */
+ data->gpios[gpio_curr] = data->vregs[LTC4245_GPIOADC - 0x10];
+
+ /* Find the next GPIO pin to read */
+ gpio_next = (gpio_curr + 1) % ARRAY_SIZE(data->gpios);
+
+ /*
+ * Calculate the correct setting for the GPIO register so it will
+ * sample the next GPIO pin
+ */
+ gpio_reg = (data->cregs[LTC4245_GPIO] & 0x3f) | ((gpio_next + 1) << 6);
+
+ /* Update the GPIO register */
+ i2c_smbus_write_byte_data(client, LTC4245_GPIO, gpio_reg);
+
+ /* Update saved data */
+ data->cregs[LTC4245_GPIO] = gpio_reg;
+}
+
static struct ltc4245_data *ltc4245_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -93,6 +158,9 @@ static struct ltc4245_data *ltc4245_update_device(struct device *dev)
data->vregs[i] = val;
}
+ /* Update GPIO readings */
+ ltc4245_update_gpios(dev);
+
data->last_updated = jiffies;
data->valid = 1;
}
@@ -233,6 +301,22 @@ static ssize_t ltc4245_show_alarm(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", (reg & mask) ? 1 : 0);
}
+static ssize_t ltc4245_show_gpio(struct device *dev,
+ struct device_attribute *da,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+ struct ltc4245_data *data = ltc4245_update_device(dev);
+ int val = data->gpios[attr->index];
+
+ /* handle stale GPIO's */
+ if (val < 0)
+ return val;
+
+ /* Convert to millivolts and print */
+ return snprintf(buf, PAGE_SIZE, "%u\n", val * 10);
+}
+
/* These macros are used below in constructing device attribute objects
* for use with sysfs_create_group() to make a sysfs device file
* for each register.
@@ -254,6 +338,10 @@ static ssize_t ltc4245_show_alarm(struct device *dev,
static SENSOR_DEVICE_ATTR_2(name, S_IRUGO, \
ltc4245_show_alarm, NULL, (mask), reg)
+#define LTC4245_GPIO_VOLTAGE(name, gpio_num) \
+ static SENSOR_DEVICE_ATTR(name, S_IRUGO, \
+ ltc4245_show_gpio, NULL, gpio_num)
+
/* Construct a sensor_device_attribute structure for each register */
/* Input voltages */
@@ -293,7 +381,9 @@ LTC4245_ALARM(in7_min_alarm, (1 << 2), LTC4245_FAULT2);
LTC4245_ALARM(in8_min_alarm, (1 << 3), LTC4245_FAULT2);
/* GPIO voltages */
-LTC4245_VOLTAGE(in9_input, LTC4245_GPIOADC);
+LTC4245_GPIO_VOLTAGE(in9_input, 0);
+LTC4245_GPIO_VOLTAGE(in10_input, 1);
+LTC4245_GPIO_VOLTAGE(in11_input, 2);
/* Power Consumption (virtual) */
LTC4245_POWER(power1_input, LTC4245_12VSENSE);
@@ -304,7 +394,7 @@ LTC4245_POWER(power4_input, LTC4245_VEESENSE);
/* Finally, construct an array of pointers to members of the above objects,
* as required for sysfs_create_group()
*/
-static struct attribute *ltc4245_attributes[] = {
+static struct attribute *ltc4245_std_attributes[] = {
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_in2_input.dev_attr.attr,
&sensor_dev_attr_in3_input.dev_attr.attr,
@@ -345,10 +435,77 @@ static struct attribute *ltc4245_attributes[] = {
NULL,
};
-static const struct attribute_group ltc4245_group = {
- .attrs = ltc4245_attributes,
+static struct attribute *ltc4245_gpio_attributes[] = {
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ltc4245_std_group = {
+ .attrs = ltc4245_std_attributes,
+};
+
+static const struct attribute_group ltc4245_gpio_group = {
+ .attrs = ltc4245_gpio_attributes,
};
+static int ltc4245_sysfs_create_groups(struct i2c_client *client)
+{
+ struct ltc4245_data *data = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+ int ret;
+
+ /* register the standard sysfs attributes */
+ ret = sysfs_create_group(&dev->kobj, &ltc4245_std_group);
+ if (ret) {
+ dev_err(dev, "unable to register standard attributes\n");
+ return ret;
+ }
+
+ /* if we're using the extra gpio support, register it's attributes */
+ if (data->use_extra_gpios) {
+ ret = sysfs_create_group(&dev->kobj, &ltc4245_gpio_group);
+ if (ret) {
+ dev_err(dev, "unable to register gpio attributes\n");
+ sysfs_remove_group(&dev->kobj, &ltc4245_std_group);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void ltc4245_sysfs_remove_groups(struct i2c_client *client)
+{
+ struct ltc4245_data *data = i2c_get_clientdata(client);
+ struct device *dev = &client->dev;
+
+ if (data->use_extra_gpios)
+ sysfs_remove_group(&dev->kobj, &ltc4245_gpio_group);
+
+ sysfs_remove_group(&dev->kobj, &ltc4245_std_group);
+}
+
+static bool ltc4245_use_extra_gpios(struct i2c_client *client)
+{
+ struct ltc4245_platform_data *pdata = dev_get_platdata(&client->dev);
+#ifdef CONFIG_OF
+ struct device_node *np = client->dev.of_node;
+#endif
+
+ /* prefer platform data */
+ if (pdata)
+ return pdata->use_extra_gpios;
+
+#ifdef CONFIG_OF
+ /* fallback on OF */
+ if (of_find_property(np, "ltc4245,use-extra-gpios", NULL))
+ return true;
+#endif
+
+ return false;
+}
+
static int ltc4245_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -367,15 +524,16 @@ static int ltc4245_probe(struct i2c_client *client,
i2c_set_clientdata(client, data);
mutex_init(&data->update_lock);
+ data->use_extra_gpios = ltc4245_use_extra_gpios(client);
/* Initialize the LTC4245 chip */
i2c_smbus_write_byte_data(client, LTC4245_FAULT1, 0x00);
i2c_smbus_write_byte_data(client, LTC4245_FAULT2, 0x00);
/* Register sysfs hooks */
- ret = sysfs_create_group(&client->dev.kobj, &ltc4245_group);
+ ret = ltc4245_sysfs_create_groups(client);
if (ret)
- goto out_sysfs_create_group;
+ goto out_sysfs_create_groups;
data->hwmon_dev = hwmon_device_register(&client->dev);
if (IS_ERR(data->hwmon_dev)) {
@@ -386,8 +544,8 @@ static int ltc4245_probe(struct i2c_client *client,
return 0;
out_hwmon_device_register:
- sysfs_remove_group(&client->dev.kobj, &ltc4245_group);
-out_sysfs_create_group:
+ ltc4245_sysfs_remove_groups(client);
+out_sysfs_create_groups:
kfree(data);
out_kzalloc:
return ret;
@@ -398,8 +556,7 @@ static int ltc4245_remove(struct i2c_client *client)
struct ltc4245_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
- sysfs_remove_group(&client->dev.kobj, &ltc4245_group);
-
+ ltc4245_sysfs_remove_groups(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 8013895a1faf..93187c3cb5e7 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -224,7 +224,6 @@ fail_remove_sysfs:
fail_restore_config:
tmp102_write_reg(client, TMP102_CONF_REG, tmp102->config_orig);
fail_free:
- i2c_set_clientdata(client, NULL);
kfree(tmp102);
return status;
@@ -247,7 +246,6 @@ static int __devexit tmp102_remove(struct i2c_client *client)
config | TMP102_CONF_SD);
}
- i2c_set_clientdata(client, NULL);
kfree(tmp102);
return 0;
diff --git a/drivers/hwmon/tmp421.c b/drivers/hwmon/tmp421.c
index 738c472ece27..6b4165c12092 100644
--- a/drivers/hwmon/tmp421.c
+++ b/drivers/hwmon/tmp421.c
@@ -295,7 +295,6 @@ exit_remove:
sysfs_remove_group(&client->dev.kobj, &tmp421_group);
exit_free:
- i2c_set_clientdata(client, NULL);
kfree(data);
return err;
@@ -308,7 +307,6 @@ static int tmp421_remove(struct i2c_client *client)
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &tmp421_group);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 32d4adee73db..c84b9b4e6960 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -1197,7 +1197,6 @@ ERROR4:
if (data->lm75[1])
i2c_unregister_device(data->lm75[1]);
ERROR3:
- i2c_set_clientdata(client, NULL);
kfree(data);
ERROR1:
return err;
@@ -1219,7 +1218,6 @@ w83781d_remove(struct i2c_client *client)
if (data->lm75[1])
i2c_unregister_device(data->lm75[1]);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 87ab0568bb0e..29e01f6238a7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -475,6 +475,26 @@ config I2C_PASEMI
help
Supports the PA Semi PWRficient on-chip SMBus interfaces.
+config I2C_PCA_PLATFORM
+ tristate "PCA9564/PCA9665 as platform device"
+ select I2C_ALGOPCA
+ default n
+ help
+ This driver supports a memory mapped Philips PCA9564/PCA9665
+ parallel bus to I2C bus controller.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-pca-platform.
+
+config I2C_PMCMSP
+ tristate "PMC MSP I2C TWI Controller"
+ depends on PMC_MSP
+ help
+ This driver supports the PMC TWI controller on MSP devices.
+
+ This driver can also be built as module. If so, the module
+ will be called i2c-pmcmsp.
+
config I2C_PNX
tristate "I2C bus support for Philips PNX targets"
depends on ARCH_PNX4008
@@ -529,7 +549,7 @@ config I2C_SH7760
config I2C_SH_MOBILE
tristate "SuperH Mobile I2C Controller"
- depends on SUPERH
+ depends on SUPERH || ARCH_SHMOBILE
help
If you say yes to this option, support will be included for the
built-in I2C interface on the Renesas SH-Mobile processor.
@@ -711,26 +731,6 @@ config I2C_PCA_ISA
delays when I2C/SMBus chip drivers are loaded (e.g. at boot
time). If unsure, say N.
-config I2C_PCA_PLATFORM
- tristate "PCA9564/PCA9665 as platform device"
- select I2C_ALGOPCA
- default n
- help
- This driver supports a memory mapped Philips PCA9564/PCA9665
- parallel bus to I2C bus controller.
-
- This driver can also be built as a module. If so, the module
- will be called i2c-pca-platform.
-
-config I2C_PMCMSP
- tristate "PMC MSP I2C TWI Controller"
- depends on PMC_MSP
- help
- This driver supports the PMC TWI controller on MSP devices.
-
- This driver can also be built as module. If so, the module
- will be called i2c-pmcmsp.
-
config I2C_SIBYTE
tristate "SiByte SMBus interface"
depends on SIBYTE_SB1xxx_SOC
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 097236f631e8..936880bd1dc5 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -27,7 +27,7 @@ obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o
obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o
obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
-# Embebbed system I2C/SMBus host controller drivers
+# Embedded system I2C/SMBus host controller drivers
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
@@ -46,6 +46,8 @@ obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o
+obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
+obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
obj-$(CONFIG_I2C_PNX) += i2c-pnx.o
obj-$(CONFIG_I2C_PXA) += i2c-pxa.o
obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o
@@ -68,8 +70,6 @@ obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o
obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
-obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o
-obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index ffb405d7c6f2..598c49acaeb5 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -119,8 +119,10 @@ struct sh_mobile_i2c_data {
struct i2c_adapter adap;
struct clk *clk;
+ u_int8_t icic;
u_int8_t iccl;
u_int8_t icch;
+ u_int8_t flags;
spinlock_t lock;
wait_queue_head_t wait;
@@ -129,15 +131,17 @@ struct sh_mobile_i2c_data {
int sr;
};
+#define IIC_FLAG_HAS_ICIC67 (1 << 0)
+
#define NORMAL_SPEED 100000 /* FAST_SPEED 400000 */
/* Register offsets */
-#define ICDR(pd) (pd->reg + 0x00)
-#define ICCR(pd) (pd->reg + 0x04)
-#define ICSR(pd) (pd->reg + 0x08)
-#define ICIC(pd) (pd->reg + 0x0c)
-#define ICCL(pd) (pd->reg + 0x10)
-#define ICCH(pd) (pd->reg + 0x14)
+#define ICDR 0x00
+#define ICCR 0x04
+#define ICSR 0x08
+#define ICIC 0x0c
+#define ICCL 0x10
+#define ICCH 0x14
/* Register bits */
#define ICCR_ICE 0x80
@@ -155,11 +159,32 @@ struct sh_mobile_i2c_data {
#define ICSR_WAIT 0x02
#define ICSR_DTE 0x01
+#define ICIC_ICCLB8 0x80
+#define ICIC_ICCHB8 0x40
#define ICIC_ALE 0x08
#define ICIC_TACKE 0x04
#define ICIC_WAITE 0x02
#define ICIC_DTEE 0x01
+static void iic_wr(struct sh_mobile_i2c_data *pd, int offs, unsigned char data)
+{
+ if (offs == ICIC)
+ data |= pd->icic;
+
+ iowrite8(data, pd->reg + offs);
+}
+
+static unsigned char iic_rd(struct sh_mobile_i2c_data *pd, int offs)
+{
+ return ioread8(pd->reg + offs);
+}
+
+static void iic_set_clr(struct sh_mobile_i2c_data *pd, int offs,
+ unsigned char set, unsigned char clr)
+{
+ iic_wr(pd, offs, (iic_rd(pd, offs) | set) & ~clr);
+}
+
static void activate_ch(struct sh_mobile_i2c_data *pd)
{
unsigned long i2c_clk;
@@ -187,6 +212,14 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
else
pd->iccl = (u_int8_t)(num/denom);
+ /* one more bit of ICCL in ICIC */
+ if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+ if ((num/denom) > 0xff)
+ pd->icic |= ICIC_ICCLB8;
+ else
+ pd->icic &= ~ICIC_ICCLB8;
+ }
+
/* Calculate the value for icch. From the data sheet:
icch = (p clock / transfer rate) * (H / (L + H)) */
num = i2c_clk * 4;
@@ -196,25 +229,33 @@ static void activate_ch(struct sh_mobile_i2c_data *pd)
else
pd->icch = (u_int8_t)(num/denom);
+ /* one more bit of ICCH in ICIC */
+ if (pd->flags & IIC_FLAG_HAS_ICIC67) {
+ if ((num/denom) > 0xff)
+ pd->icic |= ICIC_ICCHB8;
+ else
+ pd->icic &= ~ICIC_ICCHB8;
+ }
+
/* Enable channel and configure rx ack */
- iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
+ iic_set_clr(pd, ICCR, ICCR_ICE, 0);
/* Mask all interrupts */
- iowrite8(0, ICIC(pd));
+ iic_wr(pd, ICIC, 0);
/* Set the clock */
- iowrite8(pd->iccl, ICCL(pd));
- iowrite8(pd->icch, ICCH(pd));
+ iic_wr(pd, ICCL, pd->iccl);
+ iic_wr(pd, ICCH, pd->icch);
}
static void deactivate_ch(struct sh_mobile_i2c_data *pd)
{
/* Clear/disable interrupts */
- iowrite8(0, ICSR(pd));
- iowrite8(0, ICIC(pd));
+ iic_wr(pd, ICSR, 0);
+ iic_wr(pd, ICIC, 0);
/* Disable channel */
- iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
+ iic_set_clr(pd, ICCR, 0, ICCR_ICE);
/* Disable clock and mark device as idle */
clk_disable(pd->clk);
@@ -233,35 +274,35 @@ static unsigned char i2c_op(struct sh_mobile_i2c_data *pd,
switch (op) {
case OP_START: /* issue start and trigger DTE interrupt */
- iowrite8(0x94, ICCR(pd));
+ iic_wr(pd, ICCR, 0x94);
break;
case OP_TX_FIRST: /* disable DTE interrupt and write data */
- iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE, ICIC(pd));
- iowrite8(data, ICDR(pd));
+ iic_wr(pd, ICIC, ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICDR, data);
break;
case OP_TX: /* write data */
- iowrite8(data, ICDR(pd));
+ iic_wr(pd, ICDR, data);
break;
case OP_TX_STOP: /* write data and issue a stop afterwards */
- iowrite8(data, ICDR(pd));
- iowrite8(0x90, ICCR(pd));
+ iic_wr(pd, ICDR, data);
+ iic_wr(pd, ICCR, 0x90);
break;
case OP_TX_TO_RX: /* select read mode */
- iowrite8(0x81, ICCR(pd));
+ iic_wr(pd, ICCR, 0x81);
break;
case OP_RX: /* just read data */
- ret = ioread8(ICDR(pd));
+ ret = iic_rd(pd, ICDR);
break;
case OP_RX_STOP: /* enable DTE interrupt, issue stop */
- iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
- ICIC(pd));
- iowrite8(0xc0, ICCR(pd));
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ iic_wr(pd, ICCR, 0xc0);
break;
case OP_RX_STOP_DATA: /* enable DTE interrupt, read data, issue stop */
- iowrite8(ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE,
- ICIC(pd));
- ret = ioread8(ICDR(pd));
- iowrite8(0xc0, ICCR(pd));
+ iic_wr(pd, ICIC,
+ ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
+ ret = iic_rd(pd, ICDR);
+ iic_wr(pd, ICCR, 0xc0);
break;
}
@@ -367,7 +408,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
unsigned char sr;
int wakeup;
- sr = ioread8(ICSR(pd));
+ sr = iic_rd(pd, ICSR);
pd->sr |= sr; /* remember state */
dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr,
@@ -376,7 +417,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
if (sr & (ICSR_AL | ICSR_TACK)) {
/* don't interrupt transaction - continue to issue stop */
- iowrite8(sr & ~(ICSR_AL | ICSR_TACK), ICSR(pd));
+ iic_wr(pd, ICSR, sr & ~(ICSR_AL | ICSR_TACK));
wakeup = 0;
} else if (pd->msg->flags & I2C_M_RD)
wakeup = sh_mobile_i2c_isr_rx(pd);
@@ -384,7 +425,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id)
wakeup = sh_mobile_i2c_isr_tx(pd);
if (sr & ICSR_WAIT) /* TODO: add delay here to support slow acks */
- iowrite8(sr & ~ICSR_WAIT, ICSR(pd));
+ iic_wr(pd, ICSR, sr & ~ICSR_WAIT);
if (wakeup) {
pd->sr |= SW_DONE;
@@ -402,21 +443,21 @@ static int start_ch(struct sh_mobile_i2c_data *pd, struct i2c_msg *usr_msg)
}
/* Initialize channel registers */
- iowrite8(ioread8(ICCR(pd)) & ~ICCR_ICE, ICCR(pd));
+ iic_set_clr(pd, ICCR, 0, ICCR_ICE);
/* Enable channel and configure rx ack */
- iowrite8(ioread8(ICCR(pd)) | ICCR_ICE, ICCR(pd));
+ iic_set_clr(pd, ICCR, ICCR_ICE, 0);
/* Set the clock */
- iowrite8(pd->iccl, ICCL(pd));
- iowrite8(pd->icch, ICCH(pd));
+ iic_wr(pd, ICCL, pd->iccl);
+ iic_wr(pd, ICCH, pd->icch);
pd->msg = usr_msg;
pd->pos = -1;
pd->sr = 0;
/* Enable all interrupts to begin with */
- iowrite8(ICIC_WAITE | ICIC_ALE | ICIC_TACKE | ICIC_DTEE, ICIC(pd));
+ iic_wr(pd, ICIC, ICIC_DTEE | ICIC_WAITE | ICIC_ALE | ICIC_TACKE);
return 0;
}
@@ -451,7 +492,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
retry_count = 1000;
again:
- val = ioread8(ICSR(pd));
+ val = iic_rd(pd, ICSR);
dev_dbg(pd->dev, "val 0x%02x pd->sr 0x%02x\n", val, pd->sr);
@@ -576,6 +617,12 @@ static int sh_mobile_i2c_probe(struct platform_device *dev)
goto err_irq;
}
+ /* The IIC blocks on SH-Mobile ARM processors
+ * come with two new bits in ICIC.
+ */
+ if (size > 0x17)
+ pd->flags |= IIC_FLAG_HAS_ICIC67;
+
/* Enable Runtime PM for this device.
*
* Also tell the Runtime PM core to ignore children
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index e0f833cca3f1..1cca2631e5b3 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -47,7 +47,6 @@ static DEFINE_MUTEX(core_lock);
static DEFINE_IDR(i2c_adapter_idr);
static struct device_type i2c_client_type;
-static int i2c_check_addr(struct i2c_adapter *adapter, int addr);
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
/* ------------------------------------------------------------------------- */
@@ -371,6 +370,59 @@ struct i2c_client *i2c_verify_client(struct device *dev)
EXPORT_SYMBOL(i2c_verify_client);
+/* This is a permissive address validity check, I2C address map constraints
+ * are purposedly not enforced, except for the general call address. */
+static int i2c_check_client_addr_validity(const struct i2c_client *client)
+{
+ if (client->flags & I2C_CLIENT_TEN) {
+ /* 10-bit address, all values are valid */
+ if (client->addr > 0x3ff)
+ return -EINVAL;
+ } else {
+ /* 7-bit address, reject the general call address */
+ if (client->addr == 0x00 || client->addr > 0x7f)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* And this is a strict address validity check, used when probing. If a
+ * device uses a reserved address, then it shouldn't be probed. 7-bit
+ * addressing is assumed, 10-bit address devices are rare and should be
+ * explicitly enumerated. */
+static int i2c_check_addr_validity(unsigned short addr)
+{
+ /*
+ * Reserved addresses per I2C specification:
+ * 0x00 General call address / START byte
+ * 0x01 CBUS address
+ * 0x02 Reserved for different bus format
+ * 0x03 Reserved for future purposes
+ * 0x04-0x07 Hs-mode master code
+ * 0x78-0x7b 10-bit slave addressing
+ * 0x7c-0x7f Reserved for future purposes
+ */
+ if (addr < 0x08 || addr > 0x77)
+ return -EINVAL;
+ return 0;
+}
+
+static int __i2c_check_addr_busy(struct device *dev, void *addrp)
+{
+ struct i2c_client *client = i2c_verify_client(dev);
+ int addr = *(int *)addrp;
+
+ if (client && client->addr == addr)
+ return -EBUSY;
+ return 0;
+}
+
+static int i2c_check_addr_busy(struct i2c_adapter *adapter, int addr)
+{
+ return device_for_each_child(&adapter->dev, &addr,
+ __i2c_check_addr_busy);
+}
+
/**
* i2c_new_device - instantiate an i2c device
* @adap: the adapter managing the device
@@ -410,8 +462,16 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
strlcpy(client->name, info->type, sizeof(client->name));
+ /* Check for address validity */
+ status = i2c_check_client_addr_validity(client);
+ if (status) {
+ dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n",
+ client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr);
+ goto out_err_silent;
+ }
+
/* Check for address business */
- status = i2c_check_addr(adap, client->addr);
+ status = i2c_check_addr_busy(adap, client->addr);
if (status)
goto out_err;
@@ -436,6 +496,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
out_err:
dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x "
"(%d)\n", client->name, client->addr, status);
+out_err_silent:
kfree(client);
return NULL;
}
@@ -561,15 +622,9 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
return -EINVAL;
}
- if (info.addr < 0x03 || info.addr > 0x77) {
- dev_err(dev, "%s: Invalid I2C address 0x%hx\n", "new_device",
- info.addr);
- return -EINVAL;
- }
-
client = i2c_new_device(adap, &info);
if (!client)
- return -EEXIST;
+ return -EINVAL;
/* Keep track of the added device */
i2c_lock_adapter(adap);
@@ -1024,21 +1079,6 @@ EXPORT_SYMBOL(i2c_del_driver);
/* ------------------------------------------------------------------------- */
-static int __i2c_check_addr(struct device *dev, void *addrp)
-{
- struct i2c_client *client = i2c_verify_client(dev);
- int addr = *(int *)addrp;
-
- if (client && client->addr == addr)
- return -EBUSY;
- return 0;
-}
-
-static int i2c_check_addr(struct i2c_adapter *adapter, int addr)
-{
- return device_for_each_child(&adapter->dev, &addr, __i2c_check_addr);
-}
-
/**
* i2c_use_client - increments the reference count of the i2c client structure
* @client: the client being referenced
@@ -1277,6 +1317,41 @@ EXPORT_SYMBOL(i2c_master_recv);
* ----------------------------------------------------
*/
+/*
+ * Legacy default probe function, mostly relevant for SMBus. The default
+ * probe method is a quick write, but it is known to corrupt the 24RF08
+ * EEPROMs due to a state machine bug, and could also irreversibly
+ * write-protect some EEPROMs, so for address ranges 0x30-0x37 and 0x50-0x5f,
+ * we use a short byte read instead. Also, some bus drivers don't implement
+ * quick write, so we fallback to a byte read in that case too.
+ * On x86, there is another special case for FSC hardware monitoring chips,
+ * which want regular byte reads (address 0x73.) Fortunately, these are the
+ * only known chips using this I2C address on PC hardware.
+ * Returns 1 if probe succeeded, 0 if not.
+ */
+static int i2c_default_probe(struct i2c_adapter *adap, unsigned short addr)
+{
+ int err;
+ union i2c_smbus_data dummy;
+
+#ifdef CONFIG_X86
+ if (addr == 0x73 && (adap->class & I2C_CLASS_HWMON)
+ && i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE_DATA))
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &dummy);
+ else
+#endif
+ if ((addr & ~0x07) == 0x30 || (addr & ~0x0f) == 0x50
+ || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK))
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE, &dummy);
+ else
+ err = i2c_smbus_xfer(adap, addr, 0, I2C_SMBUS_WRITE, 0,
+ I2C_SMBUS_QUICK, NULL);
+
+ return err >= 0;
+}
+
static int i2c_detect_address(struct i2c_client *temp_client,
struct i2c_driver *driver)
{
@@ -1286,34 +1361,20 @@ static int i2c_detect_address(struct i2c_client *temp_client,
int err;
/* Make sure the address is valid */
- if (addr < 0x03 || addr > 0x77) {
+ err = i2c_check_addr_validity(addr);
+ if (err) {
dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n",
addr);
- return -EINVAL;
+ return err;
}
/* Skip if already in use */
- if (i2c_check_addr(adapter, addr))
+ if (i2c_check_addr_busy(adapter, addr))
return 0;
/* Make sure there is something at this address */
- if (addr == 0x73 && (adapter->class & I2C_CLASS_HWMON)) {
- /* Special probe for FSC hwmon chips */
- union i2c_smbus_data dummy;
-
- if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_READ, 0,
- I2C_SMBUS_BYTE_DATA, &dummy) < 0)
- return 0;
- } else {
- if (i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0,
- I2C_SMBUS_QUICK, NULL) < 0)
- return 0;
-
- /* Prevent 24RF08 corruption */
- if ((addr & ~0x0f) == 0x50)
- i2c_smbus_xfer(adapter, addr, 0, I2C_SMBUS_WRITE, 0,
- I2C_SMBUS_QUICK, NULL);
- }
+ if (!i2c_default_probe(adapter, addr))
+ return 0;
/* Finally call the custom detection function */
memset(&info, 0, sizeof(struct i2c_board_info));
@@ -1407,42 +1468,22 @@ i2c_new_probed_device(struct i2c_adapter *adap,
for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) {
/* Check address validity */
- if (addr_list[i] < 0x03 || addr_list[i] > 0x77) {
+ if (i2c_check_addr_validity(addr_list[i]) < 0) {
dev_warn(&adap->dev, "Invalid 7-bit address "
"0x%02x\n", addr_list[i]);
continue;
}
/* Check address availability */
- if (i2c_check_addr(adap, addr_list[i])) {
+ if (i2c_check_addr_busy(adap, addr_list[i])) {
dev_dbg(&adap->dev, "Address 0x%02x already in "
"use, not probing\n", addr_list[i]);
continue;
}
- /* Test address responsiveness
- The default probe method is a quick write, but it is known
- to corrupt the 24RF08 EEPROMs due to a state machine bug,
- and could also irreversibly write-protect some EEPROMs, so
- for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte
- read instead. Also, some bus drivers don't implement
- quick write, so we fallback to a byte read it that case
- too. */
- if ((addr_list[i] & ~0x07) == 0x30
- || (addr_list[i] & ~0x0f) == 0x50
- || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) {
- union i2c_smbus_data data;
-
- if (i2c_smbus_xfer(adap, addr_list[i], 0,
- I2C_SMBUS_READ, 0,
- I2C_SMBUS_BYTE, &data) >= 0)
- break;
- } else {
- if (i2c_smbus_xfer(adap, addr_list[i], 0,
- I2C_SMBUS_WRITE, 0,
- I2C_SMBUS_QUICK, NULL) >= 0)
- break;
- }
+ /* Test address responsiveness */
+ if (i2c_default_probe(adap, addr_list[i]))
+ break;
}
if (addr_list[i] == I2C_CLIENT_END) {
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index e0694e4d86c7..0b0427f7d348 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -167,13 +167,9 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf,
if (count > 8192)
count = 8192;
- tmp = kmalloc(count, GFP_KERNEL);
- if (tmp == NULL)
- return -ENOMEM;
- if (copy_from_user(tmp, buf, count)) {
- kfree(tmp);
- return -EFAULT;
- }
+ tmp = memdup_user(buf, count);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n",
iminor(file->f_path.dentry->d_inode), count);
@@ -219,9 +215,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
- rdwr_pa = (struct i2c_msg *)
- kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
- GFP_KERNEL);
+ rdwr_pa = kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), GFP_KERNEL);
if (!rdwr_pa)
return -ENOMEM;
@@ -247,15 +241,9 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
break;
}
data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
- rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
- if (rdwr_pa[i].buf == NULL) {
- res = -ENOMEM;
- break;
- }
- if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i],
- rdwr_pa[i].len)) {
- ++i; /* Needs to be kfreed too */
- res = -EFAULT;
+ rdwr_pa[i].buf = memdup_user(data_ptrs[i], rdwr_pa[i].len);
+ if (IS_ERR(rdwr_pa[i].buf)) {
+ res = PTR_ERR(rdwr_pa[i].buf);
break;
}
}
diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c
index a24e0bfe9201..f61ccc1e5ea3 100644
--- a/drivers/i2c/i2c-smbus.c
+++ b/drivers/i2c/i2c-smbus.c
@@ -173,7 +173,6 @@ static int smbalert_remove(struct i2c_client *ara)
cancel_work_sync(&alert->alert);
- i2c_set_clientdata(ara, NULL);
kfree(alert);
return 0;
}
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 67fb73559fd5..34b9872f35d1 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -480,13 +480,9 @@ int ide_taskfile_ioctl(ide_drive_t *drive, unsigned long arg)
u16 nsect = 0;
char __user *buf = (char __user *)arg;
- req_task = kzalloc(tasksize, GFP_KERNEL);
- if (req_task == NULL)
- return -ENOMEM;
- if (copy_from_user(req_task, buf, tasksize)) {
- kfree(req_task);
- return -EFAULT;
- }
+ req_task = memdup_user(buf, tasksize);
+ if (IS_ERR(req_task))
+ return PTR_ERR(req_task);
taskout = req_task->out_size;
taskin = req_task->in_size;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 3cb9c4e056ff..fa896210ed7b 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -177,7 +177,7 @@ EXPORT_SYMBOL_GPL(ide_pci_clk);
module_param_named(pci_clock, ide_pci_clk, int, 0);
MODULE_PARM_DESC(pci_clock, "PCI bus clock frequency (in MHz)");
-static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
+static int ide_set_dev_param_mask(const char *s, const struct kernel_param *kp)
{
int a, b, i, j = 1;
unsigned int *dev_param_mask = (unsigned int *)kp->arg;
@@ -200,34 +200,40 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
return 0;
}
+static struct kernel_param_ops param_ops_ide_dev_mask = {
+ .set = ide_set_dev_param_mask
+};
+
+#define param_check_ide_dev_mask(name, p) param_check_uint(name, p)
+
static unsigned int ide_nodma;
-module_param_call(nodma, ide_set_dev_param_mask, NULL, &ide_nodma, 0);
+module_param_named(nodma, ide_nodma, ide_dev_mask, 0);
MODULE_PARM_DESC(nodma, "disallow DMA for a device");
static unsigned int ide_noflush;
-module_param_call(noflush, ide_set_dev_param_mask, NULL, &ide_noflush, 0);
+module_param_named(noflush, ide_noflush, ide_dev_mask, 0);
MODULE_PARM_DESC(noflush, "disable flush requests for a device");
static unsigned int ide_nohpa;
-module_param_call(nohpa, ide_set_dev_param_mask, NULL, &ide_nohpa, 0);
+module_param_named(nohpa, ide_nohpa, ide_dev_mask, 0);
MODULE_PARM_DESC(nohpa, "disable Host Protected Area for a device");
static unsigned int ide_noprobe;
-module_param_call(noprobe, ide_set_dev_param_mask, NULL, &ide_noprobe, 0);
+module_param_named(noprobe, ide_noprobe, ide_dev_mask, 0);
MODULE_PARM_DESC(noprobe, "skip probing for a device");
static unsigned int ide_nowerr;
-module_param_call(nowerr, ide_set_dev_param_mask, NULL, &ide_nowerr, 0);
+module_param_named(nowerr, ide_nowerr, ide_dev_mask, 0);
MODULE_PARM_DESC(nowerr, "ignore the ATA_DF bit for a device");
static unsigned int ide_cdroms;
-module_param_call(cdrom, ide_set_dev_param_mask, NULL, &ide_cdroms, 0);
+module_param_named(cdrom, ide_cdroms, ide_dev_mask, 0);
MODULE_PARM_DESC(cdrom, "force device as a CD-ROM");
struct chs_geom {
diff --git a/drivers/ide/pmac.c b/drivers/ide/pmac.c
index 183fa38760d8..ebcf8e470a97 100644
--- a/drivers/ide/pmac.c
+++ b/drivers/ide/pmac.c
@@ -1400,8 +1400,11 @@ static struct of_device_id pmac_ide_macio_match[] =
static struct macio_driver pmac_ide_macio_driver =
{
- .name = "ide-pmac",
- .match_table = pmac_ide_macio_match,
+ .driver = {
+ .name = "ide-pmac",
+ .owner = THIS_MODULE,
+ .of_match_table = pmac_ide_macio_match,
+ },
.probe = pmac_ide_macio_attach,
.suspend = pmac_ide_macio_suspend,
.resume = pmac_ide_macio_resume,
diff --git a/drivers/ide/tx4938ide.c b/drivers/ide/tx4938ide.c
index 1d80f1fdbc97..7002765b593c 100644
--- a/drivers/ide/tx4938ide.c
+++ b/drivers/ide/tx4938ide.c
@@ -64,7 +64,7 @@ static void tx4938ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
pair = ide_get_pair_dev(drive);
if (pair)
- safe = min(safe, pair->pio_mode - XFER_PIO_0);
+ safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
tx4938ide_tune_ebusc(pdata->ebus_ch, pdata->gbus_clock, safe);
}
diff --git a/drivers/ide/tx4939ide.c b/drivers/ide/tx4939ide.c
index 3c7367751873..bed3e39aac96 100644
--- a/drivers/ide/tx4939ide.c
+++ b/drivers/ide/tx4939ide.c
@@ -114,7 +114,7 @@ static void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
pair = ide_get_pair_dev(drive);
if (pair)
- safe = min(safe, pair->pio_mode - XFER_PIO_0);
+ safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0);
/*
* Update Command Transfer Mode for master/slave and Data
* Transfer Mode for this drive.
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index a42bd6893bcf..a77483befcda 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -1045,14 +1045,9 @@ static long video1394_ioctl(struct file *file,
if (get_user(qv, &p->packet_sizes))
return -EFAULT;
- psizes = kmalloc(buf_size, GFP_KERNEL);
- if (!psizes)
- return -ENOMEM;
-
- if (copy_from_user(psizes, qv, buf_size)) {
- kfree(psizes);
- return -EFAULT;
- }
+ psizes = memdup_user(qv, buf_size);
+ if (IS_ERR(psizes))
+ return PTR_ERR(psizes);
}
spin_lock_irqsave(&d->lock,flags);
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index edef8527eb34..844954bf417b 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -542,10 +542,8 @@ static int qibfs_fill_super(struct super_block *sb, void *data, int silent)
list_for_each_entry_safe(dd, tmp, &qib_dev_list, list) {
spin_unlock_irqrestore(&qib_devs_lock, flags);
ret = add_cntr_files(sb, dd);
- if (ret) {
- deactivate_super(sb);
+ if (ret)
goto bail;
- }
spin_lock_irqsave(&qib_devs_lock, flags);
}
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 4771ab172b59..744600eff222 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -287,7 +287,6 @@ static int __devexit adp5588_remove(struct i2c_client *client)
free_irq(client->irq, kpad);
cancel_delayed_work_sync(&kpad->work);
input_unregister_device(kpad->input);
- i2c_set_clientdata(client, NULL);
kfree(kpad);
return 0;
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index bc696931fed7..40b032f0e32c 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -778,8 +778,6 @@ static int __devexit lm8323_remove(struct i2c_client *client)
struct lm8323_chip *lm = i2c_get_clientdata(client);
int i;
- i2c_set_clientdata(client, NULL);
-
disable_irq_wake(client->irq);
free_irq(client->irq, lm);
cancel_work_sync(&lm->work);
diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c
index 7fc8185e5c1b..9091ff5ea808 100644
--- a/drivers/input/keyboard/max7359_keypad.c
+++ b/drivers/input/keyboard/max7359_keypad.c
@@ -265,7 +265,6 @@ static int __devexit max7359_remove(struct i2c_client *client)
free_irq(client->irq, keypad);
input_unregister_device(keypad->input_dev);
- i2c_set_clientdata(client, NULL);
kfree(keypad);
return 0;
diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c
index 31f30087b591..fac695157e8a 100644
--- a/drivers/input/keyboard/qt2160.c
+++ b/drivers/input/keyboard/qt2160.c
@@ -358,7 +358,6 @@ static int __devexit qt2160_remove(struct i2c_client *client)
input_unregister_device(qt2160->input);
kfree(qt2160);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
index 493c93f25e2a..00137bebcf97 100644
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ b/drivers/input/keyboard/tca6416-keypad.c
@@ -316,8 +316,6 @@ static int __devexit tca6416_keypad_remove(struct i2c_client *client)
input_unregister_device(chip->input);
kfree(chip);
- i2c_set_clientdata(client, NULL);
-
return 0;
}
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index e9adbe49f6a4..2bef8fa56c94 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -97,7 +97,6 @@ static int __devexit ad714x_i2c_remove(struct i2c_client *client)
struct ad714x_chip *chip = i2c_get_clientdata(client);
ad714x_remove(chip);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index e148749b5851..23257652b8e8 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -38,7 +38,8 @@ enum {
};
static int ati_remote2_set_mask(const char *val,
- struct kernel_param *kp, unsigned int max)
+ const struct kernel_param *kp,
+ unsigned int max)
{
unsigned long mask;
int ret;
@@ -59,28 +60,31 @@ static int ati_remote2_set_mask(const char *val,
}
static int ati_remote2_set_channel_mask(const char *val,
- struct kernel_param *kp)
+ const struct kernel_param *kp)
{
pr_debug("%s()\n", __func__);
return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_CHANNEL_MASK);
}
-static int ati_remote2_get_channel_mask(char *buffer, struct kernel_param *kp)
+static int ati_remote2_get_channel_mask(char *buffer,
+ const struct kernel_param *kp)
{
pr_debug("%s()\n", __func__);
return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
}
-static int ati_remote2_set_mode_mask(const char *val, struct kernel_param *kp)
+static int ati_remote2_set_mode_mask(const char *val,
+ const struct kernel_param *kp)
{
pr_debug("%s()\n", __func__);
return ati_remote2_set_mask(val, kp, ATI_REMOTE2_MAX_MODE_MASK);
}
-static int ati_remote2_get_mode_mask(char *buffer, struct kernel_param *kp)
+static int ati_remote2_get_mode_mask(char *buffer,
+ const struct kernel_param *kp)
{
pr_debug("%s()\n", __func__);
@@ -89,15 +93,19 @@ static int ati_remote2_get_mode_mask(char *buffer, struct kernel_param *kp)
static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
#define param_check_channel_mask(name, p) __param_check(name, p, unsigned int)
-#define param_set_channel_mask ati_remote2_set_channel_mask
-#define param_get_channel_mask ati_remote2_get_channel_mask
+static struct kernel_param_ops param_ops_channel_mask = {
+ .set = ati_remote2_set_channel_mask,
+ .get = ati_remote2_get_channel_mask,
+};
module_param(channel_mask, channel_mask, 0644);
MODULE_PARM_DESC(channel_mask, "Bitmask of channels to accept <15:Channel16>...<1:Channel2><0:Channel1>");
static unsigned int mode_mask = ATI_REMOTE2_MAX_MODE_MASK;
#define param_check_mode_mask(name, p) __param_check(name, p, unsigned int)
-#define param_set_mode_mask ati_remote2_set_mode_mask
-#define param_get_mode_mask ati_remote2_get_mode_mask
+static struct kernel_param_ops param_ops_mode_mask = {
+ .set = ati_remote2_set_mode_mask,
+ .get = ati_remote2_get_mode_mask,
+};
module_param(mode_mask, mode_mask, 0644);
MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index 5c3ac4e0b055..4b42ffc0532a 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -69,7 +69,7 @@ static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
unsigned char nextstate = read_state(lp);
if (lp->laststate != nextstate) {
- int key_down = nextstate <= ARRAY_SIZE(lp->btncode);
+ int key_down = nextstate < ARRAY_SIZE(lp->btncode);
unsigned short keycode = key_down ?
lp->btncode[nextstate] : lp->btncode[lp->laststate];
@@ -168,8 +168,6 @@ static int __devexit pcf8574_kp_remove(struct i2c_client *client)
input_unregister_device(lp->idev);
kfree(lp);
- i2c_set_clientdata(client, NULL);
-
return 0;
}
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 979c50215282..73a7af2542a8 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -39,11 +39,13 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *);
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp);
+static struct kernel_param_ops param_ops_proto_abbrev = {
+ .set = psmouse_set_maxproto,
+ .get = psmouse_get_maxproto,
+};
#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
-#define param_set_proto_abbrev psmouse_set_maxproto
-#define param_get_proto_abbrev psmouse_get_maxproto
module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644);
MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches.");
@@ -1679,7 +1681,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data,
}
-static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
+static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp)
{
const struct psmouse_protocol *proto;
@@ -1696,7 +1698,7 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
return 0;
}
-static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
+static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
{
int type = *((unsigned int *)kp->arg);
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 8291e7399ffa..0ae62f0bcb32 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -613,7 +613,6 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
free_irq(client->irq, touch);
input_unregister_device(touch->input);
- i2c_set_clientdata(client, NULL);
kfree(touch);
return 0;
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index f34f1dbeb577..3bfe8fafc6ad 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -21,7 +21,8 @@ if SERIO
config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
default y
- depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN
+ depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && \
+ (!SUPERH || SH_CAYMAN) && !M68K && !BLACKFIN
help
i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices,
diff --git a/drivers/input/serio/i8042-ppcio.h b/drivers/input/serio/i8042-ppcio.h
index 2906e1b60c04..f708c75d16f1 100644
--- a/drivers/input/serio/i8042-ppcio.h
+++ b/drivers/input/serio/i8042-ppcio.h
@@ -52,81 +52,6 @@ static inline void i8042_platform_exit(void)
{
}
-#elif defined(CONFIG_SPRUCE)
-
-#define I8042_KBD_IRQ 22
-#define I8042_AUX_IRQ 21
-
-#define I8042_KBD_PHYS_DESC "spruceps2/serio0"
-#define I8042_AUX_PHYS_DESC "spruceps2/serio1"
-#define I8042_MUX_PHYS_DESC "spruceps2/serio%d"
-
-#define I8042_COMMAND_REG 0xff810000
-#define I8042_DATA_REG 0xff810001
-
-static inline int i8042_read_data(void)
-{
- unsigned long kbd_data;
-
- __raw_writel(0x00000088, 0xff500008);
- eieio();
-
- __raw_writel(0x03000000, 0xff50000c);
- eieio();
-
- asm volatile("lis 7,0xff88 \n\
- lswi 6,7,0x8 \n\
- mr %0,6"
- : "=r" (kbd_data) :: "6", "7");
-
- __raw_writel(0x00000000, 0xff50000c);
- eieio();
-
- return (unsigned char)(kbd_data >> 24);
-}
-
-static inline int i8042_read_status(void)
-{
- unsigned long kbd_status;
-
- __raw_writel(0x00000088, 0xff500008);
- eieio();
-
- __raw_writel(0x03000000, 0xff50000c);
- eieio();
-
- asm volatile("lis 7,0xff88 \n\
- ori 7,7,0x8 \n\
- lswi 6,7,0x8 \n\
- mr %0,6"
- : "=r" (kbd_status) :: "6", "7");
-
- __raw_writel(0x00000000, 0xff50000c);
- eieio();
-
- return (unsigned char)(kbd_status >> 24);
-}
-
-static inline void i8042_write_data(int val)
-{
- *((unsigned char *)0xff810000) = (char)val;
-}
-
-static inline void i8042_write_command(int val)
-{
- *((unsigned char *)0xff810001) = (char)val;
-}
-
-static inline int i8042_platform_init(void)
-{
- i8042_reset = 1;
- return 0;
-}
-
-static inline void i8042_platform_exit(void)
-{
-}
-
#else
#include "i8042-io.h"
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 2dc0c07c0469..42ba3691d908 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -508,7 +508,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
}
input_dev->name = wacom_wac->name;
- input_dev->name = wacom_wac->name;
input_dev->dev.parent = &intf->dev;
input_dev->open = wacom_open;
input_dev->close = wacom_close;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 847fd0135bcf..d564af58175c 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -300,7 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x823: /* Intuos3 Grip Pen */
case 0x813: /* Intuos3 Classic Pen */
case 0x885: /* Intuos3 Marker Pen */
- case 0x802: /* Intuos4 Grip Pen Eraser */
+ case 0x802: /* Intuos4 General Pen */
case 0x804: /* Intuos4 Marker Pen */
case 0x40802: /* Intuos4 Classic Pen */
case 0x022:
@@ -335,7 +335,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
case 0x81b: /* Intuos3 Classic Pen Eraser */
case 0x91b: /* Intuos3 Airbrush Eraser */
case 0x80c: /* Intuos4 Marker Pen Eraser */
- case 0x80a: /* Intuos4 Grip Pen Eraser */
+ case 0x80a: /* Intuos4 General Pen Eraser */
case 0x4080a: /* Intuos4 Classic Pen Eraser */
case 0x90a: /* Intuos4 Airbrush Eraser */
wacom->tool[idx] = BTN_TOOL_RUBBER;
@@ -356,6 +356,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
return 1;
}
+ /* older I4 styli don't work with new Cintiqs */
+ if (!((wacom->id[idx] >> 20) & 0x01) &&
+ (features->type == WACOM_21UX2))
+ return 1;
+
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
/*
@@ -474,21 +479,43 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_abs(input, ABS_MISC, 0);
}
} else {
- input_report_key(input, BTN_0, (data[5] & 0x01));
- input_report_key(input, BTN_1, (data[5] & 0x02));
- input_report_key(input, BTN_2, (data[5] & 0x04));
- input_report_key(input, BTN_3, (data[5] & 0x08));
- input_report_key(input, BTN_4, (data[6] & 0x01));
- input_report_key(input, BTN_5, (data[6] & 0x02));
- input_report_key(input, BTN_6, (data[6] & 0x04));
- input_report_key(input, BTN_7, (data[6] & 0x08));
- input_report_key(input, BTN_8, (data[5] & 0x10));
- input_report_key(input, BTN_9, (data[6] & 0x10));
+ if (features->type == WACOM_21UX2) {
+ input_report_key(input, BTN_0, (data[5] & 0x01));
+ input_report_key(input, BTN_1, (data[6] & 0x01));
+ input_report_key(input, BTN_2, (data[6] & 0x02));
+ input_report_key(input, BTN_3, (data[6] & 0x04));
+ input_report_key(input, BTN_4, (data[6] & 0x08));
+ input_report_key(input, BTN_5, (data[6] & 0x10));
+ input_report_key(input, BTN_6, (data[6] & 0x20));
+ input_report_key(input, BTN_7, (data[6] & 0x40));
+ input_report_key(input, BTN_8, (data[6] & 0x80));
+ input_report_key(input, BTN_9, (data[7] & 0x01));
+ input_report_key(input, BTN_A, (data[8] & 0x01));
+ input_report_key(input, BTN_B, (data[8] & 0x02));
+ input_report_key(input, BTN_C, (data[8] & 0x04));
+ input_report_key(input, BTN_X, (data[8] & 0x08));
+ input_report_key(input, BTN_Y, (data[8] & 0x10));
+ input_report_key(input, BTN_Z, (data[8] & 0x20));
+ input_report_key(input, BTN_BASE, (data[8] & 0x40));
+ input_report_key(input, BTN_BASE2, (data[8] & 0x80));
+ } else {
+ input_report_key(input, BTN_0, (data[5] & 0x01));
+ input_report_key(input, BTN_1, (data[5] & 0x02));
+ input_report_key(input, BTN_2, (data[5] & 0x04));
+ input_report_key(input, BTN_3, (data[5] & 0x08));
+ input_report_key(input, BTN_4, (data[6] & 0x01));
+ input_report_key(input, BTN_5, (data[6] & 0x02));
+ input_report_key(input, BTN_6, (data[6] & 0x04));
+ input_report_key(input, BTN_7, (data[6] & 0x08));
+ input_report_key(input, BTN_8, (data[5] & 0x10));
+ input_report_key(input, BTN_9, (data[6] & 0x10));
+ }
input_report_abs(input, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
input_report_abs(input, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) |
- data[2] | (data[3] & 0x1f) | data[4]) {
+ data[2] | (data[3] & 0x1f) | data[4] | data[8] |
+ (data[7] & 0x01)) {
input_report_key(input, wacom->tool[1], 1);
input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
} else {
@@ -640,7 +667,7 @@ static void wacom_tpc_finger_in(struct wacom_wac *wacom, char *data, int idx)
if (!idx)
input_report_key(input, BTN_TOUCH, 1);
input_event(input, EV_MSC, MSC_SERIAL, finger);
- input_sync(wacom->input);
+ input_sync(input);
wacom->last_finger = finger;
}
@@ -826,6 +853,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case INTUOS4L:
case CINTIQ:
case WACOM_BEE:
+ case WACOM_21UX2:
sync = wacom_intuos_irq(wacom_wac);
break;
@@ -921,6 +949,17 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_STYLUS2, input_dev->keybit);
break;
+ case WACOM_21UX2:
+ __set_bit(BTN_A, input_dev->keybit);
+ __set_bit(BTN_B, input_dev->keybit);
+ __set_bit(BTN_C, input_dev->keybit);
+ __set_bit(BTN_X, input_dev->keybit);
+ __set_bit(BTN_Y, input_dev->keybit);
+ __set_bit(BTN_Z, input_dev->keybit);
+ __set_bit(BTN_BASE, input_dev->keybit);
+ __set_bit(BTN_BASE2, input_dev->keybit);
+ /* fall through */
+
case WACOM_BEE:
__set_bit(BTN_8, input_dev->keybit);
__set_bit(BTN_9, input_dev->keybit);
@@ -1105,6 +1144,8 @@ static const struct wacom_features wacom_features_0xBA =
{ "Wacom Intuos4 8x13", WACOM_PKGLEN_INTUOS, 65024, 40640, 2047, 63, INTUOS4L };
static const struct wacom_features wacom_features_0xBB =
{ "Wacom Intuos4 12x19", WACOM_PKGLEN_INTUOS, 97536, 60960, 2047, 63, INTUOS4L };
+static const struct wacom_features wacom_features_0xBC =
+ { "Wacom Intuos4 WL", WACOM_PKGLEN_INTUOS, 40840, 25400, 2047, 63, INTUOS4 };
static const struct wacom_features wacom_features_0x3F =
{ "Wacom Cintiq 21UX", WACOM_PKGLEN_INTUOS, 87200, 65600, 1023, 63, CINTIQ };
static const struct wacom_features wacom_features_0xC5 =
@@ -1113,6 +1154,8 @@ static const struct wacom_features wacom_features_0xC6 =
{ "Wacom Cintiq 12WX", WACOM_PKGLEN_INTUOS, 53020, 33440, 1023, 63, WACOM_BEE };
static const struct wacom_features wacom_features_0xC7 =
{ "Wacom DTU1931", WACOM_PKGLEN_GRAPHIRE, 37832, 30305, 511, 0, PL };
+static const struct wacom_features wacom_features_0xCC =
+ { "Wacom Cintiq 21UX2", WACOM_PKGLEN_INTUOS, 87200, 65600, 2047, 63, WACOM_21UX2 };
static const struct wacom_features wacom_features_0x90 =
{ "Wacom ISDv4 90", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC };
static const struct wacom_features wacom_features_0x93 =
@@ -1185,10 +1228,12 @@ const struct usb_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0xB9) },
{ USB_DEVICE_WACOM(0xBA) },
{ USB_DEVICE_WACOM(0xBB) },
+ { USB_DEVICE_WACOM(0xBC) },
{ USB_DEVICE_WACOM(0x3F) },
{ USB_DEVICE_WACOM(0xC5) },
{ USB_DEVICE_WACOM(0xC6) },
{ USB_DEVICE_WACOM(0xC7) },
+ { USB_DEVICE_WACOM(0xCC) },
{ USB_DEVICE_WACOM(0x90) },
{ USB_DEVICE_WACOM(0x93) },
{ USB_DEVICE_WACOM(0x9A) },
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 063f1af3204f..854b92092dfc 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -50,6 +50,7 @@ enum {
INTUOS4S,
INTUOS4,
INTUOS4L,
+ WACOM_21UX2,
CINTIQ,
WACOM_BEE,
WACOM_MO,
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 6703c6b9800a..3b9d5e2105d7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -156,7 +156,7 @@ config TOUCHSCREEN_FUJITSU
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410/generic touchscreen input driver"
depends on ARCH_S3C2410 || SAMSUNG_DEV_TS
- select S3C24XX_ADC
+ select S3C_ADC
help
Say Y here if you have the s3c2410 touchscreen.
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index 794d070c6900..4b32fb4704cd 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -812,10 +812,8 @@ static int __devinit ad7879_probe(struct i2c_client *client,
ts->bus = client;
error = ad7879_construct(client, ts);
- if (error) {
- i2c_set_clientdata(client, NULL);
+ if (error)
kfree(ts);
- }
return error;
}
@@ -825,7 +823,6 @@ static int __devexit ad7879_remove(struct i2c_client *client)
struct ad7879 *ts = dev_get_drvdata(&client->dev);
ad7879_destroy(client, ts);
- i2c_set_clientdata(client, NULL);
kfree(ts);
return 0;
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 634f6f6b9b13..a9fdf55c0238 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -1164,7 +1164,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(ts->reg)) {
err = PTR_ERR(ts->reg);
- dev_err(&spi->dev, "unable to get regulator: %ld\n", err);
+ dev_err(&spi->dev, "unable to get regulator: %d\n", err);
goto err_free_gpio;
}
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 75f8b73010fa..7a3a916f84a8 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -238,7 +238,6 @@ err2:
input = NULL; /* so we dont try to free it below */
err1:
input_free_device(input);
- i2c_set_clientdata(client, NULL);
kfree(priv);
err0:
return err;
@@ -256,7 +255,6 @@ static int __devexit eeti_ts_remove(struct i2c_client *client)
enable_irq(priv->irq);
input_unregister_device(priv->input);
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
index ce8ab0269f6f..1fb0c2f06a44 100644
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ b/drivers/input/touchscreen/mcs5000_ts.c
@@ -256,7 +256,6 @@ static int __devexit mcs5000_ts_remove(struct i2c_client *client)
free_irq(client->irq, data);
input_unregister_device(data->input_dev);
kfree(data);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c
index ac5d0f9b0cb1..6085d12fd561 100644
--- a/drivers/input/touchscreen/s3c2410_ts.c
+++ b/drivers/input/touchscreen/s3c2410_ts.c
@@ -173,7 +173,7 @@ static irqreturn_t stylus_irq(int irq, void *dev_id)
if (down)
s3c_adc_start(ts.client, 0, 1 << ts.shift);
else
- dev_info(ts.dev, "%s: count=%d\n", __func__, ts.count);
+ dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
if (ts.features & FEAT_PEN_IRQ) {
/* Clear pen down/up interrupt */
diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
index 5de80a1a730b..5b70a1419b4d 100644
--- a/drivers/input/touchscreen/tps6507x-ts.c
+++ b/drivers/input/touchscreen/tps6507x-ts.c
@@ -221,7 +221,7 @@ done:
if (poll) {
schd = queue_delayed_work(tsc->wq, &tsc->work,
- tsc->poll_period * HZ / 1000);
+ msecs_to_jiffies(tsc->poll_period));
if (schd)
tsc->polling = 1;
else {
@@ -326,7 +326,7 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
goto err2;
schd = queue_delayed_work(tsc->wq, &tsc->work,
- tsc->poll_period * HZ / 1000);
+ msecs_to_jiffies(tsc->poll_period));
if (schd)
tsc->polling = 1;
@@ -339,10 +339,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
return 0;
err2:
- cancel_delayed_work(&tsc->work);
- flush_workqueue(tsc->wq);
+ cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq);
- tsc->wq = 0;
input_free_device(input_dev);
err1:
kfree(tsc);
@@ -360,10 +358,8 @@ static int __devexit tps6507x_ts_remove(struct platform_device *pdev)
if (!tsc)
return 0;
- cancel_delayed_work(&tsc->work);
- flush_workqueue(tsc->wq);
+ cancel_delayed_work_sync(&tsc->work);
destroy_workqueue(tsc->wq);
- tsc->wq = 0;
input_free_device(input_dev);
diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c
index 769b479fcaa6..be23780e8a3e 100644
--- a/drivers/input/touchscreen/tsc2007.c
+++ b/drivers/input/touchscreen/tsc2007.c
@@ -347,8 +347,6 @@ static int __devexit tsc2007_remove(struct i2c_client *client)
struct tsc2007 *ts = i2c_get_clientdata(client);
struct tsc2007_platform_data *pdata = client->dev.platform_data;
- i2c_set_clientdata(client, NULL);
-
tsc2007_free_irq(ts);
if (pdata->exit_platform_hw)
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index bde3c88b8b27..b054494df846 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -1020,12 +1020,12 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
if (cmd == AVMB1_ADDCARD) {
if ((retval = copy_from_user(&cdef, data,
sizeof(avmb1_carddef))))
- return retval;
+ return -EFAULT;
cdef.cardtype = AVM_CARDTYPE_B1;
} else {
if ((retval = copy_from_user(&cdef, data,
sizeof(avmb1_extcarddef))))
- return retval;
+ return -EFAULT;
}
cparams.port = cdef.port;
cparams.irq = cdef.irq;
@@ -1218,7 +1218,7 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
kcapi_carddef cdef;
if ((retval = copy_from_user(&cdef, data, sizeof(cdef))))
- return retval;
+ return -EFAULT;
cparams.port = cdef.port;
cparams.irq = cdef.irq;
diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c
index b3b7e2879bac..8700474747e8 100644
--- a/drivers/isdn/hardware/mISDN/hfcsusb.c
+++ b/drivers/isdn/hardware/mISDN/hfcsusb.c
@@ -97,8 +97,10 @@ static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val)
hw->name, __func__, reg, val);
spin_lock(&hw->ctrl_lock);
- if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE)
+ if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) {
+ spin_unlock(&hw->ctrl_lock);
return 1;
+ }
buf = &hw->ctrl_buff[hw->ctrl_in_idx];
buf->hfcs_reg = reg;
buf->reg_val = val;
diff --git a/drivers/isdn/hardware/mISDN/netjet.c b/drivers/isdn/hardware/mISDN/netjet.c
index 0a3553df065f..54ae71a907f9 100644
--- a/drivers/isdn/hardware/mISDN/netjet.c
+++ b/drivers/isdn/hardware/mISDN/netjet.c
@@ -320,12 +320,12 @@ inittiger(struct tiger_hw *card)
return -ENOMEM;
}
for (i = 0; i < 2; i++) {
- card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_KERNEL);
+ card->bc[i].hsbuf = kmalloc(NJ_DMA_TXSIZE, GFP_ATOMIC);
if (!card->bc[i].hsbuf) {
pr_info("%s: no B%d send buffer\n", card->name, i + 1);
return -ENOMEM;
}
- card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_KERNEL);
+ card->bc[i].hrbuf = kmalloc(NJ_DMA_RXSIZE, GFP_ATOMIC);
if (!card->bc[i].hrbuf) {
pr_info("%s: no B%d recv buffer\n", card->name, i + 1);
return -ENOMEM;
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index f37b8f68d0aa..8c46baee621b 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -449,14 +449,9 @@ static int get_filter(void __user *arg, struct sock_filter **p)
/* uprog.len is unsigned short, so no overflow here */
len = uprog.len * sizeof(struct sock_filter);
- code = kmalloc(len, GFP_KERNEL);
- if (code == NULL)
- return -ENOMEM;
-
- if (copy_from_user(code, uprog.filter, len)) {
- kfree(code);
- return -EFAULT;
- }
+ code = memdup_user(uprog.filter, len);
+ if (IS_ERR(code))
+ return PTR_ERR(code);
err = sk_chk_filter(code, uprog.len);
if (err) {
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 123c1d6c43b4..1507d2e83fbb 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -411,14 +411,10 @@ static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int cha
return -EINVAL;
}
- cbuf = kmalloc(len, GFP_KERNEL);
- if (!cbuf)
- return -ENOMEM;
+ cbuf = memdup_user(buf, len);
+ if (IS_ERR(cbuf))
+ return PTR_ERR(cbuf);
- if (copy_from_user(cbuf, buf, len)) {
- kfree(cbuf);
- return -EFAULT;
- }
memcpy_toio(dev->sh_mem, cbuf, len);
kfree(cbuf);
return len;
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 1081091bbfaf..43c5dc3516e5 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -215,19 +215,13 @@ int sc_ioctl(int card, scs_ioctl *data)
pr_debug("%s: DCBIOSETSPID: ioctl received\n",
sc_adapter[card]->devicename);
- spid = kmalloc(SCIOC_SPIDSIZE, GFP_KERNEL);
- if(!spid) {
- kfree(rcvmsg);
- return -ENOMEM;
- }
-
/*
* Get the spid from user space
*/
- if (copy_from_user(spid, data->dataptr, SCIOC_SPIDSIZE)) {
+ spid = memdup_user(data->dataptr, SCIOC_SPIDSIZE);
+ if (IS_ERR(spid)) {
kfree(rcvmsg);
- kfree(spid);
- return -EFAULT;
+ return PTR_ERR(spid);
}
pr_debug("%s: SCIOCSETSPID: setting channel %d spid to %s\n",
@@ -296,18 +290,13 @@ int sc_ioctl(int card, scs_ioctl *data)
pr_debug("%s: SCIOSETDN: ioctl received\n",
sc_adapter[card]->devicename);
- dn = kmalloc(SCIOC_DNSIZE, GFP_KERNEL);
- if (!dn) {
- kfree(rcvmsg);
- return -ENOMEM;
- }
/*
* Get the spid from user space
*/
- if (copy_from_user(dn, data->dataptr, SCIOC_DNSIZE)) {
+ dn = memdup_user(data->dataptr, SCIOC_DNSIZE);
+ if (IS_ERR(dn)) {
kfree(rcvmsg);
- kfree(dn);
- return -EFAULT;
+ return PTR_ERR(dn);
}
pr_debug("%s: SCIOCSETDN: setting channel %d dn to %s\n",
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 286b501a3573..5dcdf9d69b3a 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -742,7 +742,6 @@ failed_unregister_dev_file:
for (i--; i >= 0; i--)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
failed_free:
- i2c_set_clientdata(client, NULL);
kfree(led);
return ret;
@@ -759,7 +758,6 @@ static int __exit bd2802_remove(struct i2c_client *client)
bd2802_disable_adv_conf(led);
for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
device_remove_file(&led->client->dev, bd2802_attributes[i]);
- i2c_set_clientdata(client, NULL);
kfree(led);
return 0;
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 932a58da76c4..9010c054615e 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -432,7 +432,6 @@ static int __devexit lp3944_remove(struct i2c_client *client)
}
kfree(data);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 6682175fa9f7..43d08756d823 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -320,10 +320,8 @@ static int pca9532_probe(struct i2c_client *client,
mutex_init(&data->update_lock);
err = pca9532_configure(client, data, pca9532_pdata);
- if (err) {
+ if (err)
kfree(data);
- i2c_set_clientdata(client, NULL);
- }
return err;
}
@@ -351,7 +349,6 @@ static int pca9532_remove(struct i2c_client *client)
}
kfree(data);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index 8ff50f234190..66aa3e8e786f 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -342,7 +342,6 @@ exit:
}
kfree(pca955x);
- i2c_set_clientdata(client, NULL);
return err;
}
@@ -358,7 +357,6 @@ static int __devexit pca955x_remove(struct i2c_client *client)
}
kfree(pca955x);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 97147804a49c..b6e7ddc09d76 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -492,8 +492,8 @@ static void macio_pci_add_devices(struct macio_chip *chip)
}
/* Add media bay devices if any */
- pnode = mbdev->ofdev.dev.of_node;
- if (mbdev)
+ if (mbdev) {
+ pnode = mbdev->ofdev.dev.of_node;
for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
if (macio_skip_device(np))
continue;
@@ -502,10 +502,11 @@ static void macio_pci_add_devices(struct macio_chip *chip)
mbdev, root_res) == NULL)
of_node_put(np);
}
+ }
/* Add serial ports if any */
- pnode = sdev->ofdev.dev.of_node;
if (sdev) {
+ pnode = sdev->ofdev.dev.of_node;
for (np = NULL; (np = of_get_next_child(pnode, np)) != NULL;) {
if (macio_skip_device(np))
continue;
@@ -525,7 +526,6 @@ static void macio_pci_add_devices(struct macio_chip *chip)
int macio_register_driver(struct macio_driver *drv)
{
/* initialize common driver fields */
- drv->driver.name = drv->name;
drv->driver.bus = &macio_bus_type;
/* register with core */
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 288acce76b74..2fd435bc542e 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -728,8 +728,10 @@ static struct of_device_id media_bay_match[] =
static struct macio_driver media_bay_driver =
{
- .name = "media-bay",
- .match_table = media_bay_match,
+ .driver = {
+ .name = "media-bay",
+ .of_match_table = media_bay_match,
+ },
.probe = media_bay_attach,
.suspend = media_bay_suspend,
.resume = media_bay_resume
diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c
index 12946c5f583f..53cce3a5da23 100644
--- a/drivers/macintosh/rack-meter.c
+++ b/drivers/macintosh/rack-meter.c
@@ -584,9 +584,11 @@ static struct of_device_id rackmeter_match[] = {
};
static struct macio_driver rackmeter_driver = {
- .name = "rackmeter",
- .owner = THIS_MODULE,
- .match_table = rackmeter_match,
+ .driver = {
+ .name = "rackmeter",
+ .owner = THIS_MODULE,
+ .of_match_table = rackmeter_match,
+ },
.probe = rackmeter_probe,
.remove = __devexit_p(rackmeter_remove),
.shutdown = rackmeter_shutdown,
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 16d82f17ae82..c42eeb43042d 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -182,7 +182,6 @@ remove_thermostat(struct i2c_client *client)
thermostat = NULL;
- i2c_set_clientdata(client, NULL);
kfree(th);
return 0;
@@ -400,7 +399,6 @@ static int probe_thermostat(struct i2c_client *client,
rc = read_reg(th, CONFIG_REG);
if (rc < 0) {
dev_err(&client->dev, "Thermostat failed to read config!\n");
- i2c_set_clientdata(client, NULL);
kfree(th);
return -ENODEV;
}
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
index d8257d35afde..647c6add2193 100644
--- a/drivers/macintosh/windfarm_lm75_sensor.c
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -107,10 +107,8 @@ static int wf_lm75_probe(struct i2c_client *client,
i2c_set_clientdata(client, lm);
rc = wf_register_sensor(&lm->sens);
- if (rc) {
- i2c_set_clientdata(client, NULL);
+ if (rc)
kfree(lm);
- }
return rc;
}
@@ -216,7 +214,6 @@ static int wf_lm75_remove(struct i2c_client *client)
/* release sensor */
wf_unregister_sensor(&lm->sens);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c
index b486eb929fde..8204113268f4 100644
--- a/drivers/macintosh/windfarm_max6690_sensor.c
+++ b/drivers/macintosh/windfarm_max6690_sensor.c
@@ -81,7 +81,6 @@ static int wf_max6690_probe(struct i2c_client *client,
rc = wf_register_sensor(&max->sens);
if (rc) {
- i2c_set_clientdata(client, NULL);
kfree(max);
}
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index e20330a28959..65a8ff3e1f8e 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -376,7 +376,6 @@ static int wf_sat_remove(struct i2c_client *client)
/* XXX TODO */
sat->i2c = NULL;
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 3bdbb6115702..a8aab9cf26b9 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1168,12 +1168,11 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (ivmode && cc->iv_gen_ops) {
if (ivopts)
*(ivopts - 1) = ':';
- cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
+ cc->iv_mode = kstrdup(ivmode, GFP_KERNEL);
if (!cc->iv_mode) {
ti->error = "Error kmallocing iv_mode string";
goto bad_ivmode_string;
}
- strcpy(cc->iv_mode, ivmode);
} else
cc->iv_mode = NULL;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index d7500e1c26f2..dbb7c03eb0af 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -285,19 +285,20 @@ retry:
up_write(&_hash_lock);
}
-static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
- const char *new)
+static struct mapped_device *dm_hash_rename(struct dm_ioctl *param,
+ const char *new)
{
char *new_name, *old_name;
struct hash_cell *hc;
struct dm_table *table;
+ struct mapped_device *md;
/*
* duplicate new.
*/
new_name = kstrdup(new, GFP_KERNEL);
if (!new_name)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
down_write(&_hash_lock);
@@ -306,24 +307,24 @@ static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
*/
hc = __get_name_cell(new);
if (hc) {
- DMWARN("asked to rename to an already existing name %s -> %s",
- old, new);
+ DMWARN("asked to rename to an already-existing name %s -> %s",
+ param->name, new);
dm_put(hc->md);
up_write(&_hash_lock);
kfree(new_name);
- return -EBUSY;
+ return ERR_PTR(-EBUSY);
}
/*
* Is there such a device as 'old' ?
*/
- hc = __get_name_cell(old);
+ hc = __get_name_cell(param->name);
if (!hc) {
- DMWARN("asked to rename a non existent device %s -> %s",
- old, new);
+ DMWARN("asked to rename a non-existent device %s -> %s",
+ param->name, new);
up_write(&_hash_lock);
kfree(new_name);
- return -ENXIO;
+ return ERR_PTR(-ENXIO);
}
/*
@@ -345,13 +346,14 @@ static int dm_hash_rename(uint32_t cookie, uint32_t *flags, const char *old,
dm_table_put(table);
}
- if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, cookie))
- *flags |= DM_UEVENT_GENERATED_FLAG;
+ if (!dm_kobject_uevent(hc->md, KOBJ_CHANGE, param->event_nr))
+ param->flags |= DM_UEVENT_GENERATED_FLAG;
- dm_put(hc->md);
+ md = hc->md;
up_write(&_hash_lock);
kfree(old_name);
- return 0;
+
+ return md;
}
/*-----------------------------------------------------------------
@@ -573,7 +575,7 @@ static struct dm_table *dm_get_live_or_inactive_table(struct mapped_device *md,
* Fills in a dm_ioctl structure, ready for sending back to
* userland.
*/
-static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
+static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{
struct gendisk *disk = dm_disk(md);
struct dm_table *table;
@@ -617,8 +619,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
dm_table_put(table);
}
}
-
- return 0;
}
static int dev_create(struct dm_ioctl *param, size_t param_size)
@@ -638,14 +638,14 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
return r;
r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
- if (r) {
- dm_put(md);
- return r;
- }
+ if (r)
+ goto out;
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
- r = __dev_status(md, param);
+ __dev_status(md, param);
+
+out:
dm_put(md);
return r;
@@ -762,6 +762,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
{
int r;
char *new_name = (char *) param + param->data_start;
+ struct mapped_device *md;
if (new_name < param->data ||
invalid_str(new_name, (void *) param + param_size) ||
@@ -774,10 +775,14 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
if (r)
return r;
- param->data_size = 0;
+ md = dm_hash_rename(param, new_name);
+ if (IS_ERR(md))
+ return PTR_ERR(md);
+
+ __dev_status(md, param);
+ dm_put(md);
- return dm_hash_rename(param->event_nr, &param->flags, param->name,
- new_name);
+ return 0;
}
static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
@@ -818,8 +823,6 @@ static int dev_set_geometry(struct dm_ioctl *param, size_t param_size)
geometry.start = indata[3];
r = dm_set_geometry(md, &geometry);
- if (!r)
- r = __dev_status(md, param);
param->data_size = 0;
@@ -843,13 +846,17 @@ static int do_suspend(struct dm_ioctl *param)
if (param->flags & DM_NOFLUSH_FLAG)
suspend_flags |= DM_SUSPEND_NOFLUSH_FLAG;
- if (!dm_suspended_md(md))
+ if (!dm_suspended_md(md)) {
r = dm_suspend(md, suspend_flags);
+ if (r)
+ goto out;
+ }
- if (!r)
- r = __dev_status(md, param);
+ __dev_status(md, param);
+out:
dm_put(md);
+
return r;
}
@@ -911,7 +918,7 @@ static int do_resume(struct dm_ioctl *param)
dm_table_destroy(old_map);
if (!r)
- r = __dev_status(md, param);
+ __dev_status(md, param);
dm_put(md);
return r;
@@ -935,16 +942,16 @@ static int dev_suspend(struct dm_ioctl *param, size_t param_size)
*/
static int dev_status(struct dm_ioctl *param, size_t param_size)
{
- int r;
struct mapped_device *md;
md = find_device(param);
if (!md)
return -ENXIO;
- r = __dev_status(md, param);
+ __dev_status(md, param);
dm_put(md);
- return r;
+
+ return 0;
}
/*
@@ -1019,7 +1026,7 @@ static void retrieve_status(struct dm_table *table,
*/
static int dev_wait(struct dm_ioctl *param, size_t param_size)
{
- int r;
+ int r = 0;
struct mapped_device *md;
struct dm_table *table;
@@ -1040,9 +1047,7 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
* changed to trigger the event, so we may as well tell
* him and save an ioctl.
*/
- r = __dev_status(md, param);
- if (r)
- goto out;
+ __dev_status(md, param);
table = dm_get_live_or_inactive_table(md, param);
if (table) {
@@ -1050,8 +1055,9 @@ static int dev_wait(struct dm_ioctl *param, size_t param_size)
dm_table_put(table);
}
- out:
+out:
dm_put(md);
+
return r;
}
@@ -1186,7 +1192,7 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
up_write(&_hash_lock);
param->flags |= DM_INACTIVE_PRESENT_FLAG;
- r = __dev_status(md, param);
+ __dev_status(md, param);
out:
dm_put(md);
@@ -1196,7 +1202,6 @@ out:
static int table_clear(struct dm_ioctl *param, size_t param_size)
{
- int r;
struct hash_cell *hc;
struct mapped_device *md;
@@ -1216,11 +1221,12 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
- r = __dev_status(hc->md, param);
+ __dev_status(hc->md, param);
md = hc->md;
up_write(&_hash_lock);
dm_put(md);
- return r;
+
+ return 0;
}
/*
@@ -1265,7 +1271,6 @@ static void retrieve_deps(struct dm_table *table,
static int table_deps(struct dm_ioctl *param, size_t param_size)
{
- int r = 0;
struct mapped_device *md;
struct dm_table *table;
@@ -1273,9 +1278,7 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
if (!md)
return -ENXIO;
- r = __dev_status(md, param);
- if (r)
- goto out;
+ __dev_status(md, param);
table = dm_get_live_or_inactive_table(md, param);
if (table) {
@@ -1283,9 +1286,9 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
dm_table_put(table);
}
- out:
dm_put(md);
- return r;
+
+ return 0;
}
/*
@@ -1294,7 +1297,6 @@ static int table_deps(struct dm_ioctl *param, size_t param_size)
*/
static int table_status(struct dm_ioctl *param, size_t param_size)
{
- int r;
struct mapped_device *md;
struct dm_table *table;
@@ -1302,9 +1304,7 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
if (!md)
return -ENXIO;
- r = __dev_status(md, param);
- if (r)
- goto out;
+ __dev_status(md, param);
table = dm_get_live_or_inactive_table(md, param);
if (table) {
@@ -1312,9 +1312,9 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
dm_table_put(table);
}
-out:
dm_put(md);
- return r;
+
+ return 0;
}
/*
@@ -1333,10 +1333,6 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
if (!md)
return -ENXIO;
- r = __dev_status(md, param);
- if (r)
- goto out;
-
if (tmsg < (struct dm_target_msg *) param->data ||
invalid_str(tmsg->message, (void *) param + param_size)) {
DMWARN("Invalid target message parameters.");
@@ -1593,6 +1589,7 @@ static long dm_compat_ctl_ioctl(struct file *file, uint command, ulong u)
#endif
static const struct file_operations _ctl_fops = {
+ .open = nonseekable_open,
.unlocked_ioctl = dm_ctl_ioctl,
.compat_ioctl = dm_compat_ctl_ioctl,
.owner = THIS_MODULE,
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index c097d8a4823d..cc2bdb83f9ad 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -266,7 +266,7 @@ static int chunk_io(struct pstore *ps, void *area, chunk_t chunk, int rw,
*/
static chunk_t area_location(struct pstore *ps, chunk_t area)
{
- return 1 + ((ps->exceptions_per_area + 1) * area);
+ return NUM_SNAPSHOT_HDR_CHUNKS + ((ps->exceptions_per_area + 1) * area);
}
/*
@@ -780,8 +780,8 @@ static int persistent_commit_merge(struct dm_exception_store *store,
* ps->current_area does not get reduced by prepare_merge() until
* after commit_merge() has removed the nr_merged previous exceptions.
*/
- ps->next_free = (area_location(ps, ps->current_area) - 1) +
- (ps->current_committed + 1) + NUM_SNAPSHOT_HDR_CHUNKS;
+ ps->next_free = area_location(ps, ps->current_area) +
+ ps->current_committed + 1;
return 0;
}
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index 195c6cf359f6..d22a8ec523fc 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -13,6 +13,7 @@ source "drivers/media/IR/keymaps/Kconfig"
config IR_NEC_DECODER
tristate "Enable IR raw decoder for the NEC protocol"
depends on IR_CORE
+ select BITREVERSE
default y
---help---
@@ -22,6 +23,7 @@ config IR_NEC_DECODER
config IR_RC5_DECODER
tristate "Enable IR raw decoder for the RC-5 protocol"
depends on IR_CORE
+ select BITREVERSE
default y
---help---
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index 5e2045670004..4bbd45f4284c 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -94,6 +94,7 @@ struct imon_context {
bool display_supported; /* not all controllers do */
bool display_isopen; /* display port has been opened */
+ bool rf_device; /* true if iMON 2.4G LT/DT RF device */
bool rf_isassociating; /* RF remote associating */
bool dev_present_intf0; /* USB device presence, interface 0 */
bool dev_present_intf1; /* USB device presence, interface 1 */
@@ -385,7 +386,7 @@ static int display_open(struct inode *inode, struct file *file)
err("%s: display port is already open", __func__);
retval = -EBUSY;
} else {
- ictx->display_isopen = 1;
+ ictx->display_isopen = true;
file->private_data = ictx;
dev_dbg(ictx->dev, "display port opened\n");
}
@@ -422,7 +423,7 @@ static int display_close(struct inode *inode, struct file *file)
err("%s: display is not open", __func__);
retval = -EIO;
} else {
- ictx->display_isopen = 0;
+ ictx->display_isopen = false;
dev_dbg(ictx->dev, "display port closed\n");
if (!ictx->dev_present_intf0) {
/*
@@ -491,12 +492,12 @@ static int send_packet(struct imon_context *ictx)
}
init_completion(&ictx->tx.finished);
- ictx->tx.busy = 1;
+ ictx->tx.busy = true;
smp_rmb(); /* ensure later readers know we're busy */
retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
if (retval) {
- ictx->tx.busy = 0;
+ ictx->tx.busy = false;
smp_rmb(); /* ensure later readers know we're not busy */
err("%s: error submitting urb(%d)", __func__, retval);
} else {
@@ -682,7 +683,7 @@ static ssize_t store_associate_remote(struct device *d,
return -ENODEV;
mutex_lock(&ictx->lock);
- ictx->rf_isassociating = 1;
+ ictx->rf_isassociating = true;
send_associate_24g(ictx);
mutex_unlock(&ictx->lock);
@@ -950,7 +951,7 @@ static void usb_tx_callback(struct urb *urb)
ictx->tx.status = urb->status;
/* notify waiters that write has finished */
- ictx->tx.busy = 0;
+ ictx->tx.busy = false;
smp_rmb(); /* ensure later readers know we're not busy */
complete(&ictx->tx.finished);
}
@@ -1215,7 +1216,7 @@ static bool imon_mouse_event(struct imon_context *ictx,
{
char rel_x = 0x00, rel_y = 0x00;
u8 right_shift = 1;
- bool mouse_input = 1;
+ bool mouse_input = true;
int dir = 0;
/* newer iMON device PAD or mouse button */
@@ -1246,7 +1247,7 @@ static bool imon_mouse_event(struct imon_context *ictx,
} else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
dir = -1;
} else
- mouse_input = 0;
+ mouse_input = false;
if (mouse_input) {
dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
@@ -1450,7 +1451,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev;
u32 kc;
- bool norelease = 0;
+ bool norelease = false;
int i;
u64 temp_key;
u64 panel_key = 0;
@@ -1465,7 +1466,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
idev = ictx->idev;
/* filter out junk data on the older 0xffdc imon devices */
- if ((buf[0] == 0xff) && (buf[7] == 0xff))
+ if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
return;
/* Figure out what key was pressed */
@@ -1517,7 +1518,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
!(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
len = 8;
imon_pad_to_keys(ictx, buf);
- norelease = 1;
+ norelease = true;
}
if (debug) {
@@ -1580,7 +1581,7 @@ not_input_data:
(buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */
dev_warn(dev, "%s: remote associated refid=%02X\n",
__func__, buf[1]);
- ictx->rf_isassociating = 0;
+ ictx->rf_isassociating = false;
}
}
@@ -1790,9 +1791,9 @@ static bool imon_find_endpoints(struct imon_context *ictx,
int ifnum = iface_desc->desc.bInterfaceNumber;
int num_endpts = iface_desc->desc.bNumEndpoints;
int i, ep_dir, ep_type;
- bool ir_ep_found = 0;
- bool display_ep_found = 0;
- bool tx_control = 0;
+ bool ir_ep_found = false;
+ bool display_ep_found = false;
+ bool tx_control = false;
/*
* Scan the endpoint list and set:
@@ -1808,13 +1809,13 @@ static bool imon_find_endpoints(struct imon_context *ictx,
ep_type == USB_ENDPOINT_XFER_INT) {
rx_endpoint = ep;
- ir_ep_found = 1;
+ ir_ep_found = true;
dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
ep_type == USB_ENDPOINT_XFER_INT) {
tx_endpoint = ep;
- display_ep_found = 1;
+ display_ep_found = true;
dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
}
}
@@ -1835,8 +1836,8 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* newer iMON devices that use control urb instead of interrupt
*/
if (!display_ep_found) {
- tx_control = 1;
- display_ep_found = 1;
+ tx_control = true;
+ display_ep_found = true;
dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
"interface OUT endpoint\n", __func__);
}
@@ -1847,7 +1848,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* and without... :\
*/
if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
- display_ep_found = 0;
+ display_ep_found = false;
dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
}
@@ -1856,7 +1857,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
*/
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
- display_ep_found = 0;
+ display_ep_found = false;
dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
}
@@ -1905,9 +1906,10 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
ictx->dev = dev;
ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
- ictx->dev_present_intf0 = 1;
+ ictx->dev_present_intf0 = true;
ictx->rx_urb_intf0 = rx_urb;
ictx->tx_urb = tx_urb;
+ ictx->rf_device = false;
ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
@@ -1979,7 +1981,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
}
ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
- ictx->dev_present_intf1 = 1;
+ ictx->dev_present_intf1 = true;
ictx->rx_urb_intf1 = rx_urb;
ret = -ENODEV;
@@ -2047,6 +2049,12 @@ static void imon_get_ffdc_type(struct imon_context *ictx)
dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
ictx->display_supported = false;
break;
+ /* iMON 2.4G LT (usb stick), no display, iMON RF */
+ case 0x4e:
+ dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
+ ictx->display_supported = false;
+ ictx->rf_device = true;
+ break;
/* iMON VFD, no IR (does have vol knob tho) */
case 0x35:
dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
@@ -2197,15 +2205,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
goto fail;
}
- if (product == 0xffdc) {
- /* RF products *also* use 0xffdc... sigh... */
- sysfs_err = sysfs_create_group(&interface->dev.kobj,
- &imon_rf_attribute_group);
- if (sysfs_err)
- err("%s: Could not create RF sysfs entries(%d)",
- __func__, sysfs_err);
- }
-
} else {
/* this is the secondary interface on the device */
ictx = imon_init_intf1(interface, first_if_ctx);
@@ -2233,6 +2232,14 @@ static int __devinit imon_probe(struct usb_interface *interface,
imon_set_display_type(ictx, interface);
+ if (product == 0xffdc && ictx->rf_device) {
+ sysfs_err = sysfs_create_group(&interface->dev.kobj,
+ &imon_rf_attribute_group);
+ if (sysfs_err)
+ err("%s: Could not create RF sysfs entries(%d)",
+ __func__, sysfs_err);
+ }
+
if (ictx->display_supported)
imon_init_display(ictx, interface);
}
@@ -2297,7 +2304,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
}
if (ifnum == 0) {
- ictx->dev_present_intf0 = 0;
+ ictx->dev_present_intf0 = false;
usb_kill_urb(ictx->rx_urb_intf0);
input_unregister_device(ictx->idev);
if (ictx->display_supported) {
@@ -2307,7 +2314,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
usb_deregister_dev(interface, &imon_vfd_class);
}
} else {
- ictx->dev_present_intf1 = 0;
+ ictx->dev_present_intf1 = false;
usb_kill_urb(ictx->rx_urb_intf1);
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
input_unregister_device(ictx->touch);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index 9374a006f43d..94a8577e72eb 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -490,11 +490,12 @@ int __ir_input_register(struct input_dev *input_dev,
if (rc < 0)
goto out_table;
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
- rc = ir_raw_event_register(input_dev);
- if (rc < 0)
- goto out_event;
- }
+ if (ir_dev->props)
+ if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
+ rc = ir_raw_event_register(input_dev);
+ if (rc < 0)
+ goto out_event;
+ }
IR_dprintk(1, "Registered input device on %s for %s remote.\n",
driver_name, rc_tab->name);
@@ -530,8 +531,10 @@ void ir_input_unregister(struct input_dev *input_dev)
IR_dprintk(1, "Freed keycode table\n");
del_timer_sync(&ir_dev->timer_keyup);
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
- ir_raw_event_unregister(input_dev);
+ if (ir_dev->props)
+ if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_event_unregister(input_dev);
+
rc_tab = &ir_dev->rc_tab;
rc_tab->size = 0;
kfree(rc_tab->scan);
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index d7da63e16c92..2098dd1488e0 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -221,9 +221,10 @@ int ir_register_class(struct input_dev *input_dev)
if (unlikely(devno < 0))
return devno;
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
- ir_dev->dev.type = &rc_dev_type;
- else
+ if (ir_dev->props) {
+ if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
+ ir_dev->dev.type = &rc_dev_type;
+ } else
ir_dev->dev.type = &ir_raw_dev_type;
ir_dev->dev.class = &ir_input_class;
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
index ec25258a955f..aea649fbcf5a 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/IR/keymaps/Makefile
@@ -6,7 +6,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-avermedia.o \
rc-avermedia-cardbus.o \
rc-avermedia-dvbt.o \
- rc-avermedia-m135a-rm-jx.o \
+ rc-avermedia-m135a.o \
+ rc-avermedia-m733a-rm-k6.o \
rc-avertv-303.o \
rc-behold.o \
rc-behold-columbus.o \
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
deleted file mode 100644
index 101e7ea85941..000000000000
--- a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/*
- * Avermedia M135A with IR model RM-JX
- * The same codes exist on both Positivo (BR) and original IR
- * Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-static struct ir_scancode avermedia_m135a_rm_jx[] = {
- { 0x0200, KEY_POWER2 },
- { 0x022e, KEY_DOT }, /* '.' */
- { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
-
- { 0x0205, KEY_1 },
- { 0x0206, KEY_2 },
- { 0x0207, KEY_3 },
- { 0x0209, KEY_4 },
- { 0x020a, KEY_5 },
- { 0x020b, KEY_6 },
- { 0x020d, KEY_7 },
- { 0x020e, KEY_8 },
- { 0x020f, KEY_9 },
- { 0x0211, KEY_0 },
-
- { 0x0213, KEY_RIGHT }, /* -> or L */
- { 0x0212, KEY_LEFT }, /* <- or R */
-
- { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
- { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
-
- { 0x0303, KEY_CHANNELUP },
- { 0x0302, KEY_CHANNELDOWN },
- { 0x021f, KEY_VOLUMEUP },
- { 0x021e, KEY_VOLUMEDOWN },
- { 0x020c, KEY_ENTER }, /* Full Screen */
-
- { 0x0214, KEY_MUTE },
- { 0x0208, KEY_AUDIO },
-
- { 0x0203, KEY_TEXT }, /* Teletext */
- { 0x0204, KEY_EPG },
- { 0x022b, KEY_TV2 }, /* TV2 or PIP */
-
- { 0x021d, KEY_RED },
- { 0x021c, KEY_YELLOW },
- { 0x0301, KEY_GREEN },
- { 0x0300, KEY_BLUE },
-
- { 0x021a, KEY_PLAYPAUSE },
- { 0x0219, KEY_RECORD },
- { 0x0218, KEY_PLAY },
- { 0x021b, KEY_STOP },
-};
-
-static struct rc_keymap avermedia_m135a_rm_jx_map = {
- .map = {
- .scan = avermedia_m135a_rm_jx,
- .size = ARRAY_SIZE(avermedia_m135a_rm_jx),
- .ir_type = IR_TYPE_NEC,
- .name = RC_MAP_AVERMEDIA_M135A_RM_JX,
- }
-};
-
-static int __init init_rc_map_avermedia_m135a_rm_jx(void)
-{
- return ir_register_map(&avermedia_m135a_rm_jx_map);
-}
-
-static void __exit exit_rc_map_avermedia_m135a_rm_jx(void)
-{
- ir_unregister_map(&avermedia_m135a_rm_jx_map);
-}
-
-module_init(init_rc_map_avermedia_m135a_rm_jx)
-module_exit(exit_rc_map_avermedia_m135a_rm_jx)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a.c b/drivers/media/IR/keymaps/rc-avermedia-m135a.c
new file mode 100644
index 000000000000..e4471fb2ad1e
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-m135a.c
@@ -0,0 +1,147 @@
+/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Avermedia M135A with RM-JX and RM-K6 remote controls
+ *
+ * On Avermedia M135A with IR model RM-JX, the same codes exist on both
+ * Positivo (BR) and original IR, initial version and remote control codes
+ * added by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Positivo also ships Avermedia M135A with model RM-K6, extra control
+ * codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct ir_scancode avermedia_m135a[] = {
+ /* RM-JX */
+ { 0x0200, KEY_POWER2 },
+ { 0x022e, KEY_DOT }, /* '.' */
+ { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
+
+ { 0x0205, KEY_1 },
+ { 0x0206, KEY_2 },
+ { 0x0207, KEY_3 },
+ { 0x0209, KEY_4 },
+ { 0x020a, KEY_5 },
+ { 0x020b, KEY_6 },
+ { 0x020d, KEY_7 },
+ { 0x020e, KEY_8 },
+ { 0x020f, KEY_9 },
+ { 0x0211, KEY_0 },
+
+ { 0x0213, KEY_RIGHT }, /* -> or L */
+ { 0x0212, KEY_LEFT }, /* <- or R */
+
+ { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
+ { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
+
+ { 0x0303, KEY_CHANNELUP },
+ { 0x0302, KEY_CHANNELDOWN },
+ { 0x021f, KEY_VOLUMEUP },
+ { 0x021e, KEY_VOLUMEDOWN },
+ { 0x020c, KEY_ENTER }, /* Full Screen */
+
+ { 0x0214, KEY_MUTE },
+ { 0x0208, KEY_AUDIO },
+
+ { 0x0203, KEY_TEXT }, /* Teletext */
+ { 0x0204, KEY_EPG },
+ { 0x022b, KEY_TV2 }, /* TV2 or PIP */
+
+ { 0x021d, KEY_RED },
+ { 0x021c, KEY_YELLOW },
+ { 0x0301, KEY_GREEN },
+ { 0x0300, KEY_BLUE },
+
+ { 0x021a, KEY_PLAYPAUSE },
+ { 0x0219, KEY_RECORD },
+ { 0x0218, KEY_PLAY },
+ { 0x021b, KEY_STOP },
+
+ /* RM-K6 */
+ { 0x0401, KEY_POWER2 },
+ { 0x0406, KEY_MUTE },
+ { 0x0408, KEY_MODE }, /* TV/FM */
+
+ { 0x0409, KEY_1 },
+ { 0x040a, KEY_2 },
+ { 0x040b, KEY_3 },
+ { 0x040c, KEY_4 },
+ { 0x040d, KEY_5 },
+ { 0x040e, KEY_6 },
+ { 0x040f, KEY_7 },
+ { 0x0410, KEY_8 },
+ { 0x0411, KEY_9 },
+ { 0x044c, KEY_DOT }, /* '.' */
+ { 0x0412, KEY_0 },
+ { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
+
+ { 0x0413, KEY_AUDIO },
+ { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
+ { 0x0441, KEY_HOME },
+ { 0x0442, KEY_BACK },
+ { 0x0447, KEY_UP },
+ { 0x0448, KEY_DOWN },
+ { 0x0449, KEY_LEFT },
+ { 0x044a, KEY_RIGHT },
+ { 0x044b, KEY_OK },
+ { 0x0404, KEY_VOLUMEUP },
+ { 0x0405, KEY_VOLUMEDOWN },
+ { 0x0402, KEY_CHANNELUP },
+ { 0x0403, KEY_CHANNELDOWN },
+
+ { 0x0443, KEY_RED },
+ { 0x0444, KEY_GREEN },
+ { 0x0445, KEY_YELLOW },
+ { 0x0446, KEY_BLUE },
+
+ { 0x0414, KEY_TEXT },
+ { 0x0415, KEY_EPG },
+ { 0x041a, KEY_TV2 }, /* PIP */
+ { 0x041b, KEY_MHP }, /* Snapshot */
+
+ { 0x0417, KEY_RECORD },
+ { 0x0416, KEY_PLAYPAUSE },
+ { 0x0418, KEY_STOP },
+ { 0x0419, KEY_PAUSE },
+
+ { 0x041f, KEY_PREVIOUS },
+ { 0x041c, KEY_REWIND },
+ { 0x041d, KEY_FORWARD },
+ { 0x041e, KEY_NEXT },
+};
+
+static struct rc_keymap avermedia_m135a_map = {
+ .map = {
+ .scan = avermedia_m135a,
+ .size = ARRAY_SIZE(avermedia_m135a),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_M135A,
+ }
+};
+
+static int __init init_rc_map_avermedia_m135a(void)
+{
+ return ir_register_map(&avermedia_m135a_map);
+}
+
+static void __exit exit_rc_map_avermedia_m135a(void)
+{
+ ir_unregister_map(&avermedia_m135a_map);
+}
+
+module_init(init_rc_map_avermedia_m135a)
+module_exit(exit_rc_map_avermedia_m135a)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
new file mode 100644
index 000000000000..cf8d45717cb3
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -0,0 +1,95 @@
+/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller
+ *
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Avermedia M733A with IR model RM-K6
+ * This is the stock remote controller used with Positivo machines with M733A
+ * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct ir_scancode avermedia_m733a_rm_k6[] = {
+ { 0x0401, KEY_POWER2 },
+ { 0x0406, KEY_MUTE },
+ { 0x0408, KEY_MODE }, /* TV/FM */
+
+ { 0x0409, KEY_1 },
+ { 0x040a, KEY_2 },
+ { 0x040b, KEY_3 },
+ { 0x040c, KEY_4 },
+ { 0x040d, KEY_5 },
+ { 0x040e, KEY_6 },
+ { 0x040f, KEY_7 },
+ { 0x0410, KEY_8 },
+ { 0x0411, KEY_9 },
+ { 0x044c, KEY_DOT }, /* '.' */
+ { 0x0412, KEY_0 },
+ { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
+
+ { 0x0413, KEY_AUDIO },
+ { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
+ { 0x0441, KEY_HOME },
+ { 0x0442, KEY_BACK },
+ { 0x0447, KEY_UP },
+ { 0x0448, KEY_DOWN },
+ { 0x0449, KEY_LEFT },
+ { 0x044a, KEY_RIGHT },
+ { 0x044b, KEY_OK },
+ { 0x0404, KEY_VOLUMEUP },
+ { 0x0405, KEY_VOLUMEDOWN },
+ { 0x0402, KEY_CHANNELUP },
+ { 0x0403, KEY_CHANNELDOWN },
+
+ { 0x0443, KEY_RED },
+ { 0x0444, KEY_GREEN },
+ { 0x0445, KEY_YELLOW },
+ { 0x0446, KEY_BLUE },
+
+ { 0x0414, KEY_TEXT },
+ { 0x0415, KEY_EPG },
+ { 0x041a, KEY_TV2 }, /* PIP */
+ { 0x041b, KEY_MHP }, /* Snapshot */
+
+ { 0x0417, KEY_RECORD },
+ { 0x0416, KEY_PLAYPAUSE },
+ { 0x0418, KEY_STOP },
+ { 0x0419, KEY_PAUSE },
+
+ { 0x041f, KEY_PREVIOUS },
+ { 0x041c, KEY_REWIND },
+ { 0x041d, KEY_FORWARD },
+ { 0x041e, KEY_NEXT },
+};
+
+static struct rc_keymap avermedia_m733a_rm_k6_map = {
+ .map = {
+ .scan = avermedia_m733a_rm_k6,
+ .size = ARRAY_SIZE(avermedia_m733a_rm_k6),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_M733A_RM_K6,
+ }
+};
+
+static int __init init_rc_map_avermedia_m733a_rm_k6(void)
+{
+ return ir_register_map(&avermedia_m733a_rm_k6_map);
+}
+
+static void __exit exit_rc_map_avermedia_m733a_rm_k6(void)
+{
+ ir_unregister_map(&avermedia_m733a_rm_k6_map);
+}
+
+module_init(init_rc_map_avermedia_m733a_rm_k6)
+module_exit(exit_rc_map_avermedia_m733a_rm_k6)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index b762e561a6d5..bca07c0bcd01 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -594,7 +594,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id)
int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
{
struct input_dev *input_dev;
- char *ir_codes = NULL;
+ char *ir_codes = RC_MAP_DM1105_NEC;
int err = -ENOMEM;
input_dev = input_allocate_device();
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index f6dac2bb0ac6..6c3a8a06ccab 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -351,6 +351,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
const u8 *ts, *ts_end, *from_where = NULL;
u8 ts_remain = 0, how_much = 0, new_ts = 1;
struct ethhdr *ethh = NULL;
+ bool error = false;
#ifdef ULE_DEBUG
/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
@@ -460,10 +461,16 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
- dev_kfree_skb( priv->ule_skb );
+ error = true;
+ dev_kfree_skb(priv->ule_skb);
+ }
+
+ if (error || priv->ule_sndu_remain) {
dev->stats.rx_errors++;
dev->stats.rx_frame_errors++;
+ error = false;
}
+
reset_ule(priv);
priv->need_pusi = 1;
continue;
@@ -535,6 +542,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
from_where += 2;
}
+ priv->ule_sndu_remain = priv->ule_sndu_len + 2;
/*
* State of current TS:
* ts_remain (remaining bytes in the current TS cell)
@@ -544,6 +552,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
*/
switch (ts_remain) {
case 1:
+ priv->ule_sndu_remain--;
priv->ule_sndu_type = from_where[0] << 8;
priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
ts_remain -= 1; from_where += 1;
@@ -557,6 +566,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
default: /* complete ULE header is present in current TS. */
/* Extract ULE type field. */
if (priv->ule_sndu_type_1) {
+ priv->ule_sndu_type_1 = 0;
priv->ule_sndu_type |= from_where[0];
from_where += 1; /* points to payload start. */
ts_remain -= 1;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e5f91f16ffa4..553b48ac1919 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -76,6 +76,7 @@ config DVB_USB_DIB0700
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
@@ -134,6 +135,7 @@ config DVB_USB_M920X
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@@ -264,7 +266,7 @@ config DVB_USB_DW2102
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
select DVB_ZL10039 if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 0eb490889162..11e9e85dac86 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -1026,8 +1026,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
- &cxusb_dualdig4_rev2_config) < 0)
+ &cxusb_dualdig4_rev2_config) < 0) {
+ printk(KERN_WARNING "Unable to enumerate dib7000p\n");
return -ENODEV;
+ }
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
&cxusb_dualdig4_rev2_config);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 085c4e457e0e..b4afe6f8ed19 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -198,6 +198,7 @@
#define USB_PID_AVERMEDIA_A850 0x850a
#define USB_PID_AVERMEDIA_A805 0xa805
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
+#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 20ca9d9ee99b..a6de489a6a39 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -29,6 +29,8 @@
#include "tda826x.h"
#include "tda10086.h"
+#include "tda1002x.h"
+#include "tda827x.h"
#include "lnbp21.h"
/* debug */
@@ -150,7 +152,17 @@ static struct tda10086_config tda10086_config = {
.xtal_freq = TDA10086_XTAL_16M,
};
-static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
+static struct tda10023_config tda10023_config = {
+ .demod_address = 0x0c,
+ .invert = 0,
+ .xtal = 16000000,
+ .pll_m = 11,
+ .pll_p = 3,
+ .pll_n = 1,
+ .deltaf = 0xa511,
+};
+
+static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
{
if (usb_set_interface(adap->dev->udev,0,3) < 0)
err("set interface to alts=3 failed");
@@ -163,7 +175,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
+static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
+{
+ if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
+ err("set interface to alts=3 failed");
+ if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
+ deb_info("TDA10023 attach failed\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
+{
+ if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
+ printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
{
if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
deb_info("TDA8263 attach failed\n");
@@ -180,6 +212,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties ttusb2_properties;
static struct dvb_usb_device_properties ttusb2_properties_s2400;
+static struct dvb_usb_device_properties ttusb2_properties_ct3650;
static int ttusb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -187,6 +220,8 @@ static int ttusb2_probe(struct usb_interface *intf,
if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
THIS_MODULE, NULL, adapter_nr))
return 0;
return -ENODEV;
@@ -197,6 +232,8 @@ static struct usb_device_id ttusb2_table [] = {
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
{ USB_DEVICE(USB_VID_TECHNOTREND,
USB_PID_TECHNOTREND_CONNECT_S2400) },
+ { USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_CT3650) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -214,8 +251,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
{
.streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
- .frontend_attach = ttusb2_frontend_attach,
- .tuner_attach = ttusb2_tuner_attach,
+ .frontend_attach = ttusb2_frontend_tda10086_attach,
+ .tuner_attach = ttusb2_tuner_tda826x_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
@@ -266,8 +303,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
{
.streaming_ctrl = NULL,
- .frontend_attach = ttusb2_frontend_attach,
- .tuner_attach = ttusb2_tuner_attach,
+ .frontend_attach = ttusb2_frontend_tda10086_attach,
+ .tuner_attach = ttusb2_tuner_tda826x_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
@@ -301,6 +338,52 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
}
};
+static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct ttusb2_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = NULL,
+
+ .frontend_attach = ttusb2_frontend_tda10023_attach,
+ .tuner_attach = ttusb2_tuner_tda827x_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 4,
+ .framesize = 940,
+ .interval = 1,
+ }
+ }
+ }
+ },
+ },
+
+ .power_ctrl = ttusb2_power_ctrl,
+ .identify_state = ttusb2_identify_state,
+
+ .i2c_algo = &ttusb2_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Technotrend TT-connect CT-3650",
+ .warm_ids = { &ttusb2_table[3], NULL },
+ },
+ }
+};
+
static struct usb_driver ttusb2_driver = {
.name = "dvb_usb_ttusb2",
.probe = ttusb2_probe,
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 26333b4f4d3e..b34ca7afb0e6 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -58,7 +58,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
num = hpsb_iso_n_ready(iso);
if (!fdtv) {
- dev_err(fdtv->device, "received at unknown iso channel\n");
+ pr_err("received at unknown iso channel\n");
goto out;
}
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 68dba3a4b4da..29cdbfe36852 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -567,30 +567,6 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* ----------------------------------------------------------------------- */
-static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- /* Not yet implemented */
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int au8522_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -772,8 +748,6 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
static const struct v4l2_subdev_video_ops au8522_video_ops = {
.s_routing = au8522_s_video_routing,
- .g_fmt = au8522_g_fmt,
- .s_fmt = au8522_s_fmt,
.s_stream = au8522_s_stream,
};
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index 78001e8bcdb7..fc61d9230db8 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -969,15 +969,12 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
dprintk("%s\n", __func__);
/* allocate memory for the internal state */
- state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
if (state == NULL) {
printk(KERN_ERR "Unable to kmalloc\n");
goto error2;
}
- /* setup the state */
- memset(state, 0, sizeof(struct ds3000_state));
-
state->config = config;
state->i2c = i2c;
state->prevUCBS2 = 0;
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index 42591ce1aaad..f36cab12bdc7 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -303,7 +303,10 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
static int stv6110x_sleep(struct dvb_frontend *fe)
{
- return stv6110x_set_mode(fe, TUNER_SLEEP);
+ if (fe->tuner_priv)
+ return stv6110x_set_mode(fe, TUNER_SLEEP);
+
+ return 0;
}
static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
index 692c3e226e83..4692a41ad95b 100644
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -217,6 +217,19 @@ static struct ngene_info ngene_info_cineS2v5 = {
.fw_version = 15,
};
+static struct ngene_info ngene_info_duoFlexS2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Digital Devices DuoFlex S2 miniPCIe",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0a, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 15,
+};
+
static struct ngene_info ngene_info_m780 = {
.type = NGENE_APP,
.name = "Aver M780 ATSC/QAM-B",
@@ -256,6 +269,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+ NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),
+ NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),
NGENE_ID(0x1461, 0x062e, ngene_info_m780),
{0}
};
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index c8b4dfa0ab5f..4caeb163a666 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -53,8 +53,6 @@ MODULE_PARM_DESC(debug, "Print debugging information.");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define COMMAND_TIMEOUT_WORKAROUND
-
#define dprintk if (debug) printk
#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
@@ -147,24 +145,24 @@ static void demux_tasklet(unsigned long data)
} else {
if (chan->HWState == HWSTATE_RUN) {
u32 Flags = 0;
+ IBufferExchange *exch1 = chan->pBufferExchange;
+ IBufferExchange *exch2 = chan->pBufferExchange2;
if (Cur->ngeneBuffer.SR.Flags & 0x01)
Flags |= BEF_EVEN_FIELD;
if (Cur->ngeneBuffer.SR.Flags & 0x20)
Flags |= BEF_OVERFLOW;
- if (chan->pBufferExchange)
- chan->pBufferExchange(chan,
- Cur->Buffer1,
- chan->
- Capture1Length,
- Cur->ngeneBuffer.
- SR.Clock, Flags);
- if (chan->pBufferExchange2)
- chan->pBufferExchange2(chan,
- Cur->Buffer2,
- chan->
- Capture2Length,
- Cur->ngeneBuffer.
- SR.Clock, Flags);
+ spin_unlock_irq(&chan->state_lock);
+ if (exch1)
+ exch1(chan, Cur->Buffer1,
+ chan->Capture1Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ if (exch2)
+ exch2(chan, Cur->Buffer2,
+ chan->Capture2Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ spin_lock_irq(&chan->state_lock);
} else if (chan->HWState != HWSTATE_STOP)
chan->HWState = HWSTATE_RUN;
}
@@ -572,11 +570,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream,
u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
u16 BsSDO = 0x9B00;
- /* down(&dev->stream_mutex); */
- while (down_trylock(&dev->stream_mutex)) {
- printk(KERN_INFO DEVICE_NAME ": SC locked\n");
- msleep(1);
- }
+ down(&dev->stream_mutex);
memset(&com, 0, sizeof(com));
com.cmd.hdr.Opcode = CMD_CONTROL;
com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
@@ -1252,14 +1246,17 @@ static int ngene_load_firm(struct ngene *dev)
version = 15;
size = 23466;
fw_name = "ngene_15.fw";
+ dev->cmd_timeout_workaround = true;
break;
case 16:
size = 23498;
fw_name = "ngene_16.fw";
+ dev->cmd_timeout_workaround = true;
break;
case 17:
size = 24446;
fw_name = "ngene_17.fw";
+ dev->cmd_timeout_workaround = true;
break;
}
@@ -1299,11 +1296,16 @@ static void ngene_stop(struct ngene *dev)
ngwritel(0, NGENE_EVENT);
ngwritel(0, NGENE_EVENT_HI);
free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
}
static int ngene_start(struct ngene *dev)
{
int stat;
+ unsigned long flags;
int i;
pci_set_master(dev->pci_dev);
@@ -1333,6 +1335,28 @@ static int ngene_start(struct ngene *dev)
if (stat < 0)
goto fail;
+#ifdef CONFIG_PCI_MSI
+ /* enable MSI if kernel and card support it */
+ if (pci_msi_enabled() && dev->card_info->msi_supported) {
+ ngwritel(0, NGENE_INT_ENABLE);
+ free_irq(dev->pci_dev->irq, dev);
+ stat = pci_enable_msi(dev->pci_dev);
+ if (stat) {
+ printk(KERN_INFO DEVICE_NAME
+ ": MSI not available\n");
+ flags = IRQF_SHARED;
+ } else {
+ flags = 0;
+ dev->msi_enabled = true;
+ }
+ stat = request_irq(dev->pci_dev->irq, irq_handler,
+ flags, "nGene", dev);
+ if (stat < 0)
+ goto fail2;
+ ngwritel(1, NGENE_INT_ENABLE);
+ }
+#endif
+
stat = ngene_i2c_init(dev, 0);
if (stat < 0)
goto fail;
@@ -1358,10 +1382,18 @@ static int ngene_start(struct ngene *dev)
bconf = BUFFER_CONFIG_3333;
stat = ngene_command_config_buf(dev, bconf);
}
- return stat;
+ if (!stat)
+ return stat;
+
+ /* otherwise error: fall through */
fail:
ngwritel(0, NGENE_INT_ENABLE);
free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+fail2:
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
return stat;
}
@@ -1379,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan)
struct ngene_info *ni = dev->card_info;
int io = ni->io_type[chan->number];
-#ifdef COMMAND_TIMEOUT_WORKAROUND
- if (chan->running)
+ if (chan->dev->cmd_timeout_workaround && chan->running)
set_transfer(chan, 0);
-#endif
tasklet_kill(&chan->demux_tasklet);
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c
index 96013eb353cd..48f980b21d66 100644
--- a/drivers/media/dvb/ngene/ngene-dvb.c
+++ b/drivers/media/dvb/ngene/ngene-dvb.c
@@ -37,15 +37,12 @@
#include <linux/pci.h>
#include <linux/smp_lock.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include "ngene.h"
-#define COMMAND_TIMEOUT_WORKAROUND
-
/****************************************************************************/
/* COMMAND API interface ****************************************************/
@@ -69,9 +66,7 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
struct ngene_channel *chan = priv;
-#ifdef COMMAND_TIMEOUT_WORKAROUND
if (chan->users > 0)
-#endif
dvb_dmx_swfilter(&chan->demux, buf, len);
return NULL;
}
@@ -106,11 +101,8 @@ int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct ngene_channel *chan = dvbdmx->priv;
if (chan->users == 0) {
-#ifdef COMMAND_TIMEOUT_WORKAROUND
- if (!chan->running)
-#endif
+ if (!chan->dev->cmd_timeout_workaround || !chan->running)
set_transfer(chan, 1);
- /* msleep(10); */
}
return ++chan->users;
@@ -124,9 +116,8 @@ int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (--chan->users)
return chan->users;
-#ifndef COMMAND_TIMEOUT_WORKAROUND
- set_transfer(chan, 0);
-#endif
+ if (!chan->dev->cmd_timeout_workaround)
+ set_transfer(chan, 0);
return 0;
}
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
index 2ef54ca6badd..477fe0aade86 100644
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ b/drivers/media/dvb/ngene/ngene-i2c.c
@@ -39,7 +39,6 @@
#include <linux/pci_ids.h>
#include <linux/smp_lock.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
index 676fcbb79026..8fb4200f83f8 100644
--- a/drivers/media/dvb/ngene/ngene.h
+++ b/drivers/media/dvb/ngene/ngene.h
@@ -725,6 +725,8 @@ struct ngene {
u32 device_version;
u32 fw_interface_version;
u32 icounts;
+ bool msi_enabled;
+ bool cmd_timeout_workaround;
u8 *CmdDoneByte;
int BootFirmware;
@@ -797,6 +799,7 @@ struct ngene_info {
#define NGENE_VBOX_V2 7
int fw_version;
+ bool msi_supported;
char *name;
int io_type[MAX_STREAM];
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index d8d4214fd65f..32a7ec65ec42 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -68,13 +68,14 @@ config DVB_BUDGET
select DVB_VES1820 if !DVB_FE_CUSTOMISE
select DVB_L64781 if !DVB_FE_CUSTOMISE
select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+ select DVB_STV090x if !DVB_FE_CUSTOMISE
+ select DVB_STV6110x if !DVB_FE_CUSTOMISE
help
Support for simple SAA7146 based DVB cards (so called Budget-
or Nova-PCI cards) without onboard MPEG2 decoder, and without
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 461714396331..13ac9e3ab121 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -215,6 +215,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
break;
case 0x1010:
case 0x1017:
+ case 0x1019:
case 0x101a:
/* for the Technotrend 1500 bundled remote */
ir_codes = RC_MAP_TT_1500;
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index a5844d08d8b7..67a4ec8768a6 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -482,7 +482,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
cancel_work_sync(&radio->radio_work);
video_unregister_device(radio->videodev);
kfree(radio);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ad9e6f9c22e9..a26ded127009 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -646,7 +646,7 @@ config VIDEO_PMS
config VIDEO_BWQCAM
tristate "Quickcam BW Video For Linux"
- depends on PARPORT && VIDEO_V4L1
+ depends on PARPORT && VIDEO_V4L2
help
Say Y have if you the black and white version of the QuickCam
camera. See the next option for the color version.
@@ -656,7 +656,7 @@ config VIDEO_BWQCAM
config VIDEO_CQCAM
tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1
+ depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
help
This is the video4linux driver for the colour version of the
Connectix QuickCam. If you have one of these cameras, say Y here,
@@ -853,6 +853,16 @@ config VIDEO_CAFE_CCIC
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_VIA_CAMERA
+ tristate "VIAFB camera controller support"
+ depends on FB_VIA
+ select VIDEOBUF_DMA_SG
+ select VIDEO_OV7670
+ help
+ Driver support for the integrated camera controller in VIA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
config SOC_CAMERA
tristate "SoC camera support"
depends on VIDEO_V4L2 && HAS_DMA && I2C
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index cc93859d3164..47fa0c095e31 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -126,6 +126,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 35390d4717b9..1573392f74bd 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/ak881x.h>
@@ -141,7 +142,7 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
return ak881x_try_g_mbus_fmt(sd, mf);
}
-static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index,
+static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 3c9e754d73a0..935e0c9a9674 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -66,19 +66,58 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/parport.h>
#include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
-
-#include "bw-qcam.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+/* One from column A... */
+#define QC_NOTSET 0
+#define QC_UNIDIR 1
+#define QC_BIDIR 2
+#define QC_SERIAL 3
+
+/* ... and one from column B */
+#define QC_ANY 0x00
+#define QC_FORCE_UNIDIR 0x10
+#define QC_FORCE_BIDIR 0x20
+#define QC_FORCE_SERIAL 0x30
+/* in the port_mode member */
+
+#define QC_MODE_MASK 0x07
+#define QC_FORCE_MASK 0x70
+
+#define MAX_HEIGHT 243
+#define MAX_WIDTH 336
+
+/* Bit fields for status flags */
+#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */
+
+struct qcam {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct pardevice *pdev;
+ struct parport *pport;
+ struct mutex lock;
+ int width, height;
+ int bpp;
+ int mode;
+ int contrast, brightness, whitebal;
+ int port_mode;
+ int transfer_scale;
+ int top, left;
+ int status;
+ unsigned int saved_bits;
+ unsigned long in_use;
+};
static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */
static unsigned int yieldlines = 4; /* Yield after this many during capture */
@@ -93,22 +132,26 @@ module_param(video_nr, int, 0);
* immediately attempt to initialize qcam */
module_param(force_init, int, 0);
-static inline int read_lpstatus(struct qcam_device *q)
+#define MAX_CAMS 4
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline int read_lpstatus(struct qcam *q)
{
return parport_read_status(q->pport);
}
-static inline int read_lpdata(struct qcam_device *q)
+static inline int read_lpdata(struct qcam *q)
{
return parport_read_data(q->pport);
}
-static inline void write_lpdata(struct qcam_device *q, int d)
+static inline void write_lpdata(struct qcam *q, int d)
{
parport_write_data(q->pport, d);
}
-static inline void write_lpcontrol(struct qcam_device *q, int d)
+static void write_lpcontrol(struct qcam *q, int d)
{
if (d & 0x20) {
/* Set bidirectional mode to reverse (data in) */
@@ -124,126 +167,11 @@ static inline void write_lpcontrol(struct qcam_device *q, int d)
parport_write_control(q->pport, d);
}
-static int qc_waithand(struct qcam_device *q, int val);
-static int qc_command(struct qcam_device *q, int command);
-static int qc_readparam(struct qcam_device *q);
-static int qc_setscanmode(struct qcam_device *q);
-static int qc_readbytes(struct qcam_device *q, char buffer[]);
-
-static struct video_device qcam_template;
-
-static int qc_calibrate(struct qcam_device *q)
-{
- /*
- * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
- * The white balance is an individiual value for each
- * quickcam.
- */
-
- int value;
- int count = 0;
-
- qc_command(q, 27); /* AutoAdjustOffset */
- qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
-
- /* GetOffset (33) will read 255 until autocalibration */
- /* is finished. After that, a value of 1-254 will be */
- /* returned. */
-
- do {
- qc_command(q, 33);
- value = qc_readparam(q);
- mdelay(1);
- schedule();
- count++;
- } while (value == 0xff && count < 2048);
-
- q->whitebal = value;
- return value;
-}
-
-/* Initialize the QuickCam driver control structure. This is where
- * defaults are set for people who don't have a config file.*/
-
-static struct qcam_device *qcam_init(struct parport *port)
-{
- struct qcam_device *q;
-
- q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
- if (q == NULL)
- return NULL;
-
- q->pport = port;
- q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
- NULL, 0, NULL);
- if (q->pdev == NULL) {
- printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
- port->name);
- kfree(q);
- return NULL;
- }
-
- memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
- mutex_init(&q->lock);
-
- q->port_mode = (QC_ANY | QC_NOTSET);
- q->width = 320;
- q->height = 240;
- q->bpp = 4;
- q->transfer_scale = 2;
- q->contrast = 192;
- q->brightness = 180;
- q->whitebal = 105;
- q->top = 1;
- q->left = 14;
- q->mode = -1;
- q->status = QC_PARAM_CHANGE;
- return q;
-}
-
-
-/* qc_command is probably a bit of a misnomer -- it's used to send
- * bytes *to* the camera. Generally, these bytes are either commands
- * or arguments to commands, so the name fits, but it still bugs me a
- * bit. See the documentation for a list of commands. */
-
-static int qc_command(struct qcam_device *q, int command)
-{
- int n1, n2;
- int cmd;
-
- write_lpdata(q, command);
- write_lpcontrol(q, 6);
-
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
-
-static int qc_readparam(struct qcam_device *q)
-{
- int n1, n2;
- int cmd;
-
- write_lpcontrol(q, 6);
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
/* qc_waithand busy-waits for a handshake signal from the QuickCam.
* Almost all communication with the camera requires handshaking. */
-static int qc_waithand(struct qcam_device *q, int val)
+static int qc_waithand(struct qcam *q, int val)
{
int status;
int runs = 0;
@@ -286,7 +214,7 @@ static int qc_waithand(struct qcam_device *q, int val)
* (bit 3 of status register). It also returns the last value read,
* since this data is useful. */
-static unsigned int qc_waithand2(struct qcam_device *q, int val)
+static unsigned int qc_waithand2(struct qcam *q, int val)
{
unsigned int status;
int runs = 0;
@@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
return status;
}
+/* qc_command is probably a bit of a misnomer -- it's used to send
+ * bytes *to* the camera. Generally, these bytes are either commands
+ * or arguments to commands, so the name fits, but it still bugs me a
+ * bit. See the documentation for a list of commands. */
+
+static int qc_command(struct qcam *q, int command)
+{
+ int n1, n2;
+ int cmd;
+
+ write_lpdata(q, command);
+ write_lpcontrol(q, 6);
+
+ n1 = qc_waithand(q, 1);
+
+ write_lpcontrol(q, 0xe);
+ n2 = qc_waithand(q, 0);
+
+ cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+ return cmd;
+}
+
+static int qc_readparam(struct qcam *q)
+{
+ int n1, n2;
+ int cmd;
+
+ write_lpcontrol(q, 6);
+ n1 = qc_waithand(q, 1);
+
+ write_lpcontrol(q, 0xe);
+ n2 = qc_waithand(q, 0);
+
+ cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+ return cmd;
+}
+
/* Try to detect a QuickCam. It appears to flash the upper 4 bits of
the status register at 5-10 Hz. This is only used in the autoprobe
@@ -317,7 +282,7 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
almost completely safe, while their method screws up my printer if
I plug it in before the camera. */
-static int qc_detect(struct qcam_device *q)
+static int qc_detect(struct qcam *q)
{
int reg, lastreg;
int count = 0;
@@ -358,41 +323,6 @@ static int qc_detect(struct qcam_device *q)
}
}
-
-/* Reset the QuickCam. This uses the same sequence the Windows
- * QuickPic program uses. Someone with a bi-directional port should
- * check that bi-directional mode is detected right, and then
- * implement bi-directional mode in qc_readbyte(). */
-
-static void qc_reset(struct qcam_device *q)
-{
- switch (q->port_mode & QC_FORCE_MASK) {
- case QC_FORCE_UNIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
-
- case QC_FORCE_BIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- break;
-
- case QC_ANY:
- write_lpcontrol(q, 0x20);
- write_lpdata(q, 0x75);
-
- if (read_lpdata(q) != 0x75)
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- else
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
- }
-
- write_lpcontrol(q, 0xb);
- udelay(250);
- write_lpcontrol(q, 0xe);
- qc_setscanmode(q); /* in case port_mode changed */
-}
-
-
/* Decide which scan mode to use. There's no real requirement that
* the scanmode match the resolution in q->height and q-> width -- the
* camera takes the picture at the resolution specified in the
@@ -402,7 +332,7 @@ static void qc_reset(struct qcam_device *q)
* returned. If the scan is smaller, then the rest of the image
* returned contains garbage. */
-static int qc_setscanmode(struct qcam_device *q)
+static int qc_setscanmode(struct qcam *q)
{
int old_mode = q->mode;
@@ -442,10 +372,45 @@ static int qc_setscanmode(struct qcam_device *q)
}
+/* Reset the QuickCam. This uses the same sequence the Windows
+ * QuickPic program uses. Someone with a bi-directional port should
+ * check that bi-directional mode is detected right, and then
+ * implement bi-directional mode in qc_readbyte(). */
+
+static void qc_reset(struct qcam *q)
+{
+ switch (q->port_mode & QC_FORCE_MASK) {
+ case QC_FORCE_UNIDIR:
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+ break;
+
+ case QC_FORCE_BIDIR:
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+ break;
+
+ case QC_ANY:
+ write_lpcontrol(q, 0x20);
+ write_lpdata(q, 0x75);
+
+ if (read_lpdata(q) != 0x75)
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+ else
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+ break;
+ }
+
+ write_lpcontrol(q, 0xb);
+ udelay(250);
+ write_lpcontrol(q, 0xe);
+ qc_setscanmode(q); /* in case port_mode changed */
+}
+
+
+
/* Reset the QuickCam and program for brightness, contrast,
* white-balance, and resolution. */
-static void qc_set(struct qcam_device *q)
+static void qc_set(struct qcam *q)
{
int val;
int val2;
@@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q)
the supplied buffer. It returns the number of bytes read,
or -1 on error. */
-static inline int qc_readbytes(struct qcam_device *q, char buffer[])
+static inline int qc_readbytes(struct qcam *q, char buffer[])
{
int ret = 1;
unsigned int hi, lo;
@@ -590,7 +555,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
* n=2^(bit depth)-1. Ask me for more details if you don't understand
* this. */
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
{
int i, j, k, yield;
int bytes;
@@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void *priv,
+ struct v4l2_capability *vcap)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
- strcpy(b->name, "Quickcam");
- b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 320;
- b->maxheight = 240;
- b->minwidth = 80;
- b->minheight = 60;
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- /* Good question.. its composite or SVHS so.. */
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Camera");
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
- if (v->tuner)
- return -EINVAL;
- strcpy(v->name, "Format");
- v->rangelow = 0;
- v->rangehigh = 0;
- v->flags = 0;
- v->mode = VIDEO_MODE_AUTO;
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
- if (v->tuner)
- return -EINVAL;
- if (v->mode != VIDEO_MODE_AUTO)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- p->colour = 0x8000;
- p->hue = 0x8000;
- p->brightness = qcam->brightness << 8;
- p->contrast = qcam->contrast << 8;
- p->whiteness = qcam->whitebal << 8;
- p->depth = qcam->bpp;
- p->palette = VIDEO_PALETTE_GREY;
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- if (p->palette != VIDEO_PALETTE_GREY)
- return -EINVAL;
- if (p->depth != 4 && p->depth != 6)
- return -EINVAL;
-
- /*
- * Now load the camera.
- */
-
- qcam->brightness = p->brightness >> 8;
- qcam->contrast = p->contrast >> 8;
- qcam->whitebal = p->whiteness >> 8;
- qcam->bpp = p->depth;
-
- mutex_lock(&qcam->lock);
- qc_setscanmode(qcam);
- mutex_unlock(&qcam->lock);
- qcam->status |= QC_PARAM_CHANGE;
+ struct qcam *qcam = video_drvdata(file);
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height < 60 || vw->height > 240)
- return -EINVAL;
- if (vw->width < 80 || vw->width > 320)
- return -EINVAL;
-
- qcam->width = 320;
- qcam->height = 240;
- qcam->transfer_scale = 4;
-
- if (vw->width >= 160 && vw->height >= 120)
- qcam->transfer_scale = 2;
- if (vw->width >= 320 && vw->height >= 240) {
- qcam->width = 320;
- qcam->height = 240;
- qcam->transfer_scale = 1;
- }
- mutex_lock(&qcam->lock);
- qc_setscanmode(qcam);
- mutex_unlock(&qcam->lock);
+ strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+ strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
+ strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+ vcap->version = KERNEL_VERSION(0, 0, 2);
+ vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ return 0;
+}
- /* We must update the camera before we grab. We could
- just have changed the grab size */
- qcam->status |= QC_PARAM_CHANGE;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ if (vin->index > 0)
+ return -EINVAL;
+ strlcpy(vin->name, "Camera", sizeof(vin->name));
+ vin->type = V4L2_INPUT_TYPE_CAMERA;
+ vin->audioset = 0;
+ vin->tuner = 0;
+ vin->std = 0;
+ vin->status = 0;
+ return 0;
+}
- /* Ok we figured out what to use from our wide choice */
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+ *inp = 0;
+ return 0;
+}
- memset(vw, 0, sizeof(*vw));
- vw->width = qcam->width / qcam->transfer_scale;
- vw->height = qcam->height / qcam->transfer_scale;
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+ case V4L2_CID_GAMMA:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
+ }
+ return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = qcam->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = qcam->contrast;
+ break;
+ case V4L2_CID_GAMMA:
+ ctrl->value = qcam->whitebal;
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -EINVAL;
+ break;
}
+ return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->value;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ qc_setscanmode(qcam);
+ qcam->status |= QC_PARAM_CHANGE;
+ }
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
+
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ pix->width = qcam->width / qcam->transfer_scale;
+ pix->height = qcam->height / qcam->transfer_scale;
+ pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = qcam->width;
+ pix->sizeimage = qcam->width * qcam->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ if (pix->height <= 60 || pix->width <= 80) {
+ pix->height = 60;
+ pix->width = 80;
+ } else if (pix->height <= 120 || pix->width <= 160) {
+ pix->height = 120;
+ pix->width = 160;
+ } else {
+ pix->height = 240;
+ pix->width = 320;
+ }
+ if (pix->pixelformat != V4L2_PIX_FMT_Y4 &&
+ pix->pixelformat != V4L2_PIX_FMT_Y6)
+ pix->pixelformat = V4L2_PIX_FMT_Y4;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width;
+ pix->sizeimage = pix->width * pix->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+ if (ret)
+ return ret;
+ qcam->width = 320;
+ qcam->height = 240;
+ if (pix->height == 60)
+ qcam->transfer_scale = 4;
+ else if (pix->height == 120)
+ qcam->transfer_scale = 2;
+ else
+ qcam->transfer_scale = 1;
+ if (pix->pixelformat == V4L2_PIX_FMT_Y6)
+ qcam->bpp = 6;
+ else
+ qcam->bpp = 4;
+
+ mutex_lock(&qcam->lock);
+ qc_setscanmode(qcam);
+ /* We must update the camera before we grab. We could
+ just have changed the grab size */
+ qcam->status |= QC_PARAM_CHANGE;
+ mutex_unlock(&qcam->lock);
return 0;
}
-static long qcam_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
- return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
+ { 0, 0, 0, 0 }
+ },
+ { 0, 0, 0,
+ "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
+ { 0, 0, 0, 0 }
+ },
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (fmt->index > 1)
+ return -EINVAL;
+
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
}
static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct video_device *v = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)v;
+ struct qcam *qcam = video_drvdata(file);
int len;
parport_claim_or_block(qcam->pdev);
@@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct file *file)
+static const struct v4l2_file_operations qcam_fops = {
+ .owner = THIS_MODULE,
+ .ioctl = video_ioctl2,
+ .read = qcam_read,
+};
+
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+ .vidioc_querycap = qcam_querycap,
+ .vidioc_g_input = qcam_g_input,
+ .vidioc_s_input = qcam_s_input,
+ .vidioc_enum_input = qcam_enum_input,
+ .vidioc_queryctrl = qcam_queryctrl,
+ .vidioc_g_ctrl = qcam_g_ctrl,
+ .vidioc_s_ctrl = qcam_s_ctrl,
+ .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
+};
+
+/* Initialize the QuickCam driver control structure. This is where
+ * defaults are set for people who don't have a config file.*/
+
+static struct qcam *qcam_init(struct parport *port)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
+
+ qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
+ if (qcam == NULL)
+ return NULL;
+
+ v4l2_dev = &qcam->v4l2_dev;
+ strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name));
- return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+ if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ return NULL;
+ }
+
+ qcam->pport = port;
+ qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
+ NULL, 0, NULL);
+ if (qcam->pdev == NULL) {
+ v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ kfree(qcam);
+ return NULL;
+ }
+
+ strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
+ qcam->vdev.v4l2_dev = v4l2_dev;
+ qcam->vdev.fops = &qcam_fops;
+ qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+ qcam->vdev.release = video_device_release_empty;
+ video_set_drvdata(&qcam->vdev, qcam);
+
+ mutex_init(&qcam->lock);
+
+ qcam->port_mode = (QC_ANY | QC_NOTSET);
+ qcam->width = 320;
+ qcam->height = 240;
+ qcam->bpp = 4;
+ qcam->transfer_scale = 2;
+ qcam->contrast = 192;
+ qcam->brightness = 180;
+ qcam->whitebal = 105;
+ qcam->top = 1;
+ qcam->left = 14;
+ qcam->mode = -1;
+ qcam->status = QC_PARAM_CHANGE;
+ return qcam;
}
-static int qcam_exclusive_release(struct file *file)
+static int qc_calibrate(struct qcam *q)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ /*
+ * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
+ * The white balance is an individual value for each
+ * quickcam.
+ */
- clear_bit(0, &qcam->in_use);
- return 0;
-}
+ int value;
+ int count = 0;
-static const struct v4l2_file_operations qcam_fops = {
- .owner = THIS_MODULE,
- .open = qcam_exclusive_open,
- .release = qcam_exclusive_release,
- .ioctl = qcam_ioctl,
- .read = qcam_read,
-};
-static struct video_device qcam_template = {
- .name = "Connectix Quickcam",
- .fops = &qcam_fops,
- .release = video_device_release_empty,
-};
+ qc_command(q, 27); /* AutoAdjustOffset */
+ qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
-#define MAX_CAMS 4
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
+ /* GetOffset (33) will read 255 until autocalibration */
+ /* is finished. After that, a value of 1-254 will be */
+ /* returned. */
+
+ do {
+ qc_command(q, 33);
+ value = qc_readparam(q);
+ mdelay(1);
+ schedule();
+ count++;
+ } while (value == 0xff && count < 2048);
+
+ q->whitebal = value;
+ return value;
+}
static int init_bwqcam(struct parport *port)
{
- struct qcam_device *qcam;
+ struct qcam *qcam;
if (num_cams == MAX_CAMS) {
printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
@@ -919,7 +988,7 @@ static int init_bwqcam(struct parport *port)
parport_release(qcam->pdev);
- printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
+ v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name);
if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
parport_unregister_device(qcam->pdev);
@@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port)
return 0;
}
-static void close_bwqcam(struct qcam_device *qcam)
+static void close_bwqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
parport_unregister_device(qcam->pdev);
@@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port)
{
int i;
for (i = 0; i < num_cams; i++) {
- struct qcam_device *qcam = qcams[i];
+ struct qcam *qcam = qcams[i];
if (qcam && qcam->pdev->port == port) {
qcams[i] = NULL;
close_bwqcam(qcam);
diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h
deleted file mode 100644
index 8a60c5de0935..000000000000
--- a/drivers/media/video/bw-qcam.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Video4Linux bw-qcam driver
- *
- * Derived from code..
- */
-
-/******************************************************************
-
-Copyright (C) 1996 by Scott Laird
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-******************************************************************/
-
-/* One from column A... */
-#define QC_NOTSET 0
-#define QC_UNIDIR 1
-#define QC_BIDIR 2
-#define QC_SERIAL 3
-
-/* ... and one from column B */
-#define QC_ANY 0x00
-#define QC_FORCE_UNIDIR 0x10
-#define QC_FORCE_BIDIR 0x20
-#define QC_FORCE_SERIAL 0x30
-/* in the port_mode member */
-
-#define QC_MODE_MASK 0x07
-#define QC_FORCE_MASK 0x70
-
-#define MAX_HEIGHT 243
-#define MAX_WIDTH 336
-
-/* Bit fields for status flags */
-#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */
-
-struct qcam_device {
- struct video_device vdev;
- struct pardevice *pdev;
- struct parport *pport;
- struct mutex lock;
- int width, height;
- int bpp;
- int mode;
- int contrast, brightness, whitebal;
- int port_mode;
- int transfer_scale;
- int top, left;
- int status;
- unsigned int saved_bits;
- unsigned long in_use;
-};
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 8f1dd88b32a6..6e4b19698c13 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -33,15 +33,17 @@
#include <linux/mm.h>
#include <linux/parport.h>
#include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
#include <linux/mutex.h>
#include <linux/jiffies.h>
-
+#include <linux/version.h>
+#include <linux/videodev2.h>
#include <asm/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
-struct qcam_device {
+struct qcam {
+ struct v4l2_device v4l2_dev;
struct video_device vdev;
struct pardevice *pdev;
struct parport *pport;
@@ -51,7 +53,6 @@ struct qcam_device {
int contrast, brightness, whitebal;
int top, left;
unsigned int bidirectional;
- unsigned long in_use;
struct mutex lock;
};
@@ -68,33 +69,45 @@ struct qcam_device {
#define QC_DECIMATION_2 2
#define QC_DECIMATION_4 4
-#define BANNER "Colour QuickCam for Video4Linux v0.05"
+#define BANNER "Colour QuickCam for Video4Linux v0.06"
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
static int probe = 2;
static int force_rgb;
static int video_nr = -1;
-static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
+/* FIXME: parport=auto would never have worked, surely? --RR */
+MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
+ "probe=<0|1|2> for camera detection method\n"
+ "force_rgb=<0|1> for RGB data format (default BGR)");
+module_param_array(parport, int, NULL, 0);
+module_param(probe, int, 0);
+module_param(force_rgb, bool, 0);
+module_param(video_nr, int, 0);
+
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
{
/* note: the QC specs refer to the PCAck pin by voltage, not
software level. PC ports have builtin inverters. */
parport_frob_control(qcam->pport, 8, i ? 8 : 0);
}
-static inline unsigned int qcam_ready1(struct qcam_device *qcam)
+static inline unsigned int qcam_ready1(struct qcam *qcam)
{
return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
}
-static inline unsigned int qcam_ready2(struct qcam_device *qcam)
+static inline unsigned int qcam_ready2(struct qcam *qcam)
{
return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
}
-static unsigned int qcam_await_ready1(struct qcam_device *qcam,
- int value)
+static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
}
/* Probably somebody pulled the plug out. Not much we can do. */
- printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
+ v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
parport_read_status(qcam->pport),
parport_read_control(qcam->pport));
return 1;
}
-static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
+static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
}
/* Probably somebody pulled the plug out. Not much we can do. */
- printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
+ v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
parport_read_status(qcam->pport),
parport_read_control(qcam->pport),
parport_read_data(qcam->pport));
return 1;
}
-static int qcam_read_data(struct qcam_device *qcam)
+static int qcam_read_data(struct qcam *qcam)
{
unsigned int idata;
@@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam)
return idata;
}
-static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
+static int qcam_write_data(struct qcam *qcam, unsigned int data)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned int idata;
parport_write_data(qcam->pport, data);
idata = qcam_read_data(qcam);
if (data != idata) {
- printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
+ v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
idata);
return 1;
}
return 0;
}
-static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
+static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
{
if (qcam_write_data(qcam, cmd))
return -1;
@@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned
return 0;
}
-static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
+static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
{
if (qcam_write_data(qcam, cmd))
return -1;
return qcam_read_data(qcam);
}
-static int qc_detect(struct qcam_device *qcam)
+static int qc_detect(struct qcam *qcam)
{
unsigned int stat, ostat, i, count = 0;
@@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam)
return 0;
}
-static void qc_reset(struct qcam_device *qcam)
+static void qc_reset(struct qcam *qcam)
{
parport_write_control(qcam->pport, 0xc);
parport_write_control(qcam->pport, 0x8);
@@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam)
/* Reset the QuickCam and program for brightness, contrast,
* white-balance, and resolution. */
-static void qc_setup(struct qcam_device *q)
+static void qc_setup(struct qcam *qcam)
{
- qc_reset(q);
+ qc_reset(qcam);
/* Set the brightness. */
- qcam_set(q, 11, q->brightness);
+ qcam_set(qcam, 11, qcam->brightness);
/* Set the height and width. These refer to the actual
CCD area *before* applying the selected decimation. */
- qcam_set(q, 17, q->ccd_height);
- qcam_set(q, 19, q->ccd_width / 2);
+ qcam_set(qcam, 17, qcam->ccd_height);
+ qcam_set(qcam, 19, qcam->ccd_width / 2);
/* Set top and left. */
- qcam_set(q, 0xd, q->top);
- qcam_set(q, 0xf, q->left);
+ qcam_set(qcam, 0xd, qcam->top);
+ qcam_set(qcam, 0xf, qcam->left);
/* Set contrast and white balance. */
- qcam_set(q, 0x19, q->contrast);
- qcam_set(q, 0x1f, q->whitebal);
+ qcam_set(qcam, 0x19, qcam->contrast);
+ qcam_set(qcam, 0x1f, qcam->whitebal);
/* Set the speed. */
- qcam_set(q, 45, 2);
+ qcam_set(qcam, 45, 2);
}
/* Read some bytes from the camera and put them in the buffer.
nbytes should be a multiple of 3, because bidirectional mode gives
us three bytes at a time. */
-static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
+static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
{
unsigned int bytes = 0;
- qcam_set_ack(q, 0);
- if (q->bidirectional) {
+ qcam_set_ack(qcam, 0);
+ if (qcam->bidirectional) {
/* It's a bidirectional port */
while (bytes < nbytes) {
unsigned int lo1, hi1, lo2, hi2;
unsigned char r, g, b;
- if (qcam_await_ready2(q, 1))
+ if (qcam_await_ready2(qcam, 1))
return bytes;
- lo1 = parport_read_data(q->pport) >> 1;
- hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(q, 1);
- if (qcam_await_ready2(q, 0))
+ lo1 = parport_read_data(qcam->pport) >> 1;
+ hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready2(qcam, 0))
return bytes;
- lo2 = parport_read_data(q->pport) >> 1;
- hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(q, 0);
+ lo2 = parport_read_data(qcam->pport) >> 1;
+ hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+ qcam_set_ack(qcam, 0);
r = lo1 | ((hi1 & 1) << 7);
g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
b = lo2 | ((hi2 & 1) << 7);
@@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
while (bytes < nbytes) {
unsigned int hi, lo;
- if (qcam_await_ready1(q, 1))
+ if (qcam_await_ready1(qcam, 1))
return bytes;
- hi = (parport_read_status(q->pport) & 0xf0);
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0))
+ hi = (parport_read_status(qcam->pport) & 0xf0);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0))
return bytes;
- lo = (parport_read_status(q->pport) & 0xf0);
- qcam_set_ack(q, 0);
+ lo = (parport_read_status(qcam->pport) & 0xf0);
+ qcam_set_ack(qcam, 0);
/* flip some bits */
rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
if (i >= 2) {
@@ -361,10 +376,11 @@ get_fragment:
#define BUFSZ 150
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned lines, pixelsperline, bitsperxfer;
- unsigned int is_bi_dir = q->bidirectional;
+ unsigned int is_bi_dir = qcam->bidirectional;
size_t wantlen, outptr = 0;
char tmpbuf[BUFSZ];
@@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
/* Wait for camera to become ready */
for (;;) {
- int i = qcam_get(q, 41);
+ int i = qcam_get(qcam, 41);
if (i == -1) {
- qc_setup(q);
+ qc_setup(qcam);
return -EIO;
}
if ((i & 0x80) == 0)
@@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
schedule();
}
- if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1))
+ if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
return -EIO;
- lines = q->height;
- pixelsperline = q->width;
+ lines = qcam->height;
+ pixelsperline = qcam->width;
bitsperxfer = (is_bi_dir) ? 24 : 8;
if (is_bi_dir) {
/* Turn the port around */
- parport_data_reverse(q->pport);
+ parport_data_reverse(qcam->pport);
mdelay(3);
- qcam_set_ack(q, 0);
- if (qcam_await_ready1(q, 1)) {
- qc_setup(q);
+ qcam_set_ack(qcam, 0);
+ if (qcam_await_ready1(qcam, 1)) {
+ qc_setup(qcam);
return -EIO;
}
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0)) {
- qc_setup(q);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0)) {
+ qc_setup(qcam);
return -EIO;
}
}
@@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
size_t t, s;
s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
- t = qcam_read_bytes(q, tmpbuf, s);
+ t = qcam_read_bytes(qcam, tmpbuf, s);
if (outptr < len) {
size_t sz = len - outptr;
@@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
len = outptr;
if (wantlen) {
- printk(KERN_ERR "qcam: short read.\n");
+ v4l2_err(v4l2_dev, "short read.\n");
if (is_bi_dir)
- parport_data_forward(q->pport);
- qc_setup(q);
+ parport_data_forward(qcam->pport);
+ qc_setup(qcam);
return len;
}
@@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
int l;
do {
- l = qcam_read_bytes(q, tmpbuf, 3);
+ l = qcam_read_bytes(qcam, tmpbuf, 3);
cond_resched();
} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
if (force_rgb) {
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
} else {
if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
}
- qcam_set_ack(q, 0);
- if (qcam_await_ready1(q, 1)) {
- printk(KERN_ERR "qcam: no ack after EOF\n");
- parport_data_forward(q->pport);
- qc_setup(q);
+ qcam_set_ack(qcam, 0);
+ if (qcam_await_ready1(qcam, 1)) {
+ v4l2_err(v4l2_dev, "no ack after EOF\n");
+ parport_data_forward(qcam->pport);
+ qc_setup(qcam);
return len;
}
- parport_data_forward(q->pport);
+ parport_data_forward(qcam->pport);
mdelay(3);
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0)) {
- printk(KERN_ERR "qcam: no ack to port turnaround\n");
- qc_setup(q);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0)) {
+ v4l2_err(v4l2_dev, "no ack to port turnaround\n");
+ qc_setup(qcam);
return len;
}
} else {
int l;
do {
- l = qcam_read_bytes(q, tmpbuf, 1);
+ l = qcam_read_bytes(qcam, tmpbuf, 1);
cond_resched();
} while (l && tmpbuf[0] == 0x7e);
- l = qcam_read_bytes(q, tmpbuf + 1, 2);
+ l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
if (force_rgb) {
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
} else {
if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
}
}
- qcam_write_data(q, 0);
+ qcam_write_data(qcam, 0);
return len;
}
@@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void *priv,
+ struct v4l2_capability *vcap)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ struct qcam *qcam = video_drvdata(file);
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
+ strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+ strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
+ strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+ vcap->version = KERNEL_VERSION(0, 0, 3);
+ vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ return 0;
+}
- strcpy(b->name, "Quickcam");
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 320;
- b->maxheight = 240;
- b->minwidth = 80;
- b->minheight = 60;
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- /* Good question.. its composite or SVHS so.. */
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Camera");
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ if (vin->index > 0)
+ return -EINVAL;
+ strlcpy(vin->name, "Camera", sizeof(vin->name));
+ vin->type = V4L2_INPUT_TYPE_CAMERA;
+ vin->audioset = 0;
+ vin->tuner = 0;
+ vin->std = 0;
+ vin->status = 0;
+ return 0;
+}
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
-
- if (v->tuner)
- return -EINVAL;
- memset(v, 0, sizeof(*v));
- strcpy(v->name, "Format");
- v->mode = VIDEO_MODE_AUTO;
- return 0;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+ *inp = 0;
+ return 0;
+}
+
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+ case V4L2_CID_GAMMA:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
}
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
-
- if (v->tuner)
- return -EINVAL;
- if (v->mode != VIDEO_MODE_AUTO)
- return -EINVAL;
- return 0;
+ return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = qcam->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = qcam->contrast;
+ break;
+ case V4L2_CID_GAMMA:
+ ctrl->value = qcam->whitebal;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
-
- p->colour = 0x8000;
- p->hue = 0x8000;
- p->brightness = qcam->brightness << 8;
- p->contrast = qcam->contrast << 8;
- p->whiteness = qcam->whitebal << 8;
- p->depth = 24;
- p->palette = VIDEO_PALETTE_RGB24;
- return 0;
+ return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->value;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
-
- /*
- * Sanity check args
- */
- if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
- return -EINVAL;
-
- /*
- * Now load the camera.
- */
- qcam->brightness = p->brightness >> 8;
- qcam->contrast = p->contrast >> 8;
- qcam->whitebal = p->whiteness >> 8;
-
- mutex_lock(&qcam->lock);
+ if (ret == 0) {
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return 0;
}
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height < 60 || vw->height > 240)
- return -EINVAL;
- if (vw->width < 80 || vw->width > 320)
- return -EINVAL;
-
- qcam->width = 80;
- qcam->height = 60;
- qcam->mode = QC_DECIMATION_4;
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
- if (vw->width >= 160 && vw->height >= 120) {
- qcam->width = 160;
- qcam->height = 120;
- qcam->mode = QC_DECIMATION_2;
- }
- if (vw->width >= 320 && vw->height >= 240) {
- qcam->width = 320;
- qcam->height = 240;
- qcam->mode = QC_DECIMATION_1;
- }
- qcam->mode |= QC_MILLIONS;
-#if 0
- if (vw->width >= 640 && vw->height >= 480) {
- qcam->width = 640;
- qcam->height = 480;
- qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
- }
-#endif
- /* Ok we figured out what to use from our
- wide choice */
- mutex_lock(&qcam->lock);
- parport_claim_or_block(qcam->pdev);
- qc_setup(qcam);
- parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
- memset(vw, 0, sizeof(*vw));
- vw->width = qcam->width;
- vw->height = qcam->height;
- return 0;
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ pix->width = qcam->width;
+ pix->height = qcam->height;
+ pix->pixelformat = V4L2_PIX_FMT_RGB24;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = 3 * qcam->width;
+ pix->sizeimage = 3 * qcam->width * qcam->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ if (pix->height < 60 || pix->width < 80) {
+ pix->height = 60;
+ pix->width = 80;
+ } else if (pix->height < 120 || pix->width < 160) {
+ pix->height = 120;
+ pix->width = 160;
+ } else {
+ pix->height = 240;
+ pix->width = 320;
}
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
+ pix->pixelformat = V4L2_PIX_FMT_RGB24;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = 3 * pix->width;
+ pix->sizeimage = 3 * pix->width * pix->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+ if (ret)
+ return ret;
+ switch (pix->height) {
+ case 60:
+ qcam->mode = QC_DECIMATION_4;
+ break;
+ case 120:
+ qcam->mode = QC_DECIMATION_2;
+ break;
default:
- return -ENOIOCTLCMD;
+ qcam->mode = QC_DECIMATION_1;
+ break;
}
+
+ mutex_lock(&qcam->lock);
+ qcam->mode |= QC_MILLIONS;
+ qcam->height = pix->height;
+ qcam->width = pix->width;
+ parport_claim_or_block(qcam->pdev);
+ qc_setup(qcam);
+ parport_release(qcam->pdev);
+ mutex_unlock(&qcam->lock);
return 0;
}
-static long qcam_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
- return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
+ { 0, 0, 0, 0 }
+ },
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (fmt->index > 0)
+ return -EINVAL;
+
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
}
static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct video_device *v = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)v;
+ struct qcam *qcam = video_drvdata(file);
int len;
mutex_lock(&qcam->lock);
@@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
-}
-
-static int qcam_exclusive_release(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- clear_bit(0, &qcam->in_use);
- return 0;
-}
-
-/* video device template */
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .open = qcam_exclusive_open,
- .release = qcam_exclusive_release,
- .ioctl = qcam_ioctl,
+ .ioctl = video_ioctl2,
.read = qcam_read,
};
-static struct video_device qcam_template = {
- .name = "Colour QuickCam",
- .fops = &qcam_fops,
- .release = video_device_release_empty,
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+ .vidioc_querycap = qcam_querycap,
+ .vidioc_g_input = qcam_g_input,
+ .vidioc_s_input = qcam_s_input,
+ .vidioc_enum_input = qcam_enum_input,
+ .vidioc_queryctrl = qcam_queryctrl,
+ .vidioc_g_ctrl = qcam_g_ctrl,
+ .vidioc_s_ctrl = qcam_s_ctrl,
+ .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
};
/* Initialize the QuickCam driver control structure. */
-static struct qcam_device *qcam_init(struct parport *port)
+static struct qcam *qcam_init(struct parport *port)
{
- struct qcam_device *q;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
- q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
- if (q == NULL)
+ qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
+ if (qcam == NULL)
return NULL;
- q->pport = port;
- q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
+ v4l2_dev = &qcam->v4l2_dev;
+ strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
+
+ if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ return NULL;
+ }
+
+ qcam->pport = port;
+ qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
NULL, 0, NULL);
- q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
+ qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
- if (q->pdev == NULL) {
- printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
- port->name);
- kfree(q);
+ if (qcam->pdev == NULL) {
+ v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ kfree(qcam);
return NULL;
}
- memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
- mutex_init(&q->lock);
- q->width = q->ccd_width = 320;
- q->height = q->ccd_height = 240;
- q->mode = QC_MILLIONS | QC_DECIMATION_1;
- q->contrast = 192;
- q->brightness = 240;
- q->whitebal = 128;
- q->top = 1;
- q->left = 14;
- return q;
+ strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
+ qcam->vdev.v4l2_dev = v4l2_dev;
+ qcam->vdev.fops = &qcam_fops;
+ qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+ qcam->vdev.release = video_device_release_empty;
+ video_set_drvdata(&qcam->vdev, qcam);
+
+ mutex_init(&qcam->lock);
+ qcam->width = qcam->ccd_width = 320;
+ qcam->height = qcam->ccd_height = 240;
+ qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
+ qcam->contrast = 192;
+ qcam->brightness = 240;
+ qcam->whitebal = 128;
+ qcam->top = 1;
+ qcam->left = 14;
+ return qcam;
}
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
-
static int init_cqcam(struct parport *port)
{
- struct qcam_device *qcam;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
if (parport[0] != -1) {
/* The user gave specific instructions */
@@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port)
if (qcam == NULL)
return -ENODEV;
+ v4l2_dev = &qcam->v4l2_dev;
+
parport_claim_or_block(qcam->pdev);
qc_reset(qcam);
@@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port)
parport_release(qcam->pdev);
if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
+ v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
qcam->pport->name);
parport_unregister_device(qcam->pdev);
kfree(qcam);
return -ENODEV;
}
- printk(KERN_INFO "%s: Colour QuickCam found on %s\n",
+ v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
video_device_node_name(&qcam->vdev), qcam->pport->name);
qcams[num_cams++] = qcam;
@@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port)
return 0;
}
-static void close_cqcam(struct qcam_device *qcam)
+static void close_cqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
parport_unregister_device(qcam->pdev);
@@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = {
static int __init cqcam_init(void)
{
- printk(BANNER "\n");
+ printk(KERN_INFO BANNER "\n");
return parport_register_driver(&cqcam_driver);
}
@@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
MODULE_DESCRIPTION(BANNER);
MODULE_LICENSE("GPL");
-/* FIXME: parport=auto would never have worked, surely? --RR */
-MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
- "probe=<0|1|2> for camera detection method\n"
- "force_rgb=<0|1> for RGB data format (default BGR)");
-module_param_array(parport, int, NULL, 0);
-module_param(probe, int, 0);
-module_param(force_rgb, bool, 0);
-module_param(video_nr, int, 0);
-
module_init(cqcam_init);
module_exit(cqcam_cleanup);
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index b5d7cbf4528a..d50d69da387b 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -1,7 +1,7 @@
/*
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* Portions of this work were sponsored by ONELAN Limited.
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c
index ef21114309fe..341bddc00b77 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.c
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.c
@@ -2,7 +2,7 @@
* ALSA mixer controls for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h
index 2d418db000fe..ec9238793f6f 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.h
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.h
@@ -2,7 +2,7 @@
* ALSA mixer controls for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
index 2bd312daeb1e..8f55692db36d 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -2,7 +2,7 @@
* ALSA PCM device for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* Portions of this work were sponsored by ONELAN Limited.
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h
index 325662c647a0..d26e51f94577 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.h
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.h
@@ -2,7 +2,7 @@
* ALSA PCM device for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h
index 88a1cde7540b..447da374c9e8 100644
--- a/drivers/media/video/cx18/cx18-alsa.h
+++ b/drivers/media/video/cx18/cx18-alsa.h
@@ -1,7 +1,7 @@
/*
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
index 9e30983f2ff6..43d09a24b262 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -4,7 +4,7 @@
* Derived from cx25840-audio.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 0e5006b14279..a41951cab276 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -4,7 +4,7 @@
* Derived from cx25840-core.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1021,86 +1021,74 @@ static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
return -EINVAL;
}
-static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
-static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = v4l2_get_subdevdata(sd);
-
- struct v4l2_pix_format *pix;
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
int is_50Hz = !(state->std & V4L2_STD_525_60);
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- pix = &(fmt->fmt.pix);
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
- Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
- Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
- Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+ Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
- /*
- * This adjustment reflects the excess of vactive, set in
- * cx18_av_std_setup(), above standard values:
- *
- * 480 + 1 for 60 Hz systems
- * 576 + 3 for 50 Hz systems
- */
- Vlines = pix->height + (is_50Hz ? 3 : 1);
-
- /*
- * Invalid height and width scaling requests are:
- * 1. width less than 1/16 of the source width
- * 2. width greater than the source width
- * 3. height less than 1/8 of the source height
- * 4. height greater than the source height
- */
- if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
- CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
- pix->width, pix->height);
- return -ERANGE;
- }
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
- HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
- VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
- VSC &= 0x1fff;
+ /*
+ * This adjustment reflects the excess of vactive, set in
+ * cx18_av_std_setup(), above standard values:
+ *
+ * 480 + 1 for 60 Hz systems
+ * 576 + 3 for 50 Hz systems
+ */
+ Vlines = fmt->height + (is_50Hz ? 3 : 1);
- if (pix->width >= 385)
- filter = 0;
- else if (pix->width > 192)
- filter = 1;
- else if (pix->width > 96)
- filter = 2;
- else
- filter = 3;
+ /*
+ * Invalid height and width scaling requests are:
+ * 1. width less than 1/16 of the source width
+ * 2. width greater than the source width
+ * 3. height less than 1/8 of the source height
+ * 4. height greater than the source height
+ */
+ if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
+ fmt->width, fmt->height);
+ return -ERANGE;
+ }
- CX18_DEBUG_INFO_DEV(sd,
- "decoder set size %dx%d -> scale %ux%u\n",
- pix->width, pix->height, HSC, VSC);
-
- /* HSCALE=HSC */
- cx18_av_write(cx, 0x418, HSC & 0xff);
- cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
- cx18_av_write(cx, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx18_av_write(cx, 0x41c, VSC & 0xff);
- cx18_av_write(cx, 0x41d, VSC >> 8);
- /* VS_INTRLACE=1 VFILT=filter */
- cx18_av_write(cx, 0x41e, 0x8 | filter);
- break;
+ HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
- default:
- return -EINVAL;
- }
+ if (fmt->width >= 385)
+ filter = 0;
+ else if (fmt->width > 192)
+ filter = 1;
+ else if (fmt->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ CX18_DEBUG_INFO_DEV(sd,
+ "decoder set size %dx%d -> scale %ux%u\n",
+ fmt->width, fmt->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+ cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+ cx18_av_write(cx, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx18_av_write(cx, 0x41c, VSC & 0xff);
+ cx18_av_write(cx, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx18_av_write(cx, 0x41e, 0x8 | filter);
return 0;
}
@@ -1398,8 +1386,7 @@ static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
.s_routing = cx18_av_s_video_routing,
.s_stream = cx18_av_s_stream,
- .g_fmt = cx18_av_g_fmt,
- .s_fmt = cx18_av_s_fmt,
+ .s_mbus_fmt = cx18_av_s_mbus_fmt,
};
static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = {
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index c106967bdcc3..1956991795e3 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -4,7 +4,7 @@
* Derived from cx25840-core.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index b9e8cc5d264a..280aa4d22488 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -2,7 +2,7 @@
* cx18 ADEC firmware functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 74e122b5fc49..6b805afe5d20 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -4,7 +4,7 @@
* Derived from ivtv-cards.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 796e517300ac..3e750068f275 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -4,7 +4,7 @@
* Derived from ivtv-cards.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 4b4b46544d5a..67043c7b452b 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -297,14 +297,13 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
if (p.video_encoding != cx->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt fmt;
/* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = cx->params.width
- / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = cx->params.height;
- v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt);
+ fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.height = cx->params.height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
}
priv.cx = cx;
priv.s = &cx->streams[id->type];
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index c95a86ba33b0..df60f27337cf 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -4,7 +4,7 @@
* Derived from ivtv-driver.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b9728e8eee40..9bc51a99376b 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -4,7 +4,7 @@
* Derived from ivtv-driver.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 0ae2c2e1eab5..6d19f040d70f 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -2,7 +2,7 @@
* cx18 functions for DVB support
*
* Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index e12a15020cda..9f23b90732f2 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -4,7 +4,7 @@
* Derived from ivtv-fileops.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 83cd559cc609..1b3fb502e6be 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -2,7 +2,7 @@
* cx18 firmware functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 86a204b5448e..5374aeb0cd22 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -4,7 +4,7 @@
* Derived from ivtv-gpio.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index f9a5ca3566af..4aea2ef88e8d 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -4,7 +4,7 @@
* Derived from ivtv-gpio.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index cfa1f289b0f5..809f7d37129c 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -4,7 +4,7 @@
* Derived from ivtv-i2c.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
index ec5b3d7bcc6b..49b9dbd06248 100644
--- a/drivers/media/video/cx18/cx18-io.c
+++ b/drivers/media/video/cx18/cx18-io.c
@@ -2,7 +2,7 @@
* cx18 driver PCI memory mapped IO access routines
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
index 2635b3a8cc96..18974d886cf7 100644
--- a/drivers/media/video/cx18/cx18-io.h
+++ b/drivers/media/video/cx18/cx18-io.h
@@ -2,7 +2,7 @@
* cx18 driver PCI memory mapped IO access routines
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
/*
* Readback and retry of MMIO access for reliability:
* The concept was suggested by Steve Toth <stoth@linuxtv.org>.
- * The implmentation is the fault of Andy Walls <awalls@radix.net>.
+ * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>.
*
* *write* functions are implied to retry the mmio unless suffixed with _noretry
* *read* functions never retry the mmio (it never helps to do so)
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 2530fc54daaf..20eaf38ba959 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -4,7 +4,7 @@
* Derived from ivtv-ioctl.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -274,6 +274,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
{
struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
int w, h;
@@ -293,9 +294,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
- cx->params.width = w;
- cx->params.height = h;
- v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+ mbus_fmt.width = cx->params.width = w;
+ mbus_fmt.height = cx->params.height = h;
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
return cx18_g_fmt_vid_cap(file, fh, fmt);
}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
index e2ca0d152116..dcb2559ad520 100644
--- a/drivers/media/video/cx18/cx18-ioctl.h
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -4,7 +4,7 @@
* Derived from ivtv-ioctl.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index af2f504eda2b..80edfe93a3d8 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -2,7 +2,7 @@
* cx18 interrupt handling
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
index 91f0b5278ef9..30e7eaf8cb55 100644
--- a/drivers/media/video/cx18/cx18-irq.h
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -2,7 +2,7 @@
* cx18 interrupt handling
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 6dcce297752f..956aa190ecca 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -2,7 +2,7 @@
* cx18 mailbox functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index 33a3491c4537..077952fcbcca 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -2,7 +2,7 @@
* cx18 mailbox functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index aefc8c8cf3c1..8884537bd62f 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -4,7 +4,7 @@
* Derived from ivtv-queue.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 88a6d34ad3bb..4201ddc16091 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -4,7 +4,7 @@
* Derived from ivtv-queue.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
index 34b4d03c55cd..85cc59637e54 100644
--- a/drivers/media/video/cx18/cx18-scb.c
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -2,7 +2,7 @@
* cx18 System Control Block initialization
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
index 368f23d08709..08877652e321 100644
--- a/drivers/media/video/cx18/cx18-scb.h
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -2,7 +2,7 @@
* cx18 System Control Block initialization
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index f5c91261b2db..9045f1ece0eb 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -4,7 +4,7 @@
* Derived from ivtv-streams.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 0bff0fa29763..77412bee5963 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -4,7 +4,7 @@
* Derived from ivtv-streams.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 2782709b263f..e76014561aa7 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -993,6 +993,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct cx231xx *dev = fh->dev;
int rc;
struct cx231xx_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
rc = check_dev(dev);
if (rc < 0)
@@ -1026,7 +1027,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->format = fmt;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
- call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
/* Set the correct alternate setting for this resolution */
cx231xx_resolution_set(dev);
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 022b480918cd..2bf44ef10fec 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -1113,7 +1113,6 @@ invalid:
void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
{
int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- int temporal = p->video_temporal_filter;
/* Stream */
printk(KERN_INFO "%s: Stream: %s",
@@ -1179,14 +1178,11 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
p->video_spatial_filter);
- if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
- temporal = 0;
-
printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
prefix,
cx2341x_menu_item(p,
V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
- temporal);
+ p->video_temporal_filter);
printk(KERN_INFO
"%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
prefix,
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 9e1460828b2f..0a199d774d9b 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -991,6 +991,8 @@ static int dvb_register(struct cx23885_tsport *port)
ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, 0,
cx23885_dvb_fe_ioctl_override);
+ if (!ret)
+ return ret;
/* init CI & MAC */
switch (dev->board) {
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 4172cb387420..d4746e064516 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -365,7 +365,17 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+ /*
+ * We can't call i2c_new_probed_device() because it uses
+ * quick writes for probing and the IR receiver device only
+ * replies to reads.
+ */
+ if (i2c_smbus_xfer(&bus->i2c_adap, addr_list[0], 0,
+ I2C_SMBUS_READ, 0, I2C_SMBUS_QUICK,
+ NULL) >= 0) {
+ info.addr = addr_list[0];
+ i2c_new_device(&bus->i2c_adap, &info);
+ }
}
return bus->i2c_rc;
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 8d306d8bb61c..5de6ba98f7a8 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -5,7 +5,7 @@
*
* Most of this file is
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* However, the cx23885_input_{init,fini} functions contained herein are
* derived from Linux kernel files linux/media/video/.../...-input.c marked as:
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h
index 3572cb1ecfc2..75ef15d3f523 100644
--- a/drivers/media/video/cx23885/cx23885-input.h
+++ b/drivers/media/video/cx23885/cx23885-input.h
@@ -3,7 +3,7 @@
*
* Infrared remote control input device
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c
index dfb4627fb340..44812ca78899 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.c
+++ b/drivers/media/video/cx23885/cx23885-ioctl.c
@@ -3,7 +3,7 @@
*
* Various common ioctl() support functions
*
- * Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h
index 80b0f4923c6a..315be0ca5a04 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.h
+++ b/drivers/media/video/cx23885/cx23885-ioctl.h
@@ -3,7 +3,7 @@
*
* Various common ioctl() support functions
*
- * Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c
index 6ae982cc9856..9a677eb080af 100644
--- a/drivers/media/video/cx23885/cx23885-ir.c
+++ b/drivers/media/video/cx23885/cx23885-ir.c
@@ -3,7 +3,7 @@
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h
index 9b8a6d5d1ef6..0c9d8bda9e28 100644
--- a/drivers/media/video/cx23885/cx23885-ir.h
+++ b/drivers/media/video/cx23885/cx23885-ir.h
@@ -3,7 +3,7 @@
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 543b854f6a62..4e44dcda3875 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -976,6 +976,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct v4l2_mbus_framefmt mbus_fmt;
int err;
dprintk(2, "%s()\n", __func__);
@@ -989,7 +990,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
fh->vidq.field = f->fmt.pix.field;
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
fh->width, fh->height, fh->vidq.field);
- call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index ad728d767d69..f63d378257a7 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -3,7 +3,7 @@
*
* CX23888 Integrated Consumer Infrared Controller
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h
index 3d446f9eb94b..d2de41caaf1d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.h
+++ b/drivers/media/video/cx23885/cx23888-ir.h
@@ -3,7 +3,7 @@
*
* CX23888 Integrated Consumer Infrared Controller
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 8b6fb3544376..bb4872b2ceb0 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1014,75 +1014,59 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* ----------------------------------------------------------------------- */
-static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- return cx25840_g_sliced_fmt(sd, &fmt->fmt.sliced);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct v4l2_pix_format *pix;
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
int is_50Hz = !(state->std & V4L2_STD_525_60);
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- pix = &(fmt->fmt.pix);
-
- Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
- Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
-
- Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
- Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
- Vlines = pix->height + (is_50Hz ? 4 : 7);
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
- v4l_err(client, "%dx%d is not a valid size!\n",
- pix->width, pix->height);
- return -ERANGE;
- }
+ Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
- HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
- VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
- VSC &= 0x1fff;
+ Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
- if (pix->width >= 385)
- filter = 0;
- else if (pix->width > 192)
- filter = 1;
- else if (pix->width > 96)
- filter = 2;
- else
- filter = 3;
-
- v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n",
- pix->width, pix->height, HSC, VSC);
-
- /* HSCALE=HSC */
- cx25840_write(client, 0x418, HSC & 0xff);
- cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
- cx25840_write(client, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx25840_write(client, 0x41c, VSC & 0xff);
- cx25840_write(client, 0x41d, VSC >> 8);
- /* VS_INTRLACE=1 VFILT=filter */
- cx25840_write(client, 0x41e, 0x8 | filter);
- break;
+ Vlines = fmt->height + (is_50Hz ? 4 : 7);
- default:
- return -EINVAL;
+ if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ v4l_err(client, "%dx%d is not a valid size!\n",
+ fmt->width, fmt->height);
+ return -ERANGE;
}
+ HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (fmt->width >= 385)
+ filter = 0;
+ else if (fmt->width > 192)
+ filter = 1;
+ else if (fmt->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n",
+ fmt->width, fmt->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx25840_write(client, 0x418, HSC & 0xff);
+ cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+ cx25840_write(client, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx25840_write(client, 0x41c, VSC & 0xff);
+ cx25840_write(client, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx25840_write(client, 0x41e, 0x8 | filter);
return 0;
}
@@ -1627,8 +1611,7 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
.s_routing = cx25840_s_video_routing,
- .g_fmt = cx25840_g_fmt,
- .s_fmt = cx25840_s_fmt,
+ .s_mbus_fmt = cx25840_s_mbus_fmt,
.s_stream = cx25840_s_stream,
};
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index ee1ca39db06a..fb39f1184558 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -188,10 +188,24 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
0x18, 0x6b, 0x71,
I2C_CLIENT_END
};
+ const unsigned short *addrp;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
+ /*
+ * We can't call i2c_new_probed_device() because it uses
+ * quick writes for probing and at least some R receiver
+ * devices only reply to reads.
+ */
+ for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
+ if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
+ I2C_SMBUS_READ, 0,
+ I2C_SMBUS_QUICK, NULL) >= 0) {
+ info.addr = *addrp;
+ i2c_new_device(&core->i2c_adap, &info);
+ break;
+ }
+ }
}
return core->i2c_rc;
}
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 331e1cac4272..44c63cbd6dda 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -1186,8 +1186,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&ops->next, &em28xx_extension_devlist);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->init(dev);
+ ops->init(dev);
}
printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
mutex_unlock(&em28xx_devlist_mutex);
@@ -1201,10 +1200,8 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->fini(dev);
+ ops->fini(dev);
}
-
printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
list_del(&ops->next);
mutex_unlock(&em28xx_devlist_mutex);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 785eeb4c2014..95354a339e3d 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1453,9 +1453,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
-#endif
{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index bb923efb75bd..176c5b3d5e6f 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -3022,16 +3022,18 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
/* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
/* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */
+ {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)},
{USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)},
/* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */
/* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */
+/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */
{USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)},
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)},
{USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
#endif
{USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/
-/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, P1030xC)}, */
+/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, * / GC0305*/
/* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
{USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/
@@ -3058,6 +3060,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
{USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/
+ /* or GC0305 / GC0307 */
{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/
{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/
{USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 7cfccfd1b870..c338f3f62e77 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -366,7 +366,7 @@ static int hdpvr_open(struct file *file)
dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
if (!dev) {
- v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
+ pr_err("open failing with with ENODEV\n");
retval = -ENODEV;
goto err;
}
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index b59475bfc243..b588e30cbcf0 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -267,13 +267,13 @@ int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
if (p.video_encoding != itv->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt fmt;
/* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = itv->params.height;
- v4l2_subdev_call(itv->sd_video, video, s_fmt, &fmt);
+ fmt.width = itv->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.height = itv->params.height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt);
}
err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index abf410943cc9..3c2cc270ccd5 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -823,6 +823,12 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
IVTV_DEBUG_FILE("close() of %s\n", s->name);
+ if (id->type == IVTV_DEC_STREAM_TYPE_YUV &&
+ test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
+ /* Restore registers we've changed & clean up any mess */
+ ivtv_yuv_close(itv);
+ }
+
/* Stop decoding */
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
IVTV_DEBUG_INFO("close stopping decode\n");
@@ -832,10 +838,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
}
clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
- /* Restore registers we've changed & clean up any mess we've made */
- ivtv_yuv_close(itv);
- }
+
if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
itv->output_mode = OUT_NONE;
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index fa9f0d958f96..11ac2fa33ef7 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -569,6 +569,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct cx2341x_mpeg_params *p = &itv->params;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
@@ -586,7 +587,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
p->height = h;
if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
fmt->fmt.pix.width /= 2;
- v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+ mbus_fmt.width = fmt->fmt.pix.width;
+ mbus_fmt.height = h;
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index de4288cc1889..9ecacab4b89b 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -618,12 +618,17 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
struct ivtv *itv = s->itv;
struct cx2341x_mpeg_params *p = &itv->params;
int datatype;
+ u16 width;
+ u16 height;
if (s->vdev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+ width = p->width;
+ height = p->height;
+
/* set audio mode to left/stereo for dual/stereo mode. */
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
@@ -646,7 +651,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
2 = yuv_from_host */
switch (s->type) {
case IVTV_DEC_STREAM_TYPE_YUV:
- datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2;
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ datatype = 1;
+ } else {
+ /* Fake size to avoid switching video standard */
+ datatype = 2;
+ width = 720;
+ height = itv->is_out_50hz ? 576 : 480;
+ }
IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
break;
case IVTV_DEC_STREAM_TYPE_MPG:
@@ -655,9 +667,13 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
break;
}
if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
- p->width, p->height, p->audio_properties)) {
+ width, height, p->audio_properties)) {
IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
}
+
+ /* Decoder sometimes dies here, so wait a moment */
+ ivtv_msleep_timeout(10, 0);
+
return 0;
}
@@ -697,6 +713,9 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
/* start playback */
ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
+ /* Let things settle before we actually start */
+ ivtv_msleep_timeout(10, 0);
+
/* Clear the following Interrupt mask bits for decoding */
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 49e1a283ed36..9ff3425891ed 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -1066,7 +1066,11 @@ static int ivtvfb_init_io(struct ivtv *itv)
}
mutex_unlock(&itv->serialize_lock);
- ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
+ if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
+ &oi->video_buffer_size) < 0) {
+ IVTVFB_ERR("Firmware failed to respond\n");
+ return -EIO;
+ }
/* The osd buffer size depends on the number of video buffers allocated
on the PVR350 itself. For now we'll hardcode the smallest osd buffer
@@ -1158,8 +1162,11 @@ static int ivtvfb_init_card(struct ivtv *itv)
}
/* Find & setup the OSD buffer */
- if ((rc = ivtvfb_init_io(itv)))
+ rc = ivtvfb_init_io(itv);
+ if (rc) {
+ ivtvfb_release_buffers(itv);
return rc;
+ }
/* Set the startup video mode information */
if ((rc = ivtvfb_init_vidmode(itv))) {
@@ -1210,6 +1217,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
{
struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
struct ivtv *itv = container_of(v4l2_dev, struct ivtv, v4l2_dev);
+ struct osd_info *oi = itv->osd_info;
if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) {
@@ -1218,7 +1226,7 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p)
return 0;
}
IVTVFB_INFO("Unregister framebuffer %d\n", itv->instance);
- ivtvfb_blank(FB_BLANK_POWERDOWN, &itv->osd_info->ivtvfb_info);
+ ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
ivtvfb_release_buffers(itv);
itv->osd_video_pbase = 0;
}
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index b62c0bd3f8ea..79f096ddcf5d 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -701,13 +701,13 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
#endif
};
-static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
struct i2c_client *client = sd->priv;
struct mt9m001 *mt9m001 = to_mt9m001(client);
- if ((unsigned int)index >= mt9m001->num_fmts)
+ if (index >= mt9m001->num_fmts)
return -EINVAL;
*code = mt9m001->fmts[index].code;
@@ -785,7 +785,6 @@ static int mt9m001_probe(struct i2c_client *client,
ret = mt9m001_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9m001);
}
@@ -799,7 +798,6 @@ static int mt9m001_remove(struct i2c_client *client)
icd->ops = NULL;
mt9m001_video_remove(icd);
- i2c_set_clientdata(client, NULL);
client->driver = NULL;
kfree(mt9m001);
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index d35f536f9fc3..fbd0fc794720 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -999,10 +999,10 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
#endif
};
-static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts))
+ if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
return -EINVAL;
*code = mt9m111_colour_fmts[index].code;
@@ -1068,7 +1068,6 @@ static int mt9m111_probe(struct i2c_client *client,
ret = mt9m111_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9m111);
}
@@ -1081,7 +1080,6 @@ static int mt9m111_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
client->driver = NULL;
kfree(mt9m111);
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 78b4e091d2d5..a9a28b214235 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -798,7 +798,7 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
#endif
};
-static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
@@ -883,7 +883,6 @@ static int mt9t031_probe(struct i2c_client *client,
if (ret) {
if (icd)
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9t031);
}
@@ -897,7 +896,6 @@ static int mt9t031_remove(struct i2c_client *client)
if (icd)
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
client->driver = NULL;
kfree(mt9t031);
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 7438f8d775ba..e4bf1db9a87b 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -1017,10 +1017,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts))
+ if (index >= ARRAY_SIZE(mt9t112_cfmts))
return -EINVAL;
*code = mt9t112_cfmts[index].code;
@@ -1119,7 +1119,6 @@ static int mt9t112_probe(struct i2c_client *client,
ret = mt9t112_camera_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1132,7 +1131,6 @@ static int mt9t112_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 72e55be0b4ab..f5e778d5ca9f 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -392,27 +392,25 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return 0;
}
-static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
{
- if (fmt->index > 0)
+ if (index > 0)
return -EINVAL;
- fmt->flags = 0;
- strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG");
- fmt->pixelformat = V4L2_PIX_FMT_SGRBG8;
-
+ *code = V4L2_MBUS_FMT_SGRBG8_1X8;
return 0;
}
-static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8)
+ if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8)
return -EINVAL;
- v4l_bound_align_image(&pix->width, 48, 639, 1,
- &pix->height, 32, 480, 1, 0);
+ v4l_bound_align_image(&fmt->width, 48, 639, 1,
+ &fmt->height, 32, 480, 1, 0);
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
}
@@ -455,18 +453,17 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
return 0;
}
-static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
struct mt9v011 *core = to_mt9v011(sd);
int rc;
- rc = mt9v011_try_fmt(sd, fmt);
+ rc = mt9v011_try_mbus_fmt(sd, fmt);
if (rc < 0)
return -EINVAL;
- core->width = pix->width;
- core->height = pix->height;
+ core->width = fmt->width;
+ core->height = fmt->height;
set_res(sd);
@@ -549,9 +546,9 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
};
static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
- .enum_fmt = mt9v011_enum_fmt,
- .try_fmt = mt9v011_try_fmt,
- .s_fmt = mt9v011_s_fmt,
+ .enum_mbus_fmt = mt9v011_enum_mbus_fmt,
+ .try_mbus_fmt = mt9v011_try_mbus_fmt,
+ .s_mbus_fmt = mt9v011_s_mbus_fmt,
.g_parm = mt9v011_g_parm,
.s_parm = mt9v011_s_parm,
};
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e5bae4c9393b..e7cd23cd6394 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -838,13 +838,13 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
#endif
};
-static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
struct i2c_client *client = sd->priv;
struct mt9v022 *mt9v022 = to_mt9v022(client);
- if ((unsigned int)index >= mt9v022->num_fmts)
+ if (index >= mt9v022->num_fmts)
return -EINVAL;
*code = mt9v022->fmts[index].code;
@@ -920,7 +920,6 @@ static int mt9v022_probe(struct i2c_client *client,
ret = mt9v022_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9v022);
}
@@ -934,7 +933,6 @@ static int mt9v022_remove(struct i2c_client *client)
icd->ops = NULL;
mt9v022_video_remove(icd);
- i2c_set_clientdata(client, NULL);
client->driver = NULL;
kfree(mt9v022);
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index d477e3058002..a9be14c23912 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -672,7 +672,7 @@ static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
-static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -689,7 +689,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
dev_err(icd->dev.parent,
- "Invalid format code #%d: %d\n", idx, code);
+ "Invalid format code #%u: %d\n", idx, code);
return 0;
}
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 4c0ab499228b..e7db0554949a 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -2371,12 +2371,11 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
for (k = 0; k < pdev->num_resources; k++) {
- vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+ vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
if (!vout) {
dev_err(&pdev->dev, ": could not allocate memory\n");
return -ENOMEM;
}
- memset(vout, 0, sizeof(struct omap_vout_device));
vout->vid = k;
vid_dev->vouts[k] = vout;
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 7f8ece30c77b..34034a710214 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -1092,10 +1092,10 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
#endif
};
-static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index,
+static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts))
+ if (index >= ARRAY_SIZE(ov772x_cfmts))
return -EINVAL;
*code = ov772x_cfmts[index].code;
@@ -1159,7 +1159,6 @@ static int ov772x_probe(struct i2c_client *client,
ret = ov772x_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1172,7 +1171,6 @@ static int ov772x_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 36599a65f548..7ce9e05b4781 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -614,10 +614,10 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index,
+static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes))
+ if (index >= ARRAY_SIZE(ov9640_codes))
return -EINVAL;
*code = ov9640_codes[index];
@@ -783,7 +783,6 @@ static int ov9640_probe(struct i2c_client *client,
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -794,7 +793,6 @@ static int ov9640_remove(struct i2c_client *client)
{
struct ov9640_priv *priv = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 6bc16c13ccef..3092abfd66a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -117,6 +117,7 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
{ .module_id = PVR2_CLIENT_ID_CX25840 },
{ .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
};
static const struct pvr2_device_desc pvr2_device_gotview_2 = {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index e5b9594eb5f6..273c8d4b3853 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -177,6 +177,11 @@ struct pvr2_device_desc {
unsigned int flag_has_composite:1; /* Has composite input */
unsigned int flag_has_svideo:1; /* Has s-video input */
unsigned int flag_fx2_16kb:1; /* 16KB FX2 firmware OK here */
+
+ /* If this driver is considered experimental, i.e. not all aspects
+ are working correctly and/or it is untested, mark that fact
+ with this flag. */
+ unsigned int flag_is_experimental:1;
};
extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 301ef197d038..70ea578d6266 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2459,6 +2459,19 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw,hdw_desc->description);
pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s",
hdw_desc->description);
+ if (hdw_desc->flag_is_experimental) {
+ pvr2_trace(PVR2_TRACE_INFO, "**********");
+ pvr2_trace(PVR2_TRACE_INFO,
+ "WARNING: Support for this device (%s) is"
+ " experimental.", hdw_desc->description);
+ pvr2_trace(PVR2_TRACE_INFO,
+ "Important functionality might not be"
+ " entirely working.");
+ pvr2_trace(PVR2_TRACE_INFO,
+ "Please consider contacting the driver author to"
+ " help with further stabilization of the driver.");
+ pvr2_trace(PVR2_TRACE_INFO, "**********");
+ }
if (!hdw) goto fail;
init_timer(&hdw->quiescent_timer);
@@ -3056,14 +3069,14 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
}
if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt fmt;
memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = hdw->res_hor_val;
- fmt.fmt.pix.height = hdw->res_ver_val;
+ fmt.width = hdw->res_hor_val;
+ fmt.height = hdw->res_ver_val;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
- fmt.fmt.pix.width, fmt.fmt.pix.height);
- v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
+ fmt.width, fmt.height);
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt);
}
if (hdw->srate_dirty || hdw->force_dirty) {
@@ -4084,12 +4097,20 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
{
- char da[1];
+ char *da;
unsigned int pipe;
int ret;
if (!hdw->usb_dev) return;
+ da = kmalloc(16, GFP_KERNEL);
+
+ if (da == NULL) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Unable to allocate memory to control CPU reset");
+ return;
+ }
+
pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
da[0] = val ? 0x01 : 0x00;
@@ -4103,6 +4124,8 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
"cpureset_assert(%d) error=%d",val,ret);
pvr2_hdw_render_useless(hdw);
}
+
+ kfree(da);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index eeacd0f67855..2254194aad57 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -153,12 +153,12 @@ static void __exit pvr_exit(void)
usb_deregister(&pvr_driver);
+ pvr2_context_global_done();
+
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
- pvr2_context_global_done();
-
pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete");
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 71f50565f637..3d7e5aab547f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -74,7 +74,7 @@ struct pvr2_sysfs_ctl_item {
int ctl_id;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
- struct attribute *attr_gen[7];
+ struct attribute *attr_gen[8];
struct attribute_group grp;
int created_ok;
char name[80];
@@ -511,6 +511,7 @@ static void pvr2_sysfs_release(struct device *class_dev)
static void class_dev_destroy(struct pvr2_sysfs *sfp)
{
+ struct device *dev;
if (!sfp->class_dev) return;
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_tear_down_debugifc(sfp);
@@ -542,6 +543,9 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
}
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
dev_set_drvdata(sfp->class_dev, NULL);
+ dev = sfp->class_dev->parent;
+ sfp->class_dev->parent = NULL;
+ put_device(dev);
device_unregister(sfp->class_dev);
sfp->class_dev = NULL;
}
@@ -631,10 +635,11 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
class_dev->class = &class_ptr->class;
+
dev_set_name(class_dev, "%s",
pvr2_hdw_get_device_identifier(sfp->channel.hdw));
- class_dev->parent = &usb_dev->dev;
+ class_dev->parent = get_device(&usb_dev->dev);
sfp->class_dev = class_dev;
dev_set_drvdata(class_dev, sfp);
@@ -775,7 +780,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
struct pvr2_sysfs_class *clp;
clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
+ pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p",
+ clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
clp->class.dev_release = pvr2_sysfs_release;
@@ -791,6 +797,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
{
+ pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp);
class_unregister(&clp->class);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 5ffa0d2b0b0d..aaafa0398fd5 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -883,6 +883,17 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
enum pvr2_config cfg = dip->config;
+ char msg[80];
+ unsigned int mcnt;
+
+ /* Construct the unregistration message *before* we actually
+ perform the unregistration step. By doing it this way we don't
+ have to worry about potentially touching deleted resources. */
+ mcnt = scnprintf(msg, sizeof(msg) - 1,
+ "pvrusb2: unregistered device %s [%s]",
+ video_device_node_name(&dip->devbase),
+ pvr2_config_get_name(cfg));
+ msg[mcnt] = 0;
pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
@@ -894,9 +905,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
are gone. */
video_unregister_device(&dip->devbase);
- printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n",
- video_device_node_name(&dip->devbase),
- pvr2_config_get_name(cfg));
+ printk(KERN_INFO "%s\n", msg);
}
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 7fe70e718656..fb242f6cfb1f 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -1247,7 +1247,7 @@ static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
-static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1264,7 +1264,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "Invalid format code #%d: %d\n", idx, code);
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
return 0;
}
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index bbd9c11e2c5a..47fd207ba3b1 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -481,10 +481,10 @@ static int reg_write_multiple(struct i2c_client *client,
return 0;
}
-static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index,
+static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts))
+ if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
return -EINVAL;
*code = rj54n1_colour_fmts[index].code;
@@ -1444,7 +1444,6 @@ static int rj54n1_probe(struct i2c_client *client,
ret = rj54n1_video_probe(icd, client, rj54n1_priv);
if (ret < 0) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(rj54n1);
return ret;
}
@@ -1461,7 +1460,6 @@ static int rj54n1_remove(struct i2c_client *client)
icd->ops = NULL;
if (icl->free_bus)
icl->free_bus(icl);
- i2c_set_clientdata(client, NULL);
client->driver = NULL;
kfree(rj54n1);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 53b6fcde3800..76da74368680 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1117,13 +1117,6 @@ static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return saa711x_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
{
saa711x_set_lcr(sd, NULL);
@@ -1136,12 +1129,13 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
return -EINVAL;
-
- return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ return saa711x_set_size(sd, fmt->width, fmt->height);
}
/* Decode the sliced VBI data stream as created by the saa7115.
@@ -1556,8 +1550,7 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
static const struct v4l2_subdev_video_ops saa711x_video_ops = {
.s_routing = saa711x_s_routing,
.s_crystal_freq = saa711x_s_crystal_freq,
- .g_fmt = saa711x_g_fmt,
- .s_fmt = saa711x_s_fmt,
+ .s_mbus_fmt = saa711x_s_mbus_fmt,
.s_stream = saa711x_s_stream,
.querystd = saa711x_querystd,
.g_input_status = saa711x_g_input_status,
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 87986ad62f86..79fffcf39ba8 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -645,13 +645,6 @@ static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return saa7127_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
switch (data->id) {
@@ -731,7 +724,6 @@ static const struct v4l2_subdev_core_ops saa7127_core_ops = {
};
static const struct v4l2_subdev_video_ops saa7127_video_ops = {
- .g_fmt = saa7127_g_fmt,
.s_std_output = saa7127_s_std_output,
.s_routing = saa7127_s_routing,
.s_stream = saa7127_s_stream,
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 1eabff6b2456..40fd31ca7716 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -846,24 +846,28 @@ static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_control
return 0;
}
-static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
if (h->video_format == SAA6752HS_VF_UNKNOWN)
h->video_format = SAA6752HS_VF_D1;
- f->fmt.pix.width =
- v4l2_format_table[h->video_format].fmt.pix.width;
- f->fmt.pix.height =
- v4l2_format_table[h->video_format].fmt.pix.height;
+ f->width = v4l2_format_table[h->video_format].fmt.pix.width;
+ f->height = v4l2_format_table[h->video_format].fmt.pix.height;
+ f->code = V4L2_MBUS_FMT_FIXED;
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
-static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
int dist_352, dist_480, dist_720;
+ if (f->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
+
/*
FIXME: translate and round width/height into EMPRESS
subsample type:
@@ -876,28 +880,30 @@ static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
D1 | 720x576 | 720x480
*/
- dist_352 = abs(f->fmt.pix.width - 352);
- dist_480 = abs(f->fmt.pix.width - 480);
- dist_720 = abs(f->fmt.pix.width - 720);
+ dist_352 = abs(f->width - 352);
+ dist_480 = abs(f->width - 480);
+ dist_720 = abs(f->width - 720);
if (dist_720 < dist_480) {
- f->fmt.pix.width = 720;
- f->fmt.pix.height = 576;
+ f->width = 720;
+ f->height = 576;
h->video_format = SAA6752HS_VF_D1;
} else if (dist_480 < dist_352) {
- f->fmt.pix.width = 480;
- f->fmt.pix.height = 576;
+ f->width = 480;
+ f->height = 576;
h->video_format = SAA6752HS_VF_2_3_D1;
} else {
- f->fmt.pix.width = 352;
- if (abs(f->fmt.pix.height - 576) <
- abs(f->fmt.pix.height - 288)) {
- f->fmt.pix.height = 576;
+ f->width = 352;
+ if (abs(f->height - 576) <
+ abs(f->height - 288)) {
+ f->height = 576;
h->video_format = SAA6752HS_VF_1_2_D1;
} else {
- f->fmt.pix.height = 288;
+ f->height = 288;
h->video_format = SAA6752HS_VF_SIF;
}
}
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -932,8 +938,8 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
};
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
- .s_fmt = saa6752hs_s_fmt,
- .g_fmt = saa6752hs_g_fmt,
+ .s_mbus_fmt = saa6752hs_s_mbus_fmt,
+ .g_mbus_fmt = saa6752hs_g_mbus_fmt,
};
static const struct v4l2_subdev_ops saa6752hs_ops = {
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 72700d4e3941..07f6bb8ef9d9 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -3897,6 +3897,40 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x01,
},
},
+ [SAA7134_BOARD_AVERMEDIA_M733A] = {
+ .name = "Avermedia PCI M733A",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .gpiomask = 0x020200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00200000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
[SAA7134_BOARD_BEHOLD_401] = {
/* Beholder Intl. Ltd. 2008 */
/*Dmitry Belimov <d.belimov@gmail.com> */
@@ -5822,6 +5856,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_AVERMEDIA_M135A,
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4155,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4255,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0x2004,
@@ -6786,6 +6832,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
switch (dev->board) {
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_AVERMEDIA_M733A:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
break;
@@ -7087,6 +7134,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000);
break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ saa7134_set_gpio(dev, 1, 1);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
}
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index ea877a50f52d..e763f9fd0133 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -223,9 +223,11 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_mbus_framefmt mbus_fmt;
- saa_call_all(dev, video, g_fmt, f);
+ saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
@@ -236,8 +238,11 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_mbus_framefmt mbus_fmt;
- saa_call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index e5565e2fd426..0b336ca6d55b 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -141,8 +141,8 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
struct saa7134_dev *dev = ir->c->adapter->algo_data;
if (dev == NULL) {
- dprintk("get_key_flydvb_trio: "
- "gir->c->adapter->algo_data is NULL!\n");
+ i2cdprintk("get_key_flydvb_trio: "
+ "ir->c->adapter->algo_data is NULL!\n");
return -EIO;
}
@@ -195,8 +195,8 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
struct saa7134_dev *dev = ir->c->adapter->algo_data;
if (dev == NULL) {
- dprintk("get_key_msi_tvanywhere_plus: "
- "gir->c->adapter->algo_data is NULL!\n");
+ i2cdprintk("get_key_msi_tvanywhere_plus: "
+ "ir->c->adapter->algo_data is NULL!\n");
return -EIO;
}
@@ -657,12 +657,19 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
case SAA7134_BOARD_AVERMEDIA_M135A:
- ir_codes = RC_MAP_AVERMEDIA_M135A_RM_JX;
+ ir_codes = RC_MAP_AVERMEDIA_M135A;
mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
mask_keyup = 0x0040000;
mask_keycode = 0xffff;
raw_decode = 1;
break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = 1;
+ break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
ir_codes = RC_MAP_AVERMEDIA;
@@ -815,7 +822,6 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x020000;
polling = 50; /* ms */
break;
- break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 3962534267be..756a1ca8833d 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -303,6 +303,7 @@ struct saa7134_format {
#define SAA7134_BOARD_HAWELL_HW_404M7 177
#define SAA7134_BOARD_BEHOLD_H7 178
#define SAA7134_BOARD_BEHOLD_A7 179
+#define SAA7134_BOARD_AVERMEDIA_M733A 180
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index d521c648e157..78d69950c00a 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1199,28 +1199,32 @@ static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
}
#endif
-static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix;
int prescale, h_scale, v_scale;
- pix = &fmt->fmt.pix;
v4l2_dbg(1, debug, sd, "decoder set size\n");
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
+
/* FIXME need better bounds checking here */
- if (pix->width < 1 || pix->width > 1440)
+ if (fmt->width < 1 || fmt->width > 1440)
return -EINVAL;
- if (pix->height < 1 || pix->height > 960)
+ if (fmt->height < 1 || fmt->height > 960)
return -EINVAL;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
/* scaling setting */
/* NTSC and interlace only */
- prescale = SAA717X_NTSC_WIDTH / pix->width;
+ prescale = SAA717X_NTSC_WIDTH / fmt->width;
if (prescale == 0)
prescale = 1;
- h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+ h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
/* interlace */
- v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+ v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
/* Horizontal prescaling etc */
set_h_prescale(sd, 0, prescale);
@@ -1241,19 +1245,19 @@ static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
/* set video output size */
/* video number of pixels at output */
/* TASK A */
- saa717x_write(sd, 0x5C, (u8)(pix->width & 0xFF));
- saa717x_write(sd, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+ saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
+ saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
/* TASK B */
- saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
- saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+ saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
+ saa717x_write(sd, 0x9D, (u8)((fmt->width >> 8) & 0xFF));
/* video number of lines at output */
/* TASK A */
- saa717x_write(sd, 0x5E, (u8)(pix->height & 0xFF));
- saa717x_write(sd, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+ saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
+ saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
/* TASK B */
- saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
- saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+ saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
+ saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
return 0;
}
@@ -1403,7 +1407,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
static const struct v4l2_subdev_video_ops saa717x_video_ops = {
.s_routing = saa717x_s_video_routing,
- .s_fmt = saa717x_s_fmt,
+ .s_mbus_fmt = saa717x_s_mbus_fmt,
.s_stream = saa717x_s_stream,
};
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 4ac3b482fbb4..961bfa2fea97 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -878,7 +878,7 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
-static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -897,7 +897,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
dev_err(icd->dev.parent,
- "Invalid format code #%d: %d\n", idx, code);
+ "Invalid format code #%u: %d\n", idx, code);
return -EINVAL;
}
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 522ba3f4c285..b6643ca7656a 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -62,8 +62,8 @@ static const struct usb_device_id sn9c102_id_table[] = {
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
/* SN9C103 */
{ SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index db1ca0e90d76..475757bfd7ba 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -200,7 +200,8 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int i, fmts = 0, raw_fmts = 0, ret;
+ unsigned int i, fmts = 0, raw_fmts = 0;
+ int ret;
enum v4l2_mbus_pixelcode code;
while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 10b003a8be83..248c986f0989 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -71,7 +71,7 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
static struct v4l2_subdev_core_ops platform_subdev_core_ops;
-static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index,
+static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index b90e9da3167d..54681a535822 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -850,7 +850,6 @@ static int tcm825x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct tcm825x_sensor *sensor = &tcm825x;
- int rval;
if (i2c_get_clientdata(client))
return -EBUSY;
@@ -871,11 +870,7 @@ static int tcm825x_probe(struct i2c_client *client,
sensor->pix.height = tcm825x_sizes[QVGA].height;
sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
- rval = v4l2_int_device_register(sensor->v4l2_int_device);
- if (rval)
- i2c_set_clientdata(client, NULL);
-
- return rval;
+ return v4l2_int_device_register(sensor->v4l2_int_device);
}
static int tcm825x_remove(struct i2c_client *client)
@@ -886,7 +881,6 @@ static int tcm825x_remove(struct i2c_client *client)
return -ENODEV; /* our client isn't attached */
v4l2_int_device_unregister(sensor->v4l2_int_device);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index e826114b7fb8..71c73fa0d68c 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -88,9 +88,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
* @pdata: Board specific
* @ver: Chip version
* @streaming: TVP5146/47 decoder streaming - enabled or disabled.
- * @pix: Current pixel format
- * @num_fmts: Number of formats
- * @fmt_list: Format list
* @current_std: Current standard
* @num_stds: Number of standards
* @std_list: Standards list
@@ -105,13 +102,9 @@ struct tvp514x_decoder {
int ver;
int streaming;
- struct v4l2_pix_format pix;
- int num_fmts;
- const struct v4l2_fmtdesc *fmt_list;
-
enum tvp514x_std current_std;
int num_stds;
- struct tvp514x_std_info *std_list;
+ const struct tvp514x_std_info *std_list;
/* Input and Output Routing parameters */
u32 input;
u32 output;
@@ -203,27 +196,12 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
};
/**
- * List of image formats supported by TVP5146/47 decoder
- * Currently we are using 8 bit mode only, but can be
- * extended to 10/20 bit mode.
- */
-static const struct v4l2_fmtdesc tvp514x_fmt_list[] = {
- {
- .index = 0,
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- .flags = 0,
- .description = "8-bit UYVY 4:2:2 Format",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- },
-};
-
-/**
* Supported standards -
*
* Currently supports two standards only, need to add support for rest of the
* modes, like SECAM, etc...
*/
-static struct tvp514x_std_info tvp514x_std_list[] = {
+static const struct tvp514x_std_info tvp514x_std_list[] = {
/* Standard: STD_NTSC_MJ */
[STD_NTSC_MJ] = {
.width = NTSC_NUM_ACTIVE_PIXELS,
@@ -366,13 +344,13 @@ static int tvp514x_write_regs(struct v4l2_subdev *sd,
}
/**
- * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47
+ * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
* @sd: ptr to v4l2_subdev struct
*
- * Get current standard detected by TVP5146/47, STD_INVALID if there is no
+ * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
* standard detected.
*/
-static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
+static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
@@ -518,7 +496,7 @@ static int tvp514x_detect(struct v4l2_subdev *sd,
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
- * detected, returns -EINVAL
+ * detected then *std_id is set to 0 and the function returns 0.
*/
static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
@@ -530,10 +508,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
if (std_id == NULL)
return -EINVAL;
- /* get the current standard */
- current_std = tvp514x_get_current_std(sd);
+ *std_id = V4L2_STD_UNKNOWN;
+
+ /* query the current standard */
+ current_std = tvp514x_query_current_std(sd);
if (current_std == STD_INVALID)
- return -EINVAL;
+ return 0;
input_sel = decoder->input;
@@ -575,12 +555,11 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
/* check whether signal is locked */
sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
if (lock_mask != (sync_lock_status & lock_mask))
- return -EINVAL; /* No input detected */
+ return 0; /* No input detected */
- decoder->current_std = current_std;
*std_id = decoder->std_list[current_std].standard.id;
- v4l2_dbg(1, debug, sd, "Current STD: %s",
+ v4l2_dbg(1, debug, sd, "Current STD: %s\n",
decoder->std_list[current_std].standard.name);
return 0;
}
@@ -614,7 +593,7 @@ static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
- v4l2_dbg(1, debug, sd, "Standard set to: %s",
+ v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
decoder->std_list[i].standard.name);
return 0;
}
@@ -637,7 +616,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
int err;
enum tvp514x_input input_sel;
enum tvp514x_output output_sel;
- enum tvp514x_std current_std = STD_INVALID;
u8 sync_lock_status, lock_mask;
int try_count = LOCK_RETRY_COUNT;
@@ -721,11 +699,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
/* Allow decoder to sync up with new input */
msleep(LOCK_RETRY_DELAY);
- /* get the current standard for future reference */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- continue;
-
sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
@@ -733,15 +706,13 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
break;
}
- if ((current_std == STD_INVALID) || (try_count < 0))
+ if (try_count < 0)
return -EINVAL;
- decoder->current_std = current_std;
decoder->input = input;
decoder->output = output;
- v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
- input_sel, current_std);
+ v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
return 0;
}
@@ -794,7 +765,7 @@ tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
return err;
}
- v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+ v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n",
qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
@@ -851,7 +822,7 @@ tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return -EINVAL;
}
- v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return 0;
}
@@ -951,7 +922,7 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return err;
}
- v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return err;
@@ -967,44 +938,33 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int
tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- int index;
-
- if (fmt == NULL)
- return -EINVAL;
-
- index = fmt->index;
- if ((index >= decoder->num_fmts) || (index < 0))
- /* Index out of bound */
+ if (fmt == NULL || fmt->index)
return -EINVAL;
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
/* only capture is supported */
return -EINVAL;
- memcpy(fmt, &decoder->fmt_list[index],
- sizeof(struct v4l2_fmtdesc));
-
- v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)",
- decoder->fmt_list[index].index,
- decoder->fmt_list[index].description);
+ /* only one format */
+ fmt->flags = 0;
+ strlcpy(fmt->description, "8-bit UYVY 4:2:2 Format",
+ sizeof(fmt->description));
+ fmt->pixelformat = V4L2_PIX_FMT_UYVY;
return 0;
}
/**
- * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * tvp514x_fmt_cap() - V4L2 decoder interface handler for try/s/g_fmt
* @sd: pointer to standard V4L2 sub-device structure
* @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
*
- * Implement the VIDIOC_TRY_FMT ioctl for the CAPTURE buffer type. This
- * ioctl is used to negotiate the image capture size and pixel format
- * without actually making it take effect.
+ * Implement the VIDIOC_TRY/S/G_FMT ioctl for the CAPTURE buffer type. This
+ * ioctl is used to negotiate the image capture size and pixel format.
*/
static int
-tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+tvp514x_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
- int ifmt;
struct v4l2_pix_format *pix;
enum tvp514x_std current_std;
@@ -1012,106 +972,30 @@ tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return -EINVAL;
pix = &f->fmt.pix;
/* Calculate height and width based on current standard */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- return -EINVAL;
+ current_std = decoder->current_std;
- decoder->current_std = current_std;
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
pix->width = decoder->std_list[current_std].width;
pix->height = decoder->std_list[current_std].height;
-
- for (ifmt = 0; ifmt < decoder->num_fmts; ifmt++) {
- if (pix->pixelformat ==
- decoder->fmt_list[ifmt].pixelformat)
- break;
- }
- if (ifmt == decoder->num_fmts)
- /* None of the format matched, select default */
- ifmt = 0;
- pix->pixelformat = decoder->fmt_list[ifmt].pixelformat;
-
pix->field = V4L2_FIELD_INTERLACED;
pix->bytesperline = pix->width * 2;
pix->sizeimage = pix->bytesperline * pix->height;
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
pix->priv = 0;
- v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
- "Width - %d, Height - %d",
- decoder->fmt_list[ifmt].description, pix->bytesperline,
+ v4l2_dbg(1, debug, sd, "FMT: bytesperline - %d"
+ "Width - %d, Height - %d\n",
+ pix->bytesperline,
pix->width, pix->height);
return 0;
}
/**
- * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_S_FMT ioctl structure
- *
- * If the requested format is supported, configures the HW to use that
- * format, returns error code if format not supported or HW can't be
- * correctly configured.
- */
-static int
-tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- struct v4l2_pix_format *pix;
- int rval;
-
- if (f == NULL)
- return -EINVAL;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- pix = &f->fmt.pix;
- rval = tvp514x_try_fmt_cap(sd, f);
- if (rval)
- return rval;
-
- decoder->pix = *pix;
-
- return rval;
-}
-
-/**
- * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 v4l2_format structure
- *
- * Returns the decoder's current pixel format in the v4l2_format
- * parameter.
- */
-static int
-tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
-
- if (f == NULL)
- return -EINVAL;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- f->fmt.pix = decoder->pix;
-
- v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
- "Width - %d, Height - %d",
- decoder->pix.bytesperline,
- decoder->pix.width, decoder->pix.height);
- return 0;
-}
-
-/**
* tvp514x_g_parm() - V4L2 decoder interface handler for g_parm
* @sd: pointer to standard V4L2 sub-device structure
* @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
@@ -1132,15 +1016,8 @@ tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
/* only capture is supported */
return -EINVAL;
- memset(a, 0, sizeof(*a));
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
/* get the current standard */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- return -EINVAL;
-
- decoder->current_std = current_std;
+ current_std = decoder->current_std;
cparm = &a->parm.capture;
cparm->capability = V4L2_CAP_TIMEPERFRAME;
@@ -1175,11 +1052,7 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- return -EINVAL;
-
- decoder->current_std = current_std;
+ current_std = decoder->current_std;
*timeperframe =
decoder->std_list[current_std].standard.frameperiod;
@@ -1259,9 +1132,9 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
.enum_fmt = tvp514x_enum_fmt_cap,
- .g_fmt = tvp514x_g_fmt_cap,
- .try_fmt = tvp514x_try_fmt_cap,
- .s_fmt = tvp514x_s_fmt_cap,
+ .g_fmt = tvp514x_fmt_cap,
+ .try_fmt = tvp514x_fmt_cap,
+ .s_fmt = tvp514x_fmt_cap,
.g_parm = tvp514x_g_parm,
.s_parm = tvp514x_s_parm,
.s_stream = tvp514x_s_stream,
@@ -1274,22 +1147,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = {
static struct tvp514x_decoder tvp514x_dev = {
.streaming = 0,
-
- .fmt_list = tvp514x_fmt_list,
- .num_fmts = ARRAY_SIZE(tvp514x_fmt_list),
-
- .pix = {
- /* Default to NTSC 8-bit YUV 422 */
- .width = NTSC_NUM_ACTIVE_PIXELS,
- .height = NTSC_NUM_ACTIVE_LINES,
- .pixelformat = V4L2_PIX_FMT_UYVY,
- .field = V4L2_FIELD_INTERLACED,
- .bytesperline = NTSC_NUM_ACTIVE_PIXELS * 2,
- .sizeimage =
- NTSC_NUM_ACTIVE_PIXELS * 2 * NTSC_NUM_ACTIVE_LINES,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- },
-
.current_std = STD_NTSC_MJ,
.std_list = tvp514x_std_list,
.num_stds = ARRAY_SIZE(tvp514x_std_list),
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 47f0582d50a5..1654f65cca7c 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -934,17 +934,6 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- return tvp5150_s_sliced_fmt(sd, &fmt->fmt.sliced);
-
- default:
- return -EINVAL;
- }
-}
-
static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
{
int i, mask = 0;
@@ -960,13 +949,6 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return tvp5150_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1054,8 +1036,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.s_routing = tvp5150_s_routing,
- .g_fmt = tvp5150_g_fmt,
- .s_fmt = tvp5150_s_fmt,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 76be733eabfd..445dc93413e3 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -903,7 +903,7 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
#endif
};
-static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index,
+static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
@@ -977,7 +977,6 @@ static int tw9910_probe(struct i2c_client *client,
ret = tw9910_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -990,7 +989,6 @@ static int tw9910_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 6248a639ba2d..c2690df33438 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -1671,8 +1671,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
PDEBUG(DBG_PROBE, "");
if (usbvision == NULL) {
- dev_err(&usbvision->dev->dev,
- "%s: usb_get_intfdata() failed\n", __func__);
+ pr_err("%s: usb_get_intfdata() failed\n", __func__);
return;
}
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
new file mode 100644
index 000000000000..11bce8027f5c
--- /dev/null
+++ b/drivers/media/video/via-camera.c
@@ -0,0 +1,1369 @@
+/*
+ * Driver for the VIA Chrome integrated camera controller.
+ *
+ * Copyright 2009,2010 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under the terms of the GNU General Public License, version 2
+ *
+ * This work was supported by the One Laptop Per Child project
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_qos_params.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+#include <linux/via_i2c.h>
+
+#include "via-camera.h"
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
+MODULE_LICENSE("GPL");
+
+static int flip_image;
+module_param(flip_image, bool, 0444);
+MODULE_PARM_DESC(flip_image,
+ "If set, the sensor will be instructed to flip the image "
+ "vertically.");
+
+#ifdef CONFIG_OLPC_XO_1_5
+static int override_serial;
+module_param(override_serial, bool, 0444);
+MODULE_PARM_DESC(override_serial,
+ "The camera driver will normally refuse to load if "
+ "the XO 1.5 serial port is enabled. Set this option "
+ "to force the issue.");
+#endif
+
+/*
+ * Basic window sizes.
+ */
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+
+/*
+ * The structure describing our camera.
+ */
+enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
+
+static struct via_camera {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_subdev *sensor;
+ struct platform_device *platdev;
+ struct viafb_dev *viadev;
+ struct mutex lock;
+ enum viacam_opstate opstate;
+ unsigned long flags;
+ struct pm_qos_request_list *qos_request;
+ /*
+ * GPIO info for power/reset management
+ */
+ int power_gpio;
+ int reset_gpio;
+ /*
+ * I/O memory stuff.
+ */
+ void __iomem *mmio; /* Where the registers live */
+ void __iomem *fbmem; /* Frame buffer memory */
+ u32 fb_offset; /* Reserved memory offset (FB) */
+ /*
+ * Capture buffers and related. The controller supports
+ * up to three, so that's what we have here. These buffers
+ * live in frame buffer memory, so we don't call them "DMA".
+ */
+ unsigned int cb_offsets[3]; /* offsets into fb mem */
+ u8 *cb_addrs[3]; /* Kernel-space addresses */
+ int n_cap_bufs; /* How many are we using? */
+ int next_buf;
+ struct videobuf_queue vb_queue;
+ struct list_head buffer_queue; /* prot. by reg_lock */
+ /*
+ * User tracking.
+ */
+ int users;
+ struct file *owner;
+ /*
+ * Video format information. sensor_format is kept in a form
+ * that we can use to pass to the sensor. We always run the
+ * sensor in VGA resolution, though, and let the controller
+ * downscale things if need be. So we keep the "real*
+ * dimensions separately.
+ */
+ struct v4l2_pix_format sensor_format;
+ struct v4l2_pix_format user_format;
+} via_cam_info;
+
+/*
+ * Flag values, manipulated with bitops
+ */
+#define CF_DMA_ACTIVE 0 /* A frame is incoming */
+#define CF_CONFIG_NEEDED 1 /* Must configure hardware */
+
+
+/*
+ * Nasty ugly v4l2 boilerplate.
+ */
+#define sensor_call(cam, optype, func, args...) \
+ v4l2_subdev_call(cam->sensor, optype, func, ##args)
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+ dev_err(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+ dev_warn(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+ dev_dbg(&(cam)->platdev->dev, fmt, ##arg);
+
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Sensor power/reset management. This piece is OLPC-specific for
+ * sure; other configurations will have things connected differently.
+ */
+static int via_sensor_power_setup(struct via_camera *cam)
+{
+ int ret;
+
+ cam->power_gpio = viafb_gpio_lookup("VGPIO3");
+ cam->reset_gpio = viafb_gpio_lookup("VGPIO2");
+ if (cam->power_gpio < 0 || cam->reset_gpio < 0) {
+ dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n");
+ return -EINVAL;
+ }
+ ret = gpio_request(cam->power_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request power GPIO\n");
+ return ret;
+ }
+ ret = gpio_request(cam->reset_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n");
+ gpio_free(cam->power_gpio);
+ return ret;
+ }
+ gpio_direction_output(cam->power_gpio, 0);
+ gpio_direction_output(cam->reset_gpio, 0);
+ return 0;
+}
+
+/*
+ * Power up the sensor and perform the reset dance.
+ */
+static void via_sensor_power_up(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 1);
+ gpio_set_value(cam->reset_gpio, 0);
+ msleep(20); /* Probably excessive */
+ gpio_set_value(cam->reset_gpio, 1);
+ msleep(20);
+}
+
+static void via_sensor_power_down(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 0);
+ gpio_set_value(cam->reset_gpio, 0);
+}
+
+
+static void via_sensor_power_release(struct via_camera *cam)
+{
+ via_sensor_power_down(cam);
+ gpio_free(cam->power_gpio);
+ gpio_free(cam->reset_gpio);
+}
+
+/* --------------------------------------------------------------------------*/
+/* Sensor ops */
+
+/*
+ * Manage the ov7670 "flip" bit, which needs special help.
+ */
+static int viacam_set_flip(struct via_camera *cam)
+{
+ struct v4l2_control ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = flip_image;
+ return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+/*
+ * Configure the sensor. It's up to the caller to ensure
+ * that the camera is in the correct operating state.
+ */
+static int viacam_configure_sensor(struct via_camera *cam)
+{
+ struct v4l2_format fmt;
+ int ret;
+
+ fmt.fmt.pix = cam->sensor_format;
+ ret = sensor_call(cam, core, init, 0);
+ if (ret == 0)
+ ret = sensor_call(cam, video, s_fmt, &fmt);
+ /*
+ * OV7670 does weird things if flip is set *before* format...
+ */
+ if (ret == 0)
+ ret = viacam_set_flip(cam);
+ return ret;
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/*
+ * Some simple register accessors; they assume that the lock is held.
+ *
+ * Should we want to support the second capture engine, we could
+ * hide the register difference by adding 0x1000 to registers in the
+ * 0x300-350 range.
+ */
+static inline void viacam_write_reg(struct via_camera *cam,
+ int reg, int value)
+{
+ iowrite32(value, cam->mmio + reg);
+}
+
+static inline int viacam_read_reg(struct via_camera *cam, int reg)
+{
+ return ioread32(cam->mmio + reg);
+}
+
+static inline void viacam_write_reg_mask(struct via_camera *cam,
+ int reg, int value, int mask)
+{
+ int tmp = viacam_read_reg(cam, reg);
+
+ tmp = (tmp & ~mask) | (value & mask);
+ viacam_write_reg(cam, reg, tmp);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Interrupt management and handling */
+
+static irqreturn_t viacam_quick_irq(int irq, void *data)
+{
+ struct via_camera *cam = data;
+ irqreturn_t ret = IRQ_NONE;
+ int icv;
+
+ /*
+ * All we do here is to clear the interrupts and tell
+ * the handler thread to wake up.
+ */
+ spin_lock(&cam->viadev->reg_lock);
+ icv = viacam_read_reg(cam, VCR_INTCTRL);
+ if (icv & VCR_IC_EAV) {
+ icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL;
+ viacam_write_reg(cam, VCR_INTCTRL, icv);
+ ret = IRQ_WAKE_THREAD;
+ }
+ spin_unlock(&cam->viadev->reg_lock);
+ return ret;
+}
+
+/*
+ * Find the next videobuf buffer which has somebody waiting on it.
+ */
+static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+{
+ unsigned long flags;
+ struct videobuf_buffer *buf = NULL;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ if (cam->opstate != S_RUNNING)
+ goto out;
+ if (list_empty(&cam->buffer_queue))
+ goto out;
+ buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
+ if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
+ buf = NULL;
+ goto out;
+ }
+ list_del(&buf->queue);
+ buf->state = VIDEOBUF_ACTIVE;
+out:
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ return buf;
+}
+
+/*
+ * The threaded IRQ handler.
+ */
+static irqreturn_t viacam_irq(int irq, void *data)
+{
+ int bufn;
+ struct videobuf_buffer *vb;
+ struct via_camera *cam = data;
+ struct videobuf_dmabuf *vdma;
+
+ /*
+ * If there is no place to put the data frame, don't bother
+ * with anything else.
+ */
+ vb = viacam_next_buffer(cam);
+ if (vb == NULL)
+ goto done;
+ /*
+ * Figure out which buffer we just completed.
+ */
+ bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3;
+ bufn -= 1;
+ if (bufn < 0)
+ bufn = cam->n_cap_bufs - 1;
+ /*
+ * Copy over the data and let any waiters know.
+ */
+ vdma = videobuf_to_dma(vb);
+ viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
+ vb->state = VIDEOBUF_DONE;
+ vb->size = cam->user_format.sizeimage;
+ wake_up(&vb->done);
+done:
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * These functions must mess around with the general interrupt
+ * control register, which is relevant to much more than just the
+ * camera. Nothing else uses interrupts, though, as of this writing.
+ * Should that situation change, we'll have to improve support at
+ * the via-core level.
+ */
+static void viacam_int_enable(struct via_camera *cam)
+{
+ viacam_write_reg(cam, VCR_INTCTRL,
+ VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL);
+ viafb_irq_enable(VDE_I_C0AVEN);
+}
+
+static void viacam_int_disable(struct via_camera *cam)
+{
+ viafb_irq_disable(VDE_I_C0AVEN);
+ viacam_write_reg(cam, VCR_INTCTRL, 0);
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/* Controller operations */
+
+/*
+ * Set up our capture buffers in framebuffer memory.
+ */
+static int viacam_ctlr_cbufs(struct via_camera *cam)
+{
+ int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage;
+ int i;
+ unsigned int offset;
+
+ /*
+ * See how many buffers we can work with.
+ */
+ if (nbuf >= 3) {
+ cam->n_cap_bufs = 3;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS,
+ VCR_CI_3BUFS);
+ } else if (nbuf == 2) {
+ cam->n_cap_bufs = 2;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS);
+ } else {
+ cam_warn(cam, "Insufficient frame buffer memory\n");
+ return -ENOMEM;
+ }
+ /*
+ * Set them up.
+ */
+ offset = cam->fb_offset;
+ for (i = 0; i < cam->n_cap_bufs; i++) {
+ cam->cb_offsets[i] = offset;
+ cam->cb_addrs[i] = cam->fbmem + offset;
+ viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK);
+ offset += cam->sensor_format.sizeimage;
+ }
+ return 0;
+}
+
+/*
+ * Set the scaling register for downscaling the image.
+ *
+ * This register works like this... Vertical scaling is enabled
+ * by bit 26; if that bit is set, downscaling is controlled by the
+ * value in bits 16:25. Those bits are divided by 1024 to get
+ * the scaling factor; setting just bit 25 thus cuts the height
+ * in half.
+ *
+ * Horizontal scaling works about the same, but it's enabled by
+ * bit 11, with bits 0:10 giving the numerator of a fraction
+ * (over 2048) for the scaling value.
+ *
+ * This function is naive in that, if the user departs from
+ * the 3x4 VGA scaling factor, the image will distort. We
+ * could work around that if it really seemed important.
+ */
+static void viacam_set_scale(struct via_camera *cam)
+{
+ unsigned int avscale;
+ int sf;
+
+ if (cam->user_format.width == VGA_WIDTH)
+ avscale = 0;
+ else {
+ sf = (cam->user_format.width*2048)/VGA_WIDTH;
+ avscale = VCR_AVS_HEN | sf;
+ }
+ if (cam->user_format.height < VGA_HEIGHT) {
+ sf = (1024*cam->user_format.height)/VGA_HEIGHT;
+ avscale |= VCR_AVS_VEN | (sf << 16);
+ }
+ viacam_write_reg(cam, VCR_AVSCALE, avscale);
+}
+
+
+/*
+ * Configure image-related information into the capture engine.
+ */
+static void viacam_ctlr_image(struct via_camera *cam)
+{
+ int cicreg;
+
+ /*
+ * Disable clock before messing with stuff - from the via
+ * sample driver.
+ */
+ viacam_write_reg(cam, VCR_CAPINTC, ~VCR_CI_ENABLE);
+ viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN));
+ /*
+ * Disable a bunch of stuff.
+ */
+ viacam_write_reg(cam, VCR_HORRANGE, 0x06200120);
+ viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000);
+ viacam_set_scale(cam);
+ /*
+ * Image size info.
+ */
+ viacam_write_reg(cam, VCR_MAXDATA,
+ (cam->sensor_format.height << 16) |
+ (cam->sensor_format.bytesperline >> 3));
+ viacam_write_reg(cam, VCR_MAXVBI, 0);
+ viacam_write_reg(cam, VCR_VSTRIDE,
+ cam->user_format.bytesperline & VCR_VS_STRIDE);
+ /*
+ * Set up the capture interface control register,
+ * everything but the "go" bit.
+ *
+ * The FIFO threshold is a bit of a magic number; 8 is what
+ * VIA's sample code uses.
+ */
+ cicreg = VCR_CI_CLKEN |
+ 0x08000000 | /* FIFO threshold */
+ VCR_CI_FLDINV | /* OLPC-specific? */
+ VCR_CI_VREFINV | /* OLPC-specific? */
+ VCR_CI_DIBOTH | /* Capture both fields */
+ VCR_CI_CCIR601_8;
+ if (cam->n_cap_bufs == 3)
+ cicreg |= VCR_CI_3BUFS;
+ /*
+ * YUV formats need different byte swapping than RGB.
+ */
+ if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV)
+ cicreg |= VCR_CI_YUYV;
+ else
+ cicreg |= VCR_CI_UYVY;
+ viacam_write_reg(cam, VCR_CAPINTC, cicreg);
+}
+
+
+static int viacam_config_controller(struct via_camera *cam)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ ret = viacam_ctlr_cbufs(cam);
+ if (!ret)
+ viacam_ctlr_image(cam);
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+ return ret;
+}
+
+/*
+ * Make it start grabbing data.
+ */
+static void viacam_start_engine(struct via_camera *cam)
+{
+ spin_lock_irq(&cam->viadev->reg_lock);
+ cam->next_buf = 0;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
+ viacam_int_enable(cam);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_RUNNING;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+static void viacam_stop_engine(struct via_camera *cam)
+{
+ spin_lock_irq(&cam->viadev->reg_lock);
+ viacam_int_disable(cam);
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_IDLE;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Videobuf callback ops */
+
+/*
+ * buffer_setup. The purpose of this one would appear to be to tell
+ * videobuf how big a single image is. It's also evidently up to us
+ * to put some sort of limit on the maximum number of buffers allowed.
+ */
+static int viacam_vb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct via_camera *cam = q->priv_data;
+
+ *size = cam->user_format.sizeimage;
+ if (*count == 0 || *count > 6) /* Arbitrary number */
+ *count = 6;
+ return 0;
+}
+
+/*
+ * Prepare a buffer.
+ */
+static int viacam_vb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct via_camera *cam = q->priv_data;
+
+ vb->size = cam->user_format.sizeimage;
+ vb->width = cam->user_format.width; /* bytesperline???? */
+ vb->height = cam->user_format.height;
+ vb->field = field;
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int ret = videobuf_iolock(q, vb, NULL);
+ if (ret)
+ return ret;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+/*
+ * We've got a buffer to put data into.
+ *
+ * FIXME: check for a running engine and valid buffers?
+ */
+static void viacam_vb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct via_camera *cam = q->priv_data;
+
+ /*
+ * Note that videobuf holds the lock when it calls
+ * us, so we need not (indeed, cannot) take it here.
+ */
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &cam->buffer_queue);
+}
+
+/*
+ * Free a buffer.
+ */
+static void viacam_vb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ videobuf_dma_unmap(q, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static const struct videobuf_queue_ops viacam_vb_ops = {
+ .buf_setup = viacam_vb_buf_setup,
+ .buf_prepare = viacam_vb_buf_prepare,
+ .buf_queue = viacam_vb_buf_queue,
+ .buf_release = viacam_vb_buf_release,
+};
+
+/* --------------------------------------------------------------------------*/
+/* File operations */
+
+static int viacam_open(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ filp->private_data = cam;
+ /*
+ * Note the new user. If this is the first one, we'll also
+ * need to power up the sensor.
+ */
+ mutex_lock(&cam->lock);
+ if (cam->users == 0) {
+ int ret = viafb_request_dma();
+
+ if (ret) {
+ mutex_unlock(&cam->lock);
+ return ret;
+ }
+ via_sensor_power_up(cam);
+ set_bit(CF_CONFIG_NEEDED, &cam->flags);
+ /*
+ * Hook into videobuf. Evidently this cannot fail.
+ */
+ videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
+ &cam->platdev->dev, &cam->viadev->reg_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), cam);
+ }
+ (cam->users)++;
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+static int viacam_release(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ mutex_lock(&cam->lock);
+ (cam->users)--;
+ /*
+ * If the "owner" is closing, shut down any ongoing
+ * operations.
+ */
+ if (filp == cam->owner) {
+ videobuf_stop(&cam->vb_queue);
+ if (cam->opstate != S_IDLE)
+ viacam_stop_engine(cam);
+ cam->owner = NULL;
+ }
+ /*
+ * Last one out needs to turn out the lights.
+ */
+ if (cam->users == 0) {
+ videobuf_mmap_free(&cam->vb_queue);
+ via_sensor_power_down(cam);
+ viafb_release_dma();
+ }
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+/*
+ * Read a frame from the device.
+ */
+static ssize_t viacam_read(struct file *filp, char __user *buffer,
+ size_t len, loff_t *pos)
+{
+ struct via_camera *cam = video_drvdata(filp);
+ int ret;
+
+ mutex_lock(&cam->lock);
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+ cam->owner = filp;
+ /*
+ * Do we need to configure the hardware?
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+ if (ret)
+ goto out_unlock;
+ }
+ /*
+ * Fire up the capture engine, then have videobuf do
+ * the heavy lifting. Someday it would be good to avoid
+ * stopping and restarting the engine each time.
+ */
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ viacam_start_engine(cam);
+ ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ viacam_stop_engine(cam);
+ /* videobuf_stop() ?? */
+
+out_unlock:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_poll_stream(filp, &cam->vb_queue, pt);
+}
+
+
+static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_mmap_mapper(&cam->vb_queue, vma);
+}
+
+
+
+static const struct v4l2_file_operations viacam_fops = {
+ .owner = THIS_MODULE,
+ .open = viacam_open,
+ .release = viacam_release,
+ .read = viacam_read,
+ .poll = viacam_poll,
+ .mmap = viacam_mmap,
+ .ioctl = video_ioctl2,
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * The long list of v4l2 ioctl ops
+ */
+
+static int viacam_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *ident)
+{
+ struct via_camera *cam = priv;
+
+ ident->ident = V4L2_IDENT_NONE;
+ ident->revision = 0;
+ if (v4l2_chip_match_host(&ident->match)) {
+ ident->ident = V4L2_IDENT_VIA_VX855;
+ return 0;
+ }
+ return sensor_call(cam, core, g_chip_ident, ident);
+}
+
+/*
+ * Control ops are passed through to the sensor.
+ */
+static int viacam_queryctrl(struct file *filp, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, queryctrl, qc);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_g_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, g_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_s_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, s_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/*
+ * Only one input.
+ */
+static int viacam_enum_input(struct file *filp, void *priv,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = V4L2_STD_ALL; /* Not sure what should go here */
+ strcpy(input->name, "Camera");
+ return 0;
+}
+
+static int viacam_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+ return 0;
+}
+
+/*
+ * Video format stuff. Here is our default format until
+ * user space messes with things.
+ */
+static struct v4l2_pix_format viacam_def_pix_format = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = VGA_WIDTH * 2,
+ .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
+};
+
+static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, enum_fmt, fmt);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/*
+ * Figure out proper image dimensions, but always force the
+ * sensor to VGA.
+ */
+static void viacam_fmt_pre(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ *sensorfmt = *userfmt;
+ if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) {
+ userfmt->width = QCIF_WIDTH;
+ userfmt->height = QCIF_HEIGHT;
+ }
+ if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) {
+ userfmt->width = VGA_WIDTH;
+ userfmt->height = VGA_HEIGHT;
+ }
+ sensorfmt->width = VGA_WIDTH;
+ sensorfmt->height = VGA_HEIGHT;
+}
+
+static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ userfmt->pixelformat = sensorfmt->pixelformat;
+ userfmt->field = sensorfmt->field;
+ userfmt->bytesperline = 2 * userfmt->width;
+ userfmt->sizeimage = userfmt->bytesperline * userfmt->height;
+}
+
+static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+ struct v4l2_format sfmt;
+
+ viacam_fmt_pre(&fmt->fmt.pix, &sfmt.fmt.pix);
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, try_fmt, &sfmt);
+ mutex_unlock(&cam->lock);
+ viacam_fmt_post(&fmt->fmt.pix, &sfmt.fmt.pix);
+ return ret;
+}
+
+static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+
+ fmt->fmt.pix = cam->user_format;
+ return 0;
+}
+
+static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+ struct v4l2_format sfmt;
+
+ /*
+ * Camera must be idle or we can't mess with the
+ * video setup.
+ */
+ if (cam->opstate != S_IDLE)
+ return -EBUSY;
+ /*
+ * Let the sensor code look over and tweak the
+ * requested formatting.
+ */
+ mutex_lock(&cam->lock);
+ viacam_fmt_pre(&fmt->fmt.pix, &sfmt.fmt.pix);
+ ret = sensor_call(cam, video, try_fmt, &sfmt);
+ if (ret)
+ goto out;
+ viacam_fmt_post(&fmt->fmt.pix, &sfmt.fmt.pix);
+ /*
+ * OK, let's commit to the new format.
+ */
+ cam->user_format = fmt->fmt.pix;
+ cam->sensor_format = sfmt.fmt.pix;
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+out:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+static int viacam_querycap(struct file *filp, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "via-camera");
+ strcpy(cap->card, "via-camera");
+ cap->version = 1;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+/*
+ * Streaming operations - pure videobuf stuff.
+ */
+static int viacam_reqbufs(struct file *filp, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_reqbufs(&cam->vb_queue, rb);
+}
+
+static int viacam_querybuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_querybuf(&cam->vb_queue, buf);
+}
+
+static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_qbuf(&cam->vb_queue, buf);
+}
+
+static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+}
+
+static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret = 0;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (cam->opstate != S_IDLE)
+ return -EBUSY;
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp)
+ return -EBUSY;
+ cam->owner = filp;
+ /*
+ * Configure things if need be.
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ mutex_lock(&cam->lock);
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+ mutex_unlock(&cam->lock);
+ }
+ /*
+ * If the CPU goes into C3, the DMA transfer gets corrupted and
+ * users start filing unsightly bug reports. Put in a "latency"
+ * requirement which will keep the CPU out of the deeper sleep
+ * states.
+ */
+ cam->qos_request = pm_qos_add_request(PM_QOS_CPU_DMA_LATENCY, 50);
+ /*
+ * Fire things up.
+ */
+ if (!ret) {
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ ret = videobuf_streamon(&cam->vb_queue);
+ if (!ret)
+ viacam_start_engine(cam);
+ }
+ return ret;
+}
+
+static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ pm_qos_remove_request(cam->qos_request);
+ viacam_stop_engine(cam);
+ /*
+ * Videobuf will recycle all of the outstanding buffers, but
+ * we should be sure we don't retain any references to
+ * any of them.
+ */
+ ret = videobuf_streamoff(&cam->vb_queue);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ return ret;
+}
+
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int viacam_vidiocgmbuf(struct file *filp, void *priv,
+ struct video_mbuf *mbuf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_cgmbuf(&cam->vb_queue, mbuf, 6);
+}
+#endif
+
+/* G/S_PARM */
+
+static int viacam_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, g_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, s_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ if (sizes->index != 0)
+ return -EINVAL;
+ sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ sizes->stepwise.min_width = QCIF_WIDTH;
+ sizes->stepwise.min_height = QCIF_HEIGHT;
+ sizes->stepwise.max_width = VGA_WIDTH;
+ sizes->stepwise.max_height = VGA_HEIGHT;
+ sizes->stepwise.step_width = sizes->stepwise.step_height = 1;
+ return 0;
+}
+
+static int viacam_enum_frameintervals(struct file *filp, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, enum_frameintervals, interval);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+
+static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
+ .vidioc_g_chip_ident = viacam_g_chip_ident,
+ .vidioc_queryctrl = viacam_queryctrl,
+ .vidioc_g_ctrl = viacam_g_ctrl,
+ .vidioc_s_ctrl = viacam_s_ctrl,
+ .vidioc_enum_input = viacam_enum_input,
+ .vidioc_g_input = viacam_g_input,
+ .vidioc_s_input = viacam_s_input,
+ .vidioc_s_std = viacam_s_std,
+ .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap,
+ .vidioc_querycap = viacam_querycap,
+ .vidioc_reqbufs = viacam_reqbufs,
+ .vidioc_querybuf = viacam_querybuf,
+ .vidioc_qbuf = viacam_qbuf,
+ .vidioc_dqbuf = viacam_dqbuf,
+ .vidioc_streamon = viacam_streamon,
+ .vidioc_streamoff = viacam_streamoff,
+ .vidioc_g_parm = viacam_g_parm,
+ .vidioc_s_parm = viacam_s_parm,
+ .vidioc_enum_framesizes = viacam_enum_framesizes,
+ .vidioc_enum_frameintervals = viacam_enum_frameintervals,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = viacam_vidiocgmbuf,
+#endif
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Power management.
+ */
+
+/*
+ * Setup stuff.
+ */
+
+static struct video_device viacam_v4l_template = {
+ .name = "via-camera",
+ .minor = -1,
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
+ .fops = &viacam_fops,
+ .ioctl_ops = &viacam_ioctl_ops,
+ .release = video_device_release_empty, /* Check this */
+};
+
+
+static __devinit int viacam_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct i2c_adapter *sensor_adapter;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ /*
+ * Note that there are actually two capture channels on
+ * the device. We only deal with one for now. That
+ * is encoded here; nothing else assumes it's dealing with
+ * a unique capture device.
+ */
+ struct via_camera *cam = &via_cam_info;
+
+ /*
+ * Ensure that frame buffer memory has been set aside for
+ * this purpose. As an arbitrary limit, refuse to work
+ * with less than two frames of VGA 16-bit data.
+ *
+ * If we ever support the second port, we'll need to set
+ * aside more memory.
+ */
+ if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) {
+ printk(KERN_ERR "viacam: insufficient FB memory reserved\n");
+ return -ENOMEM;
+ }
+ if (viadev->engine_mmio == NULL) {
+ printk(KERN_ERR "viacam: No I/O memory, so no pictures\n");
+ return -ENOMEM;
+ }
+ /*
+ * Basic structure initialization.
+ */
+ cam->platdev = pdev;
+ cam->viadev = viadev;
+ cam->users = 0;
+ cam->owner = NULL;
+ cam->opstate = S_IDLE;
+ cam->user_format = cam->sensor_format = viacam_def_pix_format;
+ mutex_init(&cam->lock);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ cam->mmio = viadev->engine_mmio;
+ cam->fbmem = viadev->fbmem;
+ cam->fb_offset = viadev->camera_fbmem_offset;
+ cam->flags = 1 << CF_CONFIG_NEEDED;
+ /*
+ * Tell V4L that we exist.
+ */
+ ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register v4l2 device\n");
+ return ret;
+ }
+ /*
+ * Convince the system that we can do DMA.
+ */
+ pdev->dev.dma_mask = &viadev->pdev->dma_mask;
+ dma_set_mask(&pdev->dev, 0xffffffff);
+ /*
+ * Fire up the capture port. The write to 0x78 looks purely
+ * OLPCish; any system will need to tweak 0x1e.
+ */
+ via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+ via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+ /*
+ * Get the sensor powered up.
+ */
+ ret = via_sensor_power_setup(cam);
+ if (ret)
+ goto out_unregister;
+ via_sensor_power_up(cam);
+
+ /*
+ * See if we can't find it on the bus. The VIA_PORT_31 assumption
+ * is OLPC-specific. 0x42 assumption is ov7670-specific.
+ */
+ sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
+ cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
+ "ov7670", "ov7670", 0x42 >> 1, NULL);
+ if (cam->sensor == NULL) {
+ dev_err(&pdev->dev, "Unable to find the sensor!\n");
+ ret = -ENODEV;
+ goto out_power_down;
+ }
+ /*
+ * Get the IRQ.
+ */
+ viacam_int_disable(cam);
+ ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq,
+ viacam_irq, IRQF_SHARED, "via-camera", cam);
+ if (ret)
+ goto out_power_down;
+ /*
+ * Tell V4l2 that we exist.
+ */
+ cam->vdev = viacam_v4l_template;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto out_irq;
+ video_set_drvdata(&cam->vdev, cam);
+
+ /* Power the sensor down until somebody opens the device */
+ via_sensor_power_down(cam);
+ return 0;
+
+out_irq:
+ free_irq(viadev->pdev->irq, cam);
+out_power_down:
+ via_sensor_power_release(cam);
+out_unregister:
+ v4l2_device_unregister(&cam->v4l2_dev);
+ return ret;
+}
+
+static __devexit int viacam_remove(struct platform_device *pdev)
+{
+ struct via_camera *cam = &via_cam_info;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ video_unregister_device(&cam->vdev);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ free_irq(viadev->pdev->irq, cam);
+ via_sensor_power_release(cam);
+ return 0;
+}
+
+
+static struct platform_driver viacam_driver = {
+ .driver = {
+ .name = "viafb-camera",
+ },
+ .probe = viacam_probe,
+ .remove = viacam_remove,
+};
+
+
+#ifdef CONFIG_OLPC_XO_1_5
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera. They also get grumpy if we break the
+ * serial port and keep them from using it. So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit int viacam_check_serial_port(void)
+{
+ struct pci_bus *pbus = pci_find_bus(0, 0);
+ u8 cbyte;
+
+ pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, &cbyte);
+ if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+ return 0; /* Not enabled */
+ if (override_serial == 0) {
+ printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+ "refusing to load.\n");
+ printk(KERN_NOTICE "Specify override_serial=1 to force " \
+ "module loading.\n");
+ return -EBUSY;
+ }
+ printk(KERN_NOTICE "Via camera: overriding serial port\n");
+ pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+ return 0;
+}
+#endif
+
+
+
+
+static int viacam_init(void)
+{
+#ifdef CONFIG_OLPC_XO_1_5
+ if (viacam_check_serial_port())
+ return -EBUSY;
+#endif
+ return platform_driver_register(&viacam_driver);
+}
+module_init(viacam_init);
+
+static void viacam_exit(void)
+{
+ platform_driver_unregister(&viacam_driver);
+}
+module_exit(viacam_exit);
diff --git a/drivers/media/video/via-camera.h b/drivers/media/video/via-camera.h
new file mode 100644
index 000000000000..b12a4b3d616f
--- /dev/null
+++ b/drivers/media/video/via-camera.h
@@ -0,0 +1,93 @@
+/*
+ * VIA Camera register definitions.
+ */
+#define VCR_INTCTRL 0x300 /* Capture interrupt control */
+#define VCR_IC_EAV 0x0001 /* End of active video status */
+#define VCR_IC_EVBI 0x0002 /* End of VBI status */
+#define VCR_IC_FBOTFLD 0x0004 /* "flipping" Bottom field is active */
+#define VCR_IC_ACTBUF 0x0018 /* Active video buffer */
+#define VCR_IC_VSYNC 0x0020 /* 0 = VB, 1 = active video */
+#define VCR_IC_BOTFLD 0x0040 /* Bottom field is active */
+#define VCR_IC_FFULL 0x0080 /* FIFO full */
+#define VCR_IC_INTEN 0x0100 /* End of active video int. enable */
+#define VCR_IC_VBIINT 0x0200 /* End of VBI int enable */
+#define VCR_IC_VBIBUF 0x0400 /* Current VBI buffer */
+
+#define VCR_TSC 0x308 /* Transport stream control */
+#define VCR_TSC_ENABLE 0x000001 /* Transport stream input enable */
+#define VCR_TSC_DROPERR 0x000002 /* Drop error packets */
+#define VCR_TSC_METHOD 0x00000c /* DMA method (non-functional) */
+#define VCR_TSC_COUNT 0x07fff0 /* KByte or packet count */
+#define VCR_TSC_CBMODE 0x080000 /* Change buffer by byte count */
+#define VCR_TSC_PSSIG 0x100000 /* Packet starting signal disable */
+#define VCR_TSC_BE 0x200000 /* MSB first (serial mode) */
+#define VCR_TSC_SERIAL 0x400000 /* Serial input (0 = parallel) */
+
+#define VCR_CAPINTC 0x310 /* Capture interface control */
+#define VCR_CI_ENABLE 0x00000001 /* Capture enable */
+#define VCR_CI_BSS 0x00000002 /* WTF "bit stream selection" */
+#define VCR_CI_3BUFS 0x00000004 /* 1 = 3 buffers, 0 = 2 buffers */
+#define VCR_CI_VIPEN 0x00000008 /* VIP enable */
+#define VCR_CI_CCIR601_8 0 /* CCIR601 input stream, 8 bit */
+#define VCR_CI_CCIR656_8 0x00000010 /* ... CCIR656, 8 bit */
+#define VCR_CI_CCIR601_16 0x00000020 /* ... CCIR601, 16 bit */
+#define VCR_CI_CCIR656_16 0x00000030 /* ... CCIR656, 16 bit */
+#define VCR_CI_HDMODE 0x00000040 /* CCIR656-16 hdr decode mode; 1=16b */
+#define VCR_CI_BSWAP 0x00000080 /* Swap bytes (16-bit) */
+#define VCR_CI_YUYV 0 /* Byte order 0123 */
+#define VCR_CI_UYVY 0x00000100 /* Byte order 1032 */
+#define VCR_CI_YVYU 0x00000200 /* Byte order 0321 */
+#define VCR_CI_VYUY 0x00000300 /* Byte order 3012 */
+#define VCR_CI_VIPTYPE 0x00000400 /* VIP type */
+#define VCR_CI_IFSEN 0x00000800 /* Input field signal enable */
+#define VCR_CI_DIODD 0 /* De-interlace odd, 30fps */
+#define VCR_CI_DIEVEN 0x00001000 /* ...even field, 30fps */
+#define VCR_CI_DIBOTH 0x00002000 /* ...both fields, 60fps */
+#define VCR_CI_DIBOTH30 0x00003000 /* ...both fields, 30fps interlace */
+#define VCR_CI_CONVTYPE 0x00004000 /* 4:2:2 to 4:4:4; 1 = interpolate */
+#define VCR_CI_CFC 0x00008000 /* Capture flipping control */
+#define VCR_CI_FILTER 0x00070000 /* Horiz filter mode select
+ 000 = none
+ 001 = 2 tap
+ 010 = 3 tap
+ 011 = 4 tap
+ 100 = 5 tap */
+#define VCR_CI_CLKINV 0x00080000 /* Input CLK inverted */
+#define VCR_CI_VREFINV 0x00100000 /* VREF inverted */
+#define VCR_CI_HREFINV 0x00200000 /* HREF inverted */
+#define VCR_CI_FLDINV 0x00400000 /* Field inverted */
+#define VCR_CI_CLKPIN 0x00800000 /* Capture clock pin */
+#define VCR_CI_THRESH 0x0f000000 /* Capture fifo threshold */
+#define VCR_CI_HRLE 0x10000000 /* Positive edge of HREF */
+#define VCR_CI_VRLE 0x20000000 /* Positive edge of VREF */
+#define VCR_CI_OFLDINV 0x40000000 /* Field output inverted */
+#define VCR_CI_CLKEN 0x80000000 /* Capture clock enable */
+
+#define VCR_HORRANGE 0x314 /* Active video horizontal range */
+#define VCR_VERTRANGE 0x318 /* Active video vertical range */
+#define VCR_AVSCALE 0x31c /* Active video scaling control */
+#define VCR_AVS_HEN 0x00000800 /* Horizontal scale enable */
+#define VCR_AVS_VEN 0x04000000 /* Vertical enable */
+#define VCR_VBIHOR 0x320 /* VBI Data horizontal range */
+#define VCR_VBIVERT 0x324 /* VBI data vertical range */
+#define VCR_VBIBUF1 0x328 /* First VBI buffer */
+#define VCR_VBISTRIDE 0x32c /* VBI stride */
+#define VCR_ANCDATACNT 0x330 /* Ancillary data count setting */
+#define VCR_MAXDATA 0x334 /* Active data count of active video */
+#define VCR_MAXVBI 0x338 /* Maximum data count of VBI */
+#define VCR_CAPDATA 0x33c /* Capture data count */
+#define VCR_VBUF1 0x340 /* First video buffer */
+#define VCR_VBUF2 0x344 /* Second video buffer */
+#define VCR_VBUF3 0x348 /* Third video buffer */
+#define VCR_VBUF_MASK 0x1ffffff0 /* Bits 28:4 */
+#define VCR_VBIBUF2 0x34c /* Second VBI buffer */
+#define VCR_VSTRIDE 0x350 /* Stride of video + coring control */
+#define VCR_VS_STRIDE_SHIFT 4
+#define VCR_VS_STRIDE 0x00001ff0 /* Stride (8-byte units) */
+#define VCR_VS_CCD 0x007f0000 /* Coring compare data */
+#define VCR_VS_COREEN 0x00800000 /* Coring enable */
+#define VCR_TS0ERR 0x354 /* TS buffer 0 error indicator */
+#define VCR_TS1ERR 0x358 /* TS buffer 0 error indicator */
+#define VCR_TS2ERR 0x35c /* TS buffer 0 error indicator */
+
+/* Add 0x1000 for the second capture engine registers */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index a6a57011ba6c..b112f34d264b 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -109,8 +109,7 @@ MODULE_PARM_DESC(mpt_debug_level, " debug level - refer to mptdebug.h \
int mpt_fwfault_debug;
EXPORT_SYMBOL(mpt_fwfault_debug);
-module_param_call(mpt_fwfault_debug, param_set_int, param_get_int,
- &mpt_fwfault_debug, 0600);
+module_param(mpt_fwfault_debug, int, 0600);
MODULE_PARM_DESC(mpt_fwfault_debug, "Enable detection of Firmware fault"
" and halt Firmware on fault - (default=0)");
diff --git a/drivers/mfd/88pm860x-i2c.c b/drivers/mfd/88pm860x-i2c.c
index c933b64d1283..bc02e6b21608 100644
--- a/drivers/mfd/88pm860x-i2c.c
+++ b/drivers/mfd/88pm860x-i2c.c
@@ -200,8 +200,6 @@ static int __devexit pm860x_remove(struct i2c_client *client)
pm860x_device_exit(chip);
i2c_unregister_device(chip->companion);
- i2c_set_clientdata(chip->client, NULL);
- i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c
index 53ebfee548fa..66379b413906 100644
--- a/drivers/mfd/ab3100-core.c
+++ b/drivers/mfd/ab3100-core.c
@@ -957,7 +957,6 @@ static int __init ab3100_probe(struct i2c_client *client,
i2c_unregister_device(ab3100->testreg_client);
exit_no_testreg_client:
exit_no_detect:
- i2c_set_clientdata(client, NULL);
kfree(ab3100);
return err;
}
@@ -979,7 +978,6 @@ static int __exit ab3100_remove(struct i2c_client *client)
* their notifiers so deactivate IRQ
*/
free_irq(client->irq, ab3100);
- i2c_set_clientdata(client, NULL);
kfree(ab3100);
return 0;
}
diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c
index 1060f8e1c40a..f54ab62e7bc6 100644
--- a/drivers/mfd/ab3550-core.c
+++ b/drivers/mfd/ab3550-core.c
@@ -1362,7 +1362,6 @@ static int __exit ab3550_remove(struct i2c_client *client)
* their notifiers so deactivate IRQ
*/
free_irq(client->irq, ab);
- i2c_set_clientdata(client, NULL);
kfree(ab);
return 0;
}
diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c
index 005532865654..3122139b4300 100644
--- a/drivers/mfd/adp5520.c
+++ b/drivers/mfd/adp5520.c
@@ -302,7 +302,6 @@ out_free_irq:
free_irq(chip->irq, chip);
out_free_chip:
- i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
@@ -317,7 +316,6 @@ static int __devexit adp5520_remove(struct i2c_client *client)
adp5520_remove_subdevs(chip);
adp5520_write(chip->dev, ADP5520_MODE_STATUS, 0);
- i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c
index 3ad915d0589c..c07aece900fb 100644
--- a/drivers/mfd/da903x.c
+++ b/drivers/mfd/da903x.c
@@ -534,7 +534,6 @@ static int __devinit da903x_probe(struct i2c_client *client,
out_free_irq:
free_irq(client->irq, chip);
out_free_chip:
- i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}
@@ -544,7 +543,6 @@ static int __devexit da903x_remove(struct i2c_client *client)
struct da903x_chip *chip = i2c_get_clientdata(client);
da903x_remove_subdevs(chip);
- i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/max8925-i2c.c b/drivers/mfd/max8925-i2c.c
index e73f3f5252a8..0219115e00c7 100644
--- a/drivers/mfd/max8925-i2c.c
+++ b/drivers/mfd/max8925-i2c.c
@@ -173,7 +173,6 @@ static int __devexit max8925_remove(struct i2c_client *client)
max8925_device_exit(chip);
i2c_unregister_device(chip->adc);
i2c_unregister_device(chip->rtc);
- i2c_set_clientdata(chip->i2c, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c
index 721948be12c7..a3fb4bcb9889 100644
--- a/drivers/mfd/menelaus.c
+++ b/drivers/mfd/menelaus.c
@@ -1228,7 +1228,6 @@ fail2:
free_irq(client->irq, menelaus);
flush_scheduled_work();
fail1:
- i2c_set_clientdata(client, NULL);
kfree(menelaus);
return err;
}
@@ -1238,7 +1237,6 @@ static int __exit menelaus_remove(struct i2c_client *client)
struct menelaus_chip *menelaus = i2c_get_clientdata(client);
free_irq(client->irq, menelaus);
- i2c_set_clientdata(client, NULL);
kfree(menelaus);
the_menelaus = NULL;
return 0;
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 704736e6e9b9..23e585527285 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -336,7 +336,6 @@ static int __devinit pcf50633_probe(struct i2c_client *client,
return 0;
err_free:
- i2c_set_clientdata(client, NULL);
kfree(pcf);
return ret;
@@ -357,7 +356,6 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
for (i = 0; i < PCF50633_NUM_REGULATORS; i++)
platform_device_unregister(pcf->regulator_pdev[i]);
- i2c_set_clientdata(client, NULL);
kfree(pcf);
return 0;
diff --git a/drivers/mfd/tc35892.c b/drivers/mfd/tc35892.c
index 715f095dd7a6..e619e2a55997 100644
--- a/drivers/mfd/tc35892.c
+++ b/drivers/mfd/tc35892.c
@@ -296,7 +296,6 @@ out_freeirq:
out_removeirq:
tc35892_irq_remove(tc35892);
out_free:
- i2c_set_clientdata(i2c, NULL);
kfree(tc35892);
return ret;
}
@@ -310,7 +309,6 @@ static int __devexit tc35892_remove(struct i2c_client *client)
free_irq(tc35892->i2c->irq, tc35892);
tc35892_irq_remove(tc35892);
- i2c_set_clientdata(client, NULL);
kfree(tc35892);
return 0;
diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c
index 9b22a77f70f5..d0016b67d125 100644
--- a/drivers/mfd/tps65010.c
+++ b/drivers/mfd/tps65010.c
@@ -530,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client)
cancel_delayed_work(&tps->work);
flush_scheduled_work();
debugfs_remove(tps->file);
- i2c_set_clientdata(client, NULL);
kfree(tps);
the_tps = NULL;
return 0;
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
index 7795af4b1fe1..5fe5de166adb 100644
--- a/drivers/mfd/wm8350-i2c.c
+++ b/drivers/mfd/wm8350-i2c.c
@@ -80,7 +80,6 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
return ret;
err:
- i2c_set_clientdata(i2c, NULL);
kfree(wm8350);
return ret;
}
@@ -90,7 +89,6 @@ static int wm8350_i2c_remove(struct i2c_client *i2c)
struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
wm8350_device_exit(wm8350);
- i2c_set_clientdata(i2c, NULL);
kfree(wm8350);
return 0;
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
index e08aafa663dc..1bfef4846b07 100644
--- a/drivers/mfd/wm8400-core.c
+++ b/drivers/mfd/wm8400-core.c
@@ -415,7 +415,6 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
return 0;
struct_err:
- i2c_set_clientdata(i2c, NULL);
kfree(wm8400);
err:
return ret;
@@ -426,7 +425,6 @@ static int wm8400_i2c_remove(struct i2c_client *i2c)
struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
wm8400_release(wm8400);
- i2c_set_clientdata(i2c, NULL);
kfree(wm8400);
return 0;
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index f7ca3a42b490..559b0b3c16c3 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -643,7 +643,6 @@ static int __devexit at24_remove(struct i2c_client *client)
kfree(at24->writebuf);
kfree(at24);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
index 5bfb2a2041b8..ef34de7a8026 100644
--- a/drivers/misc/lkdtm.c
+++ b/drivers/misc/lkdtm.c
@@ -124,9 +124,9 @@ static int count = DEFAULT_COUNT;
module_param(recur_count, int, 0644);
MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\
"default is 10");
-module_param(cpoint_name, charp, 0644);
+module_param(cpoint_name, charp, 0444);
MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed");
-module_param(cpoint_type, charp, 0644);
+module_param(cpoint_type, charp, 0444);
MODULE_PARM_DESC(cpoint_type, " Crash Point Type, action to be taken on "\
"hitting the crash point");
module_param(cpoint_count, int, 0644);
diff --git a/drivers/misc/vmware_balloon.c b/drivers/misc/vmware_balloon.c
index db9cd0240c6f..2a1e804a71aa 100644
--- a/drivers/misc/vmware_balloon.c
+++ b/drivers/misc/vmware_balloon.c
@@ -45,7 +45,7 @@
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Memory Control (Balloon) Driver");
-MODULE_VERSION("1.2.1.0-K");
+MODULE_VERSION("1.2.1.1-k");
MODULE_ALIAS("dmi:*:svnVMware*:*");
MODULE_ALIAS("vmware_vmmemctl");
MODULE_LICENSE("GPL");
@@ -101,6 +101,8 @@ MODULE_LICENSE("GPL");
/* Maximum number of page allocations without yielding processor */
#define VMW_BALLOON_YIELD_THRESHOLD 1024
+/* Maximum number of refused pages we accumulate during inflation cycle */
+#define VMW_BALLOON_MAX_REFUSED 16
/*
* Hypervisor communication port definitions.
@@ -183,6 +185,7 @@ struct vmballoon {
/* transient list of non-balloonable pages */
struct list_head refused_pages;
+ unsigned int n_refused_pages;
/* balloon size in pages */
unsigned int size;
@@ -428,14 +431,21 @@ static int vmballoon_reserve_page(struct vmballoon *b, bool can_sleep)
/* inform monitor */
locked = vmballoon_send_lock_page(b, page_to_pfn(page));
if (!locked) {
+ STATS_INC(b->stats.refused_alloc);
+
if (b->reset_required) {
__free_page(page);
return -EIO;
}
- /* place on list of non-balloonable pages, retry allocation */
+ /*
+ * Place page on the list of non-balloonable pages
+ * and retry allocation, unless we already accumulated
+ * too many of them, in which case take a breather.
+ */
list_add(&page->lru, &b->refused_pages);
- STATS_INC(b->stats.refused_alloc);
+ if (++b->n_refused_pages >= VMW_BALLOON_MAX_REFUSED)
+ return -EIO;
}
} while (!locked);
@@ -483,6 +493,8 @@ static void vmballoon_release_refused_pages(struct vmballoon *b)
__free_page(page);
STATS_INC(b->stats.refused_free);
}
+
+ b->n_refused_pages = 0;
}
/*
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index e171e77f6129..f06d06e7fdfa 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -249,7 +249,7 @@ config MMC_IMX
config MMC_MSM7X00A
tristate "Qualcomm MSM 7X00A SDCC Controller Support"
- depends on MMC && ARCH_MSM
+ depends on MMC && ARCH_MSM && !ARCH_MSM7X30
help
This provides support for the SD/MMC cell found in the
MSM 7X00A controllers from Qualcomm.
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index d9d4a72e0ec7..fdf33e837a73 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -119,6 +119,7 @@ struct mxcmci_host {
int detect_irq;
int dma;
int do_dma;
+ int default_irq_mask;
int use_sdio;
unsigned int power_mode;
struct imxmmc_platform_data *pdata;
@@ -228,7 +229,7 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
unsigned int cmdat)
{
- u32 int_cntr;
+ u32 int_cntr = host->default_irq_mask;
unsigned long flags;
WARN_ON(host->cmd != NULL);
@@ -275,7 +276,7 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
static void mxcmci_finish_request(struct mxcmci_host *host,
struct mmc_request *req)
{
- u32 int_cntr = 0;
+ u32 int_cntr = host->default_irq_mask;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
@@ -585,6 +586,9 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
(stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
mxcmci_data_done(host, stat);
#endif
+ if (host->default_irq_mask &&
+ (stat & (STATUS_CARD_INSERTION | STATUS_CARD_REMOVAL)))
+ mmc_detect_change(host->mmc, msecs_to_jiffies(200));
return IRQ_HANDLED;
}
@@ -809,6 +813,12 @@ static int mxcmci_probe(struct platform_device *pdev)
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (host->pdata && host->pdata->dat3_card_detect)
+ host->default_irq_mask =
+ INT_CARD_INSERTION_EN | INT_CARD_REMOVAL_EN;
+ else
+ host->default_irq_mask = 0;
+
host->res = r;
host->irq = irq;
@@ -835,7 +845,7 @@ static int mxcmci_probe(struct platform_device *pdev)
/* recommended in data sheet */
writew(0x2db4, host->base + MMC_REG_READ_TO);
- writel(0, host->base + MMC_REG_INT_CNTR);
+ writel(host->default_irq_mask, host->base + MMC_REG_INT_CNTR);
#ifdef HAS_DMA
host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c
index 2b281680e320..d98ddcfac5e5 100644
--- a/drivers/mmc/host/omap.c
+++ b/drivers/mmc/host/omap.c
@@ -1157,7 +1157,6 @@ static void mmc_omap_start_request(struct mmc_omap_host *host,
mmc_omap_start_command(host, req->cmd);
if (host->dma_in_use)
omap_start_dma(host->dma_ch);
- BUG_ON(irqs_disabled());
}
static void mmc_omap_request(struct mmc_host *mmc, struct mmc_request *req)
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index eb97830c0344..5d3f824bb5a3 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -30,25 +30,6 @@
#define DRIVER_NAME "sh_mmcif"
#define DRIVER_VERSION "2010-04-28"
-#define MMCIF_CE_CMD_SET 0x00000000
-#define MMCIF_CE_ARG 0x00000008
-#define MMCIF_CE_ARG_CMD12 0x0000000C
-#define MMCIF_CE_CMD_CTRL 0x00000010
-#define MMCIF_CE_BLOCK_SET 0x00000014
-#define MMCIF_CE_CLK_CTRL 0x00000018
-#define MMCIF_CE_BUF_ACC 0x0000001C
-#define MMCIF_CE_RESP3 0x00000020
-#define MMCIF_CE_RESP2 0x00000024
-#define MMCIF_CE_RESP1 0x00000028
-#define MMCIF_CE_RESP0 0x0000002C
-#define MMCIF_CE_RESP_CMD12 0x00000030
-#define MMCIF_CE_DATA 0x00000034
-#define MMCIF_CE_INT 0x00000040
-#define MMCIF_CE_INT_MASK 0x00000044
-#define MMCIF_CE_HOST_STS1 0x00000048
-#define MMCIF_CE_HOST_STS2 0x0000004C
-#define MMCIF_CE_VERSION 0x0000007C
-
/* CE_CMD_SET */
#define CMD_MASK 0x3f000000
#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22))
@@ -207,27 +188,17 @@ struct sh_mmcif_host {
wait_queue_head_t intr_wait;
};
-static inline u32 sh_mmcif_readl(struct sh_mmcif_host *host, unsigned int reg)
-{
- return readl(host->addr + reg);
-}
-
-static inline void sh_mmcif_writel(struct sh_mmcif_host *host,
- unsigned int reg, u32 val)
-{
- writel(val, host->addr + reg);
-}
static inline void sh_mmcif_bitset(struct sh_mmcif_host *host,
unsigned int reg, u32 val)
{
- writel(val | sh_mmcif_readl(host, reg), host->addr + reg);
+ writel(val | readl(host->addr + reg), host->addr + reg);
}
static inline void sh_mmcif_bitclr(struct sh_mmcif_host *host,
unsigned int reg, u32 val)
{
- writel(~val & sh_mmcif_readl(host, reg), host->addr + reg);
+ writel(~val & readl(host->addr + reg), host->addr + reg);
}
@@ -253,10 +224,10 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
{
u32 tmp;
- tmp = 0x010f0000 & sh_mmcif_readl(host, MMCIF_CE_CLK_CTRL);
+ tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL);
- sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_ON);
- sh_mmcif_writel(host, MMCIF_CE_VERSION, SOFT_RST_OFF);
+ sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON);
+ sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF);
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
/* byte swap on */
@@ -271,12 +242,10 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
host->sd_error = 0;
host->wait_int = 0;
- state1 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS1);
- state2 = sh_mmcif_readl(host, MMCIF_CE_HOST_STS2);
- pr_debug("%s: ERR HOST_STS1 = %08x\n", \
- DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS1));
- pr_debug("%s: ERR HOST_STS2 = %08x\n", \
- DRIVER_NAME, sh_mmcif_readl(host, MMCIF_CE_HOST_STS2));
+ state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1);
+ state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2);
+ pr_debug("%s: ERR HOST_STS1 = %08x\n", DRIVER_NAME, state1);
+ pr_debug("%s: ERR HOST_STS2 = %08x\n", DRIVER_NAME, state2);
if (state1 & STS1_CMDSEQ) {
sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK);
@@ -288,7 +257,7 @@ static int sh_mmcif_error_manage(struct sh_mmcif_host *host)
"command sequence timeout err\n");
return -EIO;
}
- if (!(sh_mmcif_readl(host, MMCIF_CE_HOST_STS1)
+ if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1)
& STS1_CMDSEQ))
break;
mdelay(1);
@@ -330,9 +299,9 @@ static int sh_mmcif_single_read(struct sh_mmcif_host *host,
host->wait_int = 0;
blocksize = (BLOCK_SIZE_MASK &
- sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+ sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
for (i = 0; i < blocksize / 4; i++)
- *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+ *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA);
/* buffer read end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
@@ -353,7 +322,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
long time;
u32 blocksize, i, j, sec, *p;
- blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+ blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
+ MMCIF_CE_BLOCK_SET);
for (j = 0; j < data->sg_len; j++) {
p = sg_virt(data->sg);
host->wait_int = 0;
@@ -370,7 +340,8 @@ static int sh_mmcif_multi_read(struct sh_mmcif_host *host,
host->wait_int = 0;
for (i = 0; i < blocksize / 4; i++)
- *p++ = sh_mmcif_readl(host, MMCIF_CE_DATA);
+ *p++ = sh_mmcif_readl(host->addr,
+ MMCIF_CE_DATA);
}
if (j < data->sg_len - 1)
data->sg++;
@@ -397,9 +368,9 @@ static int sh_mmcif_single_write(struct sh_mmcif_host *host,
host->wait_int = 0;
blocksize = (BLOCK_SIZE_MASK &
- sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET)) + 3;
+ sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET)) + 3;
for (i = 0; i < blocksize / 4; i++)
- sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+ sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++);
/* buffer write end */
sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
@@ -421,7 +392,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
long time;
u32 i, sec, j, blocksize, *p;
- blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host, MMCIF_CE_BLOCK_SET);
+ blocksize = BLOCK_SIZE_MASK & sh_mmcif_readl(host->addr,
+ MMCIF_CE_BLOCK_SET);
for (j = 0; j < data->sg_len; j++) {
p = sg_virt(data->sg);
@@ -439,7 +411,8 @@ static int sh_mmcif_multi_write(struct sh_mmcif_host *host,
host->wait_int = 0;
for (i = 0; i < blocksize / 4; i++)
- sh_mmcif_writel(host, MMCIF_CE_DATA, *p++);
+ sh_mmcif_writel(host->addr,
+ MMCIF_CE_DATA, *p++);
}
if (j < data->sg_len - 1)
data->sg++;
@@ -451,18 +424,18 @@ static void sh_mmcif_get_response(struct sh_mmcif_host *host,
struct mmc_command *cmd)
{
if (cmd->flags & MMC_RSP_136) {
- cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP3);
- cmd->resp[1] = sh_mmcif_readl(host, MMCIF_CE_RESP2);
- cmd->resp[2] = sh_mmcif_readl(host, MMCIF_CE_RESP1);
- cmd->resp[3] = sh_mmcif_readl(host, MMCIF_CE_RESP0);
+ cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3);
+ cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2);
+ cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1);
+ cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
} else
- cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP0);
+ cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0);
}
static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host,
struct mmc_command *cmd)
{
- cmd->resp[0] = sh_mmcif_readl(host, MMCIF_CE_RESP_CMD12);
+ cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12);
}
static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
@@ -596,18 +569,19 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO;
if (host->data) {
- sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, 0);
- sh_mmcif_writel(host, MMCIF_CE_BLOCK_SET, mrq->data->blksz);
+ sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
+ sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
+ mrq->data->blksz);
}
opc = sh_mmcif_set_cmd(host, mrq, cmd, opc);
- sh_mmcif_writel(host, MMCIF_CE_INT, 0xD80430C0);
- sh_mmcif_writel(host, MMCIF_CE_INT_MASK, mask);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
/* set arg */
- sh_mmcif_writel(host, MMCIF_CE_ARG, cmd->arg);
+ sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
host->wait_int = 0;
/* set cmd */
- sh_mmcif_writel(host, MMCIF_CE_CMD_SET, opc);
+ sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc);
time = wait_event_interruptible_timeout(host->intr_wait,
host->wait_int == 1 || host->sd_error == 1, host->timeout);
@@ -752,43 +726,44 @@ static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
u32 state = 0;
int err = 0;
- state = sh_mmcif_readl(host, MMCIF_CE_INT);
+ state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
if (state & INT_RBSYE) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~(INT_RBSYE | INT_CRSPE));
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT,
+ ~(INT_RBSYE | INT_CRSPE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MRBSYE);
} else if (state & INT_CRSPE) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_CRSPE);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_CRSPE);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCRSPE);
} else if (state & INT_BUFREN) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFREN);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFREN);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFREN);
} else if (state & INT_BUFWEN) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFWEN);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFWEN);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN);
} else if (state & INT_CMD12DRE) {
- sh_mmcif_writel(host, MMCIF_CE_INT,
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT,
~(INT_CMD12DRE | INT_CMD12RBE |
INT_CMD12CRE | INT_BUFRE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE);
} else if (state & INT_BUFRE) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_BUFRE);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_BUFRE);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MBUFRE);
} else if (state & INT_DTRANE) {
- sh_mmcif_writel(host, MMCIF_CE_INT, ~INT_DTRANE);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~INT_DTRANE);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MDTRANE);
} else if (state & INT_CMD12RBE) {
- sh_mmcif_writel(host, MMCIF_CE_INT,
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT,
~(INT_CMD12RBE | INT_CMD12CRE));
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE);
} else if (state & INT_ERR_STS) {
/* err interrupts */
- sh_mmcif_writel(host, MMCIF_CE_INT, ~state);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
} else {
pr_debug("%s: Not support int\n", DRIVER_NAME);
- sh_mmcif_writel(host, MMCIF_CE_INT, ~state);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~state);
sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state);
err = 1;
}
@@ -894,12 +869,12 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
goto clean_up2;
}
- sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
sh_mmcif_detect(host->mmc);
pr_info("%s: driver version %s\n", DRIVER_NAME, DRIVER_VERSION);
pr_debug("%s: chip ver H'%04x\n", DRIVER_NAME,
- sh_mmcif_readl(host, MMCIF_CE_VERSION) & 0x0000ffff);
+ sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
return ret;
clean_up2:
@@ -917,7 +892,7 @@ static int __devexit sh_mmcif_remove(struct platform_device *pdev)
struct sh_mmcif_host *host = platform_get_drvdata(pdev);
int irq[2];
- sh_mmcif_writel(host, MMCIF_CE_INT_MASK, MASK_ALL);
+ sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
irq[0] = platform_get_irq(pdev, 0);
irq[1] = platform_get_irq(pdev, 1);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index ba124baa646d..6ac5f9f28ac3 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -353,7 +353,7 @@ static int __devinit of_flash_probe(struct of_device *dev,
&info->parts, 0);
if (err < 0) {
of_free_probes(part_probe_types);
- return err;
+ goto err_out;
}
of_free_probes(part_probe_types);
@@ -361,14 +361,14 @@ static int __devinit of_flash_probe(struct of_device *dev,
if (err == 0) {
err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
if (err < 0)
- return err;
+ goto err_out;
}
#endif
if (err == 0) {
err = parse_obsolete_partitions(dev, info, dp);
if (err < 0)
- return err;
+ goto err_out;
}
if (err > 0)
diff --git a/drivers/mtd/maps/pismo.c b/drivers/mtd/maps/pismo.c
index eb476b7f8d11..f4ce273e93fd 100644
--- a/drivers/mtd/maps/pismo.c
+++ b/drivers/mtd/maps/pismo.c
@@ -234,7 +234,6 @@ static int __devexit pismo_remove(struct i2c_client *client)
/* FIXME: set_vpp needs saner arguments */
pismo_setvpp_remove_fix(pismo);
- i2c_set_clientdata(client, NULL);
kfree(pismo);
return 0;
@@ -286,7 +285,6 @@ static int __devinit pismo_probe(struct i2c_client *client,
return 0;
exit_free:
- i2c_set_clientdata(client, NULL);
kfree(pismo);
return ret;
}
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 000d65ea55a4..91c8013cf0d9 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -404,14 +404,9 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd,
if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
return -EINVAL;
- ops.oobbuf = kmalloc(length, GFP_KERNEL);
- if (!ops.oobbuf)
- return -ENOMEM;
-
- if (copy_from_user(ops.oobbuf, ptr, length)) {
- kfree(ops.oobbuf);
- return -EFAULT;
- }
+ ops.oobbuf = memdup_user(ptr, length);
+ if (IS_ERR(ops.oobbuf))
+ return PTR_ERR(ops.oobbuf);
start &= ~((uint64_t)mtd->oobsize - 1);
ret = mtd->write_oob(mtd, start, &ops);
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 98a04b3c9526..ffc3720929f1 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,13 +1,3 @@
-menuconfig MTD_NAND
- tristate "NAND Device Support"
- depends on MTD
- select MTD_NAND_IDS
- select MTD_NAND_ECC
- help
- This enables support for accessing all type of NAND flash
- devices. For further information see
- <http://www.linux-mtd.infradead.org/doc/nand.html>.
-
config MTD_NAND_ECC
tristate
@@ -19,6 +9,17 @@ config MTD_NAND_ECC_SMC
Software ECC according to the Smart Media Specification.
The original Linux implementation had byte 0 and 1 swapped.
+
+menuconfig MTD_NAND
+ tristate "NAND Device Support"
+ depends on MTD
+ select MTD_NAND_IDS
+ select MTD_NAND_ECC
+ help
+ This enables support for accessing all type of NAND flash
+ devices. For further information see
+ <http://www.linux-mtd.infradead.org/doc/nand.html>.
+
if MTD_NAND
config MTD_NAND_VERIFY_WRITE
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 00aea6f7d1f1..1312eda57ba6 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -232,7 +232,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
if (!fun)
return -ENOMEM;
- ret = of_address_to_resource(ofdev->node, 0, &io_res);
+ ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res);
if (ret) {
dev_err(&ofdev->dev, "can't get IO base\n");
goto err1;
@@ -244,7 +244,8 @@ static int __devinit fun_probe(struct of_device *ofdev,
goto err1;
}
- prop = of_get_property(ofdev->node, "fsl,upm-addr-offset", &size);
+ prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset",
+ &size);
if (!prop || size != sizeof(uint32_t)) {
dev_err(&ofdev->dev, "can't get UPM address offset\n");
ret = -EINVAL;
@@ -252,7 +253,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
}
fun->upm_addr_offset = *prop;
- prop = of_get_property(ofdev->node, "fsl,upm-cmd-offset", &size);
+ prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size);
if (!prop || size != sizeof(uint32_t)) {
dev_err(&ofdev->dev, "can't get UPM command offset\n");
ret = -EINVAL;
@@ -260,7 +261,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
}
fun->upm_cmd_offset = *prop;
- prop = of_get_property(ofdev->node,
+ prop = of_get_property(ofdev->dev.of_node,
"fsl,upm-addr-line-cs-offsets", &size);
if (prop && (size / sizeof(uint32_t)) > 0) {
fun->mchip_count = size / sizeof(uint32_t);
@@ -276,7 +277,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
for (i = 0; i < fun->mchip_count; i++) {
fun->rnb_gpio[i] = -1;
- rnb_gpio = of_get_gpio(ofdev->node, i);
+ rnb_gpio = of_get_gpio(ofdev->dev.of_node, i);
if (rnb_gpio >= 0) {
ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
if (ret) {
@@ -292,13 +293,13 @@ static int __devinit fun_probe(struct of_device *ofdev,
}
}
- prop = of_get_property(ofdev->node, "chip-delay", NULL);
+ prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL);
if (prop)
fun->chip_delay = *prop;
else
fun->chip_delay = 50;
- prop = of_get_property(ofdev->node, "fsl,upm-wait-flags", &size);
+ prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size);
if (prop && size == sizeof(uint32_t))
fun->wait_flags = *prop;
else
@@ -315,7 +316,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
fun->dev = &ofdev->dev;
fun->last_ctrl = NAND_CLE;
- ret = fun_chip_init(fun, ofdev->node, &io_res);
+ ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res);
if (ret)
goto err2;
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 3d0867d829cb..0a130dcaa129 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -650,7 +650,7 @@ static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
static int __devinit mpc5121_nfc_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *rootnode, *dn = op->node;
+ struct device_node *rootnode, *dn = op->dev.of_node;
struct device *dev = &op->dev;
struct mpc5121_nfc_prv *prv;
struct resource res;
@@ -889,12 +889,12 @@ static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
};
static struct of_platform_driver mpc5121_nfc_driver = {
- .match_table = mpc5121_nfc_match,
.probe = mpc5121_nfc_probe,
.remove = __devexit_p(mpc5121_nfc_remove),
.driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mpc5121_nfc_match,
},
};
diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c
index 82e94389824e..0d76b169482f 100644
--- a/drivers/mtd/nand/mxc_nand.c
+++ b/drivers/mtd/nand/mxc_nand.c
@@ -623,8 +623,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
else
host->buf_start = column + mtd->writesize;
- if (mtd->writesize > 512)
- command = NAND_CMD_READ0; /* only READ0 is valid */
+ command = NAND_CMD_READ0; /* only READ0 is valid */
send_cmd(host, command, false);
mxc_do_addr_cycle(mtd, column, page_addr);
@@ -639,31 +638,11 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
break;
case NAND_CMD_SEQIN:
- if (column >= mtd->writesize) {
- /*
- * FIXME: before send SEQIN command for write OOB,
- * We must read one page out.
- * For K9F1GXX has no READ1 command to set current HW
- * pointer to spare area, we must write the whole page
- * including OOB together.
- */
- if (mtd->writesize > 512)
- /* call ourself to read a page */
- mxc_nand_command(mtd, NAND_CMD_READ0, 0,
- page_addr);
-
- host->buf_start = column;
-
- /* Set program pointer to spare region */
- if (mtd->writesize == 512)
- send_cmd(host, NAND_CMD_READOOB, false);
- } else {
- host->buf_start = column;
+ if (column >= mtd->writesize)
+ /* call ourself to read a page */
+ mxc_nand_command(mtd, NAND_CMD_READ0, 0, page_addr);
- /* Set program pointer to page start */
- if (mtd->writesize == 512)
- send_cmd(host, NAND_CMD_READ0, false);
- }
+ host->buf_start = column;
send_cmd(host, command, false);
mxc_do_addr_cycle(mtd, column, page_addr);
@@ -853,6 +832,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
parse_mtd_partitions(mtd, part_probes, &host->parts, 0);
if (nr_parts > 0)
add_mtd_partitions(mtd, host->parts, nr_parts);
+ else if (pdata->parts)
+ add_mtd_partitions(mtd, pdata->parts, pdata->nr_parts);
else
#endif
{
diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c
index 78a423295474..bcfc851fe550 100644
--- a/drivers/mtd/nand/r852.c
+++ b/drivers/mtd/nand/r852.c
@@ -150,7 +150,6 @@ static void r852_dma_done(struct r852_device *dev, int error)
if (dev->phys_dma_addr && dev->phys_dma_addr != dev->phys_bounce_buffer)
pci_unmap_single(dev->pci_dev, dev->phys_dma_addr, R852_DMA_LEN,
dev->dma_dir ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
- complete(&dev->dma_done);
}
/*
@@ -182,6 +181,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
/* Set dma direction */
dev->dma_dir = do_read;
dev->dma_stage = 1;
+ INIT_COMPLETION(dev->dma_done);
dbg_verbose("doing dma %s ", do_read ? "read" : "write");
@@ -494,6 +494,11 @@ int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
if (dev->card_unstable)
return 0;
+ if (dev->dma_error) {
+ dev->dma_error = 0;
+ return -1;
+ }
+
r852_write_reg(dev, R852_CTL, dev->ctlreg | R852_CTL_ECC_ACCESS);
ecc_reg = r852_read_reg_dword(dev, R852_DATALINE);
r852_write_reg(dev, R852_CTL, dev->ctlreg);
@@ -707,6 +712,7 @@ void r852_card_detect_work(struct work_struct *work)
container_of(work, struct r852_device, card_detect_work.work);
r852_card_update_present(dev);
+ r852_update_card_detect(dev);
dev->card_unstable = 0;
/* False alarm */
@@ -722,7 +728,6 @@ void r852_card_detect_work(struct work_struct *work)
else
r852_unregister_nand_device(dev);
exit:
- /* Update detection logic */
r852_update_card_detect(dev);
}
@@ -796,6 +801,7 @@ static irqreturn_t r852_irq(int irq, void *data)
if (dma_status & R852_DMA_IRQ_ERROR) {
dbg("recieved dma error IRQ");
r852_dma_done(dev, -EIO);
+ complete(&dev->dma_done);
goto out;
}
@@ -825,8 +831,10 @@ static irqreturn_t r852_irq(int irq, void *data)
r852_dma_enable(dev);
/* Operation done */
- if (dev->dma_stage == 3)
+ if (dev->dma_stage == 3) {
r852_dma_done(dev, 0);
+ complete(&dev->dma_done);
+ }
goto out;
}
@@ -940,18 +948,19 @@ int r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
r852_dma_test(dev);
+ dev->irq = pci_dev->irq;
+ spin_lock_init(&dev->irqlock);
+
+ dev->card_detected = 0;
+ r852_card_update_present(dev);
+
/*register irq handler*/
error = -ENODEV;
if (request_irq(pci_dev->irq, &r852_irq, IRQF_SHARED,
DRV_NAME, dev))
goto error10;
- dev->irq = pci_dev->irq;
- spin_lock_init(&dev->irqlock);
-
/* kick initial present test */
- dev->card_detected = 0;
- r852_card_update_present(dev);
queue_delayed_work(dev->card_workqueue,
&dev->card_detect_work, 0);
@@ -1081,7 +1090,7 @@ int r852_resume(struct device *device)
dev->card_detected ? "added" : "removed");
queue_delayed_work(dev->card_workqueue,
- &dev->card_detect_work, 1000);
+ &dev->card_detect_work, msecs_to_jiffies(1000));
return 0;
}
diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c
index 884852dc7eb4..cc728b12de82 100644
--- a/drivers/mtd/nand/socrates_nand.c
+++ b/drivers/mtd/nand/socrates_nand.c
@@ -183,7 +183,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev,
return -ENOMEM;
}
- host->io_base = of_iomap(ofdev->node, 0);
+ host->io_base = of_iomap(ofdev->dev.of_node, 0);
if (host->io_base == NULL) {
printk(KERN_ERR "socrates_nand: ioremap failed\n");
kfree(host);
@@ -244,7 +244,7 @@ static int __devinit socrates_nand_probe(struct of_device *ofdev,
#ifdef CONFIG_MTD_OF_PARTS
if (num_partitions == 0) {
num_partitions = of_mtd_parse_partitions(&ofdev->dev,
- ofdev->node,
+ ofdev->dev.of_node,
&partitions);
if (num_partitions < 0) {
res = num_partitions;
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 9f87c99189a9..b582671ca3a0 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -418,7 +418,8 @@ retry:
* may try to recover data. FIXME: but this is
* not implemented.
*/
- if (err == UBI_IO_BAD_VID_HDR) {
+ if (err == UBI_IO_BAD_HDR_READ ||
+ err == UBI_IO_BAD_HDR) {
ubi_warn("corrupted VID header at PEB "
"%d, LEB %d:%d", pnum, vol_id,
lnum);
@@ -961,8 +962,8 @@ write_error:
*/
static int is_error_sane(int err)
{
- if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_VID_HDR ||
- err == -ETIMEDOUT)
+ if (err == -EIO || err == -ENOMEM || err == UBI_IO_BAD_HDR ||
+ err == UBI_IO_BAD_HDR_READ || err == -ETIMEDOUT)
return 0;
return 1;
}
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 4b979e34b159..b812f8805367 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -515,7 +515,7 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
* In this case we probably anyway have garbage in this PEB.
*/
err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
- if (err1 == UBI_IO_BAD_VID_HDR)
+ if (err1 == UBI_IO_BAD_HDR_READ || err1 == UBI_IO_BAD_HDR)
/*
* The VID header is corrupted, so we can safely erase this
* PEB and not afraid that it will be treated as a valid PEB in
@@ -709,7 +709,7 @@ bad:
* o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
* and corrected by the flash driver; this is harmless but may indicate that
* this eraseblock may become bad soon (but may be not);
- * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error);
+ * o %UBI_IO_BAD_HDR if the erase counter header is corrupted (a CRC error);
* o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty;
* o a negative error code in case of failure.
*/
@@ -736,23 +736,21 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
* header is still OK, we just report this as there was a
* bit-flip.
*/
- read_err = err;
+ if (err == -EBADMSG)
+ read_err = UBI_IO_BAD_HDR_READ;
}
magic = be32_to_cpu(ec_hdr->magic);
if (magic != UBI_EC_HDR_MAGIC) {
+ if (read_err)
+ return read_err;
+
/*
* The magic field is wrong. Let's check if we have read all
* 0xFF. If yes, this physical eraseblock is assumed to be
* empty.
- *
- * But if there was a read error, we do not test it for all
- * 0xFFs. Even if it does contain all 0xFFs, this error
- * indicates that something is still wrong with this physical
- * eraseblock and we anyway cannot treat it as empty.
*/
- if (read_err != -EBADMSG &&
- check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
+ if (check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) {
/* The physical eraseblock is supposedly empty */
if (verbose)
ubi_warn("no EC header found at PEB %d, "
@@ -774,7 +772,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_EC_HDR_MAGIC);
- return UBI_IO_BAD_EC_HDR;
+ return UBI_IO_BAD_HDR;
}
crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC);
@@ -788,7 +786,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad EC header CRC at PEB %d, calculated "
"%#08x, read %#08x", pnum, crc, hdr_crc);
- return UBI_IO_BAD_EC_HDR;
+ return read_err ?: UBI_IO_BAD_HDR;
}
/* And of course validate what has just been read from the media */
@@ -798,6 +796,10 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum,
return -EINVAL;
}
+ /*
+ * If there was %-EBADMSG, but the header CRC is still OK, report about
+ * a bit-flip to force scrubbing on this PEB.
+ */
return read_err ? UBI_IO_BITFLIPS : 0;
}
@@ -977,7 +979,7 @@ bad:
* o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected
* and corrected by the flash driver; this is harmless but may indicate that
* this eraseblock may become bad soon;
- * o %UBI_IO_BAD_VID_HDR if the volume identifier header is corrupted (a CRC
+ * o %UBI_IO_BAD_HDR if the volume identifier header is corrupted (a CRC
* error detected);
* o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID
* header there);
@@ -1008,22 +1010,20 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
* CRC check-sum and we will identify this. If the VID header is
* still OK, we just report this as there was a bit-flip.
*/
- read_err = err;
+ if (err == -EBADMSG)
+ read_err = UBI_IO_BAD_HDR_READ;
}
magic = be32_to_cpu(vid_hdr->magic);
if (magic != UBI_VID_HDR_MAGIC) {
+ if (read_err)
+ return read_err;
+
/*
* If we have read all 0xFF bytes, the VID header probably does
* not exist and the physical eraseblock is assumed to be free.
- *
- * But if there was a read error, we do not test the data for
- * 0xFFs. Even if it does contain all 0xFFs, this error
- * indicates that something is still wrong with this physical
- * eraseblock and it cannot be regarded as free.
*/
- if (read_err != -EBADMSG &&
- check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
+ if (check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) {
/* The physical eraseblock is supposedly free */
if (verbose)
ubi_warn("no VID header found at PEB %d, "
@@ -1045,7 +1045,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad magic number at PEB %d: %08x instead of "
"%08x", pnum, magic, UBI_VID_HDR_MAGIC);
- return UBI_IO_BAD_VID_HDR;
+ return UBI_IO_BAD_HDR;
}
crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
@@ -1059,7 +1059,7 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
} else if (UBI_IO_DEBUG)
dbg_msg("bad CRC at PEB %d, calculated %#08x, "
"read %#08x", pnum, crc, hdr_crc);
- return UBI_IO_BAD_VID_HDR;
+ return read_err ?: UBI_IO_BAD_HDR;
}
/* Validate the VID header that we have just read */
@@ -1069,6 +1069,10 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum,
return -EINVAL;
}
+ /*
+ * If there was a read error (%-EBADMSG), but the header CRC is still
+ * OK, report about a bit-flip to force scrubbing on this PEB.
+ */
return read_err ? UBI_IO_BITFLIPS : 0;
}
diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c
index aed19f33b8f3..6b7c0c4baf07 100644
--- a/drivers/mtd/ubi/scan.c
+++ b/drivers/mtd/ubi/scan.c
@@ -72,16 +72,19 @@ static int add_to_list(struct ubi_scan_info *si, int pnum, int ec,
{
struct ubi_scan_leb *seb;
- if (list == &si->free)
+ if (list == &si->free) {
dbg_bld("add to free: PEB %d, EC %d", pnum, ec);
- else if (list == &si->erase)
+ si->free_peb_count += 1;
+ } else if (list == &si->erase) {
dbg_bld("add to erase: PEB %d, EC %d", pnum, ec);
- else if (list == &si->corr) {
+ si->erase_peb_count += 1;
+ } else if (list == &si->corr) {
dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec);
- si->corr_count += 1;
- } else if (list == &si->alien)
+ si->corr_peb_count += 1;
+ } else if (list == &si->alien) {
dbg_bld("add to alien: PEB %d, EC %d", pnum, ec);
- else
+ si->alien_peb_count += 1;
+ } else
BUG();
seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL);
@@ -517,6 +520,7 @@ int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si,
sv->leb_count += 1;
rb_link_node(&seb->u.rb, parent, p);
rb_insert_color(&seb->u.rb, &sv->root);
+ si->used_peb_count += 1;
return 0;
}
@@ -745,19 +749,17 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
bitflips = 1;
else if (err == UBI_IO_PEB_EMPTY)
return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase);
- else if (err == UBI_IO_BAD_EC_HDR) {
+ else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR) {
/*
* We have to also look at the VID header, possibly it is not
* corrupted. Set %bitflips flag in order to make this PEB be
* moved and EC be re-created.
*/
- ec_corr = 1;
+ ec_corr = err;
ec = UBI_SCAN_UNKNOWN_EC;
bitflips = 1;
}
- si->is_empty = 0;
-
if (!ec_corr) {
int image_seq;
@@ -813,9 +815,12 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
return err;
else if (err == UBI_IO_BITFLIPS)
bitflips = 1;
- else if (err == UBI_IO_BAD_VID_HDR ||
+ else if (err == UBI_IO_BAD_HDR_READ || err == UBI_IO_BAD_HDR ||
(err == UBI_IO_PEB_FREE && ec_corr)) {
/* VID header is corrupted */
+ if (err == UBI_IO_BAD_HDR_READ ||
+ ec_corr == UBI_IO_BAD_HDR_READ)
+ si->read_err_count += 1;
err = add_to_list(si, pnum, ec, &si->corr);
if (err)
return err;
@@ -855,7 +860,6 @@ static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si,
err = add_to_list(si, pnum, ec, &si->alien);
if (err)
return err;
- si->alien_peb_count += 1;
return 0;
case UBI_COMPAT_REJECT:
@@ -886,6 +890,85 @@ adjust_mean_ec:
}
/**
+ * check_what_we_have - check what PEB were found by scanning.
+ * @ubi: UBI device description object
+ * @si: scanning information
+ *
+ * This is a helper function which takes a look what PEBs were found by
+ * scanning, and decides whether the flash is empty and should be formatted and
+ * whether there are too many corrupted PEBs and we should not attach this
+ * MTD device. Returns zero if we should proceed with attaching the MTD device,
+ * and %-EINVAL if we should not.
+ */
+static int check_what_we_have(const struct ubi_device *ubi,
+ struct ubi_scan_info *si)
+{
+ struct ubi_scan_leb *seb;
+ int max_corr;
+
+ max_corr = ubi->peb_count - si->bad_peb_count - si->alien_peb_count;
+ max_corr = max_corr / 20 ?: 8;
+
+ /*
+ * Few corrupted PEBs are not a problem and may be just a result of
+ * unclean reboots. However, many of them may indicate some problems
+ * with the flash HW or driver.
+ */
+ if (si->corr_peb_count >= 8) {
+ ubi_warn("%d PEBs are corrupted", si->corr_peb_count);
+ printk(KERN_WARNING "corrupted PEBs are:");
+ list_for_each_entry(seb, &si->corr, u.list)
+ printk(KERN_CONT " %d", seb->pnum);
+ printk(KERN_CONT "\n");
+
+ /*
+ * If too many PEBs are corrupted, we refuse attaching,
+ * otherwise, only print a warning.
+ */
+ if (si->corr_peb_count >= max_corr) {
+ ubi_err("too many corrupted PEBs, refusing this device");
+ return -EINVAL;
+ }
+ }
+
+ if (si->free_peb_count + si->used_peb_count +
+ si->alien_peb_count == 0) {
+ /* No UBI-formatted eraseblocks were found */
+ if (si->corr_peb_count == si->read_err_count &&
+ si->corr_peb_count < 8) {
+ /* No or just few corrupted PEBs, and all of them had a
+ * read error. We assume that those are bad PEBs, which
+ * were just not marked as bad so far.
+ *
+ * This piece of code basically tries to distinguish
+ * between the following 2 situations:
+ *
+ * 1. Flash is empty, but there are few bad PEBs, which
+ * are not marked as bad so far, and which were read
+ * with error. We want to go ahead and format this
+ * flash. While formating, the faulty PEBs will
+ * probably be marked as bad.
+ *
+ * 2. Flash probably contains non-UBI data and we do
+ * not want to format it and destroy possibly needed
+ * data (e.g., consider the case when the bootloader
+ * MTD partition was accidentally fed to UBI).
+ */
+ si->is_empty = 1;
+ ubi_msg("empty MTD device detected");
+ } else {
+ ubi_err("MTD device possibly contains non-UBI data, "
+ "refusing it");
+ return -EINVAL;
+ }
+ }
+
+ if (si->corr_peb_count >= 0)
+ ubi_msg("corrupted PEBs will be formatted");
+ return 0;
+}
+
+/**
* ubi_scan - scan an MTD device.
* @ubi: UBI device description object
*
@@ -909,7 +992,6 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
INIT_LIST_HEAD(&si->erase);
INIT_LIST_HEAD(&si->alien);
si->volumes = RB_ROOT;
- si->is_empty = 1;
err = -ENOMEM;
ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL);
@@ -935,21 +1017,9 @@ struct ubi_scan_info *ubi_scan(struct ubi_device *ubi)
if (si->ec_count)
si->mean_ec = div_u64(si->ec_sum, si->ec_count);
- if (si->is_empty)
- ubi_msg("empty MTD device detected");
-
- /*
- * Few corrupted PEBs are not a problem and may be just a result of
- * unclean reboots. However, many of them may indicate some problems
- * with the flash HW or driver. Print a warning in this case.
- */
- if (si->corr_count >= 8 || si->corr_count >= ubi->peb_count / 4) {
- ubi_warn("%d PEBs are corrupted", si->corr_count);
- printk(KERN_WARNING "corrupted PEBs are:");
- list_for_each_entry(seb, &si->corr, u.list)
- printk(KERN_CONT " %d", seb->pnum);
- printk(KERN_CONT "\n");
- }
+ err = check_what_we_have(ubi, si);
+ if (err)
+ goto out_vidh;
/*
* In case of unknown erase counter we use the mean erase counter
diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h
index ff179ad7ca55..2576a8d1532b 100644
--- a/drivers/mtd/ubi/scan.h
+++ b/drivers/mtd/ubi/scan.h
@@ -91,10 +91,16 @@ struct ubi_scan_volume {
* @erase: list of physical eraseblocks which have to be erased
* @alien: list of physical eraseblocks which should not be used by UBI (e.g.,
* those belonging to "preserve"-compatible internal volumes)
+ * @used_peb_count: count of used PEBs
+ * @corr_peb_count: count of PEBs in the @corr list
+ * @read_err_count: count of PEBs read with error (%UBI_IO_BAD_HDR_READ was
+ * returned)
+ * @free_peb_count: count of PEBs in the @free list
+ * @erase_peb_count: count of PEBs in the @erase list
+ * @alien_peb_count: count of PEBs in the @alien list
* @bad_peb_count: count of bad physical eraseblocks
* @vols_found: number of volumes found during scanning
* @highest_vol_id: highest volume ID
- * @alien_peb_count: count of physical eraseblocks in the @alien list
* @is_empty: flag indicating whether the MTD device is empty or not
* @min_ec: lowest erase counter value
* @max_ec: highest erase counter value
@@ -102,7 +108,6 @@ struct ubi_scan_volume {
* @mean_ec: mean erase counter value
* @ec_sum: a temporary variable used when calculating @mean_ec
* @ec_count: a temporary variable used when calculating @mean_ec
- * @corr_count: count of corrupted PEBs
*
* This data structure contains the result of scanning and may be used by other
* UBI sub-systems to build final UBI data structures, further error-recovery
@@ -114,10 +119,15 @@ struct ubi_scan_info {
struct list_head free;
struct list_head erase;
struct list_head alien;
+ int used_peb_count;
+ int corr_peb_count;
+ int read_err_count;
+ int free_peb_count;
+ int erase_peb_count;
+ int alien_peb_count;
int bad_peb_count;
int vols_found;
int highest_vol_id;
- int alien_peb_count;
int is_empty;
int min_ec;
int max_ec;
@@ -125,7 +135,6 @@ struct ubi_scan_info {
int mean_ec;
uint64_t ec_sum;
int ec_count;
- int corr_count;
};
struct ubi_device;
@@ -135,7 +144,7 @@ struct ubi_vid_hdr;
* ubi_scan_move_to_list - move a PEB from the volume tree to a list.
*
* @sv: volume scanning information
- * @seb: scanning eraseblock infprmation
+ * @seb: scanning eraseblock information
* @list: the list to move to
*/
static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv,
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index a637f0283add..0359e0cce482 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -89,16 +89,16 @@
* %0xFF bytes
* UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a
* valid erase counter header, and the rest are %0xFF bytes
- * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC)
- * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or
- * CRC)
+ * UBI_IO_BAD_HDR: the EC or VID header is corrupted (bad magic or CRC)
+ * UBI_IO_BAD_HDR_READ: the same as %UBI_IO_BAD_HDR, but also there was a read
+ * error reported by the flash driver
* UBI_IO_BITFLIPS: bit-flips were detected and corrected
*/
enum {
UBI_IO_PEB_EMPTY = 1,
UBI_IO_PEB_FREE,
- UBI_IO_BAD_EC_HDR,
- UBI_IO_BAD_VID_HDR,
+ UBI_IO_BAD_HDR,
+ UBI_IO_BAD_HDR_READ,
UBI_IO_BITFLIPS
};
diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
index 75e28fef797b..d693b8d15cde 100644
--- a/drivers/net/3c527.h
+++ b/drivers/net/3c527.h
@@ -34,7 +34,7 @@ struct mc32_mailbox
{
u16 mbox;
u16 data[1];
-} __attribute((packed));
+} __packed;
struct skb_header
{
@@ -43,7 +43,7 @@ struct skb_header
u16 next; /* Do not change! */
u16 length;
u32 data;
-} __attribute((packed));
+} __packed;
struct mc32_stats
{
@@ -68,7 +68,7 @@ struct mc32_stats
u32 dataA[6];
u16 dataB[5];
u32 dataC[14];
-} __attribute((packed));
+} __packed;
#define STATUS_MASK 0x0F
#define COMPLETED (1<<7)
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 9c149750e2bf..e949ba80127d 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -322,7 +322,7 @@ struct cp_dma_stats {
__le32 rx_ok_mcast;
__le16 tx_abort;
__le16 tx_underrun;
-} __attribute__((packed));
+} __packed;
struct cp_extra_stats {
unsigned long rx_frags;
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 4ba72933f0da..cc7d46238801 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -662,7 +662,7 @@ static const struct ethtool_ops rtl8139_ethtool_ops;
/* read MMIO register */
#define RTL_R8(reg) ioread8 (ioaddr + (reg))
#define RTL_R16(reg) ioread16 (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) ioread32 (ioaddr + (reg)))
+#define RTL_R32(reg) ioread32 (ioaddr + (reg))
static const u16 rtl8139_intr_mask =
@@ -861,7 +861,7 @@ retry:
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
dev_dbg(&pdev->dev, "unknown chip version, assuming RTL-8139\n");
- dev_dbg(&pdev->dev, "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
+ dev_dbg(&pdev->dev, "TxConfig = 0x%x\n", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -1642,7 +1642,7 @@ static void rtl8139_tx_timeout_task (struct work_struct *work)
netdev_dbg(dev, "Tx queue start entry %ld dirty entry %ld\n",
tp->cur_tx, tp->dirty_tx);
for (i = 0; i < NUM_TX_DESC; i++)
- netdev_dbg(dev, "Tx descriptor %d is %08lx%s\n",
+ netdev_dbg(dev, "Tx descriptor %d is %08x%s\n",
i, RTL_R32(TxStatus0 + (i * 4)),
i == tp->dirty_tx % NUM_TX_DESC ?
" (queue head)" : "");
@@ -2486,7 +2486,7 @@ static void __set_rx_mode (struct net_device *dev)
int rx_mode;
u32 tmp;
- netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08lx\n",
+ netdev_dbg(dev, "rtl8139_set_rx_mode(%04x) done -- Rx config %08x\n",
dev->flags, RTL_R32(RxConfig));
/* Note: do not reorder, GCC is clever about common statements. */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 2decc597bda7..a940e98e1b62 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1659,6 +1659,7 @@ config R6040
depends on NET_PCI && PCI
select CRC32
select MII
+ select PHYLIB
help
This is a driver for the R6040 Fast Ethernet MACs found in the
the RDC R-321x System-on-chips.
@@ -3309,4 +3310,18 @@ config VMXNET3
To compile this driver as a module, choose M here: the
module will be called vmxnet3.
+config VBUS_ENET
+ tristate "VBUS Ethernet Driver"
+ default n
+ depends on VBUS_PROXY
+ help
+ A virtualized 802.x network device based on the VBUS
+ "virtual-ethernet" interface. It can be used with any
+ hypervisor/kernel that supports the vbus+venet protocol.
+
+config VBUS_ENET_DEBUG
+ bool "Enable Debugging"
+ depends on VBUS_ENET
+ default n
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512ae77da..8beb1e27191f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -289,6 +289,7 @@ obj-$(CONFIG_FS_ENET) += fs_enet/
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_VBUS_ENET) += vbus-enet.o
obj-$(CONFIG_SFC) += sfc/
obj-$(CONFIG_WIMAX) += wimax/
diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c
index 355797f70048..42fce91b71fc 100644
--- a/drivers/net/arcnet/capmode.c
+++ b/drivers/net/arcnet/capmode.c
@@ -37,69 +37,6 @@
#define VERSION "arcnet: cap mode (`c') encapsulation support loaded.\n"
-
-static void rx(struct net_device *dev, int bufnum,
- struct archdr *pkthdr, int length);
-static int build_header(struct sk_buff *skb,
- struct net_device *dev,
- unsigned short type,
- uint8_t daddr);
-static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
- int bufnum);
-static int ack_tx(struct net_device *dev, int acked);
-
-
-static struct ArcProto capmode_proto =
-{
- 'r',
- XMTU,
- 0,
- rx,
- build_header,
- prepare_tx,
- NULL,
- ack_tx
-};
-
-
-static void arcnet_cap_init(void)
-{
- int count;
-
- for (count = 1; count <= 8; count++)
- if (arc_proto_map[count] == arc_proto_default)
- arc_proto_map[count] = &capmode_proto;
-
- /* for cap mode, we only set the bcast proto if there's no better one */
- if (arc_bcast_proto == arc_proto_default)
- arc_bcast_proto = &capmode_proto;
-
- arc_proto_default = &capmode_proto;
- arc_raw_proto = &capmode_proto;
-}
-
-
-#ifdef MODULE
-
-static int __init capmode_module_init(void)
-{
- printk(VERSION);
- arcnet_cap_init();
- return 0;
-}
-
-static void __exit capmode_module_exit(void)
-{
- arcnet_unregister_proto(&capmode_proto);
-}
-module_init(capmode_module_init);
-module_exit(capmode_module_exit);
-
-MODULE_LICENSE("GPL");
-#endif /* MODULE */
-
-
-
/* packet receiver */
static void rx(struct net_device *dev, int bufnum,
struct archdr *pkthdr, int length)
@@ -231,65 +168,107 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length,
BUGMSG(D_DURING, "prepare_tx: length=%d ofs=%d\n",
length,ofs);
- // Copy the arcnet-header + the protocol byte down:
+ /* Copy the arcnet-header + the protocol byte down: */
lp->hw.copy_to_card(dev, bufnum, 0, hard, ARC_HDR_SIZE);
lp->hw.copy_to_card(dev, bufnum, ofs, &pkt->soft.cap.proto,
sizeof(pkt->soft.cap.proto));
- // Skip the extra integer we have written into it as a cookie
- // but write the rest of the message:
+ /* Skip the extra integer we have written into it as a cookie
+ but write the rest of the message: */
lp->hw.copy_to_card(dev, bufnum, ofs+1,
((unsigned char*)&pkt->soft.cap.mes),length-1);
lp->lastload_dest = hard->dest;
- return 1; /* done */
+ return 1; /* done */
}
-
static int ack_tx(struct net_device *dev, int acked)
{
- struct arcnet_local *lp = netdev_priv(dev);
- struct sk_buff *ackskb;
- struct archdr *ackpkt;
- int length=sizeof(struct arc_cap);
+ struct arcnet_local *lp = netdev_priv(dev);
+ struct sk_buff *ackskb;
+ struct archdr *ackpkt;
+ int length=sizeof(struct arc_cap);
- BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
- lp->outgoing.skb->protocol, acked);
+ BUGMSG(D_DURING, "capmode: ack_tx: protocol: %x: result: %d\n",
+ lp->outgoing.skb->protocol, acked);
- BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
+ BUGLVL(D_SKB) arcnet_dump_skb(dev, lp->outgoing.skb, "ack_tx");
- /* Now alloc a skb to send back up through the layers: */
- ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
- if (ackskb == NULL) {
- BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
- goto free_outskb;
- }
+ /* Now alloc a skb to send back up through the layers: */
+ ackskb = alloc_skb(length + ARC_HDR_SIZE , GFP_ATOMIC);
+ if (ackskb == NULL) {
+ BUGMSG(D_NORMAL, "Memory squeeze, can't acknowledge.\n");
+ goto free_outskb;
+ }
+
+ skb_put(ackskb, length + ARC_HDR_SIZE );
+ ackskb->dev = dev;
+
+ skb_reset_mac_header(ackskb);
+ ackpkt = (struct archdr *)skb_mac_header(ackskb);
+ /* skb_pull(ackskb, ARC_HDR_SIZE); */
- skb_put(ackskb, length + ARC_HDR_SIZE );
- ackskb->dev = dev;
+ skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
+ ARC_HDR_SIZE + sizeof(struct arc_cap));
+ ackpkt->soft.cap.proto = 0; /* using protocol 0 for acknowledge */
+ ackpkt->soft.cap.mes.ack=acked;
- skb_reset_mac_header(ackskb);
- ackpkt = (struct archdr *)skb_mac_header(ackskb);
- /* skb_pull(ackskb, ARC_HDR_SIZE); */
+ BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
+ *((int*)&ackpkt->soft.cap.cookie[0]));
+ ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
- skb_copy_from_linear_data(lp->outgoing.skb, ackpkt,
- ARC_HDR_SIZE + sizeof(struct arc_cap));
- ackpkt->soft.cap.proto=0; /* using protocol 0 for acknowledge */
- ackpkt->soft.cap.mes.ack=acked;
+ BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
+ netif_rx(ackskb);
- BUGMSG(D_PROTO, "Ackknowledge for cap packet %x.\n",
- *((int*)&ackpkt->soft.cap.cookie[0]));
+free_outskb:
+ dev_kfree_skb_irq(lp->outgoing.skb);
+ lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
- ackskb->protocol = cpu_to_be16(ETH_P_ARCNET);
+ return 0;
+}
- BUGLVL(D_SKB) arcnet_dump_skb(dev, ackskb, "ack_tx_recv");
- netif_rx(ackskb);
+static struct ArcProto capmode_proto =
+{
+ 'r',
+ XMTU,
+ 0,
+ rx,
+ build_header,
+ prepare_tx,
+ NULL,
+ ack_tx
+};
- free_outskb:
- dev_kfree_skb_irq(lp->outgoing.skb);
- lp->outgoing.proto = NULL; /* We are always finished when in this protocol */
+static void arcnet_cap_init(void)
+{
+ int count;
- return 0;
+ for (count = 1; count <= 8; count++)
+ if (arc_proto_map[count] == arc_proto_default)
+ arc_proto_map[count] = &capmode_proto;
+
+ /* for cap mode, we only set the bcast proto if there's no better one */
+ if (arc_bcast_proto == arc_proto_default)
+ arc_bcast_proto = &capmode_proto;
+
+ arc_proto_default = &capmode_proto;
+ arc_raw_proto = &capmode_proto;
}
+
+static int __init capmode_module_init(void)
+{
+ printk(VERSION);
+ arcnet_cap_init();
+ return 0;
+}
+
+static void __exit capmode_module_exit(void)
+{
+ arcnet_unregister_proto(&capmode_proto);
+}
+module_init(capmode_module_init);
+module_exit(capmode_module_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
index 24df0325090c..ee2f8425dbe7 100644
--- a/drivers/net/arm/ixp4xx_eth.c
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -738,6 +738,17 @@ static void eth_set_mcast_list(struct net_device *dev)
struct netdev_hw_addr *ha;
u8 diffs[ETH_ALEN], *addr;
int i;
+ static const u8 allmulti[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ if (dev->flags & IFF_ALLMULTI) {
+ for (i = 0; i < ETH_ALEN; i++) {
+ __raw_writel(allmulti[i], &port->regs->mcast_addr[i]);
+ __raw_writel(allmulti[i], &port->regs->mcast_mask[i]);
+ }
+ __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+ return;
+ }
if ((dev->flags & IFF_PROMISC) || netdev_mc_empty(dev)) {
__raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
index 84ae905bf732..52abbbdf8a08 100644
--- a/drivers/net/atl1c/atl1c.h
+++ b/drivers/net/atl1c/atl1c.h
@@ -73,7 +73,8 @@
#define FULL_DUPLEX 2
#define AT_RX_BUF_SIZE (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
-#define MAX_JUMBO_FRAME_SIZE (9*1024)
+#define MAX_JUMBO_FRAME_SIZE (6*1024)
+#define MAX_TSO_FRAME_SIZE (7*1024)
#define MAX_TX_OFFLOAD_THRESH (9*1024)
#define AT_MAX_RECEIVE_QUEUE 4
@@ -87,10 +88,11 @@
#define AT_MAX_INT_WORK 5
#define AT_TWSI_EEPROM_TIMEOUT 100
#define AT_HW_MAX_IDLE_DELAY 10
-#define AT_SUSPEND_LINK_TIMEOUT 28
+#define AT_SUSPEND_LINK_TIMEOUT 100
#define AT_ASPM_L0S_TIMER 6
#define AT_ASPM_L1_TIMER 12
+#define AT_LCKDET_TIMER 12
#define ATL1C_PCIE_L0S_L1_DISABLE 0x01
#define ATL1C_PCIE_PHY_RESET 0x02
@@ -316,6 +318,7 @@ enum atl1c_nic_type {
athr_l2c_b,
athr_l2c_b2,
athr_l1d,
+ athr_l1d_2,
};
enum atl1c_trans_queue {
@@ -392,6 +395,8 @@ struct atl1c_hw {
u16 subsystem_id;
u16 subsystem_vendor_id;
u8 revision_id;
+ u16 phy_id1;
+ u16 phy_id2;
u32 intr_mask;
u8 dmaw_dly_cnt;
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
index f1389d664a21..d8501f060957 100644
--- a/drivers/net/atl1c/atl1c_hw.c
+++ b/drivers/net/atl1c/atl1c_hw.c
@@ -37,6 +37,9 @@ int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
if (data & TWSI_DEBUG_DEV_EXIST)
return 1;
+ AT_READ_REG(hw, REG_MASTER_CTRL, &data);
+ if (data & MASTER_CTRL_OTP_SEL)
+ return 1;
return 0;
}
@@ -69,6 +72,8 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
u32 i;
u32 otp_ctrl_data;
u32 twsi_ctrl_data;
+ u32 ltssm_ctrl_data;
+ u32 wol_data;
u8 eth_addr[ETH_ALEN];
u16 phy_data;
bool raise_vol = false;
@@ -104,6 +109,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
udelay(20);
raise_vol = true;
}
+ /* close open bit of ReadOnly*/
+ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &ltssm_ctrl_data);
+ ltssm_ctrl_data &= ~LTSSM_ID_EN_WRO;
+ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, ltssm_ctrl_data);
+
+ /* clear any WOL settings */
+ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+ AT_READ_REG(hw, REG_WOL_CTRL, &wol_data);
+
AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
@@ -119,17 +133,15 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
}
/* Disable OTP_CLK */
if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
- if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
- otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
- AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
- AT_WRITE_FLUSH(hw);
- msleep(1);
- }
+ otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+ AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+ msleep(1);
}
if (raise_vol) {
if (hw->nic_type == athr_l2c_b ||
hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d) {
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2) {
atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x00);
if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data))
goto out;
@@ -456,14 +468,22 @@ int atl1c_phy_reset(struct atl1c_hw *hw)
if (hw->nic_type == athr_l2c_b ||
hw->nic_type == athr_l2c_b2 ||
- hw->nic_type == athr_l1d) {
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2) {
atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x3B);
atl1c_read_phy_reg(hw, MII_DBG_DATA, &phy_data);
atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data & 0xFFF7);
msleep(20);
}
-
- /*Enable PHY LinkChange Interrupt */
+ if (hw->nic_type == athr_l1d) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x929D);
+ }
+ if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b2
+ || hw->nic_type == athr_l2c || hw->nic_type == athr_l2c) {
+ atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
+ atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
+ }
err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
if (err) {
if (netif_msg_hw(adapter))
@@ -482,12 +502,10 @@ int atl1c_phy_init(struct atl1c_hw *hw)
struct pci_dev *pdev = adapter->pdev;
int ret_val;
u16 mii_bmcr_data = BMCR_RESET;
- u16 phy_id1, phy_id2;
- if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
- (atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
- if (netif_msg_link(adapter))
- dev_err(&pdev->dev, "Error get phy ID\n");
+ if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
+ (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
+ dev_err(&pdev->dev, "Error get phy ID\n");
return -1;
}
switch (hw->media_type) {
@@ -572,6 +590,65 @@ int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
return 0;
}
+int atl1c_phy_power_saving(struct atl1c_hw *hw)
+{
+ struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+ struct pci_dev *pdev = adapter->pdev;
+ int ret = 0;
+ u16 autoneg_advertised = ADVERTISED_10baseT_Half;
+ u16 save_autoneg_advertised;
+ u16 phy_data;
+ u16 mii_lpa_data;
+ u16 speed = SPEED_0;
+ u16 duplex = FULL_DUPLEX;
+ int i;
+
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (phy_data & BMSR_LSTATUS) {
+ atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
+ if (mii_lpa_data & LPA_10FULL)
+ autoneg_advertised = ADVERTISED_10baseT_Full;
+ else if (mii_lpa_data & LPA_10HALF)
+ autoneg_advertised = ADVERTISED_10baseT_Half;
+ else if (mii_lpa_data & LPA_100HALF)
+ autoneg_advertised = ADVERTISED_100baseT_Half;
+ else if (mii_lpa_data & LPA_100FULL)
+ autoneg_advertised = ADVERTISED_100baseT_Full;
+
+ save_autoneg_advertised = hw->autoneg_advertised;
+ hw->phy_configured = false;
+ hw->autoneg_advertised = autoneg_advertised;
+ if (atl1c_restart_autoneg(hw) != 0) {
+ dev_dbg(&pdev->dev, "phy autoneg failed\n");
+ ret = -1;
+ }
+ hw->autoneg_advertised = save_autoneg_advertised;
+
+ if (mii_lpa_data) {
+ for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+ mdelay(100);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+ if (phy_data & BMSR_LSTATUS) {
+ if (atl1c_get_speed_and_duplex(hw, &speed,
+ &duplex) != 0)
+ dev_dbg(&pdev->dev,
+ "get speed and duplex failed\n");
+ break;
+ }
+ }
+ }
+ } else {
+ speed = SPEED_10;
+ duplex = HALF_DUPLEX;
+ }
+ adapter->link_speed = speed;
+ adapter->link_duplex = duplex;
+
+ return ret;
+}
+
int atl1c_restart_autoneg(struct atl1c_hw *hw)
{
int err = 0;
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
index 1eeb3ed9f0cb..3dd675979aa1 100644
--- a/drivers/net/atl1c/atl1c_hw.h
+++ b/drivers/net/atl1c/atl1c_hw.h
@@ -42,7 +42,7 @@ bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
int atl1c_phy_init(struct atl1c_hw *hw);
int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
int atl1c_restart_autoneg(struct atl1c_hw *hw);
-
+int atl1c_phy_power_saving(struct atl1c_hw *hw);
/* register definition */
#define REG_DEVICE_CAP 0x5C
#define DEVICE_CAP_MAX_PAYLOAD_MASK 0x7
@@ -120,6 +120,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_PCIE_PHYMISC 0x1000
#define PCIE_PHYMISC_FORCE_RCV_DET 0x4
+#define REG_PCIE_PHYMISC2 0x1004
+#define PCIE_PHYMISC2_SERDES_CDR_MASK 0x3
+#define PCIE_PHYMISC2_SERDES_CDR_SHIFT 16
+#define PCIE_PHYMISC2_SERDES_TH_MASK 0x3
+#define PCIE_PHYMISC2_SERDES_TH_SHIFT 18
+
#define REG_TWSI_DEBUG 0x1108
#define TWSI_DEBUG_DEV_EXIST 0x20000000
@@ -150,24 +156,28 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define PM_CTRL_ASPM_L0S_EN 0x00001000
#define PM_CTRL_CLK_SWH_L1 0x00002000
#define PM_CTRL_CLK_PWM_VER1_1 0x00004000
-#define PM_CTRL_PCIE_RECV 0x00008000
+#define PM_CTRL_RCVR_WT_TIMER 0x00008000
#define PM_CTRL_L1_ENTRY_TIMER_MASK 0xF
#define PM_CTRL_L1_ENTRY_TIMER_SHIFT 16
#define PM_CTRL_PM_REQ_TIMER_MASK 0xF
#define PM_CTRL_PM_REQ_TIMER_SHIFT 20
-#define PM_CTRL_LCKDET_TIMER_MASK 0x3F
+#define PM_CTRL_LCKDET_TIMER_MASK 0xF
#define PM_CTRL_LCKDET_TIMER_SHIFT 24
#define PM_CTRL_EN_BUFS_RX_L0S 0x10000000
#define PM_CTRL_SA_DLY_EN 0x20000000
#define PM_CTRL_MAC_ASPM_CHK 0x40000000
#define PM_CTRL_HOTRST 0x80000000
+#define REG_LTSSM_ID_CTRL 0x12FC
+#define LTSSM_ID_EN_WRO 0x1000
/* Selene Master Control Register */
#define REG_MASTER_CTRL 0x1400
#define MASTER_CTRL_SOFT_RST 0x1
#define MASTER_CTRL_TEST_MODE_MASK 0x3
#define MASTER_CTRL_TEST_MODE_SHIFT 2
#define MASTER_CTRL_BERT_START 0x10
+#define MASTER_CTRL_OOB_DIS_OFF 0x40
+#define MASTER_CTRL_SA_TIMER_EN 0x80
#define MASTER_CTRL_MTIMER_EN 0x100
#define MASTER_CTRL_MANUAL_INT 0x200
#define MASTER_CTRL_TX_ITIMER_EN 0x400
@@ -220,6 +230,12 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
GPHY_CTRL_PWDOWN_HW |\
GPHY_CTRL_PHY_IDDQ)
+#define GPHY_CTRL_POWER_SAVING ( \
+ GPHY_CTRL_SEL_ANA_RST |\
+ GPHY_CTRL_HIB_EN |\
+ GPHY_CTRL_HIB_PULSE |\
+ GPHY_CTRL_PWDOWN_HW |\
+ GPHY_CTRL_PHY_IDDQ)
/* Block IDLE Status Register */
#define REG_IDLE_STATUS 0x1410
#define IDLE_STATUS_MASK 0x00FF
@@ -287,6 +303,14 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define SERDES_LOCK_DETECT 0x1 /* SerDes lock detected. This signal
* comes from Analog SerDes */
#define SERDES_LOCK_DETECT_EN 0x2 /* 1: Enable SerDes Lock detect function */
+#define SERDES_LOCK_STS_SELFB_PLL_SHIFT 0xE
+#define SERDES_LOCK_STS_SELFB_PLL_MASK 0x3
+#define SERDES_OVCLK_18_25 0x0
+#define SERDES_OVCLK_12_18 0x1
+#define SERDES_OVCLK_0_4 0x2
+#define SERDES_OVCLK_4_12 0x3
+#define SERDES_MAC_CLK_SLOWDOWN 0x20000
+#define SERDES_PYH_CLK_SLOWDOWN 0x40000
/* MAC Control Register */
#define REG_MAC_CTRL 0x1480
@@ -693,6 +717,21 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define REG_MAC_TX_STATUS_BIN 0x1760
#define REG_MAC_TX_STATUS_END 0x17c0
+#define REG_CLK_GATING_CTRL 0x1814
+#define CLK_GATING_DMAW_EN 0x0001
+#define CLK_GATING_DMAR_EN 0x0002
+#define CLK_GATING_TXQ_EN 0x0004
+#define CLK_GATING_RXQ_EN 0x0008
+#define CLK_GATING_TXMAC_EN 0x0010
+#define CLK_GATING_RXMAC_EN 0x0020
+
+#define CLK_GATING_EN_ALL (CLK_GATING_DMAW_EN |\
+ CLK_GATING_DMAR_EN |\
+ CLK_GATING_TXQ_EN |\
+ CLK_GATING_RXQ_EN |\
+ CLK_GATING_TXMAC_EN|\
+ CLK_GATING_RXMAC_EN)
+
/* DEBUG ADDR */
#define REG_DEBUG_DATA0 0x1900
#define REG_DEBUG_DATA1 0x1904
@@ -734,6 +773,10 @@ int atl1c_restart_autoneg(struct atl1c_hw *hw);
#define MII_PHYSID1 0x02
#define MII_PHYSID2 0x03
+#define L1D_MPW_PHYID1 0xD01C /* V7 */
+#define L1D_MPW_PHYID2 0xD01D /* V1-V6 */
+#define L1D_MPW_PHYID3 0xD01E /* V8 */
+
/* Autoneg Advertisement Register */
#define MII_ADVERTISE 0x04
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
index 1c3c046d5f34..c7b8ef507ebd 100644
--- a/drivers/net/atl1c/atl1c_main.c
+++ b/drivers/net/atl1c/atl1c_main.c
@@ -21,7 +21,7 @@
#include "atl1c.h"
-#define ATL1C_DRV_VERSION "1.0.0.2-NAPI"
+#define ATL1C_DRV_VERSION "1.0.1.0-NAPI"
char atl1c_driver_name[] = "atl1c";
char atl1c_driver_version[] = ATL1C_DRV_VERSION;
#define PCI_DEVICE_ID_ATTANSIC_L2C 0x1062
@@ -29,7 +29,7 @@ char atl1c_driver_version[] = ATL1C_DRV_VERSION;
#define PCI_DEVICE_ID_ATHEROS_L2C_B 0x2060 /* AR8152 v1.1 Fast 10/100 */
#define PCI_DEVICE_ID_ATHEROS_L2C_B2 0x2062 /* AR8152 v2.0 Fast 10/100 */
#define PCI_DEVICE_ID_ATHEROS_L1D 0x1073 /* AR8151 v1.0 Gigabit 1000 */
-
+#define PCI_DEVICE_ID_ATHEROS_L1D_2_0 0x1083 /* AR8151 v2.0 Gigabit 1000 */
#define L2CB_V10 0xc0
#define L2CB_V11 0xc1
@@ -97,7 +97,28 @@ static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] =
static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
+static void atl1c_pcie_patch(struct atl1c_hw *hw)
+{
+ u32 data;
+ AT_READ_REG(hw, REG_PCIE_PHYMISC, &data);
+ data |= PCIE_PHYMISC_FORCE_RCV_DET;
+ AT_WRITE_REG(hw, REG_PCIE_PHYMISC, data);
+
+ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10) {
+ AT_READ_REG(hw, REG_PCIE_PHYMISC2, &data);
+
+ data &= ~(PCIE_PHYMISC2_SERDES_CDR_MASK <<
+ PCIE_PHYMISC2_SERDES_CDR_SHIFT);
+ data |= 3 << PCIE_PHYMISC2_SERDES_CDR_SHIFT;
+ data &= ~(PCIE_PHYMISC2_SERDES_TH_MASK <<
+ PCIE_PHYMISC2_SERDES_TH_SHIFT);
+ data |= 3 << PCIE_PHYMISC2_SERDES_TH_SHIFT;
+ AT_WRITE_REG(hw, REG_PCIE_PHYMISC2, data);
+ }
+}
+
+/* FIXME: no need any more ? */
/*
* atl1c_init_pcie - init PCIE module
*/
@@ -127,6 +148,11 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
data &= ~PCIE_UC_SERVRITY_FCP;
AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data);
+ AT_READ_REG(hw, REG_LTSSM_ID_CTRL, &data);
+ data &= ~LTSSM_ID_EN_WRO;
+ AT_WRITE_REG(hw, REG_LTSSM_ID_CTRL, data);
+
+ atl1c_pcie_patch(hw);
if (flag & ATL1C_PCIE_L0S_L1_DISABLE)
atl1c_disable_l0s_l1(hw);
if (flag & ATL1C_PCIE_PHY_RESET)
@@ -135,7 +161,7 @@ static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
AT_WRITE_REG(hw, REG_GPHY_CTRL,
GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET);
- msleep(1);
+ msleep(5);
}
/*
@@ -159,6 +185,7 @@ static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
{
atomic_inc(&adapter->irq_sem);
AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+ AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
AT_WRITE_FLUSH(&adapter->hw);
synchronize_irq(adapter->pdev->irq);
}
@@ -231,15 +258,15 @@ static void atl1c_check_link_status(struct atl1c_adapter *adapter)
if ((phy_data & BMSR_LSTATUS) == 0) {
/* link down */
- if (netif_carrier_ok(netdev)) {
- hw->hibernate = true;
- if (atl1c_stop_mac(hw) != 0)
- if (netif_msg_hw(adapter))
- dev_warn(&pdev->dev,
- "stop mac failed\n");
- atl1c_set_aspm(hw, false);
- }
+ hw->hibernate = true;
+ if (atl1c_stop_mac(hw) != 0)
+ if (netif_msg_hw(adapter))
+ dev_warn(&pdev->dev, "stop mac failed\n");
+ atl1c_set_aspm(hw, false);
netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ atl1c_phy_reset(hw);
+ atl1c_phy_init(&adapter->hw);
} else {
/* Link Up */
hw->hibernate = false;
@@ -308,6 +335,7 @@ static void atl1c_common_task(struct work_struct *work)
netdev = adapter->netdev;
if (adapter->work_event & ATL1C_WORK_EVENT_RESET) {
+ adapter->work_event &= ~ATL1C_WORK_EVENT_RESET;
netif_device_detach(netdev);
atl1c_down(adapter);
atl1c_up(adapter);
@@ -315,8 +343,11 @@ static void atl1c_common_task(struct work_struct *work)
return;
}
- if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE)
+ if (adapter->work_event & ATL1C_WORK_EVENT_LINK_CHANGE) {
+ adapter->work_event &= ~ATL1C_WORK_EVENT_LINK_CHANGE;
atl1c_check_link_status(adapter);
+ }
+ return;
}
@@ -476,6 +507,13 @@ static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
adapter->hw.max_frame_size = new_mtu;
atl1c_set_rxbufsize(adapter, netdev);
+ if (new_mtu > MAX_TSO_FRAME_SIZE) {
+ adapter->netdev->features &= ~NETIF_F_TSO;
+ adapter->netdev->features &= ~NETIF_F_TSO6;
+ } else {
+ adapter->netdev->features |= NETIF_F_TSO;
+ adapter->netdev->features |= NETIF_F_TSO6;
+ }
atl1c_down(adapter);
atl1c_up(adapter);
clear_bit(__AT_RESETTING, &adapter->flags);
@@ -613,6 +651,9 @@ static void atl1c_set_mac_type(struct atl1c_hw *hw)
case PCI_DEVICE_ID_ATHEROS_L1D:
hw->nic_type = athr_l1d;
break;
+ case PCI_DEVICE_ID_ATHEROS_L1D_2_0:
+ hw->nic_type = athr_l1d_2;
+ break;
default:
break;
}
@@ -627,9 +668,7 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data);
AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
- hw->ctrl_flags = ATL1C_INTR_CLEAR_ON_READ |
- ATL1C_INTR_MODRT_ENABLE |
- ATL1C_RX_IPV6_CHKSUM |
+ hw->ctrl_flags = ATL1C_INTR_MODRT_ENABLE |
ATL1C_TXQ_MODE_ENHANCE;
if (link_ctrl_data & LINK_CTRL_L0S_EN)
hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
@@ -637,12 +676,12 @@ static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
if (link_ctrl_data & LINK_CTRL_EXT_SYNC)
hw->ctrl_flags |= ATL1C_LINK_EXT_SYNC;
+ hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
if (hw->nic_type == athr_l1c ||
- hw->nic_type == athr_l1d) {
- hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+ hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l1d_2)
hw->link_cap_flags |= ATL1C_LINK_CAP_1000M;
- }
return 0;
}
/*
@@ -657,6 +696,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
{
struct atl1c_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
+ u32 revision;
+
adapter->wol = 0;
adapter->link_speed = SPEED_0;
@@ -669,7 +710,8 @@ static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
hw->device_id = pdev->device;
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_id = pdev->subsystem_device;
-
+ AT_READ_REG(hw, PCI_CLASS_REVISION, &revision);
+ hw->revision_id = revision & 0xFF;
/* before link up, we assume hibernate is true */
hw->hibernate = true;
hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
@@ -974,6 +1016,7 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb;
struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb;
int i;
+ u32 data;
/* TPD */
AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
@@ -1017,6 +1060,23 @@ static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
(u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32));
AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO,
(u32)(smb->dma & AT_DMA_LO_ADDR_MASK));
+ if (hw->nic_type == athr_l2c_b) {
+ AT_WRITE_REG(hw, REG_SRAM_RXF_LEN, 0x02a0L);
+ AT_WRITE_REG(hw, REG_SRAM_TXF_LEN, 0x0100L);
+ AT_WRITE_REG(hw, REG_SRAM_RXF_ADDR, 0x029f0000L);
+ AT_WRITE_REG(hw, REG_SRAM_RFD0_INFO, 0x02bf02a0L);
+ AT_WRITE_REG(hw, REG_SRAM_TXF_ADDR, 0x03bf02c0L);
+ AT_WRITE_REG(hw, REG_SRAM_TRD_ADDR, 0x03df03c0L);
+ AT_WRITE_REG(hw, REG_TXF_WATER_MARK, 0); /* TX watermark, to enter l1 state.*/
+ AT_WRITE_REG(hw, REG_RXD_DMA_CTRL, 0); /* RXD threshold.*/
+ }
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d_2) {
+ /* Power Saving for L2c_B */
+ AT_READ_REG(hw, REG_SERDES_LOCK, &data);
+ data |= SERDES_MAC_CLK_SLOWDOWN;
+ data |= SERDES_PYH_CLK_SLOWDOWN;
+ AT_WRITE_REG(hw, REG_SERDES_LOCK, data);
+ }
/* Load all of base address above */
AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
}
@@ -1029,6 +1089,7 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
u16 tx_offload_thresh;
u32 txq_ctrl_data;
u32 extra_size = 0; /* Jumbo frame threshold in QWORD unit */
+ u32 max_pay_load_data;
extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
@@ -1046,8 +1107,11 @@ static void atl1c_configure_tx(struct atl1c_adapter *adapter)
TXQ_NUM_TPD_BURST_SHIFT;
if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE)
txq_ctrl_data |= TXQ_CTRL_ENH_MODE;
- txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
+ max_pay_load_data = (atl1c_pay_load_size[hw->dmar_block] &
TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2)
+ max_pay_load_data >>= 1;
+ txq_ctrl_data |= max_pay_load_data;
AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
}
@@ -1078,7 +1142,7 @@ static void atl1c_configure_rx(struct atl1c_adapter *adapter)
rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) <<
RSS_HASH_BITS_SHIFT;
if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON)
- rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_100M &
+ rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_1M &
ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
@@ -1198,21 +1262,23 @@ static int atl1c_reset_mac(struct atl1c_hw *hw)
{
struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
struct pci_dev *pdev = adapter->pdev;
- int ret;
+ u32 master_ctrl_data = 0;
AT_WRITE_REG(hw, REG_IMR, 0);
AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
- ret = atl1c_stop_mac(hw);
- if (ret)
- return ret;
+ atl1c_stop_mac(hw);
/*
* Issue Soft Reset to the MAC. This will reset the chip's
* transmit, receive, DMA. It will not effect
* the current PCI configuration. The global reset bit is self-
* clearing, and should clear within a microsecond.
*/
- AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+ master_ctrl_data |= MASTER_CTRL_OOB_DIS_OFF;
+ AT_WRITE_REGW(hw, REG_MASTER_CTRL, ((master_ctrl_data | MASTER_CTRL_SOFT_RST)
+ & 0xFFFF));
+
AT_WRITE_FLUSH(hw);
msleep(10);
/* Wait at least 10ms for All module to be Idle */
@@ -1253,42 +1319,39 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
{
u32 pm_ctrl_data;
u32 link_ctrl_data;
+ u32 link_l1_timer = 0xF;
AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
- pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+ pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
PM_CTRL_L1_ENTRY_TIMER_SHIFT);
pm_ctrl_data &= ~(PM_CTRL_LCKDET_TIMER_MASK <<
- PM_CTRL_LCKDET_TIMER_SHIFT);
-
- pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
- pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
- pm_ctrl_data |= PM_CTRL_RBER_EN;
- pm_ctrl_data |= PM_CTRL_SDES_EN;
+ PM_CTRL_LCKDET_TIMER_SHIFT);
+ pm_ctrl_data |= AT_LCKDET_TIMER << PM_CTRL_LCKDET_TIMER_SHIFT;
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l1d ||
- hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
link_ctrl_data &= ~LINK_CTRL_EXT_SYNC;
if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE)) {
- if (hw->nic_type == athr_l2c_b &&
- hw->revision_id == L2CB_V10)
+ if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V10)
link_ctrl_data |= LINK_CTRL_EXT_SYNC;
}
AT_WRITE_REG(hw, REG_LINK_CTRL, link_ctrl_data);
- pm_ctrl_data |= PM_CTRL_PCIE_RECV;
- pm_ctrl_data |= AT_ASPM_L1_TIMER << PM_CTRL_PM_REQ_TIMER_SHIFT;
- pm_ctrl_data &= ~PM_CTRL_EN_BUFS_RX_L0S;
+ pm_ctrl_data |= PM_CTRL_RCVR_WT_TIMER;
+ pm_ctrl_data &= ~(PM_CTRL_PM_REQ_TIMER_MASK <<
+ PM_CTRL_PM_REQ_TIMER_SHIFT);
+ pm_ctrl_data |= AT_ASPM_L1_TIMER <<
+ PM_CTRL_PM_REQ_TIMER_SHIFT;
pm_ctrl_data &= ~PM_CTRL_SA_DLY_EN;
pm_ctrl_data &= ~PM_CTRL_HOTRST;
pm_ctrl_data |= 1 << PM_CTRL_L1_ENTRY_TIMER_SHIFT;
pm_ctrl_data |= PM_CTRL_SERDES_PD_EX_L1;
}
-
+ pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
if (linkup) {
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
@@ -1297,27 +1360,26 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
- if (hw->nic_type == athr_l2c_b ||
- hw->nic_type == athr_l1d ||
- hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l1d ||
+ hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) {
if (hw->nic_type == athr_l2c_b)
if (!(hw->ctrl_flags & ATL1C_APS_MODE_ENABLE))
- pm_ctrl_data &= PM_CTRL_ASPM_L0S_EN;
+ pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
- if (hw->adapter->link_speed == SPEED_100 ||
- hw->adapter->link_speed == SPEED_1000) {
- pm_ctrl_data &=
- ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT);
- if (hw->nic_type == athr_l1d)
- pm_ctrl_data |= 0xF <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
- else
- pm_ctrl_data |= 7 <<
- PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+ if (hw->adapter->link_speed == SPEED_100 ||
+ hw->adapter->link_speed == SPEED_1000) {
+ pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+ if (hw->nic_type == athr_l2c_b)
+ link_l1_timer = 7;
+ else if (hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d_2)
+ link_l1_timer = 4;
+ pm_ctrl_data |= link_l1_timer <<
+ PM_CTRL_L1_ENTRY_TIMER_SHIFT;
}
} else {
pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
@@ -1326,24 +1388,12 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
- }
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0x29);
- if (hw->adapter->link_speed == SPEED_10)
- if (hw->nic_type == athr_l1d)
- atl1c_write_phy_reg(hw, MII_DBG_ADDR, 0xB69D);
- else
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB6DD);
- else if (hw->adapter->link_speed == SPEED_100)
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0xB2DD);
- else
- atl1c_write_phy_reg(hw, MII_DBG_DATA, 0x96DD);
+ }
} else {
- pm_ctrl_data &= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_L1_EN;
pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
-
pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
@@ -1351,8 +1401,9 @@ static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
else
pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
}
-
AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
+
+ return;
}
static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
@@ -1391,7 +1442,8 @@ static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
- if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2) {
+ if (hw->nic_type == athr_l1d || hw->nic_type == athr_l2c_b2 ||
+ hw->nic_type == athr_l1d_2) {
mac_ctrl_data |= MAC_CTRL_SPEED_MODE_SW;
mac_ctrl_data |= MAC_CTRL_HASH_ALG_CRC32;
}
@@ -1409,6 +1461,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
struct atl1c_hw *hw = &adapter->hw;
u32 master_ctrl_data = 0;
u32 intr_modrt_data;
+ u32 data;
/* clear interrupt status */
AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
@@ -1418,6 +1471,15 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
* HW will enable self to assert interrupt event to system after
* waiting x-time for software to notify it accept interrupt.
*/
+
+ data = CLK_GATING_EN_ALL;
+ if (hw->ctrl_flags & ATL1C_CLK_GATING_EN) {
+ if (hw->nic_type == athr_l2c_b)
+ data &= ~CLK_GATING_RXMAC_EN;
+ } else
+ data = 0;
+ AT_WRITE_REG(hw, REG_CLK_GATING_CTRL, data);
+
AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
hw->ict & INT_RETRIG_TIMER_MASK);
@@ -1436,6 +1498,7 @@ static int atl1c_configure(struct atl1c_adapter *adapter)
if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
+ master_ctrl_data |= MASTER_CTRL_SA_TIMER_EN;
AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
if (hw->ctrl_flags & ATL1C_CMB_ENABLE) {
@@ -1624,11 +1687,9 @@ static irqreturn_t atl1c_intr(int irq, void *data)
"atl1c hardware error (status = 0x%x)\n",
status & ISR_ERROR);
/* reset MAC */
- hw->intr_mask &= ~ISR_ERROR;
- AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
adapter->work_event |= ATL1C_WORK_EVENT_RESET;
schedule_work(&adapter->common_task);
- break;
+ return IRQ_HANDLED;
}
if (status & ISR_OVER)
@@ -2303,7 +2364,6 @@ void atl1c_down(struct atl1c_adapter *adapter)
napi_disable(&adapter->napi);
atl1c_irq_disable(adapter);
atl1c_free_irq(adapter);
- AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
/* reset MAC to disable all RX/TX */
atl1c_reset_mac(&adapter->hw);
msleep(1);
@@ -2387,79 +2447,68 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
struct net_device *netdev = pci_get_drvdata(pdev);
struct atl1c_adapter *adapter = netdev_priv(netdev);
struct atl1c_hw *hw = &adapter->hw;
- u32 ctrl;
- u32 mac_ctrl_data;
- u32 master_ctrl_data;
+ u32 mac_ctrl_data = 0;
+ u32 master_ctrl_data = 0;
u32 wol_ctrl_data = 0;
- u16 mii_bmsr_data;
- u16 save_autoneg_advertised;
- u16 mii_intr_status_data;
+ u16 mii_intr_status_data = 0;
u32 wufc = adapter->wol;
- u32 i;
int retval = 0;
+ atl1c_disable_l0s_l1(hw);
if (netif_running(netdev)) {
WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
atl1c_down(adapter);
}
netif_device_detach(netdev);
- atl1c_disable_l0s_l1(hw);
retval = pci_save_state(pdev);
if (retval)
return retval;
+
+ if (wufc)
+ if (atl1c_phy_power_saving(hw) != 0)
+ dev_dbg(&pdev->dev, "phy power saving failed");
+
+ AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+ AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+ master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+ mac_ctrl_data &= ~(MAC_CTRL_PRMLEN_MASK << MAC_CTRL_PRMLEN_SHIFT);
+ mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+ MAC_CTRL_PRMLEN_MASK) <<
+ MAC_CTRL_PRMLEN_SHIFT);
+ mac_ctrl_data &= ~(MAC_CTRL_SPEED_MASK << MAC_CTRL_SPEED_SHIFT);
+ mac_ctrl_data &= ~MAC_CTRL_DUPLX;
+
if (wufc) {
- AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
- master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
-
- /* get link status */
- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
- atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
- save_autoneg_advertised = hw->autoneg_advertised;
- hw->autoneg_advertised = ADVERTISED_10baseT_Half;
- if (atl1c_restart_autoneg(hw) != 0)
- if (netif_msg_link(adapter))
- dev_warn(&pdev->dev, "phy autoneg failed\n");
- hw->phy_configured = false; /* re-init PHY when resume */
- hw->autoneg_advertised = save_autoneg_advertised;
+ mac_ctrl_data |= MAC_CTRL_RX_EN;
+ if (adapter->link_speed == SPEED_1000 ||
+ adapter->link_speed == SPEED_0) {
+ mac_ctrl_data |= atl1c_mac_speed_1000 <<
+ MAC_CTRL_SPEED_SHIFT;
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+ } else
+ mac_ctrl_data |= atl1c_mac_speed_10_100 <<
+ MAC_CTRL_SPEED_SHIFT;
+
+ if (adapter->link_duplex == DUPLEX_FULL)
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+
/* turn on magic packet wol */
if (wufc & AT_WUFC_MAG)
- wol_ctrl_data = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+ wol_ctrl_data |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
if (wufc & AT_WUFC_LNKC) {
- for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
- msleep(100);
- atl1c_read_phy_reg(hw, MII_BMSR,
- (u16 *)&mii_bmsr_data);
- if (mii_bmsr_data & BMSR_LSTATUS)
- break;
- }
- if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
- if (netif_msg_link(adapter))
- dev_warn(&pdev->dev,
- "%s: Link may change"
- "when suspend\n",
- atl1c_driver_name);
wol_ctrl_data |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
/* only link up can wake up */
if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
- if (netif_msg_link(adapter))
- dev_err(&pdev->dev,
- "%s: read write phy "
- "register failed.\n",
- atl1c_driver_name);
- goto wol_dis;
+ dev_dbg(&pdev->dev, "%s: read write phy "
+ "register failed.\n",
+ atl1c_driver_name);
}
}
/* clear phy interrupt */
atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
/* Config MAC Ctrl register */
- mac_ctrl_data = MAC_CTRL_RX_EN;
- /* set to 10/100M halt duplex */
- mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
- mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
- MAC_CTRL_PRMLEN_MASK) <<
- MAC_CTRL_PRMLEN_SHIFT);
-
if (adapter->vlgrp)
mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
@@ -2467,37 +2516,30 @@ static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
if (wufc & AT_WUFC_MAG)
mac_ctrl_data |= MAC_CTRL_BC_EN;
- if (netif_msg_hw(adapter))
- dev_dbg(&pdev->dev,
- "%s: suspend MAC=0x%x\n",
- atl1c_driver_name, mac_ctrl_data);
+ dev_dbg(&pdev->dev,
+ "%s: suspend MAC=0x%x\n",
+ atl1c_driver_name, mac_ctrl_data);
AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
/* pcie patch */
- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+ device_set_wakeup_enable(&pdev->dev, 1);
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
- goto suspend_exit;
+ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT |
+ GPHY_CTRL_EXT_RESET);
+ pci_prepare_to_sleep(pdev);
+ } else {
+ AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_POWER_SAVING);
+ master_ctrl_data |= MASTER_CTRL_CLK_SEL_DIS;
+ mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+ mac_ctrl_data |= MAC_CTRL_DUPLX;
+ AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+ AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+ AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+ hw->phy_configured = false; /* re-init PHY when resume */
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
}
-wol_dis:
-
- /* WOL disabled */
- AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
-
- /* pcie patch */
- AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
- ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
- AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
-
- atl1c_phy_disable(hw);
- hw->phy_configured = false; /* re-init PHY when resume */
-
- pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-suspend_exit:
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -2516,9 +2558,19 @@ static int atl1c_resume(struct pci_dev *pdev)
pci_enable_wake(pdev, PCI_D3cold, 0);
AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+ atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
+ ATL1C_PCIE_PHY_RESET);
atl1c_phy_reset(&adapter->hw);
atl1c_reset_mac(&adapter->hw);
+ atl1c_phy_init(&adapter->hw);
+
+#if 0
+ AT_READ_REG(&adapter->hw, REG_PM_CTRLSTAT, &pm_data);
+ pm_data &= ~PM_CTRLSTAT_PME_EN;
+ AT_WRITE_REG(&adapter->hw, REG_PM_CTRLSTAT, pm_data);
+#endif
+
netif_device_attach(netdev);
if (netif_running(netdev))
atl1c_up(adapter);
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 146372fd6683..9c0ddb273ac8 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -436,8 +436,8 @@ struct rx_free_desc {
__le16 buf_len; /* Size of the receive buffer in host memory */
u16 coalese; /* Update consumer index to host after the
* reception of this frame */
- /* __attribute__ ((packed)) is required */
-} __attribute__ ((packed));
+ /* __packed is required */
+} __packed;
/*
* The L1 transmit packet descriptor is comprised of four 32-bit words.
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 293f9c16e786..3d52538df6c4 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -150,9 +150,8 @@ static inline void b44_sync_dma_desc_for_device(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
- ssb_dma_sync_single_range_for_device(sdev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_for_device(sdev->dma_dev, dma_base + offset,
+ dma_desc_sync_size, dir);
}
static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
@@ -160,9 +159,8 @@ static inline void b44_sync_dma_desc_for_cpu(struct ssb_device *sdev,
unsigned long offset,
enum dma_data_direction dir)
{
- ssb_dma_sync_single_range_for_cpu(sdev, dma_base,
- offset & dma_desc_align_mask,
- dma_desc_sync_size, dir);
+ dma_sync_single_for_cpu(sdev->dma_dev, dma_base + offset,
+ dma_desc_sync_size, dir);
}
static inline unsigned long br32(const struct b44 *bp, unsigned long reg)
@@ -608,10 +606,10 @@ static void b44_tx(struct b44 *bp)
BUG_ON(skb == NULL);
- ssb_dma_unmap_single(bp->sdev,
- rp->mapping,
- skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev,
+ rp->mapping,
+ skb->len,
+ DMA_TO_DEVICE);
rp->skb = NULL;
dev_kfree_skb_irq(skb);
}
@@ -648,29 +646,29 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
if (skb == NULL)
return -ENOMEM;
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
/* Hardware bug work-around, the chip is unable to do PCI DMA
to/from anything above 1GB :-( */
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
/* Sigh... */
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping,
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
RX_PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
skb = __netdev_alloc_skb(bp->dev, RX_PKT_BUF_SZ, GFP_ATOMIC|GFP_DMA);
if (skb == NULL)
return -ENOMEM;
- mapping = ssb_dma_map_single(bp->sdev, skb->data,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) ||
- mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) ||
+ mapping + RX_PKT_BUF_SZ > DMA_BIT_MASK(30)) {
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping, RX_PKT_BUF_SZ,DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
return -ENOMEM;
}
@@ -745,9 +743,9 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
dest_idx * sizeof(*dest_desc),
DMA_BIDIRECTIONAL);
- ssb_dma_sync_single_for_device(bp->sdev, dest_map->mapping,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_device(bp->sdev->dma_dev, dest_map->mapping,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
}
static int b44_rx(struct b44 *bp, int budget)
@@ -767,9 +765,9 @@ static int b44_rx(struct b44 *bp, int budget)
struct rx_header *rh;
u16 len;
- ssb_dma_sync_single_for_cpu(bp->sdev, map,
- RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(bp->sdev->dma_dev, map,
+ RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
rh = (struct rx_header *) skb->data;
len = le16_to_cpu(rh->len);
if ((len > (RX_PKT_BUF_SZ - RX_PKT_OFFSET)) ||
@@ -801,8 +799,8 @@ static int b44_rx(struct b44 *bp, int budget)
skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
if (skb_size < 0)
goto drop_it;
- ssb_dma_unmap_single(bp->sdev, map,
- skb_size, DMA_FROM_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, map,
+ skb_size, DMA_FROM_DEVICE);
/* Leave out rx_header */
skb_put(skb, len + RX_PKT_OFFSET);
skb_pull(skb, RX_PKT_OFFSET);
@@ -954,24 +952,24 @@ static netdev_tx_t b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto err_out;
}
- mapping = ssb_dma_map_single(bp->sdev, skb->data, len, DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+ mapping = dma_map_single(bp->sdev->dma_dev, skb->data, len, DMA_TO_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
struct sk_buff *bounce_skb;
/* Chip can't handle DMA to/from >1GB, use bounce buffer */
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping, len,
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping, len,
DMA_TO_DEVICE);
bounce_skb = __netdev_alloc_skb(dev, len, GFP_ATOMIC | GFP_DMA);
if (!bounce_skb)
goto err_out;
- mapping = ssb_dma_map_single(bp->sdev, bounce_skb->data,
- len, DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
- if (!ssb_dma_mapping_error(bp->sdev, mapping))
- ssb_dma_unmap_single(bp->sdev, mapping,
+ mapping = dma_map_single(bp->sdev->dma_dev, bounce_skb->data,
+ len, DMA_TO_DEVICE);
+ if (dma_mapping_error(bp->sdev->dma_dev, mapping) || mapping + len > DMA_BIT_MASK(30)) {
+ if (!dma_mapping_error(bp->sdev->dma_dev, mapping))
+ dma_unmap_single(bp->sdev->dma_dev, mapping,
len, DMA_TO_DEVICE);
dev_kfree_skb_any(bounce_skb);
goto err_out;
@@ -1068,8 +1066,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- ssb_dma_unmap_single(bp->sdev, rp->mapping, RX_PKT_BUF_SZ,
- DMA_FROM_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, RX_PKT_BUF_SZ,
+ DMA_FROM_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1080,8 +1078,8 @@ static void b44_free_rings(struct b44 *bp)
if (rp->skb == NULL)
continue;
- ssb_dma_unmap_single(bp->sdev, rp->mapping, rp->skb->len,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, rp->mapping, rp->skb->len,
+ DMA_TO_DEVICE);
dev_kfree_skb_any(rp->skb);
rp->skb = NULL;
}
@@ -1103,14 +1101,12 @@ static void b44_init_rings(struct b44 *bp)
memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
if (bp->flags & B44_FLAG_RX_RING_HACK)
- ssb_dma_sync_single_for_device(bp->sdev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
if (bp->flags & B44_FLAG_TX_RING_HACK)
- ssb_dma_sync_single_for_device(bp->sdev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_sync_single_for_device(bp->sdev->dma_dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
for (i = 0; i < bp->rx_pending; i++) {
if (b44_alloc_rx_skb(bp, -1, i) < 0)
@@ -1130,27 +1126,23 @@ static void b44_free_consistent(struct b44 *bp)
bp->tx_buffers = NULL;
if (bp->rx_ring) {
if (bp->flags & B44_FLAG_RX_RING_HACK) {
- ssb_dma_unmap_single(bp->sdev, bp->rx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ dma_unmap_single(bp->sdev->dma_dev, bp->rx_ring_dma,
+ DMA_TABLE_BYTES, DMA_BIDIRECTIONAL);
kfree(bp->rx_ring);
} else
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
- bp->rx_ring, bp->rx_ring_dma,
- GFP_KERNEL);
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+ bp->rx_ring, bp->rx_ring_dma);
bp->rx_ring = NULL;
bp->flags &= ~B44_FLAG_RX_RING_HACK;
}
if (bp->tx_ring) {
if (bp->flags & B44_FLAG_TX_RING_HACK) {
- ssb_dma_unmap_single(bp->sdev, bp->tx_ring_dma,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ dma_unmap_single(bp->sdev->dma_dev, bp->tx_ring_dma,
+ DMA_TABLE_BYTES, DMA_TO_DEVICE);
kfree(bp->tx_ring);
} else
- ssb_dma_free_consistent(bp->sdev, DMA_TABLE_BYTES,
- bp->tx_ring, bp->tx_ring_dma,
- GFP_KERNEL);
+ dma_free_coherent(bp->sdev->dma_dev, DMA_TABLE_BYTES,
+ bp->tx_ring, bp->tx_ring_dma);
bp->tx_ring = NULL;
bp->flags &= ~B44_FLAG_TX_RING_HACK;
}
@@ -1175,7 +1167,8 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
goto out_err;
size = DMA_TABLE_BYTES;
- bp->rx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->rx_ring_dma, gfp);
+ bp->rx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+ &bp->rx_ring_dma, gfp);
if (!bp->rx_ring) {
/* Allocation may have failed due to pci_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1187,11 +1180,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!rx_ring)
goto out_err;
- rx_ring_dma = ssb_dma_map_single(bp->sdev, rx_ring,
- DMA_TABLE_BYTES,
- DMA_BIDIRECTIONAL);
+ rx_ring_dma = dma_map_single(bp->sdev->dma_dev, rx_ring,
+ DMA_TABLE_BYTES,
+ DMA_BIDIRECTIONAL);
- if (ssb_dma_mapping_error(bp->sdev, rx_ring_dma) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, rx_ring_dma) ||
rx_ring_dma + size > DMA_BIT_MASK(30)) {
kfree(rx_ring);
goto out_err;
@@ -1202,7 +1195,8 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
bp->flags |= B44_FLAG_RX_RING_HACK;
}
- bp->tx_ring = ssb_dma_alloc_consistent(bp->sdev, size, &bp->tx_ring_dma, gfp);
+ bp->tx_ring = dma_alloc_coherent(bp->sdev->dma_dev, size,
+ &bp->tx_ring_dma, gfp);
if (!bp->tx_ring) {
/* Allocation may have failed due to ssb_dma_alloc_consistent
insisting on use of GFP_DMA, which is more restrictive
@@ -1214,11 +1208,11 @@ static int b44_alloc_consistent(struct b44 *bp, gfp_t gfp)
if (!tx_ring)
goto out_err;
- tx_ring_dma = ssb_dma_map_single(bp->sdev, tx_ring,
- DMA_TABLE_BYTES,
- DMA_TO_DEVICE);
+ tx_ring_dma = dma_map_single(bp->sdev->dma_dev, tx_ring,
+ DMA_TABLE_BYTES,
+ DMA_TO_DEVICE);
- if (ssb_dma_mapping_error(bp->sdev, tx_ring_dma) ||
+ if (dma_mapping_error(bp->sdev->dma_dev, tx_ring_dma) ||
tx_ring_dma + size > DMA_BIT_MASK(30)) {
kfree(tx_ring);
goto out_err;
@@ -2176,12 +2170,14 @@ static int __devinit b44_init_one(struct ssb_device *sdev,
"Failed to powerup the bus\n");
goto err_out_free_dev;
}
- err = ssb_dma_set_mask(sdev, DMA_BIT_MASK(30));
- if (err) {
+
+ if (dma_set_mask(sdev->dma_dev, DMA_BIT_MASK(30)) ||
+ dma_set_coherent_mask(sdev->dma_dev, DMA_BIT_MASK(30))) {
dev_err(sdev->dev,
"Required 30BIT DMA mask unsupported by the system\n");
goto err_out_powerdown;
}
+
err = b44_get_invariants(bp);
if (err) {
dev_err(sdev->dev,
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 9d11dbf5e4da..ee1ad9693c8f 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -186,7 +186,7 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
{
- int cnt = 0, wait = 5;
+ int msecs = 0;
u32 ready;
do {
@@ -201,15 +201,14 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
if (ready)
break;
- if (cnt > 4000000) {
+ if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
return -1;
}
- if (cnt > 50)
- wait = 200;
- cnt += wait;
- udelay(wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(1));
+ msecs++;
} while (true);
return 0;
@@ -1429,7 +1428,7 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
wrb = wrb_from_mccq(adapter);
if (!wrb) {
status = -EBUSY;
- goto err;
+ goto err_unlock;
}
req = cmd->va;
sge = nonembedded_sgl(wrb);
@@ -1457,7 +1456,10 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
else
status = adapter->flash_status;
-err:
+ return status;
+
+err_unlock:
+ spin_unlock_bh(&adapter->mcc_lock);
return status;
}
@@ -1497,7 +1499,7 @@ err:
return status;
}
-extern int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
+int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
struct be_dma_mem *nonemb_cmd)
{
struct be_mcc_wrb *wrb;
@@ -1590,7 +1592,7 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num,
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_LOWLEVEL,
OPCODE_LOWLEVEL_LOOPBACK_TEST, sizeof(*req));
- req->hdr.timeout = 4;
+ req->hdr.timeout = cpu_to_le32(4);
req->pattern = cpu_to_le64(pattern);
req->src_port = cpu_to_le32(port_num);
@@ -1662,7 +1664,7 @@ err:
return status;
}
-extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
+int be_cmd_get_seeprom_data(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd)
{
struct be_mcc_wrb *wrb;
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 54b14272f333..322577469852 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1735,6 +1735,44 @@ done:
adapter->isr_registered = false;
}
+static int be_close(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+ int vec;
+
+ cancel_delayed_work_sync(&adapter->work);
+
+ be_async_mcc_disable(adapter);
+
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
+ adapter->link_up = false;
+
+ be_intr_set(adapter, false);
+
+ if (adapter->msix_enabled) {
+ vec = be_msix_vec_get(adapter, tx_eq->q.id);
+ synchronize_irq(vec);
+ vec = be_msix_vec_get(adapter, rx_eq->q.id);
+ synchronize_irq(vec);
+ } else {
+ synchronize_irq(netdev->irq);
+ }
+ be_irq_unregister(adapter);
+
+ napi_disable(&rx_eq->napi);
+ napi_disable(&tx_eq->napi);
+
+ /* Wait for all pending tx completions to arrive so that
+ * all tx skbs are freed.
+ */
+ be_tx_compl_clean(adapter);
+
+ return 0;
+}
+
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1765,27 +1803,29 @@ static int be_open(struct net_device *netdev)
/* Now that interrupts are on we can process async mcc */
be_async_mcc_enable(adapter);
+ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
&link_speed);
if (status)
- goto ret_sts;
+ goto err;
be_link_status_update(adapter, link_up);
- if (be_physfn(adapter))
+ if (be_physfn(adapter)) {
status = be_vid_config(adapter);
- if (status)
- goto ret_sts;
+ if (status)
+ goto err;
- if (be_physfn(adapter)) {
status = be_cmd_set_flow_control(adapter,
adapter->tx_fc, adapter->rx_fc);
if (status)
- goto ret_sts;
+ goto err;
}
- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-ret_sts:
- return status;
+ return 0;
+err:
+ be_close(adapter->netdev);
+ return -EIO;
}
static int be_setup_wol(struct be_adapter *adapter, bool enable)
@@ -1913,43 +1953,6 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
-static int be_close(struct net_device *netdev)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
- struct be_eq_obj *tx_eq = &adapter->tx_eq;
- int vec;
-
- cancel_delayed_work_sync(&adapter->work);
-
- be_async_mcc_disable(adapter);
-
- netif_stop_queue(netdev);
- netif_carrier_off(netdev);
- adapter->link_up = false;
-
- be_intr_set(adapter, false);
-
- if (adapter->msix_enabled) {
- vec = be_msix_vec_get(adapter, tx_eq->q.id);
- synchronize_irq(vec);
- vec = be_msix_vec_get(adapter, rx_eq->q.id);
- synchronize_irq(vec);
- } else {
- synchronize_irq(netdev->irq);
- }
- be_irq_unregister(adapter);
-
- napi_disable(&rx_eq->napi);
- napi_disable(&tx_eq->napi);
-
- /* Wait for all pending tx completions to arrive so that
- * all tx skbs are freed.
- */
- be_tx_compl_clean(adapter);
-
- return 0;
-}
#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
char flash_cookie[2][16] = {"*** SE FLAS",
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 39250b2ca886..959add2410bf 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1654,8 +1654,11 @@ MODULE_DEVICE_TABLE (of, bmac_match);
static struct macio_driver bmac_driver =
{
- .name = "bmac",
- .match_table = bmac_match,
+ .driver = {
+ .name = "bmac",
+ .owner = THIS_MODULE,
+ .of_match_table = bmac_match,
+ },
.probe = bmac_probe,
.remove = bmac_remove,
#ifdef CONFIG_PM
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 188e356c30a3..949d7a9dcf92 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -247,6 +247,7 @@ static const struct flash_spec flash_5709 = {
MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
static void bnx2_init_napi(struct bnx2 *bp);
+static void bnx2_del_napi(struct bnx2 *bp);
static inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr)
{
@@ -6270,6 +6271,7 @@ open_err:
bnx2_free_skbs(bp);
bnx2_free_irq(bp);
bnx2_free_mem(bp);
+ bnx2_del_napi(bp);
return rc;
}
@@ -6537,6 +6539,7 @@ bnx2_close(struct net_device *dev)
bnx2_free_irq(bp);
bnx2_free_skbs(bp);
bnx2_free_mem(bp);
+ bnx2_del_napi(bp);
bp->link_up = 0;
netif_carrier_off(bp->dev);
bnx2_set_power_state(bp, PCI_D3hot);
@@ -8227,7 +8230,16 @@ bnx2_bus_string(struct bnx2 *bp, char *str)
return str;
}
-static void __devinit
+static void
+bnx2_del_napi(struct bnx2 *bp)
+{
+ int i;
+
+ for (i = 0; i < bp->irq_nvecs; i++)
+ netif_napi_del(&bp->bnx2_napi[i].napi);
+}
+
+static void
bnx2_init_napi(struct bnx2 *bp)
{
int i;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 40fdc41446cc..25c14c6236f5 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -233,34 +233,27 @@ static void tlb_deinitialize(struct bonding *bond)
_unlock_tx_hashtbl(bond);
}
+static long long compute_gap(struct slave *slave)
+{
+ return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
+ (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+}
+
/* Caller must hold bond lock for read */
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
{
struct slave *slave, *least_loaded;
- s64 max_gap;
- int i, found = 0;
-
- /* Find the first enabled slave */
- bond_for_each_slave(bond, slave, i) {
- if (SLAVE_IS_OK(slave)) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- return NULL;
- }
+ long long max_gap;
+ int i;
- least_loaded = slave;
- max_gap = (s64)(slave->speed << 20) - /* Convert to Megabit per sec */
- (s64)(SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+ least_loaded = NULL;
+ max_gap = LLONG_MIN;
/* Find the slave with the largest gap */
- bond_for_each_slave_from(bond, slave, i, least_loaded) {
+ bond_for_each_slave(bond, slave, i) {
if (SLAVE_IS_OK(slave)) {
- s64 gap = (s64)(slave->speed << 20) -
- (s64)(SLAVE_TLB_INFO(slave).load << 3);
+ long long gap = compute_gap(slave);
+
if (max_gap < gap) {
least_loaded = slave;
max_gap = gap;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 5e12462a9d5e..1b19276cff12 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -90,6 +90,7 @@
#define BOND_LINK_ARP_INTERV 0
static int max_bonds = BOND_DEFAULT_MAX_BONDS;
+static int tx_queues = BOND_DEFAULT_TX_QUEUES;
static int num_grat_arp = 1;
static int num_unsol_na = 1;
static int miimon = BOND_LINK_MON_INTERV;
@@ -106,10 +107,13 @@ static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS];
static char *arp_validate;
static char *fail_over_mac;
+static int all_slaves_active = 0;
static struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
MODULE_PARM_DESC(max_bonds, "Max number of bonded devices");
+module_param(tx_queues, int, 0);
+MODULE_PARM_DESC(tx_queues, "Max number of transmit queues (default = 16)");
module_param(num_grat_arp, int, 0644);
MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event");
module_param(num_unsol_na, int, 0644);
@@ -155,6 +159,10 @@ module_param(arp_validate, charp, 0);
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
module_param(fail_over_mac, charp, 0);
MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. none (default), active or follow");
+module_param(all_slaves_active, int, 0);
+MODULE_PARM_DESC(all_slaves_active, "Keep all frames received on an interface"
+ "by setting active flag for all slaves. "
+ "0 for never (default), 1 for always.");
/*----------------------------- Global variables ----------------------------*/
@@ -1522,16 +1530,32 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
}
+ /* If this is the first slave, then we need to set the master's hardware
+ * address to be the same as the slave's. */
+ if (bond->slave_cnt == 0)
+ memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
+ slave_dev->addr_len);
+
+
new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL);
if (!new_slave) {
res = -ENOMEM;
goto err_undo_flags;
}
- /* save slave's original flags before calling
- * netdev_set_master and dev_open
+ /*
+ * Set the new_slave's queue_id to be zero. Queue ID mapping
+ * is set via sysfs or module option if desired.
*/
- new_slave->original_flags = slave_dev->flags;
+ new_slave->queue_id = 0;
+
+ /* Save slave's original mtu and then set it to match the bond */
+ new_slave->original_mtu = slave_dev->mtu;
+ res = dev_set_mtu(slave_dev, bond->dev->mtu);
+ if (res) {
+ pr_debug("Error %d calling dev_set_mtu\n", res);
+ goto err_free;
+ }
/*
* Save slave's original ("permanent") mac address for modes
@@ -1550,7 +1574,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
res = dev_set_mac_address(slave_dev, &addr);
if (res) {
pr_debug("Error %d calling set_mac_address\n", res);
- goto err_free;
+ goto err_restore_mtu;
}
}
@@ -1785,6 +1809,9 @@ err_restore_mac:
dev_set_mac_address(slave_dev, &addr);
}
+err_restore_mtu:
+ dev_set_mtu(slave_dev, new_slave->original_mtu);
+
err_free:
kfree(new_slave);
@@ -1969,6 +1996,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mac_address(slave_dev, &addr);
}
+ dev_set_mtu(slave_dev, slave->original_mtu);
+
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
IFF_SLAVE_INACTIVE | IFF_BONDING |
IFF_SLAVE_NEEDARP);
@@ -3265,6 +3294,7 @@ static void bond_info_show_slave(struct seq_file *seq,
else
seq_puts(seq, "Aggregator ID: N/A\n");
}
+ seq_printf(seq, "Slave queue ID: %d\n", slave->queue_id);
}
static int bond_info_seq_show(struct seq_file *seq, void *v)
@@ -4401,9 +4431,59 @@ static void bond_set_xmit_hash_policy(struct bonding *bond)
}
}
+/*
+ * Lookup the slave that corresponds to a qid
+ */
+static inline int bond_slave_override(struct bonding *bond,
+ struct sk_buff *skb)
+{
+ int i, res = 1;
+ struct slave *slave = NULL;
+ struct slave *check_slave;
+
+ read_lock(&bond->lock);
+
+ if (!BOND_IS_OK(bond) || !skb->queue_mapping)
+ goto out;
+
+ /* Find out if any slaves have the same mapping as this skb. */
+ bond_for_each_slave(bond, check_slave, i) {
+ if (check_slave->queue_id == skb->queue_mapping) {
+ slave = check_slave;
+ break;
+ }
+ }
+
+ /* If the slave isn't UP, use default transmit policy. */
+ if (slave && slave->queue_id && IS_UP(slave->dev) &&
+ (slave->link == BOND_LINK_UP)) {
+ res = bond_dev_queue_xmit(bond, skb, slave->dev);
+ }
+
+out:
+ read_unlock(&bond->lock);
+ return res;
+}
+
+static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+ /*
+ * This helper function exists to help dev_pick_tx get the correct
+ * destination queue. Using a helper function skips the a call to
+ * skb_tx_hash and will put the skbs in the queue we expect on their
+ * way down to the bonding driver.
+ */
+ return skb->queue_mapping;
+}
+
static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- const struct bonding *bond = netdev_priv(dev);
+ struct bonding *bond = netdev_priv(dev);
+
+ if (TX_QUEUE_OVERRIDE(bond->params.mode)) {
+ if (!bond_slave_override(bond, skb))
+ return NETDEV_TX_OK;
+ }
switch (bond->params.mode) {
case BOND_MODE_ROUNDROBIN:
@@ -4488,6 +4568,7 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_open = bond_open,
.ndo_stop = bond_close,
.ndo_start_xmit = bond_start_xmit,
+ .ndo_select_queue = bond_select_queue,
.ndo_get_stats = bond_get_stats,
.ndo_do_ioctl = bond_do_ioctl,
.ndo_set_multicast_list = bond_set_multicast_list,
@@ -4756,6 +4837,20 @@ static int bond_check_params(struct bond_params *params)
}
}
+ if (tx_queues < 1 || tx_queues > 255) {
+ pr_warning("Warning: tx_queues (%d) should be between "
+ "1 and 255, resetting to %d\n",
+ tx_queues, BOND_DEFAULT_TX_QUEUES);
+ tx_queues = BOND_DEFAULT_TX_QUEUES;
+ }
+
+ if ((all_slaves_active != 0) && (all_slaves_active != 1)) {
+ pr_warning("Warning: all_slaves_active module parameter (%d), "
+ "not of valid value (0/1), so it was set to "
+ "0\n", all_slaves_active);
+ all_slaves_active = 0;
+ }
+
/* reset values for TLB/ALB */
if ((bond_mode == BOND_MODE_TLB) ||
(bond_mode == BOND_MODE_ALB)) {
@@ -4926,6 +5021,8 @@ static int bond_check_params(struct bond_params *params)
params->primary[0] = 0;
params->primary_reselect = primary_reselect_value;
params->fail_over_mac = fail_over_mac_value;
+ params->tx_queues = tx_queues;
+ params->all_slaves_active = all_slaves_active;
if (primary) {
strncpy(params->primary, primary, IFNAMSIZ);
@@ -5012,8 +5109,8 @@ int bond_create(struct net *net, const char *name)
rtnl_lock();
- bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
- bond_setup);
+ bond_dev = alloc_netdev_mq(sizeof(struct bonding), name ? name : "",
+ bond_setup, tx_queues);
if (!bond_dev) {
pr_err("%s: eek! can't alloc netdev!\n", name);
rtnl_unlock();
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index b8bec086daa1..f9a034361a8e 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -211,7 +211,8 @@ static ssize_t bonding_show_slaves(struct device *d,
/*
* Set the slaves in the current bond. The bond interface must be
* up for this to succeed.
- * This function is largely the same flow as bonding_update_bonds().
+ * This is supposed to be only thin wrapper for bond_enslave and bond_release.
+ * All hard work should be done there.
*/
static ssize_t bonding_store_slaves(struct device *d,
struct device_attribute *attr,
@@ -219,10 +220,8 @@ static ssize_t bonding_store_slaves(struct device *d,
{
char command[IFNAMSIZ + 1] = { 0, };
char *ifname;
- int i, res, found, ret = count;
- u32 original_mtu;
- struct slave *slave;
- struct net_device *dev = NULL;
+ int res, ret = count;
+ struct net_device *dev;
struct bonding *bond = to_bond(d);
/* Quick sanity check -- is the bond interface up? */
@@ -231,8 +230,6 @@ static ssize_t bonding_store_slaves(struct device *d,
bond->dev->name);
}
- /* Note: We can't hold bond->lock here, as bond_create grabs it. */
-
if (!rtnl_trylock())
return restart_syscall();
@@ -242,91 +239,33 @@ static ssize_t bonding_store_slaves(struct device *d,
!dev_valid_name(ifname))
goto err_no_cmd;
- if (command[0] == '+') {
-
- /* Got a slave name in ifname. Is it already in the list? */
- found = 0;
-
- dev = __dev_get_by_name(dev_net(bond->dev), ifname);
- if (!dev) {
- pr_info("%s: Interface %s does not exist!\n",
- bond->dev->name, ifname);
- ret = -ENODEV;
- goto out;
- }
-
- if (dev->flags & IFF_UP) {
- pr_err("%s: Error: Unable to enslave %s because it is already up.\n",
- bond->dev->name, dev->name);
- ret = -EPERM;
- goto out;
- }
-
- read_lock(&bond->lock);
- bond_for_each_slave(bond, slave, i)
- if (slave->dev == dev) {
- pr_err("%s: Interface %s is already enslaved!\n",
- bond->dev->name, ifname);
- ret = -EPERM;
- read_unlock(&bond->lock);
- goto out;
- }
- read_unlock(&bond->lock);
-
- pr_info("%s: Adding slave %s.\n", bond->dev->name, ifname);
-
- /* If this is the first slave, then we need to set
- the master's hardware address to be the same as the
- slave's. */
- if (is_zero_ether_addr(bond->dev->dev_addr))
- memcpy(bond->dev->dev_addr, dev->dev_addr,
- dev->addr_len);
-
- /* Set the slave's MTU to match the bond */
- original_mtu = dev->mtu;
- res = dev_set_mtu(dev, bond->dev->mtu);
- if (res) {
- ret = res;
- goto out;
- }
+ dev = __dev_get_by_name(dev_net(bond->dev), ifname);
+ if (!dev) {
+ pr_info("%s: Interface %s does not exist!\n",
+ bond->dev->name, ifname);
+ ret = -ENODEV;
+ goto out;
+ }
+ switch (command[0]) {
+ case '+':
+ pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name);
res = bond_enslave(bond->dev, dev);
- bond_for_each_slave(bond, slave, i)
- if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0)
- slave->original_mtu = original_mtu;
- if (res)
- ret = res;
+ break;
- goto out;
- }
+ case '-':
+ pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name);
+ res = bond_release(bond->dev, dev);
+ break;
- if (command[0] == '-') {
- dev = NULL;
- original_mtu = 0;
- bond_for_each_slave(bond, slave, i)
- if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
- dev = slave->dev;
- original_mtu = slave->original_mtu;
- break;
- }
- if (dev) {
- pr_info("%s: Removing slave %s\n",
- bond->dev->name, dev->name);
- res = bond_release(bond->dev, dev);
- if (res) {
- ret = res;
- goto out;
- }
- /* set the slave MTU to the default */
- dev_set_mtu(dev, original_mtu);
- } else {
- pr_err("unable to remove non-existent slave %s for bond %s.\n",
- ifname, bond->dev->name);
- ret = -ENODEV;
- }
- goto out;
+ default:
+ goto err_no_cmd;
}
+ if (res)
+ ret = res;
+ goto out;
+
err_no_cmd:
pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n",
bond->dev->name);
@@ -1472,7 +1411,173 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d,
}
static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+/*
+ * Show the queue_ids of the slaves in the current bond.
+ */
+static ssize_t bonding_show_queue_id(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct slave *slave;
+ int i, res = 0;
+ struct bonding *bond = to_bond(d);
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+ read_lock(&bond->lock);
+ bond_for_each_slave(bond, slave, i) {
+ if (res > (PAGE_SIZE - 6)) {
+ /* not enough space for another interface name */
+ if ((PAGE_SIZE - res) > 10)
+ res = PAGE_SIZE - 10;
+ res += sprintf(buf + res, "++more++ ");
+ break;
+ }
+ res += sprintf(buf + res, "%s:%d ",
+ slave->dev->name, slave->queue_id);
+ }
+ read_unlock(&bond->lock);
+ if (res)
+ buf[res-1] = '\n'; /* eat the leftover space */
+ rtnl_unlock();
+ return res;
+}
+
+/*
+ * Set the queue_ids of the slaves in the current bond. The bond
+ * interface must be enslaved for this to work.
+ */
+static ssize_t bonding_store_queue_id(struct device *d,
+ struct device_attribute *attr,
+ const char *buffer, size_t count)
+{
+ struct slave *slave, *update_slave;
+ struct bonding *bond = to_bond(d);
+ u16 qid;
+ int i, ret = count;
+ char *delim;
+ struct net_device *sdev = NULL;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ /* delim will point to queue id if successful */
+ delim = strchr(buffer, ':');
+ if (!delim)
+ goto err_no_cmd;
+
+ /*
+ * Terminate string that points to device name and bump it
+ * up one, so we can read the queue id there.
+ */
+ *delim = '\0';
+ if (sscanf(++delim, "%hd\n", &qid) != 1)
+ goto err_no_cmd;
+
+ /* Check buffer length, valid ifname and queue id */
+ if (strlen(buffer) > IFNAMSIZ ||
+ !dev_valid_name(buffer) ||
+ qid > bond->params.tx_queues)
+ goto err_no_cmd;
+
+ /* Get the pointer to that interface if it exists */
+ sdev = __dev_get_by_name(dev_net(bond->dev), buffer);
+ if (!sdev)
+ goto err_no_cmd;
+
+ read_lock(&bond->lock);
+
+ /* Search for thes slave and check for duplicate qids */
+ update_slave = NULL;
+ bond_for_each_slave(bond, slave, i) {
+ if (sdev == slave->dev)
+ /*
+ * We don't need to check the matching
+ * slave for dups, since we're overwriting it
+ */
+ update_slave = slave;
+ else if (qid && qid == slave->queue_id) {
+ goto err_no_cmd_unlock;
+ }
+ }
+
+ if (!update_slave)
+ goto err_no_cmd_unlock;
+
+ /* Actually set the qids for the slave */
+ update_slave->queue_id = qid;
+
+ read_unlock(&bond->lock);
+out:
+ rtnl_unlock();
+ return ret;
+
+err_no_cmd_unlock:
+ read_unlock(&bond->lock);
+err_no_cmd:
+ pr_info("invalid input for queue_id set for %s.\n",
+ bond->dev->name);
+ ret = -EPERM;
+ goto out;
+}
+
+static DEVICE_ATTR(queue_id, S_IRUGO | S_IWUSR, bonding_show_queue_id,
+ bonding_store_queue_id);
+
+
+/*
+ * Show and set the all_slaves_active flag.
+ */
+static ssize_t bonding_show_slaves_active(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bonding *bond = to_bond(d);
+
+ return sprintf(buf, "%d\n", bond->params.all_slaves_active);
+}
+
+static ssize_t bonding_store_slaves_active(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int i, new_value, ret = count;
+ struct bonding *bond = to_bond(d);
+ struct slave *slave;
+
+ if (sscanf(buf, "%d", &new_value) != 1) {
+ pr_err("%s: no all_slaves_active value specified.\n",
+ bond->dev->name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (new_value == bond->params.all_slaves_active)
+ goto out;
+
+ if ((new_value == 0) || (new_value == 1)) {
+ bond->params.all_slaves_active = new_value;
+ } else {
+ pr_info("%s: Ignoring invalid all_slaves_active value %d.\n",
+ bond->dev->name, new_value);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ bond_for_each_slave(bond, slave, i) {
+ if (slave->state == BOND_STATE_BACKUP) {
+ if (new_value)
+ slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ else
+ slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ }
+ }
+out:
+ return count;
+}
+static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,
+ bonding_show_slaves_active, bonding_store_slaves_active);
static struct attribute *per_bond_attrs[] = {
&dev_attr_slaves.attr,
@@ -1499,6 +1604,8 @@ static struct attribute *per_bond_attrs[] = {
&dev_attr_ad_actor_key.attr,
&dev_attr_ad_partner_key.attr,
&dev_attr_ad_partner_mac.attr,
+ &dev_attr_queue_id.attr,
+ &dev_attr_all_slaves_active.attr,
NULL,
};
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 2aa336720591..c6fdd851579a 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -23,8 +23,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.6.0"
-#define DRV_RELDATE "September 26, 2009"
+#define DRV_VERSION "3.7.0"
+#define DRV_RELDATE "June 2, 2010"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -60,6 +60,9 @@
((mode) == BOND_MODE_TLB) || \
((mode) == BOND_MODE_ALB))
+#define TX_QUEUE_OVERRIDE(mode) \
+ (((mode) == BOND_MODE_ACTIVEBACKUP) || \
+ ((mode) == BOND_MODE_ROUNDROBIN))
/*
* Less bad way to call ioctl from within the kernel; this needs to be
* done some other way to get the call out of interrupt context.
@@ -131,6 +134,8 @@ struct bond_params {
char primary[IFNAMSIZ];
int primary_reselect;
__be32 arp_targets[BOND_MAX_ARP_TARGETS];
+ int tx_queues;
+ int all_slaves_active;
};
struct bond_parm_tbl {
@@ -159,12 +164,12 @@ struct slave {
s8 link; /* one of BOND_LINK_XXXX */
s8 new_link;
s8 state; /* one of BOND_STATE_XXXX */
- u32 original_flags;
u32 original_mtu;
u32 link_failure_count;
u8 perm_hwaddr[ETH_ALEN];
u16 speed;
u8 duplex;
+ u16 queue_id;
struct ad_slave_info ad_info; /* HUGE - better to dynamically alloc */
struct tlb_slave_info tlb_info;
};
@@ -291,7 +296,8 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
struct bonding *bond = netdev_priv(slave->dev->master);
if (!bond_is_lb(bond))
slave->state = BOND_STATE_BACKUP;
- slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ if (!bond->params.all_slaves_active)
+ slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
if (slave_do_arp_validate(bond, slave))
slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}
diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c
index 09257ca8f563..3e706f00a0d3 100644
--- a/drivers/net/caif/caif_serial.c
+++ b/drivers/net/caif/caif_serial.c
@@ -174,6 +174,7 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data,
struct ser_device *ser;
int ret;
u8 *p;
+
ser = tty->disc_data;
/*
@@ -221,6 +222,7 @@ static int handle_tx(struct ser_device *ser)
struct tty_struct *tty;
struct sk_buff *skb;
int tty_wr, len, room;
+
tty = ser->tty;
ser->tx_started = true;
@@ -281,6 +283,7 @@ error:
static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ser_device *ser;
+
BUG_ON(dev == NULL);
ser = netdev_priv(dev);
@@ -299,6 +302,7 @@ static int caif_xmit(struct sk_buff *skb, struct net_device *dev)
static void ldisc_tx_wakeup(struct tty_struct *tty)
{
struct ser_device *ser;
+
ser = tty->disc_data;
BUG_ON(ser == NULL);
BUG_ON(ser->tty != tty);
@@ -348,6 +352,7 @@ static void ldisc_close(struct tty_struct *tty)
struct ser_device *ser = tty->disc_data;
/* Remove may be called inside or outside of rtnl_lock */
int islocked = rtnl_is_locked();
+
if (!islocked)
rtnl_lock();
/* device is freed automagically by net-sysfs */
@@ -374,6 +379,7 @@ static struct tty_ldisc_ops caif_ldisc = {
static int register_ldisc(void)
{
int result;
+
result = tty_register_ldisc(N_CAIF, &caif_ldisc);
if (result < 0) {
pr_err("cannot register CAIF ldisc=%d err=%d\n", N_CAIF,
@@ -391,6 +397,7 @@ static const struct net_device_ops netdev_ops = {
static void caifdev_setup(struct net_device *dev)
{
struct ser_device *serdev = netdev_priv(dev);
+
dev->features = 0;
dev->netdev_ops = &netdev_ops;
dev->type = ARPHRD_CAIF;
@@ -410,8 +417,6 @@ static void caifdev_setup(struct net_device *dev)
static int caif_net_open(struct net_device *dev)
{
- struct ser_device *ser;
- ser = netdev_priv(dev);
netif_wake_queue(dev);
return 0;
}
@@ -425,6 +430,7 @@ static int caif_net_close(struct net_device *dev)
static int __init caif_ser_init(void)
{
int ret;
+
ret = register_ldisc();
debugfsdir = debugfs_create_dir("caif_serial", NULL);
return ret;
@@ -435,6 +441,7 @@ static void __exit caif_ser_exit(void)
struct ser_device *ser = NULL;
struct list_head *node;
struct list_head *_tmp;
+
list_for_each_safe(node, _tmp, &ser_list) {
ser = list_entry(node, struct ser_device, node);
dev_close(ser->dev);
diff --git a/drivers/net/can/mscan/mpc5xxx_can.c b/drivers/net/can/mscan/mpc5xxx_can.c
index 8af8442c694a..af753936e835 100644
--- a/drivers/net/can/mscan/mpc5xxx_can.c
+++ b/drivers/net/can/mscan/mpc5xxx_can.c
@@ -73,7 +73,7 @@ static u32 __devinit mpc52xx_can_get_clock(struct of_device *ofdev,
else
*mscan_clksrc = MSCAN_CLKSRC_XTAL;
- freq = mpc5xxx_get_bus_frequency(ofdev->node);
+ freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
if (!freq)
return 0;
@@ -152,7 +152,7 @@ static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
}
/* Determine the MSCAN device index from the physical address */
- pval = of_get_property(ofdev->node, "reg", &plen);
+ pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
BUG_ON(!pval || plen < sizeof(*pval));
clockidx = (*pval & 0x80) ? 1 : 0;
if (*pval & 0x2000)
@@ -168,11 +168,11 @@ static u32 __devinit mpc512x_can_get_clock(struct of_device *ofdev,
*/
if (clock_name && !strcmp(clock_name, "ip")) {
*mscan_clksrc = MSCAN_CLKSRC_IPS;
- freq = mpc5xxx_get_bus_frequency(ofdev->node);
+ freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
} else {
*mscan_clksrc = MSCAN_CLKSRC_BUS;
- pval = of_get_property(ofdev->node,
+ pval = of_get_property(ofdev->dev.of_node,
"fsl,mscan-clock-divider", &plen);
if (pval && plen == sizeof(*pval))
clockdiv = *pval;
@@ -251,7 +251,7 @@ static int __devinit mpc5xxx_can_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
struct mpc5xxx_can_data *data = (struct mpc5xxx_can_data *)id->data;
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct net_device *dev;
struct mscan_priv *priv;
void __iomem *base;
diff --git a/drivers/net/can/mscan/mscan.h b/drivers/net/can/mscan/mscan.h
index 4ff966473bc9..b43e9f5d3268 100644
--- a/drivers/net/can/mscan/mscan.h
+++ b/drivers/net/can/mscan/mscan.h
@@ -227,7 +227,7 @@ struct mscan_regs {
u16 time; /* + 0x7c 0x3e */
} tx;
_MSCAN_RESERVED_(32, 2); /* + 0x7e */
-} __attribute__ ((packed));
+} __packed;
#undef _MSCAN_RESERVED_
#define MSCAN_REGION sizeof(struct mscan)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 1fc0871d2ef7..e75f1a876972 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -197,7 +197,7 @@ struct cpc_can_err_counter {
};
/* Main message type used between library and application */
-struct __attribute__ ((packed)) ems_cpc_msg {
+struct __packed ems_cpc_msg {
u8 type; /* type of message */
u8 length; /* length of data within union 'msg' */
u8 msgid; /* confirmation handle */
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index 036b2dfb1d40..092f31a126e6 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -286,7 +286,6 @@ struct board_info {
unsigned int clock_mc3;
unsigned int clock_mc4;
unsigned int espi_nports;
- unsigned int clock_cspi;
unsigned int clock_elmer0;
unsigned char mdio_mdien;
unsigned char mdio_mdiinv;
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c
index 53bde15fc94d..599d178df62d 100644
--- a/drivers/net/chelsio/subr.c
+++ b/drivers/net/chelsio/subr.c
@@ -185,9 +185,6 @@ static int t1_pci_intr_handler(adapter_t *adapter)
return 0;
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
-#include "cspi.h"
-#endif
#ifdef CONFIG_CHELSIO_T1_1G
#include "fpga_defs.h"
@@ -280,7 +277,7 @@ static void mi1_mdio_init(adapter_t *adapter, const struct board_info *bi)
t1_tpi_write(adapter, A_ELMER0_PORT0_MI1_CFG, val);
}
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
/*
* Elmer MI1 MDIO read/write operations.
*/
@@ -317,7 +314,7 @@ static int mi1_mdio_write(struct net_device *dev, int phy_addr, int mmd_addr,
return 0;
}
-#if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR)
+#if defined(CONFIG_CHELSIO_T1_1G)
static const struct mdio_ops mi1_mdio_ops = {
.init = mi1_mdio_init,
.read = mi1_mdio_read,
@@ -752,31 +749,6 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
mod_detect ? "removed" : "inserted");
}
break;
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- case CHBT_BOARD_COUGAR:
- if (adapter->params.nports == 1) {
- if (cause & ELMER0_GP_BIT1) { /* Vitesse MAC */
- struct cmac *mac = adapter->port[0].mac;
- mac->ops->interrupt_handler(mac);
- }
- if (cause & ELMER0_GP_BIT5) { /* XPAK MOD_DETECT */
- }
- } else {
- int i, port_bit;
-
- for_each_port(adapter, i) {
- port_bit = i ? i + 1 : 0;
- if (!(cause & (1 << port_bit)))
- continue;
-
- phy = adapter->port[i].phy;
- phy_cause = phy->ops->interrupt_handler(phy);
- if (phy_cause & cphy_cause_link_change)
- t1_link_changed(adapter, i);
- }
- }
- break;
-#endif
}
t1_tpi_write(adapter, A_ELMER0_INT_CAUSE, cause);
return 0;
@@ -955,7 +927,6 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
case CHBT_BOARD_N110:
case CHBT_BOARD_N210:
case CHBT_BOARD_CHT210:
- case CHBT_BOARD_COUGAR:
t1_tpi_par(adapter, 0xf);
t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
break;
@@ -1004,10 +975,6 @@ int t1_init_hw_modules(adapter_t *adapter)
adapter->regs + A_MC5_CONFIG);
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi && t1_cspi_init(adapter->cspi))
- goto out_err;
-#endif
if (adapter->espi && t1_espi_init(adapter->espi, bi->chip_mac,
bi->espi_nports))
goto out_err;
@@ -1061,10 +1028,6 @@ void t1_free_sw_modules(adapter_t *adapter)
t1_tp_destroy(adapter->tp);
if (adapter->espi)
t1_espi_destroy(adapter->espi);
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (adapter->cspi)
- t1_cspi_destroy(adapter->cspi);
-#endif
}
static void __devinit init_link_config(struct link_config *lc,
@@ -1084,14 +1047,6 @@ static void __devinit init_link_config(struct link_config *lc,
}
}
-#ifdef CONFIG_CHELSIO_T1_COUGAR
- if (bi->clock_cspi && !(adapter->cspi = t1_cspi_create(adapter))) {
- pr_err("%s: CSPI initialization failed\n",
- adapter->name);
- goto error;
- }
-#endif
-
/*
* Allocate and initialize the data structures that hold the SW state of
* the Terminator HW modules.
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index e3f1b8566495..066fd5b09fda 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -2311,15 +2311,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
if (copy_from_user(&t, useraddr, sizeof(t)))
return -EFAULT;
/* Check t.len sanity ? */
- fw_data = kmalloc(t.len, GFP_KERNEL);
- if (!fw_data)
- return -ENOMEM;
-
- if (copy_from_user
- (fw_data, useraddr + sizeof(t), t.len)) {
- kfree(fw_data);
- return -EFAULT;
- }
+ fw_data = memdup_user(useraddr + sizeof(t), t.len);
+ if (IS_ERR(fw_data))
+ return PTR_ERR(fw_data);
ret = t3_load_fw(adapter, fw_data, t.len);
kfree(fw_data);
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index abcc838e18af..4fd6b2b4554b 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -961,7 +961,7 @@ struct dm9000_rxhdr {
u8 RxPktReady;
u8 RxStatus;
__le16 RxLen;
-} __attribute__((__packed__));
+} __packed;
/*
* Received a packet and pass to upper layer
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 24507f3b8b17..57a7e41da69e 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -2554,7 +2554,7 @@ static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
mdef = er32(MDEF(i));
/* Ignore filters with anything other than IPMI ports */
- if (mdef & !(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
+ if (mdef & ~(E1000_MDEF_PORT_623 | E1000_MDEF_PORT_664))
continue;
/* Enable this decision filter in MANC2H */
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
index 882c50c9c34f..f608a6c54af5 100644
--- a/drivers/net/ehea/ehea_qmr.h
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -126,7 +126,7 @@ struct ehea_swqe {
u8 immediate_data[SWQE2_MAX_IMM];
/* 0xd0 */
struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
- } immdata_desc __attribute__ ((packed));
+ } immdata_desc __packed;
/* Send WQE Format 3 */
struct {
diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h
index 85f2a2e7030a..45e86d1e5b1b 100644
--- a/drivers/net/enic/enic.h
+++ b/drivers/net/enic/enic.h
@@ -74,7 +74,14 @@ struct enic_msix_entry {
void *devid;
};
+#define ENIC_SET_APPLIED (1 << 0)
+#define ENIC_SET_REQUEST (1 << 1)
+#define ENIC_SET_NAME (1 << 2)
+#define ENIC_SET_INSTANCE (1 << 3)
+#define ENIC_SET_HOST (1 << 4)
+
struct enic_port_profile {
+ u32 set;
u8 request;
char name[PORT_PROFILE_MAX];
u8 instance_uuid[PORT_UUID_MAX];
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index 6586b5c7e4b6..bc7d6b96de3d 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -1029,8 +1029,7 @@ static int enic_dev_init_done(struct enic *enic, int *done, int *error)
return err;
}
-static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
- char *name, u8 *instance_uuid, u8 *host_uuid)
+static int enic_set_port_profile(struct enic *enic, u8 *mac)
{
struct vic_provinfo *vp;
u8 oui[3] = VIC_PROVINFO_CISCO_OUI;
@@ -1040,97 +1039,112 @@ static int enic_set_port_profile(struct enic *enic, u8 request, u8 *mac,
"%02X%02X-%02X%02X%02X%02X%0X%02X";
int err;
- if (!name)
- return -EINVAL;
+ err = enic_vnic_dev_deinit(enic);
+ if (err)
+ return err;
- if (!is_valid_ether_addr(mac))
- return -EADDRNOTAVAIL;
+ switch (enic->pp.request) {
- vp = vic_provinfo_alloc(GFP_KERNEL, oui, VIC_PROVINFO_LINUX_TYPE);
- if (!vp)
- return -ENOMEM;
+ case PORT_REQUEST_ASSOCIATE:
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
- strlen(name) + 1, name);
-
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
- ETH_ALEN, mac);
-
- if (instance_uuid) {
- uuid = instance_uuid;
- sprintf(uuid_str, uuid_fmt,
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
+ if (!(enic->pp.set & ENIC_SET_NAME) || !strlen(enic->pp.name))
+ return -EINVAL;
- if (host_uuid) {
- uuid = host_uuid;
- sprintf(uuid_str, uuid_fmt,
- uuid[0], uuid[1], uuid[2], uuid[3],
- uuid[4], uuid[5], uuid[6], uuid[7],
- uuid[8], uuid[9], uuid[10], uuid[11],
- uuid[12], uuid[13], uuid[14], uuid[15]);
- vic_provinfo_add_tlv(vp,
- VIC_LINUX_PROV_TLV_HOST_UUID_STR,
- sizeof(uuid_str), uuid_str);
- }
+ if (!is_valid_ether_addr(mac))
+ return -EADDRNOTAVAIL;
- err = enic_vnic_dev_deinit(enic);
- if (err)
- goto err_out;
+ vp = vic_provinfo_alloc(GFP_KERNEL, oui,
+ VIC_PROVINFO_LINUX_TYPE);
+ if (!vp)
+ return -ENOMEM;
- memset(&enic->pp, 0, sizeof(enic->pp));
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_PORT_PROFILE_NAME_STR,
+ strlen(enic->pp.name) + 1, enic->pp.name);
- err = enic_dev_init_prov(enic, vp);
- if (err)
- goto err_out;
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_MAC_ADDR,
+ ETH_ALEN, mac);
+
+ if (enic->pp.set & ENIC_SET_INSTANCE) {
+ uuid = enic->pp.instance_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_CLIENT_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
- enic->pp.request = request;
- memcpy(enic->pp.name, name, PORT_PROFILE_MAX);
- if (instance_uuid)
- memcpy(enic->pp.instance_uuid,
- instance_uuid, PORT_UUID_MAX);
- if (host_uuid)
- memcpy(enic->pp.host_uuid,
- host_uuid, PORT_UUID_MAX);
+ if (enic->pp.set & ENIC_SET_HOST) {
+ uuid = enic->pp.host_uuid;
+ sprintf(uuid_str, uuid_fmt,
+ uuid[0], uuid[1], uuid[2], uuid[3],
+ uuid[4], uuid[5], uuid[6], uuid[7],
+ uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+ vic_provinfo_add_tlv(vp,
+ VIC_LINUX_PROV_TLV_HOST_UUID_STR,
+ sizeof(uuid_str), uuid_str);
+ }
-err_out:
- vic_provinfo_free(vp);
+ err = enic_dev_init_prov(enic, vp);
+ vic_provinfo_free(vp);
+ if (err)
+ return err;
+ break;
- return err;
-}
+ case PORT_REQUEST_DISASSOCIATE:
+ break;
-static int enic_unset_port_profile(struct enic *enic)
-{
- memset(&enic->pp, 0, sizeof(enic->pp));
- return enic_vnic_dev_deinit(enic);
+ default:
+ return -EINVAL;
+ }
+
+ enic->pp.set |= ENIC_SET_APPLIED;
+ return 0;
}
static int enic_set_vf_port(struct net_device *netdev, int vf,
struct nlattr *port[])
{
struct enic *enic = netdev_priv(netdev);
- char *name = NULL;
- u8 *instance_uuid = NULL;
- u8 *host_uuid = NULL;
- u8 request = PORT_REQUEST_DISASSOCIATE;
+
+ memset(&enic->pp, 0, sizeof(enic->pp));
+
+ if (port[IFLA_PORT_REQUEST]) {
+ enic->pp.set |= ENIC_SET_REQUEST;
+ enic->pp.request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ }
+
+ if (port[IFLA_PORT_PROFILE]) {
+ enic->pp.set |= ENIC_SET_NAME;
+ memcpy(enic->pp.name, nla_data(port[IFLA_PORT_PROFILE]),
+ PORT_PROFILE_MAX);
+ }
+
+ if (port[IFLA_PORT_INSTANCE_UUID]) {
+ enic->pp.set |= ENIC_SET_INSTANCE;
+ memcpy(enic->pp.instance_uuid,
+ nla_data(port[IFLA_PORT_INSTANCE_UUID]), PORT_UUID_MAX);
+ }
+
+ if (port[IFLA_PORT_HOST_UUID]) {
+ enic->pp.set |= ENIC_SET_HOST;
+ memcpy(enic->pp.host_uuid,
+ nla_data(port[IFLA_PORT_HOST_UUID]), PORT_UUID_MAX);
+ }
/* don't support VFs, yet */
if (vf != PORT_SELF_VF)
return -EOPNOTSUPP;
- if (port[IFLA_PORT_REQUEST])
- request = nla_get_u8(port[IFLA_PORT_REQUEST]);
+ if (!(enic->pp.set & ENIC_SET_REQUEST))
+ return -EOPNOTSUPP;
- switch (request) {
- case PORT_REQUEST_ASSOCIATE:
+ if (enic->pp.request == PORT_REQUEST_ASSOCIATE) {
/* If the interface mac addr hasn't been assigned,
* assign a random mac addr before setting port-
@@ -1139,30 +1153,9 @@ static int enic_set_vf_port(struct net_device *netdev, int vf,
if (is_zero_ether_addr(netdev->dev_addr))
random_ether_addr(netdev->dev_addr);
-
- if (port[IFLA_PORT_PROFILE])
- name = nla_data(port[IFLA_PORT_PROFILE]);
-
- if (port[IFLA_PORT_INSTANCE_UUID])
- instance_uuid =
- nla_data(port[IFLA_PORT_INSTANCE_UUID]);
-
- if (port[IFLA_PORT_HOST_UUID])
- host_uuid = nla_data(port[IFLA_PORT_HOST_UUID]);
-
- return enic_set_port_profile(enic, request,
- netdev->dev_addr, name,
- instance_uuid, host_uuid);
-
- case PORT_REQUEST_DISASSOCIATE:
-
- return enic_unset_port_profile(enic);
-
- default:
- break;
}
- return -EOPNOTSUPP;
+ return enic_set_port_profile(enic, netdev->dev_addr);
}
static int enic_get_vf_port(struct net_device *netdev, int vf,
@@ -1172,14 +1165,12 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
int err, error, done;
u16 response = PORT_PROFILE_RESPONSE_SUCCESS;
- /* don't support VFs, yet */
- if (vf != PORT_SELF_VF)
- return -EOPNOTSUPP;
+ if (!(enic->pp.set & ENIC_SET_APPLIED))
+ return -ENODATA;
err = enic_dev_init_done(enic, &done, &error);
-
if (err)
- return err;
+ error = err;
switch (error) {
case ERR_SUCCESS:
@@ -1202,12 +1193,15 @@ static int enic_get_vf_port(struct net_device *netdev, int vf,
NLA_PUT_U16(skb, IFLA_PORT_REQUEST, enic->pp.request);
NLA_PUT_U16(skb, IFLA_PORT_RESPONSE, response);
- NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
- enic->pp.name);
- NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
- enic->pp.instance_uuid);
- NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
- enic->pp.host_uuid);
+ if (enic->pp.set & ENIC_SET_NAME)
+ NLA_PUT(skb, IFLA_PORT_PROFILE, PORT_PROFILE_MAX,
+ enic->pp.name);
+ if (enic->pp.set & ENIC_SET_INSTANCE)
+ NLA_PUT(skb, IFLA_PORT_INSTANCE_UUID, PORT_UUID_MAX,
+ enic->pp.instance_uuid);
+ if (enic->pp.set & ENIC_SET_HOST)
+ NLA_PUT(skb, IFLA_PORT_HOST_UUID, PORT_UUID_MAX,
+ enic->pp.host_uuid);
return 0;
diff --git a/drivers/net/enic/vnic_vic.h b/drivers/net/enic/vnic_vic.h
index 085c2a274cb1..7e46e5e8600f 100644
--- a/drivers/net/enic/vnic_vic.h
+++ b/drivers/net/enic/vnic_vic.h
@@ -44,7 +44,7 @@ struct vic_provinfo {
u16 length;
u8 value[0];
} tlv[0];
-} __attribute__ ((packed));
+} __packed;
#define VIC_PROVINFO_MAX_DATA 1385
#define VIC_PROVINFO_MAX_TLV_DATA (VIC_PROVINFO_MAX_DATA - \
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 6838dfc9ef23..4c274657283c 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -87,6 +87,7 @@ static int rx_copybreak;
#include <linux/bitops.h>
#include <asm/io.h>
#include <asm/uaccess.h>
+#include <asm/byteorder.h>
/* These identify the driver base version and may not be removed. */
static char version[] __devinitdata =
@@ -230,7 +231,7 @@ static const u16 media2miictl[16] = {
* The EPIC100 Rx and Tx buffer descriptors. Note that these
* really ARE host-endian; it's not a misannotation. We tell
* the card to byteswap them internally on big-endian hosts -
- * look for #ifdef CONFIG_BIG_ENDIAN in epic_open().
+ * look for #ifdef __BIG_ENDIAN in epic_open().
*/
struct epic_tx_desc {
@@ -690,7 +691,7 @@ static int epic_open(struct net_device *dev)
outl((inl(ioaddr + NVCTL) & ~0x003C) | 0x4800, ioaddr + NVCTL);
/* Tell the chip to byteswap descriptors on big-endian hosts */
-#ifdef CONFIG_BIG_ENDIAN
+#ifdef __BIG_ENDIAN
outl(0x4432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
inl(ioaddr + GENCTL);
outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
@@ -806,7 +807,7 @@ static void epic_restart(struct net_device *dev)
for (i = 16; i > 0; i--)
outl(0x0008, ioaddr + TEST1);
-#ifdef CONFIG_BIG_ENDIAN
+#ifdef __BIG_ENDIAN
outl(0x0432 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
#else
outl(0x0412 | (RX_FIFO_THRESH<<8), ioaddr + GENCTL);
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index ddf7a86cd466..a3cae4ed6ac9 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -210,7 +210,7 @@ static void fec_stop(struct net_device *dev);
/* Transmitter timeout */
#define TX_TIMEOUT (2 * HZ)
-static int
+static netdev_tx_t
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
@@ -679,30 +679,24 @@ static int fec_enet_mii_probe(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct phy_device *phy_dev = NULL;
- int phy_addr;
+ int ret;
fep->phy_dev = NULL;
/* find the first phy */
- for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
- if (fep->mii_bus->phy_map[phy_addr]) {
- phy_dev = fep->mii_bus->phy_map[phy_addr];
- break;
- }
- }
-
+ phy_dev = phy_find_first(fep->mii_bus);
if (!phy_dev) {
printk(KERN_ERR "%s: no PHY found\n", dev->name);
return -ENODEV;
}
/* attach the mac to the phy */
- phy_dev = phy_connect(dev, dev_name(&phy_dev->dev),
+ ret = phy_connect_direct(dev, phy_dev,
&fec_enet_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
- if (IS_ERR(phy_dev)) {
+ if (ret) {
printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
- return PTR_ERR(phy_dev);
+ return ret;
}
/* mask with MAC supported features */
@@ -1365,6 +1359,8 @@ fec_drv_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+
static int
fec_suspend(struct platform_device *dev, pm_message_t state)
{
@@ -1373,10 +1369,9 @@ fec_suspend(struct platform_device *dev, pm_message_t state)
if (ndev) {
fep = netdev_priv(ndev);
- if (netif_running(ndev)) {
- netif_device_detach(ndev);
- fec_stop(ndev);
- }
+ if (netif_running(ndev))
+ fec_enet_close(ndev);
+ clk_disable(fep->clk);
}
return 0;
}
@@ -1385,25 +1380,42 @@ static int
fec_resume(struct platform_device *dev)
{
struct net_device *ndev = platform_get_drvdata(dev);
+ struct fec_enet_private *fep;
if (ndev) {
- if (netif_running(ndev)) {
- fec_enet_init(ndev, 0);
- netif_device_attach(ndev);
- }
+ fep = netdev_priv(ndev);
+ clk_enable(fep->clk);
+ if (netif_running(ndev))
+ fec_enet_open(ndev);
}
return 0;
}
+static const struct dev_pm_ops fec_pm_ops = {
+ .suspend = fec_suspend,
+ .resume = fec_resume,
+ .freeze = fec_suspend,
+ .thaw = fec_resume,
+ .poweroff = fec_suspend,
+ .restore = fec_resume,
+};
+
+#define FEC_PM_OPS (&fec_pm_ops)
+
+#else /* !CONFIG_PM */
+
+#define FEC_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
+
static struct platform_driver fec_driver = {
.driver = {
.name = "fec",
.owner = THIS_MODULE,
+ .pm = FEC_PM_OPS,
},
.probe = fec_probe,
.remove = __devexit_p(fec_drv_remove),
- .suspend = fec_suspend,
- .resume = fec_resume,
};
static int __init
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 006f64d9f96a..dbaf72cbb233 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -29,15 +29,14 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
int reg, u32 value)
{
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
- struct mpc52xx_fec __iomem *fec;
+ struct mpc52xx_fec __iomem *fec = priv->regs;
int tries = 3;
value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK;
value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK;
- fec = priv->regs;
out_be32(&fec->ievent, FEC_IEVENT_MII);
- out_be32(&priv->regs->mii_data, value);
+ out_be32(&fec->mii_data, value);
/* wait for it to finish, this takes about 23 us on lite5200b */
while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries)
@@ -47,7 +46,7 @@ static int mpc52xx_fec_mdio_transfer(struct mii_bus *bus, int phy_id,
return -ETIMEDOUT;
return value & FEC_MII_DATA_OP_RD ?
- in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK : 0;
+ in_be32(&fec->mii_data) & FEC_MII_DATA_DATAMSK : 0;
}
static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg)
@@ -69,9 +68,8 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
struct device_node *np = of->dev.of_node;
struct mii_bus *bus;
struct mpc52xx_fec_mdio_priv *priv;
- struct resource res = {};
+ struct resource res;
int err;
- int i;
bus = mdiobus_alloc();
if (bus == NULL)
@@ -93,7 +91,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
err = of_address_to_resource(np, 0, &res);
if (err)
goto out_free;
- priv->regs = ioremap(res.start, res.end - res.start + 1);
+ priv->regs = ioremap(res.start, resource_size(&res));
if (priv->regs == NULL) {
err = -ENOMEM;
goto out_free;
@@ -118,10 +116,6 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of,
out_unmap:
iounmap(priv->regs);
out_free:
- for (i=0; i<PHY_MAX_ADDR; i++)
- if (bus->irq[i] != PHY_POLL)
- irq_dispose_mapping(bus->irq[i]);
- kfree(bus->irq);
kfree(priv);
mdiobus_free(bus);
@@ -133,23 +127,16 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of)
struct device *dev = &of->dev;
struct mii_bus *bus = dev_get_drvdata(dev);
struct mpc52xx_fec_mdio_priv *priv = bus->priv;
- int i;
mdiobus_unregister(bus);
dev_set_drvdata(dev, NULL);
-
iounmap(priv->regs);
- for (i=0; i<PHY_MAX_ADDR; i++)
- if (bus->irq[i] != PHY_POLL)
- irq_dispose_mapping(bus->irq[i]);
kfree(priv);
- kfree(bus->irq);
mdiobus_free(bus);
return 0;
}
-
static struct of_device_id mpc52xx_fec_mdio_match[] = {
{ .compatible = "fsl,mpc5200b-mdio", },
{ .compatible = "fsl,mpc5200-mdio", },
@@ -171,5 +158,4 @@ struct of_platform_driver mpc52xx_fec_mdio_driver = {
/* let fec driver call it, since this has to be registered before it */
EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver);
-
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 5d45084b287d..48e91b6242ce 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -504,17 +504,54 @@ static int get_regs_len(struct net_device *dev)
}
/* Some transmit errors cause the transmitter to shut
- * down. We now issue a restart transmit. Since the
- * errors close the BD and update the pointers, the restart
- * _should_ pick up without having to reset any of our
- * pointers either. Also, To workaround 8260 device erratum
- * CPM37, we must disable and then re-enable the transmitter
- * following a Late Collision, Underrun, or Retry Limit error.
+ * down. We now issue a restart transmit.
+ * Also, to workaround 8260 device erratum CPM37, we must
+ * disable and then re-enable the transmitterfollowing a
+ * Late Collision, Underrun, or Retry Limit error.
+ * In addition, tbptr may point beyond BDs beyond still marked
+ * as ready due to internal pipelining, so we need to look back
+ * through the BDs and adjust tbptr to point to the last BD
+ * marked as ready. This may result in some buffers being
+ * retransmitted.
*/
static void tx_restart(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
fcc_t __iomem *fccp = fep->fcc.fccp;
+ const struct fs_platform_info *fpi = fep->fpi;
+ fcc_enet_t __iomem *ep = fep->fcc.ep;
+ cbd_t __iomem *curr_tbptr;
+ cbd_t __iomem *recheck_bd;
+ cbd_t __iomem *prev_bd;
+ cbd_t __iomem *last_tx_bd;
+
+ last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t));
+
+ /* get the current bd held in TBPTR and scan back from this point */
+ recheck_bd = curr_tbptr = (cbd_t __iomem *)
+ ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) +
+ fep->ring_base);
+
+ prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1;
+
+ /* Move through the bds in reverse, look for the earliest buffer
+ * that is not ready. Adjust TBPTR to the following buffer */
+ while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) {
+ /* Go back one buffer */
+ recheck_bd = prev_bd;
+
+ /* update the previous buffer */
+ prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1;
+
+ /* We should never see all bds marked as ready, check anyway */
+ if (recheck_bd == curr_tbptr)
+ break;
+ }
+ /* Now update the TBPTR and dirty flag to the current buffer */
+ W32(ep, fen_genfcc.fcc_tbptr,
+ (uint) (((void *)recheck_bd - fep->ring_base) +
+ fep->ring_mem_addr));
+ fep->dirty_tx = recheck_bd;
C32(fccp, fcc_gfmr, FCC_GFMR_ENT);
udelay(10);
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 0f90685d3d19..3607340f3da7 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -169,7 +169,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
new_bus->name = "CPM2 Bitbanged MII",
- ret = fs_mii_bitbang_init(new_bus, ofdev->node);
+ ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node);
if (ret)
goto out_free_bus;
@@ -181,7 +181,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
new_bus->parent = &ofdev->dev;
dev_set_drvdata(&ofdev->dev, new_bus);
- ret = of_mdiobus_register(new_bus, ofdev->node);
+ ret = of_mdiobus_register(new_bus, ofdev->dev.of_node);
if (ret)
goto out_free_irqs;
diff --git a/drivers/net/fsl_pq_mdio.h b/drivers/net/fsl_pq_mdio.h
index 1f7d865cedb6..bd17a2a0139b 100644
--- a/drivers/net/fsl_pq_mdio.h
+++ b/drivers/net/fsl_pq_mdio.h
@@ -39,7 +39,7 @@ struct fsl_pq_mdio {
u8 reserved[28]; /* Space holder */
u32 utbipar; /* TBI phy address reg (only on UCC) */
u8 res4[2728];
-} __attribute__ ((packed));
+} __packed;
int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int fsl_pq_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1830f3199cb5..ab54821f6709 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -681,8 +681,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
priv->rx_queue[i] = NULL;
for (i = 0; i < priv->num_tx_queues; i++) {
- priv->tx_queue[i] = (struct gfar_priv_tx_q *)kzalloc(
- sizeof (struct gfar_priv_tx_q), GFP_KERNEL);
+ priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q),
+ GFP_KERNEL);
if (!priv->tx_queue[i]) {
err = -ENOMEM;
goto tx_alloc_failed;
@@ -694,8 +694,8 @@ static int gfar_of_init(struct of_device *ofdev, struct net_device **pdev)
}
for (i = 0; i < priv->num_rx_queues; i++) {
- priv->rx_queue[i] = (struct gfar_priv_rx_q *)kzalloc(
- sizeof (struct gfar_priv_rx_q), GFP_KERNEL);
+ priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q),
+ GFP_KERNEL);
if (!priv->rx_queue[i]) {
err = -ENOMEM;
goto rx_alloc_failed;
diff --git a/drivers/net/greth.c b/drivers/net/greth.c
index f37a4c143ddd..3a029d02c2b4 100644
--- a/drivers/net/greth.c
+++ b/drivers/net/greth.c
@@ -1607,14 +1607,13 @@ static struct of_device_id greth_of_match[] = {
MODULE_DEVICE_TABLE(of, greth_of_match);
static struct of_platform_driver greth_of_driver = {
- .name = "grlib-greth",
- .match_table = greth_of_match,
+ .driver = {
+ .name = "grlib-greth",
+ .owner = THIS_MODULE,
+ .of_match_table = greth_of_match,
+ },
.probe = greth_of_probe,
.remove = __devexit_p(greth_of_remove),
- .driver = {
- .owner = THIS_MODULE,
- .name = "grlib-greth",
- },
};
static int __init greth_init(void)
diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h
index 0dbd1932b72f..36c3060411d2 100644
--- a/drivers/net/irda/donauboe.h
+++ b/drivers/net/irda/donauboe.h
@@ -273,7 +273,7 @@ struct OboeSlot
__u8 control; /*Slot control/status see below */
__u32 address; /*Slot buffer address */
}
-__attribute__ ((packed));
+__packed;
#define OBOE_NTASKS OBOE_TXRING_OFFSET_IN_SLOTS
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 4441fa3389c2..e4e71f32746b 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -1124,11 +1124,12 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
* The actual image starts after the "STMP" keyword
* so forward to the firmware header tag
*/
- for (i = 0; (fw->data[i] != STIR421X_PATCH_END_OF_HDR_TAG) &&
- (i < fw->size); i++) ;
+ for (i = 0; i < fw->size && fw->data[i] !=
+ STIR421X_PATCH_END_OF_HDR_TAG; i++)
+ ;
/* here we check for the out of buffer case */
- if ((STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) &&
- (i < STIR421X_PATCH_CODE_OFFSET)) {
+ if (i < STIR421X_PATCH_CODE_OFFSET && i < fw->size &&
+ STIR421X_PATCH_END_OF_HDR_TAG == fw->data[i]) {
if (!memcmp(fw->data + i + 1, STIR421X_PATCH_STMP_TAG,
sizeof(STIR421X_PATCH_STMP_TAG) - 1)) {
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index ac0443d52e50..58ddb5214916 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -125,7 +125,7 @@ struct irda_class_desc {
__u8 bmAdditionalBOFs;
__u8 bIrdaRateSniff;
__u8 bMaxUnicastList;
-} __attribute__ ((packed));
+} __packed;
/* class specific interface request to get the IrDA-USB class descriptor
* (6.2.5, USB-IrDA class spec 1.0) */
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index b54d3b48045e..1046014dd6c2 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -154,7 +154,7 @@ struct ks959_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c
index 8d713ebac15b..9cc142fcc712 100644
--- a/drivers/net/irda/ksdazzle-sir.c
+++ b/drivers/net/irda/ksdazzle-sir.c
@@ -117,7 +117,7 @@ struct ksdazzle_speedparams {
__le32 baudrate; /* baud rate, little endian */
__u8 flags;
__u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define KS_DATA_5_BITS 0x00
#define KS_DATA_6_BITS 0x01
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index 3050d1a0cccf..3f24a1f33022 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -544,9 +544,9 @@ struct ring_descr_hw {
struct {
u8 addr_res[3];
volatile u8 status; /* descriptor status */
- } __attribute__((packed)) rd_s;
- } __attribute((packed)) rd_u;
-} __attribute__ ((packed));
+ } __packed rd_s;
+ } __packed rd_u;
+} __packed;
#define rd_addr rd_u.addr
#define rd_status rd_u.rd_s.status
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index ffae480587ae..9270089eb282 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -44,11 +44,9 @@
#include <linux/dca.h>
#endif
-#define PFX "ixgbe: "
-#define DPRINTK(nlevel, klevel, fmt, args...) \
- ((void)((NETIF_MSG_##nlevel & adapter->msg_enable) && \
- printk(KERN_##klevel PFX "%s: %s: " fmt, adapter->netdev->name, \
- __func__ , ## args)))
+/* common prefix used by pr_<> macros */
+#undef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/* TX/RX descriptor defines */
#define IXGBE_DEFAULT_TXD 512
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
index a4e2901f2f08..976fd9e146c6 100644
--- a/drivers/net/ixgbe/ixgbe_82599.c
+++ b/drivers/net/ixgbe/ixgbe_82599.c
@@ -707,9 +707,8 @@ static s32 ixgbe_setup_mac_link_smartspeed(struct ixgbe_hw *hw,
out:
if (link_up && (link_speed == IXGBE_LINK_SPEED_1GB_FULL))
- netif_info(adapter, hw, adapter->netdev, "Smartspeed has"
- " downgraded the link speed from the maximum"
- " advertised\n");
+ e_info("Smartspeed has downgraded the link speed from "
+ "the maximum advertised\n");
return status;
}
diff --git a/drivers/net/ixgbe/ixgbe_common.c b/drivers/net/ixgbe/ixgbe_common.c
index 1159d9138f05..9595b1bfb8dd 100644
--- a/drivers/net/ixgbe/ixgbe_common.c
+++ b/drivers/net/ixgbe/ixgbe_common.c
@@ -1188,6 +1188,7 @@ s32 ixgbe_set_rar_generic(struct ixgbe_hw *hw, u32 index, u8 *addr, u32 vmdq,
IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
} else {
hw_dbg(hw, "RAR index %d is out of range.\n", index);
+ return IXGBE_ERR_RAR_INDEX;
}
return 0;
@@ -1219,6 +1220,7 @@ s32 ixgbe_clear_rar_generic(struct ixgbe_hw *hw, u32 index)
IXGBE_WRITE_REG(hw, IXGBE_RAH(index), rar_high);
} else {
hw_dbg(hw, "RAR index %d is out of range.\n", index);
+ return IXGBE_ERR_RAR_INDEX;
}
/* clear VMDq pool/queue selection for this RAR */
diff --git a/drivers/net/ixgbe/ixgbe_common.h b/drivers/net/ixgbe/ixgbe_common.h
index 3080afb12bdf..d5d3aae8524b 100644
--- a/drivers/net/ixgbe/ixgbe_common.h
+++ b/drivers/net/ixgbe/ixgbe_common.h
@@ -105,12 +105,26 @@ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index);
#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS)
-#ifdef DEBUG
-extern char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw);
+extern struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw);
#define hw_dbg(hw, format, arg...) \
- printk(KERN_DEBUG "%s: " format, ixgbe_get_hw_dev_name(hw), ##arg)
-#else
-#define hw_dbg(hw, format, arg...) do {} while (0)
-#endif
+ netdev_dbg(ixgbe_get_hw_dev(hw), format, ##arg)
+#define e_err(format, arg...) \
+ netdev_err(adapter->netdev, format, ## arg)
+#define e_info(format, arg...) \
+ netdev_info(adapter->netdev, format, ## arg)
+#define e_warn(format, arg...) \
+ netdev_warn(adapter->netdev, format, ## arg)
+#define e_notice(format, arg...) \
+ netdev_notice(adapter->netdev, format, ## arg)
+#define e_crit(format, arg...) \
+ netdev_crit(adapter->netdev, format, ## arg)
+#define e_dev_info(format, arg...) \
+ dev_info(&adapter->pdev->dev, format, ## arg)
+#define e_dev_warn(format, arg...) \
+ dev_warn(&adapter->pdev->dev, format, ## arg)
+#define e_dev_err(format, arg...) \
+ dev_err(&adapter->pdev->dev, format, ## arg)
+#define e_dev_notice(format, arg...) \
+ dev_notice(&adapter->pdev->dev, format, ## arg)
#endif /* IXGBE_COMMON */
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c
index 71da325dfa80..657623589d53 100644
--- a/drivers/net/ixgbe/ixgbe_dcb_nl.c
+++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c
@@ -121,7 +121,7 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
goto out;
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) {
- DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n");
+ e_err("Enable failed, needs MSI-X\n");
err = 1;
goto out;
}
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c
index c50a7541ffec..644e3d21b751 100644
--- a/drivers/net/ixgbe/ixgbe_ethtool.c
+++ b/drivers/net/ixgbe/ixgbe_ethtool.c
@@ -294,8 +294,7 @@ static int ixgbe_set_settings(struct net_device *netdev,
hw->mac.autotry_restart = true;
err = hw->mac.ops.setup_link(hw, advertised, true, true);
if (err) {
- DPRINTK(PROBE, INFO,
- "setup link failed with code %d\n", err);
+ e_info("setup link failed with code %d\n", err);
hw->mac.ops.setup_link(hw, old, true, true);
}
} else {
@@ -1188,9 +1187,9 @@ static struct ixgbe_reg_test reg_test_82598[] = {
writel((_test[pat] & W), (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
if (val != (_test[pat] & W & M)) { \
- DPRINTK(DRV, ERR, "pattern test reg %04X failed: got "\
- "0x%08X expected 0x%08X\n", \
- R, val, (_test[pat] & W & M)); \
+ e_err("pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ R, val, (_test[pat] & W & M)); \
*data = R; \
writel(before, adapter->hw.hw_addr + R); \
return 1; \
@@ -1206,8 +1205,8 @@ static struct ixgbe_reg_test reg_test_82598[] = {
writel((W & M), (adapter->hw.hw_addr + R)); \
val = readl(adapter->hw.hw_addr + R); \
if ((W & M) != (val & M)) { \
- DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
- "expected 0x%08X\n", R, (val & M), (W & M)); \
+ e_err("set/check reg %04X test failed: got 0x%08X " \
+ "expected 0x%08X\n", R, (val & M), (W & M)); \
*data = R; \
writel(before, (adapter->hw.hw_addr + R)); \
return 1; \
@@ -1240,8 +1239,8 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle);
after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle;
if (value != after) {
- DPRINTK(DRV, ERR, "failed STATUS register test got: "
- "0x%08X expected: 0x%08X\n", after, value);
+ e_err("failed STATUS register test got: 0x%08X expected: "
+ "0x%08X\n", after, value);
*data = 1;
return 1;
}
@@ -1341,8 +1340,8 @@ static int ixgbe_intr_test(struct ixgbe_adapter *adapter, u64 *data)
*data = 1;
return -1;
}
- DPRINTK(HW, INFO, "testing %s interrupt\n",
- (shared_int ? "shared" : "unshared"));
+ e_info("testing %s interrupt\n", shared_int ?
+ "shared" : "unshared");
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
@@ -1847,7 +1846,7 @@ static void ixgbe_diag_test(struct net_device *netdev,
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
- DPRINTK(HW, INFO, "offline testing starting\n");
+ e_info("offline testing starting\n");
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
@@ -1880,17 +1879,17 @@ static void ixgbe_diag_test(struct net_device *netdev,
else
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "register testing starting\n");
+ e_info("register testing starting\n");
if (ixgbe_reg_test(adapter, &data[0]))
eth_test->flags |= ETH_TEST_FL_FAILED;
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "eeprom testing starting\n");
+ e_info("eeprom testing starting\n");
if (ixgbe_eeprom_test(adapter, &data[1]))
eth_test->flags |= ETH_TEST_FL_FAILED;
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "interrupt testing starting\n");
+ e_info("interrupt testing starting\n");
if (ixgbe_intr_test(adapter, &data[2]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1898,14 +1897,13 @@ static void ixgbe_diag_test(struct net_device *netdev,
* loopback diagnostic. */
if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
IXGBE_FLAG_VMDQ_ENABLED)) {
- DPRINTK(HW, INFO, "Skip MAC loopback diagnostic in VT "
- "mode\n");
+ e_info("Skip MAC loopback diagnostic in VT mode\n");
data[3] = 0;
goto skip_loopback;
}
ixgbe_reset(adapter);
- DPRINTK(HW, INFO, "loopback testing starting\n");
+ e_info("loopback testing starting\n");
if (ixgbe_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1916,7 +1914,7 @@ skip_loopback:
if (if_running)
dev_open(netdev);
} else {
- DPRINTK(HW, INFO, "online testing starting\n");
+ e_info("online testing starting\n");
/* Online tests */
if (ixgbe_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -2089,8 +2087,8 @@ static bool ixgbe_reenable_rsc(struct ixgbe_adapter *adapter,
(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE)) {
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
adapter->netdev->features |= NETIF_F_LRO;
- DPRINTK(PROBE, INFO, "rx-usecs set to %d, re-enabling RSC\n",
- ec->rx_coalesce_usecs);
+ e_info("rx-usecs set to %d, re-enabling RSC\n",
+ ec->rx_coalesce_usecs);
return true;
}
return false;
@@ -2158,8 +2156,7 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
netdev->features &= ~NETIF_F_LRO;
- DPRINTK(PROBE, INFO,
- "rx-usecs set to 0, disabling RSC\n");
+ e_info("rx-usecs set to 0, disabling RSC\n");
need_reset = true;
}
diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c
index 45182ab41d6b..84e1194e0833 100644
--- a/drivers/net/ixgbe/ixgbe_fcoe.c
+++ b/drivers/net/ixgbe/ixgbe_fcoe.c
@@ -25,7 +25,6 @@
*******************************************************************************/
-
#include "ixgbe.h"
#ifdef CONFIG_IXGBE_DCB
#include "ixgbe_dcb_82599.h"
@@ -165,20 +164,20 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
adapter = netdev_priv(netdev);
if (xid >= IXGBE_FCOE_DDP_MAX) {
- DPRINTK(DRV, WARNING, "xid=0x%x out-of-range\n", xid);
+ e_warn("xid=0x%x out-of-range\n", xid);
return 0;
}
fcoe = &adapter->fcoe;
if (!fcoe->pool) {
- DPRINTK(DRV, WARNING, "xid=0x%x no ddp pool for fcoe\n", xid);
+ e_warn("xid=0x%x no ddp pool for fcoe\n", xid);
return 0;
}
ddp = &fcoe->ddp[xid];
if (ddp->sgl) {
- DPRINTK(DRV, ERR, "xid 0x%x w/ non-null sgl=%p nents=%d\n",
- xid, ddp->sgl, ddp->sgc);
+ e_err("xid 0x%x w/ non-null sgl=%p nents=%d\n",
+ xid, ddp->sgl, ddp->sgc);
return 0;
}
ixgbe_fcoe_clear_ddp(ddp);
@@ -186,14 +185,14 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
/* setup dma from scsi command sgl */
dmacount = pci_map_sg(adapter->pdev, sgl, sgc, DMA_FROM_DEVICE);
if (dmacount == 0) {
- DPRINTK(DRV, ERR, "xid 0x%x DMA map error\n", xid);
+ e_err("xid 0x%x DMA map error\n", xid);
return 0;
}
/* alloc the udl from our ddp pool */
ddp->udl = pci_pool_alloc(fcoe->pool, GFP_KERNEL, &ddp->udp);
if (!ddp->udl) {
- DPRINTK(DRV, ERR, "failed allocated ddp context\n");
+ e_err("failed allocated ddp context\n");
goto out_noddp_unmap;
}
ddp->sgl = sgl;
@@ -206,10 +205,9 @@ int ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid,
while (len) {
/* max number of buffers allowed in one DDP context */
if (j >= IXGBE_BUFFCNT_MAX) {
- netif_err(adapter, drv, adapter->netdev,
- "xid=%x:%d,%d,%d:addr=%llx "
- "not enough descriptors\n",
- xid, i, j, dmacount, (u64)addr);
+ e_err("xid=%x:%d,%d,%d:addr=%llx "
+ "not enough descriptors\n",
+ xid, i, j, dmacount, (u64)addr);
goto out_noddp_free;
}
@@ -387,8 +385,8 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
struct fc_frame_header *fh;
if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) {
- DPRINTK(DRV, ERR, "Wrong gso type %d:expecting SKB_GSO_FCOE\n",
- skb_shinfo(skb)->gso_type);
+ e_err("Wrong gso type %d:expecting SKB_GSO_FCOE\n",
+ skb_shinfo(skb)->gso_type);
return -EINVAL;
}
@@ -414,7 +412,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_SOF;
break;
default:
- DPRINTK(DRV, WARNING, "unknown sof = 0x%x\n", sof);
+ e_warn("unknown sof = 0x%x\n", sof);
return -EINVAL;
}
@@ -441,7 +439,7 @@ int ixgbe_fso(struct ixgbe_adapter *adapter,
fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A;
break;
default:
- DPRINTK(DRV, WARNING, "unknown eof = 0x%x\n", eof);
+ e_warn("unknown eof = 0x%x\n", eof);
return -EINVAL;
}
@@ -517,8 +515,7 @@ void ixgbe_configure_fcoe(struct ixgbe_adapter *adapter)
adapter->pdev, IXGBE_FCPTR_MAX,
IXGBE_FCPTR_ALIGN, PAGE_SIZE);
if (!fcoe->pool)
- DPRINTK(DRV, ERR,
- "failed to allocated FCoE DDP pool\n");
+ e_err("failed to allocated FCoE DDP pool\n");
spin_lock_init(&fcoe->lock);
}
@@ -614,7 +611,7 @@ int ixgbe_fcoe_enable(struct net_device *netdev)
if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED)
goto out_enable;
- DPRINTK(DRV, INFO, "Enabling FCoE offload features.\n");
+ e_info("Enabling FCoE offload features.\n");
if (netif_running(netdev))
netdev->netdev_ops->ndo_stop(netdev);
@@ -660,7 +657,7 @@ int ixgbe_fcoe_disable(struct net_device *netdev)
if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED))
goto out_disable;
- DPRINTK(DRV, INFO, "Disabling FCoE offload features.\n");
+ e_info("Disabling FCoE offload features.\n");
if (netif_running(netdev))
netdev->netdev_ops->ndo_stop(netdev);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index d571d101de08..6b483d352f23 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -642,7 +642,7 @@ static inline bool ixgbe_tx_xon_state(struct ixgbe_adapter *adapter,
u32 txoff = IXGBE_TFCS_TXOFF;
#ifdef CONFIG_IXGBE_DCB
- if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
+ if (adapter->dcb_cfg.pfc_mode_enable) {
int tc;
int reg_idx = tx_ring->reg_idx;
int dcb_i = adapter->ring_feature[RING_F_DCB].indices;
@@ -696,19 +696,19 @@ static inline bool ixgbe_check_tx_hang(struct ixgbe_adapter *adapter,
/* detected Tx unit hang */
union ixgbe_adv_tx_desc *tx_desc;
tx_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
- DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
- " Tx Queue <%d>\n"
- " TDH, TDT <%x>, <%x>\n"
- " next_to_use <%x>\n"
- " next_to_clean <%x>\n"
- "tx_buffer_info[next_to_clean]\n"
- " time_stamp <%lx>\n"
- " jiffies <%lx>\n",
- tx_ring->queue_index,
- IXGBE_READ_REG(hw, tx_ring->head),
- IXGBE_READ_REG(hw, tx_ring->tail),
- tx_ring->next_to_use, eop,
- tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
+ e_err("Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ IXGBE_READ_REG(hw, tx_ring->head),
+ IXGBE_READ_REG(hw, tx_ring->tail),
+ tx_ring->next_to_use, eop,
+ tx_ring->tx_buffer_info[eop].time_stamp, jiffies);
return true;
}
@@ -812,9 +812,8 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_q_vector *q_vector,
if (adapter->detect_tx_hung) {
if (ixgbe_check_tx_hang(adapter, tx_ring, i)) {
/* schedule immediate reset if we believe we hung */
- DPRINTK(PROBE, INFO,
- "tx hang %d detected, resetting adapter\n",
- adapter->tx_timeout_count + 1);
+ e_info("tx hang %d detected, resetting adapter\n",
+ adapter->tx_timeout_count + 1);
ixgbe_tx_timeout(adapter->netdev);
}
}
@@ -1653,10 +1652,10 @@ static void ixgbe_check_overtemp_task(struct work_struct *work)
return;
break;
}
- DPRINTK(DRV, ERR, "Network adapter has been stopped because it "
- "has over heated. Restart the computer. If the problem "
- "persists, power off the system and replace the "
- "adapter\n");
+ e_crit("Network adapter has been stopped because it "
+ "has over heated. Restart the computer. If the problem "
+ "persists, power off the system and replace the "
+ "adapter\n");
/* write to clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0);
}
@@ -1668,7 +1667,7 @@ static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) &&
(eicr & IXGBE_EICR_GPI_SDP1)) {
- DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n");
+ e_crit("Fan has stopped, replace the adapter\n");
/* write to clear the interrupt */
IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
}
@@ -2154,9 +2153,8 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
handler, 0, adapter->name[vector],
adapter->q_vector[vector]);
if (err) {
- DPRINTK(PROBE, ERR,
- "request_irq failed for MSIX interrupt "
- "Error: %d\n", err);
+ e_err("request_irq failed for MSIX interrupt: "
+ "Error: %d\n", err);
goto free_queue_irqs;
}
}
@@ -2165,8 +2163,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter)
err = request_irq(adapter->msix_entries[vector].vector,
ixgbe_msix_lsc, 0, adapter->name[vector], netdev);
if (err) {
- DPRINTK(PROBE, ERR,
- "request_irq for msix_lsc failed: %d\n", err);
+ e_err("request_irq for msix_lsc failed: %d\n", err);
goto free_queue_irqs;
}
@@ -2352,7 +2349,7 @@ static int ixgbe_request_irq(struct ixgbe_adapter *adapter)
}
if (err)
- DPRINTK(PROBE, ERR, "request_irq failed, Error %d\n", err);
+ e_err("request_irq failed, Error %d\n", err);
return err;
}
@@ -2423,7 +2420,7 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
map_vector_to_rxq(adapter, 0, 0);
map_vector_to_txq(adapter, 0, 0);
- DPRINTK(HW, INFO, "Legacy interrupt IVAR setup done\n");
+ e_info("Legacy interrupt IVAR setup done\n");
}
/**
@@ -3257,8 +3254,8 @@ static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
msleep(1);
}
if (k >= IXGBE_MAX_RX_DESC_POLL) {
- DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
- "not set within the polling period\n", rxr);
+ e_err("RXDCTL.ENABLE on Rx queue %d not set within "
+ "the polling period\n", rxr);
}
ixgbe_release_rx_desc(&adapter->hw, adapter->rx_ring[rxr],
(adapter->rx_ring[rxr]->count - 1));
@@ -3387,8 +3384,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
} while (--wait_loop &&
!(txdctl & IXGBE_TXDCTL_ENABLE));
if (!wait_loop)
- DPRINTK(DRV, ERR, "Could not enable "
- "Tx Queue %d\n", j);
+ e_err("Could not enable Tx Queue %d\n", j);
}
}
@@ -3436,8 +3432,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (esdp & IXGBE_ESDP_SDP1)
- DPRINTK(DRV, CRIT,
- "Fan has stopped, replace the adapter\n");
+ e_crit("Fan has stopped, replace the adapter\n");
}
/*
@@ -3466,7 +3461,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
} else {
err = ixgbe_non_sfp_link_config(hw);
if (err)
- DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
+ e_err("link_config FAILED %d\n", err);
}
for (i = 0; i < adapter->num_tx_queues; i++)
@@ -3527,19 +3522,19 @@ void ixgbe_reset(struct ixgbe_adapter *adapter)
case IXGBE_ERR_SFP_NOT_PRESENT:
break;
case IXGBE_ERR_MASTER_REQUESTS_PENDING:
- dev_err(&adapter->pdev->dev, "master disable timed out\n");
+ e_dev_err("master disable timed out\n");
break;
case IXGBE_ERR_EEPROM_VERSION:
/* We are running on a pre-production device, log a warning */
- dev_warn(&adapter->pdev->dev, "This device is a pre-production "
- "adapter/LOM. Please be aware there may be issues "
- "associated with your hardware. If you are "
- "experiencing problems please contact your Intel or "
- "hardware representative who provided you with this "
- "hardware.\n");
+ e_dev_warn("This device is a pre-production adapter/LOM. "
+ "Please be aware there may be issuesassociated with "
+ "your hardware. If you are experiencing problems "
+ "please contact your Intel or hardware "
+ "representative who provided you with this "
+ "hardware.\n");
break;
default:
- dev_err(&adapter->pdev->dev, "Hardware Error: %d\n", err);
+ e_dev_err("Hardware Error: %d\n", err);
}
/* reprogram the RAR[0] in case user changed it. */
@@ -3920,12 +3915,12 @@ static inline bool ixgbe_set_fcoe_queues(struct ixgbe_adapter *adapter)
adapter->num_tx_queues = 1;
#ifdef CONFIG_IXGBE_DCB
if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) {
- DPRINTK(PROBE, INFO, "FCoE enabled with DCB\n");
+ e_info("FCoE enabled with DCB\n");
ixgbe_set_dcb_queues(adapter);
}
#endif
if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
- DPRINTK(PROBE, INFO, "FCoE enabled with RSS\n");
+ e_info("FCoE enabled with RSS\n");
if ((adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE) ||
(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE))
ixgbe_set_fdir_queues(adapter);
@@ -4038,7 +4033,8 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter,
* This just means we'll go with either a single MSI
* vector or fall back to legacy interrupts.
*/
- DPRINTK(HW, DEBUG, "Unable to allocate MSI-X interrupts\n");
+ netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+ "Unable to allocate MSI-X interrupts\n");
adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED;
kfree(adapter->msix_entries);
adapter->msix_entries = NULL;
@@ -4435,8 +4431,9 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter)
if (!err) {
adapter->flags |= IXGBE_FLAG_MSI_ENABLED;
} else {
- DPRINTK(HW, DEBUG, "Unable to allocate MSI interrupt, "
- "falling back to legacy. Error: %d\n", err);
+ netif_printk(adapter, hw, KERN_DEBUG, adapter->netdev,
+ "Unable to allocate MSI interrupt, "
+ "falling back to legacy. Error: %d\n", err);
/* reset err */
err = 0;
}
@@ -4557,27 +4554,25 @@ int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter)
err = ixgbe_set_interrupt_capability(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to setup interrupt capabilities\n");
+ e_dev_err("Unable to setup interrupt capabilities\n");
goto err_set_interrupt;
}
err = ixgbe_alloc_q_vectors(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to allocate memory for queue "
- "vectors\n");
+ e_dev_err("Unable to allocate memory for queue vectors\n");
goto err_alloc_q_vectors;
}
err = ixgbe_alloc_queues(adapter);
if (err) {
- DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n");
+ e_dev_err("Unable to allocate memory for queues\n");
goto err_alloc_queues;
}
- DPRINTK(DRV, INFO, "Multiqueue %s: Rx Queue count = %u, "
- "Tx Queue count = %u\n",
- (adapter->num_rx_queues > 1) ? "Enabled" :
- "Disabled", adapter->num_rx_queues, adapter->num_tx_queues);
+ e_dev_info("Multiqueue %s: Rx Queue count = %u, Tx Queue count = %u\n",
+ (adapter->num_rx_queues > 1) ? "Enabled" : "Disabled",
+ adapter->num_rx_queues, adapter->num_tx_queues);
set_bit(__IXGBE_DOWN, &adapter->state);
@@ -4648,15 +4643,13 @@ static void ixgbe_sfp_task(struct work_struct *work)
goto reschedule;
ret = hw->phy.ops.reset(hw);
if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize "
- "because an unsupported SFP+ module type "
- "was detected.\n"
- "Reload the driver after installing a "
- "supported module.\n");
+ e_dev_err("failed to initialize because an unsupported "
+ "SFP+ module type was detected.\n");
+ e_dev_err("Reload the driver after installing a "
+ "supported module.\n");
unregister_netdev(adapter->netdev);
} else {
- DPRINTK(PROBE, INFO, "detected SFP+: %d\n",
- hw->phy.sfp_type);
+ e_info("detected SFP+: %d\n", hw->phy.sfp_type);
}
/* don't need this routine any more */
clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
@@ -4783,7 +4776,7 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
/* initialize eeprom parameters */
if (ixgbe_init_eeprom_params_generic(hw)) {
- dev_err(&pdev->dev, "EEPROM initialization failed\n");
+ e_dev_err("EEPROM initialization failed\n");
return -EIO;
}
@@ -4836,8 +4829,7 @@ int ixgbe_setup_tx_resources(struct ixgbe_adapter *adapter,
err:
vfree(tx_ring->tx_buffer_info);
tx_ring->tx_buffer_info = NULL;
- DPRINTK(PROBE, ERR, "Unable to allocate memory for the transmit "
- "descriptor ring\n");
+ e_err("Unable to allocate memory for the Tx descriptor ring\n");
return -ENOMEM;
}
@@ -4859,7 +4851,7 @@ static int ixgbe_setup_all_tx_resources(struct ixgbe_adapter *adapter)
err = ixgbe_setup_tx_resources(adapter, adapter->tx_ring[i]);
if (!err)
continue;
- DPRINTK(PROBE, ERR, "Allocation for Tx Queue %u failed\n", i);
+ e_err("Allocation for Tx Queue %u failed\n", i);
break;
}
@@ -4884,8 +4876,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
if (!rx_ring->rx_buffer_info)
rx_ring->rx_buffer_info = vmalloc(size);
if (!rx_ring->rx_buffer_info) {
- DPRINTK(PROBE, ERR,
- "vmalloc allocation failed for the rx desc ring\n");
+ e_err("vmalloc allocation failed for the Rx desc ring\n");
goto alloc_failed;
}
memset(rx_ring->rx_buffer_info, 0, size);
@@ -4898,8 +4889,7 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
&rx_ring->dma, GFP_KERNEL);
if (!rx_ring->desc) {
- DPRINTK(PROBE, ERR,
- "Memory allocation failed for the rx desc ring\n");
+ e_err("Memory allocation failed for the Rx desc ring\n");
vfree(rx_ring->rx_buffer_info);
goto alloc_failed;
}
@@ -4932,7 +4922,7 @@ static int ixgbe_setup_all_rx_resources(struct ixgbe_adapter *adapter)
err = ixgbe_setup_rx_resources(adapter, adapter->rx_ring[i]);
if (!err)
continue;
- DPRINTK(PROBE, ERR, "Allocation for Rx Queue %u failed\n", i);
+ e_err("Allocation for Rx Queue %u failed\n", i);
break;
}
@@ -5031,8 +5021,7 @@ static int ixgbe_change_mtu(struct net_device *netdev, int new_mtu)
if ((new_mtu < 68) || (max_frame > IXGBE_MAX_JUMBO_FRAME_SIZE))
return -EINVAL;
- DPRINTK(PROBE, INFO, "changing MTU from %d to %d\n",
- netdev->mtu, new_mtu);
+ e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu);
/* must set new MTU before calling down or up */
netdev->mtu = new_mtu;
@@ -5145,8 +5134,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
err = pci_enable_device_mem(pdev);
if (err) {
- printk(KERN_ERR "ixgbe: Cannot enable PCI device from "
- "suspend\n");
+ e_dev_err("Cannot enable PCI device from suspend\n");
return err;
}
pci_set_master(pdev);
@@ -5155,8 +5143,7 @@ static int ixgbe_resume(struct pci_dev *pdev)
err = ixgbe_init_interrupt_scheme(adapter);
if (err) {
- printk(KERN_ERR "ixgbe: Cannot initialize interrupts for "
- "device\n");
+ e_dev_err("Cannot initialize interrupts for device\n");
return err;
}
@@ -5512,10 +5499,10 @@ static void ixgbe_sfp_config_module_task(struct work_struct *work)
err = hw->phy.ops.identify_sfp(hw);
if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize because "
- "an unsupported SFP+ module type was detected.\n"
- "Reload the driver after installing a supported "
- "module.\n");
+ e_dev_err("failed to initialize because an unsupported SFP+ "
+ "module type was detected.\n");
+ e_dev_err("Reload the driver after installing a supported "
+ "module.\n");
unregister_netdev(adapter->netdev);
return;
}
@@ -5544,8 +5531,8 @@ static void ixgbe_fdir_reinit_task(struct work_struct *work)
set_bit(__IXGBE_FDIR_INIT_DONE,
&(adapter->tx_ring[i]->reinit_state));
} else {
- DPRINTK(PROBE, ERR, "failed to finish FDIR re-initialization, "
- "ignored adding FDIR ATR filters\n");
+ e_err("failed to finish FDIR re-initialization, "
+ "ignored adding FDIR ATR filters\n");
}
/* Done FDIR Re-initialization, enable transmits */
netif_tx_start_all_queues(adapter->netdev);
@@ -5616,16 +5603,14 @@ static void ixgbe_watchdog_task(struct work_struct *work)
flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X);
}
- printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
- "Flow Control: %s\n",
- netdev->name,
+ e_info("NIC Link is Up %s, Flow Control: %s\n",
(link_speed == IXGBE_LINK_SPEED_10GB_FULL ?
- "10 Gbps" :
- (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
- "1 Gbps" : "unknown speed")),
+ "10 Gbps" :
+ (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
+ "1 Gbps" : "unknown speed")),
((flow_rx && flow_tx) ? "RX/TX" :
- (flow_rx ? "RX" :
- (flow_tx ? "TX" : "None"))));
+ (flow_rx ? "RX" :
+ (flow_tx ? "TX" : "None"))));
netif_carrier_on(netdev);
} else {
@@ -5636,8 +5621,7 @@ static void ixgbe_watchdog_task(struct work_struct *work)
adapter->link_up = false;
adapter->link_speed = 0;
if (netif_carrier_ok(netdev)) {
- printk(KERN_INFO "ixgbe: %s NIC Link is Down\n",
- netdev->name);
+ e_info("NIC Link is Down\n");
netif_carrier_off(netdev);
}
}
@@ -5813,9 +5797,8 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter,
break;
default:
if (unlikely(net_ratelimit())) {
- DPRINTK(PROBE, WARNING,
- "partial checksum but proto=%x!\n",
- skb->protocol);
+ e_warn("partial checksum but "
+ "proto=%x!\n", skb->protocol);
}
break;
}
@@ -5926,7 +5909,7 @@ static int ixgbe_tx_map(struct ixgbe_adapter *adapter,
return count;
dma_error:
- dev_err(&pdev->dev, "TX DMA map failed\n");
+ e_dev_err("TX DMA map failed\n");
/* clear timestamp and dma mappings for failed tx_buffer_info map */
tx_buffer_info->dma = 0;
@@ -6423,8 +6406,7 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
adapter->flags |= IXGBE_FLAG_SRIOV_ENABLED;
err = pci_enable_sriov(adapter->pdev, adapter->num_vfs);
if (err) {
- DPRINTK(PROBE, ERR,
- "Failed to enable PCI sriov: %d\n", err);
+ e_err("Failed to enable PCI sriov: %d\n", err);
goto err_novfs;
}
/* If call to enable VFs succeeded then allocate memory
@@ -6448,9 +6430,8 @@ static void __devinit ixgbe_probe_vf(struct ixgbe_adapter *adapter,
}
/* Oh oh */
- DPRINTK(PROBE, ERR,
- "Unable to allocate memory for VF "
- "Data Storage - SRIOV disabled\n");
+ e_err("Unable to allocate memory for VF Data Storage - SRIOV "
+ "disabled\n");
pci_disable_sriov(adapter->pdev);
err_novfs:
@@ -6498,8 +6479,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err = dma_set_coherent_mask(&pdev->dev,
DMA_BIT_MASK(32));
if (err) {
- dev_err(&pdev->dev, "No usable DMA "
- "configuration, aborting\n");
+ e_dev_err("No usable DMA configuration, "
+ "aborting\n");
goto err_dma;
}
}
@@ -6509,8 +6490,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
IORESOURCE_MEM), ixgbe_driver_name);
if (err) {
- dev_err(&pdev->dev,
- "pci_request_selected_regions failed 0x%x\n", err);
+ e_dev_err("pci_request_selected_regions failed 0x%x\n", err);
goto err_pci_reg;
}
@@ -6621,8 +6601,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) {
u32 esdp = IXGBE_READ_REG(hw, IXGBE_ESDP);
if (esdp & IXGBE_ESDP_SDP1)
- DPRINTK(PROBE, CRIT,
- "Fan has stopped, replace the adapter\n");
+ e_crit("Fan has stopped, replace the adapter\n");
}
/* reset_hw fills in the perm_addr as well */
@@ -6641,19 +6620,19 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
round_jiffies(jiffies + (2 * HZ)));
err = 0;
} else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
- dev_err(&adapter->pdev->dev, "failed to initialize because "
- "an unsupported SFP+ module type was detected.\n"
- "Reload the driver after installing a supported "
- "module.\n");
+ e_dev_err("failed to initialize because an unsupported SFP+ "
+ "module type was detected.\n");
+ e_dev_err("Reload the driver after installing a supported "
+ "module.\n");
goto err_sw_init;
} else if (err) {
- dev_err(&adapter->pdev->dev, "HW Init failed: %d\n", err);
+ e_dev_err("HW Init failed: %d\n", err);
goto err_sw_init;
}
ixgbe_probe_vf(adapter, ii);
- netdev->features = NETIF_F_SG |
+ netdev->features = NETIF_F_SG |
NETIF_F_IP_CSUM |
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
@@ -6700,7 +6679,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* make sure the EEPROM is good */
if (hw->eeprom.ops.validate_checksum(hw, NULL) < 0) {
- dev_err(&pdev->dev, "The EEPROM Checksum Is Not Valid\n");
+ e_dev_err("The EEPROM Checksum Is Not Valid\n");
err = -EIO;
goto err_eeprom;
}
@@ -6709,7 +6688,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
memcpy(netdev->perm_addr, hw->mac.perm_addr, netdev->addr_len);
if (ixgbe_validate_mac_addr(netdev->perm_addr)) {
- dev_err(&pdev->dev, "invalid MAC address\n");
+ e_dev_err("invalid MAC address\n");
err = -EIO;
goto err_eeprom;
}
@@ -6744,7 +6723,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
hw->mac.ops.get_bus_info(hw);
/* print bus type/speed/width info */
- dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
+ e_dev_info("(PCI Express:%s:%s) %pM\n",
((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
(hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
@@ -6754,20 +6733,20 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->dev_addr);
ixgbe_read_pba_num_generic(hw, &part_num);
if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
- dev_info(&pdev->dev, "MAC: %d, PHY: %d, SFP+: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type, hw->phy.sfp_type,
- (part_num >> 8), (part_num & 0xff));
+ e_dev_info("MAC: %d, PHY: %d, SFP+: %d, "
+ "PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type, hw->phy.sfp_type,
+ (part_num >> 8), (part_num & 0xff));
else
- dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
- hw->mac.type, hw->phy.type,
- (part_num >> 8), (part_num & 0xff));
+ e_dev_info("MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+ hw->mac.type, hw->phy.type,
+ (part_num >> 8), (part_num & 0xff));
if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
- dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
- "this card is not sufficient for optimal "
- "performance.\n");
- dev_warn(&pdev->dev, "For optimal performance a x8 "
- "PCI-Express slot is required.\n");
+ e_dev_warn("PCI-Express bandwidth available for this card is "
+ "not sufficient for optimal performance.\n");
+ e_dev_warn("For optimal performance a x8 PCI-Express slot "
+ "is required.\n");
}
/* save off EEPROM version number */
@@ -6778,12 +6757,12 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
if (err == IXGBE_ERR_EEPROM_VERSION) {
/* We are running on a pre-production device, log a warning */
- dev_warn(&pdev->dev, "This device is a pre-production "
- "adapter/LOM. Please be aware there may be issues "
- "associated with your hardware. If you are "
- "experiencing problems please contact your Intel or "
- "hardware representative who provided you with this "
- "hardware.\n");
+ e_dev_warn("This device is a pre-production adapter/LOM. "
+ "Please be aware there may be issues associated "
+ "with your hardware. If you are experiencing "
+ "problems please contact your Intel or hardware "
+ "representative who provided you with this "
+ "hardware.\n");
}
strcpy(netdev->name, "eth%d");
err = register_netdev(netdev);
@@ -6806,8 +6785,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
}
#endif
if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) {
- DPRINTK(PROBE, INFO, "IOV is enabled with %d VFs\n",
- adapter->num_vfs);
+ e_info("IOV is enabled with %d VFs\n", adapter->num_vfs);
for (i = 0; i < adapter->num_vfs; i++)
ixgbe_vf_configuration(pdev, (i | 0x10000000));
}
@@ -6815,7 +6793,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
/* add san mac addr to netdev */
ixgbe_add_sanmac_netdev(netdev);
- dev_info(&pdev->dev, "Intel(R) 10 Gigabit Network Connection\n");
+ e_dev_info("Intel(R) 10 Gigabit Network Connection\n");
cards_found++;
return 0;
@@ -6905,7 +6883,7 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
pci_release_selected_regions(pdev, pci_select_bars(pdev,
IORESOURCE_MEM));
- DPRINTK(PROBE, INFO, "complete\n");
+ e_dev_info("complete\n");
free_netdev(netdev);
@@ -6955,8 +6933,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
int err;
if (pci_enable_device_mem(pdev)) {
- DPRINTK(PROBE, ERR,
- "Cannot re-enable PCI device after reset.\n");
+ e_err("Cannot re-enable PCI device after reset.\n");
result = PCI_ERS_RESULT_DISCONNECT;
} else {
pci_set_master(pdev);
@@ -6972,8 +6949,8 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
err = pci_cleanup_aer_uncorrect_error_status(pdev);
if (err) {
- dev_err(&pdev->dev,
- "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", err);
+ e_dev_err("pci_cleanup_aer_uncorrect_error_status "
+ "failed 0x%0x\n", err);
/* non-fatal, continue */
}
@@ -6994,7 +6971,7 @@ static void ixgbe_io_resume(struct pci_dev *pdev)
if (netif_running(netdev)) {
if (ixgbe_up(adapter)) {
- DPRINTK(PROBE, INFO, "ixgbe_up failed after reset\n");
+ e_info("ixgbe_up failed after reset\n");
return;
}
}
@@ -7030,10 +7007,9 @@ static struct pci_driver ixgbe_driver = {
static int __init ixgbe_init_module(void)
{
int ret;
- printk(KERN_INFO "%s: %s - version %s\n", ixgbe_driver_name,
- ixgbe_driver_string, ixgbe_driver_version);
-
- printk(KERN_INFO "%s: %s\n", ixgbe_driver_name, ixgbe_copyright);
+ pr_info("%s - version %s\n", ixgbe_driver_string,
+ ixgbe_driver_version);
+ pr_info("%s\n", ixgbe_copyright);
#ifdef CONFIG_IXGBE_DCA
dca_register_notify(&dca_notifier);
@@ -7072,18 +7048,17 @@ static int ixgbe_notify_dca(struct notifier_block *nb, unsigned long event,
}
#endif /* CONFIG_IXGBE_DCA */
-#ifdef DEBUG
+
/**
- * ixgbe_get_hw_dev_name - return device name string
+ * ixgbe_get_hw_dev return device
* used by hardware layer to print debugging information
**/
-char *ixgbe_get_hw_dev_name(struct ixgbe_hw *hw)
+struct net_device *ixgbe_get_hw_dev(struct ixgbe_hw *hw)
{
struct ixgbe_adapter *adapter = hw->back;
- return adapter->netdev->name;
+ return adapter->netdev;
}
-#endif
module_exit(ixgbe_exit_module);
/* ixgbe_main.c */
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index f6cee94ec8e8..66f6e62b8cb0 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -25,7 +25,6 @@
*******************************************************************************/
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -174,7 +173,7 @@ int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
vf, IXGBE_RAH_AV);
if (adapter->vfinfo[vf].rar < 0) {
- DPRINTK(DRV, ERR, "Could not set MAC Filter for VF %d\n", vf);
+ e_err("Could not set MAC Filter for VF %d\n", vf);
return -1;
}
@@ -194,11 +193,7 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask)
if (enable) {
random_ether_addr(vf_mac_addr);
- DPRINTK(PROBE, INFO, "IOV: VF %d is enabled "
- "mac %02X:%02X:%02X:%02X:%02X:%02X\n",
- vfn,
- vf_mac_addr[0], vf_mac_addr[1], vf_mac_addr[2],
- vf_mac_addr[3], vf_mac_addr[4], vf_mac_addr[5]);
+ e_info("IOV: VF %d is enabled MAC %pM\n", vfn, vf_mac_addr);
/*
* Store away the VF "permananet" MAC address, it will ask
* for it later.
@@ -243,7 +238,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
retval = ixgbe_read_mbx(hw, msgbuf, mbx_size, vf);
if (retval)
- printk(KERN_ERR "Error receiving message from VF\n");
+ pr_err("Error receiving message from VF\n");
/* this is a message we already processed, do nothing */
if (msgbuf[0] & (IXGBE_VT_MSGTYPE_ACK | IXGBE_VT_MSGTYPE_NACK))
@@ -257,7 +252,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
if (msgbuf[0] == IXGBE_VF_RESET) {
unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses;
u8 *addr = (u8 *)(&msgbuf[1]);
- DPRINTK(PROBE, INFO, "VF Reset msg received from vf %d\n", vf);
+ e_info("VF Reset msg received from vf %d\n", vf);
adapter->vfinfo[vf].clear_to_send = false;
ixgbe_vf_reset_msg(adapter, vf);
adapter->vfinfo[vf].clear_to_send = true;
@@ -310,7 +305,7 @@ static int ixgbe_rcv_msg_from_vf(struct ixgbe_adapter *adapter, u32 vf)
retval = ixgbe_set_vf_vlan(adapter, add, vid, vf);
break;
default:
- DPRINTK(DRV, ERR, "Unhandled Msg %8.8x\n", msgbuf[0]);
+ e_err("Unhandled Msg %8.8x\n", msgbuf[0]);
retval = IXGBE_ERR_MBX;
break;
}
diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h
index 2eb6e151016c..cdd1998f18c7 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -2609,6 +2609,7 @@ struct ixgbe_info {
#define IXGBE_ERR_EEPROM_VERSION -24
#define IXGBE_ERR_NO_SPACE -25
#define IXGBE_ERR_OVERTEMP -26
+#define IXGBE_ERR_RAR_INDEX -27
#define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF
#endif /* _IXGBE_TYPE_H_ */
diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c
index a16cff7e54a3..73f1e75f68d4 100644
--- a/drivers/net/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ixgbevf/ixgbevf_main.c
@@ -3411,6 +3411,7 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_IPV6_CSUM;
netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6;
+ netdev->features |= NETIF_F_GRO;
netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_IP_CSUM;
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 26bf1b76b997..c7a9bef4dfb0 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -135,6 +135,7 @@ struct korina_private {
struct napi_struct napi;
struct timer_list media_check_timer;
struct mii_if_info mii_if;
+ struct work_struct restart_task;
struct net_device *dev;
int phy_addr;
};
@@ -375,7 +376,7 @@ static int korina_rx(struct net_device *dev, int limit)
if (devcs & ETH_RX_LE)
dev->stats.rx_length_errors++;
if (devcs & ETH_RX_OVR)
- dev->stats.rx_over_errors++;
+ dev->stats.rx_fifo_errors++;
if (devcs & ETH_RX_CV)
dev->stats.rx_frame_errors++;
if (devcs & ETH_RX_CES)
@@ -764,10 +765,9 @@ static int korina_alloc_ring(struct net_device *dev)
/* Initialize the receive descriptors */
for (i = 0; i < KORINA_NUM_RDS; i++) {
- skb = dev_alloc_skb(KORINA_RBSIZE + 2);
+ skb = netdev_alloc_skb_ip_align(dev, KORINA_RBSIZE);
if (!skb)
return -ENOMEM;
- skb_reserve(skb, 2);
lp->rx_skb[i] = skb;
lp->rd_ring[i].control = DMA_DESC_IOD |
DMA_COUNT(KORINA_RBSIZE);
@@ -890,12 +890,12 @@ static int korina_init(struct net_device *dev)
/*
* Restart the RC32434 ethernet controller.
- * FIXME: check the return status where we call it
*/
-static int korina_restart(struct net_device *dev)
+static void korina_restart_task(struct work_struct *work)
{
- struct korina_private *lp = netdev_priv(dev);
- int ret;
+ struct korina_private *lp = container_of(work,
+ struct korina_private, restart_task);
+ struct net_device *dev = lp->dev;
/*
* Disable interrupts
@@ -916,10 +916,9 @@ static int korina_restart(struct net_device *dev)
napi_disable(&lp->napi);
- ret = korina_init(dev);
- if (ret < 0) {
+ if (korina_init(dev) < 0) {
printk(KERN_ERR "%s: cannot restart device\n", dev->name);
- return ret;
+ return;
}
korina_multicast_list(dev);
@@ -927,8 +926,6 @@ static int korina_restart(struct net_device *dev)
enable_irq(lp->ovr_irq);
enable_irq(lp->tx_irq);
enable_irq(lp->rx_irq);
-
- return ret;
}
static void korina_clear_and_restart(struct net_device *dev, u32 value)
@@ -937,7 +934,7 @@ static void korina_clear_and_restart(struct net_device *dev, u32 value)
netif_stop_queue(dev);
writel(value, &lp->eth_regs->ethintfc);
- korina_restart(dev);
+ schedule_work(&lp->restart_task);
}
/* Ethernet Tx Underflow interrupt */
@@ -962,11 +959,8 @@ static irqreturn_t korina_und_interrupt(int irq, void *dev_id)
static void korina_tx_timeout(struct net_device *dev)
{
struct korina_private *lp = netdev_priv(dev);
- unsigned long flags;
- spin_lock_irqsave(&lp->lock, flags);
- korina_restart(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
+ schedule_work(&lp->restart_task);
}
/* Ethernet Rx Overflow interrupt */
@@ -1086,6 +1080,8 @@ static int korina_close(struct net_device *dev)
napi_disable(&lp->napi);
+ cancel_work_sync(&lp->restart_task);
+
free_irq(lp->rx_irq, dev);
free_irq(lp->tx_irq, dev);
free_irq(lp->ovr_irq, dev);
@@ -1198,6 +1194,8 @@ static int korina_probe(struct platform_device *pdev)
}
setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev);
+ INIT_WORK(&lp->restart_task, korina_restart_task);
+
printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n",
dev->name);
out:
diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c
index c80ca64277b2..7805bbf1d53a 100644
--- a/drivers/net/ksz884x.c
+++ b/drivers/net/ksz884x.c
@@ -4854,7 +4854,7 @@ static inline void copy_old_skb(struct sk_buff *old, struct sk_buff *skb)
*
* Return 0 if successful; otherwise an error code indicating failure.
*/
-static int netdev_tx(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t netdev_tx(struct sk_buff *skb, struct net_device *dev)
{
struct dev_priv *priv = netdev_priv(dev);
struct dev_info *hw_priv = priv->adapter;
@@ -6863,6 +6863,7 @@ static const struct net_device_ops netdev_ops = {
.ndo_tx_timeout = netdev_tx_timeout,
.ndo_change_mtu = netdev_change_mtu,
.ndo_set_mac_address = netdev_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = netdev_ioctl,
.ndo_set_rx_mode = netdev_set_rx_mode,
#ifdef CONFIG_NET_POLL_CONTROLLER
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 1136c9a22b67..3832fa4961dd 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -157,6 +157,8 @@ static void dayna_block_output(struct net_device *dev, int count,
#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c))
#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c))
+#define memcmp_withio(a, b, c) memcmp((a), (void *)(b), (c))
+
/* Slow Sane (16-bit chunk memory read/write) Cabletron uses this */
static void slow_sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page);
@@ -164,8 +166,8 @@ static void slow_sane_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void slow_sane_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page);
-static void word_memcpy_tocard(void *tp, const void *fp, int count);
-static void word_memcpy_fromcard(void *tp, const void *fp, int count);
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count);
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count);
static enum mac8390_type __init mac8390_ident(struct nubus_dev *dev)
{
@@ -245,9 +247,9 @@ static enum mac8390_access __init mac8390_testio(volatile unsigned long membase)
unsigned long outdata = 0xA5A0B5B0;
unsigned long indata = 0x00000000;
/* Try writing 32 bits */
- memcpy(membase, &outdata, 4);
+ memcpy_toio(membase, &outdata, 4);
/* Now compare them */
- if (memcmp((char *)&outdata, (char *)membase, 4) == 0)
+ if (memcmp_withio(&outdata, membase, 4) == 0)
return ACCESS_32;
/* Write 16 bit output */
word_memcpy_tocard(membase, &outdata, 4);
@@ -554,7 +556,7 @@ static int __init mac8390_initdev(struct net_device *dev,
case MAC8390_APPLE:
switch (mac8390_testio(dev->mem_start)) {
case ACCESS_UNKNOWN:
- pr_info("Don't know how to access card memory!\n");
+ pr_err("Don't know how to access card memory!\n");
return -ENODEV;
break;
@@ -641,12 +643,13 @@ static int __init mac8390_initdev(struct net_device *dev,
static int mac8390_open(struct net_device *dev)
{
+ int err;
+
__ei_open(dev);
- if (request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev)) {
- pr_info("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- return 0;
+ err = request_irq(dev->irq, __ei_interrupt, 0, "8390 Ethernet", dev);
+ if (err)
+ pr_err("%s: unable to get IRQ %d\n", dev->name, dev->irq);
+ return err;
}
static int mac8390_close(struct net_device *dev)
@@ -731,7 +734,7 @@ static void sane_get_8390_hdr(struct net_device *dev,
struct e8390_pkt_hdr *hdr, int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- memcpy_fromio((void *)hdr, (char *)dev->mem_start + hdr_start, 4);
+ memcpy_fromio(hdr, dev->mem_start + hdr_start, 4);
/* Fix endianness */
hdr->count = swab16(hdr->count);
}
@@ -745,14 +748,13 @@ static void sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ memcpy_fromio(skb->data, dev->mem_start + xfer_base,
semi_count);
count -= semi_count;
- memcpy_toio(skb->data + semi_count,
- (char *)ei_status.rmem_start, count);
- } else {
- memcpy_fromio(skb->data, (char *)dev->mem_start + xfer_base,
+ memcpy_fromio(skb->data + semi_count, ei_status.rmem_start,
count);
+ } else {
+ memcpy_fromio(skb->data, dev->mem_start + xfer_base, count);
}
}
@@ -761,7 +763,7 @@ static void sane_block_output(struct net_device *dev, int count,
{
long shmem = (start_page - WD_START_PG)<<8;
- memcpy_toio((char *)dev->mem_start + shmem, buf, count);
+ memcpy_toio(dev->mem_start + shmem, buf, count);
}
/* dayna block input/output */
@@ -812,7 +814,7 @@ static void slow_sane_get_8390_hdr(struct net_device *dev,
int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
- word_memcpy_fromcard(hdr, (char *)dev->mem_start + hdr_start, 4);
+ word_memcpy_fromcard(hdr, dev->mem_start + hdr_start, 4);
/* Register endianism - fix here rather than 8390.c */
hdr->count = (hdr->count&0xFF)<<8|(hdr->count>>8);
}
@@ -826,15 +828,14 @@ static void slow_sane_block_input(struct net_device *dev, int count,
if (xfer_start + count > ei_status.rmem_end) {
/* We must wrap the input move. */
int semi_count = ei_status.rmem_end - xfer_start;
- word_memcpy_fromcard(skb->data,
- (char *)dev->mem_start + xfer_base,
+ word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
semi_count);
count -= semi_count;
word_memcpy_fromcard(skb->data + semi_count,
- (char *)ei_status.rmem_start, count);
+ ei_status.rmem_start, count);
} else {
- word_memcpy_fromcard(skb->data,
- (char *)dev->mem_start + xfer_base, count);
+ word_memcpy_fromcard(skb->data, dev->mem_start + xfer_base,
+ count);
}
}
@@ -843,12 +844,12 @@ static void slow_sane_block_output(struct net_device *dev, int count,
{
long shmem = (start_page - WD_START_PG)<<8;
- word_memcpy_tocard((char *)dev->mem_start + shmem, buf, count);
+ word_memcpy_tocard(dev->mem_start + shmem, buf, count);
}
-static void word_memcpy_tocard(void *tp, const void *fp, int count)
+static void word_memcpy_tocard(unsigned long tp, const void *fp, int count)
{
- volatile unsigned short *to = tp;
+ volatile unsigned short *to = (void *)tp;
const unsigned short *from = fp;
count++;
@@ -858,10 +859,10 @@ static void word_memcpy_tocard(void *tp, const void *fp, int count)
*to++ = *from++;
}
-static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+static void word_memcpy_fromcard(void *tp, unsigned long fp, int count)
{
unsigned short *to = tp;
- const volatile unsigned short *from = fp;
+ const volatile unsigned short *from = (const void *)fp;
count++;
count /= 2;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index b6855a6476f8..1c5221f79d6f 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -997,8 +997,11 @@ MODULE_DEVICE_TABLE (of, mace_match);
static struct macio_driver mace_driver =
{
- .name = "mace",
- .match_table = mace_match,
+ .driver = {
+ .name = "mace",
+ .owner = THIS_MODULE,
+ .of_match_table = mace_match,
+ },
.probe = mace_probe,
.remove = mace_remove,
};
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 87e8d4cb4057..53422ce26f7f 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -145,15 +145,16 @@ static void macvlan_broadcast(struct sk_buff *skb,
}
/* called under rcu_read_lock() from netif_receive_skb */
-static struct sk_buff *macvlan_handle_frame(struct macvlan_port *port,
- struct sk_buff *skb)
+static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
{
+ struct macvlan_port *port;
const struct ethhdr *eth = eth_hdr(skb);
const struct macvlan_dev *vlan;
const struct macvlan_dev *src;
struct net_device *dev;
unsigned int len;
+ port = rcu_dereference(skb->dev->macvlan_port);
if (is_multicast_ether_addr(eth->h_dest)) {
src = macvlan_hash_lookup(port, eth->h_source);
if (!src)
@@ -515,6 +516,7 @@ static int macvlan_port_create(struct net_device *dev)
{
struct macvlan_port *port;
unsigned int i;
+ int err;
if (dev->type != ARPHRD_ETHER || dev->flags & IFF_LOOPBACK)
return -EINVAL;
@@ -528,13 +530,21 @@ static int macvlan_port_create(struct net_device *dev)
for (i = 0; i < MACVLAN_HASH_SIZE; i++)
INIT_HLIST_HEAD(&port->vlan_hash[i]);
rcu_assign_pointer(dev->macvlan_port, port);
- return 0;
+
+ err = netdev_rx_handler_register(dev, macvlan_handle_frame);
+ if (err) {
+ rcu_assign_pointer(dev->macvlan_port, NULL);
+ kfree(port);
+ }
+
+ return err;
}
static void macvlan_port_destroy(struct net_device *dev)
{
struct macvlan_port *port = dev->macvlan_port;
+ netdev_rx_handler_unregister(dev);
rcu_assign_pointer(dev->macvlan_port, NULL);
synchronize_rcu();
kfree(port);
@@ -767,14 +777,12 @@ static int __init macvlan_init_module(void)
int err;
register_netdevice_notifier(&macvlan_notifier_block);
- macvlan_handle_frame_hook = macvlan_handle_frame;
err = macvlan_link_register(&macvlan_link_ops);
if (err < 0)
goto err1;
return 0;
err1:
- macvlan_handle_frame_hook = NULL;
unregister_netdevice_notifier(&macvlan_notifier_block);
return err;
}
@@ -782,7 +790,6 @@ err1:
static void __exit macvlan_cleanup_module(void)
{
rtnl_link_unregister(&macvlan_link_ops);
- macvlan_handle_frame_hook = NULL;
unregister_netdevice_notifier(&macvlan_notifier_block);
}
diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c
index 96180c0ec206..a0d8a26f5a02 100644
--- a/drivers/net/mlx4/en_netdev.c
+++ b/drivers/net/mlx4/en_netdev.c
@@ -961,6 +961,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+ dev->dev_id = port - 1;
/*
* Initialize driver private data
diff --git a/drivers/net/mlx4/eq.c b/drivers/net/mlx4/eq.c
index 423053482ed5..22d0b3b796b4 100644
--- a/drivers/net/mlx4/eq.c
+++ b/drivers/net/mlx4/eq.c
@@ -110,7 +110,7 @@ struct mlx4_eqe {
u32 raw[6];
struct {
__be32 cqn;
- } __attribute__((packed)) comp;
+ } __packed comp;
struct {
u16 reserved1;
__be16 token;
@@ -118,27 +118,27 @@ struct mlx4_eqe {
u8 reserved3[3];
u8 status;
__be64 out_param;
- } __attribute__((packed)) cmd;
+ } __packed cmd;
struct {
__be32 qpn;
- } __attribute__((packed)) qp;
+ } __packed qp;
struct {
__be32 srqn;
- } __attribute__((packed)) srq;
+ } __packed srq;
struct {
__be32 cqn;
u32 reserved1;
u8 reserved2[3];
u8 syndrome;
- } __attribute__((packed)) cq_err;
+ } __packed cq_err;
struct {
u32 reserved1[2];
__be32 port;
- } __attribute__((packed)) port_change;
+ } __packed port_change;
} event;
u8 reserved3[3];
u8 owner;
-} __attribute__((packed));
+} __packed;
static void eq_set_ci(struct mlx4_eq *eq, int req_not)
{
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 3dc69be4949f..9c188bdd7f4f 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -58,7 +58,7 @@ struct mlx4_mpt_entry {
__be32 mtt_sz;
__be32 entity_size;
__be32 first_byte_offset;
-} __attribute__((packed));
+} __packed;
#define MLX4_MPT_FLAG_SW_OWNS (0xfUL << 28)
#define MLX4_MPT_FLAG_FREE (0x3UL << 28)
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index e0b47cc8a86e..5ae8a93fe4f5 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -239,6 +239,7 @@ struct myri10ge_priv {
int watchdog_resets;
int watchdog_pause;
int pause;
+ bool fw_name_allocated;
char *fw_name;
char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
char *product_code_string;
@@ -271,6 +272,7 @@ MODULE_FIRMWARE("myri10ge_eth_z8e.dat");
MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat");
MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat");
+/* Careful: must be accessed under kparam_block_sysfs_write */
static char *myri10ge_fw_name = NULL;
module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
@@ -376,6 +378,14 @@ static inline void put_be32(__be32 val, __be32 __iomem * p)
static struct net_device_stats *myri10ge_get_stats(struct net_device *dev);
+static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated)
+{
+ if (mgp->fw_name_allocated)
+ kfree(mgp->fw_name);
+ mgp->fw_name = name;
+ mgp->fw_name_allocated = allocated;
+}
+
static int
myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
struct myri10ge_cmd *data, int atomic)
@@ -747,7 +757,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt)
dev_warn(&mgp->pdev->dev, "via hotplug\n");
}
- mgp->fw_name = "adopted";
+ set_fw_name(mgp, "adopted", false);
mgp->tx_boundary = 2048;
myri10ge_dummy_rdma(mgp, 1);
status = myri10ge_get_firmware_capabilities(mgp);
@@ -3229,7 +3239,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
* load the optimized firmware (which assumes aligned PCIe
* completions) in order to see if it works on this host.
*/
- mgp->fw_name = myri10ge_fw_aligned;
+ set_fw_name(mgp, myri10ge_fw_aligned, false);
status = myri10ge_load_firmware(mgp, 1);
if (status != 0) {
goto abort;
@@ -3257,7 +3267,7 @@ static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
abort:
/* fall back to using the unaligned firmware */
mgp->tx_boundary = 2048;
- mgp->fw_name = myri10ge_fw_unaligned;
+ set_fw_name(mgp, myri10ge_fw_unaligned, false);
}
@@ -3280,7 +3290,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
link_width);
mgp->tx_boundary = 4096;
- mgp->fw_name = myri10ge_fw_aligned;
+ set_fw_name(mgp, myri10ge_fw_aligned, false);
} else {
myri10ge_firmware_probe(mgp);
}
@@ -3289,22 +3299,29 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
dev_info(&mgp->pdev->dev,
"Assuming aligned completions (forced)\n");
mgp->tx_boundary = 4096;
- mgp->fw_name = myri10ge_fw_aligned;
+ set_fw_name(mgp, myri10ge_fw_aligned, false);
} else {
dev_info(&mgp->pdev->dev,
"Assuming unaligned completions (forced)\n");
mgp->tx_boundary = 2048;
- mgp->fw_name = myri10ge_fw_unaligned;
+ set_fw_name(mgp, myri10ge_fw_unaligned, false);
}
}
+
+ kparam_block_sysfs_write(myri10ge_fw_name);
if (myri10ge_fw_name != NULL) {
- overridden = 1;
- mgp->fw_name = myri10ge_fw_name;
+ char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL);
+ if (fw_name) {
+ overridden = 1;
+ set_fw_name(mgp, fw_name, true);
+ }
}
+ kparam_unblock_sysfs_write(myri10ge_fw_name);
+
if (mgp->board_number < MYRI10GE_MAX_BOARDS &&
myri10ge_fw_names[mgp->board_number] != NULL &&
strlen(myri10ge_fw_names[mgp->board_number])) {
- mgp->fw_name = myri10ge_fw_names[mgp->board_number];
+ set_fw_name(mgp, myri10ge_fw_names[mgp->board_number], false);
overridden = 1;
}
if (overridden)
@@ -3656,6 +3673,7 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
struct myri10ge_cmd cmd;
struct pci_dev *pdev = mgp->pdev;
char *old_fw;
+ bool old_allocated;
int i, status, ncpus, msix_cap;
mgp->num_slices = 1;
@@ -3668,17 +3686,23 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
/* try to load the slice aware rss firmware */
old_fw = mgp->fw_name;
+ old_allocated = mgp->fw_name_allocated;
+ /* don't free old_fw if we override it. */
+ mgp->fw_name_allocated = false;
+
if (myri10ge_fw_name != NULL) {
dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n",
myri10ge_fw_name);
- mgp->fw_name = myri10ge_fw_name;
+ set_fw_name(mgp, myri10ge_fw_name, false);
} else if (old_fw == myri10ge_fw_aligned)
- mgp->fw_name = myri10ge_fw_rss_aligned;
+ set_fw_name(mgp, myri10ge_fw_rss_aligned, false);
else
- mgp->fw_name = myri10ge_fw_rss_unaligned;
+ set_fw_name(mgp, myri10ge_fw_rss_unaligned, false);
status = myri10ge_load_firmware(mgp, 0);
if (status != 0) {
dev_info(&pdev->dev, "Rss firmware not found\n");
+ if (old_allocated)
+ kfree(old_fw);
return;
}
@@ -3743,6 +3767,8 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp)
mgp->num_slices);
if (status == 0) {
pci_disable_msix(pdev);
+ if (old_allocated)
+ kfree(old_fw);
return;
}
if (status > 0)
@@ -3759,7 +3785,7 @@ disable_msix:
abort_with_fw:
mgp->num_slices = 1;
- mgp->fw_name = old_fw;
+ set_fw_name(mgp, old_fw, old_allocated);
myri10ge_load_firmware(mgp, 0);
}
@@ -3989,6 +4015,7 @@ abort_with_enabled:
pci_disable_device(pdev);
abort_with_netdev:
+ set_fw_name(mgp, NULL, false);
free_netdev(netdev);
return status;
}
@@ -4033,6 +4060,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
mgp->cmd, mgp->cmd_bus);
+ set_fw_name(mgp, NULL, false);
free_netdev(netdev);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index c5f8eb102bf7..e7b4187da057 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -69,7 +69,6 @@
#define MPHDRLEN 6 /* multilink protocol header length */
#define MPHDRLEN_SSN 4 /* ditto with short sequence numbers */
-#define MIN_FRAG_SIZE 64
/*
* An instance of /dev/ppp can be associated with either a ppp
@@ -539,14 +538,9 @@ static int get_filter(void __user *arg, struct sock_filter **p)
}
len = uprog.len * sizeof(struct sock_filter);
- code = kmalloc(len, GFP_KERNEL);
- if (code == NULL)
- return -ENOMEM;
-
- if (copy_from_user(code, uprog.filter, len)) {
- kfree(code);
- return -EFAULT;
- }
+ code = memdup_user(uprog.filter, len);
+ if (IS_ERR(code))
+ return PTR_ERR(code);
err = sk_chk_filter(code, uprog.len);
if (err) {
@@ -1422,7 +1416,7 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
flen = len;
if (nfree > 0) {
if (pch->speed == 0) {
- flen = totlen/nfree;
+ flen = len/nfree;
if (nbigger > 0) {
flen++;
nbigger--;
@@ -1933,9 +1927,9 @@ ppp_receive_mp_frame(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)
/* If the queue is getting long, don't wait any longer for packets
before the start of the queue. */
if (skb_queue_len(&ppp->mrq) >= PPP_MP_MAX_QLEN) {
- struct sk_buff *skb = skb_peek(&ppp->mrq);
- if (seq_before(ppp->minseq, skb->sequence))
- ppp->minseq = skb->sequence;
+ struct sk_buff *mskb = skb_peek(&ppp->mrq);
+ if (seq_before(ppp->minseq, mskb->sequence))
+ ppp->minseq = mskb->sequence;
}
/* Pull completed packets off the queue and receive them. */
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 805b64d1e893..7ebb8e87efa4 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -949,7 +949,7 @@ static int __pppoe_xmit(struct sock *sk, struct sk_buff *skb)
abort:
kfree_skb(skb);
- return 1;
+ return 0;
}
/************************************************************************
diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h
index 0a88b535197a..f7e51b7d7049 100644
--- a/drivers/net/ps3_gelic_wireless.h
+++ b/drivers/net/ps3_gelic_wireless.h
@@ -74,7 +74,7 @@ struct gelic_eurus_common_cfg {
u16 bss_type; /* infra or adhoc */
u16 auth_method; /* shared key or open */
u16 op_mode; /* B/G */
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_WEP_CFG */
@@ -88,7 +88,7 @@ struct gelic_eurus_wep_cfg {
/* all fields are big endian */
u16 security;
u8 key[4][16];
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_WPA_CFG */
enum gelic_eurus_wpa_security {
@@ -120,7 +120,7 @@ struct gelic_eurus_wpa_cfg {
u16 security;
u16 psk_type; /* psk key encoding type */
u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */
-} __attribute__((packed));
+} __packed;
/* for GELIC_EURUS_CMD_{START,GET}_SCAN */
enum gelic_eurus_scan_capability {
@@ -171,7 +171,7 @@ struct gelic_eurus_scan_info {
__be32 reserved3;
__be32 reserved4;
u8 elements[0]; /* ie */
-} __attribute__ ((packed));
+} __packed;
/* the hypervisor returns bbs up to 16 */
#define GELIC_EURUS_MAX_SCAN (16)
@@ -193,7 +193,7 @@ struct gelic_wl_scan_info {
struct gelic_eurus_rssi_info {
/* big endian */
__be16 rssi;
-} __attribute__ ((packed));
+} __packed;
/* for 'stat' member of gelic_wl_info */
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h
index 896d40df9a13..02db363f20cd 100644
--- a/drivers/net/qlcnic/qlcnic.h
+++ b/drivers/net/qlcnic/qlcnic.h
@@ -51,8 +51,8 @@
#define _QLCNIC_LINUX_MAJOR 5
#define _QLCNIC_LINUX_MINOR 0
-#define _QLCNIC_LINUX_SUBVERSION 2
-#define QLCNIC_LINUX_VERSIONID "5.0.2"
+#define _QLCNIC_LINUX_SUBVERSION 3
+#define QLCNIC_LINUX_VERSIONID "5.0.3"
#define QLCNIC_DRV_IDC_VER 0x01
#define QLCNIC_VERSION_CODE(a, b, c) (((a) << 24) + ((b) << 16) + (c))
@@ -197,8 +197,7 @@ struct cmd_desc_type0 {
__le64 addr_buffer4;
- __le32 reserved2;
- __le16 reserved;
+ u8 eth_addr[ETH_ALEN];
__le16 vlan_TCI;
} __attribute__ ((aligned(64)));
@@ -315,6 +314,8 @@ struct uni_data_desc{
#define QLCNIC_BRDTYPE_P3_10G_XFP 0x0032
#define QLCNIC_BRDTYPE_P3_10G_TP 0x0080
+#define QLCNIC_MSIX_TABLE_OFFSET 0x44
+
/* Flash memory map */
#define QLCNIC_BRDCFG_START 0x4000 /* board config */
#define QLCNIC_BOOTLD_START 0x10000 /* bootld */
@@ -542,7 +543,17 @@ struct qlcnic_recv_context {
#define QLCNIC_CDRP_CMD_READ_PEXQ_PARAMETERS 0x0000001c
#define QLCNIC_CDRP_CMD_GET_LIC_CAPABILITIES 0x0000001d
#define QLCNIC_CDRP_CMD_READ_MAX_LRO_PER_BOARD 0x0000001e
-#define QLCNIC_CDRP_CMD_MAX 0x0000001f
+#define QLCNIC_CDRP_CMD_MAC_ADDRESS 0x0000001f
+
+#define QLCNIC_CDRP_CMD_GET_PCI_INFO 0x00000020
+#define QLCNIC_CDRP_CMD_GET_NIC_INFO 0x00000021
+#define QLCNIC_CDRP_CMD_SET_NIC_INFO 0x00000022
+#define QLCNIC_CDRP_CMD_RESET_NPAR 0x00000023
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY 0x00000024
+#define QLCNIC_CDRP_CMD_TOGGLE_ESWITCH 0x00000025
+#define QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS 0x00000026
+#define QLCNIC_CDRP_CMD_SET_PORTMIRRORING 0x00000027
+#define QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH 0x00000028
#define QLCNIC_RCODE_SUCCESS 0
#define QLCNIC_RCODE_TIMEOUT 17
@@ -560,7 +571,6 @@ struct qlcnic_recv_context {
/*
* Context state
*/
-#define QLCHAL_VERSION 1
#define QLCNIC_HOST_CTX_STATE_ACTIVE 2
@@ -881,12 +891,14 @@ struct qlcnic_mac_req {
#define QLCNIC_LRO_ENABLED 0x08
#define QLCNIC_BRIDGE_ENABLED 0X10
#define QLCNIC_DIAG_ENABLED 0x20
+#define QLCNIC_NPAR_ENABLED 0x40
#define QLCNIC_IS_MSI_FAMILY(adapter) \
((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
#define MSIX_ENTRIES_PER_ADAPTER NUM_STS_DESC_RINGS
#define QLCNIC_MSIX_TBL_SPACE 8192
#define QLCNIC_PCI_REG_MSIX_TBL 0x44
+#define QLCNIC_MSIX_TBL_PGSIZE 4096
#define QLCNIC_NETDEV_WEIGHT 128
#define QLCNIC_ADAPTER_UP_MAGIC 777
@@ -923,7 +935,6 @@ struct qlcnic_adapter {
u8 mc_enabled;
u8 max_mc_count;
u8 rss_supported;
- u8 rsrvd1;
u8 fw_wait_cnt;
u8 fw_fail_cnt;
u8 tx_timeo_cnt;
@@ -940,6 +951,15 @@ struct qlcnic_adapter {
u16 link_autoneg;
u16 module_type;
+ u16 op_mode;
+ u16 switch_mode;
+ u16 max_tx_ques;
+ u16 max_rx_ques;
+ u16 min_tx_bw;
+ u16 max_tx_bw;
+ u16 max_mtu;
+
+ u32 fw_hal_version;
u32 capabilities;
u32 flags;
u32 irq;
@@ -948,18 +968,22 @@ struct qlcnic_adapter {
u32 int_vec_bit;
u32 heartbit;
+ u8 max_mac_filters;
u8 dev_state;
u8 diag_test;
u8 diag_cnt;
u8 reset_ack_timeo;
u8 dev_init_timeo;
- u8 rsrd1;
u16 msg_enable;
u8 mac_addr[ETH_ALEN];
u64 dev_rst_time;
+ struct qlcnic_pci_info *npars;
+ struct qlcnic_eswitch *eswitch;
+ struct qlcnic_nic_template *nic_ops;
+
struct qlcnic_adapter_stats stats;
struct qlcnic_recv_context recv_ctx;
@@ -984,6 +1008,53 @@ struct qlcnic_adapter {
const struct firmware *fw;
};
+struct qlcnic_info {
+ __le16 pci_func;
+ __le16 op_mode; /* 1 = Priv, 2 = NP, 3 = NP passthru */
+ __le16 phys_port;
+ __le16 switch_mode; /* 0 = disabled, 1 = int, 2 = ext */
+
+ __le32 capabilities;
+ u8 max_mac_filters;
+ u8 reserved1;
+ __le16 max_mtu;
+
+ __le16 max_tx_ques;
+ __le16 max_rx_ques;
+ __le16 min_tx_bw;
+ __le16 max_tx_bw;
+ u8 reserved2[104];
+};
+
+struct qlcnic_pci_info {
+ __le16 id; /* pci function id */
+ __le16 active; /* 1 = Enabled */
+ __le16 type; /* 1 = NIC, 2 = FCoE, 3 = iSCSI */
+ __le16 default_port; /* default port number */
+
+ __le16 tx_min_bw; /* Multiple of 100mbpc */
+ __le16 tx_max_bw;
+ __le16 reserved1[2];
+
+ u8 mac[ETH_ALEN];
+ u8 reserved2[106];
+};
+
+struct qlcnic_eswitch {
+ u8 port;
+ u8 active_vports;
+ u8 active_vlans;
+ u8 active_ucast_filters;
+ u8 max_ucast_filters;
+ u8 max_active_vlans;
+
+ u32 flags;
+#define QLCNIC_SWITCH_ENABLE BIT_1
+#define QLCNIC_SWITCH_VLAN_FILTERING BIT_2
+#define QLCNIC_SWITCH_PROMISC_MODE BIT_3
+#define QLCNIC_SWITCH_PORT_MIRRORING BIT_4
+};
+
int qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val);
int qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val);
@@ -1070,13 +1141,14 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup);
int qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu);
int qlcnic_change_mtu(struct net_device *netdev, int new_mtu);
int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable);
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable);
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable);
int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter);
void qlcnic_update_cmd_producer(struct qlcnic_adapter *adapter,
struct qlcnic_host_tx_ring *tx_ring);
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac);
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac);
void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter);
int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter);
+void qlcnic_fetch_mac(struct qlcnic_adapter *, u32, u32, u8, u8 *);
/* Functions from qlcnic_main.c */
int qlcnic_reset_context(struct qlcnic_adapter *);
@@ -1088,6 +1160,25 @@ int qlcnic_check_loopback_buff(unsigned char *data);
netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring);
+/* Management functions */
+int qlcnic_set_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_mac_address(struct qlcnic_adapter *, u8*);
+int qlcnic_get_nic_info(struct qlcnic_adapter *, u8);
+int qlcnic_set_nic_info(struct qlcnic_adapter *, struct qlcnic_info *);
+int qlcnic_get_pci_info(struct qlcnic_adapter *);
+int qlcnic_reset_partition(struct qlcnic_adapter *, u8);
+
+/* eSwitch management functions */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *, u8,
+ struct qlcnic_eswitch *);
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *, u8,
+ struct qlcnic_eswitch *);
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *, u8, u8);
+int qlcnic_config_switch_port(struct qlcnic_adapter *, u8, int, u8, u8,
+ u8, u8, u16);
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *, u8, u8, u8);
+extern int qlcnic_config_tso;
+
/*
* QLOGIC Board information
*/
@@ -1131,6 +1222,15 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
extern const struct ethtool_ops qlcnic_ethtool_ops;
+struct qlcnic_nic_template {
+ int (*get_mac_addr) (struct qlcnic_adapter *, u8*);
+ int (*config_bridged_mode) (struct qlcnic_adapter *, u32);
+ int (*config_led) (struct qlcnic_adapter *, u32, u32);
+ int (*set_ilb_mode) (struct qlcnic_adapter *);
+ void (*clear_ilb_mode) (struct qlcnic_adapter *);
+ int (*start_firmware) (struct qlcnic_adapter *);
+};
+
#define QLCDB(adapter, lvl, _fmt, _args...) do { \
if (NETIF_MSG_##lvl & adapter->msg_enable) \
printk(KERN_INFO "%s: %s: " _fmt, \
diff --git a/drivers/net/qlcnic/qlcnic_ctx.c b/drivers/net/qlcnic/qlcnic_ctx.c
index c2c1f5cc16c6..1e1dc58cddca 100644
--- a/drivers/net/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/qlcnic/qlcnic_ctx.c
@@ -88,12 +88,12 @@ qlcnic_fw_cmd_set_mtu(struct qlcnic_adapter *adapter, int mtu)
if (recv_ctx->state == QLCNIC_HOST_CTX_STATE_ACTIVE) {
if (qlcnic_issue_cmd(adapter,
- adapter->ahw.pci_func,
- QLCHAL_VERSION,
- recv_ctx->context_id,
- mtu,
- 0,
- QLCNIC_CDRP_CMD_SET_MTU)) {
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ recv_ctx->context_id,
+ mtu,
+ 0,
+ QLCNIC_CDRP_CMD_SET_MTU)) {
dev_err(&adapter->pdev->dev, "Failed to set mtu\n");
return -EIO;
@@ -121,7 +121,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
int i, nrds_rings, nsds_rings;
size_t rq_size, rsp_size;
- u32 cap, reg, val;
+ u32 cap, reg, val, reg2;
int err;
struct qlcnic_recv_context *recv_ctx = &adapter->recv_ctx;
@@ -197,7 +197,7 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
phys_addr = hostrq_phys_addr;
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
(u32)(phys_addr >> 32),
(u32)(phys_addr & 0xffffffff),
rq_size,
@@ -216,8 +216,12 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
rds_ring = &recv_ctx->rds_rings[i];
reg = le32_to_cpu(prsp_rds[i].host_producer_crb);
- rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
+ if (adapter->fw_hal_version == QLCNIC_FW_BASE)
+ rds_ring->crb_rcv_producer = qlcnic_get_ioaddr(adapter,
QLCNIC_REG(reg - 0x200));
+ else
+ rds_ring->crb_rcv_producer = adapter->ahw.pci_base0 +
+ reg;
}
prsp_sds = ((struct qlcnic_cardrsp_sds_ring *)
@@ -227,12 +231,18 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
sds_ring = &recv_ctx->sds_rings[i];
reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
- sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
- QLCNIC_REG(reg - 0x200));
+ reg2 = le32_to_cpu(prsp_sds[i].interrupt_crb);
- reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
- sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+ if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
+ sds_ring->crb_sts_consumer = qlcnic_get_ioaddr(adapter,
QLCNIC_REG(reg - 0x200));
+ sds_ring->crb_intr_mask = qlcnic_get_ioaddr(adapter,
+ QLCNIC_REG(reg2 - 0x200));
+ } else {
+ sds_ring->crb_sts_consumer = adapter->ahw.pci_base0 +
+ reg;
+ sds_ring->crb_intr_mask = adapter->ahw.pci_base0 + reg2;
+ }
}
recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
@@ -253,7 +263,7 @@ qlcnic_fw_cmd_destroy_rx_ctx(struct qlcnic_adapter *adapter)
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
recv_ctx->context_id,
QLCNIC_DESTROY_CTX_RESET,
0,
@@ -319,7 +329,7 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
phys_addr = rq_phys_addr;
err = qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
(u32)(phys_addr >> 32),
((u32)phys_addr & 0xffffffff),
rq_size,
@@ -327,8 +337,12 @@ qlcnic_fw_cmd_create_tx_ctx(struct qlcnic_adapter *adapter)
if (err == QLCNIC_RCODE_SUCCESS) {
temp = le32_to_cpu(prsp->cds_ring.host_producer_crb);
- tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
+ if (adapter->fw_hal_version == QLCNIC_FW_BASE)
+ tx_ring->crb_cmd_producer = qlcnic_get_ioaddr(adapter,
QLCNIC_REG(temp - 0x200));
+ else
+ tx_ring->crb_cmd_producer = adapter->ahw.pci_base0 +
+ temp;
adapter->tx_context_id =
le16_to_cpu(prsp->context_id);
@@ -351,7 +365,7 @@ qlcnic_fw_cmd_destroy_tx_ctx(struct qlcnic_adapter *adapter)
{
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
adapter->tx_context_id,
QLCNIC_DESTROY_CTX_RESET,
0,
@@ -368,7 +382,7 @@ qlcnic_fw_cmd_query_phy(struct qlcnic_adapter *adapter, u32 reg, u32 *val)
if (qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
reg,
0,
0,
@@ -385,7 +399,7 @@ qlcnic_fw_cmd_set_phy(struct qlcnic_adapter *adapter, u32 reg, u32 val)
{
return qlcnic_issue_cmd(adapter,
adapter->ahw.pci_func,
- QLCHAL_VERSION,
+ adapter->fw_hal_version,
reg,
val,
0,
@@ -533,3 +547,464 @@ void qlcnic_free_hw_resources(struct qlcnic_adapter *adapter)
}
}
+/* Set MAC address of a NIC partition */
+int qlcnic_set_mac_address(struct qlcnic_adapter *adapter, u8* mac)
+{
+ int err = 0;
+ u32 arg1, arg2, arg3;
+
+ arg1 = adapter->ahw.pci_func | BIT_9;
+ arg2 = mac[0] | (mac[1] << 8) | (mac[2] << 16) | (mac[3] << 24);
+ arg3 = mac[4] | (mac[5] << 16);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ arg2,
+ arg3,
+ QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set mac address%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get MAC address of a NIC partition */
+int qlcnic_get_mac_address(struct qlcnic_adapter *adapter, u8 *mac)
+{
+ int err;
+ u32 arg1;
+
+ arg1 = adapter->ahw.pci_func | BIT_8;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_MAC_ADDRESS);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ qlcnic_fetch_mac(adapter, QLCNIC_ARG1_CRB_OFFSET,
+ QLCNIC_ARG2_CRB_OFFSET, 0, mac);
+ dev_info(&adapter->pdev->dev, "MAC address: %pM\n", mac);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get mac address%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get info of a NIC partition */
+int qlcnic_get_nic_info(struct qlcnic_adapter *adapter, u8 func_id)
+{
+ int err;
+ dma_addr_t nic_dma_t;
+ struct qlcnic_info *nic_info;
+ void *nic_info_addr;
+ size_t nic_size = sizeof(struct qlcnic_info);
+
+ nic_info_addr = pci_alloc_consistent(adapter->pdev,
+ nic_size, &nic_dma_t);
+ if (!nic_info_addr)
+ return -ENOMEM;
+ memset(nic_info_addr, 0, nic_size);
+
+ nic_info = (struct qlcnic_info *) nic_info_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(nic_dma_t),
+ LSD(nic_dma_t),
+ (func_id << 16 | nic_size),
+ QLCNIC_CDRP_CMD_GET_NIC_INFO);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ adapter->physical_port = le16_to_cpu(nic_info->phys_port);
+ adapter->switch_mode = le16_to_cpu(nic_info->switch_mode);
+ adapter->max_tx_ques = le16_to_cpu(nic_info->max_tx_ques);
+ adapter->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques);
+ adapter->min_tx_bw = le16_to_cpu(nic_info->min_tx_bw);
+ adapter->max_tx_bw = le16_to_cpu(nic_info->max_tx_bw);
+ adapter->max_mtu = le16_to_cpu(nic_info->max_mtu);
+ adapter->capabilities = le32_to_cpu(nic_info->capabilities);
+ adapter->max_mac_filters = nic_info->max_mac_filters;
+
+ dev_info(&adapter->pdev->dev,
+ "phy port: %d switch_mode: %d,\n"
+ "\tmax_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x,\n"
+ "\tmax_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x\n",
+ adapter->physical_port, adapter->switch_mode,
+ adapter->max_tx_ques, adapter->max_rx_ques,
+ adapter->min_tx_bw, adapter->max_tx_bw,
+ adapter->max_mtu, adapter->capabilities);
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get nic info%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ return err;
+}
+
+/* Configure a NIC partition */
+int qlcnic_set_nic_info(struct qlcnic_adapter *adapter, struct qlcnic_info *nic)
+{
+ int err = -EIO;
+ u32 func_state;
+ dma_addr_t nic_dma_t;
+ void *nic_info_addr;
+ struct qlcnic_info *nic_info;
+ size_t nic_size = sizeof(struct qlcnic_info);
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ if (qlcnic_api_lock(adapter))
+ return err;
+
+ func_state = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ if (QLC_DEV_CHECK_ACTIVE(func_state, nic->pci_func)) {
+ qlcnic_api_unlock(adapter);
+ return err;
+ }
+
+ qlcnic_api_unlock(adapter);
+
+ nic_info_addr = pci_alloc_consistent(adapter->pdev, nic_size,
+ &nic_dma_t);
+ if (!nic_info_addr)
+ return -ENOMEM;
+
+ memset(nic_info_addr, 0, nic_size);
+ nic_info = (struct qlcnic_info *)nic_info_addr;
+
+ nic_info->pci_func = cpu_to_le16(nic->pci_func);
+ nic_info->op_mode = cpu_to_le16(nic->op_mode);
+ nic_info->phys_port = cpu_to_le16(nic->phys_port);
+ nic_info->switch_mode = cpu_to_le16(nic->switch_mode);
+ nic_info->capabilities = cpu_to_le32(nic->capabilities);
+ nic_info->max_mac_filters = nic->max_mac_filters;
+ nic_info->max_tx_ques = cpu_to_le16(nic->max_tx_ques);
+ nic_info->max_rx_ques = cpu_to_le16(nic->max_rx_ques);
+ nic_info->min_tx_bw = cpu_to_le16(nic->min_tx_bw);
+ nic_info->max_tx_bw = cpu_to_le16(nic->max_tx_bw);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(nic_dma_t),
+ LSD(nic_dma_t),
+ nic_size,
+ QLCNIC_CDRP_CMD_SET_NIC_INFO);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to set nic info%d\n", err);
+ err = -EIO;
+ }
+
+ pci_free_consistent(adapter->pdev, nic_size, nic_info_addr, nic_dma_t);
+ return err;
+}
+
+/* Get PCI Info of a partition */
+int qlcnic_get_pci_info(struct qlcnic_adapter *adapter)
+{
+ int err = 0, i;
+ dma_addr_t pci_info_dma_t;
+ struct qlcnic_pci_info *npar;
+ void *pci_info_addr;
+ size_t npar_size = sizeof(struct qlcnic_pci_info);
+ size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC;
+
+ pci_info_addr = pci_alloc_consistent(adapter->pdev, pci_size,
+ &pci_info_dma_t);
+ if (!pci_info_addr)
+ return -ENOMEM;
+ memset(pci_info_addr, 0, pci_size);
+
+ if (!adapter->npars)
+ adapter->npars = kzalloc(pci_size, GFP_KERNEL);
+ if (!adapter->npars) {
+ err = -ENOMEM;
+ goto err_npar;
+ }
+
+ if (!adapter->eswitch)
+ adapter->eswitch = kzalloc(sizeof(struct qlcnic_eswitch) *
+ QLCNIC_NIU_MAX_XG_PORTS, GFP_KERNEL);
+ if (!adapter->eswitch) {
+ err = -ENOMEM;
+ goto err_eswitch;
+ }
+
+ npar = (struct qlcnic_pci_info *) pci_info_addr;
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ MSD(pci_info_dma_t),
+ LSD(pci_info_dma_t),
+ pci_size,
+ QLCNIC_CDRP_CMD_GET_PCI_INFO);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++, npar++) {
+ adapter->npars[i].id = le32_to_cpu(npar->id);
+ adapter->npars[i].active = le32_to_cpu(npar->active);
+ adapter->npars[i].type = le32_to_cpu(npar->type);
+ adapter->npars[i].default_port =
+ le32_to_cpu(npar->default_port);
+ adapter->npars[i].tx_min_bw =
+ le32_to_cpu(npar->tx_min_bw);
+ adapter->npars[i].tx_max_bw =
+ le32_to_cpu(npar->tx_max_bw);
+ memcpy(adapter->npars[i].mac, npar->mac, ETH_ALEN);
+ }
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get PCI Info%d\n", err);
+ kfree(adapter->npars);
+ err = -EIO;
+ }
+ goto err_npar;
+
+err_eswitch:
+ kfree(adapter->npars);
+ adapter->npars = NULL;
+
+err_npar:
+ pci_free_consistent(adapter->pdev, pci_size, pci_info_addr,
+ pci_info_dma_t);
+ return err;
+}
+
+/* Reset a NIC partition */
+
+int qlcnic_reset_partition(struct qlcnic_adapter *adapter, u8 func_no)
+{
+ int err = -EIO;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ func_no,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_RESET_NPAR);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to issue reset partition%d\n", err);
+ err = -EIO;
+ }
+
+ return err;
+}
+
+/* Get eSwitch Capabilities */
+int qlcnic_get_eswitch_capabilities(struct qlcnic_adapter *adapter, u8 port,
+ struct qlcnic_eswitch *eswitch)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ port,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+ eswitch->port = arg1 & 0xf;
+ eswitch->active_vports = LSB(arg2);
+ eswitch->max_ucast_filters = MSB(arg2);
+ eswitch->max_active_vlans = LSB(MSW(arg2));
+ if (arg1 & BIT_6)
+ eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+ if (arg1 & BIT_7)
+ eswitch->flags |= QLCNIC_SWITCH_PROMISC_MODE;
+ if (arg1 & BIT_8)
+ eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get eswitch capabilities%d\n", err);
+ }
+
+ return err;
+}
+
+/* Get current status of eswitch */
+int qlcnic_get_eswitch_status(struct qlcnic_adapter *adapter, u8 port,
+ struct qlcnic_eswitch *eswitch)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ port,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS);
+
+ if (err == QLCNIC_RCODE_SUCCESS) {
+ arg1 = QLCRD32(adapter, QLCNIC_ARG1_CRB_OFFSET);
+ arg2 = QLCRD32(adapter, QLCNIC_ARG2_CRB_OFFSET);
+
+ eswitch->port = arg1 & 0xf;
+ eswitch->active_vports = LSB(arg2);
+ eswitch->active_ucast_filters = MSB(arg2);
+ eswitch->active_vlans = LSB(MSW(arg2));
+ if (arg1 & BIT_6)
+ eswitch->flags |= QLCNIC_SWITCH_VLAN_FILTERING;
+ if (arg1 & BIT_8)
+ eswitch->flags |= QLCNIC_SWITCH_PORT_MIRRORING;
+
+ } else {
+ dev_err(&adapter->pdev->dev,
+ "Failed to get eswitch status%d\n", err);
+ }
+
+ return err;
+}
+
+/* Enable/Disable eSwitch */
+int qlcnic_toggle_eswitch(struct qlcnic_adapter *adapter, u8 id, u8 enable)
+{
+ int err = -EIO;
+ u32 arg1, arg2;
+ struct qlcnic_eswitch *eswitch;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ eswitch = &adapter->eswitch[id];
+ if (!eswitch)
+ return err;
+
+ arg1 = eswitch->port | (enable ? BIT_4 : 0);
+ arg2 = eswitch->active_vports | (eswitch->max_ucast_filters << 8) |
+ (eswitch->max_active_vlans << 16);
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ arg2,
+ 0,
+ QLCNIC_CDRP_CMD_TOGGLE_ESWITCH);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to enable eswitch%d\n", eswitch->port);
+ eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+ err = -EIO;
+ } else {
+ eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+ dev_info(&adapter->pdev->dev,
+ "Enabled eSwitch for port %d\n", eswitch->port);
+ }
+
+ return err;
+}
+
+/* Configure eSwitch for port mirroring */
+int qlcnic_config_port_mirroring(struct qlcnic_adapter *adapter, u8 id,
+ u8 enable_mirroring, u8 pci_func)
+{
+ int err = -EIO;
+ u32 arg1;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC ||
+ !(adapter->eswitch[id].flags & QLCNIC_SWITCH_ENABLE))
+ return err;
+
+ arg1 = id | (enable_mirroring ? BIT_4 : 0);
+ arg1 |= pci_func << 8;
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_SET_PORTMIRRORING);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure port mirroring%d on eswitch:%d\n",
+ pci_func, id);
+ } else {
+ dev_info(&adapter->pdev->dev,
+ "Configured eSwitch %d for port mirroring:%d\n",
+ id, pci_func);
+ }
+
+ return err;
+}
+
+/* Configure eSwitch port */
+int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, u8 id,
+ int vlan_tagging, u8 discard_tagged, u8 promsc_mode,
+ u8 mac_learn, u8 pci_func, u16 vlan_id)
+{
+ int err = -EIO;
+ u32 arg1;
+ struct qlcnic_eswitch *eswitch;
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return err;
+
+ eswitch = &adapter->eswitch[id];
+ if (!(eswitch->flags & QLCNIC_SWITCH_ENABLE))
+ return err;
+
+ arg1 = eswitch->port | (discard_tagged ? BIT_4 : 0);
+ arg1 |= (promsc_mode ? BIT_6 : 0) | (mac_learn ? BIT_7 : 0);
+ arg1 |= pci_func << 8;
+ if (vlan_tagging)
+ arg1 |= BIT_5 | (vlan_id << 16);
+
+ err = qlcnic_issue_cmd(adapter,
+ adapter->ahw.pci_func,
+ adapter->fw_hal_version,
+ arg1,
+ 0,
+ 0,
+ QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH);
+
+ if (err != QLCNIC_RCODE_SUCCESS) {
+ dev_err(&adapter->pdev->dev,
+ "Failed to configure eswitch port%d\n", eswitch->port);
+ eswitch->flags |= QLCNIC_SWITCH_ENABLE;
+ } else {
+ eswitch->flags &= ~QLCNIC_SWITCH_ENABLE;
+ dev_info(&adapter->pdev->dev,
+ "Configured eSwitch for port %d\n", eswitch->port);
+ }
+
+ return err;
+}
diff --git a/drivers/net/qlcnic/qlcnic_ethtool.c b/drivers/net/qlcnic/qlcnic_ethtool.c
index 3bd514ec7e8f..3e4822ad5a80 100644
--- a/drivers/net/qlcnic/qlcnic_ethtool.c
+++ b/drivers/net/qlcnic/qlcnic_ethtool.c
@@ -683,13 +683,13 @@ static int qlcnic_loopback_test(struct net_device *netdev)
if (ret)
goto clear_it;
- ret = qlcnic_set_ilb_mode(adapter);
+ ret = adapter->nic_ops->set_ilb_mode(adapter);
if (ret)
goto done;
ret = qlcnic_do_ilb_test(adapter);
- qlcnic_clear_ilb_mode(adapter);
+ adapter->nic_ops->clear_ilb_mode(adapter);
done:
qlcnic_diag_free_res(netdev, max_sds_rings);
@@ -715,7 +715,8 @@ static int qlcnic_irq_test(struct net_device *netdev)
adapter->diag_cnt = 0;
ret = qlcnic_issue_cmd(adapter, adapter->ahw.pci_func,
- QLCHAL_VERSION, adapter->portnum, 0, 0, 0x00000011);
+ adapter->fw_hal_version, adapter->portnum,
+ 0, 0, 0x00000011);
if (ret)
goto done;
@@ -834,7 +835,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
struct qlcnic_adapter *adapter = netdev_priv(dev);
int ret;
- ret = qlcnic_config_led(adapter, 1, 0xf);
+ ret = adapter->nic_ops->config_led(adapter, 1, 0xf);
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to set LED blink state.\n");
@@ -843,7 +844,7 @@ static int qlcnic_blink_led(struct net_device *dev, u32 val)
msleep_interruptible(val * 1000);
- ret = qlcnic_config_led(adapter, 0, 0xf);
+ ret = adapter->nic_ops->config_led(adapter, 0, 0xf);
if (ret) {
dev_err(&adapter->pdev->dev,
"Failed to reset LED blink state.\n");
diff --git a/drivers/net/qlcnic/qlcnic_hdr.h b/drivers/net/qlcnic/qlcnic_hdr.h
index ad9d167723c4..7b81cab27002 100644
--- a/drivers/net/qlcnic/qlcnic_hdr.h
+++ b/drivers/net/qlcnic/qlcnic_hdr.h
@@ -208,6 +208,39 @@ enum {
QLCNIC_HW_PX_MAP_CRB_PGR0
};
+#define BIT_0 0x1
+#define BIT_1 0x2
+#define BIT_2 0x4
+#define BIT_3 0x8
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x100
+#define BIT_9 0x200
+#define BIT_10 0x400
+#define BIT_11 0x800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x10000
+#define BIT_17 0x20000
+#define BIT_18 0x40000
+#define BIT_19 0x80000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x1000000
+#define BIT_25 0x2000000
+#define BIT_26 0x4000000
+#define BIT_27 0x8000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
/* This field defines CRB adr [31:20] of the agents */
#define QLCNIC_HW_CRB_HUB_AGT_ADR_MN \
@@ -668,10 +701,11 @@ enum {
#define QLCNIC_CRB_DEV_REF_COUNT (QLCNIC_CAM_RAM(0x138))
#define QLCNIC_CRB_DEV_STATE (QLCNIC_CAM_RAM(0x140))
-#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
-#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
-#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
+#define QLCNIC_CRB_DRV_STATE (QLCNIC_CAM_RAM(0x144))
+#define QLCNIC_CRB_DRV_SCRATCH (QLCNIC_CAM_RAM(0x148))
+#define QLCNIC_CRB_DEV_PARTITION_INFO (QLCNIC_CAM_RAM(0x14c))
#define QLCNIC_CRB_DRV_IDC_VER (QLCNIC_CAM_RAM(0x174))
+#define QLCNIC_CRB_DEV_NPAR_STATE (QLCNIC_CAM_RAM(0x19c))
#define QLCNIC_ROM_DEV_INIT_TIMEOUT (0x3e885c)
#define QLCNIC_ROM_DRV_RESET_TIMEOUT (0x3e8860)
@@ -684,15 +718,26 @@ enum {
#define QLCNIC_DEV_FAILED 0x6
#define QLCNIC_DEV_QUISCENT 0x7
+#define QLCNIC_DEV_NPAR_NOT_RDY 0
+#define QLCNIC_DEV_NPAR_RDY 1
+
+#define QLC_DEV_CHECK_ACTIVE(VAL, FN) ((VAL) &= (1 << (FN * 4)))
#define QLC_DEV_SET_REF_CNT(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_CLR_REF_CNT(VAL, FN) ((VAL) &= ~(1 << (FN * 4)))
#define QLC_DEV_SET_RST_RDY(VAL, FN) ((VAL) |= (1 << (FN * 4)))
#define QLC_DEV_SET_QSCNT_RDY(VAL, FN) ((VAL) |= (2 << (FN * 4)))
#define QLC_DEV_CLR_RST_QSCNT(VAL, FN) ((VAL) &= ~(3 << (FN * 4)))
+#define QLC_DEV_GET_DRV(VAL, FN) (0xf & ((VAL) >> (FN * 4)))
+#define QLC_DEV_SET_DRV(VAL, FN) ((VAL) << (FN * 4))
+
+#define QLCNIC_TYPE_NIC 1
+#define QLCNIC_TYPE_FCOE 2
+#define QLCNIC_TYPE_ISCSI 3
+
#define QLCNIC_RCODE_DRIVER_INFO 0x20000000
-#define QLCNIC_RCODE_DRIVER_CAN_RELOAD 0x40000000
-#define QLCNIC_RCODE_FATAL_ERROR 0x80000000
+#define QLCNIC_RCODE_DRIVER_CAN_RELOAD BIT_30
+#define QLCNIC_RCODE_FATAL_ERROR BIT_31
#define QLCNIC_FWERROR_PEGNUM(code) ((code) & 0xff)
#define QLCNIC_FWERROR_CODE(code) ((code >> 8) & 0xfffff)
@@ -721,6 +766,35 @@ struct qlcnic_legacy_intr_set {
u32 pci_int_reg;
};
+#define QLCNIC_FW_API 0x1b216c
+#define QLCNIC_DRV_OP_MODE 0x1b2170
+#define QLCNIC_MSIX_BASE 0x132110
+#define QLCNIC_MAX_PCI_FUNC 8
+
+/* PCI function operational mode */
+enum {
+ QLCNIC_MGMT_FUNC = 0,
+ QLCNIC_PRIV_FUNC = 1,
+ QLCNIC_NON_PRIV_FUNC = 2
+};
+
+/* FW HAL api version */
+enum {
+ QLCNIC_FW_BASE = 1,
+ QLCNIC_FW_NPAR = 2
+};
+
+#define QLC_DEV_DRV_DEFAULT 0x11111111
+
+#define LSB(x) ((uint8_t)(x))
+#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8))
+
+#define LSW(x) ((uint16_t)((uint32_t)(x)))
+#define MSW(x) ((uint16_t)((uint32_t)(x) >> 16))
+
+#define LSD(x) ((uint32_t)((uint64_t)(x)))
+#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
#define QLCNIC_LEGACY_INTR_CONFIG \
{ \
{ \
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c
index 0c2e1f08f459..f776956d2d6c 100644
--- a/drivers/net/qlcnic/qlcnic_hw.c
+++ b/drivers/net/qlcnic/qlcnic_hw.c
@@ -538,7 +538,7 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
return rv;
}
-int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, int enable)
+int qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
{
struct qlcnic_nic_req req;
u64 word;
@@ -704,21 +704,15 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu)
return rc;
}
-int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u64 *mac)
+int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac)
{
- u32 crbaddr, mac_hi, mac_lo;
+ u32 crbaddr;
int pci_func = adapter->ahw.pci_func;
crbaddr = CRB_MAC_BLOCK_START +
(4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1));
- mac_lo = QLCRD32(adapter, crbaddr);
- mac_hi = QLCRD32(adapter, crbaddr+4);
-
- if (pci_func & 1)
- *mac = le64_to_cpu((mac_lo >> 16) | ((u64)mac_hi << 16));
- else
- *mac = le64_to_cpu((u64)mac_lo | ((u64)mac_hi << 32));
+ qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac);
return 0;
}
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 71a4e664ad76..635c99022f06 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -520,17 +520,16 @@ qlcnic_setup_idc_param(struct qlcnic_adapter *adapter) {
int timeo;
u32 val;
- val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
- val = (val >> (adapter->portnum * 4)) & 0xf;
-
- if ((val & 0x3) != 1) {
- dev_err(&adapter->pdev->dev, "Not an Ethernet NIC func=%u\n",
- val);
- return -EIO;
+ if (adapter->fw_hal_version == QLCNIC_FW_BASE) {
+ val = QLCRD32(adapter, QLCNIC_CRB_DEV_PARTITION_INFO);
+ val = QLC_DEV_GET_DRV(val, adapter->portnum);
+ if ((val & 0x3) != QLCNIC_TYPE_NIC) {
+ dev_err(&adapter->pdev->dev,
+ "Not an Ethernet NIC func=%u\n", val);
+ return -EIO;
+ }
+ adapter->physical_port = (val >> 2);
}
-
- adapter->physical_port = (val >> 2);
-
if (qlcnic_rom_fast_read(adapter, QLCNIC_ROM_DEV_INIT_TIMEOUT, &timeo))
timeo = 30;
@@ -1701,3 +1700,24 @@ qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
sds_ring->consumer = consumer;
writel(consumer, sds_ring->crb_sts_consumer);
}
+
+void
+qlcnic_fetch_mac(struct qlcnic_adapter *adapter, u32 off1, u32 off2,
+ u8 alt_mac, u8 *mac)
+{
+ u32 mac_low, mac_high;
+ int i;
+
+ mac_low = QLCRD32(adapter, off1);
+ mac_high = QLCRD32(adapter, off2);
+
+ if (alt_mac) {
+ mac_low |= (mac_low >> 16) | (mac_high << 16);
+ mac_high >>= 16;
+ }
+
+ for (i = 0; i < 2; i++)
+ mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+ for (i = 2; i < 6; i++)
+ mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 23ea9caa5261..99371bcaa547 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -65,6 +65,10 @@ static int load_fw_file;
module_param(load_fw_file, int, 0644);
MODULE_PARM_DESC(load_fw_file, "Load firmware from (0=flash, 1=file");
+static int qlcnic_config_npars;
+module_param(qlcnic_config_npars, int, 0644);
+MODULE_PARM_DESC(qlcnic_config_npars, "Configure NPARs (0=disabled, 1=enabled");
+
static int __devinit qlcnic_probe(struct pci_dev *pdev,
const struct pci_device_id *ent);
static void __devexit qlcnic_remove(struct pci_dev *pdev);
@@ -99,7 +103,14 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data);
static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
-
+static int qlcnic_start_firmware(struct qlcnic_adapter *);
+
+static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
+static void qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_set_ilb_mode(struct qlcnic_adapter *);
+static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
/* PCI Device ID Table */
#define ENTRY(device) \
{PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, (device)), \
@@ -307,19 +318,14 @@ static void qlcnic_init_msix_entries(struct qlcnic_adapter *adapter, int count)
static int
qlcnic_read_mac_addr(struct qlcnic_adapter *adapter)
{
- int i;
- unsigned char *p;
- u64 mac_addr;
+ u8 mac_addr[ETH_ALEN];
struct net_device *netdev = adapter->netdev;
struct pci_dev *pdev = adapter->pdev;
- if (qlcnic_get_mac_addr(adapter, &mac_addr) != 0)
+ if (adapter->nic_ops->get_mac_addr(adapter, mac_addr) != 0)
return -EIO;
- p = (unsigned char *)&mac_addr;
- for (i = 0; i < 6; i++)
- netdev->dev_addr[i] = *(p + 5 - i);
-
+ memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
memcpy(adapter->mac_addr, netdev->dev_addr, netdev->addr_len);
@@ -371,6 +377,33 @@ static const struct net_device_ops qlcnic_netdev_ops = {
#endif
};
+static struct qlcnic_nic_template qlcnic_ops = {
+ .get_mac_addr = qlcnic_get_mac_addr,
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_config_led,
+ .set_ilb_mode = qlcnic_set_ilb_mode,
+ .clear_ilb_mode = qlcnic_clear_ilb_mode,
+ .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_pf_ops = {
+ .get_mac_addr = qlcnic_get_mac_address,
+ .config_bridged_mode = qlcnic_config_bridged_mode,
+ .config_led = qlcnic_config_led,
+ .set_ilb_mode = qlcnic_set_ilb_mode,
+ .clear_ilb_mode = qlcnic_clear_ilb_mode,
+ .start_firmware = qlcnic_start_firmware
+};
+
+static struct qlcnic_nic_template qlcnic_vf_ops = {
+ .get_mac_addr = qlcnic_get_mac_address,
+ .config_bridged_mode = qlcnicvf_config_bridged_mode,
+ .config_led = qlcnicvf_config_led,
+ .set_ilb_mode = qlcnicvf_set_ilb_mode,
+ .clear_ilb_mode = qlcnicvf_clear_ilb_mode,
+ .start_firmware = qlcnicvf_start_firmware
+};
+
static void
qlcnic_setup_intr(struct qlcnic_adapter *adapter)
{
@@ -453,6 +486,132 @@ qlcnic_cleanup_pci_map(struct qlcnic_adapter *adapter)
}
static int
+qlcnic_set_function_modes(struct qlcnic_adapter *adapter)
+{
+ u8 id;
+ u32 ref_count;
+ int i, ret = 1;
+ u32 data = QLCNIC_MGMT_FUNC;
+ void __iomem *priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+
+ /* If other drivers are not in use set their privilege level */
+ ref_count = QLCRD32(adapter, QLCNIC_CRB_DEV_REF_COUNT);
+ ret = qlcnic_api_lock(adapter);
+ if (ret)
+ goto err_lock;
+ if (QLC_DEV_CLR_REF_CNT(ref_count, adapter->ahw.pci_func))
+ goto err_npar;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ id = adapter->npars[i].id;
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC ||
+ id == adapter->ahw.pci_func)
+ continue;
+ data |= (qlcnic_config_npars & QLC_DEV_SET_DRV(0xf, id));
+ }
+ writel(data, priv_op);
+
+err_npar:
+ qlcnic_api_unlock(adapter);
+err_lock:
+ return ret;
+}
+
+static u8
+qlcnic_set_mgmt_driver(struct qlcnic_adapter *adapter)
+{
+ u8 i, ret = 0;
+
+ if (qlcnic_get_pci_info(adapter))
+ return ret;
+ /* Set the eswitch */
+ for (i = 0; i < QLCNIC_NIU_MAX_XG_PORTS; i++) {
+ if (!qlcnic_get_eswitch_capabilities(adapter, i,
+ &adapter->eswitch[i])) {
+ ret++;
+ qlcnic_toggle_eswitch(adapter, i, ret);
+ }
+ }
+ return ret;
+}
+
+static u32
+qlcnic_get_driver_mode(struct qlcnic_adapter *adapter)
+{
+ void __iomem *msix_base_addr;
+ void __iomem *priv_op;
+ u32 func;
+ u32 msix_base;
+ u32 op_mode, priv_level;
+
+ /* Determine FW API version */
+ adapter->fw_hal_version = readl(adapter->ahw.pci_base0 + QLCNIC_FW_API);
+ if (adapter->fw_hal_version == ~0) {
+ adapter->nic_ops = &qlcnic_ops;
+ adapter->fw_hal_version = QLCNIC_FW_BASE;
+ adapter->ahw.pci_func = PCI_FUNC(adapter->pdev->devfn);
+ dev_info(&adapter->pdev->dev,
+ "FW does not support nic partion\n");
+ return adapter->fw_hal_version;
+ }
+
+ /* Find PCI function number */
+ pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
+ msix_base_addr = adapter->ahw.pci_base0 + QLCNIC_MSIX_BASE;
+ msix_base = readl(msix_base_addr);
+ func = (func - msix_base)/QLCNIC_MSIX_TBL_PGSIZE;
+ adapter->ahw.pci_func = func;
+
+ /* Determine function privilege level */
+ priv_op = adapter->ahw.pci_base0 + QLCNIC_DRV_OP_MODE;
+ op_mode = readl(priv_op);
+ if (op_mode == QLC_DEV_DRV_DEFAULT) {
+ priv_level = QLCNIC_MGMT_FUNC;
+ if (qlcnic_api_lock(adapter))
+ return 0;
+ op_mode = (op_mode & ~QLC_DEV_SET_DRV(0xf, func)) |
+ (QLC_DEV_SET_DRV(QLCNIC_MGMT_FUNC, func));
+ writel(op_mode, priv_op);
+ qlcnic_api_unlock(adapter);
+
+ } else
+ priv_level = QLC_DEV_GET_DRV(op_mode, adapter->ahw.pci_func);
+
+ switch (priv_level) {
+ case QLCNIC_MGMT_FUNC:
+ adapter->op_mode = QLCNIC_MGMT_FUNC;
+ adapter->nic_ops = &qlcnic_pf_ops;
+ /* Set privilege level for other functions */
+ if (qlcnic_config_npars)
+ qlcnic_set_function_modes(adapter);
+ qlcnic_dev_set_npar_ready(adapter);
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Management function\n",
+ adapter->fw_hal_version);
+ break;
+ case QLCNIC_PRIV_FUNC:
+ adapter->op_mode = QLCNIC_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d, Privileged function\n",
+ adapter->fw_hal_version);
+ adapter->nic_ops = &qlcnic_pf_ops;
+ break;
+ case QLCNIC_NON_PRIV_FUNC:
+ adapter->op_mode = QLCNIC_NON_PRIV_FUNC;
+ dev_info(&adapter->pdev->dev,
+ "HAL Version: %d Non Privileged function\n",
+ adapter->fw_hal_version);
+ adapter->nic_ops = &qlcnic_vf_ops;
+ break;
+ default:
+ dev_info(&adapter->pdev->dev, "Unknown function mode: %d\n",
+ priv_level);
+ return 0;
+ }
+ return adapter->fw_hal_version;
+}
+
+static int
qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
{
void __iomem *mem_ptr0 = NULL;
@@ -460,7 +619,6 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
unsigned long mem_len, pci_len0 = 0;
struct pci_dev *pdev = adapter->pdev;
- int pci_func = adapter->ahw.pci_func;
/* remap phys address */
mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */
@@ -483,8 +641,13 @@ qlcnic_setup_pci_map(struct qlcnic_adapter *adapter)
adapter->ahw.pci_base0 = mem_ptr0;
adapter->ahw.pci_len0 = pci_len0;
+ if (!qlcnic_get_driver_mode(adapter)) {
+ iounmap(adapter->ahw.pci_base0);
+ return -EIO;
+ }
+
adapter->ahw.ocm_win_crb = qlcnic_get_ioaddr(adapter,
- QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(pci_func)));
+ QLCNIC_PCIX_PS_REG(PCIX_OCM_WINDOW_REG(adapter->ahw.pci_func)));
return 0;
}
@@ -553,7 +716,10 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
dev_info(&pdev->dev, "firmware v%d.%d.%d\n",
fw_major, fw_minor, fw_build);
- adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
+ if (adapter->fw_hal_version == QLCNIC_FW_NPAR)
+ qlcnic_get_nic_info(adapter, adapter->ahw.pci_func);
+ else
+ adapter->capabilities = QLCRD32(adapter, CRB_FW_CAPABILITIES_1);
adapter->flags &= ~QLCNIC_LRO_ENABLED;
@@ -631,8 +797,14 @@ wait_init:
QLCWR32(adapter, QLCNIC_CRB_DEV_STATE, QLCNIC_DEV_READY);
qlcnic_idc_debug_info(adapter, 1);
+ qlcnic_dev_set_npar_ready(adapter);
+
qlcnic_check_options(adapter);
+ if (adapter->fw_hal_version != QLCNIC_FW_BASE &&
+ adapter->op_mode == QLCNIC_MGMT_FUNC)
+ qlcnic_set_mgmt_driver(adapter);
+
adapter->need_fw_reset = 0;
qlcnic_release_firmware(adapter);
@@ -977,12 +1149,11 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
- netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
- netdev->features |= (NETIF_F_GRO);
- netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
+ netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_TSO | NETIF_F_TSO6);
- netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
- netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
+ netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6);
if (pci_using_dac) {
netdev->features |= NETIF_F_HIGHDMA;
@@ -1036,7 +1207,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct net_device *netdev = NULL;
struct qlcnic_adapter *adapter = NULL;
int err;
- int pci_func_id = PCI_FUNC(pdev->devfn);
uint8_t revision_id;
uint8_t pci_using_dac;
@@ -1072,7 +1242,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->dev_rst_time = jiffies;
- adapter->ahw.pci_func = pci_func_id;
revision_id = pdev->revision;
adapter->ahw.revision_id = revision_id;
@@ -1088,7 +1257,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_free_netdev;
/* This will be reset for mezz cards */
- adapter->portnum = pci_func_id;
+ adapter->portnum = adapter->ahw.pci_func;
err = qlcnic_get_board_info(adapter);
if (err) {
@@ -1102,7 +1271,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (qlcnic_setup_idc_param(adapter))
goto err_out_iounmap;
- err = qlcnic_start_firmware(adapter);
+ err = adapter->nic_ops->start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "Loading fw failed.Please Reboot\n");
goto err_out_decr_ref;
@@ -1175,6 +1344,11 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
qlcnic_detach(adapter);
+ if (adapter->npars != NULL)
+ kfree(adapter->npars);
+ if (adapter->eswitch != NULL)
+ kfree(adapter->eswitch);
+
qlcnic_clr_all_drv_state(adapter);
clear_bit(__QLCNIC_RESETTING, &adapter->state);
@@ -1263,7 +1437,7 @@ qlcnic_resume(struct pci_dev *pdev)
pci_set_master(pdev);
pci_restore_state(pdev);
- err = qlcnic_start_firmware(adapter);
+ err = adapter->nic_ops->start_firmware(adapter);
if (err) {
dev_err(&pdev->dev, "failed to start firmware\n");
return err;
@@ -1340,11 +1514,11 @@ qlcnic_tso_check(struct net_device *netdev,
u8 opcode = TX_ETHER_PKT;
__be16 protocol = skb->protocol;
u16 flags = 0, vid = 0;
- u32 producer;
int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ u32 producer = tx_ring->producer;
if (protocol == cpu_to_be16(ETH_P_8021Q)) {
@@ -1360,6 +1534,11 @@ qlcnic_tso_check(struct net_device *netdev,
vlan_oob = 1;
}
+ if (*(skb->data) & BIT_0) {
+ flags |= BIT_0;
+ memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+ }
+
if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
skb_shinfo(skb)->gso_size > 0) {
@@ -1409,7 +1588,6 @@ qlcnic_tso_check(struct net_device *netdev,
/* For LSO, we need to copy the MAC/IP/TCP headers into
* the descriptor ring
*/
- producer = tx_ring->producer;
copied = 0;
offset = 2;
@@ -2109,7 +2287,7 @@ qlcnic_fwinit_work(struct work_struct *work)
{
struct qlcnic_adapter *adapter = container_of(work,
struct qlcnic_adapter, fw_work.work);
- u32 dev_state = 0xf;
+ u32 dev_state = 0xf, npar_state;
if (qlcnic_api_lock(adapter))
goto err_ret;
@@ -2122,6 +2300,19 @@ qlcnic_fwinit_work(struct work_struct *work)
return;
}
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ npar_state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+ if (npar_state == QLCNIC_DEV_NPAR_RDY) {
+ qlcnic_api_unlock(adapter);
+ goto wait_npar;
+ } else {
+ qlcnic_schedule_work(adapter, qlcnic_fwinit_work,
+ FW_POLL_DELAY);
+ qlcnic_api_unlock(adapter);
+ return;
+ }
+ }
+
if (adapter->fw_wait_cnt++ > adapter->reset_ack_timeo) {
dev_err(&adapter->pdev->dev, "Reset:Failed to get ack %d sec\n",
adapter->reset_ack_timeo);
@@ -2154,7 +2345,7 @@ skip_ack_check:
qlcnic_api_unlock(adapter);
- if (!qlcnic_start_firmware(adapter)) {
+ if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return;
}
@@ -2163,6 +2354,7 @@ skip_ack_check:
qlcnic_api_unlock(adapter);
+wait_npar:
dev_state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
QLCDB(adapter, HW, "Func waiting: Device state=%u\n", dev_state);
@@ -2177,7 +2369,7 @@ skip_ack_check:
break;
default:
- if (!qlcnic_start_firmware(adapter)) {
+ if (!adapter->nic_ops->start_firmware(adapter)) {
qlcnic_schedule_work(adapter, qlcnic_attach_work, 0);
return;
}
@@ -2251,6 +2443,30 @@ qlcnic_dev_request_reset(struct qlcnic_adapter *adapter)
qlcnic_api_unlock(adapter);
}
+/* Transit to NPAR READY state from NPAR NOT READY state */
+static void
+qlcnic_dev_set_npar_ready(struct qlcnic_adapter *adapter)
+{
+ u32 state;
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC ||
+ adapter->fw_hal_version == QLCNIC_FW_BASE)
+ return;
+
+ if (qlcnic_api_lock(adapter))
+ return;
+
+ state = QLCRD32(adapter, QLCNIC_CRB_DEV_NPAR_STATE);
+
+ if (state != QLCNIC_DEV_NPAR_RDY) {
+ QLCWR32(adapter, QLCNIC_CRB_DEV_NPAR_STATE,
+ QLCNIC_DEV_NPAR_RDY);
+ QLCDB(adapter, DRV, "NPAR READY state set\n");
+ }
+
+ qlcnic_api_unlock(adapter);
+}
+
static void
qlcnic_schedule_work(struct qlcnic_adapter *adapter,
work_func_t func, int delay)
@@ -2365,6 +2581,46 @@ reschedule:
qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
}
+static int
+qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
+{
+ int err;
+
+ err = qlcnic_can_start_firmware(adapter);
+ if (err)
+ return err;
+
+ qlcnic_check_options(adapter);
+
+ adapter->need_fw_reset = 0;
+
+ return err;
+}
+
+static int
+qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+ return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+ return -EOPNOTSUPP;
+}
+
+static int
+qlcnicvf_set_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ return -EOPNOTSUPP;
+}
+
+static void
+qlcnicvf_clear_ilb_mode(struct qlcnic_adapter *adapter)
+{
+ return;
+}
+
static ssize_t
qlcnic_store_bridged_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
@@ -2382,7 +2638,7 @@ qlcnic_store_bridged_mode(struct device *dev,
if (strict_strtoul(buf, 2, &new))
goto err_out;
- if (!qlcnic_config_bridged_mode(adapter, !!new))
+ if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
ret = len;
err_out:
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 20624ba44a37..bfb8b327f2fd 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1062,7 +1062,7 @@ struct tx_buf_desc {
#define TX_DESC_LEN_MASK 0x000fffff
#define TX_DESC_C 0x40000000
#define TX_DESC_E 0x80000000
-} __attribute((packed));
+} __packed;
/*
* IOCB Definitions...
@@ -1095,7 +1095,7 @@ struct ob_mac_iocb_req {
__le16 vlan_tci;
__le16 reserved4;
struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
struct ob_mac_iocb_rsp {
u8 opcode; /* */
@@ -1112,7 +1112,7 @@ struct ob_mac_iocb_rsp {
u32 tid;
u32 txq_idx;
__le32 reserved[13];
-} __attribute((packed));
+} __packed;
struct ob_mac_tso_iocb_req {
u8 opcode;
@@ -1140,7 +1140,7 @@ struct ob_mac_tso_iocb_req {
__le16 vlan_tci;
__le16 mss;
struct tx_buf_desc tbd[TX_DESC_PER_IOCB];
-} __attribute((packed));
+} __packed;
struct ob_mac_tso_iocb_rsp {
u8 opcode;
@@ -1157,7 +1157,7 @@ struct ob_mac_tso_iocb_rsp {
u32 tid;
u32 txq_idx;
__le32 reserved2[13];
-} __attribute((packed));
+} __packed;
struct ib_mac_iocb_rsp {
u8 opcode; /* 0x20 */
@@ -1216,7 +1216,7 @@ struct ib_mac_iocb_rsp {
#define IB_MAC_IOCB_RSP_HL 0x80
__le32 hdr_len; /* */
__le64 hdr_addr; /* */
-} __attribute((packed));
+} __packed;
struct ib_ae_iocb_rsp {
u8 opcode;
@@ -1237,7 +1237,7 @@ struct ib_ae_iocb_rsp {
#define PCI_ERR_ANON_BUF_RD 0x40
u8 q_id;
__le32 reserved[15];
-} __attribute((packed));
+} __packed;
/*
* These three structures are for generic
@@ -1249,7 +1249,7 @@ struct ql_net_rsp_iocb {
__le16 length;
__le32 tid;
__le32 reserved[14];
-} __attribute((packed));
+} __packed;
struct net_req_iocb {
u8 opcode;
@@ -1257,7 +1257,7 @@ struct net_req_iocb {
__le16 flags1;
__le32 tid;
__le32 reserved1[30];
-} __attribute((packed));
+} __packed;
/*
* tx ring initialization control block for chip.
@@ -1283,7 +1283,7 @@ struct wqicb {
__le16 rid;
__le64 addr;
__le64 cnsmr_idx_addr;
-} __attribute((packed));
+} __packed;
/*
* rx ring initialization control block for chip.
@@ -1317,7 +1317,7 @@ struct cqicb {
__le64 sbq_addr;
__le16 sbq_buf_size;
__le16 sbq_len; /* entry count */
-} __attribute((packed));
+} __packed;
struct ricb {
u8 base_cq;
@@ -1335,7 +1335,7 @@ struct ricb {
u8 hash_cq_id[1024];
__le32 ipv6_hash_key[10];
__le32 ipv4_hash_key[4];
-} __attribute((packed));
+} __packed;
/* SOFTWARE/DRIVER DATA STRUCTURES. */
diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c
index 9a251acf5ab8..7d482a2316ac 100644
--- a/drivers/net/r6040.c
+++ b/drivers/net/r6040.c
@@ -44,12 +44,13 @@
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/uaccess.h>
+#include <linux/phy.h>
#include <asm/processor.h>
#define DRV_NAME "r6040"
-#define DRV_VERSION "0.25"
-#define DRV_RELDATE "20Aug2009"
+#define DRV_VERSION "0.26"
+#define DRV_RELDATE "30May2010"
/* PHY CHIP Address */
#define PHY1_ADDR 1 /* For MAC1 */
@@ -179,7 +180,6 @@ struct r6040_descriptor {
struct r6040_private {
spinlock_t lock; /* driver lock */
- struct timer_list timer;
struct pci_dev *pdev;
struct r6040_descriptor *rx_insert_ptr;
struct r6040_descriptor *rx_remove_ptr;
@@ -189,13 +189,15 @@ struct r6040_private {
struct r6040_descriptor *tx_ring;
dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
- u16 tx_free_desc, phy_addr, phy_mode;
+ u16 tx_free_desc, phy_addr;
u16 mcr0, mcr1;
- u16 switch_sig;
struct net_device *dev;
- struct mii_if_info mii_if;
+ struct mii_bus *mii_bus;
struct napi_struct napi;
void __iomem *base;
+ struct phy_device *phydev;
+ int old_link;
+ int old_duplex;
};
static char version[] __devinitdata = KERN_INFO DRV_NAME
@@ -238,20 +240,30 @@ static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val
}
}
-static int r6040_mdio_read(struct net_device *dev, int mii_id, int reg)
+static int r6040_mdiobus_read(struct mii_bus *bus, int phy_addr, int reg)
{
+ struct net_device *dev = bus->priv;
struct r6040_private *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
- return (r6040_phy_read(ioaddr, lp->phy_addr, reg));
+ return r6040_phy_read(ioaddr, phy_addr, reg);
}
-static void r6040_mdio_write(struct net_device *dev, int mii_id, int reg, int val)
+static int r6040_mdiobus_write(struct mii_bus *bus, int phy_addr,
+ int reg, u16 value)
{
+ struct net_device *dev = bus->priv;
struct r6040_private *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
- r6040_phy_write(ioaddr, lp->phy_addr, reg, val);
+ r6040_phy_write(ioaddr, phy_addr, reg, value);
+
+ return 0;
+}
+
+static int r6040_mdiobus_reset(struct mii_bus *bus)
+{
+ return 0;
}
static void r6040_free_txbufs(struct net_device *dev)
@@ -408,10 +420,9 @@ static void r6040_tx_timeout(struct net_device *dev)
void __iomem *ioaddr = priv->base;
netdev_warn(dev, "transmit timed out, int enable %4.4x "
- "status %4.4x, PHY status %4.4x\n",
+ "status %4.4x\n",
ioread16(ioaddr + MIER),
- ioread16(ioaddr + MISR),
- r6040_mdio_read(dev, priv->mii_if.phy_id, MII_BMSR));
+ ioread16(ioaddr + MISR));
dev->stats.tx_errors++;
@@ -463,9 +474,6 @@ static int r6040_close(struct net_device *dev)
struct r6040_private *lp = netdev_priv(dev);
struct pci_dev *pdev = lp->pdev;
- /* deleted timer */
- del_timer_sync(&lp->timer);
-
spin_lock_irq(&lp->lock);
napi_disable(&lp->napi);
netif_stop_queue(dev);
@@ -495,64 +503,14 @@ static int r6040_close(struct net_device *dev)
return 0;
}
-/* Status of PHY CHIP */
-static int r6040_phy_mode_chk(struct net_device *dev)
-{
- struct r6040_private *lp = netdev_priv(dev);
- void __iomem *ioaddr = lp->base;
- int phy_dat;
-
- /* PHY Link Status Check */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
- if (!(phy_dat & 0x4))
- phy_dat = 0x8000; /* Link Failed, full duplex */
-
- /* PHY Chip Auto-Negotiation Status */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 1);
- if (phy_dat & 0x0020) {
- /* Auto Negotiation Mode */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 5);
- phy_dat &= r6040_phy_read(ioaddr, lp->phy_addr, 4);
- if (phy_dat & 0x140)
- /* Force full duplex */
- phy_dat = 0x8000;
- else
- phy_dat = 0;
- } else {
- /* Force Mode */
- phy_dat = r6040_phy_read(ioaddr, lp->phy_addr, 0);
- if (phy_dat & 0x100)
- phy_dat = 0x8000;
- else
- phy_dat = 0x0000;
- }
-
- return phy_dat;
-};
-
-static void r6040_set_carrier(struct mii_if_info *mii)
-{
- if (r6040_phy_mode_chk(mii->dev)) {
- /* autoneg is off: Link is always assumed to be up */
- if (!netif_carrier_ok(mii->dev))
- netif_carrier_on(mii->dev);
- } else
- r6040_phy_mode_chk(mii->dev);
-}
-
static int r6040_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct r6040_private *lp = netdev_priv(dev);
- struct mii_ioctl_data *data = if_mii(rq);
- int rc;
- if (!netif_running(dev))
+ if (!lp->phydev)
return -EINVAL;
- spin_lock_irq(&lp->lock);
- rc = generic_mii_ioctl(&lp->mii_if, data, cmd, NULL);
- spin_unlock_irq(&lp->lock);
- r6040_set_carrier(&lp->mii_if);
- return rc;
+
+ return phy_mii_ioctl(lp->phydev, if_mii(rq), cmd);
}
static int r6040_rx(struct net_device *dev, int limit)
@@ -751,26 +709,6 @@ static int r6040_up(struct net_device *dev)
if (ret)
return ret;
- /* Read the PHY ID */
- lp->switch_sig = r6040_phy_read(ioaddr, 0, 2);
-
- if (lp->switch_sig == ICPLUS_PHY_ID) {
- r6040_phy_write(ioaddr, 29, 31, 0x175C); /* Enable registers */
- lp->phy_mode = 0x8000;
- } else {
- /* PHY Mode Check */
- r6040_phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
- r6040_phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
-
- if (PHY_MODE == 0x3100)
- lp->phy_mode = r6040_phy_mode_chk(dev);
- else
- lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
- }
-
- /* Set duplex mode */
- lp->mcr0 |= lp->phy_mode;
-
/* improve performance (by RDC guys) */
r6040_phy_write(ioaddr, 30, 17, (r6040_phy_read(ioaddr, 30, 17) | 0x4000));
r6040_phy_write(ioaddr, 30, 17, ~((~r6040_phy_read(ioaddr, 30, 17)) | 0x2000));
@@ -783,35 +721,6 @@ static int r6040_up(struct net_device *dev)
return 0;
}
-/*
- A periodic timer routine
- Polling PHY Chip Link Status
-*/
-static void r6040_timer(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct r6040_private *lp = netdev_priv(dev);
- void __iomem *ioaddr = lp->base;
- u16 phy_mode;
-
- /* Polling PHY Chip Status */
- if (PHY_MODE == 0x3100)
- phy_mode = r6040_phy_mode_chk(dev);
- else
- phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
-
- if (phy_mode != lp->phy_mode) {
- lp->phy_mode = phy_mode;
- lp->mcr0 = (lp->mcr0 & 0x7fff) | phy_mode;
- iowrite16(lp->mcr0, ioaddr);
- }
-
- /* Timer active again */
- mod_timer(&lp->timer, round_jiffies(jiffies + HZ));
-
- /* Check media */
- mii_check_media(&lp->mii_if, 1, 1);
-}
/* Read/set MAC address routines */
static void r6040_mac_address(struct net_device *dev)
@@ -873,10 +782,6 @@ static int r6040_open(struct net_device *dev)
napi_enable(&lp->napi);
netif_start_queue(dev);
- /* set and active a timer process */
- setup_timer(&lp->timer, r6040_timer, (unsigned long) dev);
- if (lp->switch_sig != ICPLUS_PHY_ID)
- mod_timer(&lp->timer, jiffies + HZ);
return 0;
}
@@ -1015,40 +920,22 @@ static void netdev_get_drvinfo(struct net_device *dev,
static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct r6040_private *rp = netdev_priv(dev);
- int rc;
-
- spin_lock_irq(&rp->lock);
- rc = mii_ethtool_gset(&rp->mii_if, cmd);
- spin_unlock_irq(&rp->lock);
- return rc;
+ return phy_ethtool_gset(rp->phydev, cmd);
}
static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct r6040_private *rp = netdev_priv(dev);
- int rc;
-
- spin_lock_irq(&rp->lock);
- rc = mii_ethtool_sset(&rp->mii_if, cmd);
- spin_unlock_irq(&rp->lock);
- r6040_set_carrier(&rp->mii_if);
-
- return rc;
-}
-
-static u32 netdev_get_link(struct net_device *dev)
-{
- struct r6040_private *rp = netdev_priv(dev);
- return mii_link_ok(&rp->mii_if);
+ return phy_ethtool_sset(rp->phydev, cmd);
}
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
- .get_link = netdev_get_link,
+ .get_link = ethtool_op_get_link,
};
static const struct net_device_ops r6040_netdev_ops = {
@@ -1067,6 +954,79 @@ static const struct net_device_ops r6040_netdev_ops = {
#endif
};
+static void r6040_adjust_link(struct net_device *dev)
+{
+ struct r6040_private *lp = netdev_priv(dev);
+ struct phy_device *phydev = lp->phydev;
+ int status_changed = 0;
+ void __iomem *ioaddr = lp->base;
+
+ BUG_ON(!phydev);
+
+ if (lp->old_link != phydev->link) {
+ status_changed = 1;
+ lp->old_link = phydev->link;
+ }
+
+ /* reflect duplex change */
+ if (phydev->link && (lp->old_duplex != phydev->duplex)) {
+ lp->mcr0 |= (phydev->duplex == DUPLEX_FULL ? 0x8000 : 0);
+ iowrite16(lp->mcr0, ioaddr);
+
+ status_changed = 1;
+ lp->old_duplex = phydev->duplex;
+ }
+
+ if (status_changed) {
+ pr_info("%s: link %s", dev->name, phydev->link ?
+ "UP" : "DOWN");
+ if (phydev->link)
+ pr_cont(" - %d/%s", phydev->speed,
+ DUPLEX_FULL == phydev->duplex ? "full" : "half");
+ pr_cont("\n");
+ }
+}
+
+static int r6040_mii_probe(struct net_device *dev)
+{
+ struct r6040_private *lp = netdev_priv(dev);
+ struct phy_device *phydev = NULL;
+
+ phydev = phy_find_first(lp->mii_bus);
+ if (!phydev) {
+ dev_err(&lp->pdev->dev, "no PHY found\n");
+ return -ENODEV;
+ }
+
+ phydev = phy_connect(dev, dev_name(&phydev->dev), &r6040_adjust_link,
+ 0, PHY_INTERFACE_MODE_MII);
+
+ if (IS_ERR(phydev)) {
+ dev_err(&lp->pdev->dev, "could not attach to PHY\n");
+ return PTR_ERR(phydev);
+ }
+
+ /* mask with MAC supported features */
+ phydev->supported &= (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_MII
+ | SUPPORTED_TP);
+
+ phydev->advertising = phydev->supported;
+ lp->phydev = phydev;
+ lp->old_link = 0;
+ lp->old_duplex = -1;
+
+ dev_info(&lp->pdev->dev, "attached PHY driver [%s] "
+ "(mii_bus:phy_addr=%s)\n",
+ phydev->drv->name, dev_name(&phydev->dev));
+
+ return 0;
+}
+
static int __devinit r6040_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -1077,6 +1037,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
static int card_idx = -1;
int bar = 0;
u16 *adrp;
+ int i;
printk("%s\n", version);
@@ -1163,7 +1124,6 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
/* Init RDC private data */
lp->mcr0 = 0x1002;
lp->phy_addr = phy_table[card_idx];
- lp->switch_sig = 0;
/* The RDC-specific entries in the device structure. */
dev->netdev_ops = &r6040_netdev_ops;
@@ -1171,28 +1131,54 @@ static int __devinit r6040_init_one(struct pci_dev *pdev,
dev->watchdog_timeo = TX_TIMEOUT;
netif_napi_add(dev, &lp->napi, r6040_poll, 64);
- lp->mii_if.dev = dev;
- lp->mii_if.mdio_read = r6040_mdio_read;
- lp->mii_if.mdio_write = r6040_mdio_write;
- lp->mii_if.phy_id = lp->phy_addr;
- lp->mii_if.phy_id_mask = 0x1f;
- lp->mii_if.reg_num_mask = 0x1f;
-
- /* Check the vendor ID on the PHY, if 0xffff assume none attached */
- if (r6040_phy_read(ioaddr, lp->phy_addr, 2) == 0xffff) {
- dev_err(&pdev->dev, "Failed to detect an attached PHY\n");
- err = -ENODEV;
+
+ lp->mii_bus = mdiobus_alloc();
+ if (!lp->mii_bus) {
+ dev_err(&pdev->dev, "mdiobus_alloc() failed\n");
goto err_out_unmap;
}
+ lp->mii_bus->priv = dev;
+ lp->mii_bus->read = r6040_mdiobus_read;
+ lp->mii_bus->write = r6040_mdiobus_write;
+ lp->mii_bus->reset = r6040_mdiobus_reset;
+ lp->mii_bus->name = "r6040_eth_mii";
+ snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "%x", card_idx);
+ lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
+ if (!lp->mii_bus->irq) {
+ dev_err(&pdev->dev, "mii_bus irq allocation failed\n");
+ goto err_out_mdio;
+ }
+
+ for (i = 0; i < PHY_MAX_ADDR; i++)
+ lp->mii_bus->irq[i] = PHY_POLL;
+
+ err = mdiobus_register(lp->mii_bus);
+ if (err) {
+ dev_err(&pdev->dev, "failed to register MII bus\n");
+ goto err_out_mdio_irq;
+ }
+
+ err = r6040_mii_probe(dev);
+ if (err) {
+ dev_err(&pdev->dev, "failed to probe MII bus\n");
+ goto err_out_mdio_unregister;
+ }
+
/* Register net device. After this dev->name assign */
err = register_netdev(dev);
if (err) {
dev_err(&pdev->dev, "Failed to register net device\n");
- goto err_out_unmap;
+ goto err_out_mdio_unregister;
}
return 0;
+err_out_mdio_unregister:
+ mdiobus_unregister(lp->mii_bus);
+err_out_mdio_irq:
+ kfree(lp->mii_bus->irq);
+err_out_mdio:
+ mdiobus_free(lp->mii_bus);
err_out_unmap:
pci_iounmap(pdev, ioaddr);
err_out_free_res:
@@ -1206,8 +1192,12 @@ err_out:
static void __devexit r6040_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct r6040_private *lp = netdev_priv(dev);
unregister_netdev(dev);
+ mdiobus_unregister(lp->mii_bus);
+ kfree(lp->mii_bus->irq);
+ mdiobus_free(lp->mii_bus);
pci_release_regions(pdev);
free_netdev(dev);
pci_disable_device(pdev);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 217e709bda3e..6949504589db 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -88,7 +88,7 @@ static const int multicast_filter_limit = 32;
#define RTL_W32(reg, val32) writel ((val32), ioaddr + (reg))
#define RTL_R8(reg) readb (ioaddr + (reg))
#define RTL_R16(reg) readw (ioaddr + (reg))
-#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
+#define RTL_R32(reg) readl (ioaddr + (reg))
enum mac_version {
RTL_GIGA_MAC_NONE = 0x00,
@@ -559,6 +559,11 @@ static void mdio_write(void __iomem *ioaddr, int reg_addr, int value)
break;
udelay(25);
}
+ /*
+ * Some configurations require a small delay even after the write
+ * completed indication or the next write might fail.
+ */
+ udelay(25);
}
static int mdio_read(void __iomem *ioaddr, int reg_addr)
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 156460527231..26b0cc219204 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,6 +27,7 @@
#include "nic.h"
#include "mcdi.h"
+#include "workarounds.h"
/**************************************************************************
*
@@ -92,13 +93,6 @@ const char *efx_reset_type_names[] = {
#define EFX_MAX_MTU (9 * 1024)
-/* RX slow fill workqueue. If memory allocation fails in the fast path,
- * a work item is pushed onto this work queue to retry the allocation later,
- * to avoid the NIC being starved of RX buffers. Since this is a per cpu
- * workqueue, there is nothing to be gained in making it per NIC
- */
-static struct workqueue_struct *refill_workqueue;
-
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
* queued onto this work queue. This is not a per-nic work queue, because
* efx_reset_work() acquires the rtnl lock, so resets are naturally serialised.
@@ -475,7 +469,8 @@ static void efx_init_channels(struct efx_nic *efx)
efx->rx_buffer_len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
efx->type->rx_buffer_padding);
- efx->rx_buffer_order = get_order(efx->rx_buffer_len);
+ efx->rx_buffer_order = get_order(efx->rx_buffer_len +
+ sizeof(struct efx_rx_page_state));
/* Initialise the channels */
efx_for_each_channel(channel, efx) {
@@ -515,11 +510,11 @@ static void efx_start_channel(struct efx_channel *channel)
channel->enabled = true;
smp_wmb();
- napi_enable(&channel->napi_str);
-
- /* Load up RX descriptors */
+ /* Fill the queues before enabling NAPI */
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fast_push_rx_descriptors(rx_queue);
+
+ napi_enable(&channel->napi_str);
}
/* This disables event queue processing and packet transmission.
@@ -528,8 +523,6 @@ static void efx_start_channel(struct efx_channel *channel)
*/
static void efx_stop_channel(struct efx_channel *channel)
{
- struct efx_rx_queue *rx_queue;
-
if (!channel->enabled)
return;
@@ -537,12 +530,6 @@ static void efx_stop_channel(struct efx_channel *channel)
channel->enabled = false;
napi_disable(&channel->napi_str);
-
- /* Ensure that any worker threads have exited or will be no-ops */
- efx_for_each_channel_rx_queue(rx_queue, channel) {
- spin_lock_bh(&rx_queue->add_lock);
- spin_unlock_bh(&rx_queue->add_lock);
- }
}
static void efx_fini_channels(struct efx_nic *efx)
@@ -556,10 +543,18 @@ static void efx_fini_channels(struct efx_nic *efx)
BUG_ON(efx->port_enabled);
rc = efx_nic_flush_queues(efx);
- if (rc)
+ if (rc && EFX_WORKAROUND_7803(efx)) {
+ /* Schedule a reset to recover from the flush failure. The
+ * descriptor caches reference memory we're about to free,
+ * but falcon_reconfigure_mac_wrapper() won't reconnect
+ * the MACs because of the pending reset. */
+ EFX_ERR(efx, "Resetting to recover from flush failure\n");
+ efx_schedule_reset(efx, RESET_TYPE_ALL);
+ } else if (rc) {
EFX_ERR(efx, "failed to flush queues\n");
- else
+ } else {
EFX_LOG(efx, "successfully flushed all queues\n");
+ }
efx_for_each_channel(channel, efx) {
EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
@@ -586,9 +581,9 @@ static void efx_remove_channel(struct efx_channel *channel)
efx_remove_eventq(channel);
}
-void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
{
- queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+ mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
}
/**************************************************************************
@@ -1233,15 +1228,8 @@ static void efx_start_all(struct efx_nic *efx)
* since we're holding the rtnl_lock at this point. */
static void efx_flush_all(struct efx_nic *efx)
{
- struct efx_rx_queue *rx_queue;
-
/* Make sure the hardware monitor is stopped */
cancel_delayed_work_sync(&efx->monitor_work);
-
- /* Ensure that all RX slow refills are complete. */
- efx_for_each_rx_queue(rx_queue, efx)
- cancel_delayed_work_sync(&rx_queue->work);
-
/* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->mac_work);
}
@@ -1530,11 +1518,8 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
stats->tx_window_errors = mac_stats->tx_late_collision;
stats->rx_errors = (stats->rx_length_errors +
- stats->rx_over_errors +
stats->rx_crc_errors +
stats->rx_frame_errors +
- stats->rx_fifo_errors +
- stats->rx_missed_errors +
mac_stats->rx_symbol_error);
stats->tx_errors = (stats->tx_window_errors +
mac_stats->tx_bad);
@@ -1886,6 +1871,9 @@ static void efx_reset_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, reset_work);
+ if (efx->reset_pending == RESET_TYPE_NONE)
+ return;
+
/* If we're not RUNNING then don't reset. Leave the reset_pending
* flag set so that efx_pci_probe_main will be retried */
if (efx->state != STATE_RUNNING) {
@@ -2052,8 +2040,8 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
rx_queue->queue = i;
rx_queue->channel = &efx->channel[0]; /* for safety */
rx_queue->buffer = NULL;
- spin_lock_init(&rx_queue->add_lock);
- INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
+ (unsigned long)rx_queue);
}
efx->type = type;
@@ -2332,6 +2320,9 @@ static int efx_pm_thaw(struct device *dev)
efx->type->resume_wol(efx);
+ /* Reschedule any quenched resets scheduled during efx_pm_freeze() */
+ queue_work(reset_workqueue, &efx->reset_work);
+
return 0;
}
@@ -2421,11 +2412,6 @@ static int __init efx_init_module(void)
if (rc)
goto err_notifier;
- refill_workqueue = create_workqueue("sfc_refill");
- if (!refill_workqueue) {
- rc = -ENOMEM;
- goto err_refill;
- }
reset_workqueue = create_singlethread_workqueue("sfc_reset");
if (!reset_workqueue) {
rc = -ENOMEM;
@@ -2441,8 +2427,6 @@ static int __init efx_init_module(void)
err_pci:
destroy_workqueue(reset_workqueue);
err_reset:
- destroy_workqueue(refill_workqueue);
- err_refill:
unregister_netdevice_notifier(&efx_netdev_notifier);
err_notifier:
return rc;
@@ -2454,7 +2438,6 @@ static void __exit efx_exit_module(void)
pci_unregister_driver(&efx_pci_driver);
destroy_workqueue(reset_workqueue);
- destroy_workqueue(refill_workqueue);
unregister_netdevice_notifier(&efx_netdev_notifier);
}
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
index ffd708c5304a..e1e448887dfc 100644
--- a/drivers/net/sfc/efx.h
+++ b/drivers/net/sfc/efx.h
@@ -47,12 +47,12 @@ extern void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
extern void efx_rx_strategy(struct efx_channel *channel);
extern void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
-extern void efx_rx_work(struct work_struct *data);
+extern void efx_rx_slow_fill(unsigned long context);
extern void __efx_rx_packet(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf, bool checksummed);
extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard);
-extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_RXQ_SIZE 1024
#define EFX_RXQ_MASK (EFX_RXQ_SIZE - 1)
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
index 655b697b45b2..8558865ff380 100644
--- a/drivers/net/sfc/falcon.c
+++ b/drivers/net/sfc/falcon.c
@@ -548,7 +548,9 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
efx_oword_t reg;
- int link_speed;
+ int link_speed, isolate;
+
+ isolate = (efx->reset_pending != RESET_TYPE_NONE);
switch (link_state->speed) {
case 10000: link_speed = 3; break;
@@ -570,7 +572,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
* discarded. */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
- !link_state->up);
+ !link_state->up || isolate);
}
efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
@@ -584,7 +586,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
/* Unisolate the MAC -> RX */
if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
- EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
+ EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, !isolate);
efx_writeo(efx, &reg, FR_AZ_RX_CFG);
}
diff --git a/drivers/net/sfc/mcdi_phy.c b/drivers/net/sfc/mcdi_phy.c
index 6032c0e1f1f8..86e43b1f7689 100644
--- a/drivers/net/sfc/mcdi_phy.c
+++ b/drivers/net/sfc/mcdi_phy.c
@@ -20,7 +20,7 @@
#include "nic.h"
#include "selftest.h"
-struct efx_mcdi_phy_cfg {
+struct efx_mcdi_phy_data {
u32 flags;
u32 type;
u32 supported_cap;
@@ -35,7 +35,7 @@ struct efx_mcdi_phy_cfg {
};
static int
-efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_cfg *cfg)
+efx_mcdi_get_phy_cfg(struct efx_nic *efx, struct efx_mcdi_phy_data *cfg)
{
u8 outbuf[MC_CMD_GET_PHY_CFG_OUT_LEN];
size_t outlen;
@@ -259,7 +259,7 @@ static u32 ethtool_to_mcdi_cap(u32 cap)
static u32 efx_get_mcdi_phy_flags(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
enum efx_phy_mode mode, supported;
u32 flags;
@@ -307,7 +307,7 @@ static u32 mcdi_to_ethtool_media(u32 media)
static int efx_mcdi_phy_probe(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_data;
+ struct efx_mcdi_phy_data *phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
u32 caps;
int rc;
@@ -395,6 +395,7 @@ static int efx_mcdi_phy_probe(struct efx_nic *efx)
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
if (phy_data->supported_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
efx->wanted_fc |= EFX_FC_AUTO;
+ efx_link_set_wanted_fc(efx, efx->wanted_fc);
return 0;
@@ -405,7 +406,7 @@ fail:
int efx_mcdi_phy_reconfigure(struct efx_nic *efx)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps = (efx->link_advertising ?
ethtool_to_mcdi_cap(efx->link_advertising) :
phy_cfg->forced_cap);
@@ -446,7 +447,7 @@ void efx_mcdi_phy_decode_link(struct efx_nic *efx,
*/
void efx_mcdi_phy_check_fcntl(struct efx_nic *efx, u32 lpa)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 rmtadv;
/* The link partner capabilities are only relevent if the
@@ -505,7 +506,7 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx)
static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u8 outbuf[MC_CMD_GET_LINK_OUT_LEN];
int rc;
@@ -535,7 +536,7 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 caps;
int rc;
@@ -674,7 +675,7 @@ out:
static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
unsigned flags)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
u32 mode;
int rc;
@@ -712,7 +713,7 @@ static int efx_mcdi_phy_run_tests(struct efx_nic *efx, int *results,
const char *efx_mcdi_phy_test_name(struct efx_nic *efx, unsigned int index)
{
- struct efx_mcdi_phy_cfg *phy_cfg = efx->phy_data;
+ struct efx_mcdi_phy_data *phy_cfg = efx->phy_data;
if (phy_cfg->flags & (1 << MC_CMD_GET_PHY_CFG_BIST_LBN)) {
if (index == 0)
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
index 2e6fd89f2a72..ba636e086fc3 100644
--- a/drivers/net/sfc/net_driver.h
+++ b/drivers/net/sfc/net_driver.h
@@ -18,6 +18,7 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
+#include <linux/timer.h>
#include <linux/mdio.h>
#include <linux/list.h>
#include <linux/pci.h>
@@ -221,7 +222,6 @@ struct efx_tx_queue {
* If both this and skb are %NULL, the buffer slot is currently free.
* @data: Pointer to ethernet header
* @len: Buffer length, in bytes.
- * @unmap_addr: DMA address to unmap
*/
struct efx_rx_buffer {
dma_addr_t dma_addr;
@@ -229,7 +229,24 @@ struct efx_rx_buffer {
struct page *page;
char *data;
unsigned int len;
- dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_page_state - Page-based rx buffer state
+ *
+ * Inserted at the start of every page allocated for receive buffers.
+ * Used to facilitate sharing dma mappings between recycled rx buffers
+ * and those passed up to the kernel.
+ *
+ * @refcnt: Number of struct efx_rx_buffer's referencing this page.
+ * When refcnt falls to zero, the page is unmapped for dma
+ * @dma_addr: The dma address of this page.
+ */
+struct efx_rx_page_state {
+ unsigned refcnt;
+ dma_addr_t dma_addr;
+
+ unsigned int __pad[0] ____cacheline_aligned;
};
/**
@@ -242,10 +259,6 @@ struct efx_rx_buffer {
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
- * @add_lock: Receive queue descriptor add spin lock.
- * This lock must be held in order to add buffers to the RX
- * descriptor ring (rxd and buffer) and to update added_count (but
- * not removed_count).
* @max_fill: RX descriptor maximum fill level (<= ring size)
* @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
* (<= @max_fill)
@@ -259,12 +272,7 @@ struct efx_rx_buffer {
* overflow was observed. It should never be set.
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
- * @work: Descriptor push work thread
- * @buf_page: Page for next RX buffer.
- * We can use a single page for multiple RX buffers. This tracks
- * the remaining space in the allocation.
- * @buf_dma_addr: Page's DMA address.
- * @buf_data: Page's host address.
+ * @slow_fill: Timer used to defer efx_nic_generate_fill_event().
* @flushed: Use when handling queue flushing
*/
struct efx_rx_queue {
@@ -277,7 +285,6 @@ struct efx_rx_queue {
int added_count;
int notified_count;
int removed_count;
- spinlock_t add_lock;
unsigned int max_fill;
unsigned int fast_fill_trigger;
unsigned int fast_fill_limit;
@@ -285,12 +292,9 @@ struct efx_rx_queue {
unsigned int min_overfill;
unsigned int alloc_page_count;
unsigned int alloc_skb_count;
- struct delayed_work work;
+ struct timer_list slow_fill;
unsigned int slow_fill_count;
- struct page *buf_page;
- dma_addr_t buf_dma_addr;
- char *buf_data;
enum efx_flush_state flushed;
};
@@ -336,7 +340,7 @@ enum efx_rx_alloc_method {
* @eventq: Event queue buffer
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
- * @eventq_magic: Event queue magic value for driver-generated test events
+ * @magic_count: Event queue test event count
* @irq_count: Number of IRQs since last adaptive moderation decision
* @irq_mod_score: IRQ moderation score
* @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
@@ -367,7 +371,7 @@ struct efx_channel {
struct efx_special_buffer eventq;
unsigned int eventq_read_ptr;
unsigned int last_eventq_read_ptr;
- unsigned int eventq_magic;
+ unsigned int magic_count;
unsigned int irq_count;
unsigned int irq_mod_score;
@@ -645,6 +649,7 @@ union efx_multicast_hash {
* struct efx_nic - an Efx NIC
* @name: Device name (net device name or bus id before net device registered)
* @pci_dev: The PCI device
+ * @port_num: Index of this host port within the controller
* @type: Controller type attributes
* @legacy_irq: IRQ number
* @workqueue: Workqueue for port reconfigures and the HW monitor.
@@ -728,6 +733,7 @@ union efx_multicast_hash {
struct efx_nic {
char name[IFNAMSIZ];
struct pci_dev *pci_dev;
+ unsigned port_num;
const struct efx_nic_type *type;
int legacy_irq;
struct workqueue_struct *workqueue;
@@ -830,7 +836,7 @@ static inline const char *efx_dev_name(struct efx_nic *efx)
static inline unsigned int efx_port_num(struct efx_nic *efx)
{
- return PCI_FUNC(efx->pci_dev->devfn);
+ return efx->net_dev->dev_id;
}
/**
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c
index 5d3aaec58556..0ee6fd367e6f 100644
--- a/drivers/net/sfc/nic.c
+++ b/drivers/net/sfc/nic.c
@@ -79,6 +79,14 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
/* Depth of RX flush request fifo */
#define EFX_RX_FLUSH_COUNT 4
+/* Generated event code for efx_generate_test_event() */
+#define EFX_CHANNEL_MAGIC_TEST(_channel) \
+ (0x00010100 + (_channel)->channel)
+
+/* Generated event code for efx_generate_fill_event() */
+#define EFX_CHANNEL_MAGIC_FILL(_channel) \
+ (0x00010200 + (_channel)->channel)
+
/**************************************************************************
*
* Solarstorm hardware access
@@ -850,6 +858,26 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
checksummed, discard);
}
+static void
+efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned code;
+
+ code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
+ if (code == EFX_CHANNEL_MAGIC_TEST(channel))
+ ++channel->magic_count;
+ else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
+ /* The queue must be empty, so we won't receive any rx
+ * events, so efx_process_channel() won't refill the
+ * queue. Refill it here */
+ efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
+ else
+ EFX_LOG(efx, "channel %d received generated "
+ "event "EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+}
+
/* Global events are basically PHY events */
static void
efx_handle_global_event(struct efx_channel *channel, efx_qword_t *event)
@@ -993,11 +1021,7 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
}
break;
case FSE_AZ_EV_CODE_DRV_GEN_EV:
- channel->eventq_magic = EFX_QWORD_FIELD(
- event, FSF_AZ_DRV_GEN_EV_MAGIC);
- EFX_LOG(channel->efx, "channel %d received generated "
- "event "EFX_QWORD_FMT"\n", channel->channel,
- EFX_QWORD_VAL(event));
+ efx_handle_generated_event(channel, &event);
break;
case FSE_AZ_EV_CODE_GLOBAL_EV:
efx_handle_global_event(channel, &event);
@@ -1088,12 +1112,20 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
}
-/* Generates a test event on the event queue. A subsequent call to
- * process_eventq() should pick up the event and place the value of
- * "magic" into channel->eventq_magic;
- */
-void efx_nic_generate_test_event(struct efx_channel *channel, unsigned int magic)
+void efx_nic_generate_test_event(struct efx_channel *channel)
{
+ unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
+ FSE_AZ_EV_CODE_DRV_GEN_EV,
+ FSF_AZ_DRV_GEN_EV_MAGIC, magic);
+ efx_generate_event(channel, &test_event);
+}
+
+void efx_nic_generate_fill_event(struct efx_channel *channel)
+{
+ unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
@@ -1219,9 +1251,6 @@ int efx_nic_flush_queues(struct efx_nic *efx)
rx_queue->flushed = FLUSH_DONE;
}
- if (EFX_WORKAROUND_7803(efx))
- return 0;
-
return -ETIMEDOUT;
}
diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h
index bbc2c0c2f843..95770e15115d 100644
--- a/drivers/net/sfc/nic.h
+++ b/drivers/net/sfc/nic.h
@@ -190,8 +190,8 @@ extern int efx_nic_rx_xoff_thresh, efx_nic_rx_xon_thresh;
/* Interrupts and test events */
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
-extern void efx_nic_generate_test_event(struct efx_channel *channel,
- unsigned int magic);
+extern void efx_nic_generate_test_event(struct efx_channel *channel);
+extern void efx_nic_generate_fill_event(struct efx_channel *channel);
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
index e308818b9f55..9fb698e3519d 100644
--- a/drivers/net/sfc/rx.c
+++ b/drivers/net/sfc/rx.c
@@ -25,6 +25,9 @@
/* Number of RX descriptors pushed at once. */
#define EFX_RX_BATCH 8
+/* Maximum size of a buffer sharing a page */
+#define EFX_RX_HALF_PAGE ((PAGE_SIZE >> 1) - sizeof(struct efx_rx_page_state))
+
/* Size of buffer allocated for skb header area. */
#define EFX_SKB_HEADERS 64u
@@ -98,155 +101,138 @@ static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
return PAGE_SIZE << efx->rx_buffer_order;
}
-
/**
- * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ * efx_init_rx_buffers_skb - create EFX_RX_BATCH skb-based RX buffers
*
* @rx_queue: Efx RX queue
- * @rx_buf: RX buffer structure to populate
*
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information. Return a negative error code or 0 on success.
+ * This allocates EFX_RX_BATCH skbs, maps them for DMA, and populates a
+ * struct efx_rx_buffer for each one. Return a negative error code or 0
+ * on success. May fail having only inserted fewer than EFX_RX_BATCH
+ * buffers.
*/
-static int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_skb(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
struct net_device *net_dev = efx->net_dev;
+ struct efx_rx_buffer *rx_buf;
int skb_len = efx->rx_buffer_len;
+ unsigned index, count;
- rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
- if (unlikely(!rx_buf->skb))
- return -ENOMEM;
+ for (count = 0; count < EFX_RX_BATCH; ++count) {
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ rx_buf = efx_rx_buffer(rx_queue, index);
- /* Adjust the SKB for padding and checksum */
- skb_reserve(rx_buf->skb, NET_IP_ALIGN);
- rx_buf->len = skb_len - NET_IP_ALIGN;
- rx_buf->data = (char *)rx_buf->skb->data;
- rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+ rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!rx_buf->skb))
+ return -ENOMEM;
+ rx_buf->page = NULL;
- rx_buf->dma_addr = pci_map_single(efx->pci_dev,
- rx_buf->data, rx_buf->len,
- PCI_DMA_FROMDEVICE);
+ /* Adjust the SKB for padding and checksum */
+ skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ rx_buf->len = skb_len - NET_IP_ALIGN;
+ rx_buf->data = (char *)rx_buf->skb->data;
+ rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+ rx_buf->data, rx_buf->len,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(pci_dma_mapping_error(efx->pci_dev,
+ rx_buf->dma_addr))) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ return -EIO;
+ }
- if (unlikely(pci_dma_mapping_error(efx->pci_dev, rx_buf->dma_addr))) {
- dev_kfree_skb_any(rx_buf->skb);
- rx_buf->skb = NULL;
- return -EIO;
+ ++rx_queue->added_count;
+ ++rx_queue->alloc_skb_count;
}
return 0;
}
/**
- * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ * efx_init_rx_buffers_page - create EFX_RX_BATCH page-based RX buffers
*
* @rx_queue: Efx RX queue
- * @rx_buf: RX buffer structure to populate
*
- * This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information. Return a negative error code or 0 on success.
+ * This allocates memory for EFX_RX_BATCH receive buffers, maps them for DMA,
+ * and populates struct efx_rx_buffers for each one. Return a negative error
+ * code or 0 on success. If a single page can be split between two buffers,
+ * then the page will either be inserted fully, or not at at all.
*/
-static int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *rx_buf)
+static int efx_init_rx_buffers_page(struct efx_rx_queue *rx_queue)
{
struct efx_nic *efx = rx_queue->efx;
- int bytes, space, offset;
-
- bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
-
- /* If there is space left in the previously allocated page,
- * then use it. Otherwise allocate a new one */
- rx_buf->page = rx_queue->buf_page;
- if (rx_buf->page == NULL) {
- dma_addr_t dma_addr;
-
- rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
- efx->rx_buffer_order);
- if (unlikely(rx_buf->page == NULL))
+ struct efx_rx_buffer *rx_buf;
+ struct page *page;
+ void *page_addr;
+ struct efx_rx_page_state *state;
+ dma_addr_t dma_addr;
+ unsigned index, count;
+
+ /* We can split a page between two buffers */
+ BUILD_BUG_ON(EFX_RX_BATCH & 1);
+
+ for (count = 0; count < EFX_RX_BATCH; ++count) {
+ page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(page == NULL))
return -ENOMEM;
-
- dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
- 0, efx_rx_buf_size(efx),
+ dma_addr = pci_map_page(efx->pci_dev, page, 0,
+ efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
-
if (unlikely(pci_dma_mapping_error(efx->pci_dev, dma_addr))) {
- __free_pages(rx_buf->page, efx->rx_buffer_order);
- rx_buf->page = NULL;
+ __free_pages(page, efx->rx_buffer_order);
return -EIO;
}
-
- rx_queue->buf_page = rx_buf->page;
- rx_queue->buf_dma_addr = dma_addr;
- rx_queue->buf_data = (page_address(rx_buf->page) +
- EFX_PAGE_IP_ALIGN);
- }
-
- rx_buf->len = bytes;
- rx_buf->data = rx_queue->buf_data;
- offset = efx_rx_buf_offset(rx_buf);
- rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
-
- /* Try to pack multiple buffers per page */
- if (efx->rx_buffer_order == 0) {
- /* The next buffer starts on the next 512 byte boundary */
- rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
- offset += ((bytes + 0x1ff) & ~0x1ff);
-
- space = efx_rx_buf_size(efx) - offset;
- if (space >= bytes) {
- /* Refs dropped on kernel releasing each skb */
- get_page(rx_queue->buf_page);
- goto out;
+ page_addr = page_address(page);
+ state = page_addr;
+ state->refcnt = 0;
+ state->dma_addr = dma_addr;
+
+ page_addr += sizeof(struct efx_rx_page_state);
+ dma_addr += sizeof(struct efx_rx_page_state);
+
+ split:
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rx_buf->dma_addr = dma_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->skb = NULL;
+ rx_buf->page = page;
+ rx_buf->data = page_addr + EFX_PAGE_IP_ALIGN;
+ rx_buf->len = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+ ++rx_queue->added_count;
+ ++rx_queue->alloc_page_count;
+ ++state->refcnt;
+
+ if ((~count & 1) && (efx->rx_buffer_len <= EFX_RX_HALF_PAGE)) {
+ /* Use the second half of the page */
+ get_page(page);
+ dma_addr += (PAGE_SIZE >> 1);
+ page_addr += (PAGE_SIZE >> 1);
+ ++count;
+ goto split;
}
}
- /* This is the final RX buffer for this page, so mark it for
- * unmapping */
- rx_queue->buf_page = NULL;
- rx_buf->unmap_addr = rx_queue->buf_dma_addr;
-
- out:
return 0;
}
-/* This allocates memory for a new receive buffer, maps it for DMA,
- * and populates a struct efx_rx_buffer with the relevant
- * information.
- */
-static int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
- struct efx_rx_buffer *new_rx_buf)
-{
- int rc = 0;
-
- if (rx_queue->channel->rx_alloc_push_pages) {
- new_rx_buf->skb = NULL;
- rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
- rx_queue->alloc_page_count++;
- } else {
- new_rx_buf->page = NULL;
- rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
- rx_queue->alloc_skb_count++;
- }
-
- if (unlikely(rc < 0))
- EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
- rx_queue->queue, rc);
- return rc;
-}
-
static void efx_unmap_rx_buffer(struct efx_nic *efx,
struct efx_rx_buffer *rx_buf)
{
if (rx_buf->page) {
+ struct efx_rx_page_state *state;
+
EFX_BUG_ON_PARANOID(rx_buf->skb);
- if (rx_buf->unmap_addr) {
- pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+
+ state = page_address(rx_buf->page);
+ if (--state->refcnt == 0) {
+ pci_unmap_page(efx->pci_dev,
+ state->dma_addr,
efx_rx_buf_size(efx),
PCI_DMA_FROMDEVICE);
- rx_buf->unmap_addr = 0;
}
} else if (likely(rx_buf->skb)) {
pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
@@ -273,31 +259,84 @@ static void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
efx_free_rx_buffer(rx_queue->efx, rx_buf);
}
+/* Attempt to resurrect the other receive buffer that used to share this page,
+ * which had previously been passed up to the kernel and freed. */
+static void efx_resurrect_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_rx_page_state *state = page_address(rx_buf->page);
+ struct efx_rx_buffer *new_buf;
+ unsigned fill_level, index;
+
+ /* +1 because efx_rx_packet() incremented removed_count. +1 because
+ * we'd like to insert an additional descriptor whilst leaving
+ * EFX_RXD_HEAD_ROOM for the non-recycle path */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count + 2);
+ if (unlikely(fill_level >= EFX_RXQ_SIZE - EFX_RXD_HEAD_ROOM)) {
+ /* We could place "state" on a list, and drain the list in
+ * efx_fast_push_rx_descriptors(). For now, this will do. */
+ return;
+ }
+
+ ++state->refcnt;
+ get_page(rx_buf->page);
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+ new_buf->dma_addr = rx_buf->dma_addr ^ (PAGE_SIZE >> 1);
+ new_buf->skb = NULL;
+ new_buf->page = rx_buf->page;
+ new_buf->data = (void *)
+ ((__force unsigned long)rx_buf->data ^ (PAGE_SIZE >> 1));
+ new_buf->len = rx_buf->len;
+ ++rx_queue->added_count;
+}
+
+/* Recycle the given rx buffer directly back into the rx_queue. There is
+ * always room to add this buffer, because we've just popped a buffer. */
+static void efx_recycle_rx_buffer(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = channel->efx;
+ struct efx_rx_queue *rx_queue = &efx->rx_queue[channel->channel];
+ struct efx_rx_buffer *new_buf;
+ unsigned index;
+
+ if (rx_buf->page != NULL && efx->rx_buffer_len <= EFX_RX_HALF_PAGE &&
+ page_count(rx_buf->page) == 1)
+ efx_resurrect_rx_buffer(rx_queue, rx_buf);
+
+ index = rx_queue->added_count & EFX_RXQ_MASK;
+ new_buf = efx_rx_buffer(rx_queue, index);
+
+ memcpy(new_buf, rx_buf, sizeof(*new_buf));
+ rx_buf->page = NULL;
+ rx_buf->skb = NULL;
+ ++rx_queue->added_count;
+}
+
/**
* efx_fast_push_rx_descriptors - push new RX descriptors quickly
* @rx_queue: RX descriptor queue
- * @retry: Recheck the fill level
* This will aim to fill the RX descriptor queue up to
* @rx_queue->@fast_fill_limit. If there is insufficient atomic
- * memory to do so, the caller should retry.
+ * memory to do so, a slow fill will be scheduled.
+ *
+ * The caller must provide serialisation (none is used here). In practise,
+ * this means this function must run from the NAPI handler, or be called
+ * when NAPI is disabled.
*/
-static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
- int retry)
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
{
- struct efx_rx_buffer *rx_buf;
- unsigned fill_level, index;
- int i, space, rc = 0;
+ struct efx_channel *channel = rx_queue->channel;
+ unsigned fill_level;
+ int space, rc = 0;
- /* Calculate current fill level. Do this outside the lock,
- * because most of the time we'll end up not wanting to do the
- * fill anyway.
- */
+ /* Calculate current fill level, and exit if we don't need to fill */
fill_level = (rx_queue->added_count - rx_queue->removed_count);
EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
-
- /* Don't fill if we don't need to */
if (fill_level >= rx_queue->fast_fill_trigger)
- return 0;
+ goto out;
/* Record minimum fill level */
if (unlikely(fill_level < rx_queue->min_fill)) {
@@ -305,34 +344,25 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
rx_queue->min_fill = fill_level;
}
- /* Acquire RX add lock. If this lock is contended, then a fast
- * fill must already be in progress (e.g. in the refill
- * tasklet), so we don't need to do anything
- */
- if (!spin_trylock_bh(&rx_queue->add_lock))
- return -1;
-
- retry:
- /* Recalculate current fill level now that we have the lock */
- fill_level = (rx_queue->added_count - rx_queue->removed_count);
- EFX_BUG_ON_PARANOID(fill_level > EFX_RXQ_SIZE);
space = rx_queue->fast_fill_limit - fill_level;
if (space < EFX_RX_BATCH)
- goto out_unlock;
+ goto out;
EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
" level %d to level %d using %s allocation\n",
rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
- rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+ channel->rx_alloc_push_pages ? "page" : "skb");
do {
- for (i = 0; i < EFX_RX_BATCH; ++i) {
- index = rx_queue->added_count & EFX_RXQ_MASK;
- rx_buf = efx_rx_buffer(rx_queue, index);
- rc = efx_init_rx_buffer(rx_queue, rx_buf);
- if (unlikely(rc))
- goto out;
- ++rx_queue->added_count;
+ if (channel->rx_alloc_push_pages)
+ rc = efx_init_rx_buffers_page(rx_queue);
+ else
+ rc = efx_init_rx_buffers_skb(rx_queue);
+ if (unlikely(rc)) {
+ /* Ensure that we don't leave the rx queue empty */
+ if (rx_queue->added_count == rx_queue->removed_count)
+ efx_schedule_slow_fill(rx_queue);
+ goto out;
}
} while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
@@ -341,63 +371,18 @@ static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
rx_queue->added_count - rx_queue->removed_count);
out:
- /* Send write pointer to card. */
- efx_nic_notify_rx_desc(rx_queue);
-
- /* If the fast fill is running inside from the refill tasklet, then
- * for SMP systems it may be running on a different CPU to
- * RX event processing, which means that the fill level may now be
- * out of date. */
- if (unlikely(retry && (rc == 0)))
- goto retry;
-
- out_unlock:
- spin_unlock_bh(&rx_queue->add_lock);
-
- return rc;
-}
-
-/**
- * efx_fast_push_rx_descriptors - push new RX descriptors quickly
- * @rx_queue: RX descriptor queue
- *
- * This will aim to fill the RX descriptor queue up to
- * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
- * it will schedule a work item to immediately continue the fast fill
- */
-void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
-{
- int rc;
-
- rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
- if (unlikely(rc)) {
- /* Schedule the work item to run immediately. The hope is
- * that work is immediately pending to free some memory
- * (e.g. an RX event or TX completion)
- */
- efx_schedule_slow_fill(rx_queue, 0);
- }
+ if (rx_queue->notified_count != rx_queue->added_count)
+ efx_nic_notify_rx_desc(rx_queue);
}
-void efx_rx_work(struct work_struct *data)
+void efx_rx_slow_fill(unsigned long context)
{
- struct efx_rx_queue *rx_queue;
- int rc;
-
- rx_queue = container_of(data, struct efx_rx_queue, work.work);
-
- if (unlikely(!rx_queue->channel->enabled))
- return;
-
- EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
- "%d\n", rx_queue->queue, raw_smp_processor_id());
+ struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
+ struct efx_channel *channel = rx_queue->channel;
+ /* Post an event to cause NAPI to run and refill the queue */
+ efx_nic_generate_fill_event(channel);
++rx_queue->slow_fill_count;
- /* Push new RX descriptors, allowing at least 1 jiffy for
- * the kernel to free some more memory. */
- rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
- if (rc)
- efx_schedule_slow_fill(rx_queue, 1);
}
static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
@@ -498,6 +483,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard)
{
struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = rx_queue->channel;
struct efx_rx_buffer *rx_buf;
bool leak_packet = false;
@@ -525,12 +511,13 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
/* Discard packet, if instructed to do so */
if (unlikely(discard)) {
if (unlikely(leak_packet))
- rx_queue->channel->n_skbuff_leaks++;
+ channel->n_skbuff_leaks++;
else
- /* We haven't called efx_unmap_rx_buffer yet,
- * so fini the entire rx_buffer here */
- efx_fini_rx_buffer(rx_queue, rx_buf);
- return;
+ efx_recycle_rx_buffer(channel, rx_buf);
+
+ /* Don't hold off the previous receive */
+ rx_buf = NULL;
+ goto out;
}
/* Release card resources - assumes all RX buffers consumed in-order
@@ -547,6 +534,7 @@ void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
* prefetched into cache.
*/
rx_buf->len = len;
+out:
if (rx_queue->channel->rx_pkt)
__efx_rx_packet(rx_queue->channel,
rx_queue->channel->rx_pkt,
@@ -682,6 +670,7 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+ del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
/* Release RX buffers NB start at index 0 not current HW ptr */
@@ -691,16 +680,6 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
efx_fini_rx_buffer(rx_queue, rx_buf);
}
}
-
- /* For a page that is part-way through splitting into RX buffers */
- if (rx_queue->buf_page != NULL) {
- pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
- efx_rx_buf_size(rx_queue->efx),
- PCI_DMA_FROMDEVICE);
- __free_pages(rx_queue->buf_page,
- rx_queue->efx->rx_buffer_order);
- rx_queue->buf_page = NULL;
- }
}
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c
index 371e86cc090f..1f83404af63b 100644
--- a/drivers/net/sfc/selftest.c
+++ b/drivers/net/sfc/selftest.c
@@ -38,7 +38,7 @@ struct efx_loopback_payload {
struct udphdr udp;
__be16 iteration;
const char msg[64];
-} __attribute__ ((packed));
+} __packed;
/* Loopback test source MAC address */
static const unsigned char payload_source[ETH_ALEN] = {
@@ -161,23 +161,17 @@ static int efx_test_interrupts(struct efx_nic *efx,
static int efx_test_eventq_irq(struct efx_channel *channel,
struct efx_self_tests *tests)
{
- unsigned int magic, count;
-
- /* Channel specific code, limited to 20 bits */
- magic = (0x00010150 + channel->channel);
- EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
- channel->channel, magic);
+ unsigned int magic_count, count;
tests->eventq_dma[channel->channel] = -1;
tests->eventq_int[channel->channel] = -1;
tests->eventq_poll[channel->channel] = -1;
- /* Reset flag and zero magic word */
+ magic_count = channel->magic_count;
channel->efx->last_irq_cpu = -1;
- channel->eventq_magic = 0;
smp_wmb();
- efx_nic_generate_test_event(channel, magic);
+ efx_nic_generate_test_event(channel);
/* Wait for arrival of interrupt */
count = 0;
@@ -187,7 +181,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
if (channel->work_pending)
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic)
+ if (channel->magic_count != magic_count)
goto eventq_ok;
} while (++count < 2);
@@ -204,7 +198,7 @@ static int efx_test_eventq_irq(struct efx_channel *channel,
/* Check to see if event was received even if interrupt wasn't */
efx_process_channel_now(channel);
- if (channel->eventq_magic == magic) {
+ if (channel->magic_count != magic_count) {
EFX_ERR(channel->efx, "channel %d event was generated, but "
"failed to trigger an interrupt\n", channel->channel);
tests->eventq_dma[channel->channel] = 1;
@@ -545,7 +539,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue,
static int efx_wait_for_link(struct efx_nic *efx)
{
struct efx_link_state *link_state = &efx->link_state;
- int count;
+ int count, link_up_count = 0;
bool link_up;
for (count = 0; count < 40; count++) {
@@ -567,8 +561,12 @@ static int efx_wait_for_link(struct efx_nic *efx)
link_up = !efx->mac_op->check_fault(efx);
mutex_unlock(&efx->mac_lock);
- if (link_up)
- return 0;
+ if (link_up) {
+ if (++link_up_count == 2)
+ return 0;
+ } else {
+ link_up_count = 0;
+ }
}
return -ETIMEDOUT;
diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c
index 727b4228e081..f2b1e6180753 100644
--- a/drivers/net/sfc/siena.c
+++ b/drivers/net/sfc/siena.c
@@ -206,6 +206,7 @@ static int siena_probe_nic(struct efx_nic *efx)
{
struct siena_nic_data *nic_data;
bool already_attached = 0;
+ efx_oword_t reg;
int rc;
/* Allocate storage for hardware specific data */
@@ -220,6 +221,9 @@ static int siena_probe_nic(struct efx_nic *efx)
goto fail1;
}
+ efx_reado(efx, &reg, FR_AZ_CS_DEBUG);
+ efx->net_dev->dev_id = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1;
+
efx_mcdi_init(efx);
/* Recover from a failed assertion before probing */
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
index 518f7fc91473..782e45a613d6 100644
--- a/drivers/net/sfc/workarounds.h
+++ b/drivers/net/sfc/workarounds.h
@@ -54,7 +54,7 @@
/* Increase filter depth to avoid RX_RESET */
#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
/* Flushes may never complete */
-#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_AB
/* Leak overlength packets rather than free */
#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 084eff21b67a..61891a6cacc2 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -2161,21 +2161,21 @@ struct sky2_tx_le {
__le16 length; /* also vlan tag or checksum start */
u8 ctrl;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct sky2_rx_le {
__le32 addr;
__le16 length;
u8 ctrl;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct sky2_status_le {
__le32 status; /* also checksum */
__le16 length; /* also vlan tag */
u8 css;
u8 opcode;
-} __attribute((packed));
+} __packed;
struct tx_ring_info {
struct sk_buff *skb;
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index 20ab16192325..737df6032bbc 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -646,7 +646,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
error = copy_from_user(data, ifr->ifr_data, sizeof(data));
if (error) {
pr_err("cant copy from user\n");
- RET(error);
+ RET(-EFAULT);
}
DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
}
@@ -665,7 +665,7 @@ static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd)
data[2]);
error = copy_to_user(ifr->ifr_data, data, sizeof(data));
if (error)
- RET(error);
+ RET(-EFAULT);
break;
case BDX_OP_WRITE:
diff --git a/drivers/net/tehuti.h b/drivers/net/tehuti.h
index cff98d07cba8..67e3b71bf705 100644
--- a/drivers/net/tehuti.h
+++ b/drivers/net/tehuti.h
@@ -334,7 +334,7 @@ struct txd_desc {
u32 va_lo;
u32 va_hi;
struct pbl pbl[0]; /* Fragments */
-} __attribute__ ((packed));
+} __packed;
/* Register region size */
#define BDX_REGS_SIZE 0x1000
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index 573054ae7b58..289cdc5fde92 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -67,8 +67,8 @@
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
-#define DRV_MODULE_VERSION "3.110"
-#define DRV_MODULE_RELDATE "April 9, 2010"
+#define DRV_MODULE_VERSION "3.111"
+#define DRV_MODULE_RELDATE "June 5, 2010"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -145,8 +145,6 @@
#define TG3_RX_JMB_BUFF_RING_SIZE \
(sizeof(struct ring_info) * TG3_RX_JUMBO_RING_SIZE)
-#define TG3_RSS_MIN_NUM_MSIX_VECS 2
-
/* Due to a hardware bug, the 5701 can only DMA to memory addresses
* that are at least dword aligned when used in PCIX mode. The driver
* works around this bug by double copying the packet. This workaround
@@ -272,6 +270,7 @@ static DEFINE_PCI_DEVICE_TABLE(tg3_pci_tbl) = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57765)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57791)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57795)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5719)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -585,18 +584,23 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
static void tg3_ape_lock_init(struct tg3 *tp)
{
int i;
+ u32 regbase;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ regbase = TG3_APE_LOCK_GRANT;
+ else
+ regbase = TG3_APE_PER_LOCK_GRANT;
/* Make sure the driver hasn't any stale locks. */
for (i = 0; i < 8; i++)
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
- APE_LOCK_GRANT_DRIVER);
+ tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER);
}
static int tg3_ape_lock(struct tg3 *tp, int locknum)
{
int i, off;
int ret = 0;
- u32 status;
+ u32 status, req, gnt;
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return 0;
@@ -609,13 +613,21 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
return -EINVAL;
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) {
+ req = TG3_APE_LOCK_REQ;
+ gnt = TG3_APE_LOCK_GRANT;
+ } else {
+ req = TG3_APE_PER_LOCK_REQ;
+ gnt = TG3_APE_PER_LOCK_GRANT;
+ }
+
off = 4 * locknum;
- tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);
+ tg3_ape_write32(tp, req + off, APE_LOCK_REQ_DRIVER);
/* Wait for up to 1 millisecond to acquire lock. */
for (i = 0; i < 100; i++) {
- status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
+ status = tg3_ape_read32(tp, gnt + off);
if (status == APE_LOCK_GRANT_DRIVER)
break;
udelay(10);
@@ -623,7 +635,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
if (status != APE_LOCK_GRANT_DRIVER) {
/* Revoke the lock request. */
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
+ tg3_ape_write32(tp, gnt + off,
APE_LOCK_GRANT_DRIVER);
ret = -EBUSY;
@@ -634,7 +646,7 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum)
static void tg3_ape_unlock(struct tg3 *tp, int locknum)
{
- int off;
+ u32 gnt;
if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return;
@@ -647,8 +659,12 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum)
return;
}
- off = 4 * locknum;
- tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761)
+ gnt = TG3_APE_LOCK_GRANT;
+ else
+ gnt = TG3_APE_PER_LOCK_GRANT;
+
+ tg3_ape_write32(tp, gnt + 4 * locknum, APE_LOCK_GRANT_DRIVER);
}
static void tg3_disable_ints(struct tg3 *tp)
@@ -1069,14 +1085,11 @@ static int tg3_mdio_init(struct tg3 *tp)
u32 reg;
struct phy_device *phydev;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- u32 funcnum, is_serdes;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ u32 is_serdes;
- funcnum = tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC;
- if (funcnum)
- tp->phy_addr = 2;
- else
- tp->phy_addr = 1;
+ tp->phy_addr = PCI_FUNC(tp->pdev->devfn) + 1;
if (tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
is_serdes = tr32(SG_DIG_STATUS) & SG_DIG_IS_SERDES;
@@ -1589,7 +1602,8 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
u32 reg;
if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
- (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+ ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
(tp->tg3_flags2 & TG3_FLG2_MII_SERDES)))
return;
@@ -1964,7 +1978,8 @@ static int tg3_phy_reset(struct tg3 *tp)
}
}
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 &&
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) &&
(tp->tg3_flags2 & TG3_FLG2_MII_SERDES))
return 0;
@@ -2049,6 +2064,7 @@ static void tg3_frob_aux_power(struct tg3 *tp)
/* The GPIOs do something completely different on 57765. */
if ((tp->tg3_flags2 & TG3_FLG2_IS_NIC) == 0 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
return;
@@ -4191,6 +4207,8 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
current_duplex = DUPLEX_FULL;
else
current_duplex = DUPLEX_HALF;
+ } else if (!(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
+ /* Link is up via parallel detect */
} else {
current_link_up = 0;
}
@@ -6212,6 +6230,8 @@ static void tg3_free_rings(struct tg3 *tp)
for (j = 0; j < tp->irq_cnt; j++) {
struct tg3_napi *tnapi = &tp->napi[j];
+ tg3_rx_prodring_free(tp, &tp->prodring[j]);
+
if (!tnapi->tx_buffers)
continue;
@@ -6247,8 +6267,6 @@ static void tg3_free_rings(struct tg3 *tp)
dev_kfree_skb_any(skb);
}
-
- tg3_rx_prodring_free(tp, &tp->prodring[j]);
}
}
@@ -6782,7 +6800,8 @@ static void tg3_restore_pci_state(struct tg3 *tp)
/* Allow reads and writes to the APE register and memory space. */
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);
pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd);
@@ -7069,6 +7088,7 @@ static int tg3_chip_reset(struct tg3 *tp)
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
val = tr32(0x7c00);
@@ -7504,7 +7524,8 @@ static void tg3_rings_reset(struct tg3 *tp)
/* Disable all receive return rings but the first. */
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 17;
else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
limit = NIC_SRAM_RCV_RET_RCB + TG3_BDINFO_SIZE * 16;
@@ -7720,7 +7741,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
*/
val = tr32(TG3PCI_PCISTATE);
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
tw32(TG3PCI_PCISTATE, val);
}
@@ -7741,6 +7763,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
return err;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
val = tr32(TG3PCI_DMA_RW_CTRL) &
~DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
@@ -7869,7 +7892,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
((u64) tpr->rx_std_mapping >> 32));
tw32(RCVDBDI_STD_BD + TG3_BDINFO_HOST_ADDR + TG3_64BIT_REG_LOW,
((u64) tpr->rx_std_mapping & 0xffffffff));
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
tw32(RCVDBDI_STD_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_BUFFER_DESC);
@@ -7894,7 +7918,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_MAXLEN_FLAGS,
(RX_JUMBO_MAX_SIZE << BDINFO_FLAGS_MAXLEN_SHIFT) |
BDINFO_FLAGS_USE_EXT_RECV);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+ if (!(tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tw32(RCVDBDI_JUMBO_BD + TG3_BDINFO_NIC_ADDR,
NIC_SRAM_RX_JUMBO_BUFFER_DESC);
} else {
@@ -7903,6 +7928,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
val = (RX_STD_MAX_SIZE_5705 << BDINFO_FLAGS_MAXLEN_SHIFT) |
(TG3_RX_STD_DMA_SZ << 2);
@@ -7921,6 +7947,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32_rx_mbox(TG3_RX_JMB_PROD_IDX_REG, tpr->rx_jmb_prod_idx);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
tw32(STD_REPLENISH_LWM, 32);
tw32(JMB_REPLENISH_LWM, 16);
@@ -7956,7 +7983,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB);
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
rdmac_mode |= RDMAC_MODE_MULT_DMA_RD_DIS;
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 ||
@@ -8195,6 +8223,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
tp->tx_mode = TX_MODE_ENABLE;
+ if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tp->tx_mode |= TX_MODE_MBUF_LOCKUP_FIX;
tw32_f(MAC_TX_MODE, tp->tx_mode);
udelay(100);
@@ -8206,7 +8237,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
for (i = 0; i < TG3_RSS_INDIR_TBL_SIZE; i++) {
int idx = i % sizeof(val);
- ent[idx] = i % (tp->irq_cnt - 1);
+ ent[idx] = (i % (tp->irq_cnt - 1)) + 1;
if (idx == sizeof(val) - 1) {
tw32(reg, val);
reg += 4;
@@ -8511,8 +8542,10 @@ static void tg3_timer(unsigned long __opaque)
}
tg3_setup_phy(tp, 0);
}
- } else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ } else if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) &&
+ !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) {
tg3_serdes_parallel_detect(tp);
+ }
tp->timer_counter = tp->timer_multiplier;
}
@@ -8606,6 +8639,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
* observable way to know whether the interrupt was delivered.
*/
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
val = tr32(MSGINT_MODE) | MSGINT_MODE_ONE_SHOT_DISABLE;
@@ -8650,6 +8684,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
if (intr_ok) {
/* Reenable MSI one shot mode. */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) &&
(tp->tg3_flags2 & TG3_FLG2_USING_MSI)) {
val = tr32(MSGINT_MODE) & ~MSGINT_MODE_ONE_SHOT_DISABLE;
@@ -8775,9 +8810,9 @@ static bool tg3_enable_msix(struct tg3 *tp)
}
rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt);
- if (rc != 0) {
- if (rc < TG3_RSS_MIN_NUM_MSIX_VECS)
- return false;
+ if (rc < 0) {
+ return false;
+ } else if (rc != 0) {
if (pci_enable_msix(tp->pdev, msix_ent, rc))
return false;
netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n",
@@ -8785,16 +8820,19 @@ static bool tg3_enable_msix(struct tg3 *tp)
tp->irq_cnt = rc;
}
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
-
for (i = 0; i < tp->irq_max; i++)
tp->napi[i].irq_vec = msix_ent[i].vector;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
- tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
- } else
- tp->dev->real_num_tx_queues = 1;
+ tp->dev->real_num_tx_queues = 1;
+ if (tp->irq_cnt > 1) {
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_RSS;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ tp->tg3_flags3 |= TG3_FLG3_ENABLE_TSS;
+ tp->dev->real_num_tx_queues = tp->irq_cnt - 1;
+ }
+ }
return true;
}
@@ -8943,6 +8981,7 @@ static int tg3_open(struct net_device *dev)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765 &&
(tp->tg3_flags2 & TG3_FLG2_USING_MSI) &&
(tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)) {
@@ -10554,7 +10593,8 @@ static int tg3_test_memory(struct tg3 *tp)
int err = 0;
int i;
- if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
mem_tbl = mem_tbl_5717;
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
mem_tbl = mem_tbl_57765;
@@ -11634,7 +11674,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tg3_get_57780_nvram_info(tp);
- else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719)
tg3_get_5717_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -12070,11 +12111,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
tp->phy_id = eeprom_phy_id;
if (eeprom_phy_serdes) {
- if ((tp->tg3_flags2 & TG3_FLG2_5780_CLASS) ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717)
- tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
- else
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
tp->tg3_flags2 |= TG3_FLG2_PHY_SERDES;
+ else
+ tp->tg3_flags2 |= TG3_FLG2_MII_SERDES;
}
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
@@ -12804,7 +12844,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5717 ||
tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
- tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724)
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5724 ||
+ tp->pdev->device == TG3PCI_DEVICE_TIGON3_5719)
pci_read_config_dword(tp->pdev,
TG3PCI_GEN2_PRODID_ASICREV,
&prod_id_asic_rev);
@@ -12970,6 +13011,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tp->tg3_flags3 |= TG3_FLG3_5755_PLUS;
@@ -12999,6 +13041,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
/* Determine TSO capabilities */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_3;
else if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
@@ -13036,6 +13079,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
tp->tg3_flags |= TG3_FLAG_SUPPORT_MSIX;
tp->irq_max = TG3_IRQ_MAX_VECS;
@@ -13043,6 +13087,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
else if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) {
@@ -13051,6 +13096,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tp->tg3_flags3 |= TG3_FLG3_USE_JUMBO_BDFLAG;
@@ -13242,7 +13288,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* APE register and memory space.
*/
pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
- PCISTATE_ALLOW_APE_SHMEM_WR;
+ PCISTATE_ALLOW_APE_SHMEM_WR |
+ PCISTATE_ALLOW_APE_PSPACE_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
pci_state_reg);
}
@@ -13252,6 +13299,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;
@@ -13332,6 +13380,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57765) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
@@ -13580,9 +13629,12 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
tw32_f(NVRAM_CMD, NVRAM_CMD_RESET);
else
tg3_nvram_unlock(tp);
- } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) {
- if (tr32(TG3_CPMU_STATUS) & TG3_CPMU_STATUS_PCIE_FUNC)
+ } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719) {
+ if (PCI_FUNC(tp->pdev->devfn) & 1)
mac_offset = 0xcc;
+ if (PCI_FUNC(tp->pdev->devfn) > 1)
+ mac_offset += 0x18c;
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
mac_offset = 0x10;
@@ -13668,6 +13720,7 @@ static u32 __devinit tg3_calc_dma_bndry(struct tg3 *tp, u32 val)
#endif
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
val = goal ? 0 : DMA_RWCTRL_DIS_CACHE_ALIGNMENT;
goto out;
@@ -13880,6 +13933,7 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
tp->dma_rwctrl = tg3_calc_dma_bndry(tp, tp->dma_rwctrl);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765)
goto out;
@@ -14079,6 +14133,7 @@ static void __devinit tg3_init_link_config(struct tg3 *tp)
static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
{
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765) {
tp->bufmgr_config.mbuf_read_dma_low_water =
DEFAULT_MB_RDMA_LOW_WATER_5705;
@@ -14156,6 +14211,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case TG3_PHY_ID_BCM5718C: return "5718C";
case TG3_PHY_ID_BCM5718S: return "5718S";
case TG3_PHY_ID_BCM57765: return "57765";
+ case TG3_PHY_ID_BCM5719C: return "5719C";
case TG3_PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -14404,7 +14460,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
}
if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) &&
- tp->pci_chip_rev_id != CHIPREV_ID_5717_A0)
+ tp->pci_chip_rev_id != CHIPREV_ID_5717_A0 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5719)
dev->netdev_ops = &tg3_netdev_ops;
else
dev->netdev_ops = &tg3_netdev_ops_dma_bug;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index ce9c4918c318..6b6af7698b38 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -53,6 +53,7 @@
#define TG3PCI_DEVICE_TIGON3_57765 0x16b4
#define TG3PCI_DEVICE_TIGON3_57791 0x16b2
#define TG3PCI_DEVICE_TIGON3_57795 0x16b6
+#define TG3PCI_DEVICE_TIGON3_5719 0x1657
/* 0x04 --> 0x2c unused */
#define TG3PCI_SUBVENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
#define TG3PCI_SUBDEVICE_ID_BROADCOM_95700A6 0x1644
@@ -160,6 +161,7 @@
#define ASIC_REV_57780 0x57780
#define ASIC_REV_5717 0x5717
#define ASIC_REV_57765 0x57785
+#define ASIC_REV_5719 0x5719
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -231,6 +233,7 @@
#define PCISTATE_RETRY_SAME_DMA 0x00002000
#define PCISTATE_ALLOW_APE_CTLSPC_WR 0x00010000
#define PCISTATE_ALLOW_APE_SHMEM_WR 0x00020000
+#define PCISTATE_ALLOW_APE_PSPACE_WR 0x00040000
#define TG3PCI_CLOCK_CTRL 0x00000074
#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200
#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400
@@ -468,6 +471,7 @@
#define TX_MODE_FLOW_CTRL_ENABLE 0x00000010
#define TX_MODE_BIG_BCKOFF_ENABLE 0x00000020
#define TX_MODE_LONG_PAUSE_ENABLE 0x00000040
+#define TX_MODE_MBUF_LOCKUP_FIX 0x00000100
#define MAC_TX_STATUS 0x00000460
#define TX_STATUS_XOFFED 0x00000001
#define TX_STATUS_SENT_XOFF 0x00000002
@@ -1071,10 +1075,8 @@
#define TG3_CPMU_HST_ACC 0x0000361c
#define CPMU_HST_ACC_MACCLK_MASK 0x001f0000
#define CPMU_HST_ACC_MACCLK_6_25 0x00130000
-/* 0x3620 --> 0x362c unused */
+/* 0x3620 --> 0x3630 unused */
-#define TG3_CPMU_STATUS 0x0000362c
-#define TG3_CPMU_STATUS_PCIE_FUNC 0x20000000
#define TG3_CPMU_CLCK_STAT 0x00003630
#define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000
#define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000
@@ -2209,6 +2211,11 @@
#define APE_EVENT_STATUS_STATE_SUSPEND 0x00040000
#define APE_EVENT_STATUS_EVENT_PENDING 0x80000000
+#define TG3_APE_PER_LOCK_REQ 0x8400
+#define APE_LOCK_PER_REQ_DRIVER 0x00001000
+#define TG3_APE_PER_LOCK_GRANT 0x8420
+#define APE_PER_LOCK_GRANT_DRIVER 0x00001000
+
/* APE convenience enumerations. */
#define TG3_APE_LOCK_GRC 1
#define TG3_APE_LOCK_MEM 4
@@ -2942,6 +2949,7 @@ struct tg3 {
#define TG3_PHY_ID_BCM5718C 0x5c0d8a00
#define TG3_PHY_ID_BCM5718S 0xbc050ff0
#define TG3_PHY_ID_BCM57765 0x5c0d8a40
+#define TG3_PHY_ID_BCM5719C 0x5c0d8a20
#define TG3_PHY_ID_BCM5906 0xdc00ac40
#define TG3_PHY_ID_BCM8002 0x60010140
#define TG3_PHY_ID_INVALID 0xffffffff
@@ -2965,7 +2973,8 @@ struct tg3 {
(X) == TG3_PHY_ID_BCM5755 || (X) == TG3_PHY_ID_BCM5756 || \
(X) == TG3_PHY_ID_BCM5906 || (X) == TG3_PHY_ID_BCM5761 || \
(X) == TG3_PHY_ID_BCM5718C || (X) == TG3_PHY_ID_BCM5718S || \
- (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM8002)
+ (X) == TG3_PHY_ID_BCM57765 || (X) == TG3_PHY_ID_BCM5719C || \
+ (X) == TG3_PHY_ID_BCM8002)
u32 led_ctrl;
u32 phy_otp;
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index c0e70006374e..960962660079 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -262,13 +262,13 @@ struct de_srom_media_block {
u16 csr13;
u16 csr14;
u16 csr15;
-} __attribute__((packed));
+} __packed;
struct de_srom_info_leaf {
u16 default_media;
u8 n_blocks;
u8 unused;
-} __attribute__((packed));
+} __packed;
struct de_desc {
__le32 opts1;
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 6002e651b9ea..3031ed9c4a1a 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -120,8 +120,8 @@ static void __devinit tulip_build_fake_mediatable(struct tulip_private *tp)
0x00, 0x06 /* ttm bit map */
};
- tp->mtable = (struct mediatable *)
- kmalloc(sizeof(struct mediatable) + sizeof(struct medialeaf), GFP_KERNEL);
+ tp->mtable = kmalloc(sizeof(struct mediatable) +
+ sizeof(struct medialeaf), GFP_KERNEL);
if (tp->mtable == NULL)
return; /* Horrible, impossible failure. */
@@ -227,9 +227,9 @@ subsequent_board:
return;
}
- mtable = (struct mediatable *)
- kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
- GFP_KERNEL);
+ mtable = kmalloc(sizeof(struct mediatable) +
+ count * sizeof(struct medialeaf),
+ GFP_KERNEL);
if (mtable == NULL)
return; /* Horrible, impossible failure. */
last_mediatable = tp->mtable = mtable;
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 0afa2d4f9472..e525875ed67d 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -20,6 +20,7 @@
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
+#include <linux/ethtool.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/pci.h>
@@ -51,22 +52,23 @@ struct tulip_chip_table {
enum tbl_flag {
- HAS_MII = 0x0001,
- HAS_MEDIA_TABLE = 0x0002,
- CSR12_IN_SROM = 0x0004,
- ALWAYS_CHECK_MII = 0x0008,
- HAS_ACPI = 0x0010,
- MC_HASH_ONLY = 0x0020, /* Hash-only multicast filter. */
- HAS_PNICNWAY = 0x0080,
- HAS_NWAY = 0x0040, /* Uses internal NWay xcvr. */
- HAS_INTR_MITIGATION = 0x0100,
- IS_ASIX = 0x0200,
- HAS_8023X = 0x0400,
- COMET_MAC_ADDR = 0x0800,
- HAS_PCI_MWI = 0x1000,
- HAS_PHY_IRQ = 0x2000,
- HAS_SWAPPED_SEEPROM = 0x4000,
- NEEDS_FAKE_MEDIA_TABLE = 0x8000,
+ HAS_MII = 0x00001,
+ HAS_MEDIA_TABLE = 0x00002,
+ CSR12_IN_SROM = 0x00004,
+ ALWAYS_CHECK_MII = 0x00008,
+ HAS_ACPI = 0x00010,
+ MC_HASH_ONLY = 0x00020, /* Hash-only multicast filter. */
+ HAS_PNICNWAY = 0x00080,
+ HAS_NWAY = 0x00040, /* Uses internal NWay xcvr. */
+ HAS_INTR_MITIGATION = 0x00100,
+ IS_ASIX = 0x00200,
+ HAS_8023X = 0x00400,
+ COMET_MAC_ADDR = 0x00800,
+ HAS_PCI_MWI = 0x01000,
+ HAS_PHY_IRQ = 0x02000,
+ HAS_SWAPPED_SEEPROM = 0x04000,
+ NEEDS_FAKE_MEDIA_TABLE = 0x08000,
+ COMET_PM = 0x10000,
};
@@ -120,6 +122,11 @@ enum tulip_offsets {
CSR13 = 0x68,
CSR14 = 0x70,
CSR15 = 0x78,
+ CSR18 = 0x88,
+ CSR19 = 0x8c,
+ CSR20 = 0x90,
+ CSR27 = 0xAC,
+ CSR28 = 0xB0,
};
/* register offset and bits for CFDD PCI config reg */
@@ -289,6 +296,30 @@ enum t21143_csr6_bits {
csr6_mask_100bt = (csr6_scr | csr6_pcs | csr6_hbd),
};
+enum tulip_comet_csr13_bits {
+/* The LINKOFFE and LINKONE work in conjunction with LSCE, i.e. they
+ * determine which link status transition wakes up if LSCE is
+ * enabled */
+ comet_csr13_linkoffe = (1 << 17),
+ comet_csr13_linkone = (1 << 16),
+ comet_csr13_wfre = (1 << 10),
+ comet_csr13_mpre = (1 << 9),
+ comet_csr13_lsce = (1 << 8),
+ comet_csr13_wfr = (1 << 2),
+ comet_csr13_mpr = (1 << 1),
+ comet_csr13_lsc = (1 << 0),
+};
+
+enum tulip_comet_csr18_bits {
+ comet_csr18_pmes_sticky = (1 << 24),
+ comet_csr18_pm_mode = (1 << 19),
+ comet_csr18_apm_mode = (1 << 18),
+ comet_csr18_d3a = (1 << 7)
+};
+
+enum tulip_comet_csr20_bits {
+ comet_csr20_pmes = (1 << 15),
+};
/* Keep the ring sizes a power of two for efficiency.
Making the Tx ring too large decreases the effectiveness of channel
@@ -411,6 +442,7 @@ struct tulip_private {
unsigned int csr6; /* Current CSR6 control settings. */
unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
void (*link_change) (struct net_device * dev, int csr5);
+ struct ethtool_wolinfo wolinfo; /* WOL settings */
u16 sym_advertise, mii_advertise; /* NWay capabilities advertised. */
u16 lpar; /* 21143 Link partner ability. */
u16 advertising[4];
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 254643ed945e..03e96b928c04 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -30,7 +30,6 @@
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/mii.h>
-#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <asm/unaligned.h>
#include <asm/uaccess.h>
@@ -272,6 +271,7 @@ static void tulip_down(struct net_device *dev);
static struct net_device_stats *tulip_get_stats(struct net_device *dev);
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
+static void tulip_set_wolopts(struct pci_dev *pdev, u32 wolopts);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_tulip(struct net_device *dev);
#endif
@@ -309,6 +309,11 @@ static void tulip_up(struct net_device *dev)
/* Wake the chip from sleep/snooze mode. */
tulip_set_power_state (tp, 0, 0);
+ /* Disable all WOL events */
+ pci_enable_wake(tp->pdev, PCI_D3hot, 0);
+ pci_enable_wake(tp->pdev, PCI_D3cold, 0);
+ tulip_set_wolopts(tp->pdev, 0);
+
/* On some chip revs we must set the MII/SYM port before the reset!? */
if (tp->mii_cnt || (tp->mtable && tp->mtable->has_mii))
iowrite32(0x00040000, ioaddr + CSR6);
@@ -345,8 +350,8 @@ static void tulip_up(struct net_device *dev)
} else if (tp->flags & COMET_MAC_ADDR) {
iowrite32(addr_low, ioaddr + 0xA4);
iowrite32(addr_high, ioaddr + 0xA8);
- iowrite32(0, ioaddr + 0xAC);
- iowrite32(0, ioaddr + 0xB0);
+ iowrite32(0, ioaddr + CSR27);
+ iowrite32(0, ioaddr + CSR28);
}
} else {
/* This is set_rx_mode(), but without starting the transmitter. */
@@ -876,8 +881,35 @@ static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
strcpy(info->bus_info, pci_name(np->pdev));
}
+
+static int tulip_ethtool_set_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct tulip_private *tp = netdev_priv(dev);
+
+ if (wolinfo->wolopts & (~tp->wolinfo.supported))
+ return -EOPNOTSUPP;
+
+ tp->wolinfo.wolopts = wolinfo->wolopts;
+ device_set_wakeup_enable(&tp->pdev->dev, tp->wolinfo.wolopts);
+ return 0;
+}
+
+static void tulip_ethtool_get_wol(struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ struct tulip_private *tp = netdev_priv(dev);
+
+ wolinfo->supported = tp->wolinfo.supported;
+ wolinfo->wolopts = tp->wolinfo.wolopts;
+ return;
+}
+
+
static const struct ethtool_ops ops = {
- .get_drvinfo = tulip_get_drvinfo
+ .get_drvinfo = tulip_get_drvinfo,
+ .set_wol = tulip_ethtool_set_wol,
+ .get_wol = tulip_ethtool_get_wol,
};
/* Provide ioctl() calls to examine the MII xcvr state. */
@@ -1093,8 +1125,8 @@ static void set_rx_mode(struct net_device *dev)
iowrite32(3, ioaddr + CSR13);
iowrite32(mc_filter[1], ioaddr + CSR14);
} else if (tp->flags & COMET_MAC_ADDR) {
- iowrite32(mc_filter[0], ioaddr + 0xAC);
- iowrite32(mc_filter[1], ioaddr + 0xB0);
+ iowrite32(mc_filter[0], ioaddr + CSR27);
+ iowrite32(mc_filter[1], ioaddr + CSR28);
}
tp->mc_filter[0] = mc_filter[0];
tp->mc_filter[1] = mc_filter[1];
@@ -1381,6 +1413,13 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
return i;
}
+ /* The chip will fail to enter a low-power state later unless
+ * first explicitly commanded into D0 */
+ if (pci_set_power_state(pdev, PCI_D0)) {
+ printk (KERN_NOTICE PFX
+ "Failed to set power state to D0\n");
+ }
+
irq = pdev->irq;
/* alloc_etherdev ensures aligned and zeroed private structures */
@@ -1427,6 +1466,19 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->chip_id = chip_idx;
tp->flags = tulip_tbl[chip_idx].flags;
+
+ tp->wolinfo.supported = 0;
+ tp->wolinfo.wolopts = 0;
+ /* COMET: Enable power management only for AN983B */
+ if (chip_idx == COMET ) {
+ u32 sig;
+ pci_read_config_dword (pdev, 0x80, &sig);
+ if (sig == 0x09811317) {
+ tp->flags |= COMET_PM;
+ tp->wolinfo.supported = WAKE_PHY | WAKE_MAGIC;
+ printk(KERN_INFO "tulip_init_one: Enabled WOL support for AN983B\n");
+ }
+ }
tp->pdev = pdev;
tp->base_addr = ioaddr;
tp->revision = pdev->revision;
@@ -1759,11 +1811,43 @@ err_out_free_netdev:
}
+/* set the registers according to the given wolopts */
+static void tulip_set_wolopts (struct pci_dev *pdev, u32 wolopts)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
+
+ if (tp->flags & COMET_PM) {
+
+ unsigned int tmp;
+
+ tmp = ioread32(ioaddr + CSR18);
+ tmp &= ~(comet_csr18_pmes_sticky | comet_csr18_apm_mode | comet_csr18_d3a);
+ tmp |= comet_csr18_pm_mode;
+ iowrite32(tmp, ioaddr + CSR18);
+
+ /* Set the Wake-up Control/Status Register to the given WOL options*/
+ tmp = ioread32(ioaddr + CSR13);
+ tmp &= ~(comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_wfre | comet_csr13_lsce | comet_csr13_mpre);
+ if (wolopts & WAKE_MAGIC)
+ tmp |= comet_csr13_mpre;
+ if (wolopts & WAKE_PHY)
+ tmp |= comet_csr13_linkoffe | comet_csr13_linkone | comet_csr13_lsce;
+ /* Clear the event flags */
+ tmp |= comet_csr13_wfr | comet_csr13_mpr | comet_csr13_lsc;
+ iowrite32(tmp, ioaddr + CSR13);
+ }
+}
+
#ifdef CONFIG_PM
+
static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
{
+ pci_power_t pstate;
struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
if (!dev)
return -EINVAL;
@@ -1779,7 +1863,16 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
save_state:
pci_save_state(pdev);
pci_disable_device(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ pstate = pci_choose_state(pdev, state);
+ if (state.event == PM_EVENT_SUSPEND && pstate != PCI_D0) {
+ int rc;
+
+ tulip_set_wolopts(pdev, tp->wolinfo.wolopts);
+ rc = pci_enable_wake(pdev, pstate, tp->wolinfo.wolopts);
+ if (rc)
+ printk("tulip: pci_enable_wake failed (%d)\n", rc);
+ }
+ pci_set_power_state(pdev, pstate);
return 0;
}
@@ -1788,7 +1881,10 @@ save_state:
static int tulip_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ struct tulip_private *tp = netdev_priv(dev);
+ void __iomem *ioaddr = tp->base_addr;
int retval;
+ unsigned int tmp;
if (!dev)
return -EINVAL;
@@ -1809,6 +1905,18 @@ static int tulip_resume(struct pci_dev *pdev)
return retval;
}
+ if (tp->flags & COMET_PM) {
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+
+ /* Clear the PMES flag */
+ tmp = ioread32(ioaddr + CSR20);
+ tmp |= comet_csr20_pmes;
+ iowrite32(tmp, ioaddr + CSR20);
+
+ /* Disable all wake-up events */
+ tulip_set_wolopts(pdev, 0);
+ }
netif_device_attach(dev);
if (netif_running(dev))
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 22bde49262c0..2e50077ff450 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -255,7 +255,7 @@ struct typhoon_shared {
struct rx_free rxBuff[RXFREE_ENTRIES] __3xp_aligned;
u32 zeroWord;
struct tx_desc txHi[TXHI_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
struct rxbuff_ent {
struct sk_buff *skb;
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 673fd5125914..88187fc84aa3 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -77,7 +77,7 @@ struct typhoon_indexes {
volatile __le32 cmdCleared;
volatile __le32 respReady;
volatile __le32 rxHiReady;
-} __attribute__ ((packed));
+} __packed;
/* The host<->Typhoon interface
* Our means of communicating where things are
@@ -125,7 +125,7 @@ struct typhoon_interface {
__le32 rxHiAddr;
__le32 rxHiAddrHi;
__le32 rxHiSize;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon transmit/fragment descriptor
*
@@ -187,7 +187,7 @@ struct tx_desc {
#define TYPHOON_TX_PF_VLAN_MASK cpu_to_le32(0x0ffff000)
#define TYPHOON_TX_PF_INTERNAL cpu_to_le32(0xf0000000)
#define TYPHOON_TX_PF_VLAN_TAG_SHIFT 12
-} __attribute__ ((packed));
+} __packed;
/* The TCP Segmentation offload option descriptor
*
@@ -208,7 +208,7 @@ struct tcpopt_desc {
__le32 respAddrLo;
__le32 bytesTx;
__le32 status;
-} __attribute__ ((packed));
+} __packed;
/* The IPSEC Offload descriptor
*
@@ -227,7 +227,7 @@ struct ipsec_desc {
__le32 sa1;
__le32 sa2;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon receive descriptor (Updated by NIC)
*
@@ -284,7 +284,7 @@ struct rx_desc {
#define TYPHOON_RX_UNKNOWN_SA cpu_to_le16(0x0100)
#define TYPHOON_RX_ESP_FORMAT_ERR cpu_to_le16(0x0200)
__be32 vlanTag;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon free buffer descriptor, used to give a buffer to the NIC
*
@@ -301,7 +301,7 @@ struct rx_free {
__le32 physAddrHi;
u32 virtAddr;
u32 virtAddrHi;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon command descriptor, used for commands and responses
*
@@ -347,7 +347,7 @@ struct cmd_desc {
__le16 parm1;
__le32 parm2;
__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon response descriptor, see command descriptor for details
*/
@@ -359,7 +359,7 @@ struct resp_desc {
__le16 parm1;
__le32 parm2;
__le32 parm3;
-} __attribute__ ((packed));
+} __packed;
#define INIT_COMMAND_NO_RESPONSE(x, command) \
do { struct cmd_desc *_ptr = (x); \
@@ -427,7 +427,7 @@ struct stats_resp {
#define TYPHOON_LINK_HALF_DUPLEX cpu_to_le32(0x00000000)
__le32 unused2;
__le32 unused3;
-} __attribute__ ((packed));
+} __packed;
/* TYPHOON_CMD_XCVR_SELECT xcvr values (resp.parm1)
*/
@@ -488,7 +488,7 @@ struct sa_descriptor {
u32 index;
u32 unused;
u32 unused2;
-} __attribute__ ((packed));
+} __packed;
/* TYPHOON_CMD_SET_OFFLOAD_TASKS bits (cmd.parm2 (Tx) & cmd.parm3 (Rx))
* This is all for IPv4.
@@ -518,14 +518,14 @@ struct typhoon_file_header {
__le32 numSections;
__le32 startAddr;
__le32 hmacDigest[5];
-} __attribute__ ((packed));
+} __packed;
struct typhoon_section_header {
__le32 len;
u16 checksum;
u16 reserved;
__le32 startAddr;
-} __attribute__ ((packed));
+} __packed;
/* The Typhoon Register offsets
*/
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index ef1fbeb11c6e..05a95586f3c5 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -106,7 +106,7 @@ struct ucc_geth {
u32 scar; /* Statistics carry register */
u32 scam; /* Statistics caryy mask register */
u8 res5[0x200 - 0x1c4];
-} __attribute__ ((packed));
+} __packed;
/* UCC GETH TEMODR Register */
#define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics
@@ -420,11 +420,11 @@ struct ucc_geth {
struct ucc_geth_thread_data_tx {
u8 res0[104];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_data_rx {
u8 res0[40];
-} __attribute__ ((packed));
+} __packed;
/* Send Queue Queue-Descriptor */
struct ucc_geth_send_queue_qd {
@@ -432,19 +432,19 @@ struct ucc_geth_send_queue_qd {
u8 res0[0x8];
u32 last_bd_completed_address;/* initialize to last entry in BD ring */
u8 res1[0x30];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_send_queue_mem_region {
struct ucc_geth_send_queue_qd sqqd[NUM_TX_QUEUES];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_tx_pram {
u8 res0[64];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_thread_rx_pram {
u8 res0[128];
-} __attribute__ ((packed));
+} __packed;
#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64
#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64
@@ -484,7 +484,7 @@ struct ucc_geth_scheduler {
/**< weight factor for queues */
u32 minw; /* temporary variable handled by QE */
u8 res1[0x70 - 0x64];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_tx_firmware_statistics_pram {
u32 sicoltx; /* single collision */
@@ -506,7 +506,7 @@ struct ucc_geth_tx_firmware_statistics_pram {
and 1518 octets */
u32 txpktsjumbo; /* total packets (including bad) between 1024
and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_firmware_statistics_pram {
u32 frrxfcser; /* frames with crc error */
@@ -540,7 +540,7 @@ struct ucc_geth_rx_firmware_statistics_pram {
replaced */
u32 insertvlan; /* total frames that had their VLAN tag
inserted */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_interrupt_coalescing_entry {
u32 interruptcoalescingmaxvalue; /* interrupt coalescing max
@@ -548,23 +548,23 @@ struct ucc_geth_rx_interrupt_coalescing_entry {
u32 interruptcoalescingcounter; /* interrupt coalescing counter,
initialize to
interruptcoalescingmaxvalue */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_interrupt_coalescing_table {
struct ucc_geth_rx_interrupt_coalescing_entry coalescingentry[NUM_RX_QUEUES];
/**< interrupt coalescing entry */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_prefetched_bds {
struct qe_bd bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_bd_queues_entry {
u32 bdbaseptr; /* BD base pointer */
u32 bdptr; /* BD pointer */
u32 externalbdbaseptr; /* external BD base pointer */
u32 externalbdptr; /* external BD pointer */
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_tx_global_pram {
u16 temoder;
@@ -580,13 +580,13 @@ struct ucc_geth_tx_global_pram {
u32 tqptr; /* a base pointer to the Tx Queues Memory
Region */
u8 res2[0x80 - 0x74];
-} __attribute__ ((packed));
+} __packed;
/* structure representing Extended Filtering Global Parameters in PRAM */
struct ucc_geth_exf_global_pram {
u32 l2pcdptr; /* individual address filter, high */
u8 res0[0x10 - 0x04];
-} __attribute__ ((packed));
+} __packed;
struct ucc_geth_rx_global_pram {
u32 remoder; /* ethernet mode reg. */
@@ -620,7 +620,7 @@ struct ucc_geth_rx_global_pram {
u32 exfGlobalParam; /* base address for extended filtering global
parameters */
u8 res6[0x100 - 0xC4]; /* Initialize to zero */
-} __attribute__ ((packed));
+} __packed;
#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
@@ -639,7 +639,7 @@ struct ucc_geth_init_pram {
u32 txglobal; /* tx global */
u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */
u8 res3[0x1];
-} __attribute__ ((packed));
+} __packed;
#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
@@ -661,7 +661,7 @@ struct ucc_geth_82xx_enet_address {
u16 h; /* address (MSB) */
u16 m; /* address */
u16 l; /* address (LSB) */
-} __attribute__ ((packed));
+} __packed;
/* structure representing 82xx Address Filtering PRAM */
struct ucc_geth_82xx_address_filtering_pram {
@@ -672,7 +672,7 @@ struct ucc_geth_82xx_address_filtering_pram {
struct ucc_geth_82xx_enet_address __iomem taddr;
struct ucc_geth_82xx_enet_address __iomem paddr[NUM_OF_PADDRS];
u8 res0[0x40 - 0x38];
-} __attribute__ ((packed));
+} __packed;
/* GETH Tx firmware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -696,7 +696,7 @@ struct ucc_geth_tx_firmware_statistics {
and 1518 octets */
u32 txpktsjumbo; /* total packets (including bad) between 1024
and MAXLength octets */
-} __attribute__ ((packed));
+} __packed;
/* GETH Rx firmware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -732,7 +732,7 @@ struct ucc_geth_rx_firmware_statistics {
replaced */
u32 insertvlan; /* total frames that had their VLAN tag
inserted */
-} __attribute__ ((packed));
+} __packed;
/* GETH hardware statistics structure, used when calling
UCC_GETH_GetStatistics. */
@@ -781,7 +781,7 @@ struct ucc_geth_hardware_statistics {
u32 rbca; /* Total number of frames received successfully
that had destination address equal to the
broadcast address */
-} __attribute__ ((packed));
+} __packed;
/* UCC GETH Tx errors returned via TxConf callback */
#define TX_ERRORS_DEF 0x0200
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 1f802e90474c..7e797ed0439a 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -179,7 +179,7 @@ struct ax88172_int_data {
__le16 res2;
u8 status;
__le16 res3;
-} __attribute__ ((packed));
+} __packed;
static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 0a3c41faea9c..c8570b097880 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -211,7 +211,7 @@ struct hso_serial_state_notification {
u16 wIndex;
u16 wLength;
u16 UART_state_bitmap;
-} __attribute__((packed));
+} __packed;
struct hso_tiocmget {
struct mutex mutex;
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index d6078b8c4273..2b7b39cad1ce 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -207,7 +207,7 @@ struct kaweth_ethernet_configuration
__le16 segment_size;
__u16 max_multicast_filters;
__u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
/****************************************************************
* kaweth_device
diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c
index 961a8ed38d8f..ba72a7281cb0 100644
--- a/drivers/net/usb/net1080.c
+++ b/drivers/net/usb/net1080.c
@@ -64,13 +64,13 @@ struct nc_header { // packed:
// all else is optional, and must start with:
// __le16 vendorId; // from usb-if
// __le16 productId;
-} __attribute__((__packed__));
+} __packed;
#define PAD_BYTE ((unsigned char)0xAC)
struct nc_trailer {
__le16 packet_id;
-} __attribute__((__packed__));
+} __packed;
// packets may use FLAG_FRAMING_NC and optional pad
#define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index f1942d69a0d5..ee85c8b9a858 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -165,7 +165,7 @@ struct lsi_umts {
u8 gw_addr_len; /* NW-supplied GW address len */
u8 gw_addr[16]; /* NW-supplied GW address (bigendian) */
u8 reserved[8];
-} __attribute__ ((packed));
+} __packed;
#define SIERRA_NET_LSI_COMMON_LEN 4
#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts))
diff --git a/drivers/net/vbus-enet.c b/drivers/net/vbus-enet.c
new file mode 100644
index 000000000000..94b86d482cee
--- /dev/null
+++ b/drivers/net/vbus-enet.c
@@ -0,0 +1,1560 @@
+/*
+ * vbus_enet - A virtualized 802.x network device based on the VBUS interface
+ *
+ * Copyright (C) 2009 Novell, Gregory Haskins <ghaskins@novell.com>
+ *
+ * Derived from the SNULL example from the book "Linux Device Drivers" by
+ * Alessandro Rubini, Jonathan Corbet, and Greg Kroah-Hartman, published
+ * by O'Reilly & Associates.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/ioq.h>
+#include <linux/vbus_driver.h>
+
+#include <linux/in6.h>
+#include <asm/checksum.h>
+
+#include <linux/venet.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("virtual-ethernet");
+MODULE_VERSION("1");
+
+static int rx_ringlen = 256;
+module_param(rx_ringlen, int, 0444);
+static int tx_ringlen = 256;
+module_param(tx_ringlen, int, 0444);
+static int sg_enabled = 1;
+module_param(sg_enabled, int, 0444);
+
+#define PDEBUG(_dev, fmt, args...) dev_dbg(&(_dev)->dev, fmt, ## args)
+
+#define SG_DESC_SIZE VSG_DESC_SIZE(MAX_SKB_FRAGS)
+
+struct vbus_enet_queue {
+ struct ioq *queue;
+ struct ioq_notifier notifier;
+ unsigned long count;
+};
+
+struct vbus_enet_priv {
+ spinlock_t lock;
+ struct net_device *dev;
+ struct vbus_device_proxy *vdev;
+ struct napi_struct napi;
+ struct vbus_enet_queue rxq;
+ struct {
+ struct vbus_enet_queue veq;
+ struct tasklet_struct task;
+ struct sk_buff_head outstanding;
+ } tx;
+ bool sg;
+ struct {
+ bool enabled;
+ char *pool;
+ } pmtd; /* pre-mapped transmit descriptors */
+ struct {
+ bool enabled;
+ bool linkstate;
+ bool txc;
+ unsigned long evsize;
+ struct vbus_enet_queue veq;
+ struct tasklet_struct task;
+ char *pool;
+ } evq;
+ struct {
+ bool available;
+ char *pool;
+ struct vbus_enet_queue pageq;
+ } l4ro;
+
+ struct sk_buff *(*import)(struct vbus_enet_priv *priv,
+ struct ioq_ring_desc *desc);
+};
+
+static void vbus_enet_tx_reap(struct vbus_enet_priv *priv);
+
+static struct vbus_enet_priv *
+napi_to_priv(struct napi_struct *napi)
+{
+ return container_of(napi, struct vbus_enet_priv, napi);
+}
+
+static int
+queue_init(struct vbus_enet_priv *priv,
+ struct vbus_enet_queue *q,
+ const char *name,
+ int qid,
+ size_t ringsize,
+ void (*func)(struct ioq_notifier *))
+{
+ struct vbus_device_proxy *dev = priv->vdev;
+ int ret;
+ char _name[64];
+
+ if (name)
+ snprintf(_name, sizeof(_name), "%s-%s", priv->dev->name, name);
+
+ ret = vbus_driver_ioq_alloc(dev, name ? _name : NULL, qid, 0,
+ ringsize, &q->queue);
+ if (ret < 0)
+ panic("ioq_alloc failed: %d\n", ret);
+
+ if (func) {
+ q->notifier.signal = func;
+ q->queue->notifier = &q->notifier;
+ }
+
+ q->count = ringsize;
+
+ return 0;
+}
+
+static int
+devcall(struct vbus_enet_priv *priv, u32 func, void *data, size_t len)
+{
+ struct vbus_device_proxy *dev = priv->vdev;
+
+ return dev->ops->call(dev, func, data, len, 0);
+}
+
+/*
+ * ---------------
+ * rx descriptors
+ * ---------------
+ */
+
+static void
+rxdesc_alloc(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc, size_t len)
+{
+ struct net_device *dev = priv->dev;
+ struct sk_buff *skb;
+
+ len += ETH_HLEN;
+
+ skb = netdev_alloc_skb(dev, len + NET_IP_ALIGN);
+ BUG_ON(!skb);
+
+ skb_reserve(skb, NET_IP_ALIGN); /* align IP on 16B boundary */
+
+ if (priv->l4ro.available) {
+ /*
+ * We will populate an SG descriptor initially with one
+ * IOV filled with an MTU SKB. If the packet needs to be
+ * larger than MTU, the host will grab pages out of the
+ * page-queue and populate additional IOVs
+ */
+ struct venet_sg *vsg = (struct venet_sg *)(unsigned long)desc->cookie;
+ struct venet_iov *iov = &vsg->iov[0];
+
+ memset(vsg, 0, SG_DESC_SIZE);
+
+ vsg->cookie = (u64)(unsigned long)skb;
+ vsg->count = 1;
+
+ iov->ptr = (u64)__pa(skb->data);
+ iov->len = len;
+ } else {
+ desc->cookie = (u64)(unsigned long)skb;
+ desc->ptr = cpu_to_le64(__pa(skb->data));
+ desc->len = cpu_to_le64(len); /* total length */
+ }
+
+ desc->valid = 1;
+}
+
+static void
+rx_pageq_refill(struct vbus_enet_priv *priv, gfp_t gfp_mask)
+{
+ struct ioq *ioq = priv->l4ro.pageq.queue;
+ struct ioq_iterator iter;
+ int ret, added = 0;
+
+ if (ioq_full(ioq, ioq_idxtype_inuse))
+ /* nothing to do if the pageq is already fully populated */
+ return;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0); /* will never fail unless seriously broken */
+
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty page
+ */
+ while (!iter.desc->sown) {
+ struct page *page = NULL;
+
+ page = alloc_page(gfp_mask);
+
+ if (!page)
+ break;
+
+ added = 1;
+ iter.desc->cookie = (u64)(unsigned long)page;
+ iter.desc->ptr = cpu_to_le64(__pa(page_address(page)));
+ iter.desc->len = cpu_to_le64(PAGE_SIZE);
+
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ if (added)
+ ioq_signal(ioq, 0);
+}
+
+static void
+rx_setup(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->rxq.queue;
+ struct ioq_iterator iter;
+ int ret;
+ int i = 0;
+
+ /*
+ * We want to iterate on the "valid" index. By default the iterator
+ * will not "autoupdate" which means it will not hypercall the host
+ * with our changes. This is good, because we are really just
+ * initializing stuff here anyway. Note that you can always manually
+ * signal the host with ioq_signal() if the autoupdate feature is not
+ * used.
+ */
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0); /* will never fail unless seriously broken */
+
+ /*
+ * Seek to the tail of the valid index (which should be our first
+ * item, since the queue is brand-new)
+ */
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty buffer and mark it valid
+ */
+ while (!iter.desc->valid) {
+ if (priv->l4ro.available) {
+ size_t offset = (i * SG_DESC_SIZE);
+ void *addr = &priv->l4ro.pool[offset];
+
+ iter.desc->ptr = cpu_to_le64(offset);
+ iter.desc->cookie = (u64)(unsigned long)addr;
+ iter.desc->len = cpu_to_le64(SG_DESC_SIZE);
+ }
+
+ rxdesc_alloc(priv, iter.desc, priv->dev->mtu);
+
+ /*
+ * This push operation will simultaneously advance the
+ * valid-head index and increment our position in the queue
+ * by one.
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+
+ i++;
+ }
+
+ if (priv->l4ro.available)
+ rx_pageq_refill(priv, GFP_KERNEL);
+}
+
+static void
+rx_rxq_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->rxq.queue;
+ struct ioq_iterator iter;
+ int ret;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->valid) {
+ struct sk_buff *skb;
+
+ if (priv->l4ro.available) {
+ struct venet_sg *vsg;
+ int i;
+
+ vsg = (struct venet_sg *)(unsigned long)iter.desc->cookie;
+
+ /* skip i=0, since that is the skb->data IOV */
+ for (i = 1; i < vsg->count; i++) {
+ struct venet_iov *iov = &vsg->iov[i];
+ struct page *page = (struct page *)(unsigned long)iov->ptr;
+
+ put_page(page);
+ }
+
+ skb = (struct sk_buff *)(unsigned long)vsg->cookie;
+ } else
+ skb = (struct sk_buff *)(unsigned long)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ dev_kfree_skb(skb);
+ }
+}
+
+static void
+rx_l4ro_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->l4ro.pageq.queue;
+ struct ioq_iterator iter;
+ int ret;
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->sown) {
+ struct page *page = (struct page *)(unsigned long)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ put_page(page);
+ }
+
+ ioq_put(ioq);
+ kfree(priv->l4ro.pool);
+}
+
+static void
+rx_teardown(struct vbus_enet_priv *priv)
+{
+ rx_rxq_teardown(priv);
+
+ if (priv->l4ro.available)
+ rx_l4ro_teardown(priv);
+}
+
+static int
+tx_setup(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->tx.veq.queue;
+ struct ioq_iterator iter;
+ int i;
+ int ret;
+
+ if (!priv->sg)
+ /*
+ * There is nothing to do for a ring that is not using
+ * scatter-gather
+ */
+ return 0;
+
+ /* pre-allocate our descriptor pool if pmtd is enabled */
+ if (priv->pmtd.enabled) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ size_t poollen = SG_DESC_SIZE * priv->tx.veq.count;
+ char *pool;
+ int shmid;
+
+ /* pmtdquery will return the shm-id to use for the pool */
+ ret = devcall(priv, VENET_FUNC_PMTDQUERY, NULL, 0);
+ BUG_ON(ret < 0);
+
+ shmid = ret;
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ priv->pmtd.pool = pool;
+
+ ret = dev->ops->shm(dev, NULL, shmid, 0, pool, poollen,
+ NULL, NULL, 0);
+ BUG_ON(ret < 0);
+ }
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty SG descriptor
+ */
+ for (i = 0; i < priv->tx.veq.count; i++) {
+ struct venet_sg *vsg;
+
+ if (priv->pmtd.enabled) {
+ size_t offset = (i * SG_DESC_SIZE);
+
+ vsg = (struct venet_sg *)&priv->pmtd.pool[offset];
+ iter.desc->ptr = cpu_to_le64(offset);
+ } else {
+ vsg = kzalloc(SG_DESC_SIZE, GFP_KERNEL);
+ if (!vsg)
+ return -ENOMEM;
+
+ iter.desc->ptr = cpu_to_le64(__pa(vsg));
+ }
+
+ iter.desc->cookie = (u64)(unsigned long)vsg;
+ iter.desc->len = cpu_to_le64(SG_DESC_SIZE);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+ BUG_ON(ret < 0);
+ }
+
+ return 0;
+}
+
+static void
+tx_teardown(struct vbus_enet_priv *priv)
+{
+ struct ioq *ioq = priv->tx.veq.queue;
+ struct ioq_iterator iter;
+ struct sk_buff *skb;
+ int ret;
+
+ /* forcefully free all outstanding transmissions */
+ while ((skb = __skb_dequeue(&priv->tx.outstanding)))
+ dev_kfree_skb(skb);
+
+ if (!priv->sg)
+ /*
+ * There is nothing else to do for a ring that is not using
+ * scatter-gather
+ */
+ return;
+
+ if (priv->pmtd.enabled) {
+ /*
+ * PMTD mode means we only need to free the pool
+ */
+ kfree(priv->pmtd.pool);
+ return;
+ }
+
+ ret = ioq_iter_init(ioq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ /* seek to position 0 */
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * free each valid descriptor
+ */
+ while (iter.desc->cookie) {
+ struct venet_sg *vsg = (struct venet_sg *)(unsigned long)iter.desc->cookie;
+
+ iter.desc->valid = 0;
+ wmb();
+
+ iter.desc->ptr = 0;
+ iter.desc->cookie = 0;
+
+ ret = ioq_iter_seek(&iter, ioq_seek_next, 0, 0);
+ BUG_ON(ret < 0);
+
+ kfree(vsg);
+ }
+}
+
+static void
+evq_teardown(struct vbus_enet_priv *priv)
+{
+ if (!priv->evq.enabled)
+ return;
+
+ ioq_put(priv->evq.veq.queue);
+ kfree(priv->evq.pool);
+}
+
+/*
+ * Open and close
+ */
+
+static int
+vbus_enet_open(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ ret = devcall(priv, VENET_FUNC_LINKUP, NULL, 0);
+ BUG_ON(ret < 0);
+
+ napi_enable(&priv->napi);
+
+ return 0;
+}
+
+static int
+vbus_enet_stop(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ napi_disable(&priv->napi);
+
+ ret = devcall(priv, VENET_FUNC_LINKDOWN, NULL, 0);
+ BUG_ON(ret < 0);
+
+ return 0;
+}
+
+/*
+ * Configuration changes (passed on by ifconfig)
+ */
+static int
+vbus_enet_config(struct net_device *dev, struct ifmap *map)
+{
+ if (dev->flags & IFF_UP) /* can't act on a running interface */
+ return -EBUSY;
+
+ /* Don't allow changing the I/O address */
+ if (map->base_addr != dev->base_addr) {
+ dev_warn(&dev->dev, "Can't change I/O address\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* ignore other fields */
+ return 0;
+}
+
+static void
+vbus_enet_schedule_rx(struct vbus_enet_priv *priv)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (napi_schedule_prep(&priv->napi)) {
+ /* Disable further interrupts */
+ ioq_notify_disable(priv->rxq.queue, 0);
+ __napi_schedule(&priv->napi);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int
+vbus_enet_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ int ret;
+
+ dev->mtu = new_mtu;
+
+ /*
+ * FLUSHRX will cause the device to flush any outstanding
+ * RX buffers. They will appear to come in as 0 length
+ * packets which we can simply discard and replace with new_mtu
+ * buffers for the future.
+ */
+ ret = devcall(priv, VENET_FUNC_FLUSHRX, NULL, 0);
+ BUG_ON(ret < 0);
+
+ vbus_enet_schedule_rx(priv);
+
+ return 0;
+}
+
+static struct sk_buff *
+vbus_enet_l4ro_import(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc)
+{
+ struct venet_sg *vsg = (struct venet_sg *)(unsigned long)desc->cookie;
+ struct sk_buff *skb = (struct sk_buff *)(unsigned long)vsg->cookie;
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+ int i;
+
+ rx_pageq_refill(priv, GFP_ATOMIC);
+
+ if (!vsg->len)
+ /*
+ * the device may send a zero-length packet when its
+ * flushing references on the ring. We can just drop
+ * these on the floor
+ */
+ goto fail;
+
+ /* advance only by the linear portion in IOV[0] */
+ skb_put(skb, vsg->iov[0].len);
+
+ /* skip i=0, since that is the skb->data IOV */
+ for (i = 1; i < vsg->count; i++) {
+ struct venet_iov *iov = &vsg->iov[i];
+ struct page *page = (struct page *)(unsigned long)iov->ptr;
+ skb_frag_t *f = &sinfo->frags[i-1];
+
+ f->page = page;
+ f->page_offset = 0;
+ f->size = iov->len;
+
+ PDEBUG(priv->dev, "SG: Importing %d byte page[%i]\n",
+ f->size, i);
+
+ skb->data_len += f->size;
+ skb->len += f->size;
+ skb->truesize += f->size;
+ sinfo->nr_frags++;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_NEEDS_CSUM
+ && !skb_partial_csum_set(skb, vsg->csum.start,
+ vsg->csum.offset)) {
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_GSO) {
+ PDEBUG(priv->dev, "L4RO packet detected\n");
+
+ switch (vsg->gso.type) {
+ case VENET_GSO_TYPE_TCPV4:
+ sinfo->gso_type = SKB_GSO_TCPV4;
+ break;
+ case VENET_GSO_TYPE_TCPV6:
+ sinfo->gso_type = SKB_GSO_TCPV6;
+ break;
+ case VENET_GSO_TYPE_UDP:
+ sinfo->gso_type = SKB_GSO_UDP;
+ break;
+ default:
+ PDEBUG(priv->dev, "Illegal L4RO type: %d\n",
+ vsg->gso.type);
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ if (vsg->flags & VENET_SG_FLAG_ECN)
+ sinfo->gso_type |= SKB_GSO_TCP_ECN;
+
+ sinfo->gso_size = vsg->gso.size;
+ if (sinfo->gso_size == 0) {
+ PDEBUG(priv->dev, "Illegal L4RO size: %d\n",
+ vsg->gso.size);
+ priv->dev->stats.rx_frame_errors++;
+ goto fail;
+ }
+
+ /*
+ * Header must be checked, and gso_segs
+ * computed.
+ */
+ sinfo->gso_type |= SKB_GSO_DODGY;
+ sinfo->gso_segs = 0;
+ }
+
+ return skb;
+
+fail:
+ dev_kfree_skb(skb);
+
+ return NULL;
+}
+
+static struct sk_buff *
+vbus_enet_flat_import(struct vbus_enet_priv *priv, struct ioq_ring_desc *desc)
+{
+ struct sk_buff *skb = (struct sk_buff *)(unsigned long)desc->cookie;
+
+ if (!desc->len) {
+ /*
+ * the device may send a zero-length packet when its
+ * flushing references on the ring. We can just drop
+ * these on the floor
+ */
+ dev_kfree_skb(skb);
+ return NULL;
+ }
+
+ skb_put(skb, le64_to_cpu(desc->len));
+
+ return skb;
+}
+
+/*
+ * The poll implementation.
+ */
+static int
+vbus_enet_poll(struct napi_struct *napi, int budget)
+{
+ struct vbus_enet_priv *priv = napi_to_priv(napi);
+ int npackets = 0;
+ struct ioq_iterator iter;
+ int ret;
+
+ PDEBUG(priv->dev, "polling...\n");
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(priv->rxq.queue, &iter, ioq_idxtype_inuse,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * We stop if we have met the quota or there are no more packets.
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side
+ */
+ while ((npackets < budget) && (!iter.desc->sown)) {
+ struct sk_buff *skb;
+
+ skb = priv->import(priv, iter.desc);
+ if (skb) {
+ /* Maintain stats */
+ npackets++;
+ priv->dev->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += skb->len;
+
+ /* Pass the buffer up to the stack */
+ skb->dev = priv->dev;
+ skb->protocol = eth_type_trans(skb, priv->dev);
+ netif_receive_skb(skb);
+
+ mb();
+ }
+
+ /* Grab a new buffer to put in the ring */
+ rxdesc_alloc(priv, iter.desc, priv->dev->mtu);
+
+ /* Advance the in-use tail */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ PDEBUG(priv->dev, "%d packets received\n", npackets);
+
+ /*
+ * If we processed all packets, we're done; tell the kernel and
+ * reenable ints
+ */
+ if (ioq_empty(priv->rxq.queue, ioq_idxtype_inuse)) {
+ napi_complete(napi);
+ ioq_notify_enable(priv->rxq.queue, 0);
+ ret = 0;
+ } else
+ /* We couldn't process everything. */
+ ret = 1;
+
+ return ret;
+}
+
+/*
+ * Transmit a packet (called by the kernel)
+ */
+static int
+vbus_enet_tx_start(struct sk_buff *skb, struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+ struct ioq_iterator iter;
+ int ret;
+ unsigned long flags;
+
+ PDEBUG(priv->dev, "sending %d bytes\n", skb->len);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ /*
+ * We must flow-control the kernel by disabling the
+ * queue
+ */
+ spin_unlock_irqrestore(&priv->lock, flags);
+ netif_stop_queue(dev);
+ dev_err(&priv->dev->dev, "tx on full queue bug\n");
+ return 1;
+ }
+
+ /*
+ * We want to iterate on the tail of both the "inuse" and "valid" index
+ * so we specify the "both" index
+ */
+ ret = ioq_iter_init(priv->tx.veq.queue, &iter, ioq_idxtype_both,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+ BUG_ON(iter.desc->sown);
+
+ if (priv->sg) {
+ struct venet_sg *vsg = (struct venet_sg *)(unsigned long)iter.desc->cookie;
+ struct scatterlist sgl[MAX_SKB_FRAGS+1];
+ struct scatterlist *sg;
+ int count, maxcount = ARRAY_SIZE(sgl);
+
+ sg_init_table(sgl, maxcount);
+
+ memset(vsg, 0, sizeof(*vsg));
+
+ vsg->cookie = (u64)(unsigned long)skb;
+ vsg->len = skb->len;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ vsg->flags |= VENET_SG_FLAG_NEEDS_CSUM;
+ vsg->csum.start = skb->csum_start - skb_headroom(skb);
+ vsg->csum.offset = skb->csum_offset;
+ }
+
+ if (skb_is_gso(skb)) {
+ struct skb_shared_info *sinfo = skb_shinfo(skb);
+
+ vsg->flags |= VENET_SG_FLAG_GSO;
+
+ vsg->gso.hdrlen = skb_headlen(skb);
+ vsg->gso.size = sinfo->gso_size;
+ if (sinfo->gso_type & SKB_GSO_TCPV4)
+ vsg->gso.type = VENET_GSO_TYPE_TCPV4;
+ else if (sinfo->gso_type & SKB_GSO_TCPV6)
+ vsg->gso.type = VENET_GSO_TYPE_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ vsg->gso.type = VENET_GSO_TYPE_UDP;
+ else
+ panic("Virtual-Ethernet: unknown GSO type " \
+ "0x%x\n", sinfo->gso_type);
+
+ if (sinfo->gso_type & SKB_GSO_TCP_ECN)
+ vsg->flags |= VENET_SG_FLAG_ECN;
+ }
+
+ count = skb_to_sgvec(skb, sgl, 0, skb->len);
+
+ BUG_ON(count > maxcount);
+
+ for (sg = &sgl[0]; sg; sg = sg_next(sg)) {
+ struct venet_iov *iov = &vsg->iov[vsg->count++];
+
+ iov->len = sg->length;
+ iov->ptr = (u64)sg_phys(sg);
+ }
+
+ iter.desc->len = cpu_to_le64(VSG_DESC_SIZE(vsg->count));
+
+ } else {
+ /*
+ * non scatter-gather mode: simply put the skb right onto the
+ * ring.
+ */
+ iter.desc->cookie = (u64)(unsigned long)skb;
+ iter.desc->len = cpu_to_le64(skb->len);
+ iter.desc->ptr = cpu_to_le64(__pa(skb->data));
+ }
+
+ iter.desc->valid = 1;
+
+ priv->dev->stats.tx_packets++;
+ priv->dev->stats.tx_bytes += skb->len;
+
+ skb_queue_tail(&priv->tx.outstanding, skb);
+
+ /*
+ * This advances both indexes together implicitly, and then
+ * signals the south side to consume the packet
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+
+ dev->trans_start = jiffies; /* save the timestamp */
+
+ if (ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ /*
+ * If the queue is congested, we must flow-control the kernel
+ */
+ PDEBUG(priv->dev, "backpressure tx queue\n");
+ netif_stop_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+/* assumes priv->lock held */
+static void
+vbus_enet_skb_complete(struct vbus_enet_priv *priv, struct sk_buff *skb)
+{
+ PDEBUG(priv->dev, "completed sending %d bytes\n",
+ skb->len);
+
+ skb_unlink(skb, &priv->tx.outstanding);
+ dev_kfree_skb(skb);
+}
+
+/*
+ * reclaim any outstanding completed tx packets
+ *
+ * assumes priv->lock held
+ */
+static struct sk_buff *
+vbus_enet_tx_reap_one(struct vbus_enet_priv *priv)
+{
+ struct sk_buff *skb = NULL;
+ struct ioq_iterator iter;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /*
+ * We want to iterate on the head of the valid index, but we
+ * do not want the iter_pop (below) to flip the ownership, so
+ * we set the NOFLIPOWNER option
+ */
+ ret = ioq_iter_init(priv->tx.veq.queue, &iter, ioq_idxtype_valid,
+ IOQ_ITER_NOFLIPOWNER);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ if (iter.desc->valid && !iter.desc->sown) {
+
+ if (priv->sg) {
+ struct venet_sg *vsg;
+
+ vsg = (struct venet_sg *)(unsigned long)iter.desc->cookie;
+ skb = (struct sk_buff *)(unsigned long)vsg->cookie;
+ } else
+ skb = (struct sk_buff *)(unsigned long)iter.desc->cookie;
+
+ /* Reset the descriptor */
+ iter.desc->valid = 0;
+
+ /* Advance the valid-index head */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ /*
+ * If we were previously stopped due to flow control, restart the
+ * processing
+ */
+ if (netif_queue_stopped(priv->dev)
+ && !ioq_full(priv->tx.veq.queue, ioq_idxtype_valid)) {
+ PDEBUG(priv->dev, "re-enabling tx queue\n");
+ netif_wake_queue(priv->dev);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return skb;
+}
+
+static void
+vbus_enet_tx_reap(struct vbus_enet_priv *priv)
+{
+ struct sk_buff *skb;
+
+ while ((skb = vbus_enet_tx_reap_one(priv))) {
+ if (!priv->evq.txc)
+ /*
+ * We are responsible for freeing the packet upon
+ * reap if TXC is not enabled
+ */
+ vbus_enet_skb_complete(priv, skb);
+ }
+}
+
+static void
+vbus_enet_timeout(struct net_device *dev)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+
+ dev_dbg(&dev->dev, "Transmit timeout\n");
+
+ vbus_enet_tx_reap(priv);
+}
+
+static void
+rx_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+ struct net_device *dev;
+
+ priv = container_of(notifier, struct vbus_enet_priv, rxq.notifier);
+ dev = priv->dev;
+
+ if (!ioq_empty(priv->rxq.queue, ioq_idxtype_inuse))
+ vbus_enet_schedule_rx(priv);
+}
+
+static void
+deferred_tx_isr(unsigned long data)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)data;
+
+ PDEBUG(priv->dev, "deferred_tx_isr\n");
+
+ vbus_enet_tx_reap(priv);
+
+ ioq_notify_enable(priv->tx.veq.queue, 0);
+}
+
+static void
+tx_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+
+ priv = container_of(notifier, struct vbus_enet_priv, tx.veq.notifier);
+
+ PDEBUG(priv->dev, "tx_isr\n");
+
+ ioq_notify_disable(priv->tx.veq.queue, 0);
+ tasklet_schedule(&priv->tx.task);
+}
+
+static void
+evq_linkstate_event(struct vbus_enet_priv *priv,
+ struct venet_event_header *header)
+{
+ struct venet_event_linkstate *event =
+ (struct venet_event_linkstate *)header;
+
+ switch (event->state) {
+ case 0:
+ netif_carrier_off(priv->dev);
+ break;
+ case 1:
+ netif_carrier_on(priv->dev);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+evq_txc_event(struct vbus_enet_priv *priv,
+ struct venet_event_header *header)
+{
+ struct venet_event_txc *event =
+ (struct venet_event_txc *)header;
+
+ vbus_enet_tx_reap(priv);
+
+ vbus_enet_skb_complete(priv, (struct sk_buff *)(unsigned long)event->cookie);
+}
+
+static void
+deferred_evq_isr(unsigned long data)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)data;
+ int nevents = 0;
+ struct ioq_iterator iter;
+ int ret;
+
+ PDEBUG(priv->dev, "evq: polling...\n");
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(priv->evq.veq.queue, &iter, ioq_idxtype_inuse,
+ IOQ_ITER_AUTOUPDATE);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side
+ */
+ while (!iter.desc->sown) {
+ struct venet_event_header *header;
+
+ header = (struct venet_event_header *)(unsigned long)iter.desc->cookie;
+
+ switch (header->id) {
+ case VENET_EVENT_LINKSTATE:
+ evq_linkstate_event(priv, header);
+ break;
+ case VENET_EVENT_TXC:
+ evq_txc_event(priv, header);
+ break;
+ default:
+ panic("venet: unexpected event id:%d of size %d\n",
+ header->id, header->size);
+ break;
+ }
+
+ memset((void *)(unsigned long)iter.desc->cookie, 0, priv->evq.evsize);
+
+ /* Advance the in-use tail */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ nevents++;
+ }
+
+ PDEBUG(priv->dev, "%d events received\n", nevents);
+
+ ioq_notify_enable(priv->evq.veq.queue, 0);
+}
+
+static void
+evq_isr(struct ioq_notifier *notifier)
+{
+ struct vbus_enet_priv *priv;
+
+ priv = container_of(notifier, struct vbus_enet_priv, evq.veq.notifier);
+
+ PDEBUG(priv->dev, "evq_isr\n");
+
+ ioq_notify_disable(priv->evq.veq.queue, 0);
+ tasklet_schedule(&priv->evq.task);
+}
+
+static int
+vbus_enet_sg_negcap(struct vbus_enet_priv *priv)
+{
+ struct net_device *dev = priv->dev;
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ if (sg_enabled) {
+ caps.gid = VENET_CAP_GROUP_SG;
+ caps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+ |VENET_CAP_ECN|VENET_CAP_PMTD);
+ /* note: exclude UFO for now due to stack bug */
+ }
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0)
+ return ret;
+
+ if (caps.bits & VENET_CAP_SG) {
+ priv->sg = true;
+
+ dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM|NETIF_F_FRAGLIST;
+
+ if (caps.bits & VENET_CAP_TSO4)
+ dev->features |= NETIF_F_TSO;
+ if (caps.bits & VENET_CAP_UFO)
+ dev->features |= NETIF_F_UFO;
+ if (caps.bits & VENET_CAP_TSO6)
+ dev->features |= NETIF_F_TSO6;
+ if (caps.bits & VENET_CAP_ECN)
+ dev->features |= NETIF_F_TSO_ECN;
+
+ if (caps.bits & VENET_CAP_PMTD)
+ priv->pmtd.enabled = true;
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_evq_negcap(struct vbus_enet_priv *priv, unsigned long count)
+{
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ caps.gid = VENET_CAP_GROUP_EVENTQ;
+ caps.bits |= VENET_CAP_EVQ_LINKSTATE;
+ caps.bits |= VENET_CAP_EVQ_TXC;
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0)
+ return ret;
+
+ if (caps.bits) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ struct venet_eventq_query query;
+ size_t poollen;
+ struct ioq_iterator iter;
+ char *pool;
+ int i;
+
+ priv->evq.enabled = true;
+
+ if (caps.bits & VENET_CAP_EVQ_LINKSTATE) {
+ /*
+ * We will assume there is no carrier until we get
+ * an event telling us otherwise
+ */
+ netif_carrier_off(priv->dev);
+ priv->evq.linkstate = true;
+ }
+
+ if (caps.bits & VENET_CAP_EVQ_TXC)
+ priv->evq.txc = true;
+
+ memset(&query, 0, sizeof(query));
+
+ ret = devcall(priv, VENET_FUNC_EVQQUERY, &query, sizeof(query));
+ if (ret < 0)
+ return ret;
+
+ priv->evq.evsize = query.evsize;
+ poollen = query.evsize * count;
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ priv->evq.pool = pool;
+
+ ret = dev->ops->shm(dev, NULL, query.dpid, 0,
+ pool, poollen, NULL, NULL, 0);
+ if (ret < 0)
+ return ret;
+
+ queue_init(priv, &priv->evq.veq, "evq",
+ query.qid, count, evq_isr);
+
+ ret = ioq_iter_init(priv->evq.veq.queue,
+ &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_set, 0, 0);
+ BUG_ON(ret < 0);
+
+ /* Now populate each descriptor with an empty event */
+ for (i = 0; i < count; i++) {
+ size_t offset = (i * query.evsize);
+ void *addr = &priv->evq.pool[offset];
+
+ iter.desc->ptr = cpu_to_le64(offset);
+ iter.desc->cookie = (u64)(unsigned long)addr;
+ iter.desc->len = cpu_to_le64(query.evsize);
+
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ /* Finally, enable interrupts */
+ tasklet_init(&priv->evq.task, deferred_evq_isr,
+ (unsigned long)priv);
+ ioq_notify_enable(priv->evq.veq.queue, 0);
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_l4ro_negcap(struct vbus_enet_priv *priv, unsigned long count)
+{
+ struct venet_capabilities caps;
+ int ret;
+
+ memset(&caps, 0, sizeof(caps));
+
+ caps.gid = VENET_CAP_GROUP_L4RO;
+ caps.bits |= (VENET_CAP_SG|VENET_CAP_TSO4|VENET_CAP_TSO6
+ |VENET_CAP_ECN);
+
+ ret = devcall(priv, VENET_FUNC_NEGCAP, &caps, sizeof(caps));
+ if (ret < 0) {
+ printk(KERN_ERR "Error negotiating L4RO: %d\n", ret);
+ return ret;
+ }
+
+ if (caps.bits & VENET_CAP_SG) {
+ struct vbus_device_proxy *dev = priv->vdev;
+ size_t poollen = SG_DESC_SIZE * count;
+ struct venet_l4ro_query query;
+ char *pool;
+
+ memset(&query, 0, sizeof(query));
+
+ ret = devcall(priv, VENET_FUNC_L4ROQUERY, &query, sizeof(query));
+ if (ret < 0) {
+ printk(KERN_ERR "Error querying L4RO: %d\n", ret);
+ return ret;
+ }
+
+ pool = kzalloc(poollen, GFP_KERNEL | GFP_DMA);
+ if (!pool)
+ return -ENOMEM;
+
+ /*
+ * pre-mapped descriptor pool
+ */
+ ret = dev->ops->shm(dev, NULL, query.dpid, 0,
+ pool, poollen, NULL, NULL, 0);
+ if (ret < 0) {
+ printk(KERN_ERR "Error registering L4RO pool: %d\n",
+ ret);
+ kfree(pool);
+ return ret;
+ }
+
+ /*
+ * page-queue: contains a ring of arbitrary pages for
+ * consumption by the host for when the SG::IOV count exceeds
+ * one MTU frame. All we need to do is keep it populated
+ * with free pages.
+ */
+ queue_init(priv, &priv->l4ro.pageq, "pageq", query.pqid,
+ count, NULL);
+
+ priv->l4ro.pool = pool;
+ priv->l4ro.available = true;
+ }
+
+ return 0;
+}
+
+static int
+vbus_enet_negcap(struct vbus_enet_priv *priv)
+{
+ int ret;
+
+ ret = vbus_enet_sg_negcap(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = vbus_enet_evq_negcap(priv, tx_ringlen);
+ if (ret < 0)
+ return ret;
+
+ ret = vbus_enet_l4ro_negcap(priv, rx_ringlen);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int vbus_enet_set_tx_csum(struct net_device *dev, u32 data)
+{
+ struct vbus_enet_priv *priv = netdev_priv(dev);
+
+ if (data && !priv->sg)
+ return -ENOSYS;
+
+ return ethtool_op_set_tx_hw_csum(dev, data);
+}
+
+static struct ethtool_ops vbus_enet_ethtool_ops = {
+ .set_tx_csum = vbus_enet_set_tx_csum,
+ .set_sg = ethtool_op_set_sg,
+ .set_tso = ethtool_op_set_tso,
+ .get_link = ethtool_op_get_link,
+};
+
+static const struct net_device_ops vbus_enet_netdev_ops = {
+ .ndo_open = vbus_enet_open,
+ .ndo_stop = vbus_enet_stop,
+ .ndo_set_config = vbus_enet_config,
+ .ndo_start_xmit = vbus_enet_tx_start,
+ .ndo_change_mtu = vbus_enet_change_mtu,
+ .ndo_tx_timeout = vbus_enet_timeout,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+/*
+ * This is called whenever a new vbus_device_proxy is added to the vbus
+ * with the matching VENET_ID
+ */
+static int
+vbus_enet_probe(struct vbus_device_proxy *vdev)
+{
+ struct net_device *dev;
+ struct vbus_enet_priv *priv;
+ int ret;
+
+ printk(KERN_INFO "VENET: Found new device at %lld\n", vdev->id);
+
+ ret = vdev->ops->open(vdev, VENET_VERSION, 0);
+ if (ret < 0)
+ return ret;
+
+ dev = alloc_etherdev(sizeof(struct vbus_enet_priv));
+ if (!dev)
+ return -ENOMEM;
+
+ /*
+ * establish our device-name early so we can incorporate it into
+ * the signal-path names, etc
+ */
+ rtnl_lock();
+
+ ret = dev_alloc_name(dev, dev->name);
+ if (ret < 0)
+ goto out_free;
+
+ priv = netdev_priv(dev);
+
+ spin_lock_init(&priv->lock);
+ priv->dev = dev;
+ priv->vdev = vdev;
+
+ ret = vbus_enet_negcap(priv);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: Error negotiating capabilities for " \
+ "%lld\n",
+ priv->vdev->id);
+ goto out_free;
+ }
+
+ if (priv->l4ro.available)
+ priv->import = &vbus_enet_l4ro_import;
+ else
+ priv->import = &vbus_enet_flat_import;
+
+ skb_queue_head_init(&priv->tx.outstanding);
+
+ queue_init(priv, &priv->rxq, "rx", VENET_QUEUE_RX, rx_ringlen,
+ rx_isr);
+ queue_init(priv, &priv->tx.veq, "tx", VENET_QUEUE_TX, tx_ringlen,
+ tx_isr);
+
+ rx_setup(priv);
+ tx_setup(priv);
+
+ ioq_notify_enable(priv->rxq.queue, 0); /* enable rx interrupts */
+
+ if (!priv->evq.txc) {
+ /*
+ * If the TXC feature is present, we will recieve our
+ * tx-complete notification via the event-channel. Therefore,
+ * we only enable txq interrupts if the TXC feature is not
+ * present.
+ */
+ tasklet_init(&priv->tx.task, deferred_tx_isr,
+ (unsigned long)priv);
+ ioq_notify_enable(priv->tx.veq.queue, 0);
+ }
+
+ dev->netdev_ops = &vbus_enet_netdev_ops;
+ dev->watchdog_timeo = 5 * HZ;
+ SET_ETHTOOL_OPS(dev, &vbus_enet_ethtool_ops);
+ SET_NETDEV_DEV(dev, &vdev->dev);
+
+ netif_napi_add(dev, &priv->napi, vbus_enet_poll, 128);
+
+ ret = devcall(priv, VENET_FUNC_MACQUERY, priv->dev->dev_addr, ETH_ALEN);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: Error obtaining MAC address for " \
+ "%lld\n",
+ priv->vdev->id);
+ goto out_free;
+ }
+
+ dev->features |= NETIF_F_HIGHDMA;
+
+ ret = register_netdevice(dev);
+ if (ret < 0) {
+ printk(KERN_INFO "VENET: error %i registering device \"%s\"\n",
+ ret, dev->name);
+ goto out_free;
+ }
+
+ rtnl_unlock();
+
+ vdev->priv = priv;
+
+ return 0;
+
+ out_free:
+ rtnl_unlock();
+
+ free_netdev(dev);
+
+ return ret;
+}
+
+static int
+vbus_enet_remove(struct vbus_device_proxy *vdev)
+{
+ struct vbus_enet_priv *priv = (struct vbus_enet_priv *)vdev->priv;
+ struct vbus_device_proxy *dev = priv->vdev;
+
+ unregister_netdev(priv->dev);
+ napi_disable(&priv->napi);
+
+ rx_teardown(priv);
+ ioq_put(priv->rxq.queue);
+
+ tx_teardown(priv);
+ ioq_put(priv->tx.veq.queue);
+
+ if (priv->evq.enabled)
+ evq_teardown(priv);
+
+ dev->ops->close(dev, 0);
+
+ free_netdev(priv->dev);
+
+ return 0;
+}
+
+/*
+ * Finally, the module stuff
+ */
+
+static struct vbus_driver_ops vbus_enet_driver_ops = {
+ .probe = vbus_enet_probe,
+ .remove = vbus_enet_remove,
+};
+
+static struct vbus_driver vbus_enet_driver = {
+ .type = VENET_TYPE,
+ .owner = THIS_MODULE,
+ .ops = &vbus_enet_driver_ops,
+};
+
+static __init int
+vbus_enet_init_module(void)
+{
+ printk(KERN_INFO "Virtual Ethernet: Copyright (C) 2009 Novell, Gregory Haskins\n");
+ printk(KERN_DEBUG "VENET: Using %d/%d queue depth\n",
+ rx_ringlen, tx_ringlen);
+ return vbus_driver_register(&vbus_enet_driver);
+}
+
+static __exit void
+vbus_enet_cleanup(void)
+{
+ vbus_driver_unregister(&vbus_enet_driver);
+}
+
+module_init(vbus_enet_init_module);
+module_exit(vbus_enet_cleanup);
+
+VBUS_DRIVER_AUTOPROBE(VENET_TYPE);
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index c38191179fae..f7b33ae7a703 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -193,7 +193,7 @@ struct rx_desc {
__le32 pa_low; /* Low 32 bit PCI address */
__le16 pa_high; /* Next 16 bit PCI address (48 total) */
__le16 size; /* bits 0--14 - frame size, bit 15 - enable int. */
-} __attribute__ ((__packed__));
+} __packed;
/*
* Transmit descriptor
@@ -208,7 +208,7 @@ struct tdesc1 {
__le16 vlan;
u8 TCR;
u8 cmd; /* bits 0--1 - TCPLS, bits 4--7 - CMDZ */
-} __attribute__ ((__packed__));
+} __packed;
enum {
TD_QUEUE = cpu_to_le16(0x8000)
@@ -218,7 +218,7 @@ struct td_buf {
__le32 pa_low;
__le16 pa_high;
__le16 size; /* bits 0--13 - size, bit 15 - queue */
-} __attribute__ ((__packed__));
+} __packed;
struct tx_desc {
struct tdesc0 tdesc0;
@@ -1096,7 +1096,7 @@ struct mac_regs {
volatile __le16 PatternCRC[8]; /* 0xB0 */
volatile __le32 ByteMask[4][4]; /* 0xC0 */
-} __attribute__ ((__packed__));
+} __packed;
enum hw_mib {
@@ -1216,7 +1216,7 @@ struct arp_packet {
u8 ar_sip[4];
u8 ar_tha[ETH_ALEN];
u8 ar_tip[4];
-} __attribute__ ((__packed__));
+} __packed;
struct _magic_packet {
u8 dest_mac[6];
@@ -1224,7 +1224,7 @@ struct _magic_packet {
__be16 type;
u8 MAC[16][6];
u8 password[6];
-} __attribute__ ((__packed__));
+} __packed;
/*
* Store for chip context when saving and restoring status. Not
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 78eb3190b9b1..1edb7a61983c 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -340,7 +340,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
skb_to_sgvec(skb, vi->rx_sg + 1, 0, skb->len);
- err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 2, skb);
+ err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 2, skb, gfp);
if (err < 0)
dev_kfree_skb(skb);
@@ -385,8 +385,8 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
/* chain first in list head */
first->private = (unsigned long)list;
- err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
- first);
+ err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, MAX_SKB_FRAGS + 2,
+ first, gfp);
if (err < 0)
give_pages(vi, first);
@@ -404,7 +404,7 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, gfp_t gfp)
sg_init_one(vi->rx_sg, page_address(page), PAGE_SIZE);
- err = virtqueue_add_buf(vi->rvq, vi->rx_sg, 0, 1, page);
+ err = virtqueue_add_buf_gfp(vi->rvq, vi->rx_sg, 0, 1, page, gfp);
if (err < 0)
give_pages(vi, page);
diff --git a/drivers/net/vxge/vxge-main.c b/drivers/net/vxge/vxge-main.c
index b504bd561362..45c5dc225631 100644
--- a/drivers/net/vxge/vxge-main.c
+++ b/drivers/net/vxge/vxge-main.c
@@ -4012,7 +4012,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
int high_dma = 0;
u64 vpath_mask = 0;
struct vxgedev *vdev;
- struct vxge_config ll_config;
+ struct vxge_config *ll_config = NULL;
struct vxge_hw_device_config *device_config = NULL;
struct vxge_hw_device_attr attr;
int i, j, no_of_vpath = 0, max_vpath_supported = 0;
@@ -4071,17 +4071,24 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit0;
}
- memset(&ll_config, 0, sizeof(struct vxge_config));
- ll_config.tx_steering_type = TX_MULTIQ_STEERING;
- ll_config.intr_type = MSI_X;
- ll_config.napi_weight = NEW_NAPI_WEIGHT;
- ll_config.rth_steering = RTH_STEERING;
+ ll_config = kzalloc(sizeof(*ll_config), GFP_KERNEL);
+ if (!ll_config) {
+ ret = -ENOMEM;
+ vxge_debug_init(VXGE_ERR,
+ "ll_config : malloc failed %s %d",
+ __FILE__, __LINE__);
+ goto _exit0;
+ }
+ ll_config->tx_steering_type = TX_MULTIQ_STEERING;
+ ll_config->intr_type = MSI_X;
+ ll_config->napi_weight = NEW_NAPI_WEIGHT;
+ ll_config->rth_steering = RTH_STEERING;
/* get the default configuration parameters */
vxge_hw_device_config_default_get(device_config);
/* initialize configuration parameters */
- vxge_device_config_init(device_config, &ll_config.intr_type);
+ vxge_device_config_init(device_config, &ll_config->intr_type);
ret = pci_enable_device(pdev);
if (ret) {
@@ -4134,7 +4141,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
(unsigned long long)pci_resource_start(pdev, 0));
status = vxge_hw_device_hw_info_get(attr.bar0,
- &ll_config.device_hw_info);
+ &ll_config->device_hw_info);
if (status != VXGE_HW_OK) {
vxge_debug_init(VXGE_ERR,
"%s: Reading of hardware info failed."
@@ -4143,7 +4150,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
- if (ll_config.device_hw_info.fw_version.major !=
+ if (ll_config->device_hw_info.fw_version.major !=
VXGE_DRIVER_FW_VERSION_MAJOR) {
vxge_debug_init(VXGE_ERR,
"%s: Incorrect firmware version."
@@ -4153,7 +4160,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
goto _exit3;
}
- vpath_mask = ll_config.device_hw_info.vpath_mask;
+ vpath_mask = ll_config->device_hw_info.vpath_mask;
if (vpath_mask == 0) {
vxge_debug_ll_config(VXGE_TRACE,
"%s: No vpaths available in device", VXGE_DRIVER_NAME);
@@ -4165,10 +4172,10 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
"%s:%d Vpath mask = %llx", __func__, __LINE__,
(unsigned long long)vpath_mask);
- function_mode = ll_config.device_hw_info.function_mode;
- host_type = ll_config.device_hw_info.host_type;
+ function_mode = ll_config->device_hw_info.function_mode;
+ host_type = ll_config->device_hw_info.host_type;
is_privileged = __vxge_hw_device_is_privilaged(host_type,
- ll_config.device_hw_info.func_id);
+ ll_config->device_hw_info.func_id);
/* Check how many vpaths are available */
for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
@@ -4182,7 +4189,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* Enable SRIOV mode, if firmware has SRIOV support and if it is a PF */
if (is_sriov(function_mode) && (max_config_dev > 1) &&
- (ll_config.intr_type != INTA) &&
+ (ll_config->intr_type != INTA) &&
(is_privileged == VXGE_HW_OK)) {
ret = pci_enable_sriov(pdev, ((max_config_dev - 1) < num_vfs)
? (max_config_dev - 1) : num_vfs);
@@ -4195,7 +4202,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
* Configure vpaths and get driver configured number of vpaths
* which is less than or equal to the maximum vpaths per function.
*/
- no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, &ll_config);
+ no_of_vpath = vxge_config_vpaths(device_config, vpath_mask, ll_config);
if (!no_of_vpath) {
vxge_debug_ll_config(VXGE_ERR,
"%s: No more vpaths to configure", VXGE_DRIVER_NAME);
@@ -4230,21 +4237,21 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
/* set private device info */
pci_set_drvdata(pdev, hldev);
- ll_config.gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
- ll_config.fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
- ll_config.addr_learn_en = addr_learn_en;
- ll_config.rth_algorithm = RTH_ALG_JENKINS;
- ll_config.rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
- ll_config.rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
- ll_config.rth_bkt_sz = RTH_BUCKET_SIZE;
- ll_config.tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
- ll_config.rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
-
- if (vxge_device_register(hldev, &ll_config, high_dma, no_of_vpath,
+ ll_config->gro_enable = VXGE_GRO_ALWAYS_AGGREGATE;
+ ll_config->fifo_indicate_max_pkts = VXGE_FIFO_INDICATE_MAX_PKTS;
+ ll_config->addr_learn_en = addr_learn_en;
+ ll_config->rth_algorithm = RTH_ALG_JENKINS;
+ ll_config->rth_hash_type_tcpipv4 = VXGE_HW_RING_HASH_TYPE_TCP_IPV4;
+ ll_config->rth_hash_type_ipv4 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_tcpipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_ipv6 = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_tcpipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_hash_type_ipv6ex = VXGE_HW_RING_HASH_TYPE_NONE;
+ ll_config->rth_bkt_sz = RTH_BUCKET_SIZE;
+ ll_config->tx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+ ll_config->rx_pause_enable = VXGE_PAUSE_CTRL_ENABLE;
+
+ if (vxge_device_register(hldev, ll_config, high_dma, no_of_vpath,
&vdev)) {
ret = -EINVAL;
goto _exit4;
@@ -4275,7 +4282,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vdev->vpaths[j].vdev = vdev;
vdev->vpaths[j].max_mac_addr_cnt = max_mac_vpath;
memcpy((u8 *)vdev->vpaths[j].macaddr,
- (u8 *)ll_config.device_hw_info.mac_addrs[i],
+ ll_config->device_hw_info.mac_addrs[i],
ETH_ALEN);
/* Initialize the mac address list header */
@@ -4296,18 +4303,18 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
macaddr = (u8 *)vdev->vpaths[0].macaddr;
- ll_config.device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
- ll_config.device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
- ll_config.device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.serial_number[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.product_desc[VXGE_HW_INFO_LEN - 1] = '\0';
+ ll_config->device_hw_info.part_number[VXGE_HW_INFO_LEN - 1] = '\0';
vxge_debug_init(VXGE_TRACE, "%s: SERIAL NUMBER: %s",
- vdev->ndev->name, ll_config.device_hw_info.serial_number);
+ vdev->ndev->name, ll_config->device_hw_info.serial_number);
vxge_debug_init(VXGE_TRACE, "%s: PART NUMBER: %s",
- vdev->ndev->name, ll_config.device_hw_info.part_number);
+ vdev->ndev->name, ll_config->device_hw_info.part_number);
vxge_debug_init(VXGE_TRACE, "%s: Neterion %s Server Adapter",
- vdev->ndev->name, ll_config.device_hw_info.product_desc);
+ vdev->ndev->name, ll_config->device_hw_info.product_desc);
vxge_debug_init(VXGE_TRACE, "%s: MAC ADDR: %pM",
vdev->ndev->name, macaddr);
@@ -4317,11 +4324,11 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_debug_init(VXGE_TRACE,
"%s: Firmware version : %s Date : %s", vdev->ndev->name,
- ll_config.device_hw_info.fw_version.version,
- ll_config.device_hw_info.fw_date.date);
+ ll_config->device_hw_info.fw_version.version,
+ ll_config->device_hw_info.fw_date.date);
if (new_device) {
- switch (ll_config.device_hw_info.function_mode) {
+ switch (ll_config->device_hw_info.function_mode) {
case VXGE_HW_FUNCTION_MODE_SINGLE_FUNCTION:
vxge_debug_init(VXGE_TRACE,
"%s: Single Function Mode Enabled", vdev->ndev->name);
@@ -4344,7 +4351,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
vxge_print_parm(vdev, vpath_mask);
/* Store the fw version for ethttool option */
- strcpy(vdev->fw_version, ll_config.device_hw_info.fw_version.version);
+ strcpy(vdev->fw_version, ll_config->device_hw_info.fw_version.version);
memcpy(vdev->ndev->dev_addr, (u8 *)vdev->vpaths[0].macaddr, ETH_ALEN);
memcpy(vdev->ndev->perm_addr, vdev->ndev->dev_addr, ETH_ALEN);
@@ -4383,7 +4390,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
* present to prevent such a failure.
*/
- if (ll_config.device_hw_info.function_mode ==
+ if (ll_config->device_hw_info.function_mode ==
VXGE_HW_FUNCTION_MODE_MULTI_FUNCTION)
if (vdev->config.intr_type == INTA)
vxge_hw_device_unmask_all(hldev);
@@ -4395,6 +4402,7 @@ vxge_probe(struct pci_dev *pdev, const struct pci_device_id *pre)
VXGE_COPY_DEBUG_INFO_TO_LL(vdev, vxge_hw_device_error_level_get(hldev),
vxge_hw_device_trace_level_get(hldev));
+ kfree(ll_config);
return 0;
_exit5:
@@ -4412,6 +4420,7 @@ _exit2:
_exit1:
pci_disable_device(pdev);
_exit0:
+ kfree(ll_config);
kfree(device_config);
driver_config->config_dev_cnt--;
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index e087b9a6daaa..43b77271532b 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2038,16 +2038,10 @@ fst_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
/* Now copy the data to the card. */
- buf = kmalloc(wrthdr.size, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf,
- ifr->ifr_data + sizeof (struct fstioc_write),
- wrthdr.size)) {
- kfree(buf);
- return -EFAULT;
- }
+ buf = memdup_user(ifr->ifr_data + sizeof(struct fstioc_write),
+ wrthdr.size);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
memcpy_toio(card->mem + wrthdr.offset, buf, wrthdr.size);
kfree(buf);
diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h
index 3839662ff201..e4f539ad071b 100644
--- a/drivers/net/wan/hd64570.h
+++ b/drivers/net/wan/hd64570.h
@@ -153,7 +153,7 @@ typedef struct {
u16 len; /* Data Length */
u8 stat; /* Status */
u8 unused; /* pads to 2-byte boundary */
-}__attribute__ ((packed)) pkt_desc;
+}__packed pkt_desc;
/* Packet Descriptor Status bits */
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index ee7083fbea50..b38ffa149aba 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -36,7 +36,7 @@ struct hdlc_header {
u8 address;
u8 control;
__be16 protocol;
-}__attribute__ ((packed));
+}__packed;
struct cisco_packet {
@@ -45,7 +45,7 @@ struct cisco_packet {
__be32 par2;
__be16 rel; /* reliability */
__be32 time;
-}__attribute__ ((packed));
+}__packed;
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 0e52993e2079..0edb535bb2b5 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -112,7 +112,7 @@ typedef struct {
unsigned de: 1;
unsigned ea2: 1;
#endif
-}__attribute__ ((packed)) fr_hdr;
+}__packed fr_hdr;
typedef struct pvc_device_struct {
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 43ae6f440bfb..f4125da2762f 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -330,7 +330,7 @@ struct _dlci_stat
{
short dlci;
char flags;
-} __attribute__((packed));
+} __packed;
struct _frad_stat
{
@@ -1211,14 +1211,9 @@ static int sdla_xfer(struct net_device *dev, struct sdla_mem __user *info, int r
}
else
{
- temp = kmalloc(mem.len, GFP_KERNEL);
- if (!temp)
- return(-ENOMEM);
- if(copy_from_user(temp, mem.data, mem.len))
- {
- kfree(temp);
- return -EFAULT;
- }
+ temp = memdup_user(mem.data, mem.len);
+ if (IS_ERR(temp))
+ return PTR_ERR(temp);
sdla_write(dev, mem.addr, temp, mem.len);
kfree(temp);
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 166e77dfffda..e47f5a986b1c 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -37,8 +37,6 @@
#include <net/x25device.h>
#include "x25_asy.h"
-#include <net/x25device.h>
-
static struct net_device **x25_asy_devs;
static int x25_asy_maxdev = SL_NRUNIT;
diff --git a/drivers/net/wimax/i2400m/control.c b/drivers/net/wimax/i2400m/control.c
index d86e8f31e7fc..2f725d0cc762 100644
--- a/drivers/net/wimax/i2400m/control.c
+++ b/drivers/net/wimax/i2400m/control.c
@@ -848,7 +848,7 @@ struct i2400m_cmd_enter_power_save {
struct i2400m_l3l4_hdr hdr;
struct i2400m_tlv_hdr tlv;
__le32 val;
-} __attribute__((packed));
+} __packed;
/*
diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c
index 3f283bff0ff7..e9b34b0cb197 100644
--- a/drivers/net/wimax/i2400m/fw.c
+++ b/drivers/net/wimax/i2400m/fw.c
@@ -651,7 +651,7 @@ static int i2400m_download_chunk(struct i2400m *i2400m, const void *chunk,
struct {
struct i2400m_bootrom_header cmd;
u8 cmd_payload[chunk_len];
- } __attribute__((packed)) *buf;
+ } __packed *buf;
struct i2400m_bootrom_header ack;
d_fnstart(5, dev, "(i2400m %p chunk %p __chunk_len %zu addr 0x%08lx "
@@ -794,7 +794,7 @@ int i2400m_dnload_finalize(struct i2400m *i2400m,
struct {
struct i2400m_bootrom_header cmd;
u8 cmd_pl[0];
- } __attribute__((packed)) *cmd_buf;
+ } __packed *cmd_buf;
size_t signature_block_offset, signature_block_size;
d_fnstart(3, dev, "offset %zu\n", offset);
@@ -1029,7 +1029,7 @@ int i2400m_read_mac_addr(struct i2400m *i2400m)
struct {
struct i2400m_bootrom_header ack;
u8 ack_pl[16];
- } __attribute__((packed)) ack_buf;
+ } __packed ack_buf;
d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
cmd = i2400m->bm_cmd_buf;
@@ -1115,7 +1115,7 @@ int i2400m_dnload_init_signed(struct i2400m *i2400m,
struct {
struct i2400m_bootrom_header cmd;
struct i2400m_bcf_hdr cmd_pl;
- } __attribute__((packed)) *cmd_buf;
+ } __packed *cmd_buf;
struct i2400m_bootrom_header ack;
d_fnstart(5, dev, "(i2400m %p bcf_hdr %p)\n", i2400m, bcf_hdr);
diff --git a/drivers/net/wimax/i2400m/op-rfkill.c b/drivers/net/wimax/i2400m/op-rfkill.c
index 035e4cf3e6ed..9e02b90b0080 100644
--- a/drivers/net/wimax/i2400m/op-rfkill.c
+++ b/drivers/net/wimax/i2400m/op-rfkill.c
@@ -91,7 +91,7 @@ int i2400m_op_rfkill_sw_toggle(struct wimax_dev *wimax_dev,
struct {
struct i2400m_l3l4_hdr hdr;
struct i2400m_tlv_rf_operation sw_rf;
- } __attribute__((packed)) *cmd;
+ } __packed *cmd;
char strerr[32];
d_fnstart(4, dev, "(wimax_dev %p state %d)\n", wimax_dev, state);
diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h
index b07e4d3a6b4d..bbc10b1cde87 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -80,7 +80,7 @@ struct adm8211_csr {
__le32 FEMR; /* 0x104 */
__le32 FPSR; /* 0x108 */
__le32 FFER; /* 0x10C */
-} __attribute__ ((packed));
+} __packed;
/* CSR0 - PAR (PCI Address Register) */
#define ADM8211_PAR_MWIE (1 << 24)
@@ -484,7 +484,7 @@ struct adm8211_tx_hdr {
u8 entry_control; // huh??
u16 reserved_1;
u32 reserved_2;
-} __attribute__ ((packed));
+} __packed;
#define RX_COPY_BREAK 128
@@ -531,7 +531,7 @@ struct adm8211_eeprom {
u8 lnags_threshold[14]; /* 0x70 */
__le16 checksum; /* 0x7E */
u8 cis_data[0]; /* 0x80, 384 bytes */
-} __attribute__ ((packed));
+} __packed;
struct adm8211_priv {
struct pci_dev *pdev;
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 3b7ab20a5c54..6b605df8a923 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -506,20 +506,20 @@ struct WepKeyRid {
u8 mac[ETH_ALEN];
__le16 klen;
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
/* These structures are from the Aironet's PC4500 Developers Manual */
typedef struct Ssid Ssid;
struct Ssid {
__le16 len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
typedef struct SsidRid SsidRid;
struct SsidRid {
__le16 len;
Ssid ssids[3];
-} __attribute__ ((packed));
+} __packed;
typedef struct ModulationRid ModulationRid;
struct ModulationRid {
@@ -528,7 +528,7 @@ struct ModulationRid {
#define MOD_DEFAULT cpu_to_le16(0)
#define MOD_CCK cpu_to_le16(1)
#define MOD_MOK cpu_to_le16(2)
-} __attribute__ ((packed));
+} __packed;
typedef struct ConfigRid ConfigRid;
struct ConfigRid {
@@ -652,7 +652,7 @@ struct ConfigRid {
#define MAGIC_STAY_IN_CAM (1<<10)
u8 magicControl;
__le16 autoWake;
-} __attribute__ ((packed));
+} __packed;
typedef struct StatusRid StatusRid;
struct StatusRid {
@@ -711,20 +711,20 @@ struct StatusRid {
#define STAT_LEAPFAILED 91
#define STAT_LEAPTIMEDOUT 92
#define STAT_LEAPCOMPLETE 93
-} __attribute__ ((packed));
+} __packed;
typedef struct StatsRid StatsRid;
struct StatsRid {
__le16 len;
__le16 spacer;
__le32 vals[100];
-} __attribute__ ((packed));
+} __packed;
typedef struct APListRid APListRid;
struct APListRid {
__le16 len;
u8 ap[4][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
typedef struct CapabilityRid CapabilityRid;
struct CapabilityRid {
@@ -754,7 +754,7 @@ struct CapabilityRid {
__le16 bootBlockVer;
__le16 requiredHard;
__le16 extSoftCap;
-} __attribute__ ((packed));
+} __packed;
/* Only present on firmware >= 5.30.17 */
typedef struct BSSListRidExtra BSSListRidExtra;
@@ -762,7 +762,7 @@ struct BSSListRidExtra {
__le16 unknown[4];
u8 fixed[12]; /* WLAN management frame */
u8 iep[624];
-} __attribute__ ((packed));
+} __packed;
typedef struct BSSListRid BSSListRid;
struct BSSListRid {
@@ -796,7 +796,7 @@ struct BSSListRid {
/* Only present on firmware >= 5.30.17 */
BSSListRidExtra extra;
-} __attribute__ ((packed));
+} __packed;
typedef struct {
BSSListRid bss;
@@ -807,13 +807,13 @@ typedef struct tdsRssiEntry tdsRssiEntry;
struct tdsRssiEntry {
u8 rssipct;
u8 rssidBm;
-} __attribute__ ((packed));
+} __packed;
typedef struct tdsRssiRid tdsRssiRid;
struct tdsRssiRid {
u16 len;
tdsRssiEntry x[256];
-} __attribute__ ((packed));
+} __packed;
typedef struct MICRid MICRid;
struct MICRid {
@@ -823,7 +823,7 @@ struct MICRid {
u8 multicast[16];
__le16 unicastValid;
u8 unicast[16];
-} __attribute__ ((packed));
+} __packed;
typedef struct MICBuffer MICBuffer;
struct MICBuffer {
@@ -841,7 +841,7 @@ struct MICBuffer {
} u;
__be32 mic;
__be32 seq;
-} __attribute__ ((packed));
+} __packed;
typedef struct {
u8 da[ETH_ALEN];
@@ -996,7 +996,7 @@ struct rx_hdr {
u8 rate;
u8 freq;
__le16 tmp[4];
-} __attribute__ ((packed));
+} __packed;
typedef struct {
unsigned int ctl: 15;
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
index 8a2d4afc74f8..429b281d40d1 100644
--- a/drivers/net/wireless/at76c50x-usb.c
+++ b/drivers/net/wireless/at76c50x-usb.c
@@ -305,7 +305,7 @@ struct dfu_status {
unsigned char poll_timeout[3];
unsigned char state;
unsigned char string;
-} __attribute__((packed));
+} __packed;
static inline int at76_is_intersil(enum board_type board)
{
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
index 1ec5ccffdbc0..972ea0fc1a0b 100644
--- a/drivers/net/wireless/at76c50x-usb.h
+++ b/drivers/net/wireless/at76c50x-usb.h
@@ -99,7 +99,7 @@ struct hwcfg_r505 {
u8 reserved2[14];
u8 cr15_values[14];
u8 reserved3[3];
-} __attribute__((packed));
+} __packed;
struct hwcfg_rfmd {
u8 cr20_values[14];
@@ -111,7 +111,7 @@ struct hwcfg_rfmd {
u8 low_power_values[14];
u8 normal_power_values[14];
u8 reserved1[3];
-} __attribute__((packed));
+} __packed;
struct hwcfg_intersil {
u8 mac_addr[ETH_ALEN];
@@ -120,7 +120,7 @@ struct hwcfg_intersil {
u8 pidvid[4];
u8 regulatory_domain;
u8 reserved[1];
-} __attribute__((packed));
+} __packed;
union at76_hwcfg {
struct hwcfg_intersil i;
@@ -149,14 +149,14 @@ struct at76_card_config {
u8 ssid_len;
u8 short_preamble;
__le16 beacon_period;
-} __attribute__((packed));
+} __packed;
struct at76_command {
u8 cmd;
u8 reserved;
__le16 size;
u8 data[0];
-} __attribute__((packed));
+} __packed;
/* Length of Atmel-specific Rx header before 802.11 frame */
#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
@@ -171,7 +171,7 @@ struct at76_rx_buffer {
u8 noise_level;
__le32 rx_time;
u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
/* Length of Atmel-specific Tx header before 802.11 frame */
#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
@@ -182,7 +182,7 @@ struct at76_tx_buffer {
u8 padding;
u8 reserved[4];
u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
-} __attribute__((packed));
+} __packed;
/* defines for scan_type below */
#define SCAN_TYPE_ACTIVE 0
@@ -198,7 +198,7 @@ struct at76_req_scan {
__le16 max_channel_time;
u8 essid_size;
u8 international_scan;
-} __attribute__((packed));
+} __packed;
struct at76_req_ibss {
u8 bssid[ETH_ALEN];
@@ -207,7 +207,7 @@ struct at76_req_ibss {
u8 channel;
u8 essid_size;
u8 reserved[3];
-} __attribute__((packed));
+} __packed;
struct at76_req_join {
u8 bssid[ETH_ALEN];
@@ -217,7 +217,7 @@ struct at76_req_join {
__le16 timeout;
u8 essid_size;
u8 reserved;
-} __attribute__((packed));
+} __packed;
struct set_mib_buffer {
u8 type;
@@ -229,7 +229,7 @@ struct set_mib_buffer {
__le16 word;
u8 addr[ETH_ALEN];
} data;
-} __attribute__((packed));
+} __packed;
struct mib_local {
u16 reserved0;
@@ -241,14 +241,14 @@ struct mib_local {
u16 reserved2;
u8 preamble_type;
u16 reserved3;
-} __attribute__((packed));
+} __packed;
struct mib_mac_addr {
u8 mac_addr[ETH_ALEN];
u8 res[2]; /* ??? */
u8 group_addr[4][ETH_ALEN];
u8 group_addr_status[4];
-} __attribute__((packed));
+} __packed;
struct mib_mac {
__le32 max_tx_msdu_lifetime;
@@ -269,7 +269,7 @@ struct mib_mac {
u8 desired_bssid[ETH_ALEN];
u8 desired_bsstype; /* ad-hoc or infrastructure */
u8 reserved2;
-} __attribute__((packed));
+} __packed;
struct mib_mac_mgmt {
__le16 beacon_period;
@@ -292,7 +292,7 @@ struct mib_mac_mgmt {
u8 multi_domain_capability_enabled;
u8 country_string[3];
u8 reserved[3];
-} __attribute__((packed));
+} __packed;
struct mib_mac_wep {
u8 privacy_invoked; /* 0 disable encr., 1 enable encr */
@@ -303,7 +303,7 @@ struct mib_mac_wep {
__le32 wep_excluded_count;
u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];
u8 encryption_level; /* 1 for 40bit, 2 for 104bit encryption */
-} __attribute__((packed));
+} __packed;
struct mib_phy {
__le32 ed_threshold;
@@ -320,19 +320,19 @@ struct mib_phy {
u8 current_cca_mode;
u8 phy_type;
u8 current_reg_domain;
-} __attribute__((packed));
+} __packed;
struct mib_fw_version {
u8 major;
u8 minor;
u8 patch;
u8 build;
-} __attribute__((packed));
+} __packed;
struct mib_mdomain {
u8 tx_powerlevel[14];
u8 channel_list[14]; /* 0 for invalid channels */
-} __attribute__((packed));
+} __packed;
struct at76_fw_header {
__le32 crc; /* CRC32 of the whole image */
@@ -346,7 +346,7 @@ struct at76_fw_header {
__le32 int_fw_len; /* internal firmware image length */
__le32 ext_fw_offset; /* external firmware image offset */
__le32 ext_fw_len; /* external firmware image length */
-} __attribute__((packed));
+} __packed;
/* a description of a regulatory domain and the allowed channels */
struct reg_domain {
diff --git a/drivers/net/wireless/ath/ar9170/usb.c b/drivers/net/wireless/ath/ar9170/usb.c
index 82ab532a4923..a93dc18a45c3 100644
--- a/drivers/net/wireless/ath/ar9170/usb.c
+++ b/drivers/net/wireless/ath/ar9170/usb.c
@@ -739,17 +739,27 @@ err_out:
static void ar9170_usb_firmware_failed(struct ar9170_usb *aru)
{
struct device *parent = aru->udev->dev.parent;
+ struct usb_device *udev;
+
+ /*
+ * Store a copy of the usb_device pointer locally.
+ * This is because device_release_driver initiates
+ * ar9170_usb_disconnect, which in turn frees our
+ * driver context (aru).
+ */
+ udev = aru->udev;
complete(&aru->firmware_loading_complete);
/* unbind anything failed */
if (parent)
device_lock(parent);
- device_release_driver(&aru->udev->dev);
+
+ device_release_driver(&udev->dev);
if (parent)
device_unlock(parent);
- usb_put_dev(aru->udev);
+ usb_put_dev(udev);
}
static void ar9170_usb_firmware_finish(const struct firmware *fw, void *context)
diff --git a/drivers/net/wireless/ath/ath5k/Makefile b/drivers/net/wireless/ath/ath5k/Makefile
index cc09595b781a..2242a140e4fe 100644
--- a/drivers/net/wireless/ath/ath5k/Makefile
+++ b/drivers/net/wireless/ath/ath5k/Makefile
@@ -13,5 +13,6 @@ ath5k-y += base.o
ath5k-y += led.o
ath5k-y += rfkill.o
ath5k-y += ani.o
+ath5k-y += sysfs.o
ath5k-$(CONFIG_ATH5K_DEBUG) += debug.o
obj-$(CONFIG_ATH5K) += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ani.c b/drivers/net/wireless/ath/ath5k/ani.c
index f2311ab35504..26dbe65fedb0 100644
--- a/drivers/net/wireless/ath/ath5k/ani.c
+++ b/drivers/net/wireless/ath/ath5k/ani.c
@@ -74,8 +74,8 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
const s8 fr[] = { -78, -80 };
#endif
if (level < 0 || level >= ARRAY_SIZE(sz)) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "noise immuniy level %d out of range",
+ level);
return;
}
@@ -106,8 +106,8 @@ ath5k_ani_set_spur_immunity_level(struct ath5k_hw *ah, int level)
if (level < 0 || level >= ARRAY_SIZE(val) ||
level > ah->ah_sc->ani_state.max_spur_level) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "spur immunity level %d out of range",
+ level);
return;
}
@@ -130,8 +130,7 @@ ath5k_ani_set_firstep_level(struct ath5k_hw *ah, int level)
const int val[] = { 0, 4, 8 };
if (level < 0 || level >= ARRAY_SIZE(val)) {
- ATH5K_DBG_UNLIMIT(ah->ah_sc, ATH5K_DEBUG_ANI,
- "level out of range %d", level);
+ ATH5K_ERR(ah->ah_sc, "firstep level %d out of range", level);
return;
}
@@ -481,14 +480,15 @@ ath5k_ani_calibration(struct ath5k_hw *ah)
struct ath5k_ani_state *as = &ah->ah_sc->ani_state;
int listen, ofdm_high, ofdm_low, cck_high, cck_low;
- if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
- return;
-
/* get listen time since last call and add it to the counter because we
- * might not have restarted the "ani period" last time */
+ * might not have restarted the "ani period" last time.
+ * always do this to calculate the busy time also in manual mode */
listen = ath5k_hw_ani_get_listen_time(ah, as);
as->listen_time += listen;
+ if (as->ani_mode != ATH5K_ANI_MODE_AUTO)
+ return;
+
ath5k_ani_save_and_clear_phy_errors(ah, as);
ofdm_high = as->listen_time * ATH5K_ANI_OFDM_TRIG_HIGH / 1000;
diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h
index 2785946f659a..eace74dac00e 100644
--- a/drivers/net/wireless/ath/ath5k/ath5k.h
+++ b/drivers/net/wireless/ath/ath5k/ath5k.h
@@ -204,6 +204,7 @@
#define AR5K_TUNE_TPC_TXPOWER false
#define ATH5K_TUNE_CALIBRATION_INTERVAL_FULL 10000 /* 10 sec */
#define ATH5K_TUNE_CALIBRATION_INTERVAL_ANI 1000 /* 1 sec */
+#define ATH5K_TUNE_CALIBRATION_INTERVAL_NF 60000 /* 60 sec */
#define AR5K_INIT_CARR_SENSE_EN 1
@@ -1118,6 +1119,7 @@ struct ath5k_hw {
/* Calibration timestamp */
unsigned long ah_cal_next_full;
unsigned long ah_cal_next_ani;
+ unsigned long ah_cal_next_nf;
/* Calibration mask */
u8 ah_cal_mask;
@@ -1148,6 +1150,9 @@ struct ath5k_hw {
int ath5k_hw_attach(struct ath5k_softc *sc);
void ath5k_hw_detach(struct ath5k_hw *ah);
+int ath5k_sysfs_register(struct ath5k_softc *sc);
+void ath5k_sysfs_unregister(struct ath5k_softc *sc);
+
/* LED functions */
int ath5k_init_leds(struct ath5k_softc *sc);
void ath5k_led_enable(struct ath5k_softc *sc);
@@ -1270,6 +1275,7 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah);
/* Spur mitigation */
bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
struct ieee80211_channel *channel);
diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c
index e0c244b02f05..ef2dc1dd3a5d 100644
--- a/drivers/net/wireless/ath/ath5k/attach.c
+++ b/drivers/net/wireless/ath/ath5k/attach.c
@@ -351,8 +351,6 @@ err_free:
*/
void ath5k_hw_detach(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
-
__set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
if (ah->ah_rf_banks != NULL)
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index cc6d41dec332..9d37c1a43a9d 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -195,7 +195,7 @@ static const struct ieee80211_rate ath5k_rates[] = {
static int __devinit ath5k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
static void __devexit ath5k_pci_remove(struct pci_dev *pdev);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev);
static int ath5k_pci_resume(struct device *dev);
@@ -203,7 +203,7 @@ static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
#define ATH5K_PM_OPS (&ath5k_pm_ops)
#else
#define ATH5K_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
static struct pci_driver ath5k_pci_driver = {
.name = KBUILD_MODNAME,
@@ -222,7 +222,6 @@ static int ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
static int ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath5k_txq *txq);
static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
-static int ath5k_reset_wake(struct ath5k_softc *sc);
static int ath5k_start(struct ieee80211_hw *hw);
static void ath5k_stop(struct ieee80211_hw *hw);
static int ath5k_add_interface(struct ieee80211_hw *hw,
@@ -579,7 +578,7 @@ ath5k_pci_probe(struct pci_dev *pdev,
spin_lock_init(&sc->block);
/* Set private data */
- pci_set_drvdata(pdev, hw);
+ pci_set_drvdata(pdev, sc);
/* Setup interrupt handler */
ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
@@ -695,25 +694,23 @@ err:
static void __devexit
ath5k_pci_remove(struct pci_dev *pdev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
ath5k_debug_finish_device(sc);
- ath5k_detach(pdev, hw);
+ ath5k_detach(pdev, sc->hw);
ath5k_hw_detach(sc->ah);
kfree(sc->ah);
free_irq(pdev->irq, sc);
pci_iounmap(pdev, sc->iobase);
pci_release_region(pdev, 0);
pci_disable_device(pdev);
- ieee80211_free_hw(hw);
+ ieee80211_free_hw(sc->hw);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ath5k_pci_suspend(struct device *dev)
{
- struct ieee80211_hw *hw = pci_get_drvdata(to_pci_dev(dev));
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
ath5k_led_off(sc);
return 0;
@@ -722,8 +719,7 @@ static int ath5k_pci_suspend(struct device *dev)
static int ath5k_pci_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath5k_softc *sc = hw->priv;
+ struct ath5k_softc *sc = pci_get_drvdata(pdev);
/*
* Suspend/Resume resets the PCI configuration space, so we have to
@@ -735,7 +731,7 @@ static int ath5k_pci_resume(struct device *dev)
ath5k_led_enable(sc);
return 0;
}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/***********************\
@@ -865,6 +861,8 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
ath5k_init_leds(sc);
+ ath5k_sysfs_register(sc);
+
return 0;
err_queues:
ath5k_txq_release(sc);
@@ -900,6 +898,7 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
ath5k_unregister_leds(sc);
+ ath5k_sysfs_unregister(sc);
/*
* NB: can't reclaim these until after ieee80211_ifdetach
* returns because we'll get called back to reclaim node
@@ -2770,7 +2769,7 @@ ath5k_tasklet_reset(unsigned long data)
{
struct ath5k_softc *sc = (void *)data;
- ath5k_reset_wake(sc);
+ ath5k_reset(sc, sc->curchan);
}
/*
@@ -2786,10 +2785,6 @@ ath5k_tasklet_calibrate(unsigned long data)
/* Only full calibration for now */
ah->ah_cal_mask |= AR5K_CALIBRATION_FULL;
- /* Stop queues so that calibration
- * doesn't interfere with tx */
- ieee80211_stop_queues(sc->hw);
-
ATH5K_DBG(sc, ATH5K_DEBUG_CALIBRATE, "channel %u/%x\n",
ieee80211_frequency_to_channel(sc->curchan->center_freq),
sc->curchan->hw_value);
@@ -2807,8 +2802,16 @@ ath5k_tasklet_calibrate(unsigned long data)
ieee80211_frequency_to_channel(
sc->curchan->center_freq));
- /* Wake queues */
- ieee80211_wake_queues(sc->hw);
+ /* Noise floor calibration interrupts rx/tx path while I/Q calibration
+ * doesn't. We stop the queues so that calibration doesn't interfere
+ * with TX and don't run it as often */
+ if (time_is_before_eq_jiffies(ah->ah_cal_next_nf)) {
+ ah->ah_cal_next_nf = jiffies +
+ msecs_to_jiffies(ATH5K_TUNE_CALIBRATION_INTERVAL_NF);
+ ieee80211_stop_queues(sc->hw);
+ ath5k_hw_update_noise_floor(ah);
+ ieee80211_wake_queues(sc->hw);
+ }
ah->ah_cal_mask &= ~AR5K_CALIBRATION_FULL;
}
@@ -2927,6 +2930,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ath5k_ani_init(ah, ah->ah_sc->ani_state.ani_mode);
+ ah->ah_cal_next_full = jiffies;
+ ah->ah_cal_next_ani = jiffies;
+ ah->ah_cal_next_nf = jiffies;
+
/*
* Change channels and update the h/w rate map if we're switching;
* e.g. 11a to 11b/g.
@@ -2941,23 +2948,13 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
ath5k_beacon_config(sc);
/* intrs are enabled by ath5k_beacon_config */
+ ieee80211_wake_queues(sc->hw);
+
return 0;
err:
return ret;
}
-static int
-ath5k_reset_wake(struct ath5k_softc *sc)
-{
- int ret;
-
- ret = ath5k_reset(sc, sc->curchan);
- if (!ret)
- ieee80211_wake_queues(sc->hw);
-
- return ret;
-}
-
static int ath5k_start(struct ieee80211_hw *hw)
{
return ath5k_init(hw->priv);
@@ -3151,13 +3148,15 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw,
if (changed_flags & (FIF_PROMISC_IN_BSS | FIF_OTHER_BSS)) {
if (*new_flags & FIF_PROMISC_IN_BSS) {
- rfilt |= AR5K_RX_FILTER_PROM;
__set_bit(ATH_STAT_PROMISC, sc->status);
} else {
__clear_bit(ATH_STAT_PROMISC, sc->status);
}
}
+ if (test_bit(ATH_STAT_PROMISC, sc->status))
+ rfilt |= AR5K_RX_FILTER_PROM;
+
/* Note, AR5K_RX_FILTER_MCAST is already enabled */
if (*new_flags & FIF_ALLMULTI) {
mfilt[0] = ~0;
diff --git a/drivers/net/wireless/ath/ath5k/caps.c b/drivers/net/wireless/ath/ath5k/caps.c
index 74f007126f41..beae519aa735 100644
--- a/drivers/net/wireless/ath/ath5k/caps.c
+++ b/drivers/net/wireless/ath/ath5k/caps.c
@@ -34,7 +34,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
{
u16 ee_header;
- ATH5K_TRACE(ah->ah_sc);
/* Capabilities stored in the EEPROM */
ee_header = ah->ah_capabilities.cap_eeprom.ee_header;
@@ -123,8 +122,6 @@ int ath5k_hw_get_capability(struct ath5k_hw *ah,
enum ath5k_capability_type cap_type,
u32 capability, u32 *result)
{
- ATH5K_TRACE(ah->ah_sc);
-
switch (cap_type) {
case AR5K_CAP_NUM_TXQUEUES:
if (result) {
@@ -173,8 +170,6 @@ yes:
int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
u16 assoc_id)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version == AR5K_AR5210) {
AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1,
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
@@ -186,8 +181,6 @@ int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid,
int ath5k_hw_disable_pspoll(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version == AR5K_AR5210) {
AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1,
AR5K_STA_ID1_NO_PSPOLL | AR5K_STA_ID1_DEFAULT_ANTENNA);
diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c
index 6fb5c5ffa5b1..c58503c3d0d1 100644
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -307,7 +307,6 @@ static const struct {
{ ATH5K_DEBUG_DUMP_RX, "dumprx", "print received skb content" },
{ ATH5K_DEBUG_DUMP_TX, "dumptx", "print transmit skb content" },
{ ATH5K_DEBUG_DUMPBANDS, "dumpbands", "dump bands" },
- { ATH5K_DEBUG_TRACE, "trace", "trace function calls" },
{ ATH5K_DEBUG_ANI, "ani", "adaptive noise immunity" },
{ ATH5K_DEBUG_ANY, "all", "show all debug levels" },
};
diff --git a/drivers/net/wireless/ath/ath5k/debug.h b/drivers/net/wireless/ath/ath5k/debug.h
index ddd5b3a99e8d..bd1658729141 100644
--- a/drivers/net/wireless/ath/ath5k/debug.h
+++ b/drivers/net/wireless/ath/ath5k/debug.h
@@ -115,18 +115,12 @@ enum ath5k_debug_level {
ATH5K_DEBUG_DUMP_RX = 0x00000100,
ATH5K_DEBUG_DUMP_TX = 0x00000200,
ATH5K_DEBUG_DUMPBANDS = 0x00000400,
- ATH5K_DEBUG_TRACE = 0x00001000,
ATH5K_DEBUG_ANI = 0x00002000,
ATH5K_DEBUG_ANY = 0xffffffff
};
#ifdef CONFIG_ATH5K_DEBUG
-#define ATH5K_TRACE(_sc) do { \
- if (unlikely((_sc)->debug.level & ATH5K_DEBUG_TRACE)) \
- printk(KERN_DEBUG "ath5k trace %s:%d\n", __func__, __LINE__); \
- } while (0)
-
#define ATH5K_DBG(_sc, _m, _fmt, ...) do { \
if (unlikely((_sc)->debug.level & (_m) && net_ratelimit())) \
ATH5K_PRINTK(_sc, KERN_DEBUG, "(%s:%d): " _fmt, \
@@ -168,8 +162,6 @@ ath5k_debug_printtxbuf(struct ath5k_softc *sc, struct ath5k_buf *bf);
#include <linux/compiler.h>
-#define ATH5K_TRACE(_sc) typecheck(struct ath5k_softc *, (_sc))
-
static inline void __attribute__ ((format (printf, 3, 4)))
ATH5K_DBG(struct ath5k_softc *sc, unsigned int m, const char *fmt, ...) {}
diff --git a/drivers/net/wireless/ath/ath5k/desc.c b/drivers/net/wireless/ath/ath5k/desc.c
index 7d7b646ab65a..da5dbb63047f 100644
--- a/drivers/net/wireless/ath/ath5k/desc.c
+++ b/drivers/net/wireless/ath/ath5k/desc.c
@@ -176,7 +176,6 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
unsigned int frame_len;
- ATH5K_TRACE(ah->ah_sc);
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
/*
@@ -342,8 +341,6 @@ static int ath5k_hw_proc_2word_tx_status(struct ath5k_hw *ah,
struct ath5k_hw_2w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- ATH5K_TRACE(ah->ah_sc);
-
tx_ctl = &desc->ud.ds_tx5210.tx_ctl;
tx_status = &desc->ud.ds_tx5210.tx_stat;
@@ -396,8 +393,6 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
struct ath5k_hw_4w_tx_ctl *tx_ctl;
struct ath5k_hw_tx_status *tx_status;
- ATH5K_TRACE(ah->ah_sc);
-
tx_ctl = &desc->ud.ds_tx5212.tx_ctl;
tx_status = &desc->ud.ds_tx5212.tx_stat;
@@ -490,7 +485,6 @@ static int ath5k_hw_setup_rx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
{
struct ath5k_hw_rx_ctl *rx_ctl;
- ATH5K_TRACE(ah->ah_sc);
rx_ctl = &desc->ud.ds_rx.rx_ctl;
/*
@@ -593,7 +587,6 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
struct ath5k_hw_rx_status *rx_status;
struct ath5k_hw_rx_error *rx_err;
- ATH5K_TRACE(ah->ah_sc);
rx_status = &desc->ud.ds_rx.u.rx_stat;
/* Overlay on error */
diff --git a/drivers/net/wireless/ath/ath5k/dma.c b/drivers/net/wireless/ath/ath5k/dma.c
index 941b51130a6f..484f31870ba8 100644
--- a/drivers/net/wireless/ath/ath5k/dma.c
+++ b/drivers/net/wireless/ath/ath5k/dma.c
@@ -48,7 +48,6 @@
*/
void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXE, AR5K_CR);
ath5k_hw_reg_read(ah, AR5K_CR);
}
@@ -62,7 +61,6 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
{
unsigned int i;
- ATH5K_TRACE(ah->ah_sc);
ath5k_hw_reg_write(ah, AR5K_CR_RXD, AR5K_CR);
/*
@@ -96,8 +94,6 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
*/
void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
{
- ATH5K_TRACE(ah->ah_sc);
-
ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
}
@@ -125,7 +121,6 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
{
u32 tx_queue;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -186,7 +181,6 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
unsigned int i = 40;
u32 tx_queue, pending;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -297,7 +291,6 @@ u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue)
{
u16 tx_reg;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/*
@@ -340,7 +333,6 @@ int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue, u32 phys_addr)
{
u16 tx_reg;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/*
@@ -400,8 +392,6 @@ int ath5k_hw_update_tx_triglevel(struct ath5k_hw *ah, bool increase)
u32 trigger_level, imr;
int ret = -EIO;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Disable interrupts by setting the mask
*/
@@ -451,7 +441,6 @@ done:
*/
bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
return ath5k_hw_reg_read(ah, AR5K_INTPEND) == 1 ? 1 : 0;
}
@@ -475,8 +464,6 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask)
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Read interrupt status from the Interrupt Status register
* on 5210
diff --git a/drivers/net/wireless/ath/ath5k/eeprom.c b/drivers/net/wireless/ath/ath5k/eeprom.c
index ed0263672d6d..ae316fec4a6a 100644
--- a/drivers/net/wireless/ath/ath5k/eeprom.c
+++ b/drivers/net/wireless/ath/ath5k/eeprom.c
@@ -35,7 +35,6 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
{
u32 status, timeout;
- ATH5K_TRACE(ah->ah_sc);
/*
* Initialize EEPROM access
*/
@@ -715,7 +714,7 @@ ath5k_eeprom_convert_pcal_info_5111(struct ath5k_hw *ah, int mode,
/* Only one curve for RF5111
* find out which one and place
- * in in pd_curves.
+ * in pd_curves.
* Note: ee_x_gain is reversed here */
for (idx = 0; idx < AR5K_EEPROM_N_PD_CURVES; idx++) {
diff --git a/drivers/net/wireless/ath/ath5k/gpio.c b/drivers/net/wireless/ath/ath5k/gpio.c
index 64a27e73d02e..bc90503f4b7a 100644
--- a/drivers/net/wireless/ath/ath5k/gpio.c
+++ b/drivers/net/wireless/ath/ath5k/gpio.c
@@ -34,8 +34,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
/*5210 has different led mode handling*/
u32 led_5210;
- ATH5K_TRACE(ah->ah_sc);
-
/*Reset led status*/
if (ah->ah_version != AR5K_AR5210)
AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
@@ -82,7 +80,6 @@ void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state)
*/
int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -98,7 +95,6 @@ int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio)
*/
int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -114,7 +110,6 @@ int ath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio)
*/
u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
{
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return 0xffffffff;
@@ -129,7 +124,6 @@ u32 ath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio)
int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val)
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return -EINVAL;
@@ -153,7 +147,6 @@ void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
{
u32 data;
- ATH5K_TRACE(ah->ah_sc);
if (gpio >= AR5K_NUM_GPIO)
return;
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index 5212e275f1c7..86fdb6ddfaaa 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -59,8 +59,6 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
beacon_reg = 0;
- ATH5K_TRACE(ah->ah_sc);
-
switch (op_mode) {
case NL80211_IFTYPE_ADHOC:
pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE;
@@ -173,7 +171,6 @@ void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
*/
static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
- ATH5K_TRACE(ah->ah_sc);
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_ACK))
<= timeout)
return -EINVAL;
@@ -192,7 +189,6 @@ static int ath5k_hw_set_ack_timeout(struct ath5k_hw *ah, unsigned int timeout)
*/
static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
{
- ATH5K_TRACE(ah->ah_sc);
if (ath5k_hw_clocktoh(ah, AR5K_REG_MS(0xffffffff, AR5K_TIME_OUT_CTS))
<= timeout)
return -EINVAL;
@@ -297,7 +293,6 @@ int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac)
u32 low_id, high_id;
u32 pcu_reg;
- ATH5K_TRACE(ah->ah_sc);
/* Set new station ID */
memcpy(common->macaddr, mac, ETH_ALEN);
@@ -357,7 +352,6 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah)
void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
{
struct ath_common *common = ath5k_hw_common(ah);
- ATH5K_TRACE(ah->ah_sc);
/* Cache bssid mask so that we can restore it
* on reset */
@@ -382,7 +376,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
*/
void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
}
@@ -397,7 +390,6 @@ void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
*/
void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
}
@@ -406,8 +398,6 @@ void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
*/
void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1)
{
- ATH5K_TRACE(ah->ah_sc);
- /* Set the multicat filter */
ath5k_hw_reg_write(ah, filter0, AR5K_MCAST_FILTER0);
ath5k_hw_reg_write(ah, filter1, AR5K_MCAST_FILTER1);
}
@@ -427,7 +417,6 @@ u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah)
{
u32 data, filter = 0;
- ATH5K_TRACE(ah->ah_sc);
filter = ath5k_hw_reg_read(ah, AR5K_RX_FILTER);
/*Radar detection for 5212*/
@@ -457,8 +446,6 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter)
{
u32 data = 0;
- ATH5K_TRACE(ah->ah_sc);
-
/* Set PHY error filter register on 5212*/
if (ah->ah_version == AR5K_AR5212) {
if (filter & AR5K_RX_FILTER_RADARERR)
@@ -533,8 +520,6 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
WARN_ON( i == ATH5K_MAX_TSF_READ );
- ATH5K_TRACE(ah->ah_sc);
-
return (((u64)tsf_upper1 << 32) | tsf_lower);
}
@@ -548,8 +533,6 @@ u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah)
*/
void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
{
- ATH5K_TRACE(ah->ah_sc);
-
ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
}
@@ -565,8 +548,6 @@ void ath5k_hw_reset_tsf(struct ath5k_hw *ah)
{
u32 val;
- ATH5K_TRACE(ah->ah_sc);
-
val = ath5k_hw_reg_read(ah, AR5K_BEACON) | AR5K_BEACON_RESET_TSF;
/*
@@ -586,7 +567,6 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval)
{
u32 timer1, timer2, timer3;
- ATH5K_TRACE(ah->ah_sc);
/*
* Set the additional timers by mode
*/
@@ -674,7 +654,6 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry)
unsigned int i, type;
u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry));
@@ -749,8 +728,6 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry,
bool is_tkip;
const u8 *key_ptr;
- ATH5K_TRACE(ah->ah_sc);
-
is_tkip = (key->alg == ALG_TKIP);
/*
@@ -836,7 +813,6 @@ int ath5k_hw_set_key_lladdr(struct ath5k_hw *ah, u16 entry, const u8 *mac)
{
u32 low_id, high_id;
- ATH5K_TRACE(ah->ah_sc);
/* Invalid entry (key table overflow) */
AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE);
diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c
index 1b81c4778800..34ba576d2747 100644
--- a/drivers/net/wireless/ath/ath5k/phy.c
+++ b/drivers/net/wireless/ath/ath5k/phy.c
@@ -378,8 +378,6 @@ enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah)
u32 data, type;
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_rf_banks == NULL ||
ah->ah_gain.g_state == AR5K_RFGAIN_INACTIVE)
return AR5K_RFGAIN_INACTIVE;
@@ -1167,7 +1165,7 @@ static s16 ath5k_hw_get_median_noise_floor(struct ath5k_hw *ah)
* The median of the values in the history is then loaded into the
* hardware for its own use for RSSI and CCA measurements.
*/
-static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
+void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
{
struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
u32 val;
@@ -1248,7 +1246,6 @@ static void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
/*
* Perform a PHY calibration on RF5110
* -Fix BPSK/QAM Constellation (I/Q correction)
- * -Calculate Noise Floor
*/
static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
struct ieee80211_channel *channel)
@@ -1335,8 +1332,6 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
return ret;
}
- ath5k_hw_update_noise_floor(ah);
-
/*
* Re-enable RX/TX and beacons
*/
@@ -1348,22 +1343,20 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah,
}
/*
- * Perform a PHY calibration on RF5111/5112 and newer chips
+ * Perform I/Q calibration on RF5111/5112 and newer chips
*/
-static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
- struct ieee80211_channel *channel)
+static int
+ath5k_hw_rf511x_iq_calibrate(struct ath5k_hw *ah)
{
u32 i_pwr, q_pwr;
s32 iq_corr, i_coff, i_coffd, q_coff, q_coffd;
int i;
- ATH5K_TRACE(ah->ah_sc);
if (!ah->ah_calibration ||
ath5k_hw_reg_read(ah, AR5K_PHY_IQ) & AR5K_PHY_IQ_RUN)
- goto done;
+ return 0;
/* Calibration has finished, get the results and re-run */
-
/* work around empty results which can apparently happen on 5212 */
for (i = 0; i <= 10; i++) {
iq_corr = ath5k_hw_reg_read(ah, AR5K_PHY_IQRES_CAL_CORR);
@@ -1384,7 +1377,7 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
/* protect against divide by 0 and loss of sign bits */
if (i_coffd == 0 || q_coffd < 2)
- goto done;
+ return -1;
i_coff = (-iq_corr) / i_coffd;
i_coff = clamp(i_coff, -32, 31); /* signed 6 bit */
@@ -1410,17 +1403,6 @@ static int ath5k_hw_rf511x_calibrate(struct ath5k_hw *ah,
AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ, AR5K_PHY_IQ_RUN);
-done:
-
- /* TODO: Separate noise floor calibration from I/Q calibration
- * since noise floor calibration interrupts rx path while I/Q
- * calibration doesn't. We don't need to run noise floor calibration
- * as often as I/Q calibration.*/
- ath5k_hw_update_noise_floor(ah);
-
- /* Initiate a gain_F calibration */
- ath5k_hw_request_rfgain_probe(ah);
-
return 0;
}
@@ -1434,8 +1416,10 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
if (ah->ah_radio == AR5K_RF5110)
ret = ath5k_hw_rf5110_calibrate(ah, channel);
- else
- ret = ath5k_hw_rf511x_calibrate(ah, channel);
+ else {
+ ret = ath5k_hw_rf511x_iq_calibrate(ah);
+ ath5k_hw_request_rfgain_probe(ah);
+ }
return ret;
}
@@ -1693,7 +1677,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
int ath5k_hw_phy_disable(struct ath5k_hw *ah)
{
- ATH5K_TRACE(ah->ah_sc);
/*Just a try M.F.*/
ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
@@ -1709,8 +1692,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
u32 srev;
u16 ret;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Set the radio chip access register
*/
@@ -1755,8 +1736,6 @@ u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
static void /*TODO:Boundary check*/
ath5k_hw_set_def_antenna(struct ath5k_hw *ah, u8 ant)
{
- ATH5K_TRACE(ah->ah_sc);
-
if (ah->ah_version != AR5K_AR5210)
ath5k_hw_reg_write(ah, ant & 0x7, AR5K_DEFAULT_ANTENNA);
}
@@ -1814,9 +1793,14 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
u8 def_ant, tx_ant, ee_mode;
u32 sta_id1 = 0;
- def_ant = ah->ah_def_ant;
+ /* if channel is not initialized yet we can't set the antennas
+ * so just store the mode. it will be set on the next reset */
+ if (channel == NULL) {
+ ah->ah_ant_mode = ant_mode;
+ return;
+ }
- ATH5K_TRACE(ah->ah_sc);
+ def_ant = ah->ah_def_ant;
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
@@ -2981,7 +2965,6 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
u8 type;
int ret;
- ATH5K_TRACE(ah->ah_sc);
if (txpower > AR5K_TUNE_MAX_TXPOWER) {
ATH5K_ERR(ah->ah_sc, "invalid tx power: %u\n", txpower);
return -EINVAL;
@@ -3077,8 +3060,6 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
struct ieee80211_channel *channel = ah->ah_current_channel;
u8 ee_mode;
- ATH5K_TRACE(ah->ah_sc);
-
switch (channel->hw_value & CHANNEL_MODES) {
case CHANNEL_A:
case CHANNEL_T:
diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c
index f5831da33f7b..4186ff4c6e9c 100644
--- a/drivers/net/wireless/ath/ath5k/qcu.c
+++ b/drivers/net/wireless/ath/ath5k/qcu.c
@@ -31,7 +31,6 @@ Queue Control Unit, DFS Control Unit Functions
int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
struct ath5k_txq_info *queue_info)
{
- ATH5K_TRACE(ah->ah_sc);
memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
return 0;
}
@@ -42,7 +41,6 @@ int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
int ath5k_hw_set_tx_queueprops(struct ath5k_hw *ah, int queue,
const struct ath5k_txq_info *queue_info)
{
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
@@ -69,8 +67,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
unsigned int queue;
int ret;
- ATH5K_TRACE(ah->ah_sc);
-
/*
* Get queue by type
*/
@@ -149,7 +145,6 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
{
u32 pending;
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
/* Return if queue is declared inactive */
@@ -177,7 +172,6 @@ u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
*/
void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
{
- ATH5K_TRACE(ah->ah_sc);
if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
return;
@@ -195,7 +189,6 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
u32 cw_min, cw_max, retry_lg, retry_sh;
struct ath5k_txq_info *tq = &ah->ah_txq[queue];
- ATH5K_TRACE(ah->ah_sc);
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
tq = &ah->ah_txq[queue];
@@ -523,8 +516,6 @@ int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
{
u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
- ATH5K_TRACE(ah->ah_sc);
-
if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
return -EINVAL;
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index 307f80e83f94..c17c84e93561 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -201,8 +201,6 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
int ret;
u32 mask = val ? val : ~0U;
- ATH5K_TRACE(ah->ah_sc);
-
/* Read-and-clear RX Descriptor Pointer*/
ath5k_hw_reg_read(ah, AR5K_RXDP);
@@ -246,7 +244,6 @@ static int ath5k_hw_set_power(struct ath5k_hw *ah, enum ath5k_power_mode mode,
unsigned int i;
u32 staid, data;
- ATH5K_TRACE(ah->ah_sc);
staid = ath5k_hw_reg_read(ah, AR5K_STA_ID1);
switch (mode) {
@@ -393,8 +390,6 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
mode = 0;
clock = 0;
- ATH5K_TRACE(ah->ah_sc);
-
/* Wakeup the device */
ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
if (ret) {
@@ -855,7 +850,6 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
AR5K_PHY_NF_THRESH62,
ee->ee_thr_62[ee_mode]);
-
/* False detect backoff for channels
* that have spur noise. Write the new
* cyclic power RSSI threshold. */
@@ -896,8 +890,6 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
u8 mode, freq, ee_mode, ant[2];
int i, ret;
- ATH5K_TRACE(ah->ah_sc);
-
s_ant = 0;
ee_mode = 0;
staid1_flags = 0;
@@ -1094,22 +1086,17 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
/* Write OFDM timings on 5212*/
if (ah->ah_version == AR5K_AR5212 &&
channel->hw_value & CHANNEL_OFDM) {
- struct ath5k_eeprom_info *ee =
- &ah->ah_capabilities.cap_eeprom;
ret = ath5k_hw_write_ofdm_timings(ah, channel);
if (ret)
return ret;
- /* Note: According to docs we can have a newer
- * EEPROM on old hardware, so we need to verify
- * that our hardware is new enough to have spur
- * mitigation registers (delta phase etc) */
- if (ah->ah_mac_srev >= AR5K_SREV_AR5424 ||
- (ah->ah_mac_srev >= AR5K_SREV_AR5424 &&
- ee->ee_version >= AR5K_EEPROM_VERSION_5_3))
+ /* Spur info is available only from EEPROM versions
+ * bigger than 5.3 but but the EEPOM routines will use
+ * static values for older versions */
+ if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
ath5k_hw_set_spur_mitigation_filter(ah,
- channel);
+ channel);
}
/*Enable/disable 802.11b mode on 5111
diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c
new file mode 100644
index 000000000000..90757de7bf59
--- /dev/null
+++ b/drivers/net/wireless/ath/ath5k/sysfs.c
@@ -0,0 +1,116 @@
+#include <linux/device.h>
+#include <linux/pci.h>
+
+#include "base.h"
+#include "ath5k.h"
+#include "reg.h"
+
+#define SIMPLE_SHOW_STORE(name, get, set) \
+static ssize_t ath5k_attr_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", get); \
+} \
+ \
+static ssize_t ath5k_attr_store_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ int val; \
+ \
+ val = (int)simple_strtoul(buf, NULL, 10); \
+ set(sc->ah, val); \
+ return count; \
+} \
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \
+ ath5k_attr_show_##name, ath5k_attr_store_##name)
+
+#define SIMPLE_SHOW(name, get) \
+static ssize_t ath5k_attr_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ath5k_softc *sc = dev_get_drvdata(dev); \
+ return snprintf(buf, PAGE_SIZE, "%d\n", get); \
+} \
+static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL)
+
+/*** ANI ***/
+
+SIMPLE_SHOW_STORE(ani_mode, sc->ani_state.ani_mode, ath5k_ani_init);
+SIMPLE_SHOW_STORE(noise_immunity_level, sc->ani_state.noise_imm_level,
+ ath5k_ani_set_noise_immunity_level);
+SIMPLE_SHOW_STORE(spur_level, sc->ani_state.spur_level,
+ ath5k_ani_set_spur_immunity_level);
+SIMPLE_SHOW_STORE(firstep_level, sc->ani_state.firstep_level,
+ ath5k_ani_set_firstep_level);
+SIMPLE_SHOW_STORE(ofdm_weak_signal_detection, sc->ani_state.ofdm_weak_sig,
+ ath5k_ani_set_ofdm_weak_signal_detection);
+SIMPLE_SHOW_STORE(cck_weak_signal_detection, sc->ani_state.cck_weak_sig,
+ ath5k_ani_set_cck_weak_signal_detection);
+SIMPLE_SHOW(spur_level_max, sc->ani_state.max_spur_level);
+
+static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL);
+}
+static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO,
+ ath5k_attr_show_noise_immunity_level_max, NULL);
+
+static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL);
+}
+static DEVICE_ATTR(firstep_level_max, S_IRUGO,
+ ath5k_attr_show_firstep_level_max, NULL);
+
+static struct attribute *ath5k_sysfs_entries_ani[] = {
+ &dev_attr_ani_mode.attr,
+ &dev_attr_noise_immunity_level.attr,
+ &dev_attr_spur_level.attr,
+ &dev_attr_firstep_level.attr,
+ &dev_attr_ofdm_weak_signal_detection.attr,
+ &dev_attr_cck_weak_signal_detection.attr,
+ &dev_attr_noise_immunity_level_max.attr,
+ &dev_attr_spur_level_max.attr,
+ &dev_attr_firstep_level_max.attr,
+ NULL
+};
+
+static struct attribute_group ath5k_attribute_group_ani = {
+ .name = "ani",
+ .attrs = ath5k_sysfs_entries_ani,
+};
+
+
+/*** register / unregister ***/
+
+int
+ath5k_sysfs_register(struct ath5k_softc *sc)
+{
+ struct device *dev = &sc->pdev->dev;
+ int err;
+
+ err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani);
+ if (err) {
+ ATH5K_ERR(sc, "failed to create sysfs group\n");
+ return err;
+ }
+
+ return 0;
+}
+
+void
+ath5k_sysfs_unregister(struct ath5k_softc *sc)
+{
+ struct device *dev = &sc->pdev->dev;
+
+ sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani);
+}
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index ba8b20f01594..3da820ffc65e 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -495,6 +495,7 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
REG_WRITE(ah, AR_FILT_OFDM, 0);
REG_WRITE(ah, AR_FILT_CCK, 0);
}
+EXPORT_SYMBOL(ath9k_hw_disable_mib_counters);
u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hw *ah,
u32 *rxc_pcnt,
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index b2c17c98bb38..96018d53f48e 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -742,17 +742,6 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
return -EINVAL;
}
- if (AR_SREV_9287_12_OR_LATER(ah)) {
- /* Enable ASYNC FIFO */
- REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
- REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
- REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
- REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
- AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
- }
-
/*
* Set correct baseband to analog shift setting to
* access analog chips.
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
index a8a8cdc04afa..7ba9dd68cc05 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c
@@ -18,6 +18,7 @@
#include "ar5008_initvals.h"
#include "ar9001_initvals.h"
#include "ar9002_initvals.h"
+#include "ar9002_phy.h"
/* General hardware code for the A5008/AR9001/AR9002 hadware families */
@@ -436,55 +437,84 @@ static void ar9002_hw_configpcipowersave(struct ath_hw *ah,
}
udelay(1000);
+ }
- /* set bit 19 to allow forcing of pcie core into L1 state */
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
+ if (power_off) {
+ /* clear bit 19 to disable L1 */
+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
- /* Several PCIe massages to ensure proper behaviour */
+ val = REG_READ(ah, AR_WA);
+
+ /*
+ * Set PCIe workaround bits
+ * In AR9280 and AR9285, bit 14 in WA register (disable L1)
+ * should only be set when device enters D3 and be
+ * cleared when device comes back to D0.
+ */
+ if (ah->config.pcie_waen) {
+ if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
+ val |= AR_WA_D3_L1_DISABLE;
+ } else {
+ if (((AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah) ||
+ AR_SREV_9287(ah)) &&
+ (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
+ (AR_SREV_9280(ah) &&
+ (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
+ val |= AR_WA_D3_L1_DISABLE;
+ }
+ }
+
+ if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+ /*
+ * Disable bit 6 and 7 before entering D3 to
+ * prevent system hang.
+ */
+ val &= ~(AR_WA_BIT6 | AR_WA_BIT7);
+ }
+
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
+ REG_WRITE(ah, AR_WA, val);
+ } else {
if (ah->config.pcie_waen) {
val = ah->config.pcie_waen;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
} else {
- if (AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
+ if (AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah) ||
AR_SREV_9287(ah)) {
val = AR9285_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
- } else if (AR_SREV_9280(ah)) {
+ }
+ else if (AR_SREV_9280(ah)) {
/*
- * On AR9280 chips bit 22 of 0x4004 needs to be
- * set otherwise card may disappear.
+ * For AR9280 chips, bit 22 of 0x4004
+ * needs to be set.
*/
val = AR9280_WA_DEFAULT;
if (!power_off)
val &= (~AR_WA_D3_L1_DISABLE);
- } else
+ } else {
val = AR_WA_DEFAULT;
+ }
+ }
+
+ /* WAR for ASPM system hang */
+ if (AR_SREV_9280(ah) || AR_SREV_9285(ah) || AR_SREV_9287(ah)) {
+ val |= (AR_WA_BIT6 | AR_WA_BIT7);
}
+ if (AR_SREV_9285E_20(ah))
+ val |= AR_WA_BIT23;
+
REG_WRITE(ah, AR_WA, val);
- }
- if (power_off) {
- /*
- * Set PCIe workaround bits
- * bit 14 in WA register (disable L1) should only
- * be set when device enters D3 and be cleared
- * when device comes back to D0.
- */
- if (ah->config.pcie_waen) {
- if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE)
- REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
- } else {
- if (((AR_SREV_9285(ah) || AR_SREV_9271(ah) ||
- AR_SREV_9287(ah)) &&
- (AR9285_WA_DEFAULT & AR_WA_D3_L1_DISABLE)) ||
- (AR_SREV_9280(ah) &&
- (AR9280_WA_DEFAULT & AR_WA_D3_L1_DISABLE))) {
- REG_SET_BIT(ah, AR_WA, AR_WA_D3_L1_DISABLE);
- }
- }
+ /* set bit 19 to allow forcing of pcie core into L1 state */
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA);
}
}
@@ -536,18 +566,29 @@ int ar9002_hw_rf_claim(struct ath_hw *ah)
return 0;
}
+void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+{
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL);
+ REG_SET_BIT(ah, AR_PHY_MODE, AR_PHY_MODE_ASYNCFIFO);
+ REG_CLR_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ REG_SET_BIT(ah, AR_MAC_PCU_ASYNC_FIFO_REG3,
+ AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET);
+ }
+}
+
/*
- * Enable ASYNC FIFO
- *
* If Async FIFO is enabled, the following counters change as MAC now runs
* at 117 Mhz instead of 88/44MHz when async FIFO is disabled.
*
* The values below tested for ht40 2 chain.
* Overwrite the delay/timeouts initialized in process ini.
*/
-void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
+void ar9002_hw_update_async_fifo(struct ath_hw *ah)
{
- if (AR_SREV_9287_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
REG_WRITE(ah, AR_D_GBL_IFS_SIFS,
AR_D_GBL_IFS_SIFS_ASYNC_FIFO_DUR);
REG_WRITE(ah, AR_D_GBL_IFS_SLOT,
@@ -571,9 +612,9 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
*/
void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah)
{
- if (AR_SREV_9287_12_OR_LATER(ah)) {
+ if (AR_SREV_9287_13_OR_LATER(ah)) {
REG_SET_BIT(ah, AR_PCU_MISC_MODE2,
- AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
+ AR_PCU_MISC_MODE2_ENABLE_AGGWEP);
}
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
index dae7f3304eb8..8ab24ee8564b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h
@@ -4492,7 +4492,7 @@ static const u32 ar9287PciePhy_clkreq_off_L1_9287_1_1[][2] = {
};
-/* AR9271 initialization values automaticaly created: 06/04/09 */
+/* AR9271 initialization values automaticaly created: 03/31/10 */
static const u32 ar9271Modes_9271[][6] = {
{ 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
{ 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -5011,7 +5011,7 @@ static const u32 ar9271Common_9271[][2] = {
{ 0x0000783c, 0x72ee0a72 },
{ 0x00007840, 0xbbfffffc },
{ 0x00007844, 0x000c0db6 },
- { 0x00007848, 0x6db61b6f },
+ { 0x00007848, 0x6db6246f },
{ 0x0000784c, 0x6d9b66db },
{ 0x00007850, 0x6d8c6dba },
{ 0x00007854, 0x00040000 },
@@ -5218,7 +5218,7 @@ static const u32 ar9271Modes_high_power_tx_gain_9271[][6] = {
{ 0x00007824, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff, 0x00d8a7ff },
{ 0x0000786c, 0x08609eb6, 0x08609eb6, 0x08609eba, 0x08609eba, 0x08609eb6 },
{ 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
- { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a212652, 0x0a212652, 0x0a22a652 },
+ { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a214652, 0x0a214652, 0x0a22a652 },
{ 0x0000a278, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7, 0x0e739ce7 },
{ 0x0000a27c, 0x05018063, 0x05038063, 0x05018063, 0x05018063, 0x05018063 },
{ 0x0000a394, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63, 0x06318c63 },
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
index db019dd220b7..f82a00da82b8 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p0_initvals.h
@@ -14,8 +14,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#ifndef INITVALS_9003_H
-#define INITVALS_9003_H
+#ifndef INITVALS_9003_2P0_H
+#define INITVALS_9003_2P0_H
/* AR9003 2.0 */
@@ -1781,4 +1781,4 @@ static const u32 ar9300PciePhy_clkreq_disable_L1_2p0[][2] = {
{0x00004044, 0x00000000},
};
-#endif /* INITVALS_9003_H */
+#endif /* INITVALS_9003_2P0_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
new file mode 100644
index 000000000000..745150573793
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -0,0 +1,1785 @@
+/*
+ * Copyright (c) 2010 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_9003_2P2_H
+#define INITVALS_9003_2P2_H
+
+/* AR9003 2.2 */
+
+static const u32 ar9300_2p2_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0001609c, 0x0dd08f29, 0x0dd08f29, 0x0b283f31, 0x0b283f31},
+ {0x000160ac, 0xa4653c00, 0xa4653c00, 0x24652800, 0x24652800},
+ {0x000160b0, 0x03284f3e, 0x03284f3e, 0x05d08f20, 0x05d08f20},
+ {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+ {0x0001690c, 0x08000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00016940, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+};
+
+static const u32 ar9300Modes_lowest_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x62480001, 0x62480001, 0x62480001, 0x62480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Modes_fast_clock_2p2[][3] = {
+ /* Addr 5G_HT20 5G_HT40 */
+ {0x00001030, 0x00000268, 0x000004d0},
+ {0x00001070, 0x0000018c, 0x00000318},
+ {0x000010b0, 0x00000fd0, 0x00001fa0},
+ {0x00008014, 0x044c044c, 0x08980898},
+ {0x0000801c, 0x148ec02b, 0x148ec057},
+ {0x00008318, 0x000044c0, 0x00008980},
+ {0x00009e00, 0x03721821, 0x03721821},
+ {0x0000a230, 0x0000000b, 0x00000016},
+ {0x0000a254, 0x00000898, 0x00001130},
+};
+
+static const u32 ar9300_2p2_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x7f80fff8},
+ {0x0001604c, 0x76d005b5},
+ {0x00016050, 0x556cf031},
+ {0x00016054, 0x13449440},
+ {0x00016058, 0x0c51c92c},
+ {0x0001605c, 0x3db7fffc},
+ {0x00016060, 0xfffffffc},
+ {0x00016064, 0x000f0278},
+ {0x0001606c, 0x6db60000},
+ {0x00016080, 0x00000000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x54214514},
+ {0x0001608c, 0x119f481e},
+ {0x00016090, 0x24926490},
+ {0x00016098, 0xd2888888},
+ {0x000160a0, 0x0a108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480080},
+ {0x000160c0, 0x00adb6d0},
+ {0x000160c4, 0x6db6db60},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x01e6c000},
+ {0x00016100, 0x3fffbe01},
+ {0x00016104, 0xfff80000},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x02084080},
+ {0x00016148, 0x00000000},
+ {0x00016280, 0x058a0001},
+ {0x00016284, 0x3d840208},
+ {0x00016288, 0x05a20408},
+ {0x0001628c, 0x00038c07},
+ {0x00016290, 0x00000004},
+ {0x00016294, 0x458aa14f},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x7f80fff8},
+ {0x0001644c, 0x76d005b5},
+ {0x00016450, 0x556cf031},
+ {0x00016454, 0x13449440},
+ {0x00016458, 0x0c51c92c},
+ {0x0001645c, 0x3db7fffc},
+ {0x00016460, 0xfffffffc},
+ {0x00016464, 0x000f0278},
+ {0x0001646c, 0x6db60000},
+ {0x00016500, 0x3fffbe01},
+ {0x00016504, 0xfff80000},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x02084080},
+ {0x00016548, 0x00000000},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db6db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x7f80fff8},
+ {0x0001684c, 0x76d005b5},
+ {0x00016850, 0x556cf031},
+ {0x00016854, 0x13449440},
+ {0x00016858, 0x0c51c92c},
+ {0x0001685c, 0x3db7fffc},
+ {0x00016860, 0xfffffffc},
+ {0x00016864, 0x000f0278},
+ {0x0001686c, 0x6db60000},
+ {0x00016900, 0x3fffbe01},
+ {0x00016904, 0xfff80000},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x02084080},
+ {0x00016948, 0x00000000},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
+
+static const u32 ar9300Common_rx_gain_table_merlin_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x02000101},
+ {0x0000a004, 0x02000102},
+ {0x0000a008, 0x02000103},
+ {0x0000a00c, 0x02000104},
+ {0x0000a010, 0x02000200},
+ {0x0000a014, 0x02000201},
+ {0x0000a018, 0x02000202},
+ {0x0000a01c, 0x02000203},
+ {0x0000a020, 0x02000204},
+ {0x0000a024, 0x02000205},
+ {0x0000a028, 0x02000208},
+ {0x0000a02c, 0x02000302},
+ {0x0000a030, 0x02000303},
+ {0x0000a034, 0x02000304},
+ {0x0000a038, 0x02000400},
+ {0x0000a03c, 0x02010300},
+ {0x0000a040, 0x02010301},
+ {0x0000a044, 0x02010302},
+ {0x0000a048, 0x02000500},
+ {0x0000a04c, 0x02010400},
+ {0x0000a050, 0x02020300},
+ {0x0000a054, 0x02020301},
+ {0x0000a058, 0x02020302},
+ {0x0000a05c, 0x02020303},
+ {0x0000a060, 0x02020400},
+ {0x0000a064, 0x02030300},
+ {0x0000a068, 0x02030301},
+ {0x0000a06c, 0x02030302},
+ {0x0000a070, 0x02030303},
+ {0x0000a074, 0x02030400},
+ {0x0000a078, 0x02040300},
+ {0x0000a07c, 0x02040301},
+ {0x0000a080, 0x02040302},
+ {0x0000a084, 0x02040303},
+ {0x0000a088, 0x02030500},
+ {0x0000a08c, 0x02040400},
+ {0x0000a090, 0x02050203},
+ {0x0000a094, 0x02050204},
+ {0x0000a098, 0x02050205},
+ {0x0000a09c, 0x02040500},
+ {0x0000a0a0, 0x02050301},
+ {0x0000a0a4, 0x02050302},
+ {0x0000a0a8, 0x02050303},
+ {0x0000a0ac, 0x02050400},
+ {0x0000a0b0, 0x02050401},
+ {0x0000a0b4, 0x02050402},
+ {0x0000a0b8, 0x02050403},
+ {0x0000a0bc, 0x02050500},
+ {0x0000a0c0, 0x02050501},
+ {0x0000a0c4, 0x02050502},
+ {0x0000a0c8, 0x02050503},
+ {0x0000a0cc, 0x02050504},
+ {0x0000a0d0, 0x02050600},
+ {0x0000a0d4, 0x02050601},
+ {0x0000a0d8, 0x02050602},
+ {0x0000a0dc, 0x02050603},
+ {0x0000a0e0, 0x02050604},
+ {0x0000a0e4, 0x02050700},
+ {0x0000a0e8, 0x02050701},
+ {0x0000a0ec, 0x02050702},
+ {0x0000a0f0, 0x02050703},
+ {0x0000a0f4, 0x02050704},
+ {0x0000a0f8, 0x02050705},
+ {0x0000a0fc, 0x02050708},
+ {0x0000a100, 0x02050709},
+ {0x0000a104, 0x0205070a},
+ {0x0000a108, 0x0205070b},
+ {0x0000a10c, 0x0205070c},
+ {0x0000a110, 0x0205070d},
+ {0x0000a114, 0x02050710},
+ {0x0000a118, 0x02050711},
+ {0x0000a11c, 0x02050712},
+ {0x0000a120, 0x02050713},
+ {0x0000a124, 0x02050714},
+ {0x0000a128, 0x02050715},
+ {0x0000a12c, 0x02050730},
+ {0x0000a130, 0x02050731},
+ {0x0000a134, 0x02050732},
+ {0x0000a138, 0x02050733},
+ {0x0000a13c, 0x02050734},
+ {0x0000a140, 0x02050735},
+ {0x0000a144, 0x02050750},
+ {0x0000a148, 0x02050751},
+ {0x0000a14c, 0x02050752},
+ {0x0000a150, 0x02050753},
+ {0x0000a154, 0x02050754},
+ {0x0000a158, 0x02050755},
+ {0x0000a15c, 0x02050770},
+ {0x0000a160, 0x02050771},
+ {0x0000a164, 0x02050772},
+ {0x0000a168, 0x02050773},
+ {0x0000a16c, 0x02050774},
+ {0x0000a170, 0x02050775},
+ {0x0000a174, 0x00000776},
+ {0x0000a178, 0x00000776},
+ {0x0000a17c, 0x00000776},
+ {0x0000a180, 0x00000776},
+ {0x0000a184, 0x00000776},
+ {0x0000a188, 0x00000776},
+ {0x0000a18c, 0x00000776},
+ {0x0000a190, 0x00000776},
+ {0x0000a194, 0x00000776},
+ {0x0000a198, 0x00000776},
+ {0x0000a19c, 0x00000776},
+ {0x0000a1a0, 0x00000776},
+ {0x0000a1a4, 0x00000776},
+ {0x0000a1a8, 0x00000776},
+ {0x0000a1ac, 0x00000776},
+ {0x0000a1b0, 0x00000776},
+ {0x0000a1b4, 0x00000776},
+ {0x0000a1b8, 0x00000776},
+ {0x0000a1bc, 0x00000776},
+ {0x0000a1c0, 0x00000776},
+ {0x0000a1c4, 0x00000776},
+ {0x0000a1c8, 0x00000776},
+ {0x0000a1cc, 0x00000776},
+ {0x0000a1d0, 0x00000776},
+ {0x0000a1d4, 0x00000776},
+ {0x0000a1d8, 0x00000776},
+ {0x0000a1dc, 0x00000776},
+ {0x0000a1e0, 0x00000776},
+ {0x0000a1e4, 0x00000776},
+ {0x0000a1e8, 0x00000776},
+ {0x0000a1ec, 0x00000776},
+ {0x0000a1f0, 0x00000776},
+ {0x0000a1f4, 0x00000776},
+ {0x0000a1f8, 0x00000776},
+ {0x0000a1fc, 0x00000776},
+ {0x0000b000, 0x02000101},
+ {0x0000b004, 0x02000102},
+ {0x0000b008, 0x02000103},
+ {0x0000b00c, 0x02000104},
+ {0x0000b010, 0x02000200},
+ {0x0000b014, 0x02000201},
+ {0x0000b018, 0x02000202},
+ {0x0000b01c, 0x02000203},
+ {0x0000b020, 0x02000204},
+ {0x0000b024, 0x02000205},
+ {0x0000b028, 0x02000208},
+ {0x0000b02c, 0x02000302},
+ {0x0000b030, 0x02000303},
+ {0x0000b034, 0x02000304},
+ {0x0000b038, 0x02000400},
+ {0x0000b03c, 0x02010300},
+ {0x0000b040, 0x02010301},
+ {0x0000b044, 0x02010302},
+ {0x0000b048, 0x02000500},
+ {0x0000b04c, 0x02010400},
+ {0x0000b050, 0x02020300},
+ {0x0000b054, 0x02020301},
+ {0x0000b058, 0x02020302},
+ {0x0000b05c, 0x02020303},
+ {0x0000b060, 0x02020400},
+ {0x0000b064, 0x02030300},
+ {0x0000b068, 0x02030301},
+ {0x0000b06c, 0x02030302},
+ {0x0000b070, 0x02030303},
+ {0x0000b074, 0x02030400},
+ {0x0000b078, 0x02040300},
+ {0x0000b07c, 0x02040301},
+ {0x0000b080, 0x02040302},
+ {0x0000b084, 0x02040303},
+ {0x0000b088, 0x02030500},
+ {0x0000b08c, 0x02040400},
+ {0x0000b090, 0x02050203},
+ {0x0000b094, 0x02050204},
+ {0x0000b098, 0x02050205},
+ {0x0000b09c, 0x02040500},
+ {0x0000b0a0, 0x02050301},
+ {0x0000b0a4, 0x02050302},
+ {0x0000b0a8, 0x02050303},
+ {0x0000b0ac, 0x02050400},
+ {0x0000b0b0, 0x02050401},
+ {0x0000b0b4, 0x02050402},
+ {0x0000b0b8, 0x02050403},
+ {0x0000b0bc, 0x02050500},
+ {0x0000b0c0, 0x02050501},
+ {0x0000b0c4, 0x02050502},
+ {0x0000b0c8, 0x02050503},
+ {0x0000b0cc, 0x02050504},
+ {0x0000b0d0, 0x02050600},
+ {0x0000b0d4, 0x02050601},
+ {0x0000b0d8, 0x02050602},
+ {0x0000b0dc, 0x02050603},
+ {0x0000b0e0, 0x02050604},
+ {0x0000b0e4, 0x02050700},
+ {0x0000b0e8, 0x02050701},
+ {0x0000b0ec, 0x02050702},
+ {0x0000b0f0, 0x02050703},
+ {0x0000b0f4, 0x02050704},
+ {0x0000b0f8, 0x02050705},
+ {0x0000b0fc, 0x02050708},
+ {0x0000b100, 0x02050709},
+ {0x0000b104, 0x0205070a},
+ {0x0000b108, 0x0205070b},
+ {0x0000b10c, 0x0205070c},
+ {0x0000b110, 0x0205070d},
+ {0x0000b114, 0x02050710},
+ {0x0000b118, 0x02050711},
+ {0x0000b11c, 0x02050712},
+ {0x0000b120, 0x02050713},
+ {0x0000b124, 0x02050714},
+ {0x0000b128, 0x02050715},
+ {0x0000b12c, 0x02050730},
+ {0x0000b130, 0x02050731},
+ {0x0000b134, 0x02050732},
+ {0x0000b138, 0x02050733},
+ {0x0000b13c, 0x02050734},
+ {0x0000b140, 0x02050735},
+ {0x0000b144, 0x02050750},
+ {0x0000b148, 0x02050751},
+ {0x0000b14c, 0x02050752},
+ {0x0000b150, 0x02050753},
+ {0x0000b154, 0x02050754},
+ {0x0000b158, 0x02050755},
+ {0x0000b15c, 0x02050770},
+ {0x0000b160, 0x02050771},
+ {0x0000b164, 0x02050772},
+ {0x0000b168, 0x02050773},
+ {0x0000b16c, 0x02050774},
+ {0x0000b170, 0x02050775},
+ {0x0000b174, 0x00000776},
+ {0x0000b178, 0x00000776},
+ {0x0000b17c, 0x00000776},
+ {0x0000b180, 0x00000776},
+ {0x0000b184, 0x00000776},
+ {0x0000b188, 0x00000776},
+ {0x0000b18c, 0x00000776},
+ {0x0000b190, 0x00000776},
+ {0x0000b194, 0x00000776},
+ {0x0000b198, 0x00000776},
+ {0x0000b19c, 0x00000776},
+ {0x0000b1a0, 0x00000776},
+ {0x0000b1a4, 0x00000776},
+ {0x0000b1a8, 0x00000776},
+ {0x0000b1ac, 0x00000776},
+ {0x0000b1b0, 0x00000776},
+ {0x0000b1b4, 0x00000776},
+ {0x0000b1b8, 0x00000776},
+ {0x0000b1bc, 0x00000776},
+ {0x0000b1c0, 0x00000776},
+ {0x0000b1c4, 0x00000776},
+ {0x0000b1c8, 0x00000776},
+ {0x0000b1cc, 0x00000776},
+ {0x0000b1d0, 0x00000776},
+ {0x0000b1d4, 0x00000776},
+ {0x0000b1d8, 0x00000776},
+ {0x0000b1dc, 0x00000776},
+ {0x0000b1e0, 0x00000776},
+ {0x0000b1e4, 0x00000776},
+ {0x0000b1e8, 0x00000776},
+ {0x0000b1ec, 0x00000776},
+ {0x0000b1f0, 0x00000776},
+ {0x0000b1f4, 0x00000776},
+ {0x0000b1f8, 0x00000776},
+ {0x0000b1fc, 0x00000776},
+};
+
+static const u32 ar9300_2p2_mac_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+ {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+ {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+ {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+ {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+ {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+ {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+ {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
+
+static const u32 ar9300_2p2_soc_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023},
+};
+
+static const u32 ar9200_merlin_2p2_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00007800, 0x00040000},
+ {0x00007804, 0xdb005012},
+ {0x00007808, 0x04924914},
+ {0x0000780c, 0x21084210},
+ {0x00007810, 0x6d801300},
+ {0x00007814, 0x0019beff},
+ {0x00007818, 0x07e41000},
+ {0x0000781c, 0x00392000},
+ {0x00007820, 0x92592480},
+ {0x00007824, 0x00040000},
+ {0x00007828, 0xdb005012},
+ {0x0000782c, 0x04924914},
+ {0x00007830, 0x21084210},
+ {0x00007834, 0x6d801300},
+ {0x00007838, 0x0019beff},
+ {0x0000783c, 0x07e40000},
+ {0x00007840, 0x00392000},
+ {0x00007844, 0x92592480},
+ {0x00007848, 0x00100000},
+ {0x0000784c, 0x773f0567},
+ {0x00007850, 0x54214514},
+ {0x00007854, 0x12035828},
+ {0x00007858, 0x92592692},
+ {0x0000785c, 0x00000000},
+ {0x00007860, 0x56400000},
+ {0x00007864, 0x0a8e370e},
+ {0x00007868, 0xc0102850},
+ {0x0000786c, 0x812d4000},
+ {0x00007870, 0x807ec400},
+ {0x00007874, 0x001b6db0},
+ {0x00007878, 0x00376b63},
+ {0x0000787c, 0x06db6db6},
+ {0x00007880, 0x006d8000},
+ {0x00007884, 0xffeffffe},
+ {0x00007888, 0xffeffffe},
+ {0x0000788c, 0x00010000},
+ {0x00007890, 0x02060aeb},
+ {0x00007894, 0x5a108000},
+};
+
+static const u32 ar9300_2p2_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+ {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+ {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x00802020, 0x00802020, 0x00802020, 0x00802020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+ {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
+ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+ {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x000037c0, 0x000037c4, 0x000037c4, 0x000037c0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+ {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+ {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018},
+ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e},
+ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+ {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+ {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+ {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982},
+ {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
+ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+ {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be04, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+ {0x0000c284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
+};
+
+static const u32 ar9300_2p2_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0x9280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x5f3ca3de},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x14750600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x52440bbe},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009c04, 0xff55ff55},
+ {0x00009c08, 0x0320ff55},
+ {0x00009c0c, 0x00000000},
+ {0x00009c10, 0x00000000},
+ {0x00009c14, 0x00046384},
+ {0x00009c18, 0x05b6b440},
+ {0x00009c1c, 0x00b6b440},
+ {0x00009d00, 0xc080a333},
+ {0x00009d04, 0x40206c10},
+ {0x00009d08, 0x009c4060},
+ {0x00009d0c, 0x9883800a},
+ {0x00009d10, 0x01834061},
+ {0x00009d14, 0x00c0040b},
+ {0x00009d18, 0x00000000},
+ {0x00009e08, 0x0038230c},
+ {0x00009e24, 0x990bb515},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e3c, 0xcf946222},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009e54, 0x00000000},
+ {0x00009fc0, 0x803e4788},
+ {0x00009fc4, 0x0001efb5},
+ {0x00009fcc, 0x40000014},
+ {0x00009fd0, 0x01193b93},
+ {0x0000a20c, 0x00000000},
+ {0x0000a220, 0x00000000},
+ {0x0000a224, 0x00000000},
+ {0x0000a228, 0x10002310},
+ {0x0000a22c, 0x01036a1e},
+ {0x0000a23c, 0x00000000},
+ {0x0000a244, 0x0c000000},
+ {0x0000a2a0, 0x00000001},
+ {0x0000a2c0, 0x00000001},
+ {0x0000a2c8, 0x00000000},
+ {0x0000a2cc, 0x18c43433},
+ {0x0000a2d4, 0x00000000},
+ {0x0000a2dc, 0x00000000},
+ {0x0000a2e0, 0x00000000},
+ {0x0000a2e4, 0x00000000},
+ {0x0000a2e8, 0x00000000},
+ {0x0000a2ec, 0x00000000},
+ {0x0000a2f0, 0x00000000},
+ {0x0000a2f4, 0x00000000},
+ {0x0000a2f8, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a34c, 0x00000000},
+ {0x0000a350, 0x0000a000},
+ {0x0000a364, 0x00000000},
+ {0x0000a370, 0x00000000},
+ {0x0000a390, 0x00000001},
+ {0x0000a394, 0x00000444},
+ {0x0000a398, 0x001f0e0f},
+ {0x0000a39c, 0x0075393f},
+ {0x0000a3a0, 0xb79f6427},
+ {0x0000a3a4, 0x00000000},
+ {0x0000a3a8, 0xaaaaaaaa},
+ {0x0000a3ac, 0x3c466478},
+ {0x0000a3c0, 0x20202020},
+ {0x0000a3c4, 0x22222220},
+ {0x0000a3c8, 0x20200020},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3d8, 0x20202020},
+ {0x0000a3dc, 0x20202020},
+ {0x0000a3e0, 0x20202020},
+ {0x0000a3e4, 0x20202020},
+ {0x0000a3e8, 0x20202020},
+ {0x0000a3ec, 0x20202020},
+ {0x0000a3f0, 0x00000000},
+ {0x0000a3f4, 0x00000246},
+ {0x0000a3f8, 0x0cdbd380},
+ {0x0000a3fc, 0x000f0f01},
+ {0x0000a400, 0x8fa91f01},
+ {0x0000a404, 0x00000000},
+ {0x0000a408, 0x0e79e5c6},
+ {0x0000a40c, 0x00820820},
+ {0x0000a414, 0x1ce739ce},
+ {0x0000a418, 0x2d001dce},
+ {0x0000a41c, 0x1ce739ce},
+ {0x0000a420, 0x000001ce},
+ {0x0000a424, 0x1ce739ce},
+ {0x0000a428, 0x000001ce},
+ {0x0000a42c, 0x1ce739ce},
+ {0x0000a430, 0x1ce739ce},
+ {0x0000a434, 0x00000000},
+ {0x0000a438, 0x00001801},
+ {0x0000a43c, 0x00000000},
+ {0x0000a440, 0x00000000},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x06000080},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a458, 0x00000000},
+ {0x0000a600, 0x00000000},
+ {0x0000a604, 0x00000000},
+ {0x0000a608, 0x00000000},
+ {0x0000a60c, 0x00000000},
+ {0x0000a610, 0x00000000},
+ {0x0000a614, 0x00000000},
+ {0x0000a618, 0x00000000},
+ {0x0000a61c, 0x00000000},
+ {0x0000a620, 0x00000000},
+ {0x0000a624, 0x00000000},
+ {0x0000a628, 0x00000000},
+ {0x0000a62c, 0x00000000},
+ {0x0000a630, 0x00000000},
+ {0x0000a634, 0x00000000},
+ {0x0000a638, 0x00000000},
+ {0x0000a63c, 0x00000000},
+ {0x0000a640, 0x00000000},
+ {0x0000a644, 0x3fad9d74},
+ {0x0000a648, 0x0048060a},
+ {0x0000a64c, 0x00000637},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x09080504},
+ {0x0000a678, 0x0d0c0b0a},
+ {0x0000a67c, 0x13121110},
+ {0x0000a680, 0x31301514},
+ {0x0000a684, 0x35343332},
+ {0x0000a688, 0x00000036},
+ {0x0000a690, 0x00000838},
+ {0x0000a7c0, 0x00000000},
+ {0x0000a7c4, 0xfffffffc},
+ {0x0000a7c8, 0x00000000},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000001},
+ {0x0000a8d0, 0x004b6a8e},
+ {0x0000a8d4, 0x00000820},
+ {0x0000a8dc, 0x00000000},
+ {0x0000a8f0, 0x00000000},
+ {0x0000a8f4, 0x00000000},
+ {0x0000b2d0, 0x00000080},
+ {0x0000b2d4, 0x00000000},
+ {0x0000b2dc, 0x00000000},
+ {0x0000b2e0, 0x00000000},
+ {0x0000b2e4, 0x00000000},
+ {0x0000b2e8, 0x00000000},
+ {0x0000b2ec, 0x00000000},
+ {0x0000b2f0, 0x00000000},
+ {0x0000b2f4, 0x00000000},
+ {0x0000b2f8, 0x00000000},
+ {0x0000b408, 0x0e79e5c0},
+ {0x0000b40c, 0x00820820},
+ {0x0000b420, 0x00000000},
+ {0x0000b8d0, 0x004b6a8e},
+ {0x0000b8d4, 0x00000820},
+ {0x0000b8dc, 0x00000000},
+ {0x0000b8f0, 0x00000000},
+ {0x0000b8f4, 0x00000000},
+ {0x0000c2d0, 0x00000080},
+ {0x0000c2d4, 0x00000000},
+ {0x0000c2dc, 0x00000000},
+ {0x0000c2e0, 0x00000000},
+ {0x0000c2e4, 0x00000000},
+ {0x0000c2e8, 0x00000000},
+ {0x0000c2ec, 0x00000000},
+ {0x0000c2f0, 0x00000000},
+ {0x0000c2f4, 0x00000000},
+ {0x0000c2f8, 0x00000000},
+ {0x0000c408, 0x0e79e5c0},
+ {0x0000c40c, 0x00820820},
+ {0x0000c420, 0x00000000},
+};
+
+static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+ {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
+ {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x00016044, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016048, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016068, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ {0x00016444, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016448, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016468, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+ {0x00016844, 0x056db2e6, 0x056db2e6, 0x056db2e6, 0x056db2e6},
+ {0x00016848, 0xae480001, 0xae480001, 0xae480001, 0xae480001},
+ {0x00016868, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c, 0x6eb6db6c},
+};
+
+static const u32 ar9300Modes_high_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06002223, 0x06002223, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a022220, 0x0a022220, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x0f022223, 0x0f022223, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x14022620, 0x14022620, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x18022622, 0x18022622, 0x11000400, 0x11000400},
+ {0x0000a518, 0x1b022822, 0x1b022822, 0x15000402, 0x15000402},
+ {0x0000a51c, 0x20022842, 0x20022842, 0x19000404, 0x19000404},
+ {0x0000a520, 0x22022c41, 0x22022c41, 0x1b000603, 0x1b000603},
+ {0x0000a524, 0x28023042, 0x28023042, 0x1f000a02, 0x1f000a02},
+ {0x0000a528, 0x2c023044, 0x2c023044, 0x23000a04, 0x23000a04},
+ {0x0000a52c, 0x2f023644, 0x2f023644, 0x26000a20, 0x26000a20},
+ {0x0000a530, 0x34025643, 0x34025643, 0x2a000e20, 0x2a000e20},
+ {0x0000a534, 0x38025a44, 0x38025a44, 0x2e000e22, 0x2e000e22},
+ {0x0000a538, 0x3b025e45, 0x3b025e45, 0x31000e24, 0x31000e24},
+ {0x0000a53c, 0x41025e4a, 0x41025e4a, 0x34001640, 0x34001640},
+ {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
+ {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
+ {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
+ {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83},
+ {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+ {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
+ {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
+ {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
+ {0x0000a560, 0x70049f56, 0x70049f56, 0x54001ceb, 0x54001ceb},
+ {0x0000a564, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a568, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a56c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a570, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a574, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a578, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a57c, 0x7504ff56, 0x7504ff56, 0x56001eec, 0x56001eec},
+ {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06802223, 0x06802223, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a822220, 0x0a822220, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x0f822223, 0x0f822223, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x14822620, 0x14822620, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x18822622, 0x18822622, 0x11800400, 0x11800400},
+ {0x0000a598, 0x1b822822, 0x1b822822, 0x15800402, 0x15800402},
+ {0x0000a59c, 0x20822842, 0x20822842, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x22822c41, 0x22822c41, 0x1b800603, 0x1b800603},
+ {0x0000a5a4, 0x28823042, 0x28823042, 0x1f800a02, 0x1f800a02},
+ {0x0000a5a8, 0x2c823044, 0x2c823044, 0x23800a04, 0x23800a04},
+ {0x0000a5ac, 0x2f823644, 0x2f823644, 0x26800a20, 0x26800a20},
+ {0x0000a5b0, 0x34825643, 0x34825643, 0x2a800e20, 0x2a800e20},
+ {0x0000a5b4, 0x38825a44, 0x38825a44, 0x2e800e22, 0x2e800e22},
+ {0x0000a5b8, 0x3b825e45, 0x3b825e45, 0x31800e24, 0x31800e24},
+ {0x0000a5bc, 0x41825e4a, 0x41825e4a, 0x34801640, 0x34801640},
+ {0x0000a5c0, 0x48825e6c, 0x48825e6c, 0x38801660, 0x38801660},
+ {0x0000a5c4, 0x4e825e8e, 0x4e825e8e, 0x3b801861, 0x3b801861},
+ {0x0000a5c8, 0x53825eb2, 0x53825eb2, 0x3e801a81, 0x3e801a81},
+ {0x0000a5cc, 0x59825eb5, 0x59825eb5, 0x42801a83, 0x42801a83},
+ {0x0000a5d0, 0x5f825ef6, 0x5f825ef6, 0x44801c84, 0x44801c84},
+ {0x0000a5d4, 0x62825f56, 0x62825f56, 0x48801ce3, 0x48801ce3},
+ {0x0000a5d8, 0x66827f56, 0x66827f56, 0x4c801ce5, 0x4c801ce5},
+ {0x0000a5dc, 0x6a829f56, 0x6a829f56, 0x50801ce9, 0x50801ce9},
+ {0x0000a5e0, 0x70849f56, 0x70849f56, 0x54801ceb, 0x54801ceb},
+ {0x0000a5e4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5e8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5ec, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f0, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f4, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5f8, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x0000a5fc, 0x7584ff56, 0x7584ff56, 0x56801eec, 0x56801eec},
+ {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4},
+ {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300Common_rx_gain_table_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x01910190},
+ {0x0000a030, 0x01930192},
+ {0x0000a034, 0x01950194},
+ {0x0000a038, 0x038a0196},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x22222229},
+ {0x0000a084, 0x1d1d1d1d},
+ {0x0000a088, 0x1d1d1d1d},
+ {0x0000a08c, 0x1d1d1d1d},
+ {0x0000a090, 0x171d1d1d},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x32323232},
+ {0x0000b084, 0x2f2f3232},
+ {0x0000b088, 0x23282a2d},
+ {0x0000b08c, 0x1c1e2123},
+ {0x0000b090, 0x14171919},
+ {0x0000b094, 0x0e0e1214},
+ {0x0000b098, 0x03050707},
+ {0x0000b09c, 0x00030303},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300Modes_low_ob_db_tx_gain_table_2p2[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
+ {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
+ {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
+ {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec},
+ {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
+ {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
+ {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
+ {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec},
+ {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+ {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
+ {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
+ {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
+};
+
+static const u32 ar9300_2p2_mac_core[][2] = {
+ /* Addr allmodes */
+ {0x00000008, 0x00000000},
+ {0x00000030, 0x00020085},
+ {0x00000034, 0x00000005},
+ {0x00000040, 0x00000000},
+ {0x00000044, 0x00000000},
+ {0x00000048, 0x00000008},
+ {0x0000004c, 0x00000010},
+ {0x00000050, 0x00000000},
+ {0x00001040, 0x002ffc0f},
+ {0x00001044, 0x002ffc0f},
+ {0x00001048, 0x002ffc0f},
+ {0x0000104c, 0x002ffc0f},
+ {0x00001050, 0x002ffc0f},
+ {0x00001054, 0x002ffc0f},
+ {0x00001058, 0x002ffc0f},
+ {0x0000105c, 0x002ffc0f},
+ {0x00001060, 0x002ffc0f},
+ {0x00001064, 0x002ffc0f},
+ {0x000010f0, 0x00000100},
+ {0x00001270, 0x00000000},
+ {0x000012b0, 0x00000000},
+ {0x000012f0, 0x00000000},
+ {0x0000143c, 0x00000000},
+ {0x0000147c, 0x00000000},
+ {0x00008000, 0x00000000},
+ {0x00008004, 0x00000000},
+ {0x00008008, 0x00000000},
+ {0x0000800c, 0x00000000},
+ {0x00008018, 0x00000000},
+ {0x00008020, 0x00000000},
+ {0x00008038, 0x00000000},
+ {0x0000803c, 0x00000000},
+ {0x00008040, 0x00000000},
+ {0x00008044, 0x00000000},
+ {0x00008048, 0x00000000},
+ {0x0000804c, 0xffffffff},
+ {0x00008054, 0x00000000},
+ {0x00008058, 0x00000000},
+ {0x0000805c, 0x000fc78f},
+ {0x00008060, 0x0000000f},
+ {0x00008064, 0x00000000},
+ {0x00008070, 0x00000310},
+ {0x00008074, 0x00000020},
+ {0x00008078, 0x00000000},
+ {0x0000809c, 0x0000000f},
+ {0x000080a0, 0x00000000},
+ {0x000080a4, 0x02ff0000},
+ {0x000080a8, 0x0e070605},
+ {0x000080ac, 0x0000000d},
+ {0x000080b0, 0x00000000},
+ {0x000080b4, 0x00000000},
+ {0x000080b8, 0x00000000},
+ {0x000080bc, 0x00000000},
+ {0x000080c0, 0x2a800000},
+ {0x000080c4, 0x06900168},
+ {0x000080c8, 0x13881c20},
+ {0x000080cc, 0x01f40000},
+ {0x000080d0, 0x00252500},
+ {0x000080d4, 0x00a00000},
+ {0x000080d8, 0x00400000},
+ {0x000080dc, 0x00000000},
+ {0x000080e0, 0xffffffff},
+ {0x000080e4, 0x0000ffff},
+ {0x000080e8, 0x3f3f3f3f},
+ {0x000080ec, 0x00000000},
+ {0x000080f0, 0x00000000},
+ {0x000080f4, 0x00000000},
+ {0x000080fc, 0x00020000},
+ {0x00008100, 0x00000000},
+ {0x00008108, 0x00000052},
+ {0x0000810c, 0x00000000},
+ {0x00008110, 0x00000000},
+ {0x00008114, 0x000007ff},
+ {0x00008118, 0x000000aa},
+ {0x0000811c, 0x00003210},
+ {0x00008124, 0x00000000},
+ {0x00008128, 0x00000000},
+ {0x0000812c, 0x00000000},
+ {0x00008130, 0x00000000},
+ {0x00008134, 0x00000000},
+ {0x00008138, 0x00000000},
+ {0x0000813c, 0x0000ffff},
+ {0x00008144, 0xffffffff},
+ {0x00008168, 0x00000000},
+ {0x0000816c, 0x00000000},
+ {0x00008170, 0x18486200},
+ {0x00008174, 0x33332210},
+ {0x00008178, 0x00000000},
+ {0x0000817c, 0x00020000},
+ {0x000081c0, 0x00000000},
+ {0x000081c4, 0x33332210},
+ {0x000081c8, 0x00000000},
+ {0x000081cc, 0x00000000},
+ {0x000081d4, 0x00000000},
+ {0x000081ec, 0x00000000},
+ {0x000081f0, 0x00000000},
+ {0x000081f4, 0x00000000},
+ {0x000081f8, 0x00000000},
+ {0x000081fc, 0x00000000},
+ {0x00008240, 0x00100000},
+ {0x00008244, 0x0010f424},
+ {0x00008248, 0x00000800},
+ {0x0000824c, 0x0001e848},
+ {0x00008250, 0x00000000},
+ {0x00008254, 0x00000000},
+ {0x00008258, 0x00000000},
+ {0x0000825c, 0x40000000},
+ {0x00008260, 0x00080922},
+ {0x00008264, 0x9bc00010},
+ {0x00008268, 0xffffffff},
+ {0x0000826c, 0x0000ffff},
+ {0x00008270, 0x00000000},
+ {0x00008274, 0x40000000},
+ {0x00008278, 0x003e4180},
+ {0x0000827c, 0x00000004},
+ {0x00008284, 0x0000002c},
+ {0x00008288, 0x0000002c},
+ {0x0000828c, 0x000000ff},
+ {0x00008294, 0x00000000},
+ {0x00008298, 0x00000000},
+ {0x0000829c, 0x00000000},
+ {0x00008300, 0x00000140},
+ {0x00008314, 0x00000000},
+ {0x0000831c, 0x0000010d},
+ {0x00008328, 0x00000000},
+ {0x0000832c, 0x00000007},
+ {0x00008330, 0x00000302},
+ {0x00008334, 0x00000700},
+ {0x00008338, 0x00ff0000},
+ {0x0000833c, 0x02400000},
+ {0x00008340, 0x000107ff},
+ {0x00008344, 0xaa48105b},
+ {0x00008348, 0x008f0000},
+ {0x0000835c, 0x00000000},
+ {0x00008360, 0xffffffff},
+ {0x00008364, 0xffffffff},
+ {0x00008368, 0x00000000},
+ {0x00008370, 0x00000000},
+ {0x00008374, 0x000000ff},
+ {0x00008378, 0x00000000},
+ {0x0000837c, 0x00000000},
+ {0x00008380, 0xffffffff},
+ {0x00008384, 0xffffffff},
+ {0x00008390, 0xffffffff},
+ {0x00008394, 0xffffffff},
+ {0x00008398, 0x00000000},
+ {0x0000839c, 0x00000000},
+ {0x000083a0, 0x00000000},
+ {0x000083a4, 0x0000fa14},
+ {0x000083a8, 0x000f0c00},
+ {0x000083ac, 0x33332210},
+ {0x000083b0, 0x33332210},
+ {0x000083b4, 0x33332210},
+ {0x000083b8, 0x33332210},
+ {0x000083bc, 0x00000000},
+ {0x000083c0, 0x00000000},
+ {0x000083c4, 0x00000000},
+ {0x000083c8, 0x00000000},
+ {0x000083cc, 0x00000200},
+ {0x000083d0, 0x000301ff},
+};
+
+static const u32 ar9300Common_wo_xlna_rx_gain_table_2p2[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x03820190},
+ {0x0000a030, 0x03840383},
+ {0x0000a034, 0x03880385},
+ {0x0000a038, 0x038a0389},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x29292929},
+ {0x0000a084, 0x29292929},
+ {0x0000a088, 0x29292929},
+ {0x0000a08c, 0x29292929},
+ {0x0000a090, 0x22292929},
+ {0x0000a094, 0x1d1d2222},
+ {0x0000a098, 0x0c111117},
+ {0x0000a09c, 0x00030303},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x32323232},
+ {0x0000b084, 0x2f2f3232},
+ {0x0000b088, 0x23282a2d},
+ {0x0000b08c, 0x1c1e2123},
+ {0x0000b090, 0x14171919},
+ {0x0000b094, 0x0e0e1214},
+ {0x0000b098, 0x03050707},
+ {0x0000b09c, 0x00030303},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 ar9300_2p2_soc_preamble[][2] = {
+ /* Addr allmodes */
+ {0x000040a4, 0x00a0c1c9},
+ {0x00007008, 0x00000000},
+ {0x00007020, 0x00000000},
+ {0x00007034, 0x00000002},
+ {0x00007038, 0x000004c2},
+ {0x00007048, 0x00000008},
+};
+
+static const u32 ar9300PciePhy_pll_on_clkreq_disable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08212e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_enable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08253e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+static const u32 ar9300PciePhy_clkreq_disable_L1_2p2[][2] = {
+ /* Addr allmodes */
+ {0x00004040, 0x08213e5e},
+ {0x00004040, 0x0008003b},
+ {0x00004044, 0x00000000},
+};
+
+#endif /* INITVALS_9003_2P2_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 56a9e5fa6d66..5a0650399136 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -739,6 +739,12 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
*/
ar9003_hw_set_chain_masks(ah, 0x7, 0x7);
+ /* Do Tx IQ Calibration */
+ ar9003_hw_tx_iq_cal(ah);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+ udelay(5);
+ REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
/* Calibrate the AGC */
REG_WRITE(ah, AR_PHY_AGC_CONTROL,
REG_READ(ah, AR_PHY_AGC_CONTROL) |
@@ -753,10 +759,6 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
return false;
}
- /* Do Tx IQ Calibration */
- if (ah->config.tx_iq_calibration)
- ar9003_hw_tx_iq_cal(ah);
-
/* Revert chainmasks to their original values before NF cal */
ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index b15309caf1da..863f61e3a16f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -16,7 +16,8 @@
#include "hw.h"
#include "ar9003_mac.h"
-#include "ar9003_initvals.h"
+#include "ar9003_2p0_initvals.h"
+#include "ar9003_2p2_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -31,12 +32,8 @@ static bool ar9003_hw_macversion_supported(u32 macversion)
return false;
}
-/* AR9003 2.0 - new INI format (pre, core, post arrays per subsystem) */
-/*
- * XXX: move TX/RX gain INI to its own init_mode_gain_regs after
- * ensuring it does not affect hardware bring up
- */
-static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+/* AR9003 2.0 */
+static void ar9003_2p0_hw_init_mode_regs(struct ath_hw *ah)
{
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
@@ -106,27 +103,128 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
3);
}
+/* AR9003 2.2 */
+static void ar9003_2p2_hw_init_mode_regs(struct ath_hw *ah)
+{
+ /* mac */
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ ar9300_2p2_mac_core,
+ ARRAY_SIZE(ar9300_2p2_mac_core), 2);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ ar9300_2p2_mac_postamble,
+ ARRAY_SIZE(ar9300_2p2_mac_postamble), 5);
+
+ /* bb */
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ ar9300_2p2_baseband_core,
+ ARRAY_SIZE(ar9300_2p2_baseband_core), 2);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ ar9300_2p2_baseband_postamble,
+ ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5);
+
+ /* radio */
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ ar9300_2p2_radio_core,
+ ARRAY_SIZE(ar9300_2p2_radio_core), 2);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ ar9300_2p2_radio_postamble,
+ ARRAY_SIZE(ar9300_2p2_radio_postamble), 5);
+
+ /* soc */
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ ar9300_2p2_soc_preamble,
+ ARRAY_SIZE(ar9300_2p2_soc_preamble), 2);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ ar9300_2p2_soc_postamble,
+ ARRAY_SIZE(ar9300_2p2_soc_postamble), 5);
+
+ /* rx/tx gain */
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
+
+ /* Load PCIE SERDES settings from INI */
+
+ /* Awake Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdes,
+ ar9300PciePhy_pll_on_clkreq_disable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2),
+ 2);
+
+ /* Sleep Setting */
+
+ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower,
+ ar9300PciePhy_clkreq_enable_L1_2p2,
+ ARRAY_SIZE(ar9300PciePhy_clkreq_enable_L1_2p2),
+ 2);
+
+ /* Fast clock modal settings */
+ INIT_INI_ARRAY(&ah->iniModesAdditional,
+ ar9300Modes_fast_clock_2p2,
+ ARRAY_SIZE(ar9300Modes_fast_clock_2p2),
+ 3);
+}
+
+/*
+ * The AR9003 family uses a new INI format (pre, core, post
+ * arrays per subsystem).
+ */
+static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
+{
+ if (AR_SREV_9300_20(ah))
+ ar9003_2p0_hw_init_mode_regs(ah);
+ else
+ ar9003_2p2_hw_init_mode_regs(ah);
+}
+
static void ar9003_tx_gain_table_apply(struct ath_hw *ah)
{
switch (ar9003_hw_get_tx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_lowest_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_high_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_high_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2),
+ 5);
break;
case 2:
- INIT_INI_ARRAY(&ah->iniModesTxGain,
- ar9300Modes_low_ob_db_tx_gain_table_2p0,
- ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
- 5);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p0),
+ 5);
+ else
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ ar9300Modes_low_ob_db_tx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2),
+ 5);
break;
}
}
@@ -136,15 +234,28 @@ static void ar9003_rx_gain_table_apply(struct ath_hw *ah)
switch (ar9003_hw_get_rx_gain_idx(ah)) {
case 0:
default:
- INIT_INI_ARRAY(&ah->iniModesRxGain, ar9300Common_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
- 2);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_rx_gain_table_2p2),
+ 2);
break;
case 1:
- INIT_INI_ARRAY(&ah->iniModesRxGain,
- ar9300Common_wo_xlna_rx_gain_table_2p0,
- ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
- 2);
+ if (AR_SREV_9300_20(ah))
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p0,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p0),
+ 2);
+ else
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ ar9300Common_wo_xlna_rx_gain_table_2p2,
+ ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2),
+ 2);
break;
}
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index 37ba37481a47..40731077cbb4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -90,6 +90,8 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
MAP_ISR_S2_CST);
mask2 |= ((isr2 & AR_ISR_S2_TSFOOR) >>
MAP_ISR_S2_TSFOOR);
+ mask2 |= ((isr2 & AR_ISR_S2_BB_WATCHDOG) >>
+ MAP_ISR_S2_BB_WATCHDOG);
if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
REG_WRITE(ah, AR_ISR_S2, isr2);
@@ -167,6 +169,9 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
(void) REG_READ(ah, AR_ISR);
}
+
+ if (*masked & ATH9K_INT_BB_WATCHDOG)
+ ar9003_hw_bb_watchdog_read(ah);
}
if (sync_cause) {
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.h b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
index f17558b14539..5a7a286e2773 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.h
@@ -47,6 +47,7 @@
#define MAP_ISR_S2_DTIMSYNC 7
#define MAP_ISR_S2_DTIM 7
#define MAP_ISR_S2_TSFOOR 4
+#define MAP_ISR_S2_BB_WATCHDOG 6
#define AR9003TXC_CONST(_ds) ((const struct ar9003_txc *) _ds)
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index 80431a2f6dc1..c714579b5483 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1132,3 +1132,122 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->do_getnf = ar9003_hw_do_getnf;
priv_ops->loadnf = ar9003_hw_loadnf;
}
+
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 idle_tmo_ms = ah->bb_watchdog_timeout_ms;
+ u32 val, idle_count;
+
+ if (!idle_tmo_ms) {
+ /* disable IRQ, disable chip-reset for BB panic */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) &
+ ~(AR_PHY_WATCHDOG_RST_ENABLE |
+ AR_PHY_WATCHDOG_IRQ_ENABLE));
+
+ /* disable watchdog in non-IDLE mode, disable in IDLE mode */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_1) &
+ ~(AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+ AR_PHY_WATCHDOG_IDLE_ENABLE));
+
+ ath_print(common, ATH_DBG_RESET, "Disabled BB Watchdog\n");
+ return;
+ }
+
+ /* enable IRQ, disable chip-reset for BB watchdog */
+ val = REG_READ(ah, AR_PHY_WATCHDOG_CTL_2) & AR_PHY_WATCHDOG_CNTL2_MASK;
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_2,
+ (val | AR_PHY_WATCHDOG_IRQ_ENABLE) &
+ ~AR_PHY_WATCHDOG_RST_ENABLE);
+
+ /* bound limit to 10 secs */
+ if (idle_tmo_ms > 10000)
+ idle_tmo_ms = 10000;
+
+ /*
+ * The time unit for watchdog event is 2^15 44/88MHz cycles.
+ *
+ * For HT20 we have a time unit of 2^15/44 MHz = .74 ms per tick
+ * For HT40 we have a time unit of 2^15/88 MHz = .37 ms per tick
+ *
+ * Given we use fast clock now in 5 GHz, these time units should
+ * be common for both 2 GHz and 5 GHz.
+ */
+ idle_count = (100 * idle_tmo_ms) / 74;
+ if (ah->curchan && IS_CHAN_HT40(ah->curchan))
+ idle_count = (100 * idle_tmo_ms) / 37;
+
+ /*
+ * enable watchdog in non-IDLE mode, disable in IDLE mode,
+ * set idle time-out.
+ */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_CTL_1,
+ AR_PHY_WATCHDOG_NON_IDLE_ENABLE |
+ AR_PHY_WATCHDOG_IDLE_MASK |
+ (AR_PHY_WATCHDOG_NON_IDLE_MASK & (idle_count << 2)));
+
+ ath_print(common, ATH_DBG_RESET,
+ "Enabled BB Watchdog timeout (%u ms)\n",
+ idle_tmo_ms);
+}
+
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah)
+{
+ /*
+ * we want to avoid printing in ISR context so we save the
+ * watchdog status to be printed later in bottom half context.
+ */
+ ah->bb_watchdog_last_status = REG_READ(ah, AR_PHY_WATCHDOG_STATUS);
+
+ /*
+ * the watchdog timer should reset on status read but to be sure
+ * sure we write 0 to the watchdog status bit.
+ */
+ REG_WRITE(ah, AR_PHY_WATCHDOG_STATUS,
+ ah->bb_watchdog_last_status & ~AR_PHY_WATCHDOG_STATUS_CLR);
+}
+
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ u32 rxc_pcnt = 0, rxf_pcnt = 0, txf_pcnt = 0, status;
+
+ if (likely(!(common->debug_mask & ATH_DBG_RESET)))
+ return;
+
+ status = ah->bb_watchdog_last_status;
+ ath_print(common, ATH_DBG_RESET,
+ "\n==== BB update: BB status=0x%08x ====\n", status);
+ ath_print(common, ATH_DBG_RESET,
+ "** BB state: wd=%u det=%u rdar=%u rOFDM=%d "
+ "rCCK=%u tOFDM=%u tCCK=%u agc=%u src=%u **\n",
+ MS(status, AR_PHY_WATCHDOG_INFO),
+ MS(status, AR_PHY_WATCHDOG_DET_HANG),
+ MS(status, AR_PHY_WATCHDOG_RADAR_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_RX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_OFDM_SM),
+ MS(status, AR_PHY_WATCHDOG_TX_CCK_SM),
+ MS(status, AR_PHY_WATCHDOG_AGC_SM),
+ MS(status,AR_PHY_WATCHDOG_SRCH_SM));
+
+ ath_print(common, ATH_DBG_RESET,
+ "** BB WD cntl: cntl1=0x%08x cntl2=0x%08x **\n",
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_1),
+ REG_READ(ah, AR_PHY_WATCHDOG_CTL_2));
+ ath_print(common, ATH_DBG_RESET,
+ "** BB mode: BB_gen_controls=0x%08x **\n",
+ REG_READ(ah, AR_PHY_GEN_CTRL));
+
+ if (ath9k_hw_GetMibCycleCountsPct(ah, &rxc_pcnt, &rxf_pcnt, &txf_pcnt))
+ ath_print(common, ATH_DBG_RESET,
+ "** BB busy times: rx_clear=%d%%, "
+ "rx_frame=%d%%, tx_frame=%d%% **\n",
+ rxc_pcnt, rxf_pcnt, txf_pcnt);
+
+ ath_print(common, ATH_DBG_RESET,
+ "==== BB update: done ====\n\n");
+}
+EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index f08cc8bda005..676d3f1123f4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -483,10 +483,10 @@
#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + 0x48c)
#define AR_PHY_TX_IQCAL_CORR_COEFF_01_B0 (AR_SM_BASE + 0x450)
-#define AR_PHY_PANIC_WD_STATUS (AR_SM_BASE + 0x5c0)
-#define AR_PHY_PANIC_WD_CTL_1 (AR_SM_BASE + 0x5c4)
-#define AR_PHY_PANIC_WD_CTL_2 (AR_SM_BASE + 0x5c8)
-#define AR_PHY_BT_CTL (AR_SM_BASE + 0x5cc)
+#define AR_PHY_WATCHDOG_STATUS (AR_SM_BASE + 0x5c0)
+#define AR_PHY_WATCHDOG_CTL_1 (AR_SM_BASE + 0x5c4)
+#define AR_PHY_WATCHDOG_CTL_2 (AR_SM_BASE + 0x5c8)
+#define AR_PHY_WATCHDOG_CTL (AR_SM_BASE + 0x5cc)
#define AR_PHY_ONLY_WARMRESET (AR_SM_BASE + 0x5d0)
#define AR_PHY_ONLY_CTL (AR_SM_BASE + 0x5d4)
#define AR_PHY_ECO_CTRL (AR_SM_BASE + 0x5dc)
@@ -812,35 +812,35 @@
#define AR_PHY_CAL_MEAS_2_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_2_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
#define AR_PHY_CAL_MEAS_3_9300_10(_i) (AR_PHY_IQ_ADC_MEAS_3_B0_9300_10 + (AR_PHY_CHAIN_OFFSET * (_i)))
-#define AR_PHY_BB_PANIC_NON_IDLE_ENABLE 0x00000001
-#define AR_PHY_BB_PANIC_IDLE_ENABLE 0x00000002
-#define AR_PHY_BB_PANIC_IDLE_MASK 0xFFFF0000
-#define AR_PHY_BB_PANIC_NON_IDLE_MASK 0x0000FFFC
-
-#define AR_PHY_BB_PANIC_RST_ENABLE 0x00000002
-#define AR_PHY_BB_PANIC_IRQ_ENABLE 0x00000004
-#define AR_PHY_BB_PANIC_CNTL2_MASK 0xFFFFFFF9
-
-#define AR_PHY_BB_WD_STATUS 0x00000007
-#define AR_PHY_BB_WD_STATUS_S 0
-#define AR_PHY_BB_WD_DET_HANG 0x00000008
-#define AR_PHY_BB_WD_DET_HANG_S 3
-#define AR_PHY_BB_WD_RADAR_SM 0x000000F0
-#define AR_PHY_BB_WD_RADAR_SM_S 4
-#define AR_PHY_BB_WD_RX_OFDM_SM 0x00000F00
-#define AR_PHY_BB_WD_RX_OFDM_SM_S 8
-#define AR_PHY_BB_WD_RX_CCK_SM 0x0000F000
-#define AR_PHY_BB_WD_RX_CCK_SM_S 12
-#define AR_PHY_BB_WD_TX_OFDM_SM 0x000F0000
-#define AR_PHY_BB_WD_TX_OFDM_SM_S 16
-#define AR_PHY_BB_WD_TX_CCK_SM 0x00F00000
-#define AR_PHY_BB_WD_TX_CCK_SM_S 20
-#define AR_PHY_BB_WD_AGC_SM 0x0F000000
-#define AR_PHY_BB_WD_AGC_SM_S 24
-#define AR_PHY_BB_WD_SRCH_SM 0xF0000000
-#define AR_PHY_BB_WD_SRCH_SM_S 28
-
-#define AR_PHY_BB_WD_STATUS_CLR 0x00000008
+#define AR_PHY_WATCHDOG_NON_IDLE_ENABLE 0x00000001
+#define AR_PHY_WATCHDOG_IDLE_ENABLE 0x00000002
+#define AR_PHY_WATCHDOG_IDLE_MASK 0xFFFF0000
+#define AR_PHY_WATCHDOG_NON_IDLE_MASK 0x0000FFFC
+
+#define AR_PHY_WATCHDOG_RST_ENABLE 0x00000002
+#define AR_PHY_WATCHDOG_IRQ_ENABLE 0x00000004
+#define AR_PHY_WATCHDOG_CNTL2_MASK 0xFFFFFFF9
+
+#define AR_PHY_WATCHDOG_INFO 0x00000007
+#define AR_PHY_WATCHDOG_INFO_S 0
+#define AR_PHY_WATCHDOG_DET_HANG 0x00000008
+#define AR_PHY_WATCHDOG_DET_HANG_S 3
+#define AR_PHY_WATCHDOG_RADAR_SM 0x000000F0
+#define AR_PHY_WATCHDOG_RADAR_SM_S 4
+#define AR_PHY_WATCHDOG_RX_OFDM_SM 0x00000F00
+#define AR_PHY_WATCHDOG_RX_OFDM_SM_S 8
+#define AR_PHY_WATCHDOG_RX_CCK_SM 0x0000F000
+#define AR_PHY_WATCHDOG_RX_CCK_SM_S 12
+#define AR_PHY_WATCHDOG_TX_OFDM_SM 0x000F0000
+#define AR_PHY_WATCHDOG_TX_OFDM_SM_S 16
+#define AR_PHY_WATCHDOG_TX_CCK_SM 0x00F00000
+#define AR_PHY_WATCHDOG_TX_CCK_SM_S 20
+#define AR_PHY_WATCHDOG_AGC_SM 0x0F000000
+#define AR_PHY_WATCHDOG_AGC_SM_S 24
+#define AR_PHY_WATCHDOG_SRCH_SM 0xF0000000
+#define AR_PHY_WATCHDOG_SRCH_SM_S 28
+
+#define AR_PHY_WATCHDOG_STATUS_CLR 0x00000008
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index fbb7dec6ddeb..82aca4b6154c 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -136,6 +136,8 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
#define ATH_MAX_ANTENNA 3
#define ATH_RXBUF 512
#define ATH_TXBUF 512
+#define ATH_TXBUF_RESERVE 5
+#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE)
#define ATH_TXMAXTRY 13
#define ATH_MGT_TXMAXTRY 4
@@ -204,6 +206,71 @@ struct ath_txq {
struct list_head txq_fifo_pending;
u8 txq_headidx;
u8 txq_tailidx;
+ int pending_frames;
+};
+
+struct ath_atx_ac {
+ int sched;
+ int qnum;
+ struct list_head list;
+ struct list_head tid_q;
+};
+
+struct ath_buf_state {
+ int bfs_nframes;
+ u16 bfs_al;
+ u16 bfs_frmlen;
+ int bfs_seqno;
+ int bfs_tidno;
+ int bfs_retries;
+ u8 bf_type;
+ u32 bfs_keyix;
+ enum ath9k_key_type bfs_keytype;
+};
+
+struct ath_buf {
+ struct list_head list;
+ struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
+ an aggregate) */
+ struct ath_buf *bf_next; /* next subframe in the aggregate */
+ struct sk_buff *bf_mpdu; /* enclosing frame structure */
+ void *bf_desc; /* virtual addr of desc */
+ dma_addr_t bf_daddr; /* physical addr of desc */
+ dma_addr_t bf_buf_addr; /* physical addr of data buffer */
+ bool bf_stale;
+ bool bf_isnullfunc;
+ bool bf_tx_aborted;
+ u16 bf_flags;
+ struct ath_buf_state bf_state;
+ dma_addr_t bf_dmacontext;
+ struct ath_wiphy *aphy;
+ struct ath_txq *txq;
+};
+
+struct ath_atx_tid {
+ struct list_head list;
+ struct list_head buf_q;
+ struct ath_node *an;
+ struct ath_atx_ac *ac;
+ struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
+ u16 seq_start;
+ u16 seq_next;
+ u16 baw_size;
+ int tidno;
+ int baw_head; /* first un-acked tx buffer */
+ int baw_tail; /* next unused tx buffer slot */
+ int sched;
+ int paused;
+ u8 state;
+};
+
+struct ath_node {
+ struct ath_common *common;
+ struct ath_atx_tid tid[WME_NUM_TID];
+ struct ath_atx_ac ac[WME_NUM_AC];
+ u16 maxampdu;
+ u8 mpdudensity;
+ int last_rssi;
};
#define AGGR_CLEANUP BIT(1)
@@ -267,7 +334,6 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an);
void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq);
int ath_tx_init(struct ath_softc *sc, int nbufs);
void ath_tx_cleanup(struct ath_softc *sc);
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *q);
int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c
index 7707341cd0d3..16e2849f644d 100644
--- a/drivers/net/wireless/ath/ath9k/common.c
+++ b/drivers/net/wireless/ath/ath9k/common.c
@@ -27,270 +27,6 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Shared library for Atheros wireless 802.11n LAN cards.");
MODULE_LICENSE("Dual BSD/GPL");
-/* Common RX processing */
-
-/* Assumes you've already done the endian to CPU conversion */
-static bool ath9k_rx_accept(struct ath_common *common,
- struct sk_buff *skb,
- struct ieee80211_rx_status *rxs,
- struct ath_rx_status *rx_stats,
- bool *decrypt_error)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_hdr *hdr;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- fc = hdr->frame_control;
-
- if (!rx_stats->rs_datalen)
- return false;
- /*
- * rs_status follows rs_datalen so if rs_datalen is too large
- * we can take a hint that hardware corrupted it, so ignore
- * those frames.
- */
- if (rx_stats->rs_datalen > common->rx_bufsize)
- return false;
-
- /*
- * rs_more indicates chained descriptors which can be used
- * to link buffers together for a sort of scatter-gather
- * operation.
- * reject the frame, we don't support scatter-gather yet and
- * the frame is probably corrupt anyway
- */
- if (rx_stats->rs_more)
- return false;
-
- /*
- * The rx_stats->rs_status will not be set until the end of the
- * chained descriptors so it can be ignored if rs_more is set. The
- * rs_more will be false at the last element of the chained
- * descriptors.
- */
- if (rx_stats->rs_status != 0) {
- if (rx_stats->rs_status & ATH9K_RXERR_CRC)
- rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
- if (rx_stats->rs_status & ATH9K_RXERR_PHY)
- return false;
-
- if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
- *decrypt_error = true;
- } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
- if (ieee80211_is_ctl(fc))
- /*
- * Sometimes, we get invalid
- * MIC failures on valid control frames.
- * Remove these mic errors.
- */
- rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
- else
- rxs->flag |= RX_FLAG_MMIC_ERROR;
- }
- /*
- * Reject error frames with the exception of
- * decryption and MIC failures. For monitor mode,
- * we also ignore the CRC error.
- */
- if (ah->opmode == NL80211_IFTYPE_MONITOR) {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
- ATH9K_RXERR_CRC))
- return false;
- } else {
- if (rx_stats->rs_status &
- ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
- return false;
- }
- }
- }
- return true;
-}
-
-static int ath9k_process_rate(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- struct sk_buff *skb)
-{
- struct ieee80211_supported_band *sband;
- enum ieee80211_band band;
- unsigned int i = 0;
-
- band = hw->conf.channel->band;
- sband = hw->wiphy->bands[band];
-
- if (rx_stats->rs_rate & 0x80) {
- /* HT rate */
- rxs->flag |= RX_FLAG_HT;
- if (rx_stats->rs_flags & ATH9K_RX_2040)
- rxs->flag |= RX_FLAG_40MHZ;
- if (rx_stats->rs_flags & ATH9K_RX_GI)
- rxs->flag |= RX_FLAG_SHORT_GI;
- rxs->rate_idx = rx_stats->rs_rate & 0x7f;
- return 0;
- }
-
- for (i = 0; i < sband->n_bitrates; i++) {
- if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
- rxs->rate_idx = i;
- return 0;
- }
- if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
- rxs->flag |= RX_FLAG_SHORTPRE;
- rxs->rate_idx = i;
- return 0;
- }
- }
-
- /*
- * No valid hardware bitrate found -- we should not get here
- * because hardware has already validated this frame as OK.
- */
- ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
- "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
- if ((common->debug_mask & ATH_DBG_XMIT))
- print_hex_dump_bytes("", DUMP_PREFIX_NONE, skb->data, skb->len);
-
- return -EINVAL;
-}
-
-static void ath9k_process_rssi(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_sta *sta;
- struct ieee80211_hdr *hdr;
- struct ath_node *an;
- int last_rssi = ATH_RSSI_DUMMY_MARKER;
- __le16 fc;
-
- hdr = (struct ieee80211_hdr *)skb->data;
- fc = hdr->frame_control;
-
- rcu_read_lock();
- /*
- * XXX: use ieee80211_find_sta! This requires quite a bit of work
- * under the current ath9k virtual wiphy implementation as we have
- * no way of tying a vif to wiphy. Typically vifs are attached to
- * at least one sdata of a wiphy on mac80211 but with ath9k virtual
- * wiphy you'd have to iterate over every wiphy and each sdata.
- */
- sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
- if (sta) {
- an = (struct ath_node *) sta->drv_priv;
- if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
- !rx_stats->rs_moreaggr)
- ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
- last_rssi = an->last_rssi;
- }
- rcu_read_unlock();
-
- if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
- rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
- ATH_RSSI_EP_MULTIPLIER);
- if (rx_stats->rs_rssi < 0)
- rx_stats->rs_rssi = 0;
-
- /* Update Beacon RSSI, this is used by ANI. */
- if (ieee80211_is_beacon(fc))
- ah->stats.avgbrssi = rx_stats->rs_rssi;
-}
-
-/*
- * For Decrypt or Demic errors, we only mark packet status here and always push
- * up the frame up to let mac80211 handle the actual error case, be it no
- * decryption key or real decryption error. This let us keep statistics there.
- */
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rx_status,
- bool *decrypt_error)
-{
- struct ath_hw *ah = common->ah;
-
- memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
-
- /*
- * everything but the rate is checked here, the rate check is done
- * separately to avoid doing two lookups for a rate for each frame.
- */
- if (!ath9k_rx_accept(common, skb, rx_status, rx_stats, decrypt_error))
- return -EINVAL;
-
- ath9k_process_rssi(common, hw, skb, rx_stats);
-
- if (ath9k_process_rate(common, hw, rx_stats, rx_status, skb))
- return -EINVAL;
-
- rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
- rx_status->band = hw->conf.channel->band;
- rx_status->freq = hw->conf.channel->center_freq;
- rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
- rx_status->antenna = rx_stats->rs_antenna;
- rx_status->flag |= RX_FLAG_TSFT;
-
- return 0;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_preprocess);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- bool decrypt_error)
-{
- struct ath_hw *ah = common->ah;
- struct ieee80211_hdr *hdr;
- int hdrlen, padpos, padsize;
- u8 keyix;
- __le16 fc;
-
- /* see if any padding is done by the hw and remove it */
- hdr = (struct ieee80211_hdr *) skb->data;
- hdrlen = ieee80211_get_hdrlen_from_skb(skb);
- fc = hdr->frame_control;
- padpos = ath9k_cmn_padpos(hdr->frame_control);
-
- /* The MAC header is padded to have 32-bit boundary if the
- * packet payload is non-zero. The general calculation for
- * padsize would take into account odd header lengths:
- * padsize = (4 - padpos % 4) % 4; However, since only
- * even-length headers are used, padding can only be 0 or 2
- * bytes and we can optimize this a bit. In addition, we must
- * not try to remove padding from short control frames that do
- * not have payload. */
- padsize = padpos & 3;
- if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
- memmove(skb->data + padsize, skb->data, padpos);
- skb_pull(skb, padsize);
- }
-
- keyix = rx_stats->rs_keyix;
-
- if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
- ieee80211_has_protected(fc)) {
- rxs->flag |= RX_FLAG_DECRYPTED;
- } else if (ieee80211_has_protected(fc)
- && !decrypt_error && skb->len >= hdrlen + 4) {
- keyix = skb->data[hdrlen + 3] >> 6;
-
- if (test_bit(keyix, common->keymap))
- rxs->flag |= RX_FLAG_DECRYPTED;
- }
- if (ah->sw_mgmt_crypto &&
- (rxs->flag & RX_FLAG_DECRYPTED) &&
- ieee80211_is_mgmt(fc))
- /* Use software decrypt for management frames. */
- rxs->flag &= ~RX_FLAG_DECRYPTED;
-}
-EXPORT_SYMBOL(ath9k_cmn_rx_skb_postprocess);
-
int ath9k_cmn_padpos(__le16 frame_control)
{
int padpos = 24;
@@ -475,10 +211,14 @@ static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
return -1;
}
-static int ath_reserve_key_cache_slot(struct ath_common *common)
+static int ath_reserve_key_cache_slot(struct ath_common *common,
+ enum ieee80211_key_alg alg)
{
int i;
+ if (alg == ALG_TKIP)
+ return ath_reserve_key_cache_slot_tkip(common);
+
/* First, try to find slots that would not be available for TKIP. */
if (common->splitmic) {
for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
@@ -547,6 +287,7 @@ int ath9k_cmn_key_config(struct ath_common *common,
struct ath_hw *ah = common->ah;
struct ath9k_keyval hk;
const u8 *mac = NULL;
+ u8 gmac[ETH_ALEN];
int ret = 0;
int idx;
@@ -570,9 +311,23 @@ int ath9k_cmn_key_config(struct ath_common *common,
memcpy(hk.kv_val, key->key, key->keylen);
if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
- /* For now, use the default keys for broadcast keys. This may
- * need to change with virtual interfaces. */
- idx = key->keyidx;
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP:
+ memcpy(gmac, vif->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->alg);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ memcpy(gmac, sta->addr, ETH_ALEN);
+ gmac[0] |= 0x01;
+ mac = gmac;
+ idx = ath_reserve_key_cache_slot(common, key->alg);
+ break;
+ default:
+ idx = key->keyidx;
+ break;
+ }
} else if (key->keyidx) {
if (WARN_ON(!sta))
return -EOPNOTSUPP;
@@ -589,14 +344,12 @@ int ath9k_cmn_key_config(struct ath_common *common,
return -EOPNOTSUPP;
mac = sta->addr;
- if (key->alg == ALG_TKIP)
- idx = ath_reserve_key_cache_slot_tkip(common);
- else
- idx = ath_reserve_key_cache_slot(common);
- if (idx < 0)
- return -ENOSPC; /* no free key cache entries */
+ idx = ath_reserve_key_cache_slot(common, key->alg);
}
+ if (idx < 0)
+ return -ENOSPC; /* no free key cache entries */
+
if (key->alg == ALG_TKIP)
ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
vif->type == NL80211_IFTYPE_AP);
@@ -644,6 +397,19 @@ void ath9k_cmn_key_delete(struct ath_common *common,
}
EXPORT_SYMBOL(ath9k_cmn_key_delete);
+int ath9k_cmn_count_streams(unsigned int chainmask, int max)
+{
+ int streams = 0;
+
+ do {
+ if (++streams == max)
+ break;
+ } while ((chainmask = chainmask & (chainmask - 1)));
+
+ return streams;
+}
+EXPORT_SYMBOL(ath9k_cmn_count_streams);
+
static int __init ath9k_cmn_init(void)
{
return 0;
diff --git a/drivers/net/wireless/ath/ath9k/common.h b/drivers/net/wireless/ath/ath9k/common.h
index e08f7e5a26e0..97809d39c73f 100644
--- a/drivers/net/wireless/ath/ath9k/common.h
+++ b/drivers/net/wireless/ath/ath9k/common.h
@@ -52,82 +52,6 @@
#define ATH_EP_RND(x, mul) \
((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul))
-struct ath_atx_ac {
- int sched;
- int qnum;
- struct list_head list;
- struct list_head tid_q;
-};
-
-struct ath_buf_state {
- int bfs_nframes;
- u16 bfs_al;
- u16 bfs_frmlen;
- int bfs_seqno;
- int bfs_tidno;
- int bfs_retries;
- u8 bf_type;
- u32 bfs_keyix;
- enum ath9k_key_type bfs_keytype;
-};
-
-struct ath_buf {
- struct list_head list;
- struct ath_buf *bf_lastbf; /* last buf of this unit (a frame or
- an aggregate) */
- struct ath_buf *bf_next; /* next subframe in the aggregate */
- struct sk_buff *bf_mpdu; /* enclosing frame structure */
- void *bf_desc; /* virtual addr of desc */
- dma_addr_t bf_daddr; /* physical addr of desc */
- dma_addr_t bf_buf_addr; /* physical addr of data buffer */
- bool bf_stale;
- bool bf_isnullfunc;
- bool bf_tx_aborted;
- u16 bf_flags;
- struct ath_buf_state bf_state;
- dma_addr_t bf_dmacontext;
- struct ath_wiphy *aphy;
-};
-
-struct ath_atx_tid {
- struct list_head list;
- struct list_head buf_q;
- struct ath_node *an;
- struct ath_atx_ac *ac;
- struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];
- u16 seq_start;
- u16 seq_next;
- u16 baw_size;
- int tidno;
- int baw_head; /* first un-acked tx buffer */
- int baw_tail; /* next unused tx buffer slot */
- int sched;
- int paused;
- u8 state;
-};
-
-struct ath_node {
- struct ath_common *common;
- struct ath_atx_tid tid[WME_NUM_TID];
- struct ath_atx_ac ac[WME_NUM_AC];
- u16 maxampdu;
- u8 mpdudensity;
- int last_rssi;
-};
-
-int ath9k_cmn_rx_skb_preprocess(struct ath_common *common,
- struct ieee80211_hw *hw,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rx_status,
- bool *decrypt_error);
-
-void ath9k_cmn_rx_skb_postprocess(struct ath_common *common,
- struct sk_buff *skb,
- struct ath_rx_status *rx_stats,
- struct ieee80211_rx_status *rxs,
- bool decrypt_error);
-
int ath9k_cmn_padpos(__le16 frame_control);
int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
void ath9k_cmn_update_ichannel(struct ieee80211_hw *hw,
@@ -140,3 +64,4 @@ int ath9k_cmn_key_config(struct ath_common *common,
struct ieee80211_key_conf *key);
void ath9k_cmn_key_delete(struct ath_common *common,
struct ieee80211_key_conf *key);
+int ath9k_cmn_count_streams(unsigned int chainmask, int max);
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 29898f8d1893..a127bdba5f90 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -42,7 +42,7 @@ static ssize_t read_file_debug(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->debug_mask);
+ len = sprintf(buf, "0x%08x\n", common->debug_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -57,7 +57,7 @@ static ssize_t write_file_debug(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -86,7 +86,7 @@ static ssize_t read_file_tx_chainmask(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->tx_chainmask);
+ len = sprintf(buf, "0x%08x\n", common->tx_chainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -101,7 +101,7 @@ static ssize_t write_file_tx_chainmask(struct file *file, const char __user *use
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -128,7 +128,7 @@ static ssize_t read_file_rx_chainmask(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", common->rx_chainmask);
+ len = sprintf(buf, "0x%08x\n", common->rx_chainmask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -143,7 +143,7 @@ static ssize_t write_file_rx_chainmask(struct file *file, const char __user *use
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &mask))
@@ -176,7 +176,7 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
buf = kmalloc(DMA_BUF_LEN, GFP_KERNEL);
if (!buf)
- return 0;
+ return -ENOMEM;
ath9k_ps_wakeup(sc);
@@ -248,6 +248,9 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
ath9k_ps_restore(sc);
+ if (len > DMA_BUF_LEN)
+ len = DMA_BUF_LEN;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
@@ -269,6 +272,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
sc->debug.stats.istats.rxlp++;
if (status & ATH9K_INT_RXHP)
sc->debug.stats.istats.rxhp++;
+ if (status & ATH9K_INT_BB_WATCHDOG)
+ sc->debug.stats.istats.bb_watchdog++;
} else {
if (status & ATH9K_INT_RX)
sc->debug.stats.istats.rxok++;
@@ -319,6 +324,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
"%8s: %10u\n", "RXLP", sc->debug.stats.istats.rxlp);
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "RXHP", sc->debug.stats.istats.rxhp);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%8s: %10u\n", "WATCHDOG",
+ sc->debug.stats.istats.bb_watchdog);
} else {
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "RX", sc->debug.stats.istats.rxok);
@@ -358,6 +366,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"%8s: %10u\n", "TOTAL", sc->debug.stats.istats.total);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -397,11 +408,10 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
if (sc->cur_rate_table == NULL)
return 0;
- max = 80 + sc->cur_rate_table->rate_cnt * 1024;
- buf = kmalloc(max + 1, GFP_KERNEL);
+ max = 80 + sc->cur_rate_table->rate_cnt * 1024 + 1;
+ buf = kmalloc(max, GFP_KERNEL);
if (buf == NULL)
- return 0;
- buf[max] = 0;
+ return -ENOMEM;
len += sprintf(buf, "%6s %6s %6s "
"%10s %10s %10s %10s\n",
@@ -443,6 +453,9 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
stats->per);
}
+ if (len > max)
+ len = max;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
return retval;
@@ -505,6 +518,9 @@ static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
len += snprintf(buf + len, sizeof(buf) - len,
"addrmask: %pM\n", addr);
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -630,7 +646,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
- return 0;
+ return -ENOMEM;
len += sprintf(buf, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
@@ -648,6 +664,9 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
PR("DATA Underrun: ", data_underrun);
PR("DELIM Underrun: ", delim_underrun);
+ if (len > size)
+ len = size;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
@@ -700,7 +719,7 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
buf = kzalloc(size, GFP_KERNEL);
if (buf == NULL)
- return 0;
+ return -ENOMEM;
len += snprintf(buf + len, size - len,
"%18s : %10u\n", "CRC ERR",
@@ -751,6 +770,9 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
PHY_ERR("HT-LENGTH", ATH9K_PHYERR_HT_LENGTH_ILLEGAL);
PHY_ERR("HT-RATE", ATH9K_PHYERR_HT_RATE_ILLEGAL);
+ if (len > size)
+ len = size;
+
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
@@ -802,7 +824,7 @@ static ssize_t read_file_regidx(struct file *file, char __user *user_buf,
char buf[32];
unsigned int len;
- len = snprintf(buf, sizeof(buf), "0x%08x\n", sc->debug.regidx);
+ len = sprintf(buf, "0x%08x\n", sc->debug.regidx);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -816,7 +838,7 @@ static ssize_t write_file_regidx(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &regidx))
@@ -843,7 +865,7 @@ static ssize_t read_file_regval(struct file *file, char __user *user_buf,
u32 regval;
regval = REG_READ_D(ah, sc->debug.regidx);
- len = snprintf(buf, sizeof(buf), "0x%08x\n", regval);
+ len = sprintf(buf, "0x%08x\n", regval);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -858,7 +880,7 @@ static ssize_t write_file_regval(struct file *file, const char __user *user_buf,
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
- return -EINVAL;
+ return -EFAULT;
buf[len] = '\0';
if (strict_strtoul(buf, 0, &regval))
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 5147b8709e10..5d21704e87ff 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -53,6 +53,7 @@ struct ath_buf;
* @cabend: RX End of CAB traffic
* @dtimsync: DTIM sync lossage
* @dtim: RX Beacon with DTIM
+ * @bb_watchdog: Baseband watchdog
*/
struct ath_interrupt_stats {
u32 total;
@@ -76,6 +77,7 @@ struct ath_interrupt_stats {
u32 cabend;
u32 dtimsync;
u32 dtim;
+ u32 bb_watchdog;
};
struct ath_rc_stats {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.c b/drivers/net/wireless/ath/ath9k/eeprom.c
index ca8704a9d7ac..1266333f586d 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom.c
@@ -24,6 +24,14 @@ static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz)
return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin));
}
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val)
+{
+ REG_WRITE(ah, reg, val);
+
+ if (ah->config.analog_shiftreg)
+ udelay(100);
+}
+
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
u32 shift, u32 val)
{
@@ -250,6 +258,27 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
return twiceMaxEdgePower;
}
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah)
+{
+ struct ath_common *common = ath9k_hw_common(ah);
+ struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
+
+ switch (ar5416_get_ntxchains(ah->txchainmask)) {
+ case 1:
+ break;
+ case 2:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+ break;
+ case 3:
+ regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+ break;
+ default:
+ ath_print(common, ATH_DBG_EEPROM,
+ "Invalid chainmask configuration\n");
+ break;
+ }
+}
+
int ath9k_hw_eeprom_init(struct ath_hw *ah)
{
int status;
diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h
index 21354c15a9a9..7da7d73c0847 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom.h
+++ b/drivers/net/wireless/ath/ath9k/eeprom.h
@@ -679,6 +679,7 @@ struct eeprom_ops {
u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz);
};
+void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val);
void ath9k_hw_analog_shift_rmw(struct ath_hw *ah, u32 reg, u32 mask,
u32 shift, u32 val);
int16_t ath9k_hw_interpolate(u16 target, u16 srcLeft, u16 srcRight,
@@ -704,6 +705,7 @@ void ath9k_hw_get_target_powers(struct ath_hw *ah,
u16 numRates, bool isHt40Target);
u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
bool is2GHz, int num_band_edges);
+void ath9k_hw_update_regulatory_maxpower(struct ath_hw *ah);
int ath9k_hw_eeprom_init(struct ath_hw *ah);
#define ar5416_get_ntxchains(_txchainmask) \
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 41a77d1bd439..e25a2abbf561 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -249,6 +249,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
struct chan_centers centers;
#define PD_GAIN_BOUNDARY_DEFAULT 58;
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index b471db5fb82d..39a41053705f 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -17,17 +17,19 @@
#include "hw.h"
#include "ar9002_phy.h"
-static int ath9k_hw_AR9287_get_eeprom_ver(struct ath_hw *ah)
+#define NUM_EEP_WORDS (sizeof(struct ar9287_eeprom) / sizeof(u16))
+
+static int ath9k_hw_ar9287_get_eeprom_ver(struct ath_hw *ah)
{
return (ah->eeprom.map9287.baseEepHeader.version >> 12) & 0xF;
}
-static int ath9k_hw_AR9287_get_eeprom_rev(struct ath_hw *ah)
+static int ath9k_hw_ar9287_get_eeprom_rev(struct ath_hw *ah)
{
return (ah->eeprom.map9287.baseEepHeader.version) & 0xFFF;
}
-static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
+static bool ath9k_hw_ar9287_fill_eeprom(struct ath_hw *ah)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct ath_common *common = ath9k_hw_common(ah);
@@ -40,20 +42,20 @@ static bool ath9k_hw_AR9287_fill_eeprom(struct ath_hw *ah)
"Reading from EEPROM, not flash\n");
}
- for (addr = 0; addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
- addr++) {
- if (!ath9k_hw_nvram_read(common,
- addr + eep_start_loc, eep_data)) {
+ for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
+ if (!ath9k_hw_nvram_read(common, addr + eep_start_loc,
+ eep_data)) {
ath_print(common, ATH_DBG_EEPROM,
"Unable to read eeprom region\n");
return false;
}
eep_data++;
}
+
return true;
}
-static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
+static int ath9k_hw_ar9287_check_eeprom(struct ath_hw *ah)
{
u32 sum = 0, el, integer;
u16 temp, word, magic, magic2, *eepdata;
@@ -63,8 +65,8 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
struct ath_common *common = ath9k_hw_common(ah);
if (!ath9k_hw_use_flash(ah)) {
- if (!ath9k_hw_nvram_read(common,
- AR5416_EEPROM_MAGIC_OFFSET, &magic)) {
+ if (!ath9k_hw_nvram_read(common, AR5416_EEPROM_MAGIC_OFFSET,
+ &magic)) {
ath_print(common, ATH_DBG_FATAL,
"Reading Magic # failed\n");
return false;
@@ -72,6 +74,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
ath_print(common, ATH_DBG_EEPROM,
"Read Magic = 0x%04X\n", magic);
+
if (magic != AR5416_EEPROM_MAGIC) {
magic2 = swab16(magic);
@@ -79,9 +82,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
need_swap = true;
eepdata = (u16 *)(&ah->eeprom);
- for (addr = 0;
- addr < sizeof(struct ar9287_eeprom) / sizeof(u16);
- addr++) {
+ for (addr = 0; addr < NUM_EEP_WORDS; addr++) {
temp = swab16(*eepdata);
*eepdata = temp;
eepdata++;
@@ -89,13 +90,14 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
} else {
ath_print(common, ATH_DBG_FATAL,
"Invalid EEPROM Magic. "
- "endianness mismatch.\n");
+ "Endianness mismatch.\n");
return -EINVAL;
}
}
}
- ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n", need_swap ?
- "True" : "False");
+
+ ath_print(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+ need_swap ? "True" : "False");
if (need_swap)
el = swab16(ah->eeprom.map9287.baseEepHeader.length);
@@ -108,6 +110,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
el = el / sizeof(u16);
eepdata = (u16 *)(&ah->eeprom);
+
for (i = 0; i < el; i++)
sum ^= *eepdata++;
@@ -161,7 +164,7 @@ static int ath9k_hw_AR9287_check_eeprom(struct ath_hw *ah)
return 0;
}
-static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
+static u32 ath9k_hw_ar9287_get_eeprom(struct ath_hw *ah,
enum eeprom_param param)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
@@ -170,6 +173,7 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
u16 ver_minor;
ver_minor = pBase->version & AR9287_EEP_VER_MINOR_MASK;
+
switch (param) {
case EEP_NFTHRESH_2:
return pModal->noiseFloorThreshCh[0];
@@ -214,29 +218,30 @@ static u32 ath9k_hw_AR9287_get_eeprom(struct ath_hw *ah,
}
}
-
-static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
- struct ath9k_channel *chan,
- struct cal_data_per_freq_ar9287 *pRawDataSet,
- u8 *bChans, u16 availPiers,
- u16 tPdGainOverlap, int16_t *pMinCalPower,
- u16 *pPdGainBoundaries, u8 *pPDADCValues,
- u16 numXpdGains)
+static void ath9k_hw_get_ar9287_gain_boundaries_pdadcs(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ struct cal_data_per_freq_ar9287 *pRawDataSet,
+ u8 *bChans, u16 availPiers,
+ u16 tPdGainOverlap,
+ int16_t *pMinCalPower,
+ u16 *pPdGainBoundaries,
+ u8 *pPDADCValues,
+ u16 numXpdGains)
{
-#define TMP_VAL_VPD_TABLE \
+#define TMP_VAL_VPD_TABLE \
((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep));
- int i, j, k;
- int16_t ss;
- u16 idxL = 0, idxR = 0, numPiers;
- u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
- u8 minPwrT4[AR9287_NUM_PD_GAINS];
- u8 maxPwrT4[AR9287_NUM_PD_GAINS];
- int16_t vpdStep;
- int16_t tmpVal;
- u16 sizeCurrVpdTable, maxIndex, tgtIndex;
- bool match;
- int16_t minDelta = 0;
+ int i, j, k;
+ int16_t ss;
+ u16 idxL = 0, idxR = 0, numPiers;
+ u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR;
+ u8 minPwrT4[AR9287_NUM_PD_GAINS];
+ u8 maxPwrT4[AR9287_NUM_PD_GAINS];
+ int16_t vpdStep;
+ int16_t tmpVal;
+ u16 sizeCurrVpdTable, maxIndex, tgtIndex;
+ bool match;
+ int16_t minDelta = 0;
struct chan_centers centers;
static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS]
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
@@ -245,6 +250,7 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS]
[AR5416_MAX_PWR_RANGE_IN_HALF_DB];
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
@@ -253,18 +259,18 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
}
match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center,
- IS_CHAN_2GHZ(chan)), bChans, numPiers,
- &idxL, &idxR);
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ bChans, numPiers, &idxL, &idxR);
if (match) {
for (i = 0; i < numXpdGains; i++) {
minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0];
maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4];
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pRawDataSet[idxL].pwrPdg[i],
- pRawDataSet[idxL].vpdPdg[i],
- AR9287_PD_GAIN_ICEPTS, vpdTableI[i]);
+ pRawDataSet[idxL].pwrPdg[i],
+ pRawDataSet[idxL].vpdPdg[i],
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableI[i]);
}
} else {
for (i = 0; i < numXpdGains; i++) {
@@ -275,61 +281,59 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
minPwrT4[i] = max(pPwrL[0], pPwrR[0]);
- maxPwrT4[i] =
- min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
- pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
+ maxPwrT4[i] = min(pPwrL[AR9287_PD_GAIN_ICEPTS - 1],
+ pPwrR[AR9287_PD_GAIN_ICEPTS - 1]);
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrL, pVpdL,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableL[i]);
+ pPwrL, pVpdL,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableL[i]);
ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i],
- pPwrR, pVpdR,
- AR9287_PD_GAIN_ICEPTS,
- vpdTableR[i]);
+ pPwrR, pVpdR,
+ AR9287_PD_GAIN_ICEPTS,
+ vpdTableR[i]);
for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) {
- vpdTableI[i][j] =
- (u8)(ath9k_hw_interpolate((u16)
- FREQ2FBIN(centers. synth_center,
- IS_CHAN_2GHZ(chan)),
- bChans[idxL], bChans[idxR],
- vpdTableL[i][j], vpdTableR[i][j]));
+ vpdTableI[i][j] = (u8)(ath9k_hw_interpolate(
+ (u16)FREQ2FBIN(centers. synth_center,
+ IS_CHAN_2GHZ(chan)),
+ bChans[idxL], bChans[idxR],
+ vpdTableL[i][j], vpdTableR[i][j]));
}
}
}
- *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
+ *pMinCalPower = (int16_t)(minPwrT4[0] / 2);
k = 0;
+
for (i = 0; i < numXpdGains; i++) {
if (i == (numXpdGains - 1))
- pPdGainBoundaries[i] = (u16)(maxPwrT4[i] / 2);
+ pPdGainBoundaries[i] =
+ (u16)(maxPwrT4[i] / 2);
else
- pPdGainBoundaries[i] = (u16)((maxPwrT4[i] +
- minPwrT4[i+1]) / 4);
+ pPdGainBoundaries[i] =
+ (u16)((maxPwrT4[i] + minPwrT4[i+1]) / 4);
pPdGainBoundaries[i] = min((u16)AR5416_MAX_RATE_POWER,
- pPdGainBoundaries[i]);
+ pPdGainBoundaries[i]);
- if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
- minDelta = pPdGainBoundaries[0] - 23;
- pPdGainBoundaries[0] = 23;
- } else
- minDelta = 0;
+ minDelta = 0;
if (i == 0) {
if (AR_SREV_9280_10_OR_LATER(ah))
ss = (int16_t)(0 - (minPwrT4[i] / 2));
else
ss = 0;
- } else
+ } else {
ss = (int16_t)((pPdGainBoundaries[i-1] -
- (minPwrT4[i] / 2)) -
+ (minPwrT4[i] / 2)) -
tPdGainOverlap + 1 + minDelta);
+ }
vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
while ((ss < 0) && (k < (AR9287_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep);
pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal);
@@ -348,12 +352,13 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] -
vpdTableI[i][sizeCurrVpdTable - 2]);
vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
+
if (tgtIndex > maxIndex) {
while ((ss <= tgtIndex) &&
(k < (AR9287_NUM_PDADC_VALUES - 1))) {
tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
- pPDADCValues[k++] = (u8)((tmpVal > 255) ?
- 255 : tmpVal);
+ pPDADCValues[k++] =
+ (u8)((tmpVal > 255) ? 255 : tmpVal);
ss++;
}
}
@@ -375,10 +380,9 @@ static void ath9k_hw_get_AR9287_gain_boundaries_pdadcs(struct ath_hw *ah,
static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
struct ath9k_channel *chan,
struct cal_data_op_loop_ar9287 *pRawDatasetOpLoop,
- u8 *pCalChans, u16 availPiers,
- int8_t *pPwr)
+ u8 *pCalChans, u16 availPiers, int8_t *pPwr)
{
- u16 idxL = 0, idxR = 0, numPiers;
+ u16 idxL = 0, idxR = 0, numPiers;
bool match;
struct chan_centers centers;
@@ -390,15 +394,14 @@ static void ar9287_eeprom_get_tx_gain_index(struct ath_hw *ah,
}
match = ath9k_hw_get_lower_upper_index(
- (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
- pCalChans, numPiers,
- &idxL, &idxR);
+ (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+ pCalChans, numPiers, &idxL, &idxR);
if (match) {
*pPwr = (int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0];
} else {
*pPwr = ((int8_t) pRawDatasetOpLoop[idxL].pwrPdg[0][0] +
- (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+ (int8_t) pRawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
}
}
@@ -409,16 +412,22 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
u32 tmpVal;
u32 a;
+ /* Enable OLPC for chain 0 */
+
tmpVal = REG_READ(ah, 0xa270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
REG_WRITE(ah, 0xa270, tmpVal);
+ /* Enable OLPC for chain 1 */
+
tmpVal = REG_READ(ah, 0xb270);
tmpVal = tmpVal & 0xFCFFFFFF;
tmpVal = tmpVal | (0x3 << 24);
REG_WRITE(ah, 0xb270, tmpVal);
+ /* Write the OLPC ref power for chain 0 */
+
if (chain == 0) {
tmpVal = REG_READ(ah, 0xa398);
tmpVal = tmpVal & 0xff00ffff;
@@ -427,6 +436,8 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
REG_WRITE(ah, 0xa398, tmpVal);
}
+ /* Write the OLPC ref power for chain 1 */
+
if (chain == 1) {
tmpVal = REG_READ(ah, 0xb398);
tmpVal = tmpVal & 0xff00ffff;
@@ -436,28 +447,29 @@ static void ar9287_eeprom_olpc_set_pdadcs(struct ath_hw *ah,
}
}
-static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
+static void ath9k_hw_set_ar9287_power_cal_table(struct ath_hw *ah,
struct ath9k_channel *chan,
int16_t *pTxPowerIndexOffset)
{
- struct ath_common *common = ath9k_hw_common(ah);
struct cal_data_per_freq_ar9287 *pRawDataset;
struct cal_data_op_loop_ar9287 *pRawDatasetOpenLoop;
- u8 *pCalBChans = NULL;
+ u8 *pCalBChans = NULL;
u16 pdGainOverlap_t2;
- u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
+ u8 pdadcValues[AR9287_NUM_PDADC_VALUES];
u16 gainBoundaries[AR9287_PD_GAINS_IN_MASK];
u16 numPiers = 0, i, j;
- int16_t tMinCalPower;
+ int16_t tMinCalPower;
u16 numXpdGain, xpdMask;
u16 xpdGainValues[AR9287_NUM_PD_GAINS] = {0, 0, 0, 0};
- u32 reg32, regOffset, regChainOffset;
- int16_t modalIdx, diff = 0;
+ u32 reg32, regOffset, regChainOffset, regval;
+ int16_t modalIdx, diff = 0;
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
+
modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0;
xpdMask = pEepData->modalHeader.xpdGain;
+
if ((pEepData->baseEepHeader.version & AR9287_EEP_VER_MINOR_MASK) >=
- AR9287_EEP_MINOR_VER_2)
+ AR9287_EEP_MINOR_VER_2)
pdGainOverlap_t2 = pEepData->modalHeader.pdGainOverlap;
else
pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5),
@@ -466,15 +478,16 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
if (IS_CHAN_2GHZ(chan)) {
pCalBChans = pEepData->calFreqPier2G;
numPiers = AR9287_NUM_2G_CAL_PIERS;
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
pRawDatasetOpenLoop =
- (struct cal_data_op_loop_ar9287 *)
- pEepData->calPierData2G[0];
+ (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[0];
ah->initPDADC = pRawDatasetOpenLoop->vpdPdg[0][0];
}
}
numXpdGain = 0;
+
+ /* Calculate the value of xpdgains from the xpdGain Mask */
for (i = 1; i <= AR9287_PD_GAINS_IN_MASK; i++) {
if ((xpdMask >> (AR9287_PD_GAINS_IN_MASK - i)) & 1) {
if (numXpdGain >= AR9287_NUM_PD_GAINS)
@@ -496,99 +509,80 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
for (i = 0; i < AR9287_MAX_CHAINS; i++) {
regChainOffset = i * 0x1000;
+
if (pEepData->baseEepHeader.txMask & (1 << i)) {
- pRawDatasetOpenLoop = (struct cal_data_op_loop_ar9287 *)
- pEepData->calPierData2G[i];
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ pRawDatasetOpenLoop =
+ (struct cal_data_op_loop_ar9287 *)pEepData->calPierData2G[i];
+
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
int8_t txPower;
ar9287_eeprom_get_tx_gain_index(ah, chan,
- pRawDatasetOpenLoop,
- pCalBChans, numPiers,
- &txPower);
+ pRawDatasetOpenLoop,
+ pCalBChans, numPiers,
+ &txPower);
ar9287_eeprom_olpc_set_pdadcs(ah, txPower, i);
} else {
pRawDataset =
(struct cal_data_per_freq_ar9287 *)
pEepData->calPierData2G[i];
- ath9k_hw_get_AR9287_gain_boundaries_pdadcs(
- ah, chan, pRawDataset,
- pCalBChans, numPiers,
- pdGainOverlap_t2,
- &tMinCalPower, gainBoundaries,
- pdadcValues, numXpdGain);
+
+ ath9k_hw_get_ar9287_gain_boundaries_pdadcs(ah, chan,
+ pRawDataset,
+ pCalBChans, numPiers,
+ pdGainOverlap_t2,
+ &tMinCalPower,
+ gainBoundaries,
+ pdadcValues,
+ numXpdGain);
}
if (i == 0) {
- if (!ath9k_hw_AR9287_get_eeprom(
- ah, EEP_OL_PWRCTRL)) {
- REG_WRITE(ah, AR_PHY_TPCRG5 +
- regChainOffset,
- SM(pdGainOverlap_t2,
- AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
- SM(gainBoundaries[0],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
- | SM(gainBoundaries[1],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
- | SM(gainBoundaries[2],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
- | SM(gainBoundaries[3],
- AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+ if (!ath9k_hw_ar9287_get_eeprom(ah,
+ EEP_OL_PWRCTRL)) {
+
+ regval = SM(pdGainOverlap_t2,
+ AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+ | SM(gainBoundaries[0],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+ | SM(gainBoundaries[1],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+ | SM(gainBoundaries[2],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+ | SM(gainBoundaries[3],
+ AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4);
+
+ REG_WRITE(ah,
+ AR_PHY_TPCRG5 + regChainOffset,
+ regval);
}
}
if ((int32_t)AR9287_PWR_TABLE_OFFSET_DB !=
- pEepData->baseEepHeader.pwrTableOffset) {
- diff = (u16)
- (pEepData->baseEepHeader.pwrTableOffset
- - (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
+ pEepData->baseEepHeader.pwrTableOffset) {
+ diff = (u16)(pEepData->baseEepHeader.pwrTableOffset -
+ (int32_t)AR9287_PWR_TABLE_OFFSET_DB);
diff *= 2;
- for (j = 0;
- j < ((u16)AR9287_NUM_PDADC_VALUES-diff);
- j++)
+ for (j = 0; j < ((u16)AR9287_NUM_PDADC_VALUES-diff); j++)
pdadcValues[j] = pdadcValues[j+diff];
for (j = (u16)(AR9287_NUM_PDADC_VALUES-diff);
j < AR9287_NUM_PDADC_VALUES; j++)
pdadcValues[j] =
- pdadcValues[
- AR9287_NUM_PDADC_VALUES-diff];
+ pdadcValues[AR9287_NUM_PDADC_VALUES-diff];
}
- if (!ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
- regOffset = AR_PHY_BASE + (672 << 2) +
- regChainOffset;
- for (j = 0; j < 32; j++) {
- reg32 = ((pdadcValues[4*j + 0]
- & 0xFF) << 0) |
- ((pdadcValues[4*j + 1]
- & 0xFF) << 8) |
- ((pdadcValues[4*j + 2]
- & 0xFF) << 16) |
- ((pdadcValues[4*j + 3]
- & 0xFF) << 24) ;
- REG_WRITE(ah, regOffset, reg32);
+ if (!ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ regOffset = AR_PHY_BASE +
+ (672 << 2) + regChainOffset;
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC (%d,%4x): %4.4x "
- "%8.8x\n",
- i, regChainOffset, regOffset,
- reg32);
-
- ath_print(common, ATH_DBG_EEPROM,
- "PDADC: Chain %d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d | "
- "PDADC %3d Value %3d |\n",
- i, 4 * j, pdadcValues[4 * j],
- 4 * j + 1,
- pdadcValues[4 * j + 1],
- 4 * j + 2,
- pdadcValues[4 * j + 2],
- 4 * j + 3,
- pdadcValues[4 * j + 3]);
+ for (j = 0; j < 32; j++) {
+ reg32 = ((pdadcValues[4*j + 0] & 0xFF) << 0)
+ | ((pdadcValues[4*j + 1] & 0xFF) << 8)
+ | ((pdadcValues[4*j + 2] & 0xFF) << 16)
+ | ((pdadcValues[4*j + 3] & 0xFF) << 24);
+ REG_WRITE(ah, regOffset, reg32);
regOffset += 4;
}
}
@@ -598,30 +592,45 @@ static void ath9k_hw_set_AR9287_power_cal_table(struct ath_hw *ah,
*pTxPowerIndexOffset = 0;
}
-static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
- struct ath9k_channel *chan, int16_t *ratesArray, u16 cfgCtl,
- u16 AntennaReduction, u16 twiceMaxRegulatoryPower,
- u16 powerLimit)
+static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
+ struct ath9k_channel *chan,
+ int16_t *ratesArray,
+ u16 cfgCtl,
+ u16 AntennaReduction,
+ u16 twiceMaxRegulatoryPower,
+ u16 powerLimit)
{
+#define CMP_CTL \
+ (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ pEepData->ctlIndex[i])
+
+#define CMP_NO_CTL \
+ (((cfgCtl & ~CTL_MODE_M) | (pCtlMode[ctlMode] & CTL_MODE_M)) == \
+ ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))
+
#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6
#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10
+
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
static const u16 tpScaleReductionTable[5] =
{ 0, 3, 6, 9, AR5416_MAX_RATE_POWER };
int i;
- int16_t twiceLargestAntenna;
+ int16_t twiceLargestAntenna;
struct cal_ctl_data_ar9287 *rep;
struct cal_target_power_leg targetPowerOfdm = {0, {0, 0, 0, 0} },
targetPowerCck = {0, {0, 0, 0, 0} };
struct cal_target_power_leg targetPowerOfdmExt = {0, {0, 0, 0, 0} },
targetPowerCckExt = {0, {0, 0, 0, 0} };
- struct cal_target_power_ht targetPowerHt20,
+ struct cal_target_power_ht targetPowerHt20,
targetPowerHt40 = {0, {0, 0, 0, 0} };
u16 scaledPower = 0, minCtlPower, maxRegAllowedPower;
- u16 ctlModesFor11g[] =
- {CTL_11B, CTL_11G, CTL_2GHT20,
- CTL_11B_EXT, CTL_11G_EXT, CTL_2GHT40};
+ u16 ctlModesFor11g[] = {CTL_11B,
+ CTL_11G,
+ CTL_2GHT20,
+ CTL_11B_EXT,
+ CTL_11G_EXT,
+ CTL_2GHT40};
u16 numCtlModes = 0, *pCtlMode = NULL, ctlMode, freq;
struct chan_centers centers;
int tx_chainmask;
@@ -631,19 +640,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
ath9k_hw_get_channel_centers(ah, chan, &centers);
+ /* Compute TxPower reduction due to Antenna Gain */
twiceLargestAntenna = max(pEepData->modalHeader.antennaGainCh[0],
pEepData->modalHeader.antennaGainCh[1]);
+ twiceLargestAntenna = (int16_t)min((AntennaReduction) -
+ twiceLargestAntenna, 0);
- twiceLargestAntenna = (int16_t)min((AntennaReduction) -
- twiceLargestAntenna, 0);
-
+ /*
+ * scaledPower is the minimum of the user input power level
+ * and the regulatory allowed power level.
+ */
maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna;
+
if (regulatory->tp_scale != ATH9K_TP_SCALE_MAX)
maxRegAllowedPower -=
(tpScaleReductionTable[(regulatory->tp_scale)] * 2);
scaledPower = min(powerLimit, maxRegAllowedPower);
+ /*
+ * Reduce scaled Power by number of chains active
+ * to get the per chain tx power level.
+ */
switch (ar5416_get_ntxchains(tx_chainmask)) {
case 1:
break;
@@ -656,9 +674,14 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
scaledPower = max((u16)0, scaledPower);
+ /*
+ * Get TX power from EEPROM.
+ */
if (IS_CHAN_2GHZ(chan)) {
+ /* CTL_11B, CTL_11G, CTL_2GHT20 */
numCtlModes =
ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40;
+
pCtlMode = ctlModesFor11g;
ath9k_hw_get_legacy_target_powers(ah, chan,
@@ -675,6 +698,7 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
&targetPowerHt20, 8, false);
if (IS_CHAN_HT40(chan)) {
+ /* All 2G CTLs */
numCtlModes = ARRAY_SIZE(ctlModesFor11g);
ath9k_hw_get_target_powers(ah, chan,
pEepData->calTargetPower2GHT40,
@@ -692,8 +716,9 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) {
- bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) ||
- (pCtlMode[ctlMode] == CTL_2GHT40);
+ bool isHt40CtlMode =
+ (pCtlMode[ctlMode] == CTL_2GHT40) ? true : false;
+
if (isHt40CtlMode)
freq = centers.synth_center;
else if (pCtlMode[ctlMode] & EXT_ADDITIVE)
@@ -701,31 +726,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
else
freq = centers.ctl_center;
- if (ah->eep_ops->get_eeprom_ver(ah) == 14 &&
- ah->eep_ops->get_eeprom_rev(ah) <= 2)
- twiceMaxEdgePower = AR5416_MAX_RATE_POWER;
-
+ /* Walk through the CTL indices stored in EEPROM */
for (i = 0; (i < AR9287_NUM_CTLS) && pEepData->ctlIndex[i]; i++) {
- if ((((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- pEepData->ctlIndex[i]) ||
- (((cfgCtl & ~CTL_MODE_M) |
- (pCtlMode[ctlMode] & CTL_MODE_M)) ==
- ((pEepData->ctlIndex[i] &
- CTL_MODE_M) | SD_NO_CTL))) {
+ struct cal_ctl_edges *pRdEdgesPower;
+ /*
+ * Compare test group from regulatory channel list
+ * with test mode from pCtlMode list
+ */
+ if (CMP_CTL || CMP_NO_CTL) {
rep = &(pEepData->ctlData[i]);
- twiceMinEdgePower = ath9k_hw_get_max_edge_power(
- freq,
- rep->ctlEdges[ar5416_get_ntxchains(
- tx_chainmask) - 1],
- IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES);
-
- if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
- twiceMaxEdgePower = min(
- twiceMaxEdgePower,
- twiceMinEdgePower);
- else {
+ pRdEdgesPower =
+ rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1];
+
+ twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq,
+ pRdEdgesPower,
+ IS_CHAN_2GHZ(chan),
+ AR5416_NUM_BAND_EDGES);
+
+ if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) {
+ twiceMaxEdgePower = min(twiceMaxEdgePower,
+ twiceMinEdgePower);
+ } else {
twiceMaxEdgePower = twiceMinEdgePower;
break;
}
@@ -734,55 +756,48 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+ /* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) {
case CTL_11B:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerCck.tPow2x);
- i++) {
- targetPowerCck.tPow2x[i] = (u8)min(
- (u16)targetPowerCck.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) {
+ targetPowerCck.tPow2x[i] =
+ (u8)min((u16)targetPowerCck.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_11A:
case CTL_11G:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerOfdm.tPow2x);
- i++) {
- targetPowerOfdm.tPow2x[i] = (u8)min(
- (u16)targetPowerOfdm.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) {
+ targetPowerOfdm.tPow2x[i] =
+ (u8)min((u16)targetPowerOfdm.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_5GHT20:
case CTL_2GHT20:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerHt20.tPow2x);
- i++) {
- targetPowerHt20.tPow2x[i] = (u8)min(
- (u16)targetPowerHt20.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) {
+ targetPowerHt20.tPow2x[i] =
+ (u8)min((u16)targetPowerHt20.tPow2x[i],
+ minCtlPower);
}
break;
case CTL_11B_EXT:
- targetPowerCckExt.tPow2x[0] = (u8)min(
- (u16)targetPowerCckExt.tPow2x[0],
- minCtlPower);
+ targetPowerCckExt.tPow2x[0] =
+ (u8)min((u16)targetPowerCckExt.tPow2x[0],
+ minCtlPower);
break;
case CTL_11A_EXT:
case CTL_11G_EXT:
- targetPowerOfdmExt.tPow2x[0] = (u8)min(
- (u16)targetPowerOfdmExt.tPow2x[0],
- minCtlPower);
+ targetPowerOfdmExt.tPow2x[0] =
+ (u8)min((u16)targetPowerOfdmExt.tPow2x[0],
+ minCtlPower);
break;
case CTL_5GHT40:
case CTL_2GHT40:
- for (i = 0;
- i < ARRAY_SIZE(targetPowerHt40.tPow2x);
- i++) {
- targetPowerHt40.tPow2x[i] = (u8)min(
- (u16)targetPowerHt40.tPow2x[i],
- minCtlPower);
+ for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) {
+ targetPowerHt40.tPow2x[i] =
+ (u8)min((u16)targetPowerHt40.tPow2x[i],
+ minCtlPower);
}
break;
default:
@@ -790,12 +805,13 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
}
}
+ /* Now set the rates array */
+
ratesArray[rate6mb] =
ratesArray[rate9mb] =
ratesArray[rate12mb] =
ratesArray[rate18mb] =
- ratesArray[rate24mb] =
- targetPowerOfdm.tPow2x[0];
+ ratesArray[rate24mb] = targetPowerOfdm.tPow2x[0];
ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1];
ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2];
@@ -807,12 +823,12 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
if (IS_CHAN_2GHZ(chan)) {
ratesArray[rate1l] = targetPowerCck.tPow2x[0];
- ratesArray[rate2s] = ratesArray[rate2l] =
- targetPowerCck.tPow2x[1];
- ratesArray[rate5_5s] = ratesArray[rate5_5l] =
- targetPowerCck.tPow2x[2];
- ratesArray[rate11s] = ratesArray[rate11l] =
- targetPowerCck.tPow2x[3];
+ ratesArray[rate2s] =
+ ratesArray[rate2l] = targetPowerCck.tPow2x[1];
+ ratesArray[rate5_5s] =
+ ratesArray[rate5_5l] = targetPowerCck.tPow2x[2];
+ ratesArray[rate11s] =
+ ratesArray[rate11l] = targetPowerCck.tPow2x[3];
}
if (IS_CHAN_HT40(chan)) {
for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++)
@@ -821,28 +837,28 @@ static void ath9k_hw_set_AR9287_power_per_rate_table(struct ath_hw *ah,
ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0];
ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0];
ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0];
+
if (IS_CHAN_2GHZ(chan))
ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0];
}
+#undef CMP_CTL
+#undef CMP_NO_CTL
#undef REDUCE_SCALED_POWER_BY_TWO_CHAIN
#undef REDUCE_SCALED_POWER_BY_THREE_CHAIN
}
-static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
struct ath9k_channel *chan, u16 cfgCtl,
u8 twiceAntennaReduction,
u8 twiceMaxRegulatoryPower,
u8 powerLimit)
{
-#define INCREASE_MAXPOW_BY_TWO_CHAIN 6
-#define INCREASE_MAXPOW_BY_THREE_CHAIN 10
- struct ath_common *common = ath9k_hw_common(ah);
struct ath_regulatory *regulatory = ath9k_hw_regulatory(ah);
struct ar9287_eeprom *pEepData = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &pEepData->modalHeader;
int16_t ratesArray[Ar5416RateSize];
- int16_t txPowerIndexOffset = 0;
+ int16_t txPowerIndexOffset = 0;
u8 ht40PowerIncForPdadc = 2;
int i;
@@ -852,13 +868,13 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
AR9287_EEP_MINOR_VER_2)
ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc;
- ath9k_hw_set_AR9287_power_per_rate_table(ah, chan,
+ ath9k_hw_set_ar9287_power_per_rate_table(ah, chan,
&ratesArray[0], cfgCtl,
twiceAntennaReduction,
twiceMaxRegulatoryPower,
powerLimit);
- ath9k_hw_set_AR9287_power_cal_table(ah, chan, &txPowerIndexOffset);
+ ath9k_hw_set_ar9287_power_cal_table(ah, chan, &txPowerIndexOffset);
for (i = 0; i < ARRAY_SIZE(ratesArray); i++) {
ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]);
@@ -871,6 +887,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
}
+ /* OFDM power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE1,
ATH9K_POW_SM(ratesArray[rate18mb], 24)
| ATH9K_POW_SM(ratesArray[rate12mb], 16)
@@ -883,6 +900,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rate36mb], 8)
| ATH9K_POW_SM(ratesArray[rate24mb], 0));
+ /* CCK power per rate */
if (IS_CHAN_2GHZ(chan)) {
REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
ATH9K_POW_SM(ratesArray[rate2s], 24)
@@ -896,6 +914,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rate5_5l], 0));
}
+ /* HT20 power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
ATH9K_POW_SM(ratesArray[rateHt20_3], 24)
| ATH9K_POW_SM(ratesArray[rateHt20_2], 16)
@@ -908,8 +927,9 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateHt20_5], 8)
| ATH9K_POW_SM(ratesArray[rateHt20_4], 0));
+ /* HT40 power per rate */
if (IS_CHAN_HT40(chan)) {
- if (ath9k_hw_AR9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
+ if (ath9k_hw_ar9287_get_eeprom(ah, EEP_OL_PWRCTRL)) {
REG_WRITE(ah, AR_PHY_POWER_TX_RATE7,
ATH9K_POW_SM(ratesArray[rateHt40_3], 24)
| ATH9K_POW_SM(ratesArray[rateHt40_2], 16)
@@ -943,6 +963,7 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ht40PowerIncForPdadc, 0));
}
+ /* Dup/Ext power per rate */
REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
| ATH9K_POW_SM(ratesArray[rateExtCck], 16)
@@ -960,37 +981,20 @@ static void ath9k_hw_AR9287_set_txpower(struct ath_hw *ah,
ratesArray[i] + AR9287_PWR_TABLE_OFFSET_DB * 2;
else
regulatory->max_power_level = ratesArray[i];
-
- switch (ar5416_get_ntxchains(ah->txchainmask)) {
- case 1:
- break;
- case 2:
- regulatory->max_power_level +=
- INCREASE_MAXPOW_BY_TWO_CHAIN;
- break;
- case 3:
- regulatory->max_power_level +=
- INCREASE_MAXPOW_BY_THREE_CHAIN;
- break;
- default:
- ath_print(common, ATH_DBG_EEPROM,
- "Invalid chainmask configuration\n");
- break;
- }
}
-static void ath9k_hw_AR9287_set_addac(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
struct ath9k_channel *chan)
{
}
-static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
+static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
struct modal_eep_ar9287_header *pModal = &eep->modalHeader;
u16 antWrites[AR9287_ANT_16S];
- u32 regChainOffset;
+ u32 regChainOffset, regval;
u8 txRxAttenLocal;
int i, j, offset_num;
@@ -1077,42 +1081,37 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0,
AR_PHY_EXT_CCA0_THRESH62, pModal->thresh62);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB1,
- AR9287_AN_RF2G3_DB1_S, pModal->db1);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0, AR9287_AN_RF2G3_DB2,
- AR9287_AN_RF2G3_DB2_S, pModal->db2);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_CCK,
- AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_PSK,
- AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_QAM,
- AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH0,
- AR9287_AN_RF2G3_OB_PAL_OFF,
- AR9287_AN_RF2G3_OB_PAL_OFF_S,
- pModal->ob_pal_off);
-
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_DB1, AR9287_AN_RF2G3_DB1_S,
- pModal->db1);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1, AR9287_AN_RF2G3_DB2,
- AR9287_AN_RF2G3_DB2_S, pModal->db2);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_CCK,
- AR9287_AN_RF2G3_OB_CCK_S, pModal->ob_cck);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_PSK,
- AR9287_AN_RF2G3_OB_PSK_S, pModal->ob_psk);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_QAM,
- AR9287_AN_RF2G3_OB_QAM_S, pModal->ob_qam);
- ath9k_hw_analog_shift_rmw(ah, AR9287_AN_RF2G3_CH1,
- AR9287_AN_RF2G3_OB_PAL_OFF,
- AR9287_AN_RF2G3_OB_PAL_OFF_S,
- pModal->ob_pal_off);
+ regval = REG_READ(ah, AR9287_AN_RF2G3_CH0);
+ regval &= ~(AR9287_AN_RF2G3_DB1 |
+ AR9287_AN_RF2G3_DB2 |
+ AR9287_AN_RF2G3_OB_CCK |
+ AR9287_AN_RF2G3_OB_PSK |
+ AR9287_AN_RF2G3_OB_QAM |
+ AR9287_AN_RF2G3_OB_PAL_OFF);
+ regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+ SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+ SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+ SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+ SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+ SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+ ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH0, regval);
+
+ regval = REG_READ(ah, AR9287_AN_RF2G3_CH1);
+ regval &= ~(AR9287_AN_RF2G3_DB1 |
+ AR9287_AN_RF2G3_DB2 |
+ AR9287_AN_RF2G3_OB_CCK |
+ AR9287_AN_RF2G3_OB_PSK |
+ AR9287_AN_RF2G3_OB_QAM |
+ AR9287_AN_RF2G3_OB_PAL_OFF);
+ regval |= (SM(pModal->db1, AR9287_AN_RF2G3_DB1) |
+ SM(pModal->db2, AR9287_AN_RF2G3_DB2) |
+ SM(pModal->ob_cck, AR9287_AN_RF2G3_OB_CCK) |
+ SM(pModal->ob_psk, AR9287_AN_RF2G3_OB_PSK) |
+ SM(pModal->ob_qam, AR9287_AN_RF2G3_OB_QAM) |
+ SM(pModal->ob_pal_off, AR9287_AN_RF2G3_OB_PAL_OFF));
+
+ ath9k_hw_analog_shift_regwrite(ah, AR9287_AN_RF2G3_CH1, regval);
REG_RMW_FIELD(ah, AR_PHY_RF_CTL2,
AR_PHY_TX_END_DATA_START, pModal->txFrameToDataStart);
@@ -1125,13 +1124,13 @@ static void ath9k_hw_AR9287_set_board_values(struct ath_hw *ah,
pModal->xpaBiasLvl);
}
-static u8 ath9k_hw_AR9287_get_num_ant_config(struct ath_hw *ah,
+static u8 ath9k_hw_ar9287_get_num_ant_config(struct ath_hw *ah,
enum ieee80211_band freq_band)
{
return 1;
}
-static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
+static u16 ath9k_hw_ar9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
struct ath9k_channel *chan)
{
struct ar9287_eeprom *eep = &ah->eeprom.map9287;
@@ -1140,11 +1139,12 @@ static u16 ath9k_hw_AR9287_get_eeprom_antenna_cfg(struct ath_hw *ah,
return pModal->antCtrlCommon & 0xFFFF;
}
-static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
+static u16 ath9k_hw_ar9287_get_spur_channel(struct ath_hw *ah,
u16 i, bool is2GHz)
{
#define EEP_MAP9287_SPURCHAN \
(ah->eeprom.map9287.modalHeader.spurChans[i].spurChan)
+
struct ath_common *common = ath9k_hw_common(ah);
u16 spur_val = AR_NO_SPUR;
@@ -1171,15 +1171,15 @@ static u16 ath9k_hw_AR9287_get_spur_channel(struct ath_hw *ah,
}
const struct eeprom_ops eep_ar9287_ops = {
- .check_eeprom = ath9k_hw_AR9287_check_eeprom,
- .get_eeprom = ath9k_hw_AR9287_get_eeprom,
- .fill_eeprom = ath9k_hw_AR9287_fill_eeprom,
- .get_eeprom_ver = ath9k_hw_AR9287_get_eeprom_ver,
- .get_eeprom_rev = ath9k_hw_AR9287_get_eeprom_rev,
- .get_num_ant_config = ath9k_hw_AR9287_get_num_ant_config,
- .get_eeprom_antenna_cfg = ath9k_hw_AR9287_get_eeprom_antenna_cfg,
- .set_board_values = ath9k_hw_AR9287_set_board_values,
- .set_addac = ath9k_hw_AR9287_set_addac,
- .set_txpower = ath9k_hw_AR9287_set_txpower,
- .get_spur_channel = ath9k_hw_AR9287_get_spur_channel
+ .check_eeprom = ath9k_hw_ar9287_check_eeprom,
+ .get_eeprom = ath9k_hw_ar9287_get_eeprom,
+ .fill_eeprom = ath9k_hw_ar9287_fill_eeprom,
+ .get_eeprom_ver = ath9k_hw_ar9287_get_eeprom_ver,
+ .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev,
+ .get_num_ant_config = ath9k_hw_ar9287_get_num_ant_config,
+ .get_eeprom_antenna_cfg = ath9k_hw_ar9287_get_eeprom_antenna_cfg,
+ .set_board_values = ath9k_hw_ar9287_set_board_values,
+ .set_addac = ath9k_hw_ar9287_set_addac,
+ .set_txpower = ath9k_hw_ar9287_set_txpower,
+ .get_spur_channel = ath9k_hw_ar9287_get_spur_channel
};
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 7e1ed78d0e64..77b1433312cc 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -617,6 +617,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
int16_t minDelta = 0;
struct chan_centers centers;
+ memset(&minPwrT4, 0, AR9287_NUM_PD_GAINS);
ath9k_hw_get_channel_centers(ah, chan, &centers);
for (numPiers = 0; numPiers < availPiers; numPiers++) {
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 77b359162d6c..5f3ea7091ae0 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -16,12 +16,10 @@
#include "htc.h"
-#define ATH9K_FW_USB_DEV(devid, fw) \
- { USB_DEVICE(0x0cf3, devid), .driver_info = (unsigned long) fw }
-
static struct usb_device_id ath9k_hif_usb_ids[] = {
- ATH9K_FW_USB_DEV(0x9271, "ar9271.fw"),
- ATH9K_FW_USB_DEV(0x1006, "ar9271.fw"),
+ { USB_DEVICE(0x0cf3, 0x9271) },
+ { USB_DEVICE(0x0cf3, 0x1006) },
+ { USB_DEVICE(0x0cf3, 0x7010) },
{ },
};
@@ -756,6 +754,7 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
size_t len = hif_dev->firmware->size;
u32 addr = AR9271_FIRMWARE;
u8 *buf = kzalloc(4096, GFP_KERNEL);
+ u32 firm_offset;
if (!buf)
return -ENOMEM;
@@ -779,32 +778,37 @@ static int ath9k_hif_usb_download_fw(struct hif_device_usb *hif_dev)
}
kfree(buf);
+ if (hif_dev->device_id == 0x7010)
+ firm_offset = AR7010_FIRMWARE_TEXT;
+ else
+ firm_offset = AR9271_FIRMWARE_TEXT;
+
/*
* Issue FW download complete command to firmware.
*/
err = usb_control_msg(hif_dev->udev, usb_sndctrlpipe(hif_dev->udev, 0),
FIRMWARE_DOWNLOAD_COMP,
0x40 | USB_DIR_OUT,
- AR9271_FIRMWARE_TEXT >> 8, 0, NULL, 0, HZ);
+ firm_offset >> 8, 0, NULL, 0, HZ);
if (err)
return -EIO;
dev_info(&hif_dev->udev->dev, "ath9k_htc: Transferred FW: %s, size: %ld\n",
- "ar9271.fw", (unsigned long) hif_dev->firmware->size);
+ hif_dev->fw_name, (unsigned long) hif_dev->firmware->size);
return 0;
}
-static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
- const char *fw_name)
+static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev)
{
int ret;
/* Request firmware */
- ret = request_firmware(&hif_dev->firmware, fw_name, &hif_dev->udev->dev);
+ ret = request_firmware(&hif_dev->firmware, hif_dev->fw_name,
+ &hif_dev->udev->dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Firmware - %s not found\n", fw_name);
+ "ath9k_htc: Firmware - %s not found\n", hif_dev->fw_name);
goto err_fw_req;
}
@@ -820,7 +824,8 @@ static int ath9k_hif_usb_dev_init(struct hif_device_usb *hif_dev,
ret = ath9k_hif_usb_download_fw(hif_dev);
if (ret) {
dev_err(&hif_dev->udev->dev,
- "ath9k_htc: Firmware - %s download failed\n", fw_name);
+ "ath9k_htc: Firmware - %s download failed\n",
+ hif_dev->fw_name);
goto err_fw_download;
}
@@ -847,7 +852,6 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
{
struct usb_device *udev = interface_to_usbdev(interface);
struct hif_device_usb *hif_dev;
- const char *fw_name = (const char *) id->driver_info;
int ret = 0;
hif_dev = kzalloc(sizeof(struct hif_device_usb), GFP_KERNEL);
@@ -872,7 +876,29 @@ static int ath9k_hif_usb_probe(struct usb_interface *interface,
goto err_htc_hw_alloc;
}
- ret = ath9k_hif_usb_dev_init(hif_dev, fw_name);
+ /* Find out which firmware to load */
+
+ switch(hif_dev->device_id) {
+ case 0x9271:
+ case 0x1006:
+ hif_dev->fw_name = "ar9271.fw";
+ break;
+ case 0x7010:
+ if (le16_to_cpu(udev->descriptor.bcdDevice) == 0x0202)
+ hif_dev->fw_name = "ar7010_1_1.fw";
+ else
+ hif_dev->fw_name = "ar7010.fw";
+ break;
+ default:
+ break;
+ }
+
+ if (!hif_dev->fw_name) {
+ dev_err(&udev->dev, "Can't determine firmware !\n");
+ goto err_htc_hw_alloc;
+ }
+
+ ret = ath9k_hif_usb_dev_init(hif_dev);
if (ret) {
ret = -EINVAL;
goto err_hif_init_usb;
@@ -907,12 +933,10 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev)
void *buf;
int ret;
- buf = kmalloc(4, GFP_KERNEL);
+ buf = kmemdup(&reboot_cmd, 4, GFP_KERNEL);
if (!buf)
return;
- memcpy(buf, &reboot_cmd, 4);
-
ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, USB_REG_OUT_PIPE),
buf, 4, NULL, HZ);
if (ret)
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.h b/drivers/net/wireless/ath/ath9k/hif_usb.h
index 0aca49b6fcb6..2daf97b11c08 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.h
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.h
@@ -19,6 +19,7 @@
#define AR9271_FIRMWARE 0x501000
#define AR9271_FIRMWARE_TEXT 0x903000
+#define AR7010_FIRMWARE_TEXT 0x906000
#define FIRMWARE_DOWNLOAD 0x30
#define FIRMWARE_DOWNLOAD_COMP 0x31
@@ -90,6 +91,7 @@ struct hif_device_usb {
struct usb_anchor regout_submitted;
struct usb_anchor rx_submitted;
struct sk_buff *remain_skb;
+ const char *fw_name;
int rx_remain_len;
int rx_pkt_len;
int rx_transfer_len;
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index c251603ab032..051b8d89b9f2 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -257,12 +257,15 @@ struct ath9k_htc_tx_ctl {
#define TX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.tx_stats.c++)
#define RX_STAT_INC(c) (hif_dev->htc_handle->drv_priv->debug.rx_stats.c++)
+#define TX_QSTAT_INC(q) (priv->debug.tx_stats.queue_stats[q]++)
+
struct ath_tx_stats {
u32 buf_queued;
u32 buf_completed;
u32 skb_queued;
u32 skb_completed;
u32 skb_dropped;
+ u32 queue_stats[WME_NUM_AC];
};
struct ath_rx_stats {
@@ -286,6 +289,8 @@ struct ath9k_debug {
#define TX_STAT_INC(c) do { } while (0)
#define RX_STAT_INC(c) do { } while (0)
+#define TX_QSTAT_INC(c) do { } while (0)
+
#endif /* CONFIG_ATH9K_HTC_DEBUGFS */
#define ATH_LED_PIN_DEF 1
@@ -390,13 +395,14 @@ struct ath9k_htc_priv {
int led_off_duration;
int led_on_cnt;
int led_off_cnt;
+
+ int beaconq;
+ int cabq;
int hwq_map[ATH9K_WME_AC_VO+1];
#ifdef CONFIG_ATH9K_HTC_DEBUGFS
struct ath9k_debug debug;
#endif
- struct ath9k_htc_target_rate tgt_rate;
-
struct mutex mutex;
};
@@ -405,6 +411,7 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
common->bus_ops->read_cachesize(common, csz);
}
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv);
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif);
void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending);
@@ -426,6 +433,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb);
void ath9k_tx_cleanup(struct ath9k_htc_priv *priv);
bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
enum ath9k_tx_queue_subtype qtype);
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv);
int get_hw_qnum(u16 queue, int *hwq_map);
int ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum,
struct ath9k_tx_queue_info *qinfo);
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
index c10c7d002eb7..12a3bb0a9159 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
@@ -222,6 +222,29 @@ void ath9k_htc_swba(struct ath9k_htc_priv *priv, u8 beacon_pending)
spin_unlock_bh(&priv->beacon_lock);
}
+/* Currently, only for IBSS */
+void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
+{
+ struct ath_hw *ah = priv->ah;
+ struct ath9k_tx_queue_info qi, qi_be;
+ int qnum = priv->hwq_map[ATH9K_WME_AC_BE];
+
+ memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
+ memset(&qi_be, 0, sizeof(struct ath9k_tx_queue_info));
+
+ ath9k_hw_get_txq_props(ah, qnum, &qi_be);
+
+ qi.tqi_aifs = qi_be.tqi_aifs;
+ qi.tqi_cwmin = 4*qi_be.tqi_cwmin;
+ qi.tqi_cwmax = qi_be.tqi_cwmax;
+
+ if (!ath9k_hw_set_txq_props(ah, priv->beaconq, &qi)) {
+ ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
+ "Unable to update beacon queue %u!\n", qnum);
+ } else {
+ ath9k_hw_resettxqueue(ah, priv->beaconq);
+ }
+}
void ath9k_htc_beacon_config(struct ath9k_htc_priv *priv,
struct ieee80211_vif *vif)
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index dc015077a8d9..7339439f0bef 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -34,6 +34,13 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
.max_power = 20, \
}
+#define CHAN5G(_freq, _idx) { \
+ .band = IEEE80211_BAND_5GHZ, \
+ .center_freq = (_freq), \
+ .hw_value = (_idx), \
+ .max_power = 20, \
+}
+
static struct ieee80211_channel ath9k_2ghz_channels[] = {
CHAN2G(2412, 0), /* Channel 1 */
CHAN2G(2417, 1), /* Channel 2 */
@@ -51,6 +58,37 @@ static struct ieee80211_channel ath9k_2ghz_channels[] = {
CHAN2G(2484, 13), /* Channel 14 */
};
+static struct ieee80211_channel ath9k_5ghz_channels[] = {
+ /* _We_ call this UNII 1 */
+ CHAN5G(5180, 14), /* Channel 36 */
+ CHAN5G(5200, 15), /* Channel 40 */
+ CHAN5G(5220, 16), /* Channel 44 */
+ CHAN5G(5240, 17), /* Channel 48 */
+ /* _We_ call this UNII 2 */
+ CHAN5G(5260, 18), /* Channel 52 */
+ CHAN5G(5280, 19), /* Channel 56 */
+ CHAN5G(5300, 20), /* Channel 60 */
+ CHAN5G(5320, 21), /* Channel 64 */
+ /* _We_ call this "Middle band" */
+ CHAN5G(5500, 22), /* Channel 100 */
+ CHAN5G(5520, 23), /* Channel 104 */
+ CHAN5G(5540, 24), /* Channel 108 */
+ CHAN5G(5560, 25), /* Channel 112 */
+ CHAN5G(5580, 26), /* Channel 116 */
+ CHAN5G(5600, 27), /* Channel 120 */
+ CHAN5G(5620, 28), /* Channel 124 */
+ CHAN5G(5640, 29), /* Channel 128 */
+ CHAN5G(5660, 30), /* Channel 132 */
+ CHAN5G(5680, 31), /* Channel 136 */
+ CHAN5G(5700, 32), /* Channel 140 */
+ /* _We_ call this UNII 3 */
+ CHAN5G(5745, 33), /* Channel 149 */
+ CHAN5G(5765, 34), /* Channel 153 */
+ CHAN5G(5785, 35), /* Channel 157 */
+ CHAN5G(5805, 36), /* Channel 161 */
+ CHAN5G(5825, 37), /* Channel 165 */
+};
+
/* Atheros hardware rate code addition for short premble */
#define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04) : 0)
@@ -141,7 +179,7 @@ static inline int ath9k_htc_connect_svc(struct ath9k_htc_priv *priv,
return htc_connect_service(priv->htc, &req, ep_id);
}
-static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
+static int ath9k_init_htc_services(struct ath9k_htc_priv *priv, u16 devid)
{
int ret;
@@ -199,10 +237,33 @@ static int ath9k_init_htc_services(struct ath9k_htc_priv *priv)
if (ret)
goto err;
+ /*
+ * Setup required credits before initializing HTC.
+ * This is a bit hacky, but, since queuing is done in
+ * the HIF layer, shouldn't matter much.
+ */
+
+ switch(devid) {
+ case 0x9271:
+ case 0x1006:
+ priv->htc->credits = 33;
+ break;
+ case 0x7010:
+ priv->htc->credits = 45;
+ break;
+ default:
+ dev_err(priv->dev, "ath9k_htc: Unsupported device id: 0x%x\n",
+ devid);
+ goto err;
+ }
+
ret = htc_init(priv->htc);
if (ret)
goto err;
+ dev_info(priv->dev, "ath9k_htc: HTC initialized with %d credits\n",
+ priv->htc->credits);
+
return 0;
err:
@@ -398,17 +459,43 @@ static const struct ath_bus_ops ath9k_usb_bus_ops = {
static void setup_ht_cap(struct ath9k_htc_priv *priv,
struct ieee80211_sta_ht_cap *ht_info)
{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ u8 tx_streams, rx_streams;
+ int i;
+
ht_info->ht_supported = true;
ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_SM_PS |
IEEE80211_HT_CAP_SGI_40 |
IEEE80211_HT_CAP_DSSSCCK40;
+ if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
+ ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT);
+
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- ht_info->mcs.rx_mask[0] = 0xff;
+
+ /* ath9k_htc supports only 1 or 2 stream devices */
+ tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, 2);
+ rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, 2);
+
+ ath_print(common, ATH_DBG_CONFIG,
+ "TX streams %d, RX streams: %d\n",
+ tx_streams, rx_streams);
+
+ if (tx_streams != rx_streams) {
+ ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF;
+ ht_info->mcs.tx_params |= ((tx_streams - 1) <<
+ IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT);
+ }
+
+ for (i = 0; i < rx_streams; i++)
+ ht_info->mcs.rx_mask[i] = 0xff;
+
ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_DEFINED;
}
@@ -420,6 +507,20 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
for (i = 0; i < ARRAY_SIZE(priv->hwq_map); i++)
priv->hwq_map[i] = -1;
+ priv->beaconq = ath9k_hw_beaconq_setup(priv->ah);
+ if (priv->beaconq == -1) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup BEACON xmit queue\n");
+ goto err;
+ }
+
+ priv->cabq = ath9k_htc_cabq_setup(priv);
+ if (priv->cabq == -1) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to setup CAB xmit queue\n");
+ goto err;
+ }
+
if (!ath9k_htc_txq_setup(priv, ATH9K_WME_AC_BE)) {
ath_print(common, ATH_DBG_FATAL,
"Unable to setup xmit queue for BE traffic\n");
@@ -512,6 +613,17 @@ static void ath9k_init_channels_rates(struct ath9k_htc_priv *priv)
priv->sbands[IEEE80211_BAND_2GHZ].n_bitrates =
ARRAY_SIZE(ath9k_legacy_rates);
}
+
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes)) {
+ priv->sbands[IEEE80211_BAND_5GHZ].channels = ath9k_5ghz_channels;
+ priv->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ;
+ priv->sbands[IEEE80211_BAND_5GHZ].n_channels =
+ ARRAY_SIZE(ath9k_5ghz_channels);
+ priv->sbands[IEEE80211_BAND_5GHZ].bitrates =
+ ath9k_legacy_rates + 4;
+ priv->sbands[IEEE80211_BAND_5GHZ].n_bitrates =
+ ARRAY_SIZE(ath9k_legacy_rates) - 4;
+ }
}
static void ath9k_init_misc(struct ath9k_htc_priv *priv)
@@ -643,11 +755,17 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv,
if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&priv->sbands[IEEE80211_BAND_2GHZ];
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+ &priv->sbands[IEEE80211_BAND_5GHZ];
if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
if (test_bit(ATH9K_MODE_11G, priv->ah->caps.wireless_modes))
setup_ht_cap(priv,
&priv->sbands[IEEE80211_BAND_2GHZ].ht_cap);
+ if (test_bit(ATH9K_MODE_11A, priv->ah->caps.wireless_modes))
+ setup_ht_cap(priv,
+ &priv->sbands[IEEE80211_BAND_5GHZ].ht_cap);
}
SET_IEEE80211_PERM_ADDR(hw, common->macaddr);
@@ -747,7 +865,7 @@ int ath9k_htc_probe_device(struct htc_target *htc_handle, struct device *dev,
goto err_free;
}
- ret = ath9k_init_htc_services(priv);
+ ret = ath9k_init_htc_services(priv, devid);
if (ret)
goto err_init;
@@ -790,7 +908,8 @@ int ath9k_htc_resume(struct htc_target *htc_handle)
if (ret)
return ret;
- ret = ath9k_init_htc_services(htc_handle->drv_priv);
+ ret = ath9k_init_htc_services(htc_handle->drv_priv,
+ htc_handle->drv_priv->ah->hw_version.devid);
return ret;
}
#endif
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
index 9d371c18eb41..7aefbc638770 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c
@@ -325,133 +325,122 @@ static int ath9k_htc_update_cap_target(struct ath9k_htc_priv *priv)
tcap.flags_ext = 0x80601000;
tcap.ampdu_limit = 0xffff0000;
tcap.ampdu_subframes = 20;
- tcap.tx_chainmask_legacy = 1;
+ tcap.tx_chainmask_legacy = priv->ah->caps.tx_chainmask;
tcap.protmode = 1;
- tcap.tx_chainmask = 1;
+ tcap.tx_chainmask = priv->ah->caps.tx_chainmask;
WMI_CMD_BUF(WMI_TARGET_IC_UPDATE_CMDID, &tcap);
return ret;
}
-static int ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta)
+static void ath9k_htc_setup_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta,
+ struct ath9k_htc_target_rate *trate)
{
- struct ath_common *common = ath9k_hw_common(priv->ah);
struct ath9k_htc_sta *ista = (struct ath9k_htc_sta *) sta->drv_priv;
struct ieee80211_supported_band *sband;
- struct ath9k_htc_target_rate trate;
u32 caps = 0;
- u8 cmd_rsp;
- int i, j, ret;
-
- memset(&trate, 0, sizeof(trate));
+ int i, j;
- /* Only 2GHz is supported */
- sband = priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ];
+ sband = priv->hw->wiphy->bands[priv->hw->conf.channel->band];
for (i = 0, j = 0; i < sband->n_bitrates; i++) {
if (sta->supp_rates[sband->band] & BIT(i)) {
- priv->tgt_rate.rates.legacy_rates.rs_rates[j]
+ trate->rates.legacy_rates.rs_rates[j]
= (sband->bitrates[i].bitrate * 2) / 10;
j++;
}
}
- priv->tgt_rate.rates.legacy_rates.rs_nrates = j;
+ trate->rates.legacy_rates.rs_nrates = j;
if (sta->ht_cap.ht_supported) {
for (i = 0, j = 0; i < 77; i++) {
if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8)))
- priv->tgt_rate.rates.ht_rates.rs_rates[j++] = i;
+ trate->rates.ht_rates.rs_rates[j++] = i;
if (j == ATH_HTC_RATE_MAX)
break;
}
- priv->tgt_rate.rates.ht_rates.rs_nrates = j;
+ trate->rates.ht_rates.rs_nrates = j;
caps = WLAN_RC_HT_FLAG;
+ if (priv->ah->caps.tx_chainmask != 1 &&
+ ath9k_hw_getcapability(priv->ah, ATH9K_CAP_DS, 0, NULL)) {
+ if (sta->ht_cap.mcs.rx_mask[1])
+ caps |= WLAN_RC_DS_FLAG;
+ }
if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
caps |= WLAN_RC_40_FLAG;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+ if (conf_is_ht40(&priv->hw->conf) &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40))
+ caps |= WLAN_RC_SGI_FLAG;
+ else if (conf_is_ht20(&priv->hw->conf) &&
+ (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20))
caps |= WLAN_RC_SGI_FLAG;
-
}
- priv->tgt_rate.sta_index = ista->index;
- priv->tgt_rate.isnew = 1;
- trate = priv->tgt_rate;
- priv->tgt_rate.capflags = cpu_to_be32(caps);
- trate.capflags = cpu_to_be32(caps);
+ trate->sta_index = ista->index;
+ trate->isnew = 1;
+ trate->capflags = cpu_to_be32(caps);
+}
- WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
+static int ath9k_htc_send_rate_cmd(struct ath9k_htc_priv *priv,
+ struct ath9k_htc_target_rate *trate)
+{
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ int ret;
+ u8 cmd_rsp;
+
+ WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, trate);
if (ret) {
ath_print(common, ATH_DBG_FATAL,
"Unable to initialize Rate information on target\n");
- return ret;
}
- ath_print(common, ATH_DBG_CONFIG,
- "Updated target STA: %pM (caps: 0x%x)\n", sta->addr, caps);
- return 0;
+ return ret;
}
-static bool check_rc_update(struct ieee80211_hw *hw, bool *cw40)
+static void ath9k_htc_init_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_sta *sta)
{
- struct ath9k_htc_priv *priv = hw->priv;
- struct ieee80211_conf *conf = &hw->conf;
-
- if (!conf_is_ht(conf))
- return false;
-
- if (!(priv->op_flags & OP_ASSOCIATED) ||
- (priv->op_flags & OP_SCANNING))
- return false;
+ struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+ int ret;
- if (conf_is_ht40(conf)) {
- if (priv->ah->curchan->chanmode &
- (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)) {
- return false;
- } else {
- *cw40 = true;
- return true;
- }
- } else { /* ht20 */
- if (priv->ah->curchan->chanmode & CHANNEL_HT20)
- return false;
- else
- return true;
- }
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ ret = ath9k_htc_send_rate_cmd(priv, &trate);
+ if (!ret)
+ ath_print(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ sta->addr, be32_to_cpu(trate.capflags));
}
-static void ath9k_htc_rc_update(struct ath9k_htc_priv *priv, bool is_cw40)
+static void ath9k_htc_update_rate(struct ath9k_htc_priv *priv,
+ struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *bss_conf)
{
- struct ath9k_htc_target_rate trate;
struct ath_common *common = ath9k_hw_common(priv->ah);
+ struct ath9k_htc_target_rate trate;
+ struct ieee80211_sta *sta;
int ret;
- u32 caps = be32_to_cpu(priv->tgt_rate.capflags);
- u8 cmd_rsp;
-
- memset(&trate, 0, sizeof(trate));
- trate = priv->tgt_rate;
-
- if (is_cw40)
- caps |= WLAN_RC_40_FLAG;
- else
- caps &= ~WLAN_RC_40_FLAG;
+ memset(&trate, 0, sizeof(struct ath9k_htc_target_rate));
- priv->tgt_rate.capflags = cpu_to_be32(caps);
- trate.capflags = cpu_to_be32(caps);
-
- WMI_CMD_BUF(WMI_RC_RATE_UPDATE_CMDID, &trate);
- if (ret) {
- ath_print(common, ATH_DBG_FATAL,
- "Unable to update Rate information on target\n");
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, bss_conf->bssid);
+ if (!sta) {
+ rcu_read_unlock();
return;
}
+ ath9k_htc_setup_rate(priv, sta, &trate);
+ rcu_read_unlock();
- ath_print(common, ATH_DBG_CONFIG, "Rate control updated with "
- "caps:0x%x on target\n", priv->tgt_rate.capflags);
+ ret = ath9k_htc_send_rate_cmd(priv, &trate);
+ if (!ret)
+ ath_print(common, ATH_DBG_CONFIG,
+ "Updated target sta: %pM, rate caps: 0x%X\n",
+ bss_conf->bssid, be32_to_cpu(trate.capflags));
}
static int ath9k_htc_aggr_oper(struct ath9k_htc_priv *priv,
@@ -617,6 +606,19 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
"%20s : %10u\n", "SKBs dropped",
priv->debug.tx_stats.skb_dropped);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BE queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "BK queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VI queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+ len += snprintf(buf + len, sizeof(buf) - len,
+ "%20s : %10u\n", "VO queued",
+ priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1054,6 +1056,95 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv)
wiphy_rfkill_start_polling(priv->hw->wiphy);
}
+static void ath9k_htc_radio_enable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, false);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", ret, ah->curchan->channel);
+ }
+
+ ath_update_txpow(priv);
+
+ /* Start RX */
+ WMI_CMD(WMI_START_RECV_CMDID);
+ ath9k_host_rx_init(priv);
+
+ /* Start TX */
+ htc_start(priv->htc);
+ spin_lock_bh(&priv->tx_lock);
+ priv->tx_queues_stop = false;
+ spin_unlock_bh(&priv->tx_lock);
+ ieee80211_wake_queues(hw);
+
+ WMI_CMD(WMI_ENABLE_INTR_CMDID);
+
+ /* Enable LED */
+ ath9k_hw_cfg_output(ah, ah->led_pin,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(ah, ah->led_pin, 0);
+}
+
+static void ath9k_htc_radio_disable(struct ieee80211_hw *hw)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ struct ath_hw *ah = priv->ah;
+ struct ath_common *common = ath9k_hw_common(ah);
+ int ret;
+ u8 cmd_rsp;
+
+ ath9k_htc_ps_wakeup(priv);
+
+ /* Disable LED */
+ ath9k_hw_set_gpio(ah, ah->led_pin, 1);
+ ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
+
+ WMI_CMD(WMI_DISABLE_INTR_CMDID);
+
+ /* Stop TX */
+ ieee80211_stop_queues(hw);
+ htc_stop(priv->htc);
+ WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
+ skb_queue_purge(&priv->tx_queue);
+
+ /* Stop RX */
+ WMI_CMD(WMI_STOP_RECV_CMDID);
+
+ /*
+ * The MIB counters have to be disabled here,
+ * since the target doesn't do it.
+ */
+ ath9k_hw_disable_mib_counters(ah);
+
+ if (!ah->curchan)
+ ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+
+ /* Reset the HW */
+ ret = ath9k_hw_reset(ah, ah->curchan, false);
+ if (ret) {
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d "
+ "(freq %u MHz)\n", ret, ah->curchan->channel);
+ }
+
+ /* Disable the PHY */
+ ath9k_hw_phy_disable(ah);
+
+ ath9k_htc_ps_restore(priv);
+ ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+}
+
/**********************/
/* mac80211 Callbacks */
/**********************/
@@ -1099,7 +1190,7 @@ fail_tx:
return 0;
}
-static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
+static int ath9k_htc_start(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1111,10 +1202,16 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
__be16 htc_mode;
u8 cmd_rsp;
+ mutex_lock(&priv->mutex);
+
ath_print(common, ATH_DBG_CONFIG,
"Starting driver with initial channel: %d MHz\n",
curchan->center_freq);
+ /* Ensure that HW is awake before flushing RX */
+ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+ WMI_CMD(WMI_FLUSH_RECV_CMDID);
+
/* setup initial channel */
init_channel = ath9k_cmn_get_curchannel(hw, ah);
@@ -1127,6 +1224,7 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
ath_print(common, ATH_DBG_FATAL,
"Unable to reset hardware; reset status %d "
"(freq %u MHz)\n", ret, curchan->center_freq);
+ mutex_unlock(&priv->mutex);
return ret;
}
@@ -1147,31 +1245,14 @@ static int ath9k_htc_radio_enable(struct ieee80211_hw *hw, bool led)
priv->tx_queues_stop = false;
spin_unlock_bh(&priv->tx_lock);
- if (led) {
- /* Enable LED */
- ath9k_hw_cfg_output(ah, ah->led_pin,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(ah, ah->led_pin, 0);
- }
-
ieee80211_wake_queues(hw);
- return ret;
-}
-
-static int ath9k_htc_start(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
- int ret = 0;
-
- mutex_lock(&priv->mutex);
- ret = ath9k_htc_radio_enable(hw, false);
mutex_unlock(&priv->mutex);
return ret;
}
-static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
+static void ath9k_htc_stop(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
struct ath_hw *ah = priv->ah;
@@ -1179,17 +1260,14 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
int ret = 0;
u8 cmd_rsp;
+ mutex_lock(&priv->mutex);
+
if (priv->op_flags & OP_INVALID) {
ath_print(common, ATH_DBG_ANY, "Device not present\n");
+ mutex_unlock(&priv->mutex);
return;
}
- if (led) {
- /* Disable LED */
- ath9k_hw_set_gpio(ah, ah->led_pin, 1);
- ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
- }
-
/* Cancel all the running timers/work .. */
cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_ani_work);
@@ -1202,12 +1280,6 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
WMI_CMD(WMI_DISABLE_INTR_CMDID);
WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID);
WMI_CMD(WMI_STOP_RECV_CMDID);
- ath9k_hw_phy_disable(ah);
- ath9k_hw_disable(ah);
- ath9k_hw_configpcipowersave(ah, 1, 1);
- ath9k_htc_ps_restore(priv);
- ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
-
skb_queue_purge(&priv->tx_queue);
/* Remove monitor interface here */
@@ -1220,21 +1292,18 @@ static void ath9k_htc_radio_disable(struct ieee80211_hw *hw, bool led)
"Monitor interface removed\n");
}
+ ath9k_hw_phy_disable(ah);
+ ath9k_hw_disable(ah);
+ ath9k_hw_configpcipowersave(ah, 1, 1);
+ ath9k_htc_ps_restore(priv);
+ ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP);
+
priv->op_flags |= OP_INVALID;
ath_print(common, ATH_DBG_CONFIG, "Driver halt\n");
-}
-
-static void ath9k_htc_stop(struct ieee80211_hw *hw)
-{
- struct ath9k_htc_priv *priv = hw->priv;
-
- mutex_lock(&priv->mutex);
- ath9k_htc_radio_disable(hw, false);
mutex_unlock(&priv->mutex);
}
-
static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -1302,6 +1371,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
out:
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
+
return ret;
}
@@ -1318,6 +1388,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
memcpy(&hvif.myaddr, vif->addr, ETH_ALEN);
@@ -1328,6 +1399,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
ath9k_htc_remove_station(priv, vif, NULL);
priv->vif = NULL;
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1343,30 +1415,27 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
bool enable_radio = false;
bool idle = !!(conf->flags & IEEE80211_CONF_IDLE);
+ mutex_lock(&priv->htc_pm_lock);
if (!idle && priv->ps_idle)
enable_radio = true;
-
priv->ps_idle = idle;
+ mutex_unlock(&priv->htc_pm_lock);
if (enable_radio) {
- ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
- ath9k_htc_radio_enable(hw, true);
ath_print(common, ATH_DBG_CONFIG,
"not-idle: enabling radio\n");
+ ath9k_htc_setpower(priv, ATH9K_PM_AWAKE);
+ ath9k_htc_radio_enable(hw);
}
}
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
struct ieee80211_channel *curchan = hw->conf.channel;
int pos = curchan->hw_value;
- bool is_cw40 = false;
ath_print(common, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
curchan->center_freq);
- if (check_rc_update(hw, &is_cw40))
- ath9k_htc_rc_update(priv, is_cw40);
-
ath9k_cmn_update_ichannel(hw, &priv->ah->channels[pos]);
if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
@@ -1399,14 +1468,21 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
}
}
- if (priv->ps_idle) {
+ if (changed & IEEE80211_CONF_CHANGE_IDLE) {
+ mutex_lock(&priv->htc_pm_lock);
+ if (!priv->ps_idle) {
+ mutex_unlock(&priv->htc_pm_lock);
+ goto out;
+ }
+ mutex_unlock(&priv->htc_pm_lock);
+
ath_print(common, ATH_DBG_CONFIG,
"idle: disabling radio\n");
- ath9k_htc_radio_disable(hw, true);
+ ath9k_htc_radio_disable(hw);
}
+out:
mutex_unlock(&priv->mutex);
-
return 0;
}
@@ -1428,8 +1504,8 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
u32 rfilt;
mutex_lock(&priv->mutex);
-
ath9k_htc_ps_wakeup(priv);
+
changed_flags &= SUPPORTED_FILTERS;
*total_flags &= SUPPORTED_FILTERS;
@@ -1444,30 +1520,38 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw,
mutex_unlock(&priv->mutex);
}
-static void ath9k_htc_sta_notify(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- enum sta_notify_cmd cmd,
- struct ieee80211_sta *sta)
+static int ath9k_htc_sta_add(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
{
struct ath9k_htc_priv *priv = hw->priv;
int ret;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+ ret = ath9k_htc_add_station(priv, vif, sta);
+ if (!ret)
+ ath9k_htc_init_rate(priv, sta);
+ ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
- switch (cmd) {
- case STA_NOTIFY_ADD:
- ret = ath9k_htc_add_station(priv, vif, sta);
- if (!ret)
- ath9k_htc_init_rate(priv, vif, sta);
- break;
- case STA_NOTIFY_REMOVE:
- ath9k_htc_remove_station(priv, vif, sta);
- break;
- default:
- break;
- }
+ return ret;
+}
+static int ath9k_htc_sta_remove(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+{
+ struct ath9k_htc_priv *priv = hw->priv;
+ int ret;
+
+ mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
+ ret = ath9k_htc_remove_station(priv, vif, sta);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
+
+ return ret;
}
static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
@@ -1482,6 +1566,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
return 0;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
memset(&qi, 0, sizeof(struct ath9k_tx_queue_info));
@@ -1499,9 +1584,16 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, u16 queue,
params->cw_max, params->txop);
ret = ath_htc_txq_update(priv, qnum, &qi);
- if (ret)
+ if (ret) {
ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n");
+ goto out;
+ }
+ if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
+ (qnum == priv->hwq_map[ATH9K_WME_AC_BE]))
+ ath9k_htc_beaconq_config(priv);
+out:
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
return ret;
@@ -1574,7 +1666,6 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath_start_ani(priv);
} else {
priv->op_flags &= ~OP_ASSOCIATED;
- cancel_work_sync(&priv->ps_work);
cancel_delayed_work_sync(&priv->ath9k_ani_work);
}
}
@@ -1631,6 +1722,9 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
ath9k_hw_init_global_settings(ah);
}
+ if (changed & BSS_CHANGED_HT)
+ ath9k_htc_update_rate(priv, vif, bss_conf);
+
ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1641,7 +1735,9 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
u64 tsf;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
tsf = ath9k_hw_gettsf64(priv->ah);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
return tsf;
@@ -1652,7 +1748,9 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
struct ath9k_htc_priv *priv = hw->priv;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
ath9k_hw_settsf64(priv->ah, tsf);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1660,11 +1758,11 @@ static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
- ath9k_htc_ps_wakeup(priv);
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
ath9k_hw_reset_tsf(priv->ah);
- mutex_unlock(&priv->mutex);
ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
}
static int ath9k_htc_ampdu_action(struct ieee80211_hw *hw,
@@ -1722,8 +1820,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
{
struct ath9k_htc_priv *priv = hw->priv;
- ath9k_htc_ps_wakeup(priv);
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
spin_lock_bh(&priv->beacon_lock);
priv->op_flags &= ~OP_SCANNING;
spin_unlock_bh(&priv->beacon_lock);
@@ -1731,8 +1829,8 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw)
if (priv->op_flags & OP_ASSOCIATED)
ath9k_htc_beacon_config(priv, priv->vif);
ath_start_ani(priv);
- mutex_unlock(&priv->mutex);
ath9k_htc_ps_restore(priv);
+ mutex_unlock(&priv->mutex);
}
static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -1746,8 +1844,10 @@ static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw,
struct ath9k_htc_priv *priv = hw->priv;
mutex_lock(&priv->mutex);
+ ath9k_htc_ps_wakeup(priv);
priv->ah->coverage_class = coverage_class;
ath9k_hw_init_global_settings(priv->ah);
+ ath9k_htc_ps_restore(priv);
mutex_unlock(&priv->mutex);
}
@@ -1759,7 +1859,8 @@ struct ieee80211_ops ath9k_htc_ops = {
.remove_interface = ath9k_htc_remove_interface,
.config = ath9k_htc_config,
.configure_filter = ath9k_htc_configure_filter,
- .sta_notify = ath9k_htc_sta_notify,
+ .sta_add = ath9k_htc_sta_add,
+ .sta_remove = ath9k_htc_sta_remove,
.conf_tx = ath9k_htc_conf_tx,
.bss_info_changed = ath9k_htc_bss_info_changed,
.set_key = ath9k_htc_set_key,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
index 2571b443ac82..f0cca4e36f7d 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
@@ -20,6 +20,16 @@
/* TX */
/******/
+#define ATH9K_HTC_INIT_TXQ(subtype) do { \
+ qi.tqi_subtype = subtype; \
+ qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \
+ qi.tqi_physCompBuf = 0; \
+ qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \
+ TXQ_FLAG_TXDESCINT_ENABLE; \
+ } while (0)
+
int get_hw_qnum(u16 queue, int *hwq_map)
{
switch (queue) {
@@ -71,7 +81,7 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
struct ath9k_htc_vif *avp;
struct ath9k_htc_tx_ctl tx_ctl;
enum htc_endpoint_id epid;
- u16 qnum, hw_qnum;
+ u16 qnum;
__le16 fc;
u8 *tx_fhdr;
u8 sta_idx;
@@ -131,20 +141,23 @@ int ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb)
memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr));
qnum = skb_get_queue_mapping(skb);
- hw_qnum = get_hw_qnum(qnum, priv->hwq_map);
- switch (hw_qnum) {
+ switch (qnum) {
case 0:
- epid = priv->data_be_ep;
+ TX_QSTAT_INC(WME_AC_VO);
+ epid = priv->data_vo_ep;
break;
- case 2:
+ case 1:
+ TX_QSTAT_INC(WME_AC_VI);
epid = priv->data_vi_ep;
break;
- case 3:
- epid = priv->data_vo_ep;
+ case 2:
+ TX_QSTAT_INC(WME_AC_BE);
+ epid = priv->data_be_ep;
break;
- case 1:
+ case 3:
default:
+ TX_QSTAT_INC(WME_AC_BK);
epid = priv->data_bk_ep;
break;
}
@@ -293,13 +306,7 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
int qnum;
memset(&qi, 0, sizeof(qi));
-
- qi.tqi_subtype = subtype;
- qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
- qi.tqi_physCompBuf = 0;
- qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE;
+ ATH9K_HTC_INIT_TXQ(subtype);
qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi);
if (qnum == -1)
@@ -317,6 +324,16 @@ bool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv,
return true;
}
+int ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv)
+{
+ struct ath9k_tx_queue_info qi;
+
+ memset(&qi, 0, sizeof(qi));
+ ATH9K_HTC_INIT_TXQ(0);
+
+ return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi);
+}
+
/******/
/* RX */
/******/
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index 064397fd738e..705c0f342e1c 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -89,7 +89,6 @@ static void htc_process_target_rdy(struct htc_target *target,
struct htc_endpoint *endpoint;
struct htc_ready_msg *htc_ready_msg = (struct htc_ready_msg *) buf;
- target->credits = be16_to_cpu(htc_ready_msg->credits);
target->credit_size = be16_to_cpu(htc_ready_msg->credit_size);
endpoint = &target->endpoint[ENDPOINT0];
@@ -159,7 +158,7 @@ static int htc_config_pipe_credits(struct htc_target *target)
cp_msg->message_id = cpu_to_be16(HTC_MSG_CONFIG_PIPE_ID);
cp_msg->pipe_id = USB_WLAN_TX_PIPE;
- cp_msg->credits = 28;
+ cp_msg->credits = target->credits;
target->htc_flags |= HTC_OP_CONFIG_PIPE_CREDITS;
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index c33f17dbe6f1..2adc7e78cebf 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -392,12 +392,6 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
ah->config.rx_intr_mitigation = true;
/*
- * Tx IQ Calibration (ah->config.tx_iq_calibration) is only
- * used by AR9003, but it is showing reliability issues.
- * It will take a while to fix so this is currently disabled.
- */
-
- /*
* We need this for PCI devices only (Cardbus, PCI, miniPCI)
* _and_ if on non-uniprocessor systems (Multiprocessor/HT).
* This means we use it for all AR5416 devices, and the few
@@ -627,6 +621,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
ar9003_hw_set_nf_limits(ah);
ath9k_init_nfcal_hist_buffer(ah);
+ ah->bb_watchdog_timeout_ms = 25;
common->state = ATH_HW_INITIALIZED;
@@ -1303,6 +1298,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9280_10_OR_LATER(ah))
REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, AR_GPIO_JTAG_DISABLE);
+ if (!AR_SREV_9300_20_OR_LATER(ah))
+ ar9002_hw_enable_async_fifo(ah);
+
r = ath9k_hw_process_ini(ah, chan);
if (r)
return r;
@@ -1375,7 +1373,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
ath9k_hw_init_global_settings(ah);
if (!AR_SREV_9300_20_OR_LATER(ah)) {
- ar9002_hw_enable_async_fifo(ah);
+ ar9002_hw_update_async_fifo(ah);
ar9002_hw_enable_wep_aggregation(ah);
}
@@ -1426,9 +1424,13 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
"Setting CFG 0x%x\n", REG_READ(ah, AR_CFG));
}
} else {
- /* Configure AR9271 target WLAN */
- if (AR_SREV_9271(ah))
- REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ if (common->bus_ops->ath_bus_type == ATH_USB) {
+ /* Configure AR9271 target WLAN */
+ if (AR_SREV_9271(ah))
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB);
+ else
+ REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
+ }
#ifdef __BIG_ENDIAN
else
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -1441,6 +1443,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (AR_SREV_9300_20_OR_LATER(ah)) {
ath9k_hw_loadnf(ah, curchan);
ath9k_hw_start_nfcal(ah);
+ ar9003_hw_bb_watchdog_config(ah);
}
return 0;
@@ -1489,6 +1492,7 @@ EXPORT_SYMBOL(ath9k_hw_keyreset);
bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
{
u32 macHi, macLo;
+ u32 unicast_flag = AR_KEYTABLE_VALID;
if (entry >= ah->caps.keycache_size) {
ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL,
@@ -1497,6 +1501,16 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
}
if (mac != NULL) {
+ /*
+ * AR_KEYTABLE_VALID indicates that the address is a unicast
+ * address, which must match the transmitter address for
+ * decrypting frames.
+ * Not setting this bit allows the hardware to use the key
+ * for multicast frame decryption.
+ */
+ if (mac[0] & 0x01)
+ unicast_flag = 0;
+
macHi = (mac[5] << 8) | mac[4];
macLo = (mac[3] << 24) |
(mac[2] << 16) |
@@ -1509,7 +1523,7 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
macLo = macHi = 0;
}
REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo);
- REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID);
+ REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | unicast_flag);
return true;
}
@@ -2165,7 +2179,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT;
}
#endif
- if (AR_SREV_9271(ah))
+ if (AR_SREV_9271(ah) || AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP;
else
pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP;
@@ -2232,6 +2246,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
+ if (AR_SREV_9287_10_OR_LATER(ah) || AR_SREV_9271(ah))
+ pCap->hw_caps |= ATH9K_HW_CAP_SGI_20;
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 77245dff5993..88bf2fca3736 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -199,6 +199,7 @@ enum ath9k_hw_caps {
ATH9K_HW_CAP_RAC_SUPPORTED = BIT(18),
ATH9K_HW_CAP_LDPC = BIT(19),
ATH9K_HW_CAP_FASTCLOCK = BIT(20),
+ ATH9K_HW_CAP_SGI_20 = BIT(21),
};
enum ath9k_capability_type {
@@ -262,7 +263,6 @@ struct ath9k_ops_config {
#define AR_BASE_FREQ_5GHZ 4900
#define AR_SPUR_FEEQ_BOUND_HT40 19
#define AR_SPUR_FEEQ_BOUND_HT20 10
- bool tx_iq_calibration; /* Only available for >= AR9003 */
int spurmode;
u16 spurchans[AR_EEPROM_MODAL_SPURS][2];
u8 max_txtrig_level;
@@ -279,6 +279,7 @@ enum ath9k_int {
ATH9K_INT_TX = 0x00000040,
ATH9K_INT_TXDESC = 0x00000080,
ATH9K_INT_TIM_TIMER = 0x00000100,
+ ATH9K_INT_BB_WATCHDOG = 0x00000400,
ATH9K_INT_TXURN = 0x00000800,
ATH9K_INT_MIB = 0x00001000,
ATH9K_INT_RXPHY = 0x00004000,
@@ -459,7 +460,7 @@ struct ath9k_hw_version {
#define AR_GENTMR_BIT(_index) (1 << (_index))
/*
- * Using de Bruijin sequence to to look up 1's index in a 32 bit number
+ * Using de Bruijin sequence to look up 1's index in a 32 bit number
* debruijn32 = 0000 0111 0111 1100 1011 0101 0011 0001
*/
#define debruijn32 0x077CB531U
@@ -789,6 +790,9 @@ struct ath_hw {
u32 ts_paddr_end;
u16 ts_tail;
u8 ts_size;
+
+ u32 bb_watchdog_last_status;
+ u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
};
static inline struct ath_common *ath9k_hw_common(struct ath_hw *ah)
@@ -907,13 +911,17 @@ void ath9k_hw_get_delta_slope_vals(struct ath_hw *ah, u32 coef_scaled,
void ar9002_hw_cck_chan14_spread(struct ath_hw *ah);
int ar9002_hw_rf_claim(struct ath_hw *ah);
void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
+void ar9002_hw_update_async_fifo(struct ath_hw *ah);
void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
/*
- * Code specifric to AR9003, we stuff these here to avoid callbacks
+ * Code specific to AR9003, we stuff these here to avoid callbacks
* for older families
*/
void ar9003_hw_set_nf_limits(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
+void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
/* Hardware family op attach helpers */
void ar5008_hw_attach_phy_ops(struct ath_hw *ah);
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d457cb3bd772..18d76ede859d 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -175,18 +175,6 @@ static const struct ath_ops ath9k_common_ops = {
.write = ath9k_iowrite32,
};
-static int count_streams(unsigned int chainmask, int max)
-{
- int streams = 0;
-
- do {
- if (++streams == max)
- break;
- } while ((chainmask = chainmask & (chainmask - 1)));
-
- return streams;
-}
-
/**************************/
/* Initialization */
/**************************/
@@ -208,6 +196,9 @@ static void setup_ht_cap(struct ath_softc *sc,
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_LDPC)
ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING;
+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ ht_info->cap |= IEEE80211_HT_CAP_SGI_20;
+
ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
@@ -224,8 +215,8 @@ static void setup_ht_cap(struct ath_softc *sc,
/* set up supported mcs set */
memset(&ht_info->mcs, 0, sizeof(ht_info->mcs));
- tx_streams = count_streams(common->tx_chainmask, max_streams);
- rx_streams = count_streams(common->rx_chainmask, max_streams);
+ tx_streams = ath9k_cmn_count_streams(common->tx_chainmask, max_streams);
+ rx_streams = ath9k_cmn_count_streams(common->rx_chainmask, max_streams);
ath_print(common, ATH_DBG_CONFIG,
"TX streams %d, RX streams: %d\n",
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index abfa0493236f..b8b76dd2c11e 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -520,6 +520,12 @@ irqreturn_t ath_isr(int irq, void *dev)
!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
goto chip_reset;
+ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
+ (status & ATH9K_INT_BB_WATCHDOG)) {
+ ar9003_hw_bb_watchdog_dbg_info(ah);
+ goto chip_reset;
+ }
+
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
@@ -615,234 +621,6 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
return chanmode;
}
-static int ath_setkey_tkip(struct ath_common *common, u16 keyix, const u8 *key,
- struct ath9k_keyval *hk, const u8 *addr,
- bool authenticator)
-{
- struct ath_hw *ah = common->ah;
- const u8 *key_rxmic;
- const u8 *key_txmic;
-
- key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY;
- key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
-
- if (addr == NULL) {
- /*
- * Group key installation - only two key cache entries are used
- * regardless of splitmic capability since group key is only
- * used either for TX or RX.
- */
- if (authenticator) {
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
- } else {
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
- }
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
- if (!common->splitmic) {
- /* TX and RX keys share the same key cache entry. */
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
- return ath9k_hw_set_keycache_entry(ah, keyix, hk, addr);
- }
-
- /* Separate key cache entries for TX and RX */
-
- /* TX key goes at first index, RX key at +32. */
- memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
- if (!ath9k_hw_set_keycache_entry(ah, keyix, hk, NULL)) {
- /* TX MIC entry failed. No need to proceed further */
- ath_print(common, ATH_DBG_FATAL,
- "Setting TX MIC Key Failed\n");
- return 0;
- }
-
- memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
- /* XXX delete tx key on failure? */
- return ath9k_hw_set_keycache_entry(ah, keyix + 32, hk, addr);
-}
-
-static int ath_reserve_key_cache_slot_tkip(struct ath_common *common)
-{
- int i;
-
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap))
- continue; /* At least one part of TKIP key allocated */
- if (common->splitmic &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- continue; /* At least one part of TKIP key allocated */
-
- /* Found a free slot for a TKIP key */
- return i;
- }
- return -1;
-}
-
-static int ath_reserve_key_cache_slot(struct ath_common *common)
-{
- int i;
-
- /* First, try to find slots that would not be available for TKIP. */
- if (common->splitmic) {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 4; i++) {
- if (!test_bit(i, common->keymap) &&
- (test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i;
- if (!test_bit(i + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 64, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 32;
- if (!test_bit(i + 64, common->keymap) &&
- (test_bit(i , common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64 + 32, common->keymap)))
- return i + 64;
- if (!test_bit(i + 64 + 32, common->keymap) &&
- (test_bit(i, common->keymap) ||
- test_bit(i + 32, common->keymap) ||
- test_bit(i + 64, common->keymap)))
- return i + 64 + 32;
- }
- } else {
- for (i = IEEE80211_WEP_NKID; i < common->keymax / 2; i++) {
- if (!test_bit(i, common->keymap) &&
- test_bit(i + 64, common->keymap))
- return i;
- if (test_bit(i, common->keymap) &&
- !test_bit(i + 64, common->keymap))
- return i + 64;
- }
- }
-
- /* No partially used TKIP slots, pick any available slot */
- for (i = IEEE80211_WEP_NKID; i < common->keymax; i++) {
- /* Do not allow slots that could be needed for TKIP group keys
- * to be used. This limitation could be removed if we know that
- * TKIP will not be used. */
- if (i >= 64 && i < 64 + IEEE80211_WEP_NKID)
- continue;
- if (common->splitmic) {
- if (i >= 32 && i < 32 + IEEE80211_WEP_NKID)
- continue;
- if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID)
- continue;
- }
-
- if (!test_bit(i, common->keymap))
- return i; /* Found a free slot for a key */
- }
-
- /* No free slot found */
- return -1;
-}
-
-static int ath_key_config(struct ath_common *common,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key)
-{
- struct ath_hw *ah = common->ah;
- struct ath9k_keyval hk;
- const u8 *mac = NULL;
- int ret = 0;
- int idx;
-
- memset(&hk, 0, sizeof(hk));
-
- switch (key->alg) {
- case ALG_WEP:
- hk.kv_type = ATH9K_CIPHER_WEP;
- break;
- case ALG_TKIP:
- hk.kv_type = ATH9K_CIPHER_TKIP;
- break;
- case ALG_CCMP:
- hk.kv_type = ATH9K_CIPHER_AES_CCM;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- hk.kv_len = key->keylen;
- memcpy(hk.kv_val, key->key, key->keylen);
-
- if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
- /* For now, use the default keys for broadcast keys. This may
- * need to change with virtual interfaces. */
- idx = key->keyidx;
- } else if (key->keyidx) {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- if (vif->type != NL80211_IFTYPE_AP) {
- /* Only keyidx 0 should be used with unicast key, but
- * allow this for client mode for now. */
- idx = key->keyidx;
- } else
- return -EIO;
- } else {
- if (WARN_ON(!sta))
- return -EOPNOTSUPP;
- mac = sta->addr;
-
- if (key->alg == ALG_TKIP)
- idx = ath_reserve_key_cache_slot_tkip(common);
- else
- idx = ath_reserve_key_cache_slot(common);
- if (idx < 0)
- return -ENOSPC; /* no free key cache entries */
- }
-
- if (key->alg == ALG_TKIP)
- ret = ath_setkey_tkip(common, idx, key->key, &hk, mac,
- vif->type == NL80211_IFTYPE_AP);
- else
- ret = ath9k_hw_set_keycache_entry(ah, idx, &hk, mac);
-
- if (!ret)
- return -EIO;
-
- set_bit(idx, common->keymap);
- if (key->alg == ALG_TKIP) {
- set_bit(idx + 64, common->keymap);
- if (common->splitmic) {
- set_bit(idx + 32, common->keymap);
- set_bit(idx + 64 + 32, common->keymap);
- }
- }
-
- return idx;
-}
-
-static void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key)
-{
- struct ath_hw *ah = common->ah;
-
- ath9k_hw_keyreset(ah, key->hw_key_idx);
- if (key->hw_key_idx < IEEE80211_WEP_NKID)
- return;
-
- clear_bit(key->hw_key_idx, common->keymap);
- if (key->alg != ALG_TKIP)
- return;
-
- clear_bit(key->hw_key_idx + 64, common->keymap);
- if (common->splitmic) {
- ath9k_hw_keyreset(ah, key->hw_key_idx + 32);
- clear_bit(key->hw_key_idx + 32, common->keymap);
- clear_bit(key->hw_key_idx + 64 + 32, common->keymap);
- }
-}
-
static void ath9k_bss_assoc_info(struct ath_softc *sc,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf)
@@ -1195,7 +973,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
ATH9K_INT_GLOBAL;
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
- ah->imask |= ATH9K_INT_RXHP | ATH9K_INT_RXLP;
+ ah->imask |= ATH9K_INT_RXHP |
+ ATH9K_INT_RXLP |
+ ATH9K_INT_BB_WATCHDOG;
else
ah->imask |= ATH9K_INT_RX;
@@ -1245,6 +1025,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
struct ath_tx_control txctl;
int padpos, padsize;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ int qnum;
if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
ath_print(common, ATH_DBG_XMIT,
@@ -1274,7 +1055,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
* completed and if needed, also for RX of buffered frames.
*/
ath9k_ps_wakeup(sc);
- ath9k_hw_setrxabort(sc->sc_ah, 0);
+ if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
+ ath9k_hw_setrxabort(sc->sc_ah, 0);
if (ieee80211_is_pspoll(hdr->frame_control)) {
ath_print(common, ATH_DBG_PS,
"Sending PS-Poll to pick a buffered frame\n");
@@ -1316,11 +1098,8 @@ static int ath9k_tx(struct ieee80211_hw *hw,
memmove(skb->data, skb->data + padsize, padpos);
}
- /* Check if a tx queue is available */
-
- txctl.txq = ath_test_get_txq(sc, skb);
- if (!txctl.txq)
- goto exit;
+ qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ txctl.txq = &sc->tx.txq[qnum];
ath_print(common, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
@@ -1538,8 +1317,8 @@ void ath9k_enable_ps(struct ath_softc *sc)
ah->imask |= ATH9K_INT_TIM_TIMER;
ath9k_hw_set_interrupts(ah, ah->imask);
}
+ ath9k_hw_setrxabort(ah, 1);
}
- ath9k_hw_setrxabort(ah, 1);
}
static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
@@ -1804,7 +1583,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
switch (cmd) {
case SET_KEY:
- ret = ath_key_config(common, vif, sta, key);
+ ret = ath9k_cmn_key_config(common, vif, sta, key);
if (ret >= 0) {
key->hw_key_idx = ret;
/* push IV and Michael MIC generation to stack */
@@ -1817,7 +1596,7 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
}
break;
case DISABLE_KEY:
- ath_key_delete(common, key);
+ ath9k_cmn_key_delete(common, key);
break;
default:
ret = -EINVAL;
diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c
index 8519452c95f1..02b605273ca5 100644
--- a/drivers/net/wireless/ath/ath9k/rc.c
+++ b/drivers/net/wireless/ath/ath9k/rc.c
@@ -20,7 +20,7 @@
#include "ath9k.h"
static const struct ath_rate_table ar5416_11na_ratetable = {
- 42,
+ 43,
8, /* MCS start */
{
{ VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
@@ -40,73 +40,75 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
29300, 7, 108, 4, 7, 7, 7, 7 },
{ VALID_2040, VALID_2040, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
- 6400, 0, 0, 0, 8, 24, 8, 24 },
+ 6400, 0, 0, 0, 8, 25, 8, 25 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
- 12700, 1, 1, 2, 9, 25, 9, 25 },
+ 12700, 1, 1, 2, 9, 26, 9, 26 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
- 18800, 2, 2, 2, 10, 26, 10, 26 },
+ 18800, 2, 2, 2, 10, 27, 10, 27 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
- 25000, 3, 3, 4, 11, 27, 11, 27 },
+ 25000, 3, 3, 4, 11, 28, 11, 28 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
- 36700, 4, 4, 4, 12, 28, 12, 28 },
+ 36700, 4, 4, 4, 12, 29, 12, 29 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
- 48100, 5, 5, 4, 13, 29, 13, 29 },
+ 48100, 5, 5, 4, 13, 30, 13, 30 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
- 53500, 6, 6, 4, 14, 30, 14, 30 },
+ 53500, 6, 6, 4, 14, 31, 14, 31 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
- 59000, 7, 7, 4, 15, 31, 15, 32 },
+ 59000, 7, 7, 4, 15, 32, 15, 33 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
- 12700, 8, 8, 3, 16, 33, 16, 33 },
+ 12700, 8, 8, 3, 16, 34, 16, 34 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
- 24800, 9, 9, 2, 17, 34, 17, 34 },
+ 24800, 9, 9, 2, 17, 35, 17, 35 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
- 36600, 10, 10, 2, 18, 35, 18, 35 },
+ 36600, 10, 10, 2, 18, 36, 18, 36 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
- 48100, 11, 11, 4, 19, 36, 19, 36 },
+ 48100, 11, 11, 4, 19, 37, 19, 37 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
- 69500, 12, 12, 4, 20, 37, 20, 37 },
+ 69500, 12, 12, 4, 20, 38, 20, 38 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
- 89500, 13, 13, 4, 21, 38, 21, 38 },
+ 89500, 13, 13, 4, 21, 39, 21, 39 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
- 98900, 14, 14, 4, 22, 39, 22, 39 },
+ 98900, 14, 14, 4, 22, 40, 22, 40 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
- 108300, 15, 15, 4, 23, 40, 23, 41 },
+ 108300, 15, 15, 4, 23, 41, 24, 42 },
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS_HGI, 144400, /* 144.4 Mb */
+ 12000, 15, 15, 4, 23, 41, 24, 42 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
- 13200, 0, 0, 0, 8, 24, 24, 24 },
+ 13200, 0, 0, 0, 8, 25, 25, 25 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
- 25900, 1, 1, 2, 9, 25, 25, 25 },
+ 25900, 1, 1, 2, 9, 26, 26, 26 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
- 38600, 2, 2, 2, 10, 26, 26, 26 },
+ 38600, 2, 2, 2, 10, 27, 27, 27 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
- 49800, 3, 3, 4, 11, 27, 27, 27 },
+ 49800, 3, 3, 4, 11, 28, 28, 28 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
- 72200, 4, 4, 4, 12, 28, 28, 28 },
+ 72200, 4, 4, 4, 12, 29, 29, 29 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
- 92900, 5, 5, 4, 13, 29, 29, 29 },
+ 92900, 5, 5, 4, 13, 30, 30, 30 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
- 102700, 6, 6, 4, 14, 30, 30, 30 },
+ 102700, 6, 6, 4, 14, 31, 31, 31 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
- 112000, 7, 7, 4, 15, 31, 32, 32 },
+ 112000, 7, 7, 4, 15, 32, 33, 33 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
- 122000, 7, 7, 4, 15, 31, 32, 32 },
+ 122000, 7, 7, 4, 15, 32, 33, 33 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
- 25800, 8, 8, 0, 16, 33, 33, 33 },
+ 25800, 8, 8, 0, 16, 34, 34, 34 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
- 49800, 9, 9, 2, 17, 34, 34, 34 },
+ 49800, 9, 9, 2, 17, 35, 35, 35 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
- 71900, 10, 10, 2, 18, 35, 35, 35 },
+ 71900, 10, 10, 2, 18, 36, 36, 36 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
- 92500, 11, 11, 4, 19, 36, 36, 36 },
+ 92500, 11, 11, 4, 19, 37, 37, 37 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
- 130300, 12, 12, 4, 20, 37, 37, 37 },
+ 130300, 12, 12, 4, 20, 38, 38, 38 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
- 162800, 13, 13, 4, 21, 38, 38, 38 },
+ 162800, 13, 13, 4, 21, 39, 39, 39 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
- 178200, 14, 14, 4, 22, 39, 39, 39 },
+ 178200, 14, 14, 4, 22, 40, 40, 40 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
- 192100, 15, 15, 4, 23, 40, 41, 41 },
+ 192100, 15, 15, 4, 23, 41, 42, 42 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
- 207000, 15, 15, 4, 23, 40, 41, 41 },
+ 207000, 15, 15, 4, 23, 41, 42, 42 },
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
@@ -116,7 +118,7 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
* for HT are the 64K max aggregate limit */
static const struct ath_rate_table ar5416_11ng_ratetable = {
- 46,
+ 47,
12, /* MCS start */
{
{ VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
@@ -144,73 +146,75 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
{ VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
30900, 11, 108, 8, 11, 11, 11, 11 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */
- 6400, 0, 0, 4, 12, 28, 12, 28 },
+ 6400, 0, 0, 4, 12, 29, 12, 29 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */
- 12700, 1, 1, 6, 13, 29, 13, 29 },
+ 12700, 1, 1, 6, 13, 30, 13, 30 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */
- 18800, 2, 2, 6, 14, 30, 14, 30 },
+ 18800, 2, 2, 6, 14, 31, 14, 31 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */
- 25000, 3, 3, 8, 15, 31, 15, 31 },
+ 25000, 3, 3, 8, 15, 32, 15, 32 },
{ VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */
- 36700, 4, 4, 8, 16, 32, 16, 32 },
+ 36700, 4, 4, 8, 16, 33, 16, 33 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */
- 48100, 5, 5, 8, 17, 33, 17, 33 },
+ 48100, 5, 5, 8, 17, 34, 17, 34 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */
- 53500, 6, 6, 8, 18, 34, 18, 34 },
+ 53500, 6, 6, 8, 18, 35, 18, 35 },
{ INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */
- 59000, 7, 7, 8, 19, 35, 19, 36 },
+ 59000, 7, 7, 8, 19, 36, 19, 37 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */
- 12700, 8, 8, 4, 20, 37, 20, 37 },
+ 12700, 8, 8, 4, 20, 38, 20, 38 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */
- 24800, 9, 9, 6, 21, 38, 21, 38 },
+ 24800, 9, 9, 6, 21, 39, 21, 39 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */
- 36600, 10, 10, 6, 22, 39, 22, 39 },
+ 36600, 10, 10, 6, 22, 40, 22, 40 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */
- 48100, 11, 11, 8, 23, 40, 23, 40 },
+ 48100, 11, 11, 8, 23, 41, 23, 41 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */
- 69500, 12, 12, 8, 24, 41, 24, 41 },
+ 69500, 12, 12, 8, 24, 42, 24, 42 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */
- 89500, 13, 13, 8, 25, 42, 25, 42 },
+ 89500, 13, 13, 8, 25, 43, 25, 43 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */
- 98900, 14, 14, 8, 26, 43, 26, 44 },
+ 98900, 14, 14, 8, 26, 44, 26, 44 },
{ VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */
- 108300, 15, 15, 8, 27, 44, 27, 45 },
+ 108300, 15, 15, 8, 27, 45, 28, 46 },
+ { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS_HGI, 144400, /* 130 Mb */
+ 120000, 15, 15, 8, 27, 45, 28, 46 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */
- 13200, 0, 0, 8, 12, 28, 28, 28 },
+ 13200, 0, 0, 8, 12, 29, 29, 29 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */
- 25900, 1, 1, 8, 13, 29, 29, 29 },
+ 25900, 1, 1, 8, 13, 30, 30, 30 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */
- 38600, 2, 2, 8, 14, 30, 30, 30 },
+ 38600, 2, 2, 8, 14, 31, 31, 31 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */
- 49800, 3, 3, 8, 15, 31, 31, 31 },
+ 49800, 3, 3, 8, 15, 32, 32, 32 },
{ VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */
- 72200, 4, 4, 8, 16, 32, 32, 32 },
+ 72200, 4, 4, 8, 16, 33, 33, 33 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */
- 92900, 5, 5, 8, 17, 33, 33, 33 },
+ 92900, 5, 5, 8, 17, 34, 34, 34 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */
- 102700, 6, 6, 8, 18, 34, 34, 34 },
+ 102700, 6, 6, 8, 18, 35, 35, 35 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */
- 112000, 7, 7, 8, 19, 35, 36, 36 },
+ 112000, 7, 7, 8, 19, 36, 37, 37 },
{ INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */
- 122000, 7, 7, 8, 19, 35, 36, 36 },
+ 122000, 7, 7, 8, 19, 36, 37, 37 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */
- 25800, 8, 8, 8, 20, 37, 37, 37 },
+ 25800, 8, 8, 8, 20, 38, 38, 38 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */
- 49800, 9, 9, 8, 21, 38, 38, 38 },
+ 49800, 9, 9, 8, 21, 39, 39, 39 },
{ INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */
- 71900, 10, 10, 8, 22, 39, 39, 39 },
+ 71900, 10, 10, 8, 22, 40, 40, 40 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */
- 92500, 11, 11, 8, 23, 40, 40, 40 },
+ 92500, 11, 11, 8, 23, 41, 41, 41 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */
- 130300, 12, 12, 8, 24, 41, 41, 41 },
+ 130300, 12, 12, 8, 24, 42, 42, 42 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */
- 162800, 13, 13, 8, 25, 42, 42, 42 },
+ 162800, 13, 13, 8, 25, 43, 43, 43 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */
- 178200, 14, 14, 8, 26, 43, 43, 43 },
+ 178200, 14, 14, 8, 26, 44, 44, 44 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */
- 192100, 15, 15, 8, 27, 44, 45, 45 },
+ 192100, 15, 15, 8, 27, 45, 46, 46 },
{ VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */
- 207000, 15, 15, 8, 27, 44, 45, 45 },
+ 207000, 15, 15, 8, 27, 45, 46, 46 },
},
50, /* probe interval */
WLAN_RC_HT_FLAG, /* Phy rates allowed initially */
@@ -1193,7 +1197,7 @@ static void ath_rc_init(struct ath_softc *sc,
}
static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
- bool is_cw40, bool is_sgi40)
+ bool is_cw40, bool is_sgi)
{
u8 caps = 0;
@@ -1206,8 +1210,9 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
}
if (is_cw40)
caps |= WLAN_RC_40_FLAG;
- if (is_sgi40)
+ if (is_sgi)
caps |= WLAN_RC_SGI_FLAG;
+
}
return caps;
@@ -1300,7 +1305,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table;
- bool is_cw40, is_sgi40;
+ bool is_cw40, is_sgi = false;
int i, j = 0;
for (i = 0; i < sband->n_bitrates; i++) {
@@ -1323,7 +1328,11 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
}
is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+
+ if (is_cw40)
+ is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+ else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ is_sgi = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20;
/* Choose rate table first */
@@ -1336,7 +1345,7 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
rate_table = hw_rate_table[sc->cur_rate_mode];
}
- ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi40);
+ ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
}
@@ -1347,10 +1356,10 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
struct ath_softc *sc = priv;
struct ath_rate_priv *ath_rc_priv = priv_sta;
const struct ath_rate_table *rate_table = NULL;
- bool oper_cw40 = false, oper_sgi40;
+ bool oper_cw40 = false, oper_sgi;
bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
true : false;
- bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
+ bool local_sgi = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
true : false;
/* FIXME: Handle AP mode later when we support CWM */
@@ -1363,15 +1372,21 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
oper_chan_type == NL80211_CHAN_HT40PLUS)
oper_cw40 = true;
- oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
- true : false;
+ if (oper_cw40)
+ oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ true : false;
+ else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
+ oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ true : false;
+ else
+ oper_sgi = false;
- if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
+ if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
rate_table = ath_choose_rate_table(sc, sband->band,
sta->ht_cap.ht_supported,
oper_cw40);
ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
- oper_cw40, oper_sgi40);
+ oper_cw40, oper_sgi);
ath_rc_init(sc, priv_sta, sband, sta, rate_table);
ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_CONFIG,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index ca6065b71b46..d373364ef8a9 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -700,12 +700,16 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
bf = SKB_CB_ATHBUF(skb);
BUG_ON(!bf);
- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
common->rx_bufsize, DMA_FROM_DEVICE);
ret = ath9k_hw_process_rxdesc_edma(ah, NULL, skb->data);
- if (ret == -EINPROGRESS)
+ if (ret == -EINPROGRESS) {
+ /*let device gain the buffer again*/
+ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ common->rx_bufsize, DMA_FROM_DEVICE);
return false;
+ }
__skb_unlink(skb, &rx_edma->rx_fifo);
if (ret == -EINVAL) {
@@ -814,13 +818,266 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
* 1. accessing the frame
* 2. requeueing the same buffer to h/w
*/
- dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+ dma_sync_single_for_cpu(sc->dev, bf->bf_buf_addr,
common->rx_bufsize,
DMA_FROM_DEVICE);
return bf;
}
+/* Assumes you've already done the endian to CPU conversion */
+static bool ath9k_rx_accept(struct ath_common *common,
+ struct ieee80211_hdr *hdr,
+ struct ieee80211_rx_status *rxs,
+ struct ath_rx_status *rx_stats,
+ bool *decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ __le16 fc;
+ u8 rx_status_len = ah->caps.rx_status_len;
+
+ fc = hdr->frame_control;
+
+ if (!rx_stats->rs_datalen)
+ return false;
+ /*
+ * rs_status follows rs_datalen so if rs_datalen is too large
+ * we can take a hint that hardware corrupted it, so ignore
+ * those frames.
+ */
+ if (rx_stats->rs_datalen > (common->rx_bufsize - rx_status_len))
+ return false;
+
+ /*
+ * rs_more indicates chained descriptors which can be used
+ * to link buffers together for a sort of scatter-gather
+ * operation.
+ * reject the frame, we don't support scatter-gather yet and
+ * the frame is probably corrupt anyway
+ */
+ if (rx_stats->rs_more)
+ return false;
+
+ /*
+ * The rx_stats->rs_status will not be set until the end of the
+ * chained descriptors so it can be ignored if rs_more is set. The
+ * rs_more will be false at the last element of the chained
+ * descriptors.
+ */
+ if (rx_stats->rs_status != 0) {
+ if (rx_stats->rs_status & ATH9K_RXERR_CRC)
+ rxs->flag |= RX_FLAG_FAILED_FCS_CRC;
+ if (rx_stats->rs_status & ATH9K_RXERR_PHY)
+ return false;
+
+ if (rx_stats->rs_status & ATH9K_RXERR_DECRYPT) {
+ *decrypt_error = true;
+ } else if (rx_stats->rs_status & ATH9K_RXERR_MIC) {
+ if (ieee80211_is_ctl(fc))
+ /*
+ * Sometimes, we get invalid
+ * MIC failures on valid control frames.
+ * Remove these mic errors.
+ */
+ rx_stats->rs_status &= ~ATH9K_RXERR_MIC;
+ else
+ rxs->flag |= RX_FLAG_MMIC_ERROR;
+ }
+ /*
+ * Reject error frames with the exception of
+ * decryption and MIC failures. For monitor mode,
+ * we also ignore the CRC error.
+ */
+ if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC |
+ ATH9K_RXERR_CRC))
+ return false;
+ } else {
+ if (rx_stats->rs_status &
+ ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+static int ath9k_process_rate(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs)
+{
+ struct ieee80211_supported_band *sband;
+ enum ieee80211_band band;
+ unsigned int i = 0;
+
+ band = hw->conf.channel->band;
+ sband = hw->wiphy->bands[band];
+
+ if (rx_stats->rs_rate & 0x80) {
+ /* HT rate */
+ rxs->flag |= RX_FLAG_HT;
+ if (rx_stats->rs_flags & ATH9K_RX_2040)
+ rxs->flag |= RX_FLAG_40MHZ;
+ if (rx_stats->rs_flags & ATH9K_RX_GI)
+ rxs->flag |= RX_FLAG_SHORT_GI;
+ rxs->rate_idx = rx_stats->rs_rate & 0x7f;
+ return 0;
+ }
+
+ for (i = 0; i < sband->n_bitrates; i++) {
+ if (sband->bitrates[i].hw_value == rx_stats->rs_rate) {
+ rxs->rate_idx = i;
+ return 0;
+ }
+ if (sband->bitrates[i].hw_value_short == rx_stats->rs_rate) {
+ rxs->flag |= RX_FLAG_SHORTPRE;
+ rxs->rate_idx = i;
+ return 0;
+ }
+ }
+
+ /*
+ * No valid hardware bitrate found -- we should not get here
+ * because hardware has already validated this frame as OK.
+ */
+ ath_print(common, ATH_DBG_XMIT, "unsupported hw bitrate detected "
+ "0x%02x using 1 Mbit\n", rx_stats->rs_rate);
+
+ return -EINVAL;
+}
+
+static void ath9k_process_rssi(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rx_stats)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_sta *sta;
+ struct ath_node *an;
+ int last_rssi = ATH_RSSI_DUMMY_MARKER;
+ __le16 fc;
+
+ fc = hdr->frame_control;
+
+ rcu_read_lock();
+ /*
+ * XXX: use ieee80211_find_sta! This requires quite a bit of work
+ * under the current ath9k virtual wiphy implementation as we have
+ * no way of tying a vif to wiphy. Typically vifs are attached to
+ * at least one sdata of a wiphy on mac80211 but with ath9k virtual
+ * wiphy you'd have to iterate over every wiphy and each sdata.
+ */
+ sta = ieee80211_find_sta_by_hw(hw, hdr->addr2);
+ if (sta) {
+ an = (struct ath_node *) sta->drv_priv;
+ if (rx_stats->rs_rssi != ATH9K_RSSI_BAD &&
+ !rx_stats->rs_moreaggr)
+ ATH_RSSI_LPF(an->last_rssi, rx_stats->rs_rssi);
+ last_rssi = an->last_rssi;
+ }
+ rcu_read_unlock();
+
+ if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
+ rx_stats->rs_rssi = ATH_EP_RND(last_rssi,
+ ATH_RSSI_EP_MULTIPLIER);
+ if (rx_stats->rs_rssi < 0)
+ rx_stats->rs_rssi = 0;
+
+ /* Update Beacon RSSI, this is used by ANI. */
+ if (ieee80211_is_beacon(fc))
+ ah->stats.avgbrssi = rx_stats->rs_rssi;
+}
+
+/*
+ * For Decrypt or Demic errors, we only mark packet status here and always push
+ * up the frame up to let mac80211 handle the actual error case, be it no
+ * decryption key or real decryption error. This let us keep statistics there.
+ */
+static int ath9k_rx_skb_preprocess(struct ath_common *common,
+ struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rx_status,
+ bool *decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+
+ memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+
+ /*
+ * everything but the rate is checked here, the rate check is done
+ * separately to avoid doing two lookups for a rate for each frame.
+ */
+ if (!ath9k_rx_accept(common, hdr, rx_status, rx_stats, decrypt_error))
+ return -EINVAL;
+
+ ath9k_process_rssi(common, hw, hdr, rx_stats);
+
+ if (ath9k_process_rate(common, hw, rx_stats, rx_status))
+ return -EINVAL;
+
+ rx_status->mactime = ath9k_hw_extend_tsf(ah, rx_stats->rs_tstamp);
+ rx_status->band = hw->conf.channel->band;
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->signal = ATH_DEFAULT_NOISE_FLOOR + rx_stats->rs_rssi;
+ rx_status->antenna = rx_stats->rs_antenna;
+ rx_status->flag |= RX_FLAG_TSFT;
+
+ return 0;
+}
+
+static void ath9k_rx_skb_postprocess(struct ath_common *common,
+ struct sk_buff *skb,
+ struct ath_rx_status *rx_stats,
+ struct ieee80211_rx_status *rxs,
+ bool decrypt_error)
+{
+ struct ath_hw *ah = common->ah;
+ struct ieee80211_hdr *hdr;
+ int hdrlen, padpos, padsize;
+ u8 keyix;
+ __le16 fc;
+
+ /* see if any padding is done by the hw and remove it */
+ hdr = (struct ieee80211_hdr *) skb->data;
+ hdrlen = ieee80211_get_hdrlen_from_skb(skb);
+ fc = hdr->frame_control;
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+
+ /* The MAC header is padded to have 32-bit boundary if the
+ * packet payload is non-zero. The general calculation for
+ * padsize would take into account odd header lengths:
+ * padsize = (4 - padpos % 4) % 4; However, since only
+ * even-length headers are used, padding can only be 0 or 2
+ * bytes and we can optimize this a bit. In addition, we must
+ * not try to remove padding from short control frames that do
+ * not have payload. */
+ padsize = padpos & 3;
+ if (padsize && skb->len>=padpos+padsize+FCS_LEN) {
+ memmove(skb->data + padsize, skb->data, padpos);
+ skb_pull(skb, padsize);
+ }
+
+ keyix = rx_stats->rs_keyix;
+
+ if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error &&
+ ieee80211_has_protected(fc)) {
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ } else if (ieee80211_has_protected(fc)
+ && !decrypt_error && skb->len >= hdrlen + 4) {
+ keyix = skb->data[hdrlen + 3] >> 6;
+
+ if (test_bit(keyix, common->keymap))
+ rxs->flag |= RX_FLAG_DECRYPTED;
+ }
+ if (ah->sw_mgmt_crypto &&
+ (rxs->flag & RX_FLAG_DECRYPTED) &&
+ ieee80211_is_mgmt(fc))
+ /* Use software decrypt for management frames. */
+ rxs->flag &= ~RX_FLAG_DECRYPTED;
+}
int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
{
@@ -842,11 +1099,12 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
enum ath9k_rx_qtype qtype;
bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
int dma_type;
+ u8 rx_status_len = ah->caps.rx_status_len;
if (edma)
- dma_type = DMA_FROM_DEVICE;
- else
dma_type = DMA_BIDIRECTIONAL;
+ else
+ dma_type = DMA_FROM_DEVICE;
qtype = hp ? ATH9K_RX_QUEUE_HP : ATH9K_RX_QUEUE_LP;
spin_lock_bh(&sc->rx.rxbuflock);
@@ -869,7 +1127,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (!skb)
continue;
- hdr = (struct ieee80211_hdr *) skb->data;
+ hdr = (struct ieee80211_hdr *) (skb->data + rx_status_len);
rxs = IEEE80211_SKB_RXCB(skb);
hw = ath_get_virt_hw(sc, hdr);
@@ -883,8 +1141,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (flush)
goto requeue;
- retval = ath9k_cmn_rx_skb_preprocess(common, hw, skb, &rs,
- rxs, &decrypt_error);
+ retval = ath9k_rx_skb_preprocess(common, hw, hdr, &rs,
+ rxs, &decrypt_error);
if (retval)
goto requeue;
@@ -908,8 +1166,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
if (ah->caps.rx_status_len)
skb_pull(skb, ah->caps.rx_status_len);
- ath9k_cmn_rx_skb_postprocess(common, skb, &rs,
- rxs, decrypt_error);
+ ath9k_rx_skb_postprocess(common, skb, &rs,
+ rxs, decrypt_error);
/* We will now give hardware our shiny new allocated skb */
bf->bf_mpdu = requeue_skb;
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index d4371a43bdaa..3e3ccef438db 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -222,6 +222,7 @@
#define AR_ISR_S2 0x008c
#define AR_ISR_S2_QCU_TXURN 0x000003FF
+#define AR_ISR_S2_BB_WATCHDOG 0x00010000
#define AR_ISR_S2_CST 0x00400000
#define AR_ISR_S2_GTT 0x00800000
#define AR_ISR_S2_TIM 0x01000000
@@ -699,6 +700,9 @@
#define AR_RC_HOSTIF 0x00000100
#define AR_WA 0x4004
+#define AR_WA_BIT6 (1 << 6)
+#define AR_WA_BIT7 (1 << 7)
+#define AR_WA_BIT23 (1 << 23)
#define AR_WA_D3_L1_DISABLE (1 << 14)
#define AR9285_WA_DEFAULT 0x004a050b
#define AR9280_WA_DEFAULT 0x0040073b
@@ -756,32 +760,33 @@
#define AR_SREV_REVISION2 0x00000F00
#define AR_SREV_REVISION2_S 8
-#define AR_SREV_VERSION_5416_PCI 0xD
-#define AR_SREV_VERSION_5416_PCIE 0xC
-#define AR_SREV_REVISION_5416_10 0
-#define AR_SREV_REVISION_5416_20 1
-#define AR_SREV_REVISION_5416_22 2
-#define AR_SREV_VERSION_9100 0x14
-#define AR_SREV_VERSION_9160 0x40
-#define AR_SREV_REVISION_9160_10 0
-#define AR_SREV_REVISION_9160_11 1
-#define AR_SREV_VERSION_9280 0x80
-#define AR_SREV_REVISION_9280_10 0
-#define AR_SREV_REVISION_9280_20 1
-#define AR_SREV_REVISION_9280_21 2
-#define AR_SREV_VERSION_9285 0xC0
-#define AR_SREV_REVISION_9285_10 0
-#define AR_SREV_REVISION_9285_11 1
-#define AR_SREV_REVISION_9285_12 2
-#define AR_SREV_VERSION_9287 0x180
-#define AR_SREV_REVISION_9287_10 0
-#define AR_SREV_REVISION_9287_11 1
-#define AR_SREV_REVISION_9287_12 2
-#define AR_SREV_VERSION_9271 0x140
-#define AR_SREV_REVISION_9271_10 0
-#define AR_SREV_REVISION_9271_11 1
-#define AR_SREV_VERSION_9300 0x1c0
-#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
+#define AR_SREV_VERSION_5416_PCI 0xD
+#define AR_SREV_VERSION_5416_PCIE 0xC
+#define AR_SREV_REVISION_5416_10 0
+#define AR_SREV_REVISION_5416_20 1
+#define AR_SREV_REVISION_5416_22 2
+#define AR_SREV_VERSION_9100 0x14
+#define AR_SREV_VERSION_9160 0x40
+#define AR_SREV_REVISION_9160_10 0
+#define AR_SREV_REVISION_9160_11 1
+#define AR_SREV_VERSION_9280 0x80
+#define AR_SREV_REVISION_9280_10 0
+#define AR_SREV_REVISION_9280_20 1
+#define AR_SREV_REVISION_9280_21 2
+#define AR_SREV_VERSION_9285 0xC0
+#define AR_SREV_REVISION_9285_10 0
+#define AR_SREV_REVISION_9285_11 1
+#define AR_SREV_REVISION_9285_12 2
+#define AR_SREV_VERSION_9287 0x180
+#define AR_SREV_REVISION_9287_10 0
+#define AR_SREV_REVISION_9287_11 1
+#define AR_SREV_REVISION_9287_12 2
+#define AR_SREV_REVISION_9287_13 3
+#define AR_SREV_VERSION_9271 0x140
+#define AR_SREV_REVISION_9271_10 0
+#define AR_SREV_REVISION_9271_11 1
+#define AR_SREV_VERSION_9300 0x1c0
+#define AR_SREV_REVISION_9300_20 2 /* 2.0 and 2.1 */
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -859,6 +864,11 @@
(((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_12)))
+#define AR_SREV_9287_13_OR_LATER(_ah) \
+ (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9287) || \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9287) && \
+ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9287_13)))
+
#define AR_SREV_9271(_ah) \
(((_ah))->hw_version.macVersion == AR_SREV_VERSION_9271)
#define AR_SREV_9271_10(_ah) \
diff --git a/drivers/net/wireless/ath/ath9k/wmi.c b/drivers/net/wireless/ath/ath9k/wmi.c
index e23172c9caaf..6260faa658a2 100644
--- a/drivers/net/wireless/ath/ath9k/wmi.c
+++ b/drivers/net/wireless/ath/ath9k/wmi.c
@@ -279,9 +279,6 @@ int ath9k_wmi_cmd(struct wmi *wmi, enum wmi_cmd_id cmd_id,
if (wmi->drv_priv->op_flags & OP_UNPLUGGED)
return 0;
- if (!wmi)
- return -EINVAL;
-
skb = alloc_skb(headroom + cmd_len, GFP_ATOMIC);
if (!skb)
return -ENOMEM;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 3db19172b43b..7547c8f9a584 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -984,32 +984,6 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
return qnum;
}
-struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
-{
- struct ath_txq *txq = NULL;
- u16 skb_queue = skb_get_queue_mapping(skb);
- int qnum;
-
- qnum = ath_get_hal_qnum(skb_queue, sc);
- txq = &sc->tx.txq[qnum];
-
- spin_lock_bh(&txq->axq_lock);
-
- if (txq->axq_depth >= (ATH_TXBUF - 20)) {
- ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
- "TX queue: %d is full, depth: %d\n",
- qnum, txq->axq_depth);
- ath_mac80211_stop_queue(sc, skb_queue);
- txq->stopped = 1;
- spin_unlock_bh(&txq->axq_lock);
- return NULL;
- }
-
- spin_unlock_bh(&txq->axq_lock);
-
- return txq;
-}
-
int ath_txq_update(struct ath_softc *sc, int qnum,
struct ath9k_tx_queue_info *qinfo)
{
@@ -1198,7 +1172,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
int r;
ath_print(common, ATH_DBG_FATAL,
- "Unable to stop TxDMA. Reset HAL!\n");
+ "Failed to stop TX DMA. Resetting hardware!\n");
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, false);
@@ -1728,6 +1702,8 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
} else
bf->bf_isnullfunc = false;
+ bf->bf_tx_aborted = false;
+
return 0;
}
@@ -1807,6 +1783,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+ struct ath_txq *txq = txctl->txq;
struct ath_buf *bf;
int r;
@@ -1816,10 +1793,16 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
return -1;
}
+ bf->txq = txctl->txq;
+ spin_lock_bh(&bf->txq->axq_lock);
+ if (++bf->txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
+ ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
+ txq->stopped = 1;
+ }
+ spin_unlock_bh(&bf->txq->axq_lock);
+
r = ath_tx_setup_buffer(hw, bf, skb, txctl);
if (unlikely(r)) {
- struct ath_txq *txq = txctl->txq;
-
ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
/* upon ath_tx_processq() this TX queue will be resumed, we
@@ -1827,7 +1810,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* we will at least have to run TX completionon one buffer
* on the queue */
spin_lock_bh(&txq->axq_lock);
- if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
+ if (!txq->stopped && txq->axq_depth > 1) {
ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
txq->stopped = 1;
}
@@ -1968,6 +1951,13 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
tx_flags |= ATH_TX_XRETRY;
}
+ if (bf->txq) {
+ spin_lock_bh(&bf->txq->axq_lock);
+ bf->txq->pending_frames--;
+ spin_unlock_bh(&bf->txq->axq_lock);
+ bf->txq = NULL;
+ }
+
dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
ath_tx_complete(sc, skb, bf->aphy, tx_flags);
ath_debug_stat_tx(sc, txq, bf, ts);
@@ -1989,7 +1979,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
int nbad = 0;
int isaggr = 0;
- if (bf->bf_tx_aborted)
+ if (bf->bf_lastbf->bf_tx_aborted)
return 0;
isaggr = bf_isaggr(bf);
@@ -2056,8 +2046,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
int qnum;
spin_lock_bh(&txq->axq_lock);
- if (txq->stopped &&
- sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
+ if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
if (qnum != -1) {
ath_mac80211_start_queue(sc, qnum);
@@ -2277,6 +2266,17 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
txok = !(txs.ts_status & ATH9K_TXERR_MASK);
+ /*
+ * Make sure null func frame is acked before configuring
+ * hw into ps mode.
+ */
+ if (bf->bf_isnullfunc && txok) {
+ if ((sc->ps_flags & PS_ENABLED))
+ ath9k_enable_ps(sc);
+ else
+ sc->ps_flags |= PS_NULLFUNC_COMPLETED;
+ }
+
if (!bf_isampdu(bf)) {
bf->bf_retries = txs.ts_longretry;
if (txs.ts_status & ATH9K_TXERR_XRETRY)
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 3a003e6803a5..8674a99356af 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -530,7 +530,7 @@ struct b43_fw_header {
/* Size of the data. For ucode and PCM this is in bytes.
* For IV this is number-of-ivs. */
__be32 size;
-} __attribute__((__packed__));
+} __packed;
/* Initial Value file format */
#define B43_IV_OFFSET_MASK 0x7FFF
@@ -540,8 +540,8 @@ struct b43_iv {
union {
__be16 d16;
__be32 d32;
- } data __attribute__((__packed__));
-} __attribute__((__packed__));
+ } data __packed;
+} __packed;
/* Data structures for DMA transmission, per 80211 core. */
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index fa40fdfea719..10d0aaf754c5 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -333,11 +333,11 @@ static inline
dma_addr_t dmaaddr;
if (tx) {
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
- buf, len, DMA_TO_DEVICE);
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ buf, len, DMA_TO_DEVICE);
} else {
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
- buf, len, DMA_FROM_DEVICE);
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
+ buf, len, DMA_FROM_DEVICE);
}
return dmaaddr;
@@ -348,11 +348,11 @@ static inline
dma_addr_t addr, size_t len, int tx)
{
if (tx) {
- ssb_dma_unmap_single(ring->dev->dev,
- addr, len, DMA_TO_DEVICE);
+ dma_unmap_single(ring->dev->dev->dma_dev,
+ addr, len, DMA_TO_DEVICE);
} else {
- ssb_dma_unmap_single(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_unmap_single(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
}
@@ -361,7 +361,7 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_cpu(ring->dev->dev,
+ dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
addr, len, DMA_FROM_DEVICE);
}
@@ -370,8 +370,8 @@ static inline
dma_addr_t addr, size_t len)
{
B43_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_device(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -401,9 +401,9 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
*/
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
- ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
- B43_DMA_RINGMEMSIZE,
- &(ring->dmabase), flags);
+ ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+ B43_DMA_RINGMEMSIZE,
+ &(ring->dmabase), flags);
if (!ring->descbase) {
b43err(ring->dev->wl, "DMA ringmemory allocation failed\n");
return -ENOMEM;
@@ -420,8 +420,8 @@ static void free_ringmemory(struct b43_dmaring *ring)
if (ring->type == B43_DMA_64BIT)
flags |= GFP_DMA;
- ssb_dma_free_consistent(ring->dev->dev, B43_DMA_RINGMEMSIZE,
- ring->descbase, ring->dmabase, flags);
+ dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
}
/* Reset the RX DMA channel */
@@ -528,7 +528,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
dma_addr_t addr,
size_t buffersize, bool dma_to_device)
{
- if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+ if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
return 1;
switch (ring->type) {
@@ -874,10 +874,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = ssb_dma_map_single(dev->dev,
- ring->txhdr_cache,
- b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_test = dma_map_single(dev->dev->dma_dev,
+ ring->txhdr_cache,
+ b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
@@ -889,10 +889,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = ssb_dma_map_single(dev->dev,
- ring->txhdr_cache,
- b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_test = dma_map_single(dev->dev->dma_dev,
+ ring->txhdr_cache,
+ b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
if (b43_dma_mapping_error(ring, dma_test,
b43_txhdr_size(dev), 1)) {
@@ -903,9 +903,9 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
}
}
- ssb_dma_unmap_single(dev->dev,
- dma_test, b43_txhdr_size(dev),
- DMA_TO_DEVICE);
+ dma_unmap_single(dev->dev->dma_dev,
+ dma_test, b43_txhdr_size(dev),
+ DMA_TO_DEVICE);
}
err = alloc_ringmemory(ring);
@@ -1018,9 +1018,12 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
/* Try to set the DMA mask. If it fails, try falling back to a
* lower mask, as we can always also support a lower one. */
while (1) {
- err = ssb_dma_set_mask(dev->dev, mask);
- if (!err)
- break;
+ err = dma_set_mask(dev->dev->dma_dev, mask);
+ if (!err) {
+ err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+ if (!err)
+ break;
+ }
if (mask == DMA_BIT_MASK(64)) {
mask = DMA_BIT_MASK(32);
fallback = 1;
@@ -1221,14 +1224,14 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
/* create a bounce buffer in zone_dma on mapping failure. */
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
- priv_info->bouncebuffer = kmalloc(skb->len, GFP_ATOMIC | GFP_DMA);
+ priv_info->bouncebuffer = kmemdup(skb->data, skb->len,
+ GFP_ATOMIC | GFP_DMA);
if (!priv_info->bouncebuffer) {
ring->current_slot = old_top_slot;
ring->used_slots = old_used_slots;
err = -ENOMEM;
goto out_unmap_hdr;
}
- memcpy(priv_info->bouncebuffer, skb->data, skb->len);
meta->dmaaddr = map_descbuffer(ring, priv_info->bouncebuffer, skb->len, 1);
if (b43_dma_mapping_error(ring, meta->dmaaddr, skb->len, 1)) {
diff --git a/drivers/net/wireless/b43/dma.h b/drivers/net/wireless/b43/dma.h
index dc91944d6022..a01c2100f166 100644
--- a/drivers/net/wireless/b43/dma.h
+++ b/drivers/net/wireless/b43/dma.h
@@ -67,7 +67,7 @@
struct b43_dmadesc32 {
__le32 control;
__le32 address;
-} __attribute__ ((__packed__));
+} __packed;
#define B43_DMA32_DCTL_BYTECNT 0x00001FFF
#define B43_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define B43_DMA32_DCTL_ADDREXT_SHIFT 16
@@ -140,7 +140,7 @@ struct b43_dmadesc64 {
__le32 control1;
__le32 address_low;
__le32 address_high;
-} __attribute__ ((__packed__));
+} __packed;
#define B43_DMA64_DCTL0_DTABLEEND 0x10000000
#define B43_DMA64_DCTL0_IRQ 0x20000000
#define B43_DMA64_DCTL0_FRAMEEND 0x40000000
@@ -153,8 +153,8 @@ struct b43_dmadesc_generic {
union {
struct b43_dmadesc32 dma32;
struct b43_dmadesc64 dma64;
- } __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+ } __packed;
+} __packed;
/* Misc DMA constants */
#define B43_DMA_RINGMEMSIZE PAGE_SIZE
diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h
index d23ff9fe0c9e..d4cf9b390af3 100644
--- a/drivers/net/wireless/b43/xmit.h
+++ b/drivers/net/wireless/b43/xmit.h
@@ -10,8 +10,8 @@
union { \
__le32 data; \
__u8 raw[size]; \
- } __attribute__((__packed__)); \
- } __attribute__((__packed__))
+ } __packed; \
+ } __packed
/* struct b43_plcp_hdr4 */
_b43_declare_plcp_hdr(4);
@@ -57,7 +57,7 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } new_format __attribute__ ((__packed__));
+ } new_format __packed;
/* The old r351 format. */
struct {
@@ -68,10 +68,10 @@ struct b43_txhdr {
__u8 rts_frame[16]; /* The RTS frame (if used) */
PAD_BYTES(2);
struct b43_plcp_hdr6 plcp; /* Main PLCP header */
- } old_format __attribute__ ((__packed__));
+ } old_format __packed;
- } __attribute__ ((__packed__));
-} __attribute__ ((__packed__));
+ } __packed;
+} __packed;
/* MAC TX control */
#define B43_TXH_MAC_USEFBR 0x10000000 /* Use fallback rate for this AMPDU */
@@ -218,20 +218,20 @@ struct b43_rxhdr_fw4 {
struct {
__u8 jssi; /* PHY RX Status 1: JSSI */
__u8 sig_qual; /* PHY RX Status 1: Signal Quality */
- } __attribute__ ((__packed__));
+ } __packed;
/* RSSI for N-PHYs */
struct {
__s8 power0; /* PHY RX Status 1: Power 0 */
__s8 power1; /* PHY RX Status 1: Power 1 */
- } __attribute__ ((__packed__));
- } __attribute__ ((__packed__));
+ } __packed;
+ } __packed;
__le16 phy_status2; /* PHY RX Status 2 */
__le16 phy_status3; /* PHY RX Status 3 */
__le32 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
-} __attribute__ ((__packed__));
+} __packed;
/* PHY RX Status 0 */
#define B43_RX_PHYST0_GAINCTL 0x4000 /* Gain Control */
diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h
index 89fe2f972c72..c81b2f53b0c5 100644
--- a/drivers/net/wireless/b43legacy/b43legacy.h
+++ b/drivers/net/wireless/b43legacy/b43legacy.h
@@ -372,7 +372,7 @@ struct b43legacy_fw_header {
/* Size of the data. For ucode and PCM this is in bytes.
* For IV this is number-of-ivs. */
__be32 size;
-} __attribute__((__packed__));
+} __packed;
/* Initial Value file format */
#define B43legacy_IV_OFFSET_MASK 0x7FFF
@@ -382,8 +382,8 @@ struct b43legacy_iv {
union {
__be16 d16;
__be32 d32;
- } data __attribute__((__packed__));
-} __attribute__((__packed__));
+ } data __packed;
+} __packed;
#define B43legacy_PHYMODE(phytype) (1 << (phytype))
#define B43legacy_PHYMODE_B B43legacy_PHYMODE \
diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c
index e91520d0312e..e03e01d0bc35 100644
--- a/drivers/net/wireless/b43legacy/dma.c
+++ b/drivers/net/wireless/b43legacy/dma.c
@@ -394,11 +394,11 @@ dma_addr_t map_descbuffer(struct b43legacy_dmaring *ring,
dma_addr_t dmaaddr;
if (tx)
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_TO_DEVICE);
else
- dmaaddr = ssb_dma_map_single(ring->dev->dev,
+ dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
buf, len,
DMA_FROM_DEVICE);
@@ -412,11 +412,11 @@ void unmap_descbuffer(struct b43legacy_dmaring *ring,
int tx)
{
if (tx)
- ssb_dma_unmap_single(ring->dev->dev,
+ dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_TO_DEVICE);
else
- ssb_dma_unmap_single(ring->dev->dev,
+ dma_unmap_single(ring->dev->dev->dma_dev,
addr, len,
DMA_FROM_DEVICE);
}
@@ -428,8 +428,8 @@ void sync_descbuffer_for_cpu(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_cpu(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -439,8 +439,8 @@ void sync_descbuffer_for_device(struct b43legacy_dmaring *ring,
{
B43legacy_WARN_ON(ring->tx);
- ssb_dma_sync_single_for_device(ring->dev->dev,
- addr, len, DMA_FROM_DEVICE);
+ dma_sync_single_for_device(ring->dev->dev->dma_dev,
+ addr, len, DMA_FROM_DEVICE);
}
static inline
@@ -460,10 +460,10 @@ void free_descriptor_buffer(struct b43legacy_dmaring *ring,
static int alloc_ringmemory(struct b43legacy_dmaring *ring)
{
/* GFP flags must match the flags in free_ringmemory()! */
- ring->descbase = ssb_dma_alloc_consistent(ring->dev->dev,
- B43legacy_DMA_RINGMEMSIZE,
- &(ring->dmabase),
- GFP_KERNEL);
+ ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
+ B43legacy_DMA_RINGMEMSIZE,
+ &(ring->dmabase),
+ GFP_KERNEL);
if (!ring->descbase) {
b43legacyerr(ring->dev->wl, "DMA ringmemory allocation"
" failed\n");
@@ -476,8 +476,8 @@ static int alloc_ringmemory(struct b43legacy_dmaring *ring)
static void free_ringmemory(struct b43legacy_dmaring *ring)
{
- ssb_dma_free_consistent(ring->dev->dev, B43legacy_DMA_RINGMEMSIZE,
- ring->descbase, ring->dmabase, GFP_KERNEL);
+ dma_free_coherent(ring->dev->dev->dma_dev, B43legacy_DMA_RINGMEMSIZE,
+ ring->descbase, ring->dmabase);
}
/* Reset the RX DMA channel */
@@ -589,7 +589,7 @@ static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring,
size_t buffersize,
bool dma_to_device)
{
- if (unlikely(ssb_dma_mapping_error(ring->dev->dev, addr)))
+ if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
return 1;
switch (ring->type) {
@@ -906,7 +906,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
goto err_kfree_meta;
/* test for ability to dma to txhdr_cache */
- dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache,
+ dma_test = dma_map_single(dev->dev->dma_dev, ring->txhdr_cache,
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
@@ -920,7 +920,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
if (!ring->txhdr_cache)
goto err_kfree_meta;
- dma_test = ssb_dma_map_single(dev->dev,
+ dma_test = dma_map_single(dev->dev->dma_dev,
ring->txhdr_cache,
sizeof(struct b43legacy_txhdr_fw3),
DMA_TO_DEVICE);
@@ -930,9 +930,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev,
goto err_kfree_txhdr_cache;
}
- ssb_dma_unmap_single(dev->dev, dma_test,
- sizeof(struct b43legacy_txhdr_fw3),
- DMA_TO_DEVICE);
+ dma_unmap_single(dev->dev->dma_dev, dma_test,
+ sizeof(struct b43legacy_txhdr_fw3),
+ DMA_TO_DEVICE);
}
ring->nr_slots = nr_slots;
@@ -1040,9 +1040,12 @@ static int b43legacy_dma_set_mask(struct b43legacy_wldev *dev, u64 mask)
/* Try to set the DMA mask. If it fails, try falling back to a
* lower mask, as we can always also support a lower one. */
while (1) {
- err = ssb_dma_set_mask(dev->dev, mask);
- if (!err)
- break;
+ err = dma_set_mask(dev->dev->dma_dev, mask);
+ if (!err) {
+ err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
+ if (!err)
+ break;
+ }
if (mask == DMA_BIT_MASK(64)) {
mask = DMA_BIT_MASK(32);
fallback = 1;
diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h
index f9681041c2d8..f89c34226288 100644
--- a/drivers/net/wireless/b43legacy/dma.h
+++ b/drivers/net/wireless/b43legacy/dma.h
@@ -72,7 +72,7 @@
struct b43legacy_dmadesc32 {
__le32 control;
__le32 address;
-} __attribute__((__packed__));
+} __packed;
#define B43legacy_DMA32_DCTL_BYTECNT 0x00001FFF
#define B43legacy_DMA32_DCTL_ADDREXT_MASK 0x00030000
#define B43legacy_DMA32_DCTL_ADDREXT_SHIFT 16
@@ -147,7 +147,7 @@ struct b43legacy_dmadesc64 {
__le32 control1;
__le32 address_low;
__le32 address_high;
-} __attribute__((__packed__));
+} __packed;
#define B43legacy_DMA64_DCTL0_DTABLEEND 0x10000000
#define B43legacy_DMA64_DCTL0_IRQ 0x20000000
#define B43legacy_DMA64_DCTL0_FRAMEEND 0x40000000
@@ -162,8 +162,8 @@ struct b43legacy_dmadesc_generic {
union {
struct b43legacy_dmadesc32 dma32;
struct b43legacy_dmadesc64 dma64;
- } __attribute__((__packed__));
-} __attribute__((__packed__));
+ } __packed;
+} __packed;
/* Misc DMA constants */
diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h
index 91633087a20b..289db00a4a7b 100644
--- a/drivers/net/wireless/b43legacy/xmit.h
+++ b/drivers/net/wireless/b43legacy/xmit.h
@@ -9,8 +9,8 @@
union { \
__le32 data; \
__u8 raw[size]; \
- } __attribute__((__packed__)); \
- } __attribute__((__packed__))
+ } __packed; \
+ } __packed
/* struct b43legacy_plcp_hdr4 */
_b43legacy_declare_plcp_hdr(4);
@@ -39,7 +39,7 @@ struct b43legacy_txhdr_fw3 {
struct b43legacy_plcp_hdr6 rts_plcp; /* RTS PLCP */
__u8 rts_frame[18]; /* The RTS frame (if used) */
struct b43legacy_plcp_hdr6 plcp;
-} __attribute__((__packed__));
+} __packed;
/* MAC TX control */
#define B43legacy_TX4_MAC_KEYIDX 0x0FF00000 /* Security key index */
@@ -123,7 +123,7 @@ struct b43legacy_hwtxstatus {
__le16 seq;
u8 phy_stat;
PAD_BYTES(1);
-} __attribute__((__packed__));
+} __packed;
/* Receive header for v3 firmware. */
@@ -138,7 +138,7 @@ struct b43legacy_rxhdr_fw3 {
__le16 mac_status; /* MAC RX status */
__le16 mac_time;
__le16 channel;
-} __attribute__((__packed__));
+} __packed;
/* PHY RX Status 0 */
diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h
index 7f9d8d976aa8..ed98ce7c8f65 100644
--- a/drivers/net/wireless/hostap/hostap_80211.h
+++ b/drivers/net/wireless/hostap/hostap_80211.h
@@ -19,35 +19,35 @@ struct hostap_ieee80211_mgmt {
__le16 status_code;
/* possibly followed by Challenge text */
u8 variable[0];
- } __attribute__ ((packed)) auth;
+ } __packed auth;
struct {
__le16 reason_code;
- } __attribute__ ((packed)) deauth;
+ } __packed deauth;
struct {
__le16 capab_info;
__le16 listen_interval;
/* followed by SSID and Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) assoc_req;
+ } __packed assoc_req;
struct {
__le16 capab_info;
__le16 status_code;
__le16 aid;
/* followed by Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) assoc_resp, reassoc_resp;
+ } __packed assoc_resp, reassoc_resp;
struct {
__le16 capab_info;
__le16 listen_interval;
u8 current_ap[6];
/* followed by SSID and Supported rates */
u8 variable[0];
- } __attribute__ ((packed)) reassoc_req;
+ } __packed reassoc_req;
struct {
__le16 reason_code;
- } __attribute__ ((packed)) disassoc;
+ } __packed disassoc;
struct {
- } __attribute__ ((packed)) probe_req;
+ } __packed probe_req;
struct {
u8 timestamp[8];
__le16 beacon_int;
@@ -55,9 +55,9 @@ struct hostap_ieee80211_mgmt {
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
u8 variable[0];
- } __attribute__ ((packed)) beacon, probe_resp;
+ } __packed beacon, probe_resp;
} u;
-} __attribute__ ((packed));
+} __packed;
#define IEEE80211_MGMT_HDR_LEN 24
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h
index 90b64b092007..4230102ac9e4 100644
--- a/drivers/net/wireless/hostap/hostap_common.h
+++ b/drivers/net/wireless/hostap/hostap_common.h
@@ -179,7 +179,7 @@ struct hfa384x_comp_ident
__le16 variant;
__le16 major;
__le16 minor;
-} __attribute__ ((packed));
+} __packed;
#define HFA384X_COMP_ID_PRI 0x15
#define HFA384X_COMP_ID_STA 0x1f
@@ -192,14 +192,14 @@ struct hfa384x_sup_range
__le16 variant;
__le16 bottom;
__le16 top;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_build_id
{
__le16 pri_seq;
__le16 sec_seq;
-} __attribute__ ((packed));
+} __packed;
/* FD01 - Download Buffer */
struct hfa384x_rid_download_buffer
@@ -207,14 +207,14 @@ struct hfa384x_rid_download_buffer
__le16 page;
__le16 offset;
__le16 length;
-} __attribute__ ((packed));
+} __packed;
/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
struct hfa384x_comms_quality {
__le16 comm_qual; /* 0 .. 92 */
__le16 signal_level; /* 27 .. 154 */
__le16 noise_level; /* 27 .. 154 */
-} __attribute__ ((packed));
+} __packed;
/* netdevice private ioctls (used, e.g., with iwpriv from user space) */
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index d70732819423..ff9b5c882184 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2618,15 +2618,6 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
int events = 0;
u16 ev;
- /* Detect early interrupt before driver is fully configued */
- if (!dev->base_addr) {
- if (net_ratelimit()) {
- printk(KERN_DEBUG "%s: Interrupt, but dev not configured\n",
- dev->name);
- }
- return IRQ_HANDLED;
- }
-
iface = netdev_priv(dev);
local = iface->local;
diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h
index 3d238917af07..c02f8667a7e0 100644
--- a/drivers/net/wireless/hostap/hostap_wlan.h
+++ b/drivers/net/wireless/hostap/hostap_wlan.h
@@ -31,14 +31,14 @@ struct linux_wlan_ng_val {
u32 did;
u16 status, len;
u32 data;
-} __attribute__ ((packed));
+} __packed;
struct linux_wlan_ng_prism_hdr {
u32 msgcode, msglen;
char devname[16];
struct linux_wlan_ng_val hosttime, mactime, channel, rssi, sq, signal,
noise, rate, istx, frmlen;
-} __attribute__ ((packed));
+} __packed;
struct linux_wlan_ng_cap_hdr {
__be32 version;
@@ -55,7 +55,7 @@ struct linux_wlan_ng_cap_hdr {
__be32 ssi_noise;
__be32 preamble;
__be32 encoding;
-} __attribute__ ((packed));
+} __packed;
struct hostap_radiotap_rx {
struct ieee80211_radiotap_header hdr;
@@ -66,7 +66,7 @@ struct hostap_radiotap_rx {
__le16 chan_flags;
s8 dbm_antsignal;
s8 dbm_antnoise;
-} __attribute__ ((packed));
+} __packed;
#define LWNG_CAP_DID_BASE (4 | (1 << 6)) /* section 4, group 1 */
#define LWNG_CAPHDR_VERSION 0x80211001
@@ -97,7 +97,7 @@ struct hfa384x_rx_frame {
__be16 len;
/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_tx_frame {
@@ -126,14 +126,14 @@ struct hfa384x_tx_frame {
__be16 len;
/* followed by frame data; max 2304 bytes */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_rid_hdr
{
__le16 len;
__le16 rid;
-} __attribute__ ((packed));
+} __packed;
/* Macro for converting signal levels (range 27 .. 154) to wireless ext
@@ -145,24 +145,24 @@ struct hfa384x_rid_hdr
struct hfa384x_scan_request {
__le16 channel_list;
__le16 txrate; /* HFA384X_RATES_* */
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_hostscan_request {
__le16 channel_list;
__le16 txrate;
__le16 target_ssid_len;
u8 target_ssid[32];
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_join_request {
u8 bssid[6];
__le16 channel;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_info_frame {
__le16 len;
__le16 type;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_comm_tallies {
__le16 tx_unicast_frames;
@@ -186,7 +186,7 @@ struct hfa384x_comm_tallies {
__le16 rx_discards_wep_undecryptable;
__le16 rx_message_in_msg_fragments;
__le16 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_comm_tallies32 {
__le32 tx_unicast_frames;
@@ -210,7 +210,7 @@ struct hfa384x_comm_tallies32 {
__le32 rx_discards_wep_undecryptable;
__le32 rx_message_in_msg_fragments;
__le32 rx_message_in_bad_msg_fragments;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_scan_result_hdr {
__le16 reserved;
@@ -219,7 +219,7 @@ struct hfa384x_scan_result_hdr {
#define HFA384X_SCAN_HOST_INITIATED 1
#define HFA384X_SCAN_FIRMWARE_INITIATED 2
#define HFA384X_SCAN_INQUIRY_FROM_HOST 3
-} __attribute__ ((packed));
+} __packed;
#define HFA384X_SCAN_MAX_RESULTS 32
@@ -234,7 +234,7 @@ struct hfa384x_scan_result {
u8 ssid[32];
u8 sup_rates[10];
__le16 rate;
-} __attribute__ ((packed));
+} __packed;
struct hfa384x_hostscan_result {
__le16 chid;
@@ -248,7 +248,7 @@ struct hfa384x_hostscan_result {
u8 sup_rates[10];
__le16 rate;
__le16 atim;
-} __attribute__ ((packed));
+} __packed;
struct comm_tallies_sums {
unsigned int tx_unicast_frames;
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c
index 0bd4dfa59a8a..56350d571960 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.c
+++ b/drivers/net/wireless/ipw2x00/ipw2100.c
@@ -3467,10 +3467,8 @@ static int ipw2100_msg_allocate(struct ipw2100_priv *priv)
dma_addr_t p;
priv->msg_buffers =
- (struct ipw2100_tx_packet *)kmalloc(IPW_COMMAND_POOL_SIZE *
- sizeof(struct
- ipw2100_tx_packet),
- GFP_KERNEL);
+ kmalloc(IPW_COMMAND_POOL_SIZE * sizeof(struct ipw2100_tx_packet),
+ GFP_KERNEL);
if (!priv->msg_buffers) {
printk(KERN_ERR DRV_NAME ": %s: PCI alloc failed for msg "
"buffers.\n", priv->net_dev->name);
@@ -4499,10 +4497,8 @@ static int ipw2100_tx_allocate(struct ipw2100_priv *priv)
}
priv->tx_buffers =
- (struct ipw2100_tx_packet *)kmalloc(TX_PENDED_QUEUE_LENGTH *
- sizeof(struct
- ipw2100_tx_packet),
- GFP_ATOMIC);
+ kmalloc(TX_PENDED_QUEUE_LENGTH * sizeof(struct ipw2100_tx_packet),
+ GFP_ATOMIC);
if (!priv->tx_buffers) {
printk(KERN_ERR DRV_NAME
": %s: alloc failed form tx buffers.\n",
@@ -4651,9 +4647,9 @@ static int ipw2100_rx_allocate(struct ipw2100_priv *priv)
/*
* allocate packets
*/
- priv->rx_buffers = (struct ipw2100_rx_packet *)
- kmalloc(RX_QUEUE_LENGTH * sizeof(struct ipw2100_rx_packet),
- GFP_KERNEL);
+ priv->rx_buffers = kmalloc(RX_QUEUE_LENGTH *
+ sizeof(struct ipw2100_rx_packet),
+ GFP_KERNEL);
if (!priv->rx_buffers) {
IPW_DEBUG_INFO("can't allocate rx packet buffer table\n");
@@ -5233,7 +5229,7 @@ struct security_info_params {
u8 auth_mode;
u8 replay_counters_number;
u8 unicast_using_group;
-} __attribute__ ((packed));
+} __packed;
static int ipw2100_set_security_information(struct ipw2100_priv *priv,
int auth_mode,
@@ -8475,7 +8471,7 @@ struct ipw2100_fw_header {
short mode;
unsigned int fw_size;
unsigned int uc_size;
-} __attribute__ ((packed));
+} __packed;
static int ipw2100_mod_firmware_load(struct ipw2100_fw *fw)
{
diff --git a/drivers/net/wireless/ipw2x00/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h
index 1eab0d698f4d..838002b4881e 100644
--- a/drivers/net/wireless/ipw2x00/ipw2100.h
+++ b/drivers/net/wireless/ipw2x00/ipw2100.h
@@ -164,7 +164,7 @@ struct bd_status {
} fields;
u8 field;
} info;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_bd {
u32 host_addr;
@@ -174,7 +174,7 @@ struct ipw2100_bd {
* 1st TBD) */
u8 num_fragments;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define IPW_BD_QUEUE_LENGTH(n) (1<<n)
#define IPW_BD_ALIGNMENT(L) (L*sizeof(struct ipw2100_bd))
@@ -232,7 +232,7 @@ struct ipw2100_status {
#define IPW_STATUS_FLAG_WEP_ENCRYPTED (1<<1)
#define IPW_STATUS_FLAG_CRC_ERROR (1<<2)
u8 rssi;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_status_queue {
/* driver (virtual) pointer to queue */
@@ -293,7 +293,7 @@ struct ipw2100_cmd_header {
u32 reserved1[3];
u32 *ordinal1_ptr;
u32 *ordinal2_ptr;
-} __attribute__ ((packed));
+} __packed;
struct ipw2100_data_header {
u32 host_command_reg;
@@ -307,7 +307,7 @@ struct ipw2100_data_header {
u8 src_addr[ETH_ALEN];
u8 dst_addr[ETH_ALEN];
u16 fragment_size;
-} __attribute__ ((packed));
+} __packed;
/* Host command data structure */
struct host_command {
@@ -316,7 +316,7 @@ struct host_command {
u32 host_command_sequence; // UNIQUE COMMAND NUMBER (ID)
u32 host_command_length; // LENGTH
u32 host_command_parameters[HOST_COMMAND_PARAMS_REG_LEN]; // COMMAND PARAMETERS
-} __attribute__ ((packed));
+} __packed;
typedef enum {
POWER_ON_RESET,
@@ -382,7 +382,7 @@ struct ipw2100_notification {
u32 hnhdr_size; /* size in bytes of data
or number of entries, if table.
Does NOT include header */
-} __attribute__ ((packed));
+} __packed;
#define MAX_KEY_SIZE 16
#define MAX_KEYS 8
@@ -814,7 +814,7 @@ struct ipw2100_rx {
struct ipw2100_notification notification;
struct ipw2100_cmd_header command;
} rx_data;
-} __attribute__ ((packed));
+} __packed;
/* Bit 0-7 are for 802.11b tx rates - . Bit 5-7 are reserved */
#define TX_RATE_1_MBIT 0x0001
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 3aa3bb18f615..8feaa1d358ea 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -6624,13 +6624,12 @@ static int ipw_wx_set_genie(struct net_device *dev,
return -EINVAL;
if (wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
if (buf == NULL) {
err = -ENOMEM;
goto out;
}
- memcpy(buf, extra, wrqu->data.length);
kfree(ieee->wpa_ie);
ieee->wpa_ie = buf;
ieee->wpa_ie_len = wrqu->data.length;
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h
index bf0eeb2e873a..d7d049c7a4fa 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.h
+++ b/drivers/net/wireless/ipw2x00/ipw2200.h
@@ -388,7 +388,7 @@ struct clx2_queue {
dma_addr_t dma_addr; /**< physical addr for BD's */
int low_mark; /**< low watermark, resume queue if free space more than this */
int high_mark; /**< high watermark, stop queue if free space less than this */
-} __attribute__ ((packed)); /* XXX */
+} __packed; /* XXX */
struct machdr32 {
__le16 frame_ctl;
@@ -399,7 +399,7 @@ struct machdr32 {
__le16 seq_ctrl; // more endians!
u8 addr4[MACADRR_BYTE_LEN];
__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct machdr30 {
__le16 frame_ctl;
@@ -409,7 +409,7 @@ struct machdr30 {
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
u8 addr4[MACADRR_BYTE_LEN];
-} __attribute__ ((packed));
+} __packed;
struct machdr26 {
__le16 frame_ctl;
@@ -419,7 +419,7 @@ struct machdr26 {
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
__le16 qos_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct machdr24 {
__le16 frame_ctl;
@@ -428,20 +428,20 @@ struct machdr24 {
u8 addr2[MACADRR_BYTE_LEN];
u8 addr3[MACADRR_BYTE_LEN];
__le16 seq_ctrl; // more endians!
-} __attribute__ ((packed));
+} __packed;
// TX TFD with 32 byte MAC Header
struct tx_tfd_32 {
struct machdr32 mchdr; // 32
__le32 uivplaceholder[2]; // 8
-} __attribute__ ((packed));
+} __packed;
// TX TFD with 30 byte MAC Header
struct tx_tfd_30 {
struct machdr30 mchdr; // 30
u8 reserved[2]; // 2
__le32 uivplaceholder[2]; // 8
-} __attribute__ ((packed));
+} __packed;
// tx tfd with 26 byte mac header
struct tx_tfd_26 {
@@ -449,14 +449,14 @@ struct tx_tfd_26 {
u8 reserved1[2]; // 2
__le32 uivplaceholder[2]; // 8
u8 reserved2[4]; // 4
-} __attribute__ ((packed));
+} __packed;
// tx tfd with 24 byte mac header
struct tx_tfd_24 {
struct machdr24 mchdr; // 24
__le32 uivplaceholder[2]; // 8
u8 reserved[8]; // 8
-} __attribute__ ((packed));
+} __packed;
#define DCT_WEP_KEY_FIELD_LENGTH 16
@@ -465,7 +465,7 @@ struct tfd_command {
u8 length;
__le16 reserved;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct tfd_data {
/* Header */
@@ -504,14 +504,14 @@ struct tfd_data {
__le32 num_chunks;
__le32 chunk_ptr[NUM_TFD_CHUNKS];
__le16 chunk_len[NUM_TFD_CHUNKS];
-} __attribute__ ((packed));
+} __packed;
struct txrx_control_flags {
u8 message_type;
u8 rx_seq_num;
u8 control_bits;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
#define TFD_SIZE 128
#define TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH (TFD_SIZE - sizeof(struct txrx_control_flags))
@@ -523,7 +523,7 @@ struct tfd_frame {
struct tfd_command cmd;
u8 raw[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH];
} u;
-} __attribute__ ((packed));
+} __packed;
typedef void destructor_func(const void *);
@@ -559,7 +559,7 @@ struct rate_histogram {
__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
} failed;
-} __attribute__ ((packed));
+} __packed;
/* statistics command response */
struct ipw_cmd_stats {
@@ -586,13 +586,13 @@ struct ipw_cmd_stats {
__le16 rx_autodetec_no_ofdm;
__le16 rx_autodetec_no_barker;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_channel_result {
u8 channel_num;
struct ipw_cmd_stats stats;
u8 uReserved;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_COMPLETED_STATUS_COMPLETE 1
#define SCAN_COMPLETED_STATUS_ABORTED 2
@@ -602,24 +602,24 @@ struct notif_scan_complete {
u8 num_channels;
u8 status;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_frag_length {
__le16 frag_length;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct notif_beacon_state {
__le32 state;
__le32 number;
-} __attribute__ ((packed));
+} __packed;
struct notif_tgi_tx_key {
u8 key_state;
u8 security_type;
u8 station_index;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
#define SILENCE_OVER_THRESH (1)
#define SILENCE_UNDER_THRESH (2)
@@ -631,25 +631,25 @@ struct notif_link_deterioration {
struct rate_histogram histogram;
u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */
__le16 silence_count;
-} __attribute__ ((packed));
+} __packed;
struct notif_association {
u8 state;
-} __attribute__ ((packed));
+} __packed;
struct notif_authenticate {
u8 state;
struct machdr24 addr;
__le16 status;
-} __attribute__ ((packed));
+} __packed;
struct notif_calibration {
u8 data[104];
-} __attribute__ ((packed));
+} __packed;
struct notif_noise {
__le32 value;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_notification {
u8 reserved[8];
@@ -669,7 +669,7 @@ struct ipw_rx_notification {
struct notif_noise noise;
u8 raw[0];
} u;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_frame {
__le32 reserved1;
@@ -692,14 +692,14 @@ struct ipw_rx_frame {
u8 rtscts_seen; // 0x1 RTS seen ; 0x2 CTS seen
__le16 length;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_header {
u8 message_type;
u8 rx_seq_num;
u8 control_bits;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_packet {
struct ipw_rx_header header;
@@ -707,7 +707,7 @@ struct ipw_rx_packet {
struct ipw_rx_frame frame;
struct ipw_rx_notification notification;
} u;
-} __attribute__ ((packed));
+} __packed;
#define IPW_RX_NOTIFICATION_SIZE sizeof(struct ipw_rx_header) + 12
#define IPW_RX_FRAME_SIZE (unsigned int)(sizeof(struct ipw_rx_header) + \
@@ -717,7 +717,7 @@ struct ipw_rx_mem_buffer {
dma_addr_t dma_addr;
struct sk_buff *skb;
struct list_head list;
-}; /* Not transferred over network, so not __attribute__ ((packed)) */
+}; /* Not transferred over network, so not __packed */
struct ipw_rx_queue {
struct ipw_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
@@ -730,7 +730,7 @@ struct ipw_rx_queue {
struct list_head rx_free; /* Own an SKBs */
struct list_head rx_used; /* No SKB allocated */
spinlock_t lock;
-}; /* Not transferred over network, so not __attribute__ ((packed)) */
+}; /* Not transferred over network, so not __packed */
struct alive_command_responce {
u8 alive_command;
@@ -745,21 +745,21 @@ struct alive_command_responce {
__le16 reserved4;
u8 time_stamp[5]; /* month, day, year, hours, minutes */
u8 ucode_valid;
-} __attribute__ ((packed));
+} __packed;
#define IPW_MAX_RATES 12
struct ipw_rates {
u8 num_rates;
u8 rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct command_block {
unsigned int control;
u32 source_addr;
u32 dest_addr;
unsigned int status;
-} __attribute__ ((packed));
+} __packed;
#define CB_NUMBER_OF_ELEMENTS_SMALL 64
struct fw_image_desc {
@@ -792,7 +792,7 @@ struct ipw_sys_config {
u8 accept_all_mgmt_frames;
u8 pass_noise_stats_to_host;
u8 reserved3;
-} __attribute__ ((packed));
+} __packed;
struct ipw_multicast_addr {
u8 num_of_multicast_addresses;
@@ -801,7 +801,7 @@ struct ipw_multicast_addr {
u8 mac2[6];
u8 mac3[6];
u8 mac4[6];
-} __attribute__ ((packed));
+} __packed;
#define DCW_WEP_KEY_INDEX_MASK 0x03 /* bits [0:1] */
#define DCW_WEP_KEY_SEC_TYPE_MASK 0x30 /* bits [4:5] */
@@ -822,7 +822,7 @@ struct ipw_wep_key {
u8 key_index;
u8 key_size;
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
struct ipw_tgi_tx_key {
u8 key_id;
@@ -831,7 +831,7 @@ struct ipw_tgi_tx_key {
u8 flags;
u8 key[16];
__le32 tx_counter[2];
-} __attribute__ ((packed));
+} __packed;
#define IPW_SCAN_CHANNELS 54
@@ -840,7 +840,7 @@ struct ipw_scan_request {
__le16 dwell_time;
u8 channels_list[IPW_SCAN_CHANNELS];
u8 channels_reserved[3];
-} __attribute__ ((packed));
+} __packed;
enum {
IPW_SCAN_PASSIVE_TILL_FIRST_BEACON_SCAN = 0,
@@ -857,7 +857,7 @@ struct ipw_scan_request_ext {
u8 scan_type[IPW_SCAN_CHANNELS / 2];
u8 reserved;
__le16 dwell_time[IPW_SCAN_TYPES];
-} __attribute__ ((packed));
+} __packed;
static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index)
{
@@ -902,7 +902,7 @@ struct ipw_associate {
u8 smr;
u8 reserved1;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
struct ipw_supported_rates {
u8 ieee_mode;
@@ -910,36 +910,36 @@ struct ipw_supported_rates {
u8 purpose;
u8 reserved;
u8 supported_rates[IPW_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rts_threshold {
__le16 rts_threshold;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_frag_threshold {
__le16 frag_threshold;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_retry_limit {
u8 short_retry_limit;
u8 long_retry_limit;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_dino_config {
__le32 dino_config_addr;
__le16 dino_config_size;
u8 dino_response;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_aironet_info {
u8 id;
u8 length;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_rx_key {
u8 station_index;
@@ -950,25 +950,25 @@ struct ipw_rx_key {
u8 station_address[6];
u8 key_index;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct ipw_country_channel_info {
u8 first_channel;
u8 no_channels;
s8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
struct ipw_country_info {
u8 id;
u8 length;
u8 country_str[3];
struct ipw_country_channel_info groups[7];
-} __attribute__ ((packed));
+} __packed;
struct ipw_channel_tx_power {
u8 channel_number;
s8 tx_power;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_ASSOCIATED_INTERVAL (HZ)
#define SCAN_INTERVAL (HZ / 10)
@@ -979,18 +979,18 @@ struct ipw_tx_power {
u8 num_channels;
u8 ieee_mode;
struct ipw_channel_tx_power channels_tx_power[MAX_A_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
struct ipw_rsn_capabilities {
u8 id;
u8 length;
__le16 version;
-} __attribute__ ((packed));
+} __packed;
struct ipw_sensitivity_calib {
__le16 beacon_rssi_raw;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* Host command structure.
@@ -1019,7 +1019,7 @@ struct ipw_cmd { /* XXX */
* nParams=(len+3)/4+status_len
*/
u32 param[0];
-} __attribute__ ((packed));
+} __packed;
#define STATUS_HCMD_ACTIVE (1<<0) /**< host command in progress */
@@ -1114,7 +1114,7 @@ struct ipw_event { /* XXX */
u32 event;
u32 time;
u32 data;
-} __attribute__ ((packed));
+} __packed;
struct ipw_fw_error { /* XXX */
unsigned long jiffies;
@@ -1125,7 +1125,7 @@ struct ipw_fw_error { /* XXX */
struct ipw_error_elem *elem;
struct ipw_event *log;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
#ifdef CONFIG_IPW2200_PROMISCUOUS
@@ -1170,7 +1170,7 @@ struct ipw_rt_hdr {
s8 rt_dbmnoise;
u8 rt_antenna; /* antenna number */
u8 payload[0]; /* payload... */
-} __attribute__ ((packed));
+} __packed;
#endif
struct ipw_priv {
@@ -1957,7 +1957,7 @@ enum {
struct ipw_fixed_rate {
__le16 tx_rates;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
#define IPW_INDIRECT_ADDR_MASK (~0x3ul)
@@ -1966,14 +1966,14 @@ struct host_cmd {
u8 len;
u16 reserved;
u32 *param;
-} __attribute__ ((packed)); /* XXX */
+} __packed; /* XXX */
struct cmdlog_host_cmd {
u8 cmd;
u8 len;
__le16 reserved;
char param[124];
-} __attribute__ ((packed));
+} __packed;
struct ipw_cmd_log {
unsigned long jiffies;
diff --git a/drivers/net/wireless/ipw2x00/libipw.h b/drivers/net/wireless/ipw2x00/libipw.h
index 284b0e4cb815..4736861bc4f8 100644
--- a/drivers/net/wireless/ipw2x00/libipw.h
+++ b/drivers/net/wireless/ipw2x00/libipw.h
@@ -154,7 +154,7 @@ struct libipw_snap_hdr {
u8 ctrl; /* always 0x03 */
u8 oui[P80211_OUI_LEN]; /* organizational universal id */
-} __attribute__ ((packed));
+} __packed;
#define SNAP_SIZE sizeof(struct libipw_snap_hdr)
@@ -323,7 +323,7 @@ struct libipw_security {
u8 keys[WEP_KEYS][SCM_KEY_LEN];
u8 level;
u16 flags;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -347,7 +347,7 @@ struct libipw_hdr_1addr {
__le16 duration_id;
u8 addr1[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_2addr {
__le16 frame_ctl;
@@ -355,7 +355,7 @@ struct libipw_hdr_2addr {
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_3addr {
__le16 frame_ctl;
@@ -365,7 +365,7 @@ struct libipw_hdr_3addr {
u8 addr3[ETH_ALEN];
__le16 seq_ctl;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_4addr {
__le16 frame_ctl;
@@ -376,7 +376,7 @@ struct libipw_hdr_4addr {
__le16 seq_ctl;
u8 addr4[ETH_ALEN];
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_hdr_3addrqos {
__le16 frame_ctl;
@@ -387,13 +387,13 @@ struct libipw_hdr_3addrqos {
__le16 seq_ctl;
u8 payload[0];
__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
struct libipw_info_element {
u8 id;
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/*
* These are the data types that can make up management packets
@@ -406,7 +406,7 @@ struct libipw_info_element {
u16 listen_interval;
struct {
u16 association_id:14, reserved:2;
- } __attribute__ ((packed));
+ } __packed;
u32 time_stamp[2];
u16 reason;
u16 status;
@@ -419,7 +419,7 @@ struct libipw_auth {
__le16 status;
/* challenge */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_channel_switch {
u8 id;
@@ -427,7 +427,7 @@ struct libipw_channel_switch {
u8 mode;
u8 channel;
u8 count;
-} __attribute__ ((packed));
+} __packed;
struct libipw_action {
struct libipw_hdr_3addr header;
@@ -441,12 +441,12 @@ struct libipw_action {
struct libipw_channel_switch channel_switch;
} format;
-} __attribute__ ((packed));
+} __packed;
struct libipw_disassoc {
struct libipw_hdr_3addr header;
__le16 reason;
-} __attribute__ ((packed));
+} __packed;
/* Alias deauth for disassoc */
#define libipw_deauth libipw_disassoc
@@ -455,7 +455,7 @@ struct libipw_probe_request {
struct libipw_hdr_3addr header;
/* SSID, supported rates */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_probe_response {
struct libipw_hdr_3addr header;
@@ -465,7 +465,7 @@ struct libipw_probe_response {
/* SSID, supported rates, FH params, DS params,
* CF params, IBSS params, TIM (if beacon), RSN */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
/* Alias beacon for probe_response */
#define libipw_beacon libipw_probe_response
@@ -476,7 +476,7 @@ struct libipw_assoc_request {
__le16 listen_interval;
/* SSID, supported rates, RSN */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_reassoc_request {
struct libipw_hdr_3addr header;
@@ -484,7 +484,7 @@ struct libipw_reassoc_request {
__le16 listen_interval;
u8 current_ap[ETH_ALEN];
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_assoc_response {
struct libipw_hdr_3addr header;
@@ -493,7 +493,7 @@ struct libipw_assoc_response {
__le16 aid;
/* supported rates */
struct libipw_info_element info_element[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_txb {
u8 nr_frags;
@@ -555,19 +555,19 @@ struct libipw_qos_information_element {
u8 qui_subtype;
u8 version;
u8 ac_info;
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_ac_parameter {
u8 aci_aifsn;
u8 ecw_min_max;
__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_parameter_info {
struct libipw_qos_information_element info_element;
u8 reserved;
struct libipw_qos_ac_parameter ac_params_record[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_parameters {
__le16 cw_min[QOS_QUEUE_NUM];
@@ -575,7 +575,7 @@ struct libipw_qos_parameters {
u8 aifs[QOS_QUEUE_NUM];
u8 flag[QOS_QUEUE_NUM];
__le16 tx_op_limit[QOS_QUEUE_NUM];
-} __attribute__ ((packed));
+} __packed;
struct libipw_qos_data {
struct libipw_qos_parameters parameters;
@@ -588,7 +588,7 @@ struct libipw_qos_data {
struct libipw_tim_parameters {
u8 tim_count;
u8 tim_period;
-} __attribute__ ((packed));
+} __packed;
/*******************************************************/
@@ -606,7 +606,7 @@ struct libipw_basic_report {
__le64 start_time;
__le16 duration;
u8 map;
-} __attribute__ ((packed));
+} __packed;
enum { /* libipw_measurement_request.mode */
/* Bit 0 is reserved */
@@ -627,7 +627,7 @@ struct libipw_measurement_params {
u8 channel;
__le64 start_time;
__le16 duration;
-} __attribute__ ((packed));
+} __packed;
struct libipw_measurement_request {
struct libipw_info_element ie;
@@ -635,7 +635,7 @@ struct libipw_measurement_request {
u8 mode;
u8 type;
struct libipw_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
struct libipw_measurement_report {
struct libipw_info_element ie;
@@ -645,17 +645,17 @@ struct libipw_measurement_report {
union {
struct libipw_basic_report basic[0];
} u;
-} __attribute__ ((packed));
+} __packed;
struct libipw_tpc_report {
u8 transmit_power;
u8 link_margin;
-} __attribute__ ((packed));
+} __packed;
struct libipw_channel_map {
u8 channel;
u8 map;
-} __attribute__ ((packed));
+} __packed;
struct libipw_ibss_dfs {
struct libipw_info_element ie;
@@ -668,14 +668,14 @@ struct libipw_csa {
u8 mode;
u8 channel;
u8 count;
-} __attribute__ ((packed));
+} __packed;
struct libipw_quiet {
u8 count;
u8 period;
u8 duration;
u8 offset;
-} __attribute__ ((packed));
+} __packed;
struct libipw_network {
/* These entries are used to identify a unique network */
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index dc8ed1527666..6491e27baac5 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -30,9 +30,11 @@ config IWLWIFI_DEBUG
config IWLWIFI_DEBUGFS
bool "iwlagn debugfs support"
- depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS
+ depends on IWLWIFI && MAC80211_DEBUGFS
---help---
- Enable creation of debugfs files for the iwlwifi drivers.
+ Enable creation of debugfs files for the iwlwifi drivers. This
+ is a low-impact option that allows getting insight into the
+ driver's state at runtime.
config IWLWIFI_DEVICE_TRACING
bool "iwlwifi device access tracing"
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 6be2992f8f21..dba91e0233b6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -158,6 +158,8 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
index 6a9c64a50e36..ef0835b01b6b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-debugfs.c
@@ -28,6 +28,28 @@
#include "iwl-3945-debugfs.h"
+
+static int iwl3945_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+ int p = 0;
+
+ p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
+ le32_to_cpu(priv->_3945.statistics.flag));
+ if (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_CLEAR_MSK)
+ p += scnprintf(buf + p, bufsz - p,
+ "\tStatistics have been cleared\n");
+ p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+ (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_FREQUENCY_MSK)
+ ? "2.4 GHz" : "5.2 GHz");
+ p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+ (le32_to_cpu(priv->_3945.statistics.flag) &
+ UCODE_STATISTICS_NARROW_BAND_MSK)
+ ? "enabled" : "disabled");
+ return p;
+}
+
ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
@@ -70,7 +92,7 @@ ssize_t iwl3945_ucode_rx_stats_read(struct file *file,
max_cck = &priv->_3945.max_delta.rx.cck;
max_general = &priv->_3945.max_delta.rx.general;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Rx - OFDM:");
@@ -331,7 +353,7 @@ ssize_t iwl3945_ucode_tx_stats_read(struct file *file,
accum_tx = &priv->_3945.accum_statistics.tx;
delta_tx = &priv->_3945.delta_statistics.tx;
max_tx = &priv->_3945.max_delta.tx;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Tx:");
@@ -438,7 +460,7 @@ ssize_t iwl3945_ucode_general_stats_read(struct file *file,
accum_div = &priv->_3945.accum_statistics.general.div;
delta_div = &priv->_3945.delta_statistics.general.div;
max_div = &priv->_3945.max_delta.general.div;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl3945_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_General:");
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
index 042f6bc0df13..2c9ed2b502a3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-fh.h
@@ -175,13 +175,13 @@
struct iwl3945_tfd_tb {
__le32 addr;
__le32 len;
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_tfd {
__le32 control_flags;
struct iwl3945_tfd_tb tbs[4];
u8 __pad[28];
-} __attribute__ ((packed));
+} __packed;
#endif /* __iwl_3945_fh_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
index 91bcb4e3cdfb..7c731a793632 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h
@@ -96,7 +96,7 @@ struct iwl3945_eeprom_txpower_sample {
u8 gain_index; /* index into power (gain) setup table ... */
s8 power; /* ... for this pwr level for this chnl group */
u16 v_det; /* PA output voltage */
-} __attribute__ ((packed));
+} __packed;
/*
* Mappings of Tx power levels -> nominal radio/DSP gain table indexes.
@@ -117,7 +117,7 @@ struct iwl3945_eeprom_txpower_group {
u8 group_channel; /* "representative" channel # in this band */
s16 temperature; /* h/w temperature at factory calib this band
* (signed) */
-} __attribute__ ((packed));
+} __packed;
/*
* Temperature-based Tx-power compensation data, not band-specific.
@@ -131,7 +131,7 @@ struct iwl3945_eeprom_temperature_corr {
u32 Tc;
u32 Td;
u32 Te;
-} __attribute__ ((packed));
+} __packed;
/*
* EEPROM map
@@ -215,7 +215,7 @@ struct iwl3945_eeprom {
/* abs.ofs: 512 */
struct iwl3945_eeprom_temperature_corr corrections; /* abs.ofs: 832 */
u8 reserved16[172]; /* fill out to full 1024 byte block */
-} __attribute__ ((packed));
+} __packed;
#define IWL3945_EEPROM_IMG_SIZE 1024
@@ -274,7 +274,7 @@ static inline int iwl3945_hw_valid_rtc_data_addr(u32 addr)
* and &iwl3945_shared.rx_read_ptr[0] is provided to FH_RCSR_RPTR_ADDR(0) */
struct iwl3945_shared {
__le32 tx_base_ptr[8];
-} __attribute__ ((packed));
+} __packed;
static inline u8 iwl3945_hw_get_rate(__le16 rate_n_flags)
{
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 068f7f8435c5..0fa1d51c9c5a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -279,8 +279,8 @@ static void iwl3945_tx_queue_reclaim(struct iwl_priv *priv,
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]);
- tx_info->skb[0] = NULL;
+ ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
+ tx_info->skb = NULL;
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
}
@@ -315,7 +315,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
ieee80211_tx_info_clear_status(info);
/* Fill the MRR chain with some info about on-chip retransmissions */
@@ -352,7 +352,7 @@ static void iwl3945_rx_reply_tx(struct iwl_priv *priv,
* RX handler implementations
*
*****************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
/*
* based on the assumption of all statistics counter are in DWORD
* FIXME: This function is for debugging, do not deal with
@@ -460,7 +460,7 @@ void iwl3945_hw_rx_statistics(struct iwl_priv *priv,
IWL_DEBUG_RX(priv, "Statistics notification received (%d vs %d).\n",
(int)sizeof(struct iwl3945_notif_statistics),
le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl3945_accumulative_statistics(priv, (__le32 *)&pkt->u.raw);
#endif
iwl_recover_from_statistics(priv, pkt);
@@ -475,7 +475,7 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
__le32 *flag = (__le32 *)&pkt->u.raw;
if (le32_to_cpu(*flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
memset(&priv->_3945.accum_statistics, 0,
sizeof(struct iwl3945_notif_statistics));
memset(&priv->_3945.delta_statistics, 0,
@@ -494,158 +494,6 @@ void iwl3945_reply_statistics(struct iwl_priv *priv,
* Misc. internal state and helper functions
*
******************************************************************************/
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/**
- * iwl3945_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good frames.
- */
-static void _iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- __le16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- u16 length;
- u16 status;
- u16 bcn_tmr;
- u32 tsf_low;
- u64 tsf;
- u8 rssi;
- u8 agc;
- u16 sig_avg;
- u16 noise_diff;
- struct iwl3945_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt);
- struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
- struct iwl3945_rx_frame_end *rx_end = IWL_RX_END(pkt);
- u8 *data = IWL_RX_DATA(pkt);
-
- /* MAC header */
- fc = header->frame_control;
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(rx_hdr->channel);
- phy_flags = le16_to_cpu(rx_hdr->phy_flags);
- length = le16_to_cpu(rx_hdr->len);
-
- /* end-of-frame status and timestamp */
- status = le32_to_cpu(rx_end->status);
- bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp);
- tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff;
- tsf = le64_to_cpu(rx_end->timestamp);
-
- /* signal statistics */
- rssi = rx_stats->rssi;
- agc = rx_stats->agc;
- sig_avg = le16_to_cpu(rx_stats->sig_avg);
- noise_diff = le16_to_cpu(rx_stats->noise_diff);
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
- cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- int rate;
-
- if (hundred)
- title = "100Frames";
- else if (ieee80211_has_retry(fc))
- title = "Retry";
- else if (ieee80211_is_assoc_resp(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_resp(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_resp(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate = iwl3945_hwrate_to_plcp_idx(rx_hdr->rate);
- if (rate == -1)
- rate = 0;
- else
- rate = iwl3945_rates[rate].ieee / 2;
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%d,\n",
- title, le16_to_cpu(fc), header->addr1[5],
- length, rssi, channel, rate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, "
- "src=0x%02x, rssi=%u, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, le16_to_cpu(fc), header->addr1[5],
- header->addr3[5], rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, data, length);
-}
-
-static void iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
- if (iwl_get_debug_level(priv) & IWL_DL_RX)
- _iwl3945_dbg_report_frame(priv, pkt, header, group100);
-}
-
-#else
-static inline void iwl3945_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_packet *pkt,
- struct ieee80211_hdr *header, int group100)
-{
-}
-#endif
/* This is necessary only for a number of statistics, see the caller. */
static int iwl3945_is_network_packet(struct iwl_priv *priv,
@@ -777,8 +625,6 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
rx_status.signal, rx_status.signal,
rx_status.rate_idx);
- /* Set "1" to report good data frames in groups of 100 */
- iwl3945_dbg_report_frame(priv, pkt, header, 1);
iwl_dbg_log_rx_data_frame(priv, le16_to_cpu(rx_hdr->len), header);
if (network_packet) {
@@ -850,25 +696,28 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (counter)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->meta[index], mapping),
- pci_unmap_len(&txq->meta[index], len),
+ dma_unmap_addr(&txq->meta[index], mapping),
+ dma_unmap_len(&txq->meta[index], len),
PCI_DMA_TODEVICE);
/* unmap chunks if any */
- for (i = 1; i < counter; i++) {
+ for (i = 1; i < counter; i++)
pci_unmap_single(dev, le32_to_cpu(tfd->tbs[i].addr),
le32_to_cpu(tfd->tbs[i].len), PCI_DMA_TODEVICE);
- if (txq->txb[txq->q.read_ptr].skb[0]) {
- struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[0];
- if (txq->txb[txq->q.read_ptr].skb[0]) {
- /* Can be called from interrupt context */
- dev_kfree_skb_any(skb);
- txq->txb[txq->q.read_ptr].skb[0] = NULL;
- }
+
+ /* free SKB */
+ if (txq->txb) {
+ struct sk_buff *skb;
+
+ skb = txq->txb[txq->q.read_ptr].skb;
+
+ /* can be called from irqs-disabled context */
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.read_ptr].skb = NULL;
}
}
- return ;
}
/**
@@ -947,8 +796,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl_priv *priv,
tx_cmd->supp_rates[1], tx_cmd->supp_rates[0]);
}
-static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
- u16 tx_rate, u8 flags)
+static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id, u16 tx_rate)
{
unsigned long flags_spin;
struct iwl_station_entry *station;
@@ -962,10 +810,9 @@ static u8 iwl3945_sync_sta(struct iwl_priv *priv, int sta_id,
station->sta.sta.modify_mask = STA_MODIFY_TX_RATE_MSK;
station->sta.rate_n_flags = cpu_to_le16(tx_rate);
station->sta.mode = STA_CONTROL_MODIFY_MSK;
-
+ iwl_send_add_sta(priv, &station->sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- iwl_send_add_sta(priv, &station->sta, flags);
IWL_DEBUG_RATE(priv, "SCALE sync station %d to rate %d\n",
sta_id, tx_rate);
return sta_id;
@@ -2473,8 +2320,7 @@ static int iwl3945_manage_ibss_station(struct iwl_priv *priv,
iwl3945_sync_sta(priv, vif_priv->ibss_bssid_sta_id,
(priv->band == IEEE80211_BAND_5GHZ) ?
- IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP,
- CMD_ASYNC);
+ IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP);
iwl3945_rate_scale_init(priv->hw, vif_priv->ibss_bssid_sta_id);
return 0;
@@ -2590,6 +2436,7 @@ int iwl3945_hw_set_hw_params(struct iwl_priv *priv)
priv->hw_params.rx_wrt_ptr_reg = FH39_RSCSR_CHNL0_WPTR;
priv->hw_params.max_beacon_itrvl = IWL39_MAX_UCODE_BEACON_INTERVAL;
+ priv->hw_params.beacon_time_tsf_bits = IWL3945_EXT_BEACON_TIME_POS;
return 0;
}
@@ -2852,6 +2699,7 @@ static struct iwl_lib_ops iwl3945_lib = {
.isr = iwl_isr_legacy,
.config_ap = iwl3945_config_ap,
.manage_ibss_station = iwl3945_manage_ibss_station,
+ .recover_from_tx_stall = iwl_bg_monitor_recover,
.check_plcp_health = iwl3945_good_plcp_health,
.debugfs_ops = {
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
index cd4b61ae25b7..9166794eda0d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h
@@ -787,6 +787,6 @@ enum {
struct iwl4965_scd_bc_tbl {
__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)];
-} __attribute__ ((packed));
+} __packed;
#endif /* !__iwl_4965_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index d3afddae8d9f..83e6a42ca2da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -346,9 +346,19 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv)
{
struct iwl_chain_noise_data *data = &(priv->chain_noise_data);
- if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+ iwl_is_associated(priv)) {
struct iwl_calib_diff_gain_cmd cmd;
+ /* clear data for chain noise calibration algorithm */
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+
memset(&cmd, 0, sizeof(cmd));
cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD;
cmd.diff_gain_a = 0;
@@ -419,13 +429,6 @@ static void iwl4965_gain_computation(struct iwl_priv *priv,
/* Mark so we run this algo only once! */
data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
- data->chain_noise_a = 0;
- data->chain_noise_b = 0;
- data->chain_noise_c = 0;
- data->chain_signal_a = 0;
- data->chain_signal_b = 0;
- data->chain_signal_c = 0;
- data->beacon_count = 0;
}
static void iwl4965_bg_txpower_work(struct work_struct *work)
@@ -669,6 +672,7 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv)
priv->cfg->ops->lib->temp_ops.set_ct_kill(priv);
priv->hw_params.sens = &iwl4965_sensitivity;
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
return 0;
}
@@ -1441,7 +1445,8 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl4965_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
int rc;
u8 band = 0;
@@ -1449,11 +1454,14 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
u8 ctrl_chan_high = 0;
struct iwl4965_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
-
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
band = priv->band == IEEE80211_BAND_2GHZ;
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
-
is_ht40 = is_ht40_channel(priv->staging_rxon.flags);
if (is_ht40 &&
@@ -1462,26 +1470,56 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel)
cmd.band = band;
cmd.expect_beacon = 0;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- rc = iwl4965_fill_txpower_tbl(priv, band, channel, is_ht40,
+ rc = iwl4965_fill_txpower_tbl(priv, band, ch, is_ht40,
ctrl_chan_high, &cmd.tx_power);
if (rc) {
IWL_DEBUG_11H(priv, "error:%d fill txpower_tbl\n", rc);
return rc;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_pdu(priv, REPLY_CHANNEL_SWITCH, sizeof(cmd), &cmd);
@@ -1870,7 +1908,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
- info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->flags |= iwl_tx_status_to_mac80211(status);
@@ -2026,6 +2064,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
int sta_id;
int freed;
u8 *qc = NULL;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -2035,7 +2074,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
hdr = iwl_tx_queue_get_hdr(priv, txq_id, index);
@@ -2050,10 +2089,10 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
return;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp);
struct iwl_ht_agg *agg = NULL;
-
WARN_ON(!qc);
agg = &priv->stations[sta_id].tid[tid].agg;
@@ -2110,6 +2149,8 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
static int iwl4965_calc_rssi(struct iwl_priv *priv,
@@ -2285,7 +2326,7 @@ struct iwl_cfg iwl4965_agn_cfg = {
* Force use of chains B and C for scan RX on 5 GHz band
* because the device has off-channel reception on chain A.
*/
- .scan_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
+ .scan_rx_antennas[IEEE80211_BAND_5GHZ] = ANT_BC,
};
/* Module firmware */
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index a28af7eb67eb..32710a801cb0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -208,6 +208,8 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ_PERD) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
@@ -252,6 +254,8 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
@@ -267,33 +271,69 @@ static void iwl5150_temperature(struct iwl_priv *priv)
iwl_tt_handler(priv);
}
-static int iwl5000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
struct iwl5000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
- .flags = CMD_SIZE_HUGE,
+ .flags = CMD_SYNC,
.data = &cmd,
};
- IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
- priv->active_rxon.channel, channel);
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
+ priv->active_rxon.channel, ch);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 9fbf54cd3e1a..afdeec56b13f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -71,6 +71,10 @@
#define _IWL6000G2A_MODULE_FIRMWARE(api) IWL6000G2A_FW_PRE #api ".ucode"
#define IWL6000G2A_MODULE_FIRMWARE(api) _IWL6000G2A_MODULE_FIRMWARE(api)
+#define IWL6000G2B_FW_PRE "iwlwifi-6000g2b-"
+#define _IWL6000G2B_MODULE_FIRMWARE(api) IWL6000G2B_FW_PRE #api ".ucode"
+#define IWL6000G2B_MODULE_FIRMWARE(api) _IWL6000G2B_MODULE_FIRMWARE(api)
+
static void iwl6000_set_ct_threshold(struct iwl_priv *priv)
{
@@ -183,6 +187,8 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
@@ -228,37 +234,74 @@ static int iwl6050_hw_set_hw_params(struct iwl_priv *priv)
BIT(IWL_CALIB_TX_IQ) |
BIT(IWL_CALIB_BASE_BAND);
+ priv->hw_params.beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
+
return 0;
}
-static int iwl6000_hw_channel_switch(struct iwl_priv *priv, u16 channel)
+static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch)
{
struct iwl6000_channel_switch_cmd cmd;
const struct iwl_channel_info *ch_info;
+ u32 switch_time_in_usec, ucode_switch_time;
+ u16 ch;
+ u32 tsf_low;
+ u8 switch_count;
+ u16 beacon_interval = le16_to_cpu(priv->rxon_timing.beacon_interval);
+ struct ieee80211_vif *vif = priv->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
.len = sizeof(cmd),
- .flags = CMD_SIZE_HUGE,
+ .flags = CMD_SYNC,
.data = &cmd,
};
- IWL_DEBUG_11H(priv, "channel switch from %d to %d\n",
- priv->active_rxon.channel, channel);
-
cmd.band = priv->band == IEEE80211_BAND_2GHZ;
- cmd.channel = cpu_to_le16(channel);
+ ch = ieee80211_frequency_to_channel(ch_switch->channel->center_freq);
+ IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
+ priv->active_rxon.channel, ch);
+ cmd.channel = cpu_to_le16(ch);
cmd.rxon_flags = priv->staging_rxon.flags;
cmd.rxon_filter_flags = priv->staging_rxon.filter_flags;
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
- ch_info = iwl_get_channel_info(priv, priv->band, channel);
+ switch_count = ch_switch->count;
+ tsf_low = ch_switch->timestamp & 0x0ffffffff;
+ /*
+ * calculate the ucode channel switch time
+ * adding TSF as one of the factor for when to switch
+ */
+ if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
+ if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
+ beacon_interval)) {
+ switch_count -= (priv->ucode_beacon_time -
+ tsf_low) / beacon_interval;
+ } else
+ switch_count = 0;
+ }
+ if (switch_count <= 1)
+ cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ else {
+ switch_time_in_usec =
+ vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
+ ucode_switch_time = iwl_usecs_to_beacons(priv,
+ switch_time_in_usec,
+ beacon_interval);
+ cmd.switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
+ }
+ IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
+ cmd.switch_time);
+ ch_info = iwl_get_channel_info(priv, priv->band, ch);
if (ch_info)
cmd.expect_beacon = is_channel_radar(ch_info);
else {
IWL_ERR(priv, "invalid channel switch from %u to %u\n",
- priv->active_rxon.channel, channel);
+ priv->active_rxon.channel, ch);
return -EFAULT;
}
- priv->switch_rxon.channel = cpu_to_le16(channel);
+ priv->switch_rxon.channel = cmd.channel;
priv->switch_rxon.switch_in_progress = true;
return iwl_send_cmd_sync(priv, &hcmd);
@@ -335,6 +378,25 @@ static const struct iwl_ops iwl6000_ops = {
.led = &iwlagn_led_ops,
};
+static void do_not_send_bt_config(struct iwl_priv *priv)
+{
+}
+
+static struct iwl_hcmd_ops iwl6000g2b_hcmd = {
+ .rxon_assoc = iwlagn_send_rxon_assoc,
+ .commit_rxon = iwl_commit_rxon,
+ .set_rxon_chain = iwl_set_rxon_chain,
+ .set_tx_ant = iwlagn_send_tx_ant_config,
+ .send_bt_config = do_not_send_bt_config,
+};
+
+static const struct iwl_ops iwl6000g2b_ops = {
+ .lib = &iwl6000_lib,
+ .hcmd = &iwl6000g2b_hcmd,
+ .utils = &iwlagn_hcmd_utils,
+ .led = &iwlagn_led_ops,
+};
+
static struct iwl_lib_ops iwl6050_lib = {
.set_hw_params = iwl6050_hw_set_hw_params,
.txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
@@ -445,6 +507,268 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
.chain_noise_calib_by_driver = true,
};
+struct iwl_cfg iwl6000g2a_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2a_2bg_cfg = {
+ .name = "6000 Series 2x2 BG Gen2a",
+ .fw_name_pre = IWL6000G2A_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_2agn_cfg = {
+ .name = "6000 Series 2x2 AGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_2abg_cfg = {
+ .name = "6000 Series 2x2 ABG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_A|IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_2bgn_cfg = {
+ .name = "6000 Series 2x2 BGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_2bg_cfg = {
+ .name = "6000 Series 2x2 BG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_AB,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_bgn_cfg = {
+ .name = "6000 Series 1x2 BGN Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G|IWL_SKU_N,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .ht_greenfield_support = true,
+ .led_compensation = 51,
+ .use_rts_for_ht = true, /* use rts/cts protection */
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
+struct iwl_cfg iwl6000g2b_bg_cfg = {
+ .name = "6000 Series 1x2 BG Gen2b",
+ .fw_name_pre = IWL6000G2B_FW_PRE,
+ .ucode_api_max = IWL6000G2_UCODE_API_MAX,
+ .ucode_api_min = IWL6000G2_UCODE_API_MIN,
+ .sku = IWL_SKU_G,
+ .ops = &iwl6000g2b_ops,
+ .eeprom_size = OTP_LOW_IMAGE_SIZE,
+ .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
+ .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
+ .num_of_queues = IWLAGN_NUM_QUEUES,
+ .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
+ .mod_params = &iwlagn_mod_params,
+ .valid_tx_ant = ANT_A,
+ .valid_rx_ant = ANT_AB,
+ .pll_cfg_val = 0,
+ .set_l0s = true,
+ .use_bsm = false,
+ .pa_type = IWL_PA_SYSTEM,
+ .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
+ .shadow_ram_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
+ .supports_idle = true,
+ .adv_thermal_throttle = true,
+ .support_ct_kill_exit = true,
+ .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
+ .chain_noise_scale = 1000,
+ .monitor_recover_period = IWL_MONITORING_PERIOD,
+ .max_event_log_size = 512,
+};
+
/*
* "i": Internal configuration, use internal Power Amplifier
*/
@@ -667,3 +991,4 @@ struct iwl_cfg iwl6000_3agn_cfg = {
MODULE_FIRMWARE(IWL6000_MODULE_FIRMWARE(IWL6000_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6050_MODULE_FIRMWARE(IWL6050_UCODE_API_MAX));
MODULE_FIRMWARE(IWL6000G2A_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL6000G2B_MODULE_FIRMWARE(IWL6000G2_UCODE_API_MAX));
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
index 48c023b4ca36..3d08dc8af143 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-debugfs.c
@@ -28,6 +28,27 @@
#include "iwl-agn-debugfs.h"
+static int iwl_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
+{
+ int p = 0;
+
+ p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
+ le32_to_cpu(priv->statistics.flag));
+ if (le32_to_cpu(priv->statistics.flag) &
+ UCODE_STATISTICS_CLEAR_MSK)
+ p += scnprintf(buf + p, bufsz - p,
+ "\tStatistics have been cleared\n");
+ p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
+ (le32_to_cpu(priv->statistics.flag) &
+ UCODE_STATISTICS_FREQUENCY_MSK)
+ ? "2.4 GHz" : "5.2 GHz");
+ p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
+ (le32_to_cpu(priv->statistics.flag) &
+ UCODE_STATISTICS_NARROW_BAND_MSK)
+ ? "enabled" : "disabled");
+ return p;
+}
+
ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
@@ -75,7 +96,7 @@ ssize_t iwl_ucode_rx_stats_read(struct file *file, char __user *user_buf,
max_general = &priv->max_delta.rx.general;
max_ht = &priv->max_delta.rx.ofdm_ht;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Rx - OFDM:");
@@ -543,7 +564,7 @@ ssize_t iwl_ucode_tx_stats_read(struct file *file,
accum_tx = &priv->accum_statistics.tx;
delta_tx = &priv->delta_statistics.tx;
max_tx = &priv->max_delta.tx;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_Tx:");
@@ -768,7 +789,7 @@ ssize_t iwl_ucode_general_stats_read(struct file *file, char __user *user_buf,
accum_div = &priv->accum_statistics.general.div;
delta_div = &priv->delta_statistics.general.div;
max_div = &priv->max_delta.general.div;
- pos += iwl_dbgfs_statistics_flag(priv, buf, bufsz);
+ pos += iwl_statistics_flag(priv, buf, bufsz);
pos += scnprintf(buf + pos, bufsz - pos, "%-32s current"
"acumulative delta max\n",
"Statistics_General:");
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 44ef5d93befc..3f765ba15cb8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -37,7 +37,7 @@
#include "iwl-io.h"
#include "iwl-agn.h"
-static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
{
int ret = 0;
struct iwl5000_rxon_assoc_cmd rxon_assoc;
@@ -84,7 +84,7 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv)
return ret;
}
-static int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant)
{
struct iwl_tx_ant_config_cmd tx_ant_cmd = {
.valid = cpu_to_le32(valid_tx_ant),
@@ -176,14 +176,6 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
data->radio_write = 1;
data->state = IWL_CHAIN_NOISE_CALIBRATED;
}
-
- data->chain_noise_a = 0;
- data->chain_noise_b = 0;
- data->chain_noise_c = 0;
- data->chain_signal_a = 0;
- data->chain_signal_b = 0;
- data->chain_signal_c = 0;
- data->beacon_count = 0;
}
static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
@@ -191,10 +183,20 @@ static void iwlagn_chain_noise_reset(struct iwl_priv *priv)
struct iwl_chain_noise_data *data = &priv->chain_noise_data;
int ret;
- if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) {
+ if ((data->state == IWL_CHAIN_NOISE_ALIVE) &&
+ iwl_is_associated(priv)) {
struct iwl_calib_chain_noise_reset_cmd cmd;
- memset(&cmd, 0, sizeof(cmd));
+ /* clear data for chain noise calibration algorithm */
+ data->chain_noise_a = 0;
+ data->chain_noise_b = 0;
+ data->chain_noise_c = 0;
+ data->chain_signal_a = 0;
+ data->chain_signal_b = 0;
+ data->chain_signal_c = 0;
+ data->beacon_count = 0;
+
+ memset(&cmd, 0, sizeof(cmd));
cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD;
cmd.hdr.first_group = 0;
cmd.hdr.groups_num = 1;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
index f9a3fbb6338f..a52b82c8e7a6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h
@@ -112,7 +112,7 @@
*/
struct iwlagn_scd_bc_tbl {
__le16 tfd_offset[TFD_QUEUE_BC_SIZE];
-} __attribute__ ((packed));
+} __packed;
#endif /* __iwl_agn_hw_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 1004cfc403b1..548f51d92de0 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -77,7 +77,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "FrameCnt = %d, StartIdx=%d idx=%d\n",
agg->frame_count, agg->start_idx, idx);
- info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb);
info->status.rates[0].count = tx_resp->failure_frame + 1;
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
info->flags |= iwl_tx_status_to_mac80211(status);
@@ -93,6 +93,12 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
} else {
/* Two or more frames were attempted; expect block-ack */
u64 bitmap = 0;
+
+ /*
+ * Start is the lowest frame sent. It may not be the first
+ * frame in the batch; we figure this out dynamically during
+ * the following loop.
+ */
int start = agg->start_idx;
/* Construct bit-map of pending frames within Tx window */
@@ -131,25 +137,58 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv,
IWL_DEBUG_TX_REPLY(priv, "AGG Frame i=%d idx %d seq=%d\n",
i, idx, SEQ_TO_SN(sc));
+ /*
+ * sh -> how many frames ahead of the starting frame is
+ * the current one?
+ *
+ * Note that all frames sent in the batch must be in a
+ * 64-frame window, so this number should be in [0,63].
+ * If outside of this window, then we've found a new
+ * "first" frame in the batch and need to change start.
+ */
sh = idx - start;
- if (sh > 64) {
- sh = (start - idx) + 0xff;
+
+ /*
+ * If >= 64, out of window. start must be at the front
+ * of the circular buffer, idx must be near the end of
+ * the buffer, and idx is the new "first" frame. Shift
+ * the indices around.
+ */
+ if (sh >= 64) {
+ /* Shift bitmap by start - idx, wrapped */
+ sh = 0x100 - idx + start;
bitmap = bitmap << sh;
+ /* Now idx is the new start so sh = 0 */
sh = 0;
start = idx;
- } else if (sh < -64)
- sh = 0xff - (start - idx);
- else if (sh < 0) {
+ /*
+ * If <= -64 then wraps the 256-pkt circular buffer
+ * (e.g., start = 255 and idx = 0, sh should be 1)
+ */
+ } else if (sh <= -64) {
+ sh = 0x100 - start + idx;
+ /*
+ * If < 0 but > -64, out of window. idx is before start
+ * but not wrapped. Shift the indices around.
+ */
+ } else if (sh < 0) {
+ /* Shift by how far start is ahead of idx */
sh = start - idx;
- start = idx;
bitmap = bitmap << sh;
+ /* Now idx is the new start so sh = 0 */
+ start = idx;
sh = 0;
}
+ /* Sequence number start + sh was sent in this batch */
bitmap |= 1ULL << sh;
IWL_DEBUG_TX_REPLY(priv, "start=%d bitmap=0x%llx\n",
start, (unsigned long long)bitmap);
}
+ /*
+ * Store the bitmap and possibly the new start, if we wrapped
+ * the buffer above
+ */
agg->bitmap = bitmap;
agg->start_idx = start;
IWL_DEBUG_TX_REPLY(priv, "Frames %d start_idx=%d bitmap=0x%llx\n",
@@ -184,6 +223,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
int tid;
int sta_id;
int freed;
+ unsigned long flags;
if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
@@ -193,15 +233,16 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
return;
}
- info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]);
+ info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb);
memset(&info->status, 0, sizeof(info->status));
tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS;
sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS;
+ spin_lock_irqsave(&priv->sta_lock, flags);
if (txq->sched_retry) {
const u32 scd_ssn = iwlagn_get_scd_ssn(tx_resp);
- struct iwl_ht_agg *agg = NULL;
+ struct iwl_ht_agg *agg;
agg = &priv->stations[sta_id].tid[tid].agg;
@@ -256,6 +297,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, txq_id);
iwl_check_abort_status(priv, tx_resp->frame_count, status);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
void iwlagn_rx_handler_setup(struct iwl_priv *priv)
@@ -755,132 +797,6 @@ static inline int iwlagn_calc_rssi(struct iwl_priv *priv,
return priv->cfg->ops->utils->calc_rssi(priv, rx_resp);
}
-#ifdef CONFIG_IWLWIFI_DEBUG
-/**
- * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions
- *
- * You may hack this function to show different aspects of received frames,
- * including selective frame dumps.
- * group100 parameter selects whether to show 1 out of 100 good data frames.
- * All beacon and probe response frames are printed.
- */
-static void iwlagn_dbg_report_frame(struct iwl_priv *priv,
- struct iwl_rx_phy_res *phy_res, u16 length,
- struct ieee80211_hdr *header, int group100)
-{
- u32 to_us;
- u32 print_summary = 0;
- u32 print_dump = 0; /* set to 1 to dump all frames' contents */
- u32 hundred = 0;
- u32 dataframe = 0;
- __le16 fc;
- u16 seq_ctl;
- u16 channel;
- u16 phy_flags;
- u32 rate_n_flags;
- u32 tsf_low;
- int rssi;
-
- if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX)))
- return;
-
- /* MAC header */
- fc = header->frame_control;
- seq_ctl = le16_to_cpu(header->seq_ctrl);
-
- /* metadata */
- channel = le16_to_cpu(phy_res->channel);
- phy_flags = le16_to_cpu(phy_res->phy_flags);
- rate_n_flags = le32_to_cpu(phy_res->rate_n_flags);
-
- /* signal statistics */
- rssi = iwlagn_calc_rssi(priv, phy_res);
- tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff;
-
- to_us = !compare_ether_addr(header->addr1, priv->mac_addr);
-
- /* if data frame is to us and all is good,
- * (optionally) print summary for only 1 out of every 100 */
- if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) ==
- cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) {
- dataframe = 1;
- if (!group100)
- print_summary = 1; /* print each frame */
- else if (priv->framecnt_to_us < 100) {
- priv->framecnt_to_us++;
- print_summary = 0;
- } else {
- priv->framecnt_to_us = 0;
- print_summary = 1;
- hundred = 1;
- }
- } else {
- /* print summary for all other frames */
- print_summary = 1;
- }
-
- if (print_summary) {
- char *title;
- int rate_idx;
- u32 bitrate;
-
- if (hundred)
- title = "100Frames";
- else if (ieee80211_has_retry(fc))
- title = "Retry";
- else if (ieee80211_is_assoc_resp(fc))
- title = "AscRsp";
- else if (ieee80211_is_reassoc_resp(fc))
- title = "RasRsp";
- else if (ieee80211_is_probe_resp(fc)) {
- title = "PrbRsp";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_beacon(fc)) {
- title = "Beacon";
- print_dump = 1; /* dump frame contents */
- } else if (ieee80211_is_atim(fc))
- title = "ATIM";
- else if (ieee80211_is_auth(fc))
- title = "Auth";
- else if (ieee80211_is_deauth(fc))
- title = "DeAuth";
- else if (ieee80211_is_disassoc(fc))
- title = "DisAssoc";
- else
- title = "Frame";
-
- rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags);
- if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) {
- bitrate = 0;
- WARN_ON_ONCE(1);
- } else {
- bitrate = iwl_rates[rate_idx].ieee / 2;
- }
-
- /* print frame summary.
- * MAC addresses show just the last byte (for brevity),
- * but you can hack it to show more, if you'd like to. */
- if (dataframe)
- IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, "
- "len=%u, rssi=%d, chnl=%d, rate=%u,\n",
- title, le16_to_cpu(fc), header->addr1[5],
- length, rssi, channel, bitrate);
- else {
- /* src/dst addresses assume managed mode */
- IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, "
- "len=%u, rssi=%d, tim=%lu usec, "
- "phy=0x%02x, chnl=%d\n",
- title, le16_to_cpu(fc), header->addr1[5],
- header->addr3[5], length, rssi,
- tsf_low - priv->scan_start_tsf,
- phy_flags, channel);
- }
- }
- if (print_dump)
- iwl_print_hex_dump(priv, IWL_DL_RX, header, length);
-}
-#endif
-
static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in)
{
u32 decrypt_out = 0;
@@ -1060,11 +976,6 @@ void iwlagn_rx_reply_rx(struct iwl_priv *priv,
/* Find max signal strength (dBm) among 3 antenna/receiver chains */
rx_status.signal = iwlagn_calc_rssi(priv, phy_res);
-#ifdef CONFIG_IWLWIFI_DEBUG
- /* Set "1" to report good data frames in groups of 100 */
- if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX))
- iwlagn_dbg_report_frame(priv, phy_res, len, header, 1);
-#endif
iwl_dbg_log_rx_data_frame(priv, len, header);
IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, TSF %llu\n",
rx_status.signal, (unsigned long long)rx_status.mactime);
@@ -1119,10 +1030,9 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
struct iwl_scan_channel *scan_ch)
{
const struct ieee80211_supported_band *sband;
- const struct iwl_channel_info *ch_info;
u16 passive_dwell = 0;
u16 active_dwell = 0;
- int i, added = 0;
+ int added = 0;
u16 channel = 0;
sband = iwl_get_hw_mode(priv, band);
@@ -1137,32 +1047,7 @@ static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
if (passive_dwell <= active_dwell)
passive_dwell = active_dwell + 1;
- /* only scan single channel, good enough to reset the RF */
- /* pick the first valid not in-use channel */
- if (band == IEEE80211_BAND_5GHZ) {
- for (i = 14; i < priv->channel_count; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel = priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
- }
- } else {
- for (i = 0; i < 14; i++) {
- if (priv->channel_info[i].channel !=
- le16_to_cpu(priv->staging_rxon.channel)) {
- channel =
- priv->channel_info[i].channel;
- ch_info = iwl_get_channel_info(priv,
- band, channel);
- if (is_channel_valid(ch_info))
- break;
- }
- }
- }
+ channel = iwl_get_single_channel_number(priv, band);
if (channel) {
scan_ch->channel = cpu_to_le16(channel);
scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
@@ -1278,6 +1163,7 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
bool is_active = false;
int chan_mod;
u8 active_chains;
+ u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
conf = ieee80211_get_hw_conf(priv->hw);
@@ -1429,11 +1315,14 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
band = priv->scan_band;
- if (priv->cfg->scan_antennas[band])
- rx_ant = priv->cfg->scan_antennas[band];
+ if (priv->cfg->scan_rx_antennas[band])
+ rx_ant = priv->cfg->scan_rx_antennas[band];
- priv->scan_tx_ant[band] =
- iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]);
+ if (priv->cfg->scan_tx_antennas[band])
+ scan_tx_antennas = priv->cfg->scan_tx_antennas[band];
+
+ priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
+ scan_tx_antennas);
rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
@@ -1459,13 +1348,15 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (!priv->is_internal_short_scan) {
cmd_len = iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
+ vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
} else {
+ /* use bcast addr, will not be transmitted but must be valid */
cmd_len = iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
- NULL, 0,
+ iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
}
@@ -1528,3 +1419,18 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
return iwl_remove_station(priv, vif_priv->ibss_bssid_sta_id,
vif->bss_conf.bssid);
}
+
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed)
+{
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
+ if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
+ priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
+ else {
+ IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
+ priv->stations[sta_id].tid[tid].tfds_in_queue,
+ freed);
+ priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
+ }
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index cf4a95bae4ff..40933a5de027 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -313,8 +313,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
*/
IWL_DEBUG_HT(priv, "Fail start Tx agg on tid: %d\n",
tid);
- ieee80211_stop_tx_ba_session(sta, tid,
- WLAN_BACK_INITIATOR);
+ ieee80211_stop_tx_ba_session(sta, tid);
}
} else
IWL_ERR(priv, "Fail finding valid aggregation tid: %d\n", tid);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index c402bfc83f36..10a0acdb9dd4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -469,7 +469,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv,
}
/* Set up antennas */
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+ priv->hw_params.valid_tx_ant);
rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
/* Set the rate in the TX cmd */
@@ -567,10 +568,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- if (!info->control.sta)
- sta_id = priv->hw_params.bcast_sta_id;
- else
- sta_id = iwl_sta_id(info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -598,11 +596,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
}
txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
+
+ /* irqs already disabled/saved above when locking priv->lock */
+ spin_lock(&priv->sta_lock);
+
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (unlikely(tid >= MAX_TID_COUNT))
+ if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
@@ -620,15 +624,22 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
swq_id = txq->swq_id;
q = &txq->q;
- if (unlikely(iwl_queue_space(q) < q->high_mark))
+ if (unlikely(iwl_queue_space(q) < q->high_mark)) {
+ spin_unlock(&priv->sta_lock);
goto drop_unlock;
+ }
- if (ieee80211_is_data_qos(fc))
+ if (ieee80211_is_data_qos(fc)) {
priv->stations[sta_id].tid[tid].tfds_in_queue++;
+ if (!ieee80211_has_morefrags(fc))
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+
+ spin_unlock(&priv->sta_lock);
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
- txq->txb[q->write_ptr].skb[0] = skb;
+ txq->txb[q->write_ptr].skb = skb;
/* Set up first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[q->write_ptr];
@@ -694,8 +705,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, len,
PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
- pci_unmap_len_set(out_meta, len, len);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -703,8 +714,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc)
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
@@ -1009,6 +1018,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
if (ret)
return ret;
+ spin_lock_irqsave(&priv->sta_lock, flags);
+ tid_data = &priv->stations[sta_id].tid[tid];
if (tid_data->tfds_in_queue == 0) {
IWL_DEBUG_HT(priv, "HW queue is empty\n");
tid_data->agg.state = IWL_AGG_ON;
@@ -1018,6 +1029,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
tid_data->tfds_in_queue);
tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
}
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return ret;
}
@@ -1040,11 +1052,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
return -ENXIO;
}
+ spin_lock_irqsave(&priv->sta_lock, flags);
+
if (priv->stations[sta_id].tid[tid].agg.state ==
IWL_EMPTYING_HW_QUEUE_ADDBA) {
IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
@@ -1062,13 +1077,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
priv->stations[sta_id].tid[tid].agg.state =
IWL_EMPTYING_HW_QUEUE_DELBA;
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
return 0;
}
IWL_DEBUG_HT(priv, "HW queue is empty\n");
priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
- spin_lock_irqsave(&priv->lock, flags);
+ /* do not restore/save irqs */
+ spin_unlock(&priv->sta_lock);
+ spin_lock(&priv->lock);
+
/*
* the only reason this call can fail is queue number out of range,
* which can happen if uCode is reloaded and all the station
@@ -1092,6 +1111,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
u8 *addr = priv->stations[sta_id].sta.sta.addr;
struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
+ WARN_ON(!spin_is_locked(&priv->sta_lock));
+
switch (priv->stations[sta_id].tid[tid].agg.state) {
case IWL_EMPTYING_HW_QUEUE_DELBA:
/* We are reclaiming the last packet of the */
@@ -1116,6 +1137,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
}
break;
}
+
return 0;
}
@@ -1157,12 +1179,12 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
tx_info = &txq->txb[txq->q.read_ptr];
- iwlagn_tx_status(priv, tx_info->skb[0]);
+ iwlagn_tx_status(priv, tx_info->skb);
- hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data;
+ hdr = (struct ieee80211_hdr *)tx_info->skb->data;
if (hdr && ieee80211_is_data_qos(hdr->frame_control))
nfreed++;
- tx_info->skb[0] = NULL;
+ tx_info->skb = NULL;
if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
@@ -1186,7 +1208,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
int i, sh, ack;
u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
- u64 bitmap;
+ u64 bitmap, sent_bitmap;
int successes = 0;
struct ieee80211_tx_info *info;
@@ -1214,24 +1236,26 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
/* check for success or failure according to the
* transmitted bitmap and block-ack bitmap */
- bitmap &= agg->bitmap;
+ sent_bitmap = bitmap & agg->bitmap;
/* For each frame attempted in aggregation,
* update driver's record of tx frame's status. */
- for (i = 0; i < agg->frame_count ; i++) {
- ack = bitmap & (1ULL << i);
- successes += !!ack;
+ i = 0;
+ while (sent_bitmap) {
+ ack = sent_bitmap & 1ULL;
+ successes += ack;
IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
agg->start_idx + i);
+ sent_bitmap >>= 1;
+ ++i;
}
- info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
+ info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
memset(&info->status, 0, sizeof(info->status));
info->flags |= IEEE80211_TX_STAT_ACK;
info->flags |= IEEE80211_TX_STAT_AMPDU;
info->status.ampdu_ack_len = successes;
- info->status.ampdu_ack_map = bitmap;
info->status.ampdu_len = agg->frame_count;
iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
@@ -1279,6 +1303,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
int index;
int sta_id;
int tid;
+ unsigned long flags;
/* "flow" corresponds to Tx queue */
u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1301,7 +1326,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
/* Find index just before block-ack window */
index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
- /* TODO: Need to get this copy more safely - now good for debug */
+ spin_lock_irqsave(&priv->sta_lock, flags);
IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
"sta_id = %d\n",
@@ -1337,4 +1362,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
}
+
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index 637286c396fe..6f77441cb65a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -423,3 +423,126 @@ int iwlagn_alive_notify(struct iwl_priv *priv)
return 0;
}
+
+
+/**
+ * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
+ * using sample data 100 bytes apart. If these sample points are good,
+ * it's a pretty good bet that everything between them is good, too.
+ */
+static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
+{
+ u32 val;
+ int ret = 0;
+ u32 errcnt = 0;
+ u32 i;
+
+ IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+ for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ i + IWLAGN_RTC_INST_LOWER_BOUND);
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 3)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
+ * looking at all data.
+ */
+static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
+ u32 len)
+{
+ u32 val;
+ u32 save_len = len;
+ int ret = 0;
+ u32 errcnt;
+
+ IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
+
+ iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
+ IWLAGN_RTC_INST_LOWER_BOUND);
+
+ errcnt = 0;
+ for (; len > 0; len -= sizeof(u32), image++) {
+ /* read data comes through single port, auto-incr addr */
+ /* NOTE: Use the debugless read so we don't flood kernel log
+ * if IWL_DL_IO is set */
+ val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
+ if (val != le32_to_cpu(*image)) {
+ IWL_ERR(priv, "uCode INST section is invalid at "
+ "offset 0x%x, is 0x%x, s/b 0x%x\n",
+ save_len - len, val, le32_to_cpu(*image));
+ ret = -EIO;
+ errcnt++;
+ if (errcnt >= 20)
+ break;
+ }
+ }
+
+ if (!errcnt)
+ IWL_DEBUG_INFO(priv,
+ "ucode image in INSTRUCTION memory is good\n");
+
+ return ret;
+}
+
+/**
+ * iwl_verify_ucode - determine which instruction image is in SRAM,
+ * and verify its contents
+ */
+int iwl_verify_ucode(struct iwl_priv *priv)
+{
+ __le32 *image;
+ u32 len;
+ int ret;
+
+ /* Try bootstrap */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try initialize */
+ image = (__le32 *)priv->ucode_init.v_addr;
+ len = priv->ucode_init.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ /* Try runtime/protocol */
+ image = (__le32 *)priv->ucode_code.v_addr;
+ len = priv->ucode_code.len;
+ ret = iwlcore_verify_inst_sparse(priv, image, len);
+ if (!ret) {
+ IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
+ return 0;
+ }
+
+ IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
+
+ /* Since nothing seems to match, show first several data entries in
+ * instruction SRAM, so maybe visual inspection will give a clue.
+ * Selection of bootstrap image (vs. other images) is arbitrary. */
+ image = (__le32 *)priv->ucode_boot.v_addr;
+ len = priv->ucode_boot.len;
+ ret = iwl_verify_inst_full(priv, image, len);
+
+ return ret;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index aef4f71f1981..69e17d782883 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -120,7 +120,7 @@ int iwl_commit_rxon(struct iwl_priv *priv)
(priv->switch_rxon.channel != priv->staging_rxon.channel)) {
IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
le16_to_cpu(priv->switch_rxon.channel));
- priv->switch_rxon.switch_in_progress = false;
+ iwl_chswitch_done(priv, false);
}
/* If we don't need to send a full RXON, we can use
@@ -367,7 +367,8 @@ static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
/* Set up packet rate and flags */
rate = iwl_rate_get_lowest_plcp(priv);
- priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant);
+ priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant,
+ priv->hw_params.valid_tx_ant);
rate_flags = iwl_ant_idx_to_flags(priv->mgmt_tx_ant);
if ((rate >= IWL_FIRST_CCK_RATE) && (rate <= IWL_LAST_CCK_RATE))
rate_flags |= RATE_MCS_CCK_MSK;
@@ -474,18 +475,25 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
/* Unmap tx_cmd */
if (num_tbs)
pci_unmap_single(dev,
- pci_unmap_addr(&txq->meta[index], mapping),
- pci_unmap_len(&txq->meta[index], len),
+ dma_unmap_addr(&txq->meta[index], mapping),
+ dma_unmap_len(&txq->meta[index], len),
PCI_DMA_BIDIRECTIONAL);
/* Unmap chunks, if any. */
- for (i = 1; i < num_tbs; i++) {
+ for (i = 1; i < num_tbs; i++)
pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i),
iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE);
- if (txq->txb) {
- dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]);
- txq->txb[txq->q.read_ptr].skb[i - 1] = NULL;
+ /* free SKB */
+ if (txq->txb) {
+ struct sk_buff *skb;
+
+ skb = txq->txb[txq->q.read_ptr].skb;
+
+ /* can be called from irqs-disabled context */
+ if (skb) {
+ dev_kfree_skb_any(skb);
+ txq->txb[txq->q.read_ptr].skb = NULL;
}
}
}
@@ -1466,7 +1474,12 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
" expected_ack_cnt = %d\n",
actual_ack_cnt_delta, expected_ack_cnt_delta);
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ /*
+ * This is ifdef'ed on DEBUGFS because otherwise the
+ * statistics aren't available. If DEBUGFS is set but
+ * DEBUG is not, these will just compile out.
+ */
IWL_DEBUG_RADIO(priv, "rx_detected_cnt delta = %d\n",
priv->delta_statistics.tx.rx_detected_cnt);
IWL_DEBUG_RADIO(priv,
@@ -1484,6 +1497,156 @@ bool iwl_good_ack_health(struct iwl_priv *priv,
}
+/*****************************************************************************
+ *
+ * sysfs attributes
+ *
+ *****************************************************************************/
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+
+/*
+ * The following adds a new attribute to the sysfs representation
+ * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
+ * used for controlling the debug level.
+ *
+ * See the level definitions in iwl for details.
+ *
+ * The debug_level being managed using sysfs below is a per device debug
+ * level that is used instead of the global debug level if it (the per
+ * device debug level) is set.
+ */
+static ssize_t show_debug_level(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
+}
+static ssize_t store_debug_level(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 0, &val);
+ if (ret)
+ IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
+ else {
+ priv->debug_level = val;
+ if (iwl_alloc_traffic_mem(priv))
+ IWL_ERR(priv,
+ "Not enough memory to generate traffic log\n");
+ }
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
+ show_debug_level, store_debug_level);
+
+
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
+
+static ssize_t show_temperature(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_alive(priv))
+ return -EAGAIN;
+
+ return sprintf(buf, "%d\n", priv->temperature);
+}
+
+static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
+
+static ssize_t show_tx_power(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ if (!iwl_is_ready_rf(priv))
+ return sprintf(buf, "off\n");
+ else
+ return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
+}
+
+static ssize_t store_tx_power(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "%s is not in decimal form.\n", buf);
+ else {
+ ret = iwl_set_tx_power(priv, val, false);
+ if (ret)
+ IWL_ERR(priv, "failed setting tx power (0x%d).\n",
+ ret);
+ else
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+
+static ssize_t show_rts_ht_protection(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+
+ return sprintf(buf, "%s\n",
+ priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
+}
+
+static ssize_t store_rts_ht_protection(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct iwl_priv *priv = dev_get_drvdata(d);
+ unsigned long val;
+ int ret;
+
+ ret = strict_strtoul(buf, 10, &val);
+ if (ret)
+ IWL_INFO(priv, "Input is not in decimal form.\n");
+ else {
+ if (!iwl_is_associated(priv))
+ priv->cfg->use_rts_for_ht = val ? true : false;
+ else
+ IWL_ERR(priv, "Sta associated with AP - "
+ "Change protection mechanism is not allowed\n");
+ ret = count;
+ }
+ return ret;
+}
+
+static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
+ show_rts_ht_protection, store_rts_ht_protection);
+
+
+static struct attribute *iwl_sysfs_entries[] = {
+ &dev_attr_temperature.attr,
+ &dev_attr_tx_power.attr,
+ &dev_attr_rts_ht_protection.attr,
+#ifdef CONFIG_IWLWIFI_DEBUG
+ &dev_attr_debug_level.attr,
+#endif
+ NULL
+};
+
+static struct attribute_group iwl_attribute_group = {
+ .name = NULL, /* put in device directory */
+ .attrs = iwl_sysfs_entries,
+};
+
/******************************************************************************
*
* uCode download functions
@@ -1544,6 +1707,9 @@ struct iwlagn_firmware_pieces {
size_t inst_size, data_size, init_size, init_data_size, boot_size;
u32 build;
+
+ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+ u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
};
static int iwlagn_load_legacy_firmware(struct iwl_priv *priv,
@@ -1721,6 +1887,42 @@ static int iwlagn_load_firmware(struct iwl_priv *priv,
capa->max_probe_length =
le32_to_cpup((__le32 *)tlv_data);
break;
+ case IWL_UCODE_TLV_INIT_EVTLOG_PTR:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->init_evtlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_INIT_EVTLOG_SIZE:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->init_evtlog_size =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_INIT_ERRLOG_PTR:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->init_errlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_EVTLOG_PTR:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->inst_evtlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_EVTLOG_SIZE:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->inst_evtlog_size =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
+ case IWL_UCODE_TLV_RUNT_ERRLOG_PTR:
+ if (tlv_len != 4)
+ return -EINVAL;
+ pieces->inst_errlog_ptr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
default:
break;
}
@@ -1913,6 +2115,26 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
goto err_pci_alloc;
}
+ /* Now that we can no longer fail, copy information */
+
+ /*
+ * The (size - 16) / 12 formula is based on the information recorded
+ * for each event, which is of mode 1 (including timestamp) for all
+ * new microcodes that include this information.
+ */
+ priv->_agn.init_evtlog_ptr = pieces.init_evtlog_ptr;
+ if (pieces.init_evtlog_size)
+ priv->_agn.init_evtlog_size = (pieces.init_evtlog_size - 16)/12;
+ else
+ priv->_agn.init_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.init_errlog_ptr = pieces.init_errlog_ptr;
+ priv->_agn.inst_evtlog_ptr = pieces.inst_evtlog_ptr;
+ if (pieces.inst_evtlog_size)
+ priv->_agn.inst_evtlog_size = (pieces.inst_evtlog_size - 16)/12;
+ else
+ priv->_agn.inst_evtlog_size = priv->cfg->max_event_log_size;
+ priv->_agn.inst_errlog_ptr = pieces.inst_errlog_ptr;
+
/* Copy images into buffers for card's bus-master reads ... */
/* Runtime instructions (first block of data in file) */
@@ -1965,6 +2187,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
if (err)
IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
+ err = sysfs_create_group(&priv->pci_dev->dev.kobj,
+ &iwl_attribute_group);
+ if (err) {
+ IWL_ERR(priv, "failed to create sysfs device attributes\n");
+ goto out_unbind;
+ }
+
/* We have our copies now, allow OS release its copies */
release_firmware(ucode_raw);
complete(&priv->_agn.firmware_loading_complete);
@@ -2038,10 +2267,15 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv)
u32 blink1, blink2, ilink1, ilink2;
u32 pc, hcmd;
- if (priv->ucode_type == UCODE_INIT)
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.error_event_table_ptr);
- else
+ if (!base)
+ base = priv->_agn.init_errlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.error_event_table_ptr);
+ if (!base)
+ base = priv->_agn.inst_errlog_ptr;
+ }
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
@@ -2101,10 +2335,16 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx,
if (num_events == 0)
return pos;
- if (priv->ucode_type == UCODE_INIT)
+
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
+ if (!base)
+ base = priv->_agn.init_evtlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ if (!base)
+ base = priv->_agn.inst_evtlog_ptr;
+ }
if (mode == 0)
event_size = 2 * sizeof(u32);
@@ -2206,13 +2446,21 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
u32 num_wraps; /* # times uCode wrapped to top of log */
u32 next_entry; /* index of next entry to be written by uCode */
u32 size; /* # entries that we'll print */
+ u32 logsize;
int pos = 0;
size_t bufsz = 0;
- if (priv->ucode_type == UCODE_INIT)
+ if (priv->ucode_type == UCODE_INIT) {
base = le32_to_cpu(priv->card_alive_init.log_event_table_ptr);
- else
+ logsize = priv->_agn.init_evtlog_size;
+ if (!base)
+ base = priv->_agn.init_evtlog_ptr;
+ } else {
base = le32_to_cpu(priv->card_alive.log_event_table_ptr);
+ logsize = priv->_agn.inst_evtlog_size;
+ if (!base)
+ base = priv->_agn.inst_evtlog_ptr;
+ }
if (!priv->cfg->ops->lib->is_valid_rtc_data_addr(base)) {
IWL_ERR(priv,
@@ -2227,16 +2475,16 @@ int iwl_dump_nic_event_log(struct iwl_priv *priv, bool full_log,
num_wraps = iwl_read_targ_mem(priv, base + (2 * sizeof(u32)));
next_entry = iwl_read_targ_mem(priv, base + (3 * sizeof(u32)));
- if (capacity > priv->cfg->max_event_log_size) {
+ if (capacity > logsize) {
IWL_ERR(priv, "Log capacity %d is bogus, limit to %d entries\n",
- capacity, priv->cfg->max_event_log_size);
- capacity = priv->cfg->max_event_log_size;
+ capacity, logsize);
+ capacity = logsize;
}
- if (next_entry > priv->cfg->max_event_log_size) {
+ if (next_entry > logsize) {
IWL_ERR(priv, "Log write index %d is bogus, limit to %d\n",
- next_entry, priv->cfg->max_event_log_size);
- next_entry = priv->cfg->max_event_log_size;
+ next_entry, logsize);
+ next_entry = logsize;
}
size = num_wraps ? capacity : next_entry;
@@ -2361,8 +2609,6 @@ static void iwl_alive_start(struct iwl_priv *priv)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
-
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
}
/* Configure Bluetooth device coexistence support */
@@ -2777,20 +3023,16 @@ void iwl_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
iwlcore_commit_rxon(priv);
@@ -3016,8 +3258,7 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
priv->staging_rxon.assoc_id = 0;
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
@@ -3025,17 +3266,12 @@ void iwl_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &=
- ~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3081,17 +3317,9 @@ static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
return -EOPNOTSUPP;
}
- if (sta) {
- sta_id = iwl_sta_id(sta);
-
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
- sta->addr);
- return -EINVAL;
- }
- } else {
- sta_id = priv->hw_params.bcast_sta_id;
- }
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return -EINVAL;
mutex_lock(&priv->mutex);
iwl_scan_cancel_timeout(priv, 100);
@@ -3262,141 +3490,98 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
return 0;
}
-/*****************************************************************************
- *
- * sysfs attributes
- *
- *****************************************************************************/
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
- * used for controlling the debug level.
- *
- * See the level definitions in iwl for details.
- *
- * The debug_level being managed using sysfs below is a per device debug
- * level that is used instead of the global debug level if it (the per
- * device debug level) is set.
- */
-static ssize_t show_debug_level(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv));
-}
-static ssize_t store_debug_level(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 0, &val);
- if (ret)
- IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
- else {
- priv->debug_level = val;
- if (iwl_alloc_traffic_mem(priv))
- IWL_ERR(priv,
- "Not enough memory to generate traffic log\n");
- }
- return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
- show_debug_level, store_debug_level);
-
-
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-
-static ssize_t show_temperature(struct device *d,
- struct device_attribute *attr, char *buf)
+static void iwl_mac_channel_switch(struct ieee80211_hw *hw,
+ struct ieee80211_channel_switch *ch_switch)
{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_alive(priv))
- return -EAGAIN;
-
- return sprintf(buf, "%d\n", priv->temperature);
-}
-
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-
-static ssize_t show_tx_power(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
-
- if (!iwl_is_ready_rf(priv))
- return sprintf(buf, "off\n");
- else
- return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
-}
+ struct iwl_priv *priv = hw->priv;
+ const struct iwl_channel_info *ch_info;
+ struct ieee80211_conf *conf = &hw->conf;
+ struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+ u16 ch;
+ unsigned long flags = 0;
-static ssize_t store_tx_power(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
+ IWL_DEBUG_MAC80211(priv, "enter\n");
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "%s is not in decimal form.\n", buf);
- else {
- ret = iwl_set_tx_power(priv, val, false);
- if (ret)
- IWL_ERR(priv, "failed setting tx power (0x%d).\n",
- ret);
- else
- ret = count;
- }
- return ret;
-}
+ if (iwl_is_rfkill(priv))
+ goto out_exit;
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
+ test_bit(STATUS_SCANNING, &priv->status))
+ goto out_exit;
-static ssize_t show_rts_ht_protection(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
+ if (!iwl_is_associated(priv))
+ goto out_exit;
- return sprintf(buf, "%s\n",
- priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self");
-}
+ /* channel switch in progress */
+ if (priv->switch_rxon.switch_in_progress == true)
+ goto out_exit;
-static ssize_t store_rts_ht_protection(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct iwl_priv *priv = dev_get_drvdata(d);
- unsigned long val;
- int ret;
-
- ret = strict_strtoul(buf, 10, &val);
- if (ret)
- IWL_INFO(priv, "Input is not in decimal form.\n");
- else {
- if (!iwl_is_associated(priv))
- priv->cfg->use_rts_for_ht = val ? true : false;
- else
- IWL_ERR(priv, "Sta associated with AP - "
- "Change protection mechanism is not allowed\n");
- ret = count;
+ mutex_lock(&priv->mutex);
+ if (priv->cfg->ops->lib->set_channel_switch) {
+
+ ch = ieee80211_frequency_to_channel(
+ ch_switch->channel->center_freq);
+ if (le16_to_cpu(priv->active_rxon.channel) != ch) {
+ ch_info = iwl_get_channel_info(priv,
+ conf->channel->band,
+ ch);
+ if (!is_channel_valid(ch_info)) {
+ IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+ goto out;
+ }
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->current_ht_config.smps = conf->smps_mode;
+
+ /* Configure HT40 channels */
+ ht_conf->is_ht = conf_is_ht(conf);
+ if (ht_conf->is_ht) {
+ if (conf_is_ht40_minus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+ ht_conf->is_40mhz = true;
+ } else if (conf_is_ht40_plus(conf)) {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+ ht_conf->is_40mhz = true;
+ } else {
+ ht_conf->extension_chan_offset =
+ IEEE80211_HT_PARAM_CHA_SEC_NONE;
+ ht_conf->is_40mhz = false;
+ }
+ } else
+ ht_conf->is_40mhz = false;
+
+ /* if we are switching from ht to 2.4 clear flags
+ * from any ht related info since 2.4 does not
+ * support ht */
+ if ((le16_to_cpu(priv->staging_rxon.channel) != ch))
+ priv->staging_rxon.flags = 0;
+
+ iwl_set_rxon_channel(priv, conf->channel);
+ iwl_set_rxon_ht(priv, ht_conf);
+ iwl_set_flags_for_band(priv, conf->channel->band,
+ priv->vif);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ iwl_set_rate(priv);
+ /*
+ * at this point, staging_rxon has the
+ * configuration for channel switch
+ */
+ if (priv->cfg->ops->lib->set_channel_switch(priv,
+ ch_switch))
+ priv->switch_rxon.switch_in_progress = false;
+ }
}
- return ret;
+out:
+ mutex_unlock(&priv->mutex);
+out_exit:
+ if (!priv->switch_rxon.switch_in_progress)
+ ieee80211_chswitch_done(priv->vif, false);
+ IWL_DEBUG_MAC80211(priv, "leave\n");
}
-static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO,
- show_rts_ht_protection, store_rts_ht_protection);
-
-
/*****************************************************************************
*
* driver setup and teardown
@@ -3550,21 +3735,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
kfree(priv->scan_cmd);
}
-static struct attribute *iwl_sysfs_entries[] = {
- &dev_attr_temperature.attr,
- &dev_attr_tx_power.attr,
- &dev_attr_rts_ht_protection.attr,
-#ifdef CONFIG_IWLWIFI_DEBUG
- &dev_attr_debug_level.attr,
-#endif
- NULL
-};
-
-static struct attribute_group iwl_attribute_group = {
- .name = NULL, /* put in device directory */
- .attrs = iwl_sysfs_entries,
-};
-
static struct ieee80211_ops iwl_hw_ops = {
.tx = iwl_mac_tx,
.start = iwl_mac_start,
@@ -3583,6 +3753,7 @@ static struct ieee80211_ops iwl_hw_ops = {
.sta_notify = iwl_mac_sta_notify,
.sta_add = iwlagn_mac_sta_add,
.sta_remove = iwl_mac_sta_remove,
+ .channel_switch = iwl_mac_channel_switch,
};
static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -3593,6 +3764,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data);
unsigned long flags;
u16 pci_cmd;
+ u8 perm_addr[ETH_ALEN];
/************************
* 1. Allocating HW data
@@ -3622,9 +3794,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
-#ifdef CONFIG_IWLWIFI_DEBUG
- atomic_set(&priv->restrict_refcnt, 0);
-#endif
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
@@ -3713,9 +3882,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_free_eeprom;
/* extract MAC Address */
- iwl_eeprom_get_mac(priv, priv->mac_addr);
- IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ iwl_eeprom_get_mac(priv, perm_addr);
+ IWL_DEBUG_INFO(priv, "MAC address: %pM\n", perm_addr);
+ SET_IEEE80211_PERM_ADDR(priv->hw, perm_addr);
/************************
* 5. Setup HW constants
@@ -3750,11 +3919,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
goto out_disable_msi;
}
- err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
- if (err) {
- IWL_ERR(priv, "failed to create sysfs device attributes\n");
- goto out_free_irq;
- }
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
@@ -3788,15 +3952,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
err = iwl_request_firmware(priv, true);
if (err)
- goto out_remove_sysfs;
+ goto out_destroy_workqueue;
return 0;
- out_remove_sysfs:
+ out_destroy_workqueue:
destroy_workqueue(priv->workqueue);
priv->workqueue = NULL;
- sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
- out_free_irq:
free_irq(priv->pci_dev->irq, priv);
iwl_free_isr_ict(priv);
out_disable_msi:
@@ -3989,6 +4151,47 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
{IWL_PCI_DEVICE(0x0082, 0x1201, iwl6000g2a_2agn_cfg)},
{IWL_PCI_DEVICE(0x0085, 0x1211, iwl6000g2a_2agn_cfg)},
{IWL_PCI_DEVICE(0x0082, 0x1221, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1206, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1216, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1226, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1207, iwl6000g2a_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1301, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1306, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1307, iwl6000g2a_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1321, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0082, 0x1326, iwl6000g2a_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6000g2a_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6000g2a_2abg_cfg)},
+
+/* 6x00 Series Gen2b */
+ {IWL_PCI_DEVICE(0x008F, 0x5105, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5115, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5125, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5107, iwl6000g2b_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5201, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5221, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5206, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5226, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x008F, 0x5207, iwl6000g2b_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5301, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6000g2b_bg_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5321, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5311, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6000g2b_bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5201, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5205, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5206, iwl6000g2b_2abg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5207, iwl6000g2b_2bg_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5221, iwl6000g2b_2agn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5225, iwl6000g2b_2bgn_cfg)},
+ {IWL_PCI_DEVICE(0x0091, 0x5226, iwl6000g2b_2abg_cfg)},
/* 6x50 WiFi/WiMax Series */
{IWL_PCI_DEVICE(0x0087, 0x1301, iwl6050_2agn_cfg)},
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 2d748053358e..5c32777b0a49 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -65,6 +65,33 @@
#include "iwl-dev.h"
+/* configuration for the _agn devices */
+extern struct iwl_cfg iwl4965_agn_cfg;
+extern struct iwl_cfg iwl5300_agn_cfg;
+extern struct iwl_cfg iwl5100_agn_cfg;
+extern struct iwl_cfg iwl5350_agn_cfg;
+extern struct iwl_cfg iwl5100_bgn_cfg;
+extern struct iwl_cfg iwl5100_abg_cfg;
+extern struct iwl_cfg iwl5150_agn_cfg;
+extern struct iwl_cfg iwl5150_abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2agn_cfg;
+extern struct iwl_cfg iwl6000g2a_2abg_cfg;
+extern struct iwl_cfg iwl6000g2a_2bg_cfg;
+extern struct iwl_cfg iwl6000g2b_bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_bg_cfg;
+extern struct iwl_cfg iwl6000g2b_2agn_cfg;
+extern struct iwl_cfg iwl6000g2b_2abg_cfg;
+extern struct iwl_cfg iwl6000g2b_2bgn_cfg;
+extern struct iwl_cfg iwl6000g2b_2bg_cfg;
+extern struct iwl_cfg iwl6000i_2agn_cfg;
+extern struct iwl_cfg iwl6000i_2abg_cfg;
+extern struct iwl_cfg iwl6000i_2bg_cfg;
+extern struct iwl_cfg iwl6000_3agn_cfg;
+extern struct iwl_cfg iwl6050_2agn_cfg;
+extern struct iwl_cfg iwl6050_2abg_cfg;
+extern struct iwl_cfg iwl1000_bgn_cfg;
+extern struct iwl_cfg iwl1000_bg_cfg;
+
extern struct iwl_mod_params iwlagn_mod_params;
extern struct iwl_hcmd_ops iwlagn_hcmd;
extern struct iwl_hcmd_utils_ops iwlagn_hcmd_utils;
@@ -93,6 +120,8 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
u16 ssn_idx, u8 tx_fifo);
void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
+void iwl_free_tfds_in_queue(struct iwl_priv *priv,
+ int sta_id, int tid, int freed);
/* uCode */
int iwlagn_load_ucode(struct iwl_priv *priv);
@@ -102,6 +131,7 @@ void iwlagn_rx_calib_complete(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwlagn_init_alive_start(struct iwl_priv *priv);
int iwlagn_alive_notify(struct iwl_priv *priv);
+int iwl_verify_ucode(struct iwl_priv *priv);
/* lib */
void iwl_check_abort_status(struct iwl_priv *priv,
@@ -178,4 +208,8 @@ void iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
int iwlagn_manage_ibss_station(struct iwl_priv *priv,
struct ieee80211_vif *vif, bool add);
+/* hcmd */
+int iwlagn_send_rxon_assoc(struct iwl_priv *priv);
+int iwlagn_send_tx_ant_config(struct iwl_priv *priv, u8 valid_tx_ant);
+
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h
index 9aab020c474b..c579965ec556 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -95,7 +95,7 @@ enum {
/* Multi-Station support */
REPLY_ADD_STA = 0x18,
- REPLY_REMOVE_STA = 0x19, /* not used */
+ REPLY_REMOVE_STA = 0x19,
REPLY_REMOVE_ALL_STA = 0x1a, /* not used */
/* Security */
@@ -227,7 +227,7 @@ struct iwl_cmd_header {
/* command or response/notification data follows immediately */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/**
@@ -247,7 +247,7 @@ struct iwl_cmd_header {
struct iwl3945_tx_power {
u8 tx_gain; /* gain for analog radio */
u8 dsp_atten; /* gain for DSP */
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl3945_power_per_rate
@@ -258,7 +258,7 @@ struct iwl3945_power_per_rate {
u8 rate; /* plcp */
struct iwl3945_tx_power tpc;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* iwlagn rate_n_flags bit fields
@@ -389,7 +389,7 @@ union iwl4965_tx_power_dual_stream {
*/
struct tx_power_dual_stream {
__le32 dw;
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl4965_tx_power_db
@@ -398,7 +398,7 @@ struct tx_power_dual_stream {
*/
struct iwl4965_tx_power_db {
struct tx_power_dual_stream power_tbl[POWER_TABLE_NUM_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/**
* Command REPLY_TX_POWER_DBM_CMD = 0x98
@@ -412,7 +412,7 @@ struct iwl5000_tx_power_dbm_cmd {
u8 flags;
s8 srv_chan_lmt; /*in half-dBm (e.g. 30 = 15 dBm) */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/**
* Command TX_ANT_CONFIGURATION_CMD = 0x98
@@ -422,7 +422,7 @@ struct iwl5000_tx_power_dbm_cmd {
*/
struct iwl_tx_ant_config_cmd {
__le32 valid;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (0a)
@@ -478,7 +478,7 @@ struct iwl_init_alive_resp {
__le32 therm_r4[2]; /* signed */
__le32 tx_atten[5][2]; /* signed MIMO gain comp, 5 freq groups,
* 2 Tx chains */
-} __attribute__ ((packed));
+} __packed;
/**
@@ -570,7 +570,7 @@ struct iwl_alive_resp {
__le32 error_event_table_ptr; /* SRAM address for error log */
__le32 timestamp;
__le32 is_valid;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_ERROR = 0x2 (response only, not a command)
@@ -582,7 +582,7 @@ struct iwl_error_resp {
__le16 bad_cmd_seq_num;
__le32 error_info;
__le64 timestamp;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (1)
@@ -718,7 +718,7 @@ struct iwl3945_rxon_cmd {
__le32 filter_flags;
__le16 channel;
__le16 reserved5;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_rxon_cmd {
u8 node_addr[6];
@@ -738,7 +738,7 @@ struct iwl4965_rxon_cmd {
__le16 channel;
u8 ofdm_ht_single_stream_basic_rates;
u8 ofdm_ht_dual_stream_basic_rates;
-} __attribute__ ((packed));
+} __packed;
/* 5000 HW just extend this command */
struct iwl_rxon_cmd {
@@ -763,7 +763,7 @@ struct iwl_rxon_cmd {
u8 reserved5;
__le16 acquisition_data;
__le16 reserved6;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_RXON_ASSOC = 0x11 (command, has simple generic response)
@@ -774,7 +774,7 @@ struct iwl3945_rxon_assoc_cmd {
u8 ofdm_basic_rates;
u8 cck_basic_rates;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_rxon_assoc_cmd {
__le32 flags;
@@ -785,7 +785,7 @@ struct iwl4965_rxon_assoc_cmd {
u8 ofdm_ht_dual_stream_basic_rates;
__le16 rx_chain_select_flags;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl5000_rxon_assoc_cmd {
__le32 flags;
@@ -800,7 +800,7 @@ struct iwl5000_rxon_assoc_cmd {
__le16 rx_chain_select_flags;
__le16 acquisition_data;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
#define IWL_CONN_MAX_LISTEN_INTERVAL 10
#define IWL_MAX_UCODE_BEACON_INTERVAL 4 /* 4096 */
@@ -816,7 +816,7 @@ struct iwl_rxon_time_cmd {
__le32 beacon_init_val;
__le16 listen_interval;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
@@ -829,7 +829,7 @@ struct iwl3945_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_channel_switch_cmd {
u8 band;
@@ -839,7 +839,7 @@ struct iwl4965_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl5000_channel_switch_cmd
@@ -860,7 +860,7 @@ struct iwl5000_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[2][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/**
* struct iwl6000_channel_switch_cmd
@@ -881,7 +881,7 @@ struct iwl6000_channel_switch_cmd {
__le32 rxon_filter_flags;
__le32 switch_time;
__le32 reserved[3][IWL_PWR_NUM_HT_OFDM_ENTRIES + IWL_PWR_CCK_ENTRIES];
-} __attribute__ ((packed));
+} __packed;
/*
* CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command)
@@ -890,7 +890,7 @@ struct iwl_csa_notification {
__le16 band;
__le16 channel;
__le32 status; /* 0 - OK, 1 - fail */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (2)
@@ -920,7 +920,7 @@ struct iwl_ac_qos {
u8 aifsn;
u8 reserved1;
__le16 edca_txop;
-} __attribute__ ((packed));
+} __packed;
/* QoS flags defines */
#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01)
@@ -939,7 +939,7 @@ struct iwl_ac_qos {
struct iwl_qosparam_cmd {
__le32 qos_flags;
struct iwl_ac_qos ac[AC_NUM];
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (3)
@@ -952,7 +952,6 @@ struct iwl_qosparam_cmd {
/* Special, dedicated locations within device's station table */
#define IWL_AP_ID 0
-#define IWL_MULTICAST_ID 1
#define IWL_STA_ID 2
#define IWL3945_BROADCAST_ID 24
#define IWL3945_STATION_COUNT 25
@@ -1015,7 +1014,7 @@ struct iwl4965_keyinfo {
u8 key_offset;
u8 reserved2;
u8 key[16]; /* 16-byte unicast decryption key */
-} __attribute__ ((packed));
+} __packed;
/* 5000 */
struct iwl_keyinfo {
@@ -1029,7 +1028,7 @@ struct iwl_keyinfo {
__le64 tx_secur_seq_cnt;
__le64 hw_tkip_mic_rx_key;
__le64 hw_tkip_mic_tx_key;
-} __attribute__ ((packed));
+} __packed;
/**
* struct sta_id_modify
@@ -1049,7 +1048,7 @@ struct sta_id_modify {
u8 sta_id;
u8 modify_mask;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_ADD_STA = 0x18 (command)
@@ -1103,7 +1102,7 @@ struct iwl3945_addsta_cmd {
/* Starting Sequence Number for added block-ack support.
* Set modify_mask bit STA_MODIFY_ADDBA_TID_MSK to use this field. */
__le16 add_immediate_ba_ssn;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_addsta_cmd {
u8 mode; /* 1: modify existing, 0: add new station */
@@ -1140,7 +1139,7 @@ struct iwl4965_addsta_cmd {
__le16 sleep_tx_count;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
/* 5000 */
struct iwl_addsta_cmd {
@@ -1178,7 +1177,7 @@ struct iwl_addsta_cmd {
__le16 sleep_tx_count;
__le16 reserved2;
-} __attribute__ ((packed));
+} __packed;
#define ADD_STA_SUCCESS_MSK 0x1
@@ -1190,7 +1189,7 @@ struct iwl_addsta_cmd {
*/
struct iwl_add_sta_resp {
u8 status; /* ADD_STA_* */
-} __attribute__ ((packed));
+} __packed;
#define REM_STA_SUCCESS_MSK 0x1
/*
@@ -1198,7 +1197,7 @@ struct iwl_add_sta_resp {
*/
struct iwl_rem_sta_resp {
u8 status;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_REM_STA = 0x19 (command)
@@ -1208,7 +1207,7 @@ struct iwl_rem_sta_cmd {
u8 reserved[3];
u8 addr[ETH_ALEN]; /* MAC addr of the first station */
u8 reserved2[2];
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_WEP_KEY = 0x20
@@ -1220,7 +1219,7 @@ struct iwl_wep_key {
u8 key_size;
u8 reserved2[3];
u8 key[16];
-} __attribute__ ((packed));
+} __packed;
struct iwl_wep_cmd {
u8 num_keys;
@@ -1228,7 +1227,7 @@ struct iwl_wep_cmd {
u8 flags;
u8 reserved;
struct iwl_wep_key key[0];
-} __attribute__ ((packed));
+} __packed;
#define WEP_KEY_WEP_TYPE 1
#define WEP_KEYS_MAX 4
@@ -1282,7 +1281,7 @@ struct iwl3945_rx_frame_stats {
__le16 sig_avg;
__le16 noise_diff;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rx_frame_hdr {
__le16 channel;
@@ -1291,13 +1290,13 @@ struct iwl3945_rx_frame_hdr {
u8 rate;
__le16 len;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rx_frame_end {
__le32 status;
__le64 timestamp;
__le32 beacon_timestamp;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_3945_RX = 0x1b (response only, not a command)
@@ -1311,7 +1310,7 @@ struct iwl3945_rx_frame {
struct iwl3945_rx_frame_stats stats;
struct iwl3945_rx_frame_hdr hdr;
struct iwl3945_rx_frame_end end;
-} __attribute__ ((packed));
+} __packed;
#define IWL39_RX_FRAME_SIZE (4 + sizeof(struct iwl3945_rx_frame))
@@ -1327,7 +1326,7 @@ struct iwl4965_rx_non_cfg_phy {
__le16 agc_info; /* agc code 0:6, agc dB 7:13, reserved 14:15 */
u8 rssi_info[6]; /* we use even entries, 0/2/4 for A/B/C rssi */
u8 pad[0];
-} __attribute__ ((packed));
+} __packed;
#define IWL50_RX_RES_PHY_CNT 8
@@ -1345,7 +1344,7 @@ struct iwl4965_rx_non_cfg_phy {
struct iwl5000_non_cfg_phy {
__le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -1365,12 +1364,12 @@ struct iwl_rx_phy_res {
__le32 rate_n_flags; /* RATE_MCS_* */
__le16 byte_count; /* frame's byte-count */
__le16 reserved3;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_rx_mpdu_res_start {
__le16 byte_count;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -1557,7 +1556,7 @@ struct iwl3945_tx_cmd {
*/
u8 payload[0];
struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX = 0x1c (response)
@@ -1569,7 +1568,7 @@ struct iwl3945_tx_resp {
u8 rate;
__le32 wireless_media_time;
__le32 status; /* TX status */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -1581,7 +1580,7 @@ struct iwl_dram_scratch {
u8 try_cnt; /* Tx attempts */
u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_tx_cmd {
/*
@@ -1660,7 +1659,7 @@ struct iwl_tx_cmd {
*/
u8 payload[0];
struct ieee80211_hdr hdr[0];
-} __attribute__ ((packed));
+} __packed;
/* TX command response is sent after *3945* transmission attempts.
*
@@ -1826,7 +1825,7 @@ enum {
struct agg_tx_status {
__le16 status;
__le16 sequence;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_tx_resp {
u8 frame_count; /* 1 no aggregation, >1 aggregation */
@@ -1863,7 +1862,7 @@ struct iwl4965_tx_resp {
__le32 status;
struct agg_tx_status agg_status[0]; /* for each agg frame */
} u;
-} __attribute__ ((packed));
+} __packed;
/*
* definitions for initial rate index field
@@ -1927,7 +1926,7 @@ struct iwl5000_tx_resp {
*/
struct agg_tx_status status; /* TX status (in aggregation -
* status of 1st frame) */
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_COMPRESSED_BA = 0xc5 (response only, not a command)
*
@@ -1945,7 +1944,7 @@ struct iwl_compressed_ba_resp {
__le64 bitmap;
__le16 scd_flow;
__le16 scd_ssn;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_PWR_TABLE_CMD = 0x97 (command, has simple generic response)
@@ -1958,14 +1957,14 @@ struct iwl3945_txpowertable_cmd {
u8 reserved;
__le16 channel;
struct iwl3945_power_per_rate power[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_txpowertable_cmd {
u8 band; /* 0: 5 GHz, 1: 2.4 GHz */
u8 reserved;
__le16 channel;
struct iwl4965_tx_power_db tx_power;
-} __attribute__ ((packed));
+} __packed;
/**
@@ -1987,13 +1986,13 @@ struct iwl3945_rate_scaling_info {
__le16 rate_n_flags;
u8 try_cnt;
u8 next_rate_index;
-} __attribute__ ((packed));
+} __packed;
struct iwl3945_rate_scaling_cmd {
u8 table_id;
u8 reserved[3];
struct iwl3945_rate_scaling_info table[IWL_MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
/*RS_NEW_API: only TLC_RTS remains and moved to bit 0 */
@@ -2040,7 +2039,7 @@ struct iwl_link_qual_general_params {
* TX FIFOs above 3 use same value (typically 0) as TX FIFO 3.
*/
u8 start_rate_index[LINK_QUAL_AC_NUM];
-} __attribute__ ((packed));
+} __packed;
#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
#define LINK_QUAL_AGG_TIME_LIMIT_MAX (65535)
@@ -2081,7 +2080,7 @@ struct iwl_link_qual_agg_params {
u8 agg_frame_cnt_limit;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_LINK_QUALITY_CMD = 0x4e (command, has simple generic response)
@@ -2287,7 +2286,7 @@ struct iwl_link_quality_cmd {
__le32 rate_n_flags; /* RATE_MCS_*, IWL_RATE_* */
} rs_table[LINK_QUAL_MAX_RETRY_NUM];
__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
/*
* BT configuration enable flags:
@@ -2328,7 +2327,7 @@ struct iwl_bt_cmd {
u8 reserved;
__le32 kill_ack_mask;
__le32 kill_cts_mask;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (6)
@@ -2353,7 +2352,7 @@ struct iwl_measure_channel {
u8 channel; /* channel to measure */
u8 type; /* see enum iwl_measure_type */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command)
@@ -2372,7 +2371,7 @@ struct iwl_spectrum_cmd {
__le16 channel_count; /* minimum 1, maximum 10 */
__le16 reserved3;
struct iwl_measure_channel channels[10];
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response)
@@ -2383,7 +2382,7 @@ struct iwl_spectrum_resp {
__le16 status; /* 0 - command will be handled
* 1 - cannot handle (conflicts with another
* measurement) */
-} __attribute__ ((packed));
+} __packed;
enum iwl_measurement_state {
IWL_MEASUREMENT_START = 0,
@@ -2406,13 +2405,13 @@ enum iwl_measurement_status {
struct iwl_measurement_histogram {
__le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */
__le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */
-} __attribute__ ((packed));
+} __packed;
/* clear channel availability counters */
struct iwl_measurement_cca_counters {
__le32 ofdm;
__le32 cck;
-} __attribute__ ((packed));
+} __packed;
enum iwl_measure_type {
IWL_MEASURE_BASIC = (1 << 0),
@@ -2448,7 +2447,7 @@ struct iwl_spectrum_notification {
struct iwl_measurement_histogram histogram;
__le32 stop_time; /* lower 32-bits of TSF */
__le32 status; /* see iwl_measurement_status */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (7)
@@ -2504,7 +2503,7 @@ struct iwl3945_powertable_cmd {
__le32 rx_data_timeout;
__le32 tx_data_timeout;
__le32 sleep_interval[IWL_POWER_VEC_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct iwl_powertable_cmd {
__le16 flags;
@@ -2514,7 +2513,7 @@ struct iwl_powertable_cmd {
__le32 tx_data_timeout;
__le32 sleep_interval[IWL_POWER_VEC_SIZE];
__le32 keep_alive_beacons;
-} __attribute__ ((packed));
+} __packed;
/*
* PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command)
@@ -2527,7 +2526,7 @@ struct iwl_sleep_notification {
__le32 sleep_time;
__le32 tsf_low;
__le32 bcon_timer;
-} __attribute__ ((packed));
+} __packed;
/* Sleep states. 3945 and 4965 identical. */
enum {
@@ -2552,14 +2551,14 @@ enum {
#define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */
struct iwl_card_state_cmd {
__le32 status; /* CARD_STATE_CMD_* request new power state */
-} __attribute__ ((packed));
+} __packed;
/*
* CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command)
*/
struct iwl_card_state_notif {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
#define HW_CARD_DISABLED 0x01
#define SW_CARD_DISABLED 0x02
@@ -2570,14 +2569,14 @@ struct iwl_ct_kill_config {
__le32 reserved;
__le32 critical_temperature_M;
__le32 critical_temperature_R;
-} __attribute__ ((packed));
+} __packed;
/* 1000, and 6x00 */
struct iwl_ct_kill_throttling_config {
__le32 critical_temperature_exit;
__le32 reserved;
__le32 critical_temperature_enter;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (8)
@@ -2622,7 +2621,7 @@ struct iwl3945_scan_channel {
struct iwl3945_tx_power tpc;
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
__le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
/* set number of direct probes u8 type */
#define IWL39_SCAN_PROBE_MASK(n) ((BIT(n) | (BIT(n) - BIT(1))))
@@ -2641,7 +2640,7 @@ struct iwl_scan_channel {
u8 dsp_atten; /* gain for DSP */
__le16 active_dwell; /* in 1024-uSec TU (time units), typ 5-50 */
__le16 passive_dwell; /* in 1024-uSec TU (time units), typ 20-500 */
-} __attribute__ ((packed));
+} __packed;
/* set number of direct probes __le32 type */
#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1))))
@@ -2658,7 +2657,7 @@ struct iwl_ssid_ie {
u8 id;
u8 len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
#define PROBE_OPTION_MAX_3945 4
#define PROBE_OPTION_MAX 20
@@ -2764,7 +2763,7 @@ struct iwl3945_scan_cmd {
* before requesting another scan.
*/
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct iwl_scan_cmd {
__le16 len;
@@ -2808,7 +2807,7 @@ struct iwl_scan_cmd {
* before requesting another scan.
*/
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* Can abort will notify by complete notification with abort status. */
#define CAN_ABORT_STATUS cpu_to_le32(0x1)
@@ -2820,7 +2819,7 @@ struct iwl_scan_cmd {
*/
struct iwl_scanreq_notification {
__le32 status; /* 1: okay, 2: cannot fulfill request */
-} __attribute__ ((packed));
+} __packed;
/*
* SCAN_START_NOTIFICATION = 0x82 (notification only, not a command)
@@ -2833,7 +2832,7 @@ struct iwl_scanstart_notification {
u8 band;
u8 reserved[2];
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#define SCAN_OWNER_STATUS 0x1;
#define MEASURE_OWNER_STATUS 0x2;
@@ -2849,7 +2848,7 @@ struct iwl_scanresults_notification {
__le32 tsf_low;
__le32 tsf_high;
__le32 statistics[NUMBER_OF_STATISTICS];
-} __attribute__ ((packed));
+} __packed;
/*
* SCAN_COMPLETE_NOTIFICATION = 0x84 (notification only, not a command)
@@ -2861,7 +2860,7 @@ struct iwl_scancomplete_notification {
u8 last_channel;
__le32 tsf_low;
__le32 tsf_high;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -2879,14 +2878,14 @@ struct iwl3945_beacon_notif {
__le32 low_tsf;
__le32 high_tsf;
__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
struct iwl4965_beacon_notif {
struct iwl4965_tx_resp beacon_notify_hdr;
__le32 low_tsf;
__le32 high_tsf;
__le32 ibss_mgr_status;
-} __attribute__ ((packed));
+} __packed;
/*
* REPLY_TX_BEACON = 0x91 (command, has simple generic response)
@@ -2898,7 +2897,7 @@ struct iwl3945_tx_beacon_cmd {
u8 tim_size;
u8 reserved1;
struct ieee80211_hdr frame[0]; /* beacon frame */
-} __attribute__ ((packed));
+} __packed;
struct iwl_tx_beacon_cmd {
struct iwl_tx_cmd tx;
@@ -2906,7 +2905,7 @@ struct iwl_tx_beacon_cmd {
u8 tim_size;
u8 reserved1;
struct ieee80211_hdr frame[0]; /* beacon frame */
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (10)
@@ -2932,7 +2931,7 @@ struct rate_histogram {
__le32 b[SUP_RATE_11B_MAX_NUM_CHANNELS];
__le32 g[SUP_RATE_11G_MAX_NUM_CHANNELS];
} failed;
-} __attribute__ ((packed));
+} __packed;
/* statistics command response */
@@ -2952,7 +2951,7 @@ struct iwl39_statistics_rx_phy {
__le32 rxe_frame_limit_overrun;
__le32 sent_ack_cnt;
__le32 sent_cts_cnt;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_rx_non_phy {
__le32 bogus_cts; /* CTS received when not expecting CTS */
@@ -2963,13 +2962,13 @@ struct iwl39_statistics_rx_non_phy {
* filtering process */
__le32 non_channel_beacons; /* beacons with our bss id but not on
* our serving channel */
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_rx {
struct iwl39_statistics_rx_phy ofdm;
struct iwl39_statistics_rx_phy cck;
struct iwl39_statistics_rx_non_phy general;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_tx {
__le32 preamble_cnt;
@@ -2981,20 +2980,20 @@ struct iwl39_statistics_tx {
__le32 ack_timeout;
__le32 expected_ack_cnt;
__le32 actual_ack_cnt;
-} __attribute__ ((packed));
+} __packed;
struct statistics_dbg {
__le32 burst_check;
__le32 burst_count;
__le32 reserved[4];
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_div {
__le32 tx_on_a;
__le32 tx_on_b;
__le32 exec_time;
__le32 probe_time;
-} __attribute__ ((packed));
+} __packed;
struct iwl39_statistics_general {
__le32 temperature;
@@ -3004,7 +3003,7 @@ struct iwl39_statistics_general {
__le32 slots_idle;
__le32 ttl_timestamp;
struct iwl39_statistics_div div;
-} __attribute__ ((packed));
+} __packed;
struct statistics_rx_phy {
__le32 ina_cnt;
@@ -3027,7 +3026,7 @@ struct statistics_rx_phy {
__le32 mh_format_err;
__le32 re_acq_main_rssi_sum;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
struct statistics_rx_ht_phy {
__le32 plcp_err;
@@ -3040,7 +3039,7 @@ struct statistics_rx_ht_phy {
__le32 agg_mpdu_cnt;
__le32 agg_cnt;
__le32 unsupport_mcs;
-} __attribute__ ((packed));
+} __packed;
#define INTERFERENCE_DATA_AVAILABLE cpu_to_le32(1)
@@ -3075,14 +3074,14 @@ struct statistics_rx_non_phy {
__le32 beacon_energy_a;
__le32 beacon_energy_b;
__le32 beacon_energy_c;
-} __attribute__ ((packed));
+} __packed;
struct statistics_rx {
struct statistics_rx_phy ofdm;
struct statistics_rx_phy cck;
struct statistics_rx_non_phy general;
struct statistics_rx_ht_phy ofdm_ht;
-} __attribute__ ((packed));
+} __packed;
/**
* struct statistics_tx_power - current tx power
@@ -3096,7 +3095,7 @@ struct statistics_tx_power {
u8 ant_b;
u8 ant_c;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct statistics_tx_non_phy_agg {
__le32 ba_timeout;
@@ -3109,7 +3108,7 @@ struct statistics_tx_non_phy_agg {
__le32 underrun;
__le32 bt_prio_kill;
__le32 rx_ba_rsp_cnt;
-} __attribute__ ((packed));
+} __packed;
struct statistics_tx {
__le32 preamble_cnt;
@@ -3134,7 +3133,7 @@ struct statistics_tx {
*/
struct statistics_tx_power tx_power;
__le32 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct statistics_div {
@@ -3144,7 +3143,7 @@ struct statistics_div {
__le32 probe_time;
__le32 reserved1;
__le32 reserved2;
-} __attribute__ ((packed));
+} __packed;
struct statistics_general {
__le32 temperature; /* radio temperature */
@@ -3164,7 +3163,7 @@ struct statistics_general {
__le32 num_of_sos_states;
__le32 reserved2;
__le32 reserved3;
-} __attribute__ ((packed));
+} __packed;
#define UCODE_STATISTICS_CLEAR_MSK (0x1 << 0)
#define UCODE_STATISTICS_FREQUENCY_MSK (0x1 << 1)
@@ -3189,7 +3188,7 @@ struct statistics_general {
#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */
struct iwl_statistics_cmd {
__le32 configuration_flags; /* IWL_STATS_CONF_* */
-} __attribute__ ((packed));
+} __packed;
/*
* STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
@@ -3214,14 +3213,14 @@ struct iwl3945_notif_statistics {
struct iwl39_statistics_rx rx;
struct iwl39_statistics_tx tx;
struct iwl39_statistics_general general;
-} __attribute__ ((packed));
+} __packed;
struct iwl_notif_statistics {
__le32 flag;
struct statistics_rx rx;
struct statistics_tx tx;
struct statistics_general general;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -3253,7 +3252,7 @@ struct iwl_missed_beacon_notif {
__le32 total_missed_becons;
__le32 num_expected_beacons;
__le32 num_recvd_beacons;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -3455,7 +3454,7 @@ struct iwl_missed_beacon_notif {
struct iwl_sensitivity_cmd {
__le16 control; /* always use "1" */
__le16 table[HD_TABLE_SIZE]; /* use HD_* as index */
-} __attribute__ ((packed));
+} __packed;
/**
@@ -3536,31 +3535,31 @@ struct iwl_calib_cfg_elmnt_s {
__le32 send_res;
__le32 apply_res;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cfg_status_s {
struct iwl_calib_cfg_elmnt_s once;
struct iwl_calib_cfg_elmnt_s perd;
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cfg_cmd {
struct iwl_calib_cfg_status_s ucd_calib_cfg;
struct iwl_calib_cfg_status_s drv_calib_cfg;
__le32 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_hdr {
u8 op_code;
u8 first_group;
u8 groups_num;
u8 data_valid;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_cmd {
struct iwl_calib_hdr hdr;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */
struct iwl_calib_diff_gain_cmd {
@@ -3569,14 +3568,14 @@ struct iwl_calib_diff_gain_cmd {
s8 diff_gain_b;
s8 diff_gain_c;
u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
struct iwl_calib_xtal_freq_cmd {
struct iwl_calib_hdr hdr;
u8 cap_pin1;
u8 cap_pin2;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
struct iwl_calib_chain_noise_reset_cmd {
@@ -3590,7 +3589,7 @@ struct iwl_calib_chain_noise_gain_cmd {
u8 delta_gain_1;
u8 delta_gain_2;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
* (12)
@@ -3613,7 +3612,7 @@ struct iwl_led_cmd {
u8 on; /* # intervals on while blinking;
* "0", regardless of "off", turns LED off */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* station priority table entries
@@ -3749,7 +3748,7 @@ struct iwl_wimax_coex_event_entry {
u8 win_medium_prio;
u8 reserved;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
/* COEX flag masks */
@@ -3766,7 +3765,7 @@ struct iwl_wimax_coex_cmd {
u8 flags;
u8 reserved[3];
struct iwl_wimax_coex_event_entry sta_prio[COEX_NUM_OF_EVENTS];
-} __attribute__ ((packed));
+} __packed;
/*
* Coexistence MEDIUM NOTIFICATION
@@ -3795,7 +3794,7 @@ struct iwl_wimax_coex_cmd {
struct iwl_coex_medium_notification {
__le32 status;
__le32 events;
-} __attribute__ ((packed));
+} __packed;
/*
* Coexistence EVENT Command
@@ -3810,11 +3809,11 @@ struct iwl_coex_event_cmd {
u8 flags;
u8 event;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwl_coex_event_resp {
__le32 status;
-} __attribute__ ((packed));
+} __packed;
/******************************************************************************
@@ -3858,7 +3857,7 @@ struct iwl_rx_packet {
__le32 status;
u8 raw[0];
} u;
-} __attribute__ ((packed));
+} __packed;
int iwl_agn_check_rxon_cmd(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 5a7eca8fb789..62c50bc0089a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -141,13 +141,14 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags)
}
EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx);
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant)
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant, u8 valid)
{
int i;
u8 ind = ant;
+
for (i = 0; i < RATE_ANT_NUM - 1; i++) {
ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0;
- if (priv->hw_params.valid_tx_ant & BIT(ind))
+ if (valid & BIT(ind))
return ind;
}
return ant;
@@ -457,7 +458,7 @@ u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
if (!sta_ht_inf->ht_supported)
return 0;
}
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
if (priv->disable_ht40)
return 0;
#endif
@@ -506,11 +507,11 @@ void iwl_setup_rxon_timing(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
beacon_int = iwl_adjust_beacon_interval(beacon_int,
- priv->hw_params.max_beacon_itrvl * 1024);
+ priv->hw_params.max_beacon_itrvl * TIME_UNIT);
priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int);
tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */
- interval_tm = beacon_int * 1024;
+ interval_tm = beacon_int * TIME_UNIT;
rem = do_div(tsf, interval_tm);
priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem);
@@ -854,6 +855,45 @@ void iwl_set_rxon_chain(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_set_rxon_chain);
+/* Return valid channel */
+u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+ enum ieee80211_band band)
+{
+ const struct iwl_channel_info *ch_info;
+ int i;
+ u8 channel = 0;
+
+ /* only scan single channel, good enough to reset the RF */
+ /* pick the first valid not in-use channel */
+ if (band == IEEE80211_BAND_5GHZ) {
+ for (i = 14; i < priv->channel_count; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel = priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < 14; i++) {
+ if (priv->channel_info[i].channel !=
+ le16_to_cpu(priv->staging_rxon.channel)) {
+ channel =
+ priv->channel_info[i].channel;
+ ch_info = iwl_get_channel_info(priv,
+ band, channel);
+ if (is_channel_valid(ch_info))
+ break;
+ }
+ }
+ }
+
+ return channel;
+}
+EXPORT_SYMBOL(iwl_get_single_channel_number);
+
/**
* iwl_set_rxon_channel - Set the phymode and channel values in staging RXON
* @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz
@@ -893,9 +933,9 @@ int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch)
}
EXPORT_SYMBOL(iwl_set_rxon_channel);
-static void iwl_set_flags_for_band(struct iwl_priv *priv,
- enum ieee80211_band band,
- struct ieee80211_vif *vif)
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ struct ieee80211_vif *vif)
{
if (band == IEEE80211_BAND_5GHZ) {
priv->staging_rxon.flags &=
@@ -904,19 +944,17 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv,
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
} else {
/* Copied from iwl_post_associate() */
- if (vif && vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif && vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
- if (vif && vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;
priv->staging_rxon.flags |= RXON_FLG_AUTO_DETECT_MSK;
priv->staging_rxon.flags &= ~RXON_FLG_CCK_MSK;
}
}
+EXPORT_SYMBOL(iwl_set_flags_for_band);
/*
* initialize rxon structure with default values from eeprom
@@ -982,15 +1020,17 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
/* clear both MIX and PURE40 mode flag */
priv->staging_rxon.flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED |
RXON_FLG_CHANNEL_MODE_PURE_40);
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
- memcpy(priv->staging_rxon.wlap_bssid_addr, priv->mac_addr, ETH_ALEN);
+
+ if (vif)
+ memcpy(priv->staging_rxon.node_addr, vif->addr, ETH_ALEN);
+
priv->staging_rxon.ofdm_ht_single_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_dual_stream_basic_rates = 0xff;
priv->staging_rxon.ofdm_ht_triple_stream_basic_rates = 0xff;
}
EXPORT_SYMBOL(iwl_connection_init_rx_config);
-static void iwl_set_rate(struct iwl_priv *priv)
+void iwl_set_rate(struct iwl_priv *priv)
{
const struct ieee80211_supported_band *hw = NULL;
struct ieee80211_rate *rate;
@@ -1018,6 +1058,21 @@ static void iwl_set_rate(struct iwl_priv *priv)
priv->staging_rxon.ofdm_basic_rates =
(IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF;
}
+EXPORT_SYMBOL(iwl_set_rate);
+
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
+{
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ return;
+
+ if (priv->switch_rxon.switch_in_progress) {
+ ieee80211_chswitch_done(priv->vif, is_success);
+ mutex_lock(&priv->mutex);
+ priv->switch_rxon.switch_in_progress = false;
+ mutex_unlock(&priv->mutex);
+ }
+}
+EXPORT_SYMBOL(iwl_chswitch_done);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
{
@@ -1032,11 +1087,12 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
priv->staging_rxon.channel = csa->channel;
IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
le16_to_cpu(csa->channel));
- } else
+ iwl_chswitch_done(priv, true);
+ } else {
IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
le16_to_cpu(csa->channel));
-
- priv->switch_rxon.switch_in_progress = false;
+ iwl_chswitch_done(priv, false);
+ }
}
}
EXPORT_SYMBOL(iwl_rx_csa);
@@ -1463,130 +1519,6 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
}
EXPORT_SYMBOL(iwl_send_statistics_request);
-/**
- * iwl_verify_inst_sparse - verify runtime uCode image in card vs. host,
- * using sample data 100 bytes apart. If these sample points are good,
- * it's a pretty good bet that everything between them is good, too.
- */
-static int iwlcore_verify_inst_sparse(struct iwl_priv *priv, __le32 *image, u32 len)
-{
- u32 val;
- int ret = 0;
- u32 errcnt = 0;
- u32 i;
-
- IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
- for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- i + IWL49_RTC_INST_LOWER_BOUND);
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- ret = -EIO;
- errcnt++;
- if (errcnt >= 3)
- break;
- }
- }
-
- return ret;
-}
-
-/**
- * iwlcore_verify_inst_full - verify runtime uCode image in card vs. host,
- * looking at all data.
- */
-static int iwl_verify_inst_full(struct iwl_priv *priv, __le32 *image,
- u32 len)
-{
- u32 val;
- u32 save_len = len;
- int ret = 0;
- u32 errcnt;
-
- IWL_DEBUG_INFO(priv, "ucode inst image size is %u\n", len);
-
- iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR,
- IWL49_RTC_INST_LOWER_BOUND);
-
- errcnt = 0;
- for (; len > 0; len -= sizeof(u32), image++) {
- /* read data comes through single port, auto-incr addr */
- /* NOTE: Use the debugless read so we don't flood kernel log
- * if IWL_DL_IO is set */
- val = _iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT);
- if (val != le32_to_cpu(*image)) {
- IWL_ERR(priv, "uCode INST section is invalid at "
- "offset 0x%x, is 0x%x, s/b 0x%x\n",
- save_len - len, val, le32_to_cpu(*image));
- ret = -EIO;
- errcnt++;
- if (errcnt >= 20)
- break;
- }
- }
-
- if (!errcnt)
- IWL_DEBUG_INFO(priv,
- "ucode image in INSTRUCTION memory is good\n");
-
- return ret;
-}
-
-/**
- * iwl_verify_ucode - determine which instruction image is in SRAM,
- * and verify its contents
- */
-int iwl_verify_ucode(struct iwl_priv *priv)
-{
- __le32 *image;
- u32 len;
- int ret;
-
- /* Try bootstrap */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Bootstrap uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try initialize */
- image = (__le32 *)priv->ucode_init.v_addr;
- len = priv->ucode_init.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Initialize uCode is good in inst SRAM\n");
- return 0;
- }
-
- /* Try runtime/protocol */
- image = (__le32 *)priv->ucode_code.v_addr;
- len = priv->ucode_code.len;
- ret = iwlcore_verify_inst_sparse(priv, image, len);
- if (!ret) {
- IWL_DEBUG_INFO(priv, "Runtime uCode is good in inst SRAM\n");
- return 0;
- }
-
- IWL_ERR(priv, "NO VALID UCODE IMAGE IN INSTRUCTION SRAM!!\n");
-
- /* Since nothing seems to match, show first several data entries in
- * instruction SRAM, so maybe visual inspection will give a clue.
- * Selection of bootstrap image (vs. other images) is arbitrary. */
- image = (__le32 *)priv->ucode_boot.v_addr;
- len = priv->ucode_boot.len;
- ret = iwl_verify_inst_full(priv, image, len);
-
- return ret;
-}
-EXPORT_SYMBOL(iwl_verify_ucode);
-
-
void iwl_rf_kill_ct_config(struct iwl_priv *priv)
{
struct iwl_ct_kill_config cmd;
@@ -2007,8 +1939,6 @@ static int iwl_set_mode(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->cfg->ops->hcmd->set_rxon_chain)
priv->cfg->ops->hcmd->set_rxon_chain(priv);
- memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN);
-
return iwlcore_commit_rxon(priv);
}
@@ -2017,7 +1947,8 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
struct iwl_priv *priv = hw->priv;
int err = 0;
- IWL_DEBUG_MAC80211(priv, "enter: type %d\n", vif->type);
+ IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+ vif->type, vif->addr);
mutex_lock(&priv->mutex);
@@ -2035,9 +1966,6 @@ int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
priv->vif = vif;
priv->iw_mode = vif->type;
- IWL_DEBUG_MAC80211(priv, "Set %pM\n", vif->addr);
- memcpy(priv->mac_addr, vif->addr, ETH_ALEN);
-
err = iwl_set_mode(priv, vif);
if (err)
goto out_err;
@@ -2071,6 +1999,11 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
}
if (priv->vif == vif) {
priv->vif = NULL;
+ if (priv->scan_vif == vif) {
+ ieee80211_scan_completed(priv->hw, true);
+ priv->scan_vif = NULL;
+ priv->scan_request = NULL;
+ }
memset(priv->bssid, 0, ETH_ALEN);
}
mutex_unlock(&priv->mutex);
@@ -2171,22 +2104,7 @@ int iwl_mac_config(struct ieee80211_hw *hw, u32 changed)
iwl_set_flags_for_band(priv, conf->channel->band, priv->vif);
spin_unlock_irqrestore(&priv->lock, flags);
- if (iwl_is_associated(priv) &&
- (le16_to_cpu(priv->active_rxon.channel) != ch) &&
- priv->cfg->ops->lib->set_channel_switch) {
- iwl_set_rate(priv);
- /*
- * at this point, staging_rxon has the
- * configuration for channel switch
- */
- ret = priv->cfg->ops->lib->set_channel_switch(priv,
- ch);
- if (!ret) {
- iwl_print_rx_config_cmd(priv);
- goto out;
- }
- priv->switch_rxon.switch_in_progress = false;
- }
+
set_ch_out:
/* The list of supported rates and rate mask can be different
* for each band; since the band may have changed, reset
@@ -2544,7 +2462,7 @@ void iwl_update_stats(struct iwl_priv *priv, bool is_tx, __le16 fc, u16 len)
EXPORT_SYMBOL(iwl_update_stats);
#endif
-const static char *get_csr_string(int cmd)
+static const char *get_csr_string(int cmd)
{
switch (cmd) {
IWL_CMD(CSR_HW_IF_CONFIG_REG);
@@ -2615,7 +2533,7 @@ void iwl_dump_csr(struct iwl_priv *priv)
}
EXPORT_SYMBOL(iwl_dump_csr);
-const static char *get_fh_string(int cmd)
+static const char *get_fh_string(int cmd)
{
switch (cmd) {
IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
@@ -2837,6 +2755,61 @@ void iwl_bg_monitor_recover(unsigned long data)
}
EXPORT_SYMBOL(iwl_bg_monitor_recover);
+
+/*
+ * extended beacon time format
+ * time in usec will be changed into a 32-bit value in extended:internal format
+ * the extended part is the beacon counts
+ * the internal part is the time in usec within one beacon interval
+ */
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
+{
+ u32 quot;
+ u32 rem;
+ u32 interval = beacon_interval * TIME_UNIT;
+
+ if (!interval || !usec)
+ return 0;
+
+ quot = (usec / interval) &
+ (iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits) >>
+ priv->hw_params.beacon_time_tsf_bits);
+ rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+
+ return (quot << priv->hw_params.beacon_time_tsf_bits) + rem;
+}
+EXPORT_SYMBOL(iwl_usecs_to_beacons);
+
+/* base is usually what we get from ucode with each received frame,
+ * the same as HW timer counter counting down
+ */
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+ u32 addon, u32 beacon_interval)
+{
+ u32 base_low = base & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+ u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
+ priv->hw_params.beacon_time_tsf_bits);
+ u32 interval = beacon_interval * TIME_UNIT;
+ u32 res = (base & iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits)) +
+ (addon & iwl_beacon_time_mask_high(priv,
+ priv->hw_params.beacon_time_tsf_bits));
+
+ if (base_low > addon_low)
+ res += base_low - addon_low;
+ else if (base_low < addon_low) {
+ res += interval + base_low - addon_low;
+ res += (1 << priv->hw_params.beacon_time_tsf_bits);
+ } else
+ res += (1 << priv->hw_params.beacon_time_tsf_bits);
+
+ return cpu_to_le32(res);
+}
+EXPORT_SYMBOL(iwl_add_beacon_time);
+
#ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 7e5a5ba41fd2..76288c56a7d7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -79,6 +79,8 @@ struct iwl_cmd;
.subvendor = PCI_ANY_ID, .subdevice = (subdev), \
.driver_data = (kernel_ulong_t)&(cfg)
+#define TIME_UNIT 1024
+
#define IWL_SKU_G 0x1
#define IWL_SKU_A 0x2
#define IWL_SKU_N 0x8
@@ -173,7 +175,8 @@ struct iwl_lib_ops {
void (*dump_nic_error_log)(struct iwl_priv *priv);
void (*dump_csr)(struct iwl_priv *priv);
int (*dump_fh)(struct iwl_priv *priv, char **buf, bool display);
- int (*set_channel_switch)(struct iwl_priv *priv, u16 channel);
+ int (*set_channel_switch)(struct iwl_priv *priv,
+ struct ieee80211_channel_switch *ch_switch);
/* power management */
struct iwl_apm_ops apm_ops;
@@ -325,7 +328,8 @@ struct iwl_cfg {
const bool ucode_tracing;
const bool sensitivity_calib_by_driver;
const bool chain_noise_calib_by_driver;
- u8 scan_antennas[IEEE80211_NUM_BANDS];
+ u8 scan_rx_antennas[IEEE80211_NUM_BANDS];
+ u8 scan_tx_antennas[IEEE80211_NUM_BANDS];
};
/***************************
@@ -343,11 +347,17 @@ int iwl_check_rxon_cmd(struct iwl_priv *priv);
int iwl_full_rxon_required(struct iwl_priv *priv);
void iwl_set_rxon_chain(struct iwl_priv *priv);
int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch);
+void iwl_set_flags_for_band(struct iwl_priv *priv,
+ enum ieee80211_band band,
+ struct ieee80211_vif *vif);
+u8 iwl_get_single_channel_number(struct iwl_priv *priv,
+ enum ieee80211_band band);
void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_config *ht_conf);
u8 iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
struct ieee80211_sta_ht_cap *sta_ht_inf);
void iwl_connection_init_rx_config(struct iwl_priv *priv,
struct ieee80211_vif *vif);
+void iwl_set_rate(struct iwl_priv *priv);
int iwl_set_decrypted_flag(struct iwl_priv *priv,
struct ieee80211_hdr *hdr,
u32 decrypt_res,
@@ -459,6 +469,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
void iwl_reply_statistics(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
+void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);
void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
/* TX helpers */
@@ -472,8 +483,6 @@ int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
dma_addr_t addr, u16 len, u8 reset, u8 pad);
int iwl_hw_tx_queue_init(struct iwl_priv *priv,
struct iwl_tx_queue *txq);
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed);
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
int slots_num, u32 txq_id);
@@ -493,7 +502,7 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags);
u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv);
-u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx);
+u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
{
@@ -526,7 +535,7 @@ void iwl_bg_start_internal_scan(struct work_struct *work);
void iwl_internal_short_hw_scan(struct iwl_priv *priv);
int iwl_force_reset(struct iwl_priv *priv, int mode);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
- const u8 *ie, int ie_len, int left);
+ const u8 *ta, const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
enum ieee80211_band band,
@@ -593,6 +602,9 @@ static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
}
void iwl_bg_monitor_recover(unsigned long data);
+u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
+__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
+ u32 addon, u32 beacon_interval);
#ifdef CONFIG_PM
int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state);
@@ -691,7 +703,6 @@ extern void iwl_rf_kill_ct_config(struct iwl_priv *priv);
extern void iwl_send_bt_config(struct iwl_priv *priv);
extern int iwl_send_statistics_request(struct iwl_priv *priv,
u8 flags, bool clear);
-extern int iwl_verify_ucode(struct iwl_priv *priv);
extern int iwl_send_lq_cmd(struct iwl_priv *priv,
struct iwl_link_quality_cmd *lq, u8 flags, bool init);
void iwl_apm_stop(struct iwl_priv *priv);
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 9659c5d01df9..d9f21bb9d75d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -106,27 +106,6 @@ static const struct file_operations iwl_dbgfs_##name##_ops = { \
.open = iwl_dbgfs_open_file_generic, \
};
-int iwl_dbgfs_statistics_flag(struct iwl_priv *priv, char *buf, int bufsz)
-{
- int p = 0;
-
- p += scnprintf(buf + p, bufsz - p, "Statistics Flag(0x%X):\n",
- le32_to_cpu(priv->statistics.flag));
- if (le32_to_cpu(priv->statistics.flag) & UCODE_STATISTICS_CLEAR_MSK)
- p += scnprintf(buf + p, bufsz - p,
- "\tStatistics have been cleared\n");
- p += scnprintf(buf + p, bufsz - p, "\tOperational Frequency: %s\n",
- (le32_to_cpu(priv->statistics.flag) &
- UCODE_STATISTICS_FREQUENCY_MSK)
- ? "2.4 GHz" : "5.2 GHz");
- p += scnprintf(buf + p, bufsz - p, "\tTGj Narrow Band: %s\n",
- (le32_to_cpu(priv->statistics.flag) &
- UCODE_STATISTICS_NARROW_BAND_MSK)
- ? "enabled" : "disabled");
- return p;
-}
-EXPORT_SYMBOL(iwl_dbgfs_statistics_flag);
-
static ssize_t iwl_dbgfs_tx_statistics_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos) {
@@ -330,45 +309,35 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
for (i = 0; i < max_sta; i++) {
station = &priv->stations[i];
- if (station->used) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "station %d:\ngeneral data:\n", i+1);
- pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n",
- station->sta.sta.sta_id);
- pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n",
- station->sta.mode);
- pos += scnprintf(buf + pos, bufsz - pos,
- "flags: 0x%x\n",
- station->sta.station_flags_msk);
- pos += scnprintf(buf + pos, bufsz - pos, "tid data:\n");
- pos += scnprintf(buf + pos, bufsz - pos,
- "seq_num\t\ttxq_id");
- pos += scnprintf(buf + pos, bufsz - pos,
- "\tframe_count\twait_for_ba\t");
- pos += scnprintf(buf + pos, bufsz - pos,
- "start_idx\tbitmap0\t");
- pos += scnprintf(buf + pos, bufsz - pos,
- "bitmap1\trate_n_flags");
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
+ if (!station->used)
+ continue;
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "station %d - addr: %pM, flags: %#x\n",
+ i, station->sta.sta.addr,
+ station->sta.station_flags_msk);
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "TID\tseq_num\ttxq_id\tframes\ttfds\t");
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "start_idx\tbitmap\t\t\trate_n_flags\n");
- for (j = 0; j < MAX_TID_COUNT; j++) {
- pos += scnprintf(buf + pos, bufsz - pos,
- "[%d]:\t\t%u", j,
- station->tid[j].seq_number);
- pos += scnprintf(buf + pos, bufsz - pos,
- "\t%u\t\t%u\t\t%u\t\t",
- station->tid[j].agg.txq_id,
- station->tid[j].agg.frame_count,
- station->tid[j].agg.wait_for_ba);
+ for (j = 0; j < MAX_TID_COUNT; j++) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%d:\t%#x\t%#x\t%u\t%u\t%u\t\t%#.16llx\t%#x",
+ j, station->tid[j].seq_number,
+ station->tid[j].agg.txq_id,
+ station->tid[j].agg.frame_count,
+ station->tid[j].tfds_in_queue,
+ station->tid[j].agg.start_idx,
+ station->tid[j].agg.bitmap,
+ station->tid[j].agg.rate_n_flags);
+
+ if (station->tid[j].agg.wait_for_ba)
pos += scnprintf(buf + pos, bufsz - pos,
- "%u\t%llu\t%u",
- station->tid[j].agg.start_idx,
- (unsigned long long)station->tid[j].agg.bitmap,
- station->tid[j].agg.rate_n_flags);
- pos += scnprintf(buf + pos, bufsz - pos, "\n");
- }
+ " - waitforba");
pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
+
+ pos += scnprintf(buf + pos, bufsz - pos, "\n");
}
ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f3f3473c5c7e..fc6072cdd96f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -48,25 +48,6 @@
#include "iwl-power.h"
#include "iwl-agn-rs.h"
-/* configuration for the iwl4965 */
-extern struct iwl_cfg iwl4965_agn_cfg;
-extern struct iwl_cfg iwl5300_agn_cfg;
-extern struct iwl_cfg iwl5100_agn_cfg;
-extern struct iwl_cfg iwl5350_agn_cfg;
-extern struct iwl_cfg iwl5100_bgn_cfg;
-extern struct iwl_cfg iwl5100_abg_cfg;
-extern struct iwl_cfg iwl5150_agn_cfg;
-extern struct iwl_cfg iwl5150_abg_cfg;
-extern struct iwl_cfg iwl6000g2a_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2agn_cfg;
-extern struct iwl_cfg iwl6000i_2abg_cfg;
-extern struct iwl_cfg iwl6000i_2bg_cfg;
-extern struct iwl_cfg iwl6000_3agn_cfg;
-extern struct iwl_cfg iwl6050_2agn_cfg;
-extern struct iwl_cfg iwl6050_2abg_cfg;
-extern struct iwl_cfg iwl1000_bgn_cfg;
-extern struct iwl_cfg iwl1000_bg_cfg;
-
struct iwl_tx_queue;
/* CT-KILL constants */
@@ -133,8 +114,8 @@ struct iwl_cmd_meta {
* structure is stored at the end of the shared queue memory. */
u32 flags;
- DECLARE_PCI_UNMAP_ADDR(mapping)
- DECLARE_PCI_UNMAP_LEN(len)
+ DEFINE_DMA_UNMAP_ADDR(mapping);
+ DEFINE_DMA_UNMAP_LEN(len);
};
/*
@@ -157,11 +138,11 @@ struct iwl_queue {
* space more than this */
int high_mark; /* high watermark, stop queue if free
* space less than this */
-} __attribute__ ((packed));
+} __packed;
/* One for each TFD */
struct iwl_tx_info {
- struct sk_buff *skb[IWL_NUM_OF_TBS - 1];
+ struct sk_buff *skb;
};
/**
@@ -343,8 +324,8 @@ struct iwl_device_cmd {
struct iwl_tx_cmd tx;
struct iwl6000_channel_switch_cmd chswitch;
u8 payload[DEF_CMD_PAYLOAD_SIZE];
- } __attribute__ ((packed)) cmd;
-} __attribute__ ((packed));
+ } __packed cmd;
+} __packed;
#define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
@@ -433,7 +414,7 @@ struct iwl_ht_agg {
struct iwl_tid_data {
- u16 seq_number;
+ u16 seq_number; /* agn only */
u16 tfds_in_queue;
struct iwl_ht_agg agg;
};
@@ -583,6 +564,12 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_INIT_DATA = 4,
IWL_UCODE_TLV_BOOT = 5,
IWL_UCODE_TLV_PROBE_MAX_LEN = 6, /* a u32 value */
+ IWL_UCODE_TLV_RUNT_EVTLOG_PTR = 8,
+ IWL_UCODE_TLV_RUNT_EVTLOG_SIZE = 9,
+ IWL_UCODE_TLV_RUNT_ERRLOG_PTR = 10,
+ IWL_UCODE_TLV_INIT_EVTLOG_PTR = 11,
+ IWL_UCODE_TLV_INIT_EVTLOG_SIZE = 12,
+ IWL_UCODE_TLV_INIT_ERRLOG_PTR = 13,
};
struct iwl_ucode_tlv {
@@ -590,7 +577,7 @@ struct iwl_ucode_tlv {
__le16 alternative; /* see comment */
__le32 length; /* not including type/length fields */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define IWL_TLV_UCODE_MAGIC 0x0a4c5749
@@ -675,6 +662,7 @@ struct iwl_sensitivity_ranges {
* @sw_crypto: 0 for hw, 1 for sw
* @max_xxx_size: for ucode uses
* @ct_kill_threshold: temperature threshold
+ * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
* @calib_init_cfg: setup initial calibrations for the hw
* @struct iwl_sensitivity_ranges: range of sensitivity values
*/
@@ -701,6 +689,7 @@ struct iwl_hw_params {
u32 ct_kill_threshold; /* value in hw-dependent units */
u32 ct_kill_exit_threshold; /* value in hw-dependent units */
/* for 1000, 6000 series and up */
+ u16 beacon_time_tsf_bits;
u32 calib_init_cfg;
const struct iwl_sensitivity_ranges *sens;
};
@@ -1075,6 +1064,20 @@ struct iwl_force_reset {
unsigned long last_force_reset_jiffies;
};
+/* extend beacon time format bit shifting */
+/*
+ * for _3945 devices
+ * bits 31:24 - extended
+ * bits 23:0 - interval
+ */
+#define IWL3945_EXT_BEACON_TIME_POS 24
+/*
+ * for _agn devices
+ * bits 31:22 - extended
+ * bits 21:0 - interval
+ */
+#define IWLAGN_EXT_BEACON_TIME_POS 22
+
struct iwl_priv {
/* ieee device used by generic ieee processing code */
@@ -1109,7 +1112,7 @@ struct iwl_priv {
/* force reset */
struct iwl_force_reset force_reset[IWL_MAX_FORCE_RESET];
- /* we allocate array of iwl4965_channel_info for NIC's valid channels.
+ /* we allocate array of iwl_channel_info for NIC's valid channels.
* Access via channel # using indirect index array */
struct iwl_channel_info *channel_info; /* channel info array */
u8 channel_count; /* # of channels */
@@ -1127,6 +1130,7 @@ struct iwl_priv {
void *scan_cmd;
enum ieee80211_band scan_band;
struct cfg80211_scan_request *scan_request;
+ struct ieee80211_vif *scan_vif;
bool is_internal_short_scan;
u8 scan_tx_ant[IEEE80211_NUM_BANDS];
u8 mgmt_tx_ant;
@@ -1174,7 +1178,7 @@ struct iwl_priv {
struct iwl_switch_rxon switch_rxon;
/* 1st responses from initialize and runtime uCode images.
- * 4965's initialize alive response contains some calibration data. */
+ * _agn's initialize alive response contains some calibration data. */
struct iwl_init_alive_resp card_alive_init;
struct iwl_alive_resp card_alive;
@@ -1221,7 +1225,7 @@ struct iwl_priv {
struct iwl_tt_mgmt thermal_throttle;
struct iwl_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl_notif_statistics accum_statistics;
struct iwl_notif_statistics delta_statistics;
struct iwl_notif_statistics max_delta;
@@ -1229,9 +1233,10 @@ struct iwl_priv {
/* context information */
u8 bssid[ETH_ALEN]; /* used only on 3945 but filled by core */
- u8 mac_addr[ETH_ALEN];
- /*station table variables */
+ /* station table variables */
+
+ /* Note: if lock and sta_lock are needed, lock must be acquired first */
spinlock_t sta_lock;
int num_stations;
struct iwl_station_entry stations[IWL_STATION_COUNT];
@@ -1273,7 +1278,7 @@ struct iwl_priv {
struct delayed_work rfkill_poll;
struct iwl3945_notif_statistics statistics;
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
struct iwl3945_notif_statistics accum_statistics;
struct iwl3945_notif_statistics delta_statistics;
struct iwl3945_notif_statistics max_delta;
@@ -1315,6 +1320,9 @@ struct iwl_priv {
bool last_phy_res_valid;
struct completion firmware_loading_complete;
+
+ u32 init_evtlog_ptr, init_evtlog_size, init_errlog_ptr;
+ u32 inst_evtlog_ptr, inst_evtlog_size, inst_errlog_ptr;
} _agn;
#endif
};
@@ -1353,9 +1361,7 @@ struct iwl_priv {
/* debugging info */
u32 debug_level; /* per device debugging will override global
iwl_debug_level if set */
- u32 framecnt_to_us;
- atomic_t restrict_refcnt;
- bool disable_ht40;
+#endif /* CONFIG_IWLWIFI_DEBUG */
#ifdef CONFIG_IWLWIFI_DEBUGFS
/* debugfs */
u16 tx_traffic_idx;
@@ -1364,8 +1370,8 @@ struct iwl_priv {
u8 *rx_traffic;
struct dentry *debugfs_dir;
u32 dbgfs_sram_offset, dbgfs_sram_len;
+ bool disable_ht40;
#endif /* CONFIG_IWLWIFI_DEBUGFS */
-#endif /* CONFIG_IWLWIFI_DEBUG */
struct work_struct txpower_work;
u32 disable_sens_cal;
@@ -1419,9 +1425,9 @@ static inline u32 iwl_get_debug_level(struct iwl_priv *priv)
static inline struct ieee80211_hdr *iwl_tx_queue_get_hdr(struct iwl_priv *priv,
int txq_id, int idx)
{
- if (priv->txq[txq_id].txb[idx].skb[0])
+ if (priv->txq[txq_id].txb[idx].skb)
return (struct ieee80211_hdr *)priv->txq[txq_id].
- txb[idx].skb[0]->data;
+ txb[idx].skb->data;
return NULL;
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
index 95aa202c85e3..5488006491a2 100644
--- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h
+++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h
@@ -118,7 +118,7 @@ enum {
struct iwl_eeprom_channel {
u8 flags; /* EEPROM_CHANNEL_* flags copied from EEPROM */
s8 max_power_avg; /* max power (dBm) on this chnl, limit 31 */
-} __attribute__ ((packed));
+} __packed;
/**
* iwl_eeprom_enhanced_txpwr structure
@@ -144,7 +144,7 @@ struct iwl_eeprom_enhanced_txpwr {
s8 reserved;
s8 mimo2_max;
s8 mimo3_max;
-} __attribute__ ((packed));
+} __packed;
/* 3945 Specific */
#define EEPROM_3945_EEPROM_VERSION (0x2f)
@@ -312,7 +312,7 @@ struct iwl_eeprom_calib_measure {
u8 gain_idx; /* Index into gain table */
u8 actual_pow; /* Measured RF output power, half-dBm */
s8 pa_det; /* Power amp detector level (not used) */
-} __attribute__ ((packed));
+} __packed;
/*
@@ -328,7 +328,7 @@ struct iwl_eeprom_calib_ch_info {
struct iwl_eeprom_calib_measure
measurements[EEPROM_TX_POWER_TX_CHAINS]
[EEPROM_TX_POWER_MEASUREMENTS];
-} __attribute__ ((packed));
+} __packed;
/*
* txpower subband info.
@@ -345,7 +345,7 @@ struct iwl_eeprom_calib_subband_info {
u8 ch_to; /* channel number of highest channel in subband */
struct iwl_eeprom_calib_ch_info ch1;
struct iwl_eeprom_calib_ch_info ch2;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -374,7 +374,7 @@ struct iwl_eeprom_calib_info {
__le16 voltage; /* signed */
struct iwl_eeprom_calib_subband_info
band_info[EEPROM_TX_POWER_BANDS];
-} __attribute__ ((packed));
+} __packed;
#define ADDRESS_MSK 0x0000FFFF
diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h
index 113c3669b9ce..a3fcbb5f2c70 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fh.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fh.h
@@ -449,7 +449,7 @@ struct iwl_rb_status {
__le16 finished_rb_num;
__le16 finished_fr_nam;
__le32 __unused; /* 3945 only */
-} __attribute__ ((packed));
+} __packed;
#define TFD_QUEUE_SIZE_MAX (256)
@@ -475,7 +475,7 @@ static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr)
struct iwl_tfd_tb {
__le32 lo;
__le16 hi_n_len;
-} __attribute__((packed));
+} __packed;
/**
* struct iwl_tfd
@@ -510,7 +510,7 @@ struct iwl_tfd {
u8 num_tbs;
struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS];
__le32 __pad;
-} __attribute__ ((packed));
+} __packed;
/* Keep Warm Size */
#define IWL_KW_SIZE 0x1000 /* 4k */
diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h
index 3ff6b9d25a10..621abe3c5afc 100644
--- a/drivers/net/wireless/iwlwifi/iwl-helpers.h
+++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h
@@ -92,6 +92,11 @@ static inline void iwl_free_fw_desc(struct pci_dev *pci_dev,
static inline int iwl_alloc_fw_desc(struct pci_dev *pci_dev,
struct fw_desc *desc)
{
+ if (!desc->len) {
+ desc->v_addr = NULL;
+ return -EINVAL;
+ }
+
desc->v_addr = dma_alloc_coherent(&pci_dev->dev, desc->len,
&desc->p_addr, GFP_KERNEL);
return (desc->v_addr != NULL) ? 0 : -ENOMEM;
@@ -170,4 +175,26 @@ static inline void iwl_enable_interrupts(struct iwl_priv *priv)
iwl_write32(priv, CSR_INT_MASK, priv->inta_mask);
}
+/**
+ * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return (1 << tsf_bits) - 1;
+}
+
+/**
+ * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
+ * @priv -- pointer to iwl_priv data structure
+ * @tsf_bits -- number of bits need to shift for masking)
+ */
+static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
+ u16 tsf_bits)
+{
+ return ((1 << (32 - tsf_bits)) - 1) << tsf_bits;
+}
+
#endif /* __iwl_helpers_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 0a5d7cf25196..5e32057d6938 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -286,7 +286,7 @@ static void iwl_rx_calc_noise(struct iwl_priv *priv)
last_rx_noise);
}
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
/*
* based on the assumption of all statistics counter are in DWORD
* FIXME: This function is for debugging, do not deal with
@@ -448,7 +448,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
STATISTICS_REPLY_FLG_HT40_MODE_MSK) !=
(pkt->u.stats.flag & STATISTICS_REPLY_FLG_HT40_MODE_MSK)));
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_accumulative_statistics(priv, (__le32 *)&pkt->u.stats);
#endif
iwl_recover_from_statistics(priv, pkt);
@@ -480,7 +480,7 @@ void iwl_reply_statistics(struct iwl_priv *priv,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
if (le32_to_cpu(pkt->u.stats.flag) & UCODE_STATISTICS_CLEAR_MSK) {
-#ifdef CONFIG_IWLWIFI_DEBUG
+#ifdef CONFIG_IWLWIFI_DEBUGFS
memset(&priv->accum_statistics, 0,
sizeof(struct iwl_notif_statistics));
memset(&priv->delta_statistics, 0,
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c
index 5d3f51ff2f0d..b8bcd48eb8fa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scan.c
+++ b/drivers/net/wireless/iwlwifi/iwl-scan.c
@@ -333,7 +333,8 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
goto out_unlock;
}
- if (test_bit(STATUS_SCANNING, &priv->status)) {
+ if (test_bit(STATUS_SCANNING, &priv->status) &&
+ !priv->is_internal_short_scan) {
IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
ret = -EAGAIN;
goto out_unlock;
@@ -348,8 +349,16 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
/* mac80211 will only ask for one band at a time */
priv->scan_band = req->channels[0]->band;
priv->scan_request = req;
+ priv->scan_vif = vif;
- ret = iwl_scan_initiate(priv, vif);
+ /*
+ * If an internal scan is in progress, just set
+ * up the scan_request as per above.
+ */
+ if (priv->is_internal_short_scan)
+ ret = 0;
+ else
+ ret = iwl_scan_initiate(priv, vif);
IWL_DEBUG_MAC80211(priv, "leave\n");
@@ -438,7 +447,7 @@ EXPORT_SYMBOL(iwl_bg_scan_check);
*/
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
- const u8 *ies, int ie_len, int left)
+ const u8 *ta, const u8 *ies, int ie_len, int left)
{
int len = 0;
u8 *pos = NULL;
@@ -451,7 +460,7 @@ u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
memcpy(frame->da, iwl_bcast_addr, ETH_ALEN);
- memcpy(frame->sa, priv->mac_addr, ETH_ALEN);
+ memcpy(frame->sa, ta, ETH_ALEN);
memcpy(frame->bssid, iwl_bcast_addr, ETH_ALEN);
frame->seq_ctrl = 0;
@@ -513,7 +522,21 @@ void iwl_bg_scan_completed(struct work_struct *work)
priv->is_internal_short_scan = false;
IWL_DEBUG_SCAN(priv, "internal short scan completed\n");
internal = true;
+ } else {
+ priv->scan_request = NULL;
+ priv->scan_vif = NULL;
}
+
+ if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+ goto out;
+
+ if (internal && priv->scan_request)
+ iwl_scan_initiate(priv, priv->scan_vif);
+
+ /* Since setting the TXPOWER may have been deferred while
+ * performing the scan, fire one off */
+ iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
+ out:
mutex_unlock(&priv->mutex);
/*
@@ -523,15 +546,6 @@ void iwl_bg_scan_completed(struct work_struct *work)
*/
if (!internal)
ieee80211_scan_completed(priv->hw, false);
-
- if (test_bit(STATUS_EXIT_PENDING, &priv->status))
- return;
-
- /* Since setting the TXPOWER may have been deferred while
- * performing the scan, fire one off */
- mutex_lock(&priv->mutex);
- iwl_set_tx_power(priv, priv->tx_power_user_lmt, true);
- mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL(iwl_bg_scan_completed);
diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
index af6babee2891..c4ca0b5d77da 100644
--- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h
+++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h
@@ -42,7 +42,7 @@ struct ieee80211_basic_report {
__le64 start_time;
__le16 duration;
u8 map;
-} __attribute__ ((packed));
+} __packed;
enum { /* ieee80211_measurement_request.mode */
/* Bit 0 is reserved */
@@ -63,13 +63,13 @@ struct ieee80211_measurement_params {
u8 channel;
__le64 start_time;
__le16 duration;
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_info_element {
u8 id;
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_measurement_request {
struct ieee80211_info_element ie;
@@ -77,7 +77,7 @@ struct ieee80211_measurement_request {
u8 mode;
u8 type;
struct ieee80211_measurement_params params[0];
-} __attribute__ ((packed));
+} __packed;
struct ieee80211_measurement_report {
struct ieee80211_info_element ie;
@@ -87,6 +87,6 @@ struct ieee80211_measurement_report {
union {
struct ieee80211_basic_report basic[0];
} u;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c
index 83a26361a9b5..c7127132c298 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.c
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.c
@@ -311,10 +311,10 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
struct ieee80211_sta_ht_cap *ht_info,
u8 *sta_id_r)
{
- struct iwl_station_entry *station;
unsigned long flags_spin;
int ret = 0;
u8 sta_id;
+ struct iwl_addsta_cmd sta_cmd;
*sta_id_r = 0;
spin_lock_irqsave(&priv->sta_lock, flags_spin);
@@ -347,14 +347,15 @@ int iwl_add_station_common(struct iwl_priv *priv, const u8 *addr,
}
priv->stations[sta_id].used |= IWL_STA_UCODE_INPROGRESS;
- station = &priv->stations[sta_id];
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
/* Add station to device's station table */
- ret = iwl_send_add_sta(priv, &station->sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n", station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[sta_id].sta.sta.addr);
priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[sta_id].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -488,7 +489,7 @@ static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, u8 sta_id)
}
static int iwl_send_remove_station(struct iwl_priv *priv,
- struct iwl_station_entry *station)
+ const u8 *addr, int sta_id)
{
struct iwl_rx_packet *pkt;
int ret;
@@ -505,7 +506,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
memset(&rm_sta_cmd, 0, sizeof(rm_sta_cmd));
rm_sta_cmd.num_sta = 1;
- memcpy(&rm_sta_cmd.addr, &station->sta.sta.addr , ETH_ALEN);
+ memcpy(&rm_sta_cmd.addr, addr, ETH_ALEN);
cmd.flags |= CMD_WANT_SKB;
@@ -525,7 +526,7 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
switch (pkt->u.rem_sta.status) {
case REM_STA_SUCCESS_MSK:
spin_lock_irqsave(&priv->sta_lock, flags_spin);
- iwl_sta_ucode_deactivate(priv, station->sta.sta.sta_id);
+ iwl_sta_ucode_deactivate(priv, sta_id);
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
IWL_DEBUG_ASSOC(priv, "REPLY_REMOVE_STA PASSED\n");
break;
@@ -546,7 +547,6 @@ static int iwl_send_remove_station(struct iwl_priv *priv,
int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
const u8 *addr)
{
- struct iwl_station_entry *station;
unsigned long flags;
if (!iwl_is_ready(priv)) {
@@ -592,10 +592,9 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
BUG_ON(priv->num_stations < 0);
- station = &priv->stations[sta_id];
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_remove_station(priv, station);
+ return iwl_send_remove_station(priv, addr, sta_id);
out_err:
spin_unlock_irqrestore(&priv->sta_lock, flags);
return -EINVAL;
@@ -643,11 +642,13 @@ EXPORT_SYMBOL(iwl_clear_ucode_stations);
*/
void iwl_restore_stations(struct iwl_priv *priv)
{
- struct iwl_station_entry *station;
+ struct iwl_addsta_cmd sta_cmd;
+ struct iwl_link_quality_cmd lq;
unsigned long flags_spin;
int i;
bool found = false;
int ret;
+ bool send_lq;
if (!iwl_is_ready(priv)) {
IWL_DEBUG_INFO(priv, "Not ready yet, not restoring any stations.\n");
@@ -669,13 +670,20 @@ void iwl_restore_stations(struct iwl_priv *priv)
for (i = 0; i < priv->hw_params.max_stations; i++) {
if ((priv->stations[i].used & IWL_STA_UCODE_INPROGRESS)) {
+ memcpy(&sta_cmd, &priv->stations[i].sta,
+ sizeof(struct iwl_addsta_cmd));
+ send_lq = false;
+ if (priv->stations[i].lq) {
+ memcpy(&lq, priv->stations[i].lq,
+ sizeof(struct iwl_link_quality_cmd));
+ send_lq = true;
+ }
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
- station = &priv->stations[i];
- ret = iwl_send_add_sta(priv, &priv->stations[i].sta, CMD_SYNC);
+ ret = iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
if (ret) {
- IWL_ERR(priv, "Adding station %pM failed.\n",
- station->sta.sta.addr);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
+ IWL_ERR(priv, "Adding station %pM failed.\n",
+ priv->stations[i].sta.sta.addr);
priv->stations[i].used &= ~IWL_STA_DRIVER_ACTIVE;
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
spin_unlock_irqrestore(&priv->sta_lock, flags_spin);
@@ -684,8 +692,8 @@ void iwl_restore_stations(struct iwl_priv *priv)
* Rate scaling has already been initialized, send
* current LQ command
*/
- if (station->lq)
- iwl_send_lq_cmd(priv, station->lq, CMD_SYNC, true);
+ if (send_lq)
+ iwl_send_lq_cmd(priv, &lq, CMD_SYNC, true);
spin_lock_irqsave(&priv->sta_lock, flags_spin);
priv->stations[i].used &= ~IWL_STA_UCODE_INPROGRESS;
}
@@ -972,24 +980,16 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
unsigned long flags;
int i;
- if (sta) {
- sta_id = iwl_sta_id(sta);
-
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv, "leave - %pM not initialised.\n",
- sta->addr);
- return;
- }
- } else
- sta_id = priv->hw_params.bcast_sta_id;
-
-
if (iwl_scan_cancel(priv)) {
/* cancel scan failed, just live w/ bad key and rely
briefly on SW decryption */
return;
}
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return;
+
spin_lock_irqsave(&priv->sta_lock, flags);
priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32;
@@ -1277,9 +1277,8 @@ void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid)
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_TID_DISABLE_TX;
priv->stations[sta_id].sta.tid_disable_tx &= cpu_to_le16(~(1 << tid));
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
- spin_unlock_irqrestore(&priv->sta_lock, flags);
-
iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+ spin_unlock_irqrestore(&priv->sta_lock, flags);
}
EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid);
@@ -1310,7 +1309,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
int tid)
{
unsigned long flags;
- int sta_id;
+ int sta_id, ret;
sta_id = iwl_sta_id(sta);
if (sta_id == IWL_INVALID_STATION) {
@@ -1323,10 +1322,11 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK;
priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ ret = iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- return iwl_send_add_sta(priv, &priv->stations[sta_id].sta,
- CMD_ASYNC);
+ return ret;
+
}
EXPORT_SYMBOL(iwl_sta_rx_agg_stop);
@@ -1340,9 +1340,9 @@ void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
priv->stations[sta_id].sta.sta.modify_mask = 0;
priv->stations[sta_id].sta.sleep_tx_count = 0;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_ps_wake);
@@ -1357,9 +1357,9 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
STA_MODIFY_SLEEP_TX_COUNT_MSK;
priv->stations[sta_id].sta.sleep_tx_count = cpu_to_le16(cnt);
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
spin_unlock_irqrestore(&priv->sta_lock, flags);
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
}
EXPORT_SYMBOL(iwl_sta_modify_sleep_tx_count);
diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h
index c2a453a1a991..5b1b1e461eb6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-sta.h
+++ b/drivers/net/wireless/iwlwifi/iwl-sta.h
@@ -107,4 +107,33 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
}
+
+/**
+ * iwl_sta_id_or_broadcast - return sta_id or broadcast sta
+ * @priv: iwl priv
+ * @sta: mac80211 station
+ *
+ * In certain circumstances mac80211 passes a station pointer
+ * that may be %NULL, for example during TX or key setup. In
+ * that case, we need to use the broadcast station, so this
+ * inline wraps that pattern.
+ */
+static inline int iwl_sta_id_or_broadcast(struct iwl_priv *priv,
+ struct ieee80211_sta *sta)
+{
+ int sta_id;
+
+ if (!sta)
+ return priv->hw_params.bcast_sta_id;
+
+ sta_id = iwl_sta_id(sta);
+
+ /*
+ * mac80211 should not be passing a partially
+ * initialised station!
+ */
+ WARN_ON(sta_id == IWL_INVALID_STATION);
+
+ return sta_id;
+}
#endif /* __iwl_sta_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 1ece2ea09773..a81989c06983 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -77,21 +77,6 @@ void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq)
}
EXPORT_SYMBOL(iwl_txq_update_write_ptr);
-
-void iwl_free_tfds_in_queue(struct iwl_priv *priv,
- int sta_id, int tid, int freed)
-{
- if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed)
- priv->stations[sta_id].tid[tid].tfds_in_queue -= freed;
- else {
- IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n",
- priv->stations[sta_id].tid[tid].tfds_in_queue,
- freed);
- priv->stations[sta_id].tid[tid].tfds_in_queue = 0;
- }
-}
-EXPORT_SYMBOL(iwl_free_tfds_in_queue);
-
/**
* iwl_tx_queue_free - Deallocate DMA queue.
* @txq: Transmit queue to deallocate.
@@ -169,15 +154,15 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
}
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->meta[i], mapping),
- pci_unmap_len(&txq->meta[i], len),
+ dma_unmap_addr(&txq->meta[i], mapping),
+ dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
}
if (huge) {
i = q->n_window;
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(&txq->meta[i], mapping),
- pci_unmap_len(&txq->meta[i], len),
+ dma_unmap_addr(&txq->meta[i], mapping),
+ dma_unmap_len(&txq->meta[i], len),
PCI_DMA_BIDIRECTIONAL);
}
@@ -287,7 +272,7 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv,
/* Driver private data, only for Tx (not command) queues,
* not shared with device. */
if (id != IWL_CMD_QUEUE_NUM) {
- txq->txb = kmalloc(sizeof(txq->txb[0]) *
+ txq->txb = kzalloc(sizeof(txq->txb[0]) *
TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
if (!txq->txb) {
IWL_ERR(priv, "kmalloc for auxiliary BD "
@@ -531,8 +516,8 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL);
- pci_unmap_addr_set(out_meta, mapping, phys_addr);
- pci_unmap_len_set(out_meta, len, fix_size);
+ dma_unmap_addr_set(out_meta, mapping, phys_addr);
+ dma_unmap_len_set(out_meta, len, fix_size);
trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
@@ -626,8 +611,8 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
meta = &txq->meta[cmd_index];
pci_unmap_single(priv->pci_dev,
- pci_unmap_addr(meta, mapping),
- pci_unmap_len(meta, len),
+ dma_unmap_addr(meta, mapping),
+ dma_unmap_len(meta, len),
PCI_DMA_BIDIRECTIONAL);
/* Input error checking is done when commands are added to queue. */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 3e5bffb6034f..0f16c7d518f7 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -197,6 +197,7 @@ static int iwl3945_set_wep_dynamic_key_info(struct iwl_priv *priv,
static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
{
unsigned long flags;
+ struct iwl_addsta_cmd sta_cmd;
spin_lock_irqsave(&priv->sta_lock, flags);
memset(&priv->stations[sta_id].keyinfo, 0, sizeof(struct iwl_hw_key));
@@ -205,11 +206,11 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
priv->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC;
priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+ memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(struct iwl_addsta_cmd));
spin_unlock_irqrestore(&priv->sta_lock, flags);
IWL_DEBUG_INFO(priv, "hwcrypto: clear ucode station key info\n");
- iwl_send_add_sta(priv, &priv->stations[sta_id].sta, 0);
- return 0;
+ return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
}
static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
@@ -474,10 +475,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
u8 unicast;
u8 sta_id;
u8 tid = 0;
- u16 seq_number = 0;
__le16 fc;
u8 wait_write_ptr = 0;
- u8 *qc = NULL;
unsigned long flags;
spin_lock_irqsave(&priv->lock, flags);
@@ -510,10 +509,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
hdr_len = ieee80211_hdrlen(fc);
/* Find index into station table for destination station */
- if (!info->control.sta)
- sta_id = priv->hw_params.bcast_sta_id;
- else
- sta_id = iwl_sta_id(info->control.sta);
+ sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
@@ -523,16 +519,10 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
IWL_DEBUG_RATE(priv, "station Id %d\n", sta_id);
if (ieee80211_is_data_qos(fc)) {
- qc = ieee80211_get_qos_ctl(hdr);
+ u8 *qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
if (unlikely(tid >= MAX_TID_COUNT))
goto drop;
- seq_number = priv->stations[sta_id].tid[tid].seq_number &
- IEEE80211_SCTL_SEQ;
- hdr->seq_ctrl = cpu_to_le16(seq_number) |
- (hdr->seq_ctrl &
- cpu_to_le16(IEEE80211_SCTL_FRAG));
- seq_number += 0x10;
}
/* Descriptor for chosen Tx queue */
@@ -548,7 +538,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
- txq->txb[q->write_ptr].skb[0] = skb;
+ txq->txb[q->write_ptr].skb = skb;
/* Init first empty entry in queue's array of Tx/cmd buffers */
out_cmd = txq->cmd[idx];
@@ -591,8 +581,6 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
- if (qc)
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
} else {
wait_write_ptr = 1;
txq->need_update = 0;
@@ -631,8 +619,8 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
len, PCI_DMA_TODEVICE);
/* we do not map meta data ... so we can safely access address to
* provide to unmap command*/
- pci_unmap_addr_set(out_meta, mapping, txcmd_phys);
- pci_unmap_len_set(out_meta, len, len);
+ dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+ dma_unmap_len_set(out_meta, len, len);
/* Add buffer containing Tx command and MAC(!) header to TFD's
* first entry */
@@ -677,55 +665,6 @@ drop:
return -1;
}
-#define BEACON_TIME_MASK_LOW 0x00FFFFFF
-#define BEACON_TIME_MASK_HIGH 0xFF000000
-#define TIME_UNIT 1024
-
-/*
- * extended beacon time format
- * time in usec will be changed into a 32-bit value in 8:24 format
- * the high 1 byte is the beacon counts
- * the lower 3 bytes is the time in usec within one beacon interval
- */
-
-static u32 iwl3945_usecs_to_beacons(u32 usec, u32 beacon_interval)
-{
- u32 quot;
- u32 rem;
- u32 interval = beacon_interval * 1024;
-
- if (!interval || !usec)
- return 0;
-
- quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24);
- rem = (usec % interval) & BEACON_TIME_MASK_LOW;
-
- return (quot << 24) + rem;
-}
-
-/* base is usually what we get from ucode with each received frame,
- * the same as HW timer counter counting down
- */
-
-static __le32 iwl3945_add_beacon_time(u32 base, u32 addon, u32 beacon_interval)
-{
- u32 base_low = base & BEACON_TIME_MASK_LOW;
- u32 addon_low = addon & BEACON_TIME_MASK_LOW;
- u32 interval = beacon_interval * TIME_UNIT;
- u32 res = (base & BEACON_TIME_MASK_HIGH) +
- (addon & BEACON_TIME_MASK_HIGH);
-
- if (base_low > addon_low)
- res += base_low - addon_low;
- else if (base_low < addon_low) {
- res += interval + base_low - addon_low;
- res += (1 << 24);
- } else
- res += (1 << 24);
-
- return cpu_to_le32(res);
-}
-
static int iwl3945_get_measurement(struct iwl_priv *priv,
struct ieee80211_measurement_params *params,
u8 type)
@@ -743,8 +682,7 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
int duration = le16_to_cpu(params->duration);
if (iwl_is_associated(priv))
- add_time =
- iwl3945_usecs_to_beacons(
+ add_time = iwl_usecs_to_beacons(priv,
le64_to_cpu(params->start_time) - priv->_3945.last_tsf,
le16_to_cpu(priv->rxon_timing.beacon_interval));
@@ -759,8 +697,8 @@ static int iwl3945_get_measurement(struct iwl_priv *priv,
if (iwl_is_associated(priv))
spectrum.start_time =
- iwl3945_add_beacon_time(priv->_3945.last_beacon_time,
- add_time,
+ iwl_add_beacon_time(priv,
+ priv->_3945.last_beacon_time, add_time,
le16_to_cpu(priv->rxon_timing.beacon_interval));
else
spectrum.start_time = 0;
@@ -1844,6 +1782,49 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
#endif
}
+static int iwl3945_get_single_channel_for_scan(struct iwl_priv *priv,
+ struct ieee80211_vif *vif,
+ enum ieee80211_band band,
+ struct iwl3945_scan_channel *scan_ch)
+{
+ const struct ieee80211_supported_band *sband;
+ u16 passive_dwell = 0;
+ u16 active_dwell = 0;
+ int added = 0;
+ u8 channel = 0;
+
+ sband = iwl_get_hw_mode(priv, band);
+ if (!sband) {
+ IWL_ERR(priv, "invalid band\n");
+ return added;
+ }
+
+ active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+ passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
+
+ if (passive_dwell <= active_dwell)
+ passive_dwell = active_dwell + 1;
+
+
+ channel = iwl_get_single_channel_number(priv, band);
+
+ if (channel) {
+ scan_ch->channel = channel;
+ scan_ch->type = 0; /* passive */
+ scan_ch->active_dwell = cpu_to_le16(active_dwell);
+ scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+ /* Set txpower levels to defaults */
+ scan_ch->tpc.dsp_atten = 110;
+ if (band == IEEE80211_BAND_5GHZ)
+ scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3;
+ else
+ scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3));
+ added++;
+ } else
+ IWL_ERR(priv, "no valid channel found\n");
+ return added;
+}
+
static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
enum ieee80211_band band,
u8 is_active, u8 n_probes,
@@ -2979,22 +2960,31 @@ void iwl3945_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
scan->tx_cmd.len = cpu_to_le16(
iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
+ vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan)));
} else {
+ /* use bcast addr, will not be transmitted but must be valid */
scan->tx_cmd.len = cpu_to_le16(
iwl_fill_probe_req(priv,
(struct ieee80211_mgmt *)scan->data,
- NULL, 0,
+ iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan)));
}
/* select Rx antennas */
scan->flags |= iwl3945_get_antenna_flags(priv);
- scan->channel_count =
- iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
- (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
+ if (priv->is_internal_short_scan) {
+ scan->channel_count =
+ iwl3945_get_single_channel_for_scan(priv, vif, band,
+ (void *)&scan->data[le16_to_cpu(
+ scan->tx_cmd.len)]);
+ } else {
+ scan->channel_count =
+ iwl3945_get_channels_for_scan(priv, band, is_active, n_probes,
+ (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)], vif);
+ }
if (scan->channel_count == 0) {
IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
@@ -3108,19 +3098,16 @@ void iwl3945_post_associate(struct iwl_priv *priv, struct ieee80211_vif *vif)
IWL_DEBUG_ASSOC(priv, "assoc id %d beacon interval %d\n",
vif->bss_conf.aid, vif->bss_conf.beacon_int);
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &= ~RXON_FLG_SHORT_SLOT_MSK;
}
iwlcore_commit_rxon(priv);
@@ -3284,8 +3271,7 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
priv->staging_rxon.assoc_id = 0;
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_PREAMBLE)
+ if (vif->bss_conf.use_short_preamble)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_PREAMBLE_MSK;
else
@@ -3293,17 +3279,12 @@ void iwl3945_config_ap(struct iwl_priv *priv, struct ieee80211_vif *vif)
~RXON_FLG_SHORT_PREAMBLE_MSK;
if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) {
- if (vif->bss_conf.assoc_capability &
- WLAN_CAPABILITY_SHORT_SLOT_TIME)
+ if (vif->bss_conf.use_short_slot)
priv->staging_rxon.flags |=
RXON_FLG_SHORT_SLOT_MSK;
else
priv->staging_rxon.flags &=
~RXON_FLG_SHORT_SLOT_MSK;
-
- if (vif->type == NL80211_IFTYPE_ADHOC)
- priv->staging_rxon.flags &=
- ~RXON_FLG_SHORT_SLOT_MSK;
}
/* restore RXON assoc */
priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK;
@@ -3336,17 +3317,9 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
static_key = !iwl_is_associated(priv);
if (!static_key) {
- if (!sta) {
- sta_id = priv->hw_params.bcast_sta_id;
- } else {
- sta_id = iwl_sta_id(sta);
- if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_MAC80211(priv,
- "leave - %pM not in station map.\n",
- sta->addr);
- return -EINVAL;
- }
- }
+ sta_id = iwl_sta_id_or_broadcast(priv, sta);
+ if (sta_id == IWL_INVALID_STATION)
+ return -EINVAL;
}
mutex_lock(&priv->mutex);
@@ -3973,9 +3946,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
priv->pci_dev = pdev;
priv->inta_mask = CSR_INI_SET_MASK;
-#ifdef CONFIG_IWLWIFI_DEBUG
- atomic_set(&priv->restrict_refcnt, 0);
-#endif
if (iwl_alloc_traffic_mem(priv))
IWL_ERR(priv, "Not enough memory to generate traffic log\n");
@@ -4044,9 +4014,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
}
/* MAC Address location in EEPROM same for 3945/4965 */
eeprom = (struct iwl3945_eeprom *)priv->eeprom;
- memcpy(priv->mac_addr, eeprom->mac_address, ETH_ALEN);
- IWL_DEBUG_INFO(priv, "MAC address: %pM\n", priv->mac_addr);
- SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+ IWL_DEBUG_INFO(priv, "MAC address: %pM\n", eeprom->mac_address);
+ SET_IEEE80211_PERM_ADDR(priv->hw, eeprom->mac_address);
/***********************
* 5. Setup HW Constants
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h
index 7e16bcf59978..6421689f5e8e 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.h
+++ b/drivers/net/wireless/iwmc3200wifi/commands.h
@@ -56,7 +56,7 @@
struct iwm_umac_cmd_reset {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_PARAM_TBL_ORD_FIX 0x0
#define UMAC_PARAM_TBL_ORD_VAR 0x1
@@ -220,37 +220,37 @@ struct iwm_umac_cmd_set_param_fix {
__le16 tbl;
__le16 key;
__le32 value;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_set_param_var {
__le16 tbl;
__le16 key;
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_param {
__le16 tbl;
__le16 key;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_param_resp {
__le16 tbl;
__le16 key;
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_eeprom_proxy_hdr {
__le32 type;
__le32 offset;
__le32 len;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_eeprom_proxy {
struct iwm_umac_cmd_eeprom_proxy_hdr hdr;
u8 buf[0];
-} __attribute__ ((packed));
+} __packed;
#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1
#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2
@@ -267,13 +267,13 @@ struct iwm_umac_channel_info {
u8 reserved;
u8 flags;
__le32 channels_mask;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_get_channel_list {
__le16 count;
__le16 reserved;
struct iwm_umac_channel_info ch[0];
-} __attribute__ ((packed));
+} __packed;
/* UMAC WiFi interface commands */
@@ -304,7 +304,7 @@ struct iwm_umac_ssid {
u8 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_scan_request {
struct iwm_umac_wifi_if hdr;
@@ -314,7 +314,7 @@ struct iwm_umac_cmd_scan_request {
u8 timeout; /* In seconds */
u8 reserved;
struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_CIPHER_TYPE_NONE 0xFF
#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00
@@ -357,7 +357,7 @@ struct iwm_umac_security {
u8 ucast_cipher;
u8 mcast_cipher;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_ibss {
u8 beacon_interval; /* in millisecond */
@@ -366,7 +366,7 @@ struct iwm_umac_ibss {
u8 band;
u8 channel;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_MODE_BSS 0
#define UMAC_MODE_IBSS 1
@@ -385,13 +385,13 @@ struct iwm_umac_profile {
__le16 flags;
u8 wireless_mode;
u8 bss_num;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_invalidate_profile {
struct iwm_umac_wifi_if hdr;
u8 reason;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
/* Encryption key commands */
struct iwm_umac_key_wep40 {
@@ -400,7 +400,7 @@ struct iwm_umac_key_wep40 {
u8 key[WLAN_KEY_LEN_WEP40];
u8 static_key;
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_wep104 {
struct iwm_umac_wifi_if hdr;
@@ -408,7 +408,7 @@ struct iwm_umac_key_wep104 {
u8 key[WLAN_KEY_LEN_WEP104];
u8 static_key;
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
#define IWM_TKIP_KEY_SIZE 16
#define IWM_TKIP_MIC_SIZE 8
@@ -420,7 +420,7 @@ struct iwm_umac_key_tkip {
u8 tkip_key[IWM_TKIP_KEY_SIZE];
u8 mic_rx_key[IWM_TKIP_MIC_SIZE];
u8 mic_tx_key[IWM_TKIP_MIC_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_ccmp {
struct iwm_umac_wifi_if hdr;
@@ -428,27 +428,27 @@ struct iwm_umac_key_ccmp {
u8 iv_count[6];
u8 reserved[2];
u8 key[WLAN_KEY_LEN_CCMP];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_key_remove {
struct iwm_umac_wifi_if hdr;
struct iwm_umac_key_hdr key_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_tx_key_id {
struct iwm_umac_wifi_if hdr;
u8 key_idx;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_pwr_trigger {
struct iwm_umac_wifi_if hdr;
__le32 reseved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_stats_req {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_cmd_stop_resume_tx {
u8 flags;
@@ -456,7 +456,7 @@ struct iwm_umac_cmd_stop_resume_tx {
__le16 stop_resume_tid_msk;
__le16 last_seq_num[IWM_UMAC_TID_NR];
u16 reserved;
-} __attribute__ ((packed));
+} __packed;
#define IWM_CMD_PMKID_ADD 1
#define IWM_CMD_PMKID_DEL 2
@@ -468,7 +468,7 @@ struct iwm_umac_pmkid_update {
u8 bssid[ETH_ALEN];
__le16 reserved;
u8 pmkid[WLAN_PMKID_LEN];
-} __attribute__ ((packed));
+} __packed;
/* LMAC commands */
int iwm_read_mac(struct iwm_priv *iwm, u8 *mac);
diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c
index 9531b18cf72a..907ac890997c 100644
--- a/drivers/net/wireless/iwmc3200wifi/hal.c
+++ b/drivers/net/wireless/iwmc3200wifi/hal.c
@@ -54,7 +54,7 @@
* LMAC. If you look at LMAC commands you'll se that they
* are actually regular iwlwifi target commands encapsulated
* into a special UMAC command called UMAC passthrough.
- * This is due to the fact the the host talks exclusively
+ * This is due to the fact the host talks exclusively
* to the UMAC and so there needs to be a special UMAC
* command for talking to the LMAC.
* This is how a wifi command is layed out:
diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h
index 13266c3842f8..51d7efa15ae6 100644
--- a/drivers/net/wireless/iwmc3200wifi/iwm.h
+++ b/drivers/net/wireless/iwmc3200wifi/iwm.h
@@ -162,7 +162,7 @@ struct iwm_umac_key_hdr {
u8 mac[ETH_ALEN];
u8 key_idx;
u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */
-} __attribute__ ((packed));
+} __packed;
struct iwm_key {
struct iwm_umac_key_hdr hdr;
diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h
index a855a99e49b8..5ddcdf8c70c0 100644
--- a/drivers/net/wireless/iwmc3200wifi/lmac.h
+++ b/drivers/net/wireless/iwmc3200wifi/lmac.h
@@ -43,7 +43,7 @@ struct iwm_lmac_hdr {
u8 id;
u8 flags;
__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
/* LMAC commands */
#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1
@@ -54,23 +54,23 @@ struct iwm_lmac_cal_cfg_elt {
__le32 send_res; /* 1 for sending back results */
__le32 apply_res; /* 1 for applying calibration results to HW */
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_status {
struct iwm_lmac_cal_cfg_elt init;
struct iwm_lmac_cal_cfg_elt periodic;
__le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_cmd {
struct iwm_lmac_cal_cfg_status ucode_cfg;
struct iwm_lmac_cal_cfg_status driver_cfg;
__le32 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_cal_cfg_resp {
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#define IWM_CARD_STATE_SW_HW_ENABLED 0x00
#define IWM_CARD_STATE_HW_DISABLED 0x01
@@ -80,7 +80,7 @@ struct iwm_lmac_cal_cfg_resp {
struct iwm_lmac_card_state {
__le32 flags;
-} __attribute__ ((packed));
+} __packed;
/**
* COEX_PRIORITY_TABLE_CMD
@@ -131,7 +131,7 @@ struct coex_event {
u8 win_med_prio;
u8 reserved;
u8 flags;
-} __attribute__ ((packed));
+} __packed;
#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1
#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4
@@ -142,7 +142,7 @@ struct iwm_coex_prio_table_cmd {
u8 flags;
u8 reserved[3];
struct coex_event sta_prio[COEX_EVENTS_NUM];
-} __attribute__ ((packed));
+} __packed;
/* Coexistence definitions
*
@@ -192,7 +192,7 @@ struct iwm_ct_kill_cfg_cmd {
u32 exit_threshold;
u32 reserved;
u32 entry_threshold;
-} __attribute__ ((packed));
+} __packed;
/* LMAC OP CODES */
@@ -428,7 +428,7 @@ struct iwm_lmac_calib_hdr {
u8 first_grp;
u8 grp_num;
u8 all_data_valid;
-} __attribute__ ((packed));
+} __packed;
#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7
#define IWM_CALIB_FREQ_GROUPS_NR 5
@@ -437,20 +437,20 @@ struct iwm_lmac_calib_hdr {
struct iwm_calib_rxiq_entry {
u16 ptam_postdist_ars;
u16 ptam_postdist_arc;
-} __attribute__ ((packed));
+} __packed;
struct iwm_calib_rxiq_group {
struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR];
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_calib_rxiq {
struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
struct iwm_calib_rxiq {
struct iwm_lmac_calib_hdr hdr;
struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR];
-} __attribute__ ((packed));
+} __packed;
#define LMAC_STA_ID_SEED 0x0f
#define LMAC_STA_ID_POS 0
@@ -463,7 +463,7 @@ struct iwm_lmac_power_report {
u8 pa_integ_res_A[3];
u8 pa_integ_res_B[3];
u8 pa_integ_res_C[3];
-} __attribute__ ((packed));
+} __packed;
struct iwm_lmac_tx_resp {
u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */
@@ -479,6 +479,6 @@ struct iwm_lmac_tx_resp {
u8 ra_tid;
__le16 frame_ctl;
__le32 status;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index e1184deca559..c02fcedea9fa 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -321,14 +321,14 @@ iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket)
return ERR_PTR(-ENOMEM);
}
- ticket_node->ticket = kzalloc(sizeof(struct iwm_rx_ticket), GFP_KERNEL);
+ ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket),
+ GFP_KERNEL);
if (!ticket_node->ticket) {
IWM_ERR(iwm, "Couldn't allocate RX ticket\n");
kfree(ticket_node);
return ERR_PTR(-ENOMEM);
}
- memcpy(ticket_node->ticket, ticket, sizeof(struct iwm_rx_ticket));
INIT_LIST_HEAD(&ticket_node->node);
return ticket_node;
diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h
index 0cbba3ecc813..4a137d334a42 100644
--- a/drivers/net/wireless/iwmc3200wifi/umac.h
+++ b/drivers/net/wireless/iwmc3200wifi/umac.h
@@ -42,19 +42,19 @@
struct iwm_udma_in_hdr {
__le32 cmd;
__le32 size;
-} __attribute__ ((packed));
+} __packed;
struct iwm_udma_out_nonwifi_hdr {
__le32 cmd;
__le32 addr;
__le32 op1_sz;
__le32 op2;
-} __attribute__ ((packed));
+} __packed;
struct iwm_udma_out_wifi_hdr {
__le32 cmd;
__le32 meta_data;
-} __attribute__ ((packed));
+} __packed;
/* Sequence numbering */
#define UMAC_WIFI_SEQ_NUM_BASE 1
@@ -408,12 +408,12 @@ struct iwm_rx_ticket {
__le16 flags;
u8 payload_offset; /* includes: MAC header, pad, IV */
u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */
-} __attribute__ ((packed));
+} __packed;
struct iwm_rx_mpdu_hdr {
__le16 len;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/* UMAC SW WIFI API */
@@ -421,31 +421,31 @@ struct iwm_dev_cmd_hdr {
u8 cmd;
u8 flags;
__le16 seq_num;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_fw_cmd_hdr {
__le32 meta_data;
struct iwm_dev_cmd_hdr cmd;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_wifi_out_hdr {
struct iwm_udma_out_wifi_hdr hw_hdr;
struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_nonwifi_out_hdr {
struct iwm_udma_out_nonwifi_hdr hw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_wifi_in_hdr {
struct iwm_udma_in_hdr hw_hdr;
struct iwm_umac_fw_cmd_hdr sw_hdr;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_nonwifi_in_hdr {
struct iwm_udma_in_hdr hw_hdr;
__le32 time_stamp;
-} __attribute__ ((packed));
+} __packed;
#define IWM_UMAC_PAGE_SIZE 0x200
@@ -521,7 +521,7 @@ struct iwm_umac_notif_wifi_if {
u8 status;
u8 flags;
__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1
#define UMAC_ROAM_REASON_AP_DEAUTH 0x2
@@ -535,7 +535,7 @@ struct iwm_umac_notif_assoc_start {
__le32 roam_reason;
u8 bssid[ETH_ALEN];
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0
#define UMAC_ASSOC_COMPLETE_FAILURE 0x1
@@ -546,7 +546,7 @@ struct iwm_umac_notif_assoc_complete {
u8 bssid[ETH_ALEN];
u8 band;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0
#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1
@@ -556,7 +556,7 @@ struct iwm_umac_notif_assoc_complete {
struct iwm_umac_notif_profile_invalidate {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le32 reason;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_SCAN_RESULT_SUCCESS 0x0
#define UMAC_SCAN_RESULT_ABORTED 0x1
@@ -568,7 +568,7 @@ struct iwm_umac_notif_scan_complete {
__le32 type;
__le32 result;
u8 seq_num;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_OPCODE_ADD_MODIFY 0x0
#define UMAC_OPCODE_REMOVE 0x1
@@ -582,7 +582,7 @@ struct iwm_umac_notif_sta_info {
u8 mac_addr[ETH_ALEN];
u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */
u8 flags;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_BAND_2GHZ 0
#define UMAC_BAND_5GHZ 1
@@ -601,7 +601,7 @@ struct iwm_umac_notif_bss_info {
s8 rssi;
u8 reserved;
u8 frame_buf[1];
-} __attribute__ ((packed));
+} __packed;
#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff
#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00
@@ -614,13 +614,13 @@ struct iwm_umac_notif_bss_removed {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le32 count;
__le16 entries[0];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_mgt_frame {
struct iwm_umac_notif_wifi_if mlme_hdr;
__le16 len;
u8 frame[1];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_alive {
struct iwm_umac_wifi_in_hdr hdr;
@@ -630,13 +630,13 @@ struct iwm_umac_notif_alive {
__le16 reserved2;
__le16 page_grp_count;
__le32 page_grp_state[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_init_complete {
struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
/* error categories */
enum {
@@ -667,12 +667,12 @@ struct iwm_fw_error_hdr {
__le32 dbm_buf_end;
__le32 dbm_buf_write_ptr;
__le32 dbm_buf_cycle_cnt;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_error {
struct iwm_umac_wifi_in_hdr hdr;
struct iwm_fw_error_hdr err;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0
#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff
@@ -687,20 +687,20 @@ struct iwm_umac_notif_page_dealloc {
struct iwm_umac_wifi_in_hdr hdr;
__le32 changes;
__le32 grp_info[IWM_MACS_OUT_GROUPS];
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_wifi_status {
struct iwm_umac_wifi_in_hdr hdr;
__le16 status;
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct iwm_umac_notif_rx_ticket {
struct iwm_umac_wifi_in_hdr hdr;
u8 num_tickets;
u8 reserved[3];
struct iwm_rx_ticket tickets[1];
-} __attribute__ ((packed));
+} __packed;
/* Tx/Rx rates window (number of max of last update window per second) */
#define UMAC_NTF_RATE_SAMPLE_NR 4
@@ -758,7 +758,7 @@ struct iwm_umac_notif_stats {
__le32 roam_unassoc;
__le32 roam_deauth;
__le32 roam_ap_loadblance;
-} __attribute__ ((packed));
+} __packed;
#define UMAC_STOP_TX_FLAG 0x1
#define UMAC_RESUME_TX_FLAG 0x2
@@ -770,7 +770,7 @@ struct iwm_umac_notif_stop_resume_tx {
u8 flags; /* UMAC_*_TX_FLAG_* */
u8 sta_id;
__le16 stop_resume_tid_msk; /* tid bitmask */
-} __attribute__ ((packed));
+} __packed;
#define UMAC_MAX_NUM_PMKIDS 4
@@ -779,7 +779,7 @@ struct iwm_umac_wifi_if {
u8 oid;
u8 flags;
__le16 buf_size;
-} __attribute__ ((packed));
+} __packed;
#define IWM_SEQ_NUM_HOST_MSK 0x0000
#define IWM_SEQ_NUM_UMAC_MSK 0x4000
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index cdb9b9650d73..0fa6b0e59ea5 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -70,6 +70,8 @@ static u8 is_command_allowed_in_ps(u16 cmd)
switch (cmd) {
case CMD_802_11_RSSI:
return 1;
+ case CMD_802_11_HOST_SLEEP_CFG:
+ return 1;
default:
break;
}
@@ -185,6 +187,23 @@ out:
return ret;
}
+static int lbs_ret_host_sleep_cfg(struct lbs_private *priv, unsigned long dummy,
+ struct cmd_header *resp)
+{
+ lbs_deb_enter(LBS_DEB_CMD);
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ priv->is_host_sleep_configured = 0;
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+ } else {
+ priv->is_host_sleep_configured = 1;
+ }
+ lbs_deb_leave(LBS_DEB_CMD);
+ return 0;
+}
+
int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
struct wol_config *p_wol_config)
{
@@ -202,12 +221,11 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria,
else
cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE;
- ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config);
+ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config.hdr,
+ le16_to_cpu(cmd_config.hdr.size),
+ lbs_ret_host_sleep_cfg, 0);
if (!ret) {
- if (criteria) {
- lbs_deb_cmd("Set WOL criteria to %x\n", criteria);
- priv->wol_criteria = criteria;
- } else
+ if (p_wol_config)
memcpy((uint8_t *) p_wol_config,
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
@@ -712,6 +730,10 @@ static void lbs_queue_cmd(struct lbs_private *priv,
}
}
+ if (le16_to_cpu(cmdnode->cmdbuf->command) ==
+ CMD_802_11_WAKEUP_CONFIRM)
+ addtail = 0;
+
spin_lock_irqsave(&priv->driver_lock, flags);
if (addtail)
@@ -1353,6 +1375,11 @@ static void lbs_send_confirmsleep(struct lbs_private *priv)
/* We don't get a response on the sleep-confirmation */
priv->dnld_sent = DNLD_RES_RECEIVED;
+ if (priv->is_host_sleep_configured) {
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
+ }
+
/* If nothing to do, go back to sleep (?) */
if (!kfifo_len(&priv->event_fifo) && !priv->resp_len[priv->resp_idx])
priv->psstate = PS_STATE_SLEEP;
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 88f7131d66e9..d6c306353640 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -17,6 +17,7 @@
#include "dev.h"
#include "assoc.h"
#include "wext.h"
+#include "cmd.h"
/**
* @brief This function handles disconnect event. it
@@ -341,32 +342,10 @@ done:
return ret;
}
-static int lbs_send_confirmwake(struct lbs_private *priv)
-{
- struct cmd_header cmd;
- int ret = 0;
-
- lbs_deb_enter(LBS_DEB_HOST);
-
- cmd.command = cpu_to_le16(CMD_802_11_WAKEUP_CONFIRM);
- cmd.size = cpu_to_le16(sizeof(cmd));
- cmd.seqnum = cpu_to_le16(++priv->seqnum);
- cmd.result = 0;
-
- lbs_deb_hex(LBS_DEB_HOST, "wake confirm", (u8 *) &cmd,
- sizeof(cmd));
-
- ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &cmd, sizeof(cmd));
- if (ret)
- lbs_pr_alert("SEND_WAKEC_CMD: Host to Card failed for Confirm Wake\n");
-
- lbs_deb_leave_args(LBS_DEB_HOST, "ret %d", ret);
- return ret;
-}
-
int lbs_process_event(struct lbs_private *priv, u32 event)
{
int ret = 0;
+ struct cmd_header cmd;
lbs_deb_enter(LBS_DEB_CMD);
@@ -410,7 +389,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
if (priv->reset_deep_sleep_wakeup)
priv->reset_deep_sleep_wakeup(priv);
priv->is_deep_sleep = 0;
- lbs_send_confirmwake(priv);
+ lbs_cmd_async(priv, CMD_802_11_WAKEUP_CONFIRM, &cmd,
+ sizeof(cmd));
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
break;
case MACREG_INT_CODE_DEEP_SLEEP_AWAKE:
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 709ffcad22ad..61db8bc62b3c 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -38,7 +38,7 @@ int lbs_set_mac_address(struct net_device *dev, void *addr);
void lbs_set_multicast_list(struct net_device *dev);
int lbs_suspend(struct lbs_private *priv);
-void lbs_resume(struct lbs_private *priv);
+int lbs_resume(struct lbs_private *priv);
void lbs_queue_event(struct lbs_private *priv, u32 event);
void lbs_notify_command_response(struct lbs_private *priv, u8 resp_idx);
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index a54880e4ad2b..71c5ad46ebf6 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -75,6 +75,7 @@ struct lbs_private {
/* Deep sleep */
int is_deep_sleep;
+ int deep_sleep_required;
int is_auto_deep_sleep_enabled;
int wakeup_dev_required;
int is_activity_detected;
@@ -82,6 +83,11 @@ struct lbs_private {
wait_queue_head_t ds_awake_q;
struct timer_list auto_deepsleep_timer;
+ /* Host sleep*/
+ int is_host_sleep_configured;
+ int is_host_sleep_activated;
+ wait_queue_head_t host_sleep_q;
+
/* Hardware access */
void *card;
u8 fw_ready;
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c
index 3804a58d7f4e..6a36c9956fdc 100644
--- a/drivers/net/wireless/libertas/ethtool.c
+++ b/drivers/net/wireless/libertas/ethtool.c
@@ -91,23 +91,22 @@ static int lbs_ethtool_set_wol(struct net_device *dev,
struct ethtool_wolinfo *wol)
{
struct lbs_private *priv = dev->ml_priv;
- uint32_t criteria = 0;
if (wol->wolopts & ~(WAKE_UCAST|WAKE_MCAST|WAKE_BCAST|WAKE_PHY))
return -EOPNOTSUPP;
+ priv->wol_criteria = 0;
if (wol->wolopts & WAKE_UCAST)
- criteria |= EHS_WAKE_ON_UNICAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_UNICAST_DATA;
if (wol->wolopts & WAKE_MCAST)
- criteria |= EHS_WAKE_ON_MULTICAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_MULTICAST_DATA;
if (wol->wolopts & WAKE_BCAST)
- criteria |= EHS_WAKE_ON_BROADCAST_DATA;
+ priv->wol_criteria |= EHS_WAKE_ON_BROADCAST_DATA;
if (wol->wolopts & WAKE_PHY)
- criteria |= EHS_WAKE_ON_MAC_EVENT;
+ priv->wol_criteria |= EHS_WAKE_ON_MAC_EVENT;
if (wol->wolopts == 0)
- criteria |= EHS_REMOVE_WAKEUP;
-
- return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
+ priv->wol_criteria |= EHS_REMOVE_WAKEUP;
+ return 0;
}
const struct ethtool_ops lbs_ethtool_ops = {
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index 3809c0b49464..3bd5d3b6037a 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -326,7 +326,7 @@ struct txpd {
u8 pktdelay_2ms;
/* reserved */
u8 reserved1;
-} __attribute__ ((packed));
+} __packed;
/* RxPD Descriptor */
struct rxpd {
@@ -339,8 +339,8 @@ struct rxpd {
u8 bss_type;
/* BSS number */
u8 bss_num;
- } __attribute__ ((packed)) bss;
- } __attribute__ ((packed)) u;
+ } __packed bss;
+ } __packed u;
/* SNR */
u8 snr;
@@ -366,14 +366,14 @@ struct rxpd {
/* Pkt Priority */
u8 priority;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_header {
__le16 command;
__le16 size;
__le16 seqnum;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
/* Generic structure to hold all key types. */
struct enc_key {
@@ -387,7 +387,7 @@ struct enc_key {
struct lbs_offset_value {
u32 offset;
u32 value;
-} __attribute__ ((packed));
+} __packed;
/*
* Define data structure for CMD_GET_HW_SPEC
@@ -426,7 +426,7 @@ struct cmd_ds_get_hw_spec {
/*FW/HW capability */
__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_subscribe_event {
struct cmd_header hdr;
@@ -440,7 +440,7 @@ struct cmd_ds_802_11_subscribe_event {
* bump this up a bit.
*/
uint8_t tlv[128];
-} __attribute__ ((packed));
+} __packed;
/*
* This scan handle Country Information IE(802.11d compliant)
@@ -452,7 +452,7 @@ struct cmd_ds_802_11_scan {
uint8_t bsstype;
uint8_t bssid[ETH_ALEN];
uint8_t tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_scan_rsp {
struct cmd_header hdr;
@@ -460,7 +460,7 @@ struct cmd_ds_802_11_scan_rsp {
__le16 bssdescriptsize;
uint8_t nr_sets;
uint8_t bssdesc_and_tlvbuffer[0];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_get_log {
struct cmd_header hdr;
@@ -478,20 +478,20 @@ struct cmd_ds_802_11_get_log {
__le32 fcserror;
__le32 txframe;
__le32 wepundecryptable;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_control {
struct cmd_header hdr;
__le16 action;
u16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_multicast_adr {
struct cmd_header hdr;
__le16 action;
__le16 nr_of_adrs;
u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_authenticate {
struct cmd_header hdr;
@@ -499,14 +499,14 @@ struct cmd_ds_802_11_authenticate {
u8 bssid[ETH_ALEN];
u8 authtype;
u8 reserved[10];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_deauthenticate {
struct cmd_header hdr;
u8 macaddr[ETH_ALEN];
__le16 reasoncode;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_associate {
struct cmd_header hdr;
@@ -517,7 +517,7 @@ struct cmd_ds_802_11_associate {
__le16 bcnperiod;
u8 dtimperiod;
u8 iebuf[512]; /* Enough for required and most optional IEs */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_associate_response {
struct cmd_header hdr;
@@ -526,7 +526,7 @@ struct cmd_ds_802_11_associate_response {
__le16 statuscode;
__le16 aid;
u8 iebuf[512];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_set_wep {
struct cmd_header hdr;
@@ -540,7 +540,7 @@ struct cmd_ds_802_11_set_wep {
/* 40, 128bit or TXWEP */
uint8_t keytype[4];
uint8_t keymaterial[4][16];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_snmp_mib {
struct cmd_header hdr;
@@ -549,40 +549,40 @@ struct cmd_ds_802_11_snmp_mib {
__le16 oid;
__le16 bufsize;
u8 value[128];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_reg_access {
__le16 action;
__le16 offset;
__le32 value;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_bbp_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_rf_reg_access {
__le16 action;
__le16 offset;
u8 value;
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_radio_control {
struct cmd_header hdr;
__le16 action;
__le16 control;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_beacon_control {
__le16 action;
__le16 beacon_enable;
__le16 beacon_period;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_sleep_params {
struct cmd_header hdr;
@@ -607,7 +607,7 @@ struct cmd_ds_802_11_sleep_params {
/* reserved field, should be set to zero */
__le16 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rf_channel {
struct cmd_header hdr;
@@ -617,7 +617,7 @@ struct cmd_ds_802_11_rf_channel {
__le16 rftype; /* unused */
__le16 reserved; /* unused */
u8 channellist[32]; /* unused */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rssi {
/* weighting factor */
@@ -626,21 +626,21 @@ struct cmd_ds_802_11_rssi {
__le16 reserved_0;
__le16 reserved_1;
__le16 reserved_2;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rssi_rsp {
__le16 SNR;
__le16 noisefloor;
__le16 avgSNR;
__le16 avgnoisefloor;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_mac_address {
struct cmd_header hdr;
__le16 action;
u8 macadd[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rf_tx_power {
struct cmd_header hdr;
@@ -649,26 +649,26 @@ struct cmd_ds_802_11_rf_tx_power {
__le16 curlevel;
s8 maxlevel;
s8 minlevel;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_monitor_mode {
__le16 action;
__le16 mode;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_set_boot2_ver {
struct cmd_header hdr;
__le16 action;
__le16 version;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_fw_wake_method {
struct cmd_header hdr;
__le16 action;
__le16 method;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ps_mode {
__le16 action;
@@ -676,7 +676,7 @@ struct cmd_ds_802_11_ps_mode {
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
-} __attribute__ ((packed));
+} __packed;
struct cmd_confirm_sleep {
struct cmd_header hdr;
@@ -686,7 +686,7 @@ struct cmd_confirm_sleep {
__le16 multipledtim;
__le16 reserved;
__le16 locallisteninterval;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_data_rate {
struct cmd_header hdr;
@@ -694,14 +694,14 @@ struct cmd_ds_802_11_data_rate {
__le16 action;
__le16 reserved;
u8 rates[MAX_RATES];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_rate_adapt_rateset {
struct cmd_header hdr;
__le16 action;
__le16 enablehwauto;
__le16 bitmap;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_start {
struct cmd_header hdr;
@@ -718,14 +718,14 @@ struct cmd_ds_802_11_ad_hoc_start {
__le16 capability;
u8 rates[MAX_RATES];
u8 tlv_memory_size_pad[100];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_result {
struct cmd_header hdr;
u8 pad[3];
u8 bssid[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct adhoc_bssdesc {
u8 bssid[ETH_ALEN];
@@ -746,7 +746,7 @@ struct adhoc_bssdesc {
* Adhoc join command and will cause a binary layout mismatch with
* the firmware
*/
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_join {
struct cmd_header hdr;
@@ -754,18 +754,18 @@ struct cmd_ds_802_11_ad_hoc_join {
struct adhoc_bssdesc bss;
__le16 failtimeout; /* Reserved on v9 and later */
__le16 probedelay; /* Reserved on v9 and later */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_ad_hoc_stop {
struct cmd_header hdr;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_enable_rsn {
struct cmd_header hdr;
__le16 action;
__le16 enable;
-} __attribute__ ((packed));
+} __packed;
struct MrvlIEtype_keyParamSet {
/* type ID */
@@ -785,7 +785,7 @@ struct MrvlIEtype_keyParamSet {
/* key material of size keylen */
u8 key[32];
-} __attribute__ ((packed));
+} __packed;
#define MAX_WOL_RULES 16
@@ -797,7 +797,7 @@ struct host_wol_rule {
__le16 reserve;
__be32 sig_mask;
__be32 signature;
-} __attribute__ ((packed));
+} __packed;
struct wol_config {
uint8_t action;
@@ -805,7 +805,7 @@ struct wol_config {
uint8_t no_rules_in_cmd;
uint8_t result;
struct host_wol_rule rule[MAX_WOL_RULES];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_host_sleep {
struct cmd_header hdr;
@@ -813,7 +813,7 @@ struct cmd_ds_host_sleep {
uint8_t gpio;
uint16_t gap;
struct wol_config wol_conf;
-} __attribute__ ((packed));
+} __packed;
@@ -822,7 +822,7 @@ struct cmd_ds_802_11_key_material {
__le16 action;
struct MrvlIEtype_keyParamSet keyParamSet[2];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_eeprom_access {
struct cmd_header hdr;
@@ -832,7 +832,7 @@ struct cmd_ds_802_11_eeprom_access {
/* firmware says it returns a maximum of 20 bytes */
#define LBS_EEPROM_READ_LEN 20
u8 value[LBS_EEPROM_READ_LEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_tpc_cfg {
struct cmd_header hdr;
@@ -843,7 +843,7 @@ struct cmd_ds_802_11_tpc_cfg {
int8_t P1;
int8_t P2;
uint8_t usesnr;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_pa_cfg {
@@ -854,14 +854,14 @@ struct cmd_ds_802_11_pa_cfg {
int8_t P0;
int8_t P1;
int8_t P2;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_led_ctrl {
__le16 action;
__le16 numled;
u8 data[256];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_802_11_afc {
__le16 afc_auto;
@@ -875,22 +875,22 @@ struct cmd_ds_802_11_afc {
__le16 carrier_offset; /* signed */
};
};
-} __attribute__ ((packed));
+} __packed;
struct cmd_tx_rate_query {
__le16 txrate;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_get_tsf {
__le64 tsfvalue;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_bt_access {
__le16 action;
__le32 id;
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_fwt_access {
__le16 action;
@@ -910,7 +910,7 @@ struct cmd_ds_fwt_access {
__le32 snr;
__le32 references;
u8 prec[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mesh_config {
struct cmd_header hdr;
@@ -920,14 +920,14 @@ struct cmd_ds_mesh_config {
__le16 type;
__le16 length;
u8 data[128]; /* last position reserved */
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mesh_access {
struct cmd_header hdr;
__le16 action;
__le32 data[32]; /* last position reserved */
-} __attribute__ ((packed));
+} __packed;
/* Number of stats counters returned by the firmware */
#define MESH_STATS_NUM 8
@@ -957,6 +957,6 @@ struct cmd_ds_command {
struct cmd_ds_fwt_access fwt;
struct cmd_ds_802_11_beacon_control bcn_ctrl;
} params;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index 64dd345d30f5..ba854c70ab94 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -125,6 +125,8 @@ struct if_sdio_card {
const char *helper;
const char *firmware;
+ bool helper_allocated;
+ bool firmware_allocated;
u8 buffer[65536];
@@ -984,16 +986,34 @@ static int if_sdio_probe(struct sdio_func *func,
card->helper = if_sdio_models[i].helper;
card->firmware = if_sdio_models[i].firmware;
+ kparam_block_sysfs_write(helper_name);
if (lbs_helper_name) {
+ char *helper = kstrdup(lbs_helper_name, GFP_KERNEL);
+ if (!helper) {
+ kparam_unblock_sysfs_write(helper_name);
+ ret = -ENOMEM;
+ goto free;
+ }
lbs_deb_sdio("overriding helper firmware: %s\n",
lbs_helper_name);
- card->helper = lbs_helper_name;
+ card->helper = helper;
+ card->helper_allocated = true;
}
+ kparam_unblock_sysfs_write(helper_name);
+ kparam_block_sysfs_write(fw_name);
if (lbs_fw_name) {
+ char *fw_name = kstrdup(lbs_fw_name, GFP_KERNEL);
+ if (!fw_name) {
+ kparam_unblock_sysfs_write(fw_name);
+ ret = -ENOMEM;
+ goto free;
+ }
lbs_deb_sdio("overriding firmware: %s\n", lbs_fw_name);
- card->firmware = lbs_fw_name;
+ card->firmware = fw_name;
+ card->firmware_allocated = true;
}
+ kparam_unblock_sysfs_write(fw_name);
sdio_claim_host(func);
@@ -1127,6 +1147,10 @@ free:
kfree(packet);
}
+ if (card->helper_allocated)
+ kfree(card->helper);
+ if (card->firmware_allocated)
+ kfree(card->firmware);
kfree(card);
goto out;
@@ -1177,16 +1201,78 @@ static void if_sdio_remove(struct sdio_func *func)
kfree(packet);
}
+ if (card->helper_allocated)
+ kfree(card->helper);
+ if (card->firmware_allocated)
+ kfree(card->firmware);
kfree(card);
lbs_deb_leave(LBS_DEB_SDIO);
}
+static int if_sdio_suspend(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ int ret;
+ struct if_sdio_card *card = sdio_get_drvdata(func);
+
+ mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
+
+ lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
+ sdio_func_id(func), flags);
+
+ /* If we aren't being asked to wake on anything, we should bail out
+ * and let the SD stack power down the card.
+ */
+ if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ lbs_pr_info("Suspend without wake params -- "
+ "powering down card.");
+ return -ENOSYS;
+ }
+
+ if (!(flags & MMC_PM_KEEP_POWER)) {
+ lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+ sdio_func_id(func));
+ return -ENOSYS;
+ }
+
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret)
+ return ret;
+
+ ret = lbs_suspend(card->priv);
+ if (ret)
+ return ret;
+
+ return sdio_set_host_pm_flags(func, MMC_PM_WAKE_SDIO_IRQ);
+}
+
+static int if_sdio_resume(struct device *dev)
+{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct if_sdio_card *card = sdio_get_drvdata(func);
+ int ret;
+
+ lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
+
+ ret = lbs_resume(card->priv);
+
+ return ret;
+}
+
+static const struct dev_pm_ops if_sdio_pm_ops = {
+ .suspend = if_sdio_suspend,
+ .resume = if_sdio_resume,
+};
+
static struct sdio_driver if_sdio_driver = {
.name = "libertas_sdio",
.id_table = if_sdio_ids,
.probe = if_sdio_probe,
.remove = if_sdio_remove,
+ .drv = {
+ .pm = &if_sdio_pm_ops,
+ },
};
/*******************************************************************/
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index f41594c7ac16..6fc9219cd5bf 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -289,10 +289,13 @@ static int if_usb_probe(struct usb_interface *intf,
}
/* Upload firmware */
+ kparam_block_sysfs_write(fw_name);
if (__if_usb_prog_firmware(cardp, lbs_fw_name, BOOT_CMD_FW_BY_USB)) {
+ kparam_unblock_sysfs_write(fw_name);
lbs_deb_usbd(&udev->dev, "FW upload failed\n");
goto err_prog_firmware;
}
+ kparam_unblock_sysfs_write(fw_name);
if (!(priv = lbs_add_card(cardp, &udev->dev)))
goto err_prog_firmware;
@@ -613,16 +616,14 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ syncfwheader = kmemdup(skb->data + IPFIELD_ALIGN_OFFSET,
+ sizeof(struct fwsyncheader), GFP_ATOMIC);
if (!syncfwheader) {
lbs_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
kfree_skb(skb);
return;
}
- memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET,
- sizeof(struct fwsyncheader));
-
if (!syncfwheader->cmd) {
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbs_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
@@ -1043,6 +1044,12 @@ static int if_usb_suspend(struct usb_interface *intf, pm_message_t message)
if (priv->psstate != PS_STATE_FULL_POWER)
return -1;
+ if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
+ lbs_pr_info("Suspend attempt without "
+ "configuring wake params!\n");
+ return -ENOSYS;
+ }
+
ret = lbs_suspend(priv);
if (ret)
goto out;
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index d9b8ee130c45..abfecc4814b4 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -625,16 +625,13 @@ static int lbs_thread(void *data)
return 0;
}
-static int lbs_suspend_callback(struct lbs_private *priv, unsigned long dummy,
- struct cmd_header *cmd)
+static int lbs_ret_host_sleep_activate(struct lbs_private *priv,
+ unsigned long dummy,
+ struct cmd_header *cmd)
{
lbs_deb_enter(LBS_DEB_FW);
-
- netif_device_detach(priv->dev);
- if (priv->mesh_dev)
- netif_device_detach(priv->mesh_dev);
-
- priv->fw_ready = 0;
+ priv->is_host_sleep_activated = 1;
+ wake_up_interruptible(&priv->host_sleep_q);
lbs_deb_leave(LBS_DEB_FW);
return 0;
}
@@ -646,39 +643,65 @@ int lbs_suspend(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_FW);
- if (priv->wol_criteria == 0xffffffff) {
- lbs_pr_info("Suspend attempt without configuring wake params!\n");
- return -EINVAL;
+ if (priv->is_deep_sleep) {
+ ret = lbs_set_deep_sleep(priv, 0);
+ if (ret) {
+ lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ return ret;
+ }
+ priv->deep_sleep_required = 1;
}
memset(&cmd, 0, sizeof(cmd));
+ ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
+ (struct wol_config *)NULL);
+ if (ret) {
+ lbs_pr_info("Host sleep configuration failed: %d\n", ret);
+ return ret;
+ }
+ if (priv->psstate == PS_STATE_FULL_POWER) {
+ ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
+ sizeof(cmd), lbs_ret_host_sleep_activate, 0);
+ if (ret)
+ lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+ }
- ret = __lbs_cmd(priv, CMD_802_11_HOST_SLEEP_ACTIVATE, &cmd,
- sizeof(cmd), lbs_suspend_callback, 0);
- if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE failed: %d\n", ret);
+ if (!wait_event_interruptible_timeout(priv->host_sleep_q,
+ priv->is_host_sleep_activated, (10 * HZ))) {
+ lbs_pr_err("host_sleep_q: timer expired\n");
+ ret = -1;
+ }
+ netif_device_detach(priv->dev);
+ if (priv->mesh_dev)
+ netif_device_detach(priv->mesh_dev);
lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
return ret;
}
EXPORT_SYMBOL_GPL(lbs_suspend);
-void lbs_resume(struct lbs_private *priv)
+int lbs_resume(struct lbs_private *priv)
{
- lbs_deb_enter(LBS_DEB_FW);
+ int ret;
+ uint32_t criteria = EHS_REMOVE_WAKEUP;
- priv->fw_ready = 1;
+ lbs_deb_enter(LBS_DEB_FW);
- /* Firmware doesn't seem to give us RX packets any more
- until we send it some command. Might as well update */
- lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0,
- 0, 0, NULL);
+ ret = lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL);
netif_device_attach(priv->dev);
if (priv->mesh_dev)
netif_device_attach(priv->mesh_dev);
- lbs_deb_leave(LBS_DEB_FW);
+ if (priv->deep_sleep_required) {
+ priv->deep_sleep_required = 0;
+ ret = lbs_set_deep_sleep(priv, 1);
+ if (ret)
+ lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ }
+
+ lbs_deb_leave_args(LBS_DEB_FW, "ret %d", ret);
+ return ret;
}
EXPORT_SYMBOL_GPL(lbs_resume);
@@ -834,10 +857,13 @@ static int lbs_init_adapter(struct lbs_private *priv)
priv->psstate = PS_STATE_FULL_POWER;
priv->is_deep_sleep = 0;
priv->is_auto_deep_sleep_enabled = 0;
+ priv->deep_sleep_required = 0;
priv->wakeup_dev_required = 0;
init_waitqueue_head(&priv->ds_awake_q);
priv->authtype_auto = 1;
-
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ init_waitqueue_head(&priv->host_sleep_q);
mutex_init(&priv->lock);
setup_timer(&priv->command_timer, lbs_cmd_timeout_handler,
@@ -976,6 +1002,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
priv->wol_criteria = 0xffffffff;
priv->wol_gpio = 0xff;
+ priv->wol_gap = 20;
goto done;
@@ -1031,6 +1058,10 @@ void lbs_remove_card(struct lbs_private *priv)
wake_up_interruptible(&priv->ds_awake_q);
}
+ priv->is_host_sleep_configured = 0;
+ priv->is_host_sleep_activated = 0;
+ wake_up_interruptible(&priv->host_sleep_q);
+
/* Stop the thread servicing the interrupts */
priv->surpriseremoved = 1;
kthread_stop(priv->main_thread);
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h
index d16b26416e82..b3c8ea6d610e 100644
--- a/drivers/net/wireless/libertas/radiotap.h
+++ b/drivers/net/wireless/libertas/radiotap.h
@@ -6,7 +6,7 @@ struct tx_radiotap_hdr {
u8 txpower;
u8 rts_retries;
u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
#define TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_RATE) | \
@@ -34,7 +34,7 @@ struct rx_radiotap_hdr {
u8 flags;
u8 rate;
u8 antsignal;
-} __attribute__ ((packed));
+} __packed;
#define RX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a115bfa9513a..1c63f8ce7349 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -15,7 +15,7 @@ struct eth803hdr {
u8 dest_addr[6];
u8 src_addr[6];
u16 h803_len;
-} __attribute__ ((packed));
+} __packed;
struct rfc1042hdr {
u8 llc_dsap;
@@ -23,17 +23,17 @@ struct rfc1042hdr {
u8 llc_ctrl;
u8 snap_oui[3];
u16 snap_type;
-} __attribute__ ((packed));
+} __packed;
struct rxpackethdr {
struct eth803hdr eth803_hdr;
struct rfc1042hdr rfc1042_hdr;
-} __attribute__ ((packed));
+} __packed;
struct rx80211packethdr {
struct rxpd rx_pd;
void *eth80211_hdr;
-} __attribute__ ((packed));
+} __packed;
static int process_rxed_802_11_packet(struct lbs_private *priv,
struct sk_buff *skb);
@@ -329,9 +329,8 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
/* create the exported radio header */
/* radiotap header */
- radiotap_hdr.hdr.it_version = 0;
- /* XXX must check this value for pad */
- radiotap_hdr.hdr.it_pad = 0;
+ memset(&radiotap_hdr, 0, sizeof(radiotap_hdr));
+ /* XXX must check radiotap_hdr.hdr.it_pad for pad */
radiotap_hdr.hdr.it_len = cpu_to_le16 (sizeof(struct rx_radiotap_hdr));
radiotap_hdr.hdr.it_present = cpu_to_le32 (RX_RADIOTAP_PRESENT);
radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 24cd54b3a806..7d82f13bdf1d 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -666,7 +666,7 @@ void lbs_scan_worker(struct work_struct *work)
/**
* @brief Interpret a BSS scan response returned from the firmware
*
- * Parse the various fixed fields and IEs passed back for a a BSS probe
+ * Parse the various fixed fields and IEs passed back for a BSS probe
* response or beacon from the scan command. Record information as needed
* in the scan table struct bss_descriptor for that entry.
*
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h
index 3e72c86ceca8..462fbb4cb743 100644
--- a/drivers/net/wireless/libertas/types.h
+++ b/drivers/net/wireless/libertas/types.h
@@ -11,7 +11,7 @@
struct ieee_ie_header {
u8 id;
u8 len;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_cf_param_set {
struct ieee_ie_header header;
@@ -20,19 +20,19 @@ struct ieee_ie_cf_param_set {
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_ibss_param_set {
struct ieee_ie_header header;
__le16 atimwindow;
-} __attribute__ ((packed));
+} __packed;
union ieee_ss_param_set {
struct ieee_ie_cf_param_set cf;
struct ieee_ie_ibss_param_set ibss;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_fh_param_set {
struct ieee_ie_header header;
@@ -41,18 +41,18 @@ struct ieee_ie_fh_param_set {
u8 hopset;
u8 hoppattern;
u8 hopindex;
-} __attribute__ ((packed));
+} __packed;
struct ieee_ie_ds_param_set {
struct ieee_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
union ieee_phy_param_set {
struct ieee_ie_fh_param_set fh;
struct ieee_ie_ds_param_set ds;
-} __attribute__ ((packed));
+} __packed;
/** TLV type ID definition */
#define PROPRIETARY_TLV_BASE_ID 0x0100
@@ -100,28 +100,28 @@ union ieee_phy_param_set {
struct mrvl_ie_header {
__le16 type;
__le16 len;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_data {
struct mrvl_ie_header header;
u8 Data[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_rates_param_set {
struct mrvl_ie_header header;
u8 rates[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ssid_param_set {
struct mrvl_ie_header header;
u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_wildcard_ssid_param_set {
struct mrvl_ie_header header;
u8 MaxSsidlength;
u8 ssid[1];
-} __attribute__ ((packed));
+} __packed;
struct chanscanmode {
#ifdef __BIG_ENDIAN_BITFIELD
@@ -133,7 +133,7 @@ struct chanscanmode {
u8 disablechanfilt:1;
u8 reserved_2_7:6;
#endif
-} __attribute__ ((packed));
+} __packed;
struct chanscanparamset {
u8 radiotype;
@@ -141,12 +141,12 @@ struct chanscanparamset {
struct chanscanmode chanscanmode;
__le16 minscantime;
__le16 maxscantime;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_chanlist_param_set {
struct mrvl_ie_header header;
struct chanscanparamset chanscanparam[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_cf_param_set {
struct mrvl_ie_header header;
@@ -154,86 +154,86 @@ struct mrvl_ie_cf_param_set {
u8 cfpperiod;
__le16 cfpmaxduration;
__le16 cfpdurationremaining;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ds_param_set {
struct mrvl_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_rsn_param_set {
struct mrvl_ie_header header;
u8 rsnie[1];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_tsf_timestamp {
struct mrvl_ie_header header;
__le64 tsftable[1];
-} __attribute__ ((packed));
+} __packed;
/* v9 and later firmware only */
struct mrvl_ie_auth_type {
struct mrvl_ie_header header;
__le16 auth;
-} __attribute__ ((packed));
+} __packed;
/** Local Power capability */
struct mrvl_ie_power_capability {
struct mrvl_ie_header header;
s8 minpower;
s8 maxpower;
-} __attribute__ ((packed));
+} __packed;
/* used in CMD_802_11_SUBSCRIBE_EVENT for SNR, RSSI and Failure */
struct mrvl_ie_thresholds {
struct mrvl_ie_header header;
u8 value;
u8 freq;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_beacons_missed {
struct mrvl_ie_header header;
u8 beaconmissed;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_num_probes {
struct mrvl_ie_header header;
__le16 numprobes;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_bcast_probe {
struct mrvl_ie_header header;
__le16 bcastprobe;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_num_ssid_probe {
struct mrvl_ie_header header;
__le16 numssidprobe;
-} __attribute__ ((packed));
+} __packed;
struct led_pin {
u8 led;
u8 pin;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ledgpio {
struct mrvl_ie_header header;
struct led_pin ledpin[1];
-} __attribute__ ((packed));
+} __packed;
struct led_bhv {
uint8_t firmwarestate;
uint8_t led;
uint8_t ledstate;
uint8_t ledarg;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_ie_ledbhv {
struct mrvl_ie_header header;
struct led_bhv ledbhv[1];
-} __attribute__ ((packed));
+} __packed;
/* Meant to be packed as the value member of a struct ieee80211_info_element.
* Note that the len member of the ieee80211_info_element varies depending on
@@ -248,12 +248,12 @@ struct mrvl_meshie_val {
uint8_t mesh_capability;
uint8_t mesh_id_len;
uint8_t mesh_id[IEEE80211_MAX_SSID_LEN];
-} __attribute__ ((packed));
+} __packed;
struct mrvl_meshie {
u8 id, len;
struct mrvl_meshie_val val;
-} __attribute__ ((packed));
+} __packed;
struct mrvl_mesh_defaults {
__le32 bootflag;
@@ -261,6 +261,6 @@ struct mrvl_mesh_defaults {
uint8_t reserved;
__le16 channel;
struct mrvl_meshie meshie;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index c445500ffc61..41a4f214ade1 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -538,7 +538,8 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC);
+ syncfwheader = kmemdup(skb->data, sizeof(struct fwsyncheader),
+ GFP_ATOMIC);
if (!syncfwheader) {
lbtf_deb_usbd(&cardp->udev->dev, "Failure to allocate syncfwheader\n");
kfree_skb(skb);
@@ -546,8 +547,6 @@ static void if_usb_receive_fwload(struct urb *urb)
return;
}
- memcpy(syncfwheader, skb->data, sizeof(struct fwsyncheader));
-
if (!syncfwheader->cmd) {
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk with correct CRC\n");
lbtf_deb_usb2(&cardp->udev->dev, "FW received Blk seqnum = %d\n",
@@ -812,12 +811,15 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
lbtf_deb_enter(LBTF_DEB_USB);
+ kparam_block_sysfs_write(fw_name);
ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
if (ret < 0) {
pr_err("request_firmware() failed with %#x\n", ret);
pr_err("firmware %s not found\n", lbtf_fw_name);
+ kparam_unblock_sysfs_write(fw_name);
goto done;
}
+ kparam_unblock_sysfs_write(fw_name);
if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
goto release_fw;
diff --git a/drivers/net/wireless/libertas_tf/libertas_tf.h b/drivers/net/wireless/libertas_tf/libertas_tf.h
index fbbaaae7a1ae..737eac92ef72 100644
--- a/drivers/net/wireless/libertas_tf/libertas_tf.h
+++ b/drivers/net/wireless/libertas_tf/libertas_tf.h
@@ -316,7 +316,7 @@ struct cmd_header {
__le16 size;
__le16 seqnum;
__le16 result;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ctrl_node {
struct list_head list;
@@ -369,7 +369,7 @@ struct cmd_ds_get_hw_spec {
/*FW/HW capability */
__le32 fwcapinfo;
-} __attribute__ ((packed));
+} __packed;
struct cmd_ds_mac_control {
struct cmd_header hdr;
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 6f8cb3ee6fed..49a7dfb4809a 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -317,7 +317,7 @@ struct hwsim_radiotap_hdr {
u8 rt_rate;
__le16 rt_channel;
__le16 rt_chbitmask;
-} __attribute__ ((packed));
+} __packed;
static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 808adb909095..c019fdc131c0 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -109,7 +109,7 @@ struct mwl8k_rx_queue {
dma_addr_t rxd_dma;
struct {
struct sk_buff *skb;
- DECLARE_PCI_UNMAP_ADDR(dma)
+ DEFINE_DMA_UNMAP_ADDR(dma);
} *buf;
};
@@ -426,7 +426,7 @@ struct mwl8k_cmd_pkt {
__u8 macid;
__le16 result;
char payload[0];
-} __attribute__((packed));
+} __packed;
/*
* Firmware loading.
@@ -632,7 +632,7 @@ struct mwl8k_dma_data {
__le16 fwlen;
struct ieee80211_hdr wh;
char data[0];
-} __attribute__((packed));
+} __packed;
/* Routines to add/remove DMA header from skb. */
static inline void mwl8k_remove_dma_header(struct sk_buff *skb, __le16 qos)
@@ -711,7 +711,7 @@ struct mwl8k_rxd_8366_ap {
__u8 rx_status;
__u8 channel;
__u8 rx_ctrl;
-} __attribute__((packed));
+} __packed;
#define MWL8K_8366_AP_RATE_INFO_MCS_FORMAT 0x80
#define MWL8K_8366_AP_RATE_INFO_40MHZ 0x40
@@ -806,7 +806,7 @@ struct mwl8k_rxd_sta {
__u8 rx_ctrl;
__u8 rx_status;
__u8 pad2[2];
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_RATE_INFO_SHORTPRE 0x8000
#define MWL8K_STA_RATE_INFO_ANTSELECT(x) (((x) >> 11) & 0x3)
@@ -963,7 +963,7 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
if (rxq->tail == MWL8K_RX_DESCS)
rxq->tail = 0;
rxq->buf[rx].skb = skb;
- pci_unmap_addr_set(&rxq->buf[rx], dma, addr);
+ dma_unmap_addr_set(&rxq->buf[rx], dma, addr);
rxd = rxq->rxd + (rx * priv->rxd_ops->rxd_size);
priv->rxd_ops->rxd_refill(rxd, addr, MWL8K_RX_MAXSZ);
@@ -984,9 +984,9 @@ static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
for (i = 0; i < MWL8K_RX_DESCS; i++) {
if (rxq->buf[i].skb != NULL) {
pci_unmap_single(priv->pdev,
- pci_unmap_addr(&rxq->buf[i], dma),
+ dma_unmap_addr(&rxq->buf[i], dma),
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
- pci_unmap_addr_set(&rxq->buf[i], dma, 0);
+ dma_unmap_addr_set(&rxq->buf[i], dma, 0);
kfree_skb(rxq->buf[i].skb);
rxq->buf[i].skb = NULL;
@@ -1060,9 +1060,9 @@ static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
rxq->buf[rxq->head].skb = NULL;
pci_unmap_single(priv->pdev,
- pci_unmap_addr(&rxq->buf[rxq->head], dma),
+ dma_unmap_addr(&rxq->buf[rxq->head], dma),
MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
- pci_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
+ dma_unmap_addr_set(&rxq->buf[rxq->head], dma, 0);
rxq->head++;
if (rxq->head == MWL8K_RX_DESCS)
@@ -1120,7 +1120,7 @@ struct mwl8k_tx_desc {
__le16 rate_info;
__u8 peer_id;
__u8 tx_frag_cnt;
-} __attribute__((packed));
+} __packed;
#define MWL8K_TX_DESCS 128
@@ -1666,7 +1666,7 @@ struct mwl8k_cmd_get_hw_spec_sta {
__le32 caps2;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
#define MWL8K_CAP_MAX_AMSDU 0x20000000
#define MWL8K_CAP_GREENFIELD 0x08000000
@@ -1810,7 +1810,7 @@ struct mwl8k_cmd_get_hw_spec_ap {
__le32 wcbbase1;
__le32 wcbbase2;
__le32 wcbbase3;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_get_hw_spec_ap(struct ieee80211_hw *hw)
{
@@ -1883,7 +1883,7 @@ struct mwl8k_cmd_set_hw_spec {
__le32 flags;
__le32 num_tx_desc_per_queue;
__le32 total_rxd;
-} __attribute__((packed));
+} __packed;
#define MWL8K_SET_HW_SPEC_FLAG_HOST_DECR_MGMT 0x00000080
#define MWL8K_SET_HW_SPEC_FLAG_HOSTFORM_PROBERESP 0x00000020
@@ -1985,7 +1985,7 @@ __mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw, int allmulti,
struct mwl8k_cmd_get_stat {
struct mwl8k_cmd_pkt header;
__le32 stats[64];
-} __attribute__((packed));
+} __packed;
#define MWL8K_STAT_ACK_FAILURE 9
#define MWL8K_STAT_RTS_FAILURE 12
@@ -2029,7 +2029,7 @@ struct mwl8k_cmd_radio_control {
__le16 action;
__le16 control;
__le16 radio_on;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_radio_control(struct ieee80211_hw *hw, bool enable, bool force)
@@ -2092,7 +2092,7 @@ struct mwl8k_cmd_rf_tx_power {
__le16 current_level;
__le16 reserved;
__le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_rf_tx_power(struct ieee80211_hw *hw, int dBm)
{
@@ -2121,7 +2121,7 @@ struct mwl8k_cmd_rf_antenna {
struct mwl8k_cmd_pkt header;
__le16 antenna;
__le16 mode;
-} __attribute__((packed));
+} __packed;
#define MWL8K_RF_ANTENNA_RX 1
#define MWL8K_RF_ANTENNA_TX 2
@@ -2182,7 +2182,7 @@ static int mwl8k_cmd_set_beacon(struct ieee80211_hw *hw,
*/
struct mwl8k_cmd_set_pre_scan {
struct mwl8k_cmd_pkt header;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
{
@@ -2209,7 +2209,7 @@ struct mwl8k_cmd_set_post_scan {
struct mwl8k_cmd_pkt header;
__le32 isibss;
__u8 bssid[ETH_ALEN];
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, const __u8 *mac)
@@ -2240,7 +2240,7 @@ struct mwl8k_cmd_set_rf_channel {
__le16 action;
__u8 current_channel;
__le32 channel_flags;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
struct ieee80211_conf *conf)
@@ -2293,7 +2293,7 @@ struct mwl8k_cmd_update_set_aid {
__u8 bssid[ETH_ALEN];
__le16 protection_mode;
__u8 supp_rates[14];
-} __attribute__((packed));
+} __packed;
static void legacy_rate_mask_to_array(u8 *rates, u32 mask)
{
@@ -2364,7 +2364,7 @@ struct mwl8k_cmd_set_rate {
/* Bitmap for supported MCS codes. */
__u8 mcs_set[16];
__u8 reserved[16];
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_rate(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -2397,7 +2397,7 @@ struct mwl8k_cmd_finalize_join {
struct mwl8k_cmd_pkt header;
__le32 sleep_interval; /* Number of beacon periods to sleep */
__u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_finalize_join(struct ieee80211_hw *hw, void *frame,
int framelen, int dtim)
@@ -2436,7 +2436,7 @@ struct mwl8k_cmd_set_rts_threshold {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 threshold;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh)
@@ -2466,7 +2466,7 @@ struct mwl8k_cmd_set_slot {
struct mwl8k_cmd_pkt header;
__le16 action;
__u8 short_slot;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, bool short_slot_time)
{
@@ -2528,7 +2528,7 @@ struct mwl8k_cmd_set_edca_params {
__u8 txq;
} sta;
};
-} __attribute__((packed));
+} __packed;
#define MWL8K_SET_EDCA_CW 0x01
#define MWL8K_SET_EDCA_TXOP 0x02
@@ -2579,7 +2579,7 @@ mwl8k_cmd_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
struct mwl8k_cmd_set_wmm_mode {
struct mwl8k_cmd_pkt header;
__le16 action;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_wmm_mode(struct ieee80211_hw *hw, bool enable)
{
@@ -2612,7 +2612,7 @@ struct mwl8k_cmd_mimo_config {
__le32 action;
__u8 rx_antenna_map;
__u8 tx_antenna_map;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
{
@@ -2652,7 +2652,7 @@ struct mwl8k_cmd_use_fixed_rate_sta {
__le32 rate_type;
__le32 reserved1;
__le32 reserved2;
-} __attribute__((packed));
+} __packed;
#define MWL8K_USE_AUTO_RATE 0x0002
#define MWL8K_UCAST_RATE 0
@@ -2694,7 +2694,7 @@ struct mwl8k_cmd_use_fixed_rate_ap {
u8 multicast_rate;
u8 multicast_rate_type;
u8 management_rate;
-} __attribute__((packed));
+} __packed;
static int
mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
@@ -2724,7 +2724,7 @@ mwl8k_cmd_use_fixed_rate_ap(struct ieee80211_hw *hw, int mcast, int mgmt)
struct mwl8k_cmd_enable_sniffer {
struct mwl8k_cmd_pkt header;
__le32 action;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_enable_sniffer(struct ieee80211_hw *hw, bool enable)
{
@@ -2757,7 +2757,7 @@ struct mwl8k_cmd_set_mac_addr {
} mbss;
__u8 mac_addr[ETH_ALEN];
};
-} __attribute__((packed));
+} __packed;
#define MWL8K_MAC_TYPE_PRIMARY_CLIENT 0
#define MWL8K_MAC_TYPE_SECONDARY_CLIENT 1
@@ -2812,7 +2812,7 @@ struct mwl8k_cmd_set_rate_adapt_mode {
struct mwl8k_cmd_pkt header;
__le16 action;
__le16 mode;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
{
@@ -2840,7 +2840,7 @@ static int mwl8k_cmd_set_rateadapt_mode(struct ieee80211_hw *hw, __u16 mode)
struct mwl8k_cmd_bss_start {
struct mwl8k_cmd_pkt header;
__le32 enable;
-} __attribute__((packed));
+} __packed;
static int mwl8k_cmd_bss_start(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int enable)
@@ -2885,7 +2885,7 @@ struct mwl8k_cmd_set_new_stn {
__u8 add_qos_info;
__u8 is_qos_sta;
__le32 fw_sta_ptr;
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_ACTION_ADD 0
#define MWL8K_STA_ACTION_REMOVE 2
@@ -2978,7 +2978,7 @@ struct ewc_ht_info {
__le16 control1;
__le16 control2;
__le16 control3;
-} __attribute__((packed));
+} __packed;
struct peer_capability_info {
/* Peer type - AP vs. STA. */
@@ -3007,7 +3007,7 @@ struct peer_capability_info {
__u8 pad2;
__u8 station_id;
__le16 amsdu_enabled;
-} __attribute__((packed));
+} __packed;
struct mwl8k_cmd_update_stadb {
struct mwl8k_cmd_pkt header;
@@ -3022,7 +3022,7 @@ struct mwl8k_cmd_update_stadb {
/* Peer info - valid during add/update. */
struct peer_capability_info peer_info;
-} __attribute__((packed));
+} __packed;
#define MWL8K_STA_DB_MODIFY_ENTRY 1
#define MWL8K_STA_DB_DEL_ENTRY 2
diff --git a/drivers/net/wireless/orinoco/airport.c b/drivers/net/wireless/orinoco/airport.c
index 9bcee10c9308..4a0a0e5265c9 100644
--- a/drivers/net/wireless/orinoco/airport.c
+++ b/drivers/net/wireless/orinoco/airport.c
@@ -239,8 +239,11 @@ static struct of_device_id airport_match[] =
MODULE_DEVICE_TABLE(of, airport_match);
static struct macio_driver airport_driver = {
- .name = DRIVER_NAME,
- .match_table = airport_match,
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = airport_match,
+ },
.probe = airport_attach,
.remove = airport_detach,
.suspend = airport_suspend,
diff --git a/drivers/net/wireless/orinoco/fw.c b/drivers/net/wireless/orinoco/fw.c
index 3e1947d097ca..259d75853984 100644
--- a/drivers/net/wireless/orinoco/fw.c
+++ b/drivers/net/wireless/orinoco/fw.c
@@ -49,7 +49,7 @@ struct orinoco_fw_header {
__le32 pri_offset; /* Offset to primary plug data */
__le32 compat_offset; /* Offset to compatibility data*/
char signature[0]; /* FW signature length headersize-20 */
-} __attribute__ ((packed));
+} __packed;
/* Check the range of various header entries. Return a pointer to a
* description of the problem, or NULL if everything checks out. */
diff --git a/drivers/net/wireless/orinoco/hermes.h b/drivers/net/wireless/orinoco/hermes.h
index 9ca34e722b45..d9f18c11682a 100644
--- a/drivers/net/wireless/orinoco/hermes.h
+++ b/drivers/net/wireless/orinoco/hermes.h
@@ -205,7 +205,7 @@ struct hermes_tx_descriptor {
u8 retry_count;
u8 tx_rate;
__le16 tx_control;
-} __attribute__ ((packed));
+} __packed;
#define HERMES_TXSTAT_RETRYERR (0x0001)
#define HERMES_TXSTAT_AGEDERR (0x0002)
@@ -254,7 +254,7 @@ struct hermes_tallies_frame {
/* Those last are probably not available in very old firmwares */
__le16 RxDiscards_WEPICVError;
__le16 RxDiscards_WEPExcluded;
-} __attribute__ ((packed));
+} __packed;
/* Grabbed from wlan-ng - Thanks Mark... - Jean II
* This is the result of a scan inquiry command */
@@ -271,7 +271,7 @@ struct prism2_scan_apinfo {
u8 rates[10]; /* Bit rate supported */
__le16 proberesp_rate; /* Data rate of the response frame */
__le16 atim; /* ATIM window time, Kus (hostscan only) */
-} __attribute__ ((packed));
+} __packed;
/* Same stuff for the Lucent/Agere card.
* Thanks to h1kari <h1kari AT dachb0den.com> - Jean II */
@@ -285,7 +285,7 @@ struct agere_scan_apinfo {
/* bits: 0-ess, 1-ibss, 4-privacy [wep] */
__le16 essid_len; /* ESSID length */
u8 essid[32]; /* ESSID of the network */
-} __attribute__ ((packed));
+} __packed;
/* Moustafa: Scan structure for Symbol cards */
struct symbol_scan_apinfo {
@@ -303,7 +303,7 @@ struct symbol_scan_apinfo {
__le16 basic_rates; /* Basic rates bitmask */
u8 unknown2[6]; /* Always FF:FF:FF:FF:00:00 */
u8 unknown3[8]; /* Always 0, appeared in f/w 3.91-68 */
-} __attribute__ ((packed));
+} __packed;
union hermes_scan_info {
struct agere_scan_apinfo a;
@@ -343,7 +343,7 @@ struct agere_ext_scan_info {
__le16 beacon_interval;
__le16 capabilities;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
#define HERMES_LINKSTATUS_CONNECTED (0x0001)
@@ -355,7 +355,7 @@ struct agere_ext_scan_info {
struct hermes_linkstatus {
__le16 linkstatus; /* Link status */
-} __attribute__ ((packed));
+} __packed;
struct hermes_response {
u16 status, resp0, resp1, resp2;
@@ -365,11 +365,11 @@ struct hermes_response {
struct hermes_idstring {
__le16 len;
__le16 val[16];
-} __attribute__ ((packed));
+} __packed;
struct hermes_multicast {
u8 addr[HERMES_MAX_MULTICAST][ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
/* Timeouts */
#define HERMES_BAP_BUSY_TIMEOUT (10000) /* In iterations of ~1us */
diff --git a/drivers/net/wireless/orinoco/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c
index 6da85e75fce0..2b2b9a1a979c 100644
--- a/drivers/net/wireless/orinoco/hermes_dld.c
+++ b/drivers/net/wireless/orinoco/hermes_dld.c
@@ -65,10 +65,10 @@ struct dblock {
__le32 addr; /* adapter address where to write the block */
__le16 len; /* length of the data only, in bytes */
char data[0]; /* data to be written */
-} __attribute__ ((packed));
+} __packed;
/*
- * Plug Data References are located in in the image after the last data
+ * Plug Data References are located in the image after the last data
* block. They refer to areas in the adapter memory where the plug data
* items with matching ID should be written.
*/
@@ -77,7 +77,7 @@ struct pdr {
__le32 addr; /* adapter address where to write the data */
__le32 len; /* expected length of the data, in bytes */
char next[0]; /* next PDR starts here */
-} __attribute__ ((packed));
+} __packed;
/*
* Plug Data Items are located in the EEPROM read from the adapter by
@@ -88,7 +88,7 @@ struct pdi {
__le16 len; /* length of ID and data, in words */
__le16 id; /* record ID */
char data[0]; /* plug data */
-} __attribute__ ((packed));
+} __packed;
/*** FW data block access functions ***/
@@ -317,7 +317,7 @@ static const struct { \
__le16 len; \
__le16 id; \
u8 val[length]; \
-} __attribute__ ((packed)) default_pdr_data_##pid = { \
+} __packed default_pdr_data_##pid = { \
cpu_to_le16((sizeof(default_pdr_data_##pid)/ \
sizeof(__le16)) - 1), \
cpu_to_le16(pid), \
diff --git a/drivers/net/wireless/orinoco/hw.c b/drivers/net/wireless/orinoco/hw.c
index 6fbd78850123..077baa86756b 100644
--- a/drivers/net/wireless/orinoco/hw.c
+++ b/drivers/net/wireless/orinoco/hw.c
@@ -45,7 +45,7 @@ static const struct {
/* Firmware version encoding */
struct comp_id {
u16 id, variant, major, minor;
-} __attribute__ ((packed));
+} __packed;
static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
{
@@ -995,7 +995,7 @@ int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
u8 tx_mic[MIC_KEYLEN];
u8 rx_mic[MIC_KEYLEN];
u8 tsc[ORINOCO_SEQ_LEN];
- } __attribute__ ((packed)) buf;
+ } __packed buf;
hermes_t *hw = &priv->hw;
int ret;
int err;
@@ -1326,7 +1326,7 @@ int orinoco_hw_disassociate(struct orinoco_private *priv,
struct {
u8 addr[ETH_ALEN];
__le16 reason_code;
- } __attribute__ ((packed)) buf;
+ } __packed buf;
/* Currently only supported by WPA enabled Agere fw */
if (!priv->has_wpa)
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index ca71f08709bc..e8e2d0f4763d 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -172,7 +172,7 @@ struct hermes_txexc_data {
__le16 frame_ctl;
__le16 duration_id;
u8 addr1[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
@@ -196,7 +196,7 @@ struct hermes_rx_descriptor {
/* Data length */
__le16 data_len;
-} __attribute__ ((packed));
+} __packed;
struct orinoco_rx_data {
struct hermes_rx_descriptor *desc;
@@ -390,7 +390,7 @@ int orinoco_process_xmit_skb(struct sk_buff *skb,
struct header_struct {
struct ethhdr eth; /* 802.3 header */
u8 encap[6]; /* 802.2 header */
- } __attribute__ ((packed)) hdr;
+ } __packed hdr;
int len = skb->len + sizeof(encaps_hdr) - (2 * ETH_ALEN);
if (skb_headroom(skb) < ENCAPS_OVERHEAD) {
@@ -1170,7 +1170,7 @@ static void orinoco_join_ap(struct work_struct *work)
struct join_req {
u8 bssid[ETH_ALEN];
__le16 channel;
- } __attribute__ ((packed)) req;
+ } __packed req;
const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
struct prism2_scan_apinfo *atom = NULL;
int offset = 4;
@@ -1410,7 +1410,7 @@ void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
struct {
__le16 len;
__le16 type;
- } __attribute__ ((packed)) info;
+ } __packed info;
int len, type;
int err;
diff --git a/drivers/net/wireless/orinoco/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h
index a6da86e0a70f..255710ef082a 100644
--- a/drivers/net/wireless/orinoco/orinoco.h
+++ b/drivers/net/wireless/orinoco/orinoco.h
@@ -32,7 +32,7 @@
struct orinoco_key {
__le16 len; /* always stored as little-endian */
char data[ORINOCO_MAX_KEY_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define TKIP_KEYLEN 16
#define MIC_KEYLEN 8
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 78f089baa8c9..1558381998ee 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -90,7 +90,7 @@ struct header_struct {
/* SNAP */
u8 oui[3];
__be16 ethertype;
-} __attribute__ ((packed));
+} __packed;
struct ez_usb_fw {
u16 size;
@@ -222,7 +222,7 @@ struct ezusb_packet {
__le16 hermes_len;
__le16 hermes_rid;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
/* Table of devices that work or may work with this driver */
static struct usb_device_id ezusb_table[] = {
@@ -356,12 +356,10 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
{
struct request_context *ctx;
- ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC);
+ ctx = kzalloc(sizeof(*ctx), GFP_ATOMIC);
if (!ctx)
return NULL;
- memset(ctx, 0, sizeof(*ctx));
-
ctx->buf = kmalloc(BULK_BUF_SIZE, GFP_ATOMIC);
if (!ctx->buf) {
kfree(ctx);
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c
index 5775124e2aee..cf7be1eb6124 100644
--- a/drivers/net/wireless/orinoco/wext.c
+++ b/drivers/net/wireless/orinoco/wext.c
@@ -128,7 +128,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev)
} else {
struct {
__le16 qual, signal, noise, unused;
- } __attribute__ ((packed)) cq;
+ } __packed cq;
err = HERMES_READ_RECORD(hw, USER_BAP,
HERMES_RID_COMMSQUALITY, &cq);
@@ -993,11 +993,9 @@ static int orinoco_ioctl_set_genie(struct net_device *dev,
return -EINVAL;
if (wrqu->data.length) {
- buf = kmalloc(wrqu->data.length, GFP_KERNEL);
+ buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
-
- memcpy(buf, extra, wrqu->data.length);
} else
buf = NULL;
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 187e263b045a..e51650ed49f2 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -599,13 +599,13 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len)
}
break;
case PDR_PRISM_ZIF_TX_IQ_CALIBRATION:
- priv->iq_autocal = kmalloc(data_len, GFP_KERNEL);
+ priv->iq_autocal = kmemdup(entry->data, data_len,
+ GFP_KERNEL);
if (!priv->iq_autocal) {
err = -ENOMEM;
goto err;
}
- memcpy(priv->iq_autocal, entry->data, data_len);
priv->iq_autocal_len = data_len / sizeof(struct pda_iq_autocal_entry);
break;
case PDR_DEFAULT_COUNTRY:
diff --git a/drivers/net/wireless/p54/net2280.h b/drivers/net/wireless/p54/net2280.h
index 4915d9d54203..e3ed893b5aaf 100644
--- a/drivers/net/wireless/p54/net2280.h
+++ b/drivers/net/wireless/p54/net2280.h
@@ -232,7 +232,7 @@ struct net2280_regs {
#define GPIO2_INTERRUPT 2
#define GPIO1_INTERRUPT 1
#define GPIO0_INTERRUPT 0
-} __attribute__ ((packed));
+} __packed;
/* usb control, BAR0 + 0x0080 */
struct net2280_usb_regs {
@@ -296,7 +296,7 @@ struct net2280_usb_regs {
#define FORCE_IMMEDIATE 7
#define OUR_USB_ADDRESS 0
__le32 ourconfig;
-} __attribute__ ((packed));
+} __packed;
/* pci control, BAR0 + 0x0100 */
struct net2280_pci_regs {
@@ -323,7 +323,7 @@ struct net2280_pci_regs {
#define PCI_ARBITER_CLEAR 2
#define PCI_EXTERNAL_ARBITER 1
#define PCI_HOST_MODE 0
-} __attribute__ ((packed));
+} __packed;
/* dma control, BAR0 + 0x0180 ... array of four structs like this,
* for channels 0..3. see also struct net2280_dma: descriptor
@@ -364,7 +364,7 @@ struct net2280_dma_regs { /* [11.7] */
__le32 dmaaddr;
__le32 dmadesc;
u32 _unused1;
-} __attribute__ ((packed));
+} __packed;
/* dedicated endpoint registers, BAR0 + 0x0200 */
@@ -374,7 +374,7 @@ struct net2280_dep_regs { /* [11.8] */
/* offset 0x0204, 0x0214, 0x224, 0x234, 0x244 */
__le32 dep_rsp;
u32 _unused[2];
-} __attribute__ ((packed));
+} __packed;
/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
* like this, for ep0 then the configurable endpoints A..F
@@ -437,16 +437,16 @@ struct net2280_ep_regs { /* [11.9] */
__le32 ep_avail;
__le32 ep_data;
u32 _unused0[2];
-} __attribute__ ((packed));
+} __packed;
struct net2280_reg_write {
__le16 port;
__le32 addr;
__le32 val;
-} __attribute__ ((packed));
+} __packed;
struct net2280_reg_read {
__le16 port;
__le32 addr;
-} __attribute__ ((packed));
+} __packed;
#endif /* NET2280_H */
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index 2feead617a3b..ee9bc62a4fa2 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -65,7 +65,7 @@ struct p54p_csr {
u8 unused_6[1924];
u8 cardbus_cis[0x800];
u8 direct_mem_win[0x1000];
-} __attribute__ ((packed));
+} __packed;
/* usb backend only needs the register defines above */
#ifndef P54USB_H
@@ -74,7 +74,7 @@ struct p54p_desc {
__le32 device_addr;
__le16 len;
__le16 flags;
-} __attribute__ ((packed));
+} __packed;
struct p54p_ring_control {
__le32 host_idx[4];
@@ -83,7 +83,7 @@ struct p54p_ring_control {
struct p54p_desc tx_data[32];
struct p54p_desc rx_mgmt[4];
struct p54p_desc tx_mgmt[4];
-} __attribute__ ((packed));
+} __packed;
#define P54P_READ(r) (__force __le32)__raw_readl(&priv->map->r)
#define P54P_WRITE(r, val) __raw_writel((__force u32)(__le32)(val), &priv->map->r)
diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c
index c8f09da1f84d..087bf0698a5a 100644
--- a/drivers/net/wireless/p54/p54spi.c
+++ b/drivers/net/wireless/p54/p54spi.c
@@ -697,9 +697,7 @@ static int __devexit p54spi_remove(struct spi_device *spi)
static struct spi_driver p54spi_driver = {
.driver = {
- /* use cx3110x name because board-n800.c uses that for the
- * SPI port */
- .name = "cx3110x",
+ .name = "p54spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
@@ -733,3 +731,4 @@ module_exit(p54spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Lamparter <chunkeey@web.de>");
MODULE_ALIAS("spi:cx3110x");
+MODULE_ALIAS("spi:p54spi");
diff --git a/drivers/net/wireless/p54/p54spi.h b/drivers/net/wireless/p54/p54spi.h
index 7fbe8d8fc67c..dfaa62aaeb07 100644
--- a/drivers/net/wireless/p54/p54spi.h
+++ b/drivers/net/wireless/p54/p54spi.h
@@ -96,7 +96,7 @@ struct p54s_dma_regs {
__le16 cmd;
__le16 len;
__le32 addr;
-} __attribute__ ((packed));
+} __packed;
struct p54s_tx_info {
struct list_head tx_list;
diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c
index d5b197b4d5bb..b0318ea59b7f 100644
--- a/drivers/net/wireless/p54/p54usb.c
+++ b/drivers/net/wireless/p54/p54usb.c
@@ -80,6 +80,7 @@ static struct usb_device_id p54u_table[] __devinitdata = {
{USB_DEVICE(0x1413, 0x5400)}, /* Telsey 802.11g USB2.0 Adapter */
{USB_DEVICE(0x1435, 0x0427)}, /* Inventel UR054G */
{USB_DEVICE(0x2001, 0x3704)}, /* DLink DWL-G122 rev A2 */
+ {USB_DEVICE(0x413c, 0x5513)}, /* Dell WLA3310 USB Wireless Adapter */
{USB_DEVICE(0x413c, 0x8102)}, /* Spinnaker DUT */
{USB_DEVICE(0x413c, 0x8104)}, /* Cohiba Proto board */
{}
@@ -433,10 +434,9 @@ static int p54u_firmware_reset_3887(struct ieee80211_hw *dev)
u8 *buf;
int ret;
- buf = kmalloc(4, GFP_KERNEL);
+ buf = kmemdup(p54u_romboot_3887, 4, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, p54u_romboot_3887, 4);
ret = p54u_bulk_msg(priv, P54U_PIPE_DATA,
buf, 4);
kfree(buf);
diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h
index e935b79f7f75..ed4034ade59a 100644
--- a/drivers/net/wireless/p54/p54usb.h
+++ b/drivers/net/wireless/p54/p54usb.h
@@ -70,12 +70,12 @@ struct net2280_tx_hdr {
__le16 len;
__le16 follower; /* ? */
u8 padding[8];
-} __attribute__((packed));
+} __packed;
struct lm87_tx_hdr {
__le32 device_addr;
__le32 chksum;
-} __attribute__((packed));
+} __packed;
/* Some flags for the isl hardware registers controlling DMA inside the
* chip */
@@ -103,7 +103,7 @@ struct x2_header {
__le32 fw_load_addr;
__le32 fw_length;
__le32 crc;
-} __attribute__((packed));
+} __packed;
/* pipes 3 and 4 are not used by the driver */
#define P54U_PIPE_NUMBER 9
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 8d1190c0f062..912fdc022d08 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -2101,7 +2101,7 @@ struct ieee80211_beacon_phdr {
u8 timestamp[8];
u16 beacon_int;
u16 capab_info;
-} __attribute__ ((packed));
+} __packed;
#define WLAN_EID_GENERIC 0xdd
static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
@@ -2751,14 +2751,9 @@ prism54_hostapd(struct net_device *ndev, struct iw_point *p)
p->length > PRISM2_HOSTAPD_MAX_BUF_SIZE || !p->pointer)
return -EINVAL;
- param = kmalloc(p->length, GFP_KERNEL);
- if (param == NULL)
- return -ENOMEM;
-
- if (copy_from_user(param, p->pointer, p->length)) {
- kfree(param);
- return -EFAULT;
- }
+ param = memdup_user(p->pointer, p->length);
+ if (IS_ERR(param))
+ return PTR_ERR(param);
switch (param->cmd) {
case PRISM2_SET_ENCRYPTION:
diff --git a/drivers/net/wireless/prism54/isl_oid.h b/drivers/net/wireless/prism54/isl_oid.h
index b7534c2869c8..59e31258d450 100644
--- a/drivers/net/wireless/prism54/isl_oid.h
+++ b/drivers/net/wireless/prism54/isl_oid.h
@@ -29,20 +29,20 @@
struct obj_ssid {
u8 length;
char octets[33];
-} __attribute__ ((packed));
+} __packed;
struct obj_key {
u8 type; /* dot11_priv_t */
u8 length;
char key[32];
-} __attribute__ ((packed));
+} __packed;
struct obj_mlme {
u8 address[6];
u16 id;
u16 state;
u16 code;
-} __attribute__ ((packed));
+} __packed;
struct obj_mlmeex {
u8 address[6];
@@ -51,12 +51,12 @@ struct obj_mlmeex {
u16 code;
u16 size;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_buffer {
u32 size;
u32 addr; /* 32bit bus address */
-} __attribute__ ((packed));
+} __packed;
struct obj_bss {
u8 address[6];
@@ -77,17 +77,17 @@ struct obj_bss {
short rates;
short basic_rates;
int:16; /* padding */
-} __attribute__ ((packed));
+} __packed;
struct obj_bsslist {
u32 nr;
struct obj_bss bsslist[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_frequencies {
u16 nr;
u16 mhz[0];
-} __attribute__ ((packed));
+} __packed;
struct obj_attachment {
char type;
@@ -95,7 +95,7 @@ struct obj_attachment {
short id;
short size;
char data[0];
-} __attribute__((packed));
+} __packed;
/*
* in case everything's ok, the inlined function below will be
diff --git a/drivers/net/wireless/prism54/islpci_eth.h b/drivers/net/wireless/prism54/islpci_eth.h
index 54f9a4b7bf9b..6ca30a5b7bfb 100644
--- a/drivers/net/wireless/prism54/islpci_eth.h
+++ b/drivers/net/wireless/prism54/islpci_eth.h
@@ -34,13 +34,13 @@ struct rfmon_header {
__le16 unk3;
u8 rssi;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct rx_annex_header {
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
struct rfmon_header rfmon;
-} __attribute__ ((packed));
+} __packed;
/* wlan-ng (and hopefully others) AVS header, version one. Fields in
* network byte order. */
diff --git a/drivers/net/wireless/prism54/islpci_mgt.h b/drivers/net/wireless/prism54/islpci_mgt.h
index 0b27e50fe0d5..0db93db9b675 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.h
+++ b/drivers/net/wireless/prism54/islpci_mgt.h
@@ -101,7 +101,7 @@ typedef struct {
u8 device_id;
u8 flags;
u32 length;
-} __attribute__ ((packed))
+} __packed
pimfor_header_t;
/* A received and interrupt-processed management frame, either for
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 4bd61ee627c0..5e7f344b000d 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -238,19 +238,19 @@ struct ndis_80211_auth_request {
u8 bssid[6];
u8 padding[2];
__le32 flags;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_pmkid_candidate {
u8 bssid[6];
u8 padding[2];
__le32 flags;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_pmkid_cand_list {
__le32 version;
__le32 num_candidates;
struct ndis_80211_pmkid_candidate candidate_list[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_status_indication {
__le32 status_type;
@@ -260,19 +260,19 @@ struct ndis_80211_status_indication {
struct ndis_80211_auth_request auth_request[0];
struct ndis_80211_pmkid_cand_list cand_list;
} u;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_ssid {
__le32 length;
u8 essid[NDIS_802_11_LENGTH_SSID];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_conf_freq_hop {
__le32 length;
__le32 hop_pattern;
__le32 hop_set;
__le32 dwell_time;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_conf {
__le32 length;
@@ -280,7 +280,7 @@ struct ndis_80211_conf {
__le32 atim_window;
__le32 ds_config;
struct ndis_80211_conf_freq_hop fh_config;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_ex {
__le32 length;
@@ -295,25 +295,25 @@ struct ndis_80211_bssid_ex {
u8 rates[NDIS_802_11_LENGTH_RATES_EX];
__le32 ie_length;
u8 ies[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_list_ex {
__le32 num_items;
struct ndis_80211_bssid_ex bssid[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_fixed_ies {
u8 timestamp[8];
__le16 beacon_interval;
__le16 capabilities;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_wep_key {
__le32 size;
__le32 index;
__le32 length;
u8 material[32];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_key {
__le32 size;
@@ -323,14 +323,14 @@ struct ndis_80211_key {
u8 padding[6];
u8 rsc[8];
u8 material[32];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_remove_key {
__le32 size;
__le32 index;
u8 bssid[6];
u8 padding[2];
-} __attribute__((packed));
+} __packed;
struct ndis_config_param {
__le32 name_offs;
@@ -338,7 +338,7 @@ struct ndis_config_param {
__le32 type;
__le32 value_offs;
__le32 value_length;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_assoc_info {
__le32 length;
@@ -358,12 +358,12 @@ struct ndis_80211_assoc_info {
} resp_ie;
__le32 resp_ie_length;
__le32 offset_resp_ies;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_auth_encr_pair {
__le32 auth_mode;
__le32 encr_mode;
-} __attribute__((packed));
+} __packed;
struct ndis_80211_capability {
__le32 length;
@@ -371,7 +371,7 @@ struct ndis_80211_capability {
__le32 num_pmkids;
__le32 num_auth_encr_pair;
struct ndis_80211_auth_encr_pair auth_encr_pair[0];
-} __attribute__((packed));
+} __packed;
struct ndis_80211_bssid_info {
u8 bssid[6];
@@ -2495,8 +2495,7 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev)
static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
{
struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
- struct ndis_80211_assoc_info *info;
- u8 assoc_buf[sizeof(*info) + IW_CUSTOM_MAX + 32];
+ struct ndis_80211_assoc_info *info = NULL;
u8 bssid[ETH_ALEN];
int resp_ie_len, req_ie_len;
u8 *req_ie, *resp_ie;
@@ -2515,23 +2514,43 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
resp_ie = NULL;
if (priv->infra_mode == NDIS_80211_INFRA_INFRA) {
- memset(assoc_buf, 0, sizeof(assoc_buf));
- info = (void *)assoc_buf;
+ info = kzalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
+ if (!info) {
+ /* No memory? Try resume work later */
+ set_bit(WORK_LINK_UP, &priv->work_pending);
+ queue_work(priv->workqueue, &priv->work);
+ return;
+ }
- /* Get association info IEs from device and send them back to
- * userspace. */
- ret = get_association_info(usbdev, info, sizeof(assoc_buf));
+ /* Get association info IEs from device. */
+ ret = get_association_info(usbdev, info, CONTROL_BUFFER_SIZE);
if (!ret) {
req_ie_len = le32_to_cpu(info->req_ie_length);
if (req_ie_len > 0) {
offset = le32_to_cpu(info->offset_req_ies);
+
+ if (offset > CONTROL_BUFFER_SIZE)
+ offset = CONTROL_BUFFER_SIZE;
+
req_ie = (u8 *)info + offset;
+
+ if (offset + req_ie_len > CONTROL_BUFFER_SIZE)
+ req_ie_len =
+ CONTROL_BUFFER_SIZE - offset;
}
resp_ie_len = le32_to_cpu(info->resp_ie_length);
if (resp_ie_len > 0) {
offset = le32_to_cpu(info->offset_resp_ies);
+
+ if (offset > CONTROL_BUFFER_SIZE)
+ offset = CONTROL_BUFFER_SIZE;
+
resp_ie = (u8 *)info + offset;
+
+ if (offset + resp_ie_len > CONTROL_BUFFER_SIZE)
+ resp_ie_len =
+ CONTROL_BUFFER_SIZE - offset;
}
}
} else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC))
@@ -2563,6 +2582,9 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev)
} else if (priv->infra_mode == NDIS_80211_INFRA_ADHOC)
cfg80211_ibss_joined(usbdev->net, bssid, GFP_KERNEL);
+ if (info != NULL)
+ kfree(info);
+
priv->connected = true;
memcpy(priv->bssid, bssid, ETH_ALEN);
diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index ad2c98af7e9d..1eb882e15fb4 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1076,9 +1076,6 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1091,9 +1088,15 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2400pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
@@ -1226,7 +1229,7 @@ static void rt2400pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 41da3d218c65..a29cb212f89a 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1233,9 +1233,6 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- struct queue_entry_priv_pci *entry_priv = entry->priv_data;
- struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
- u32 word;
u32 reg;
/*
@@ -1248,9 +1245,15 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00queue_map_txskb(rt2x00dev, entry->skb);
- rt2x00_desc_read(entry_priv->desc, 1, &word);
- rt2x00_set_field32(&word, TXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma);
- rt2x00_desc_write(entry_priv->desc, 1, word);
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Enable beaconing again.
@@ -1362,7 +1365,7 @@ static void rt2500pci_txdone(struct rt2x00_dev *rt2x00dev,
}
txdesc.retry = rt2x00_get_field32(word, TXD_W0_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index 9ae96a626e6d..002db646ae0b 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -345,7 +345,6 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
struct rt2x00lib_crypto *crypto,
struct ieee80211_key_conf *key)
{
- int timeout;
u32 mask;
u16 reg;
@@ -367,18 +366,8 @@ static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev,
key->hw_key_idx += reg ? ffz(reg) : 0;
- /*
- * The encryption key doesn't fit within the CSR cache,
- * this means we should allocate it separately and use
- * rt2x00usb_vendor_request() to send the key to the hardware.
- */
- reg = KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(crypto->key));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- crypto->key,
- sizeof(crypto->key),
- timeout);
+ rt2500usb_register_multiwrite(rt2x00dev, reg,
+ crypto->key, sizeof(crypto->key));
/*
* The driver does not support the IV/EIV generation
@@ -1034,7 +1023,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1080,6 +1069,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1108,9 +1098,20 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
/*
- * Take the descriptor in front of the skb into account.
+ * Add space for the descriptor in front of the skb.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt2500usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* USB devices cannot blindly pass the skb->len as the
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index 2aa03751c341..317b7807175e 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -63,7 +63,6 @@
*/
#define REV_RT2860C 0x0100
#define REV_RT2860D 0x0101
-#define REV_RT2870D 0x0101
#define REV_RT2872E 0x0200
#define REV_RT3070E 0x0200
#define REV_RT3070F 0x0201
@@ -99,6 +98,21 @@
*/
/*
+ * E2PROM_CSR: PCI EEPROM control register.
+ * RELOAD: Write 1 to reload eeprom content.
+ * TYPE: 0: 93c46, 1:93c66.
+ * LOAD_STATUS: 1:loading, 0:done.
+ */
+#define E2PROM_CSR 0x0004
+#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
+#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
+#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
+#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
+#define E2PROM_CSR_TYPE FIELD32(0x00000030)
+#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
+#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
+
+/*
* OPT_14: Unknown register used by rt3xxx devices.
*/
#define OPT_14_CSR 0x0114
@@ -322,6 +336,39 @@
#define RX_DRX_IDX 0x029c
/*
+ * USB_DMA_CFG
+ * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
+ * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
+ * PHY_CLEAR: phy watch dog enable.
+ * TX_CLEAR: Clear USB DMA TX path.
+ * TXOP_HALT: Halt TXOP count down when TX buffer is full.
+ * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
+ * RX_BULK_EN: Enable USB DMA Rx.
+ * TX_BULK_EN: Enable USB DMA Tx.
+ * EP_OUT_VALID: OUT endpoint data valid.
+ * RX_BUSY: USB DMA RX FSM busy.
+ * TX_BUSY: USB DMA TX FSM busy.
+ */
+#define USB_DMA_CFG 0x02a0
+#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff)
+#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00)
+#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000)
+#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000)
+#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000)
+#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000)
+#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000)
+#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000)
+#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000)
+#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000)
+#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000)
+
+/*
+ * US_CYC_CNT
+ */
+#define US_CYC_CNT 0x02a4
+#define US_CYC_CNT_CLOCK_CYCLE FIELD32(0x000000ff)
+
+/*
* PBF_SYS_CTRL
* HOST_RAM_WRITE: enable Host program ram write selection
*/
@@ -1370,17 +1417,17 @@
struct mac_wcid_entry {
u8 mac[6];
u8 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct mac_iveiv_entry {
u8 iv[8];
-} __attribute__ ((packed));
+} __packed;
/*
* MAC_WCID_ATTRIBUTE:
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index db4250d1c8b3..ae20e6728b1e 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -38,12 +38,8 @@
#include <linux/slab.h>
#include "rt2x00.h"
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
-#include "rt2x00usb.h"
-#endif
#include "rt2800lib.h"
#include "rt2800.h"
-#include "rt2800usb.h"
MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
MODULE_DESCRIPTION("rt2800 library");
@@ -282,9 +278,8 @@ int rt2800_wait_wpdma_ready(struct rt2x00_dev *rt2x00dev)
}
EXPORT_SYMBOL_GPL(rt2800_wait_wpdma_ready);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc)
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc)
{
- __le32 *txwi = (__le32 *)(skb->data - TXWI_DESC_SIZE);
u32 word;
/*
@@ -380,6 +375,67 @@ void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc)
}
EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+ unsigned int beacon_base;
+ u32 reg;
+
+ /*
+ * Disable beaconing while we are reloading the beacon data,
+ * otherwise we might be sending out invalid data.
+ */
+ rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Add space for the TXWI in front of the skb.
+ */
+ skb_push(entry->skb, TXWI_DESC_SIZE);
+ memset(entry->skb, 0, TXWI_DESC_SIZE);
+
+ /*
+ * Register descriptor details in skb frame descriptor.
+ */
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
+ skbdesc->desc = entry->skb->data;
+ skbdesc->desc_len = TXWI_DESC_SIZE;
+
+ /*
+ * Add the TXWI for the beacon to the skb.
+ */
+ rt2800_write_txwi((__le32 *)entry->skb->data, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
+ * Write entire beacon with TXWI to register.
+ */
+ beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
+ rt2800_register_multiwrite(rt2x00dev, beacon_base,
+ entry->skb->data, entry->skb->len);
+
+ /*
+ * Enable beaconing again.
+ */
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
+ rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
+ rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
+
+ /*
+ * Clean up beacon skb.
+ */
+ dev_kfree_skb_any(entry->skb);
+ entry->skb = NULL;
+}
+EXPORT_SYMBOL(rt2800_write_beacon);
+
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
const struct rt2x00debug rt2800_rt2x00debug = {
.owner = THIS_MODULE,
@@ -1212,6 +1268,7 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
u32 reg;
u16 eeprom;
unsigned int i;
+ int ret;
rt2800_register_read(rt2x00dev, WPDMA_GLO_CFG, &reg);
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_ENABLE_TX_DMA, 0);
@@ -1221,59 +1278,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, WPDMA_GLO_CFG_TX_WRITEBACK_DONE, 1);
rt2800_register_write(rt2x00dev, WPDMA_GLO_CFG, reg);
- if (rt2x00_is_usb(rt2x00dev)) {
- /*
- * Wait until BBP and RF are ready.
- */
- for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
- rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
- if (reg && reg != ~0)
- break;
- msleep(1);
- }
-
- if (i == REGISTER_BUSY_COUNT) {
- ERROR(rt2x00dev, "Unstable hardware.\n");
- return -EBUSY;
- }
-
- rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL,
- reg & ~0x00002000);
- } else if (rt2x00_is_pci(rt2x00dev) || rt2x00_is_soc(rt2x00dev)) {
- /*
- * Reset DMA indexes
- */
- rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
- rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
- rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
-
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
- rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
-
- rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
- }
-
- rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
- rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
-
- if (rt2x00_is_usb(rt2x00dev)) {
- rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
-#if defined(CONFIG_RT2X00_LIB_USB) || defined(CONFIG_RT2X00_LIB_USB_MODULE)
- rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
- USB_MODE_RESET, REGISTER_TIMEOUT);
-#endif
- }
-
- rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+ ret = rt2800_drv_init_registers(rt2x00dev);
+ if (ret)
+ return ret;
rt2800_register_read(rt2x00dev, BCN_OFFSET0, &reg);
rt2x00_set_field32(&reg, BCN_OFFSET0_BCN0, 0xe0); /* 0x3800 */
@@ -1328,7 +1335,6 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
} else {
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
}
- rt2800_register_write(rt2x00dev, TX_SW_CFG2, reg);
} else if (rt2x00_rt(rt2x00dev, RT3070)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
@@ -1339,6 +1345,10 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
}
+ } else if (rt2800_is_305x_soc(rt2x00dev)) {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x0000001f);
} else {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000000);
rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -1560,9 +1570,9 @@ int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
rt2800_register_write(rt2x00dev, HW_BEACON_BASE7, 0);
if (rt2x00_is_usb(rt2x00dev)) {
- rt2800_register_read(rt2x00dev, USB_CYC_CFG, &reg);
- rt2x00_set_field32(&reg, USB_CYC_CFG_CLOCK_CYCLE, 30);
- rt2800_register_write(rt2x00dev, USB_CYC_CFG, reg);
+ rt2800_register_read(rt2x00dev, US_CYC_CNT, &reg);
+ rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 30);
+ rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
}
rt2800_register_read(rt2x00dev, HT_FBK_CFG0, &reg);
@@ -1706,8 +1716,7 @@ int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
rt2800_bbp_write(rt2x00dev, 82, 0x62);
rt2800_bbp_write(rt2x00dev, 83, 0x6a);
- if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D) ||
- rt2x00_rt_rev(rt2x00dev, RT2870, REV_RT2870D))
+ if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D))
rt2800_bbp_write(rt2x00dev, 84, 0x19);
else
rt2800_bbp_write(rt2x00dev, 84, 0x99);
@@ -2013,8 +2022,7 @@ int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
- rt2x00_eeprom_read(rt2x00dev, EEPROM_NIC, &eeprom);
- if (rt2x00_get_field16(eeprom, EEPROM_NIC_EXTERNAL_LNA_BG))
+ if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags))
rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
}
rt2x00_eeprom_read(rt2x00dev, EEPROM_TXMIXER_GAIN_BG, &eeprom);
@@ -2147,7 +2155,6 @@ int rt2800_validate_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00_eeprom_write(rt2x00dev, EEPROM_ANTENNA, word);
EEPROM(rt2x00dev, "Antenna: 0x%04x\n", word);
} else if (rt2x00_rt(rt2x00dev, RT2860) ||
- rt2x00_rt(rt2x00dev, RT2870) ||
rt2x00_rt(rt2x00dev, RT2872)) {
/*
* There is a max of 2 RX streams for RT28x0 series
@@ -2251,7 +2258,6 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
value, rt2x00_get_field32(reg, MAC_CSR0_REVISION));
if (!rt2x00_rt(rt2x00dev, RT2860) &&
- !rt2x00_rt(rt2x00dev, RT2870) &&
!rt2x00_rt(rt2x00dev, RT2872) &&
!rt2x00_rt(rt2x00dev, RT2883) &&
!rt2x00_rt(rt2x00dev, RT3070) &&
@@ -2528,16 +2534,16 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
else
spec->ht.ht_supported = false;
- /*
- * Don't set IEEE80211_HT_CAP_SUP_WIDTH_20_40 for now as it causes
- * reception problems with HT40 capable 11n APs
- */
spec->ht.cap =
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
IEEE80211_HT_CAP_GRN_FLD |
IEEE80211_HT_CAP_SGI_20 |
IEEE80211_HT_CAP_SGI_40 |
- IEEE80211_HT_CAP_TX_STBC |
IEEE80211_HT_CAP_RX_STBC;
+
+ if (rt2x00_get_field16(eeprom, EEPROM_ANTENNA_TXPATH) >= 2)
+ spec->ht.cap |= IEEE80211_HT_CAP_TX_STBC;
+
spec->ht.ampdu_factor = 3;
spec->ht.ampdu_density = 4;
spec->ht.mcs.tx_params =
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index 94de999e2290..8313dbf441a5 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -40,6 +40,8 @@ struct rt2800_ops {
int (*regbusy_read)(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
const struct rt2x00_field32 field, u32 *reg);
+
+ int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
};
static inline void rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -107,13 +109,22 @@ static inline int rt2800_regbusy_read(struct rt2x00_dev *rt2x00dev,
return rt2800ops->regbusy_read(rt2x00dev, offset, field, reg);
}
+static inline int rt2800_drv_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->priv;
+
+ return rt2800ops->drv_init_registers(rt2x00dev);
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
-void rt2800_write_txwi(struct sk_buff *skb, struct txentry_desc *txdesc);
+void rt2800_write_txwi(__le32 *txwi, struct txentry_desc *txdesc);
void rt2800_process_rxwi(struct sk_buff *skb, struct rxdone_entry_desc *txdesc);
+void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
+
extern const struct rt2x00debug rt2800_rt2x00debug;
int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c
index b2f23272c3aa..b5a871eb8881 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/rt2x00/rt2800pci.c
@@ -446,6 +446,38 @@ static void rt2800pci_toggle_irq(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, INT_MASK_CSR, reg);
}
+static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+
+ /*
+ * Reset DMA indexes
+ */
+ rt2800_register_read(rt2x00dev, WPDMA_RST_IDX, &reg);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX0, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX1, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX2, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX3, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX4, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DTX_IDX5, 1);
+ rt2x00_set_field32(&reg, WPDMA_RST_IDX_DRX_IDX0, 1);
+ rt2800_register_write(rt2x00dev, WPDMA_RST_IDX, reg);
+
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
+
+ rt2800_register_write(rt2x00dev, PWR_PIN_CFG, 0x00000003);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ return 0;
+}
+
static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -465,7 +497,7 @@ static int rt2800pci_enable_radio(struct rt2x00_dev *rt2x00dev)
/*
* Send signal to firmware during boot time.
*/
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
/*
* Enable RX.
@@ -613,18 +645,10 @@ static int rt2800pci_set_device_state(struct rt2x00_dev *rt2x00dev,
/*
* TX descriptor initialization
*/
-static int rt2800pci_write_tx_data(struct queue_entry* entry,
- struct txentry_desc *txdesc)
+static void rt2800pci_write_tx_datadesc(struct queue_entry* entry,
+ struct txentry_desc *txdesc)
{
- int ret;
-
- ret = rt2x00pci_write_tx_data(entry, txdesc);
- if (ret)
- return ret;
-
- rt2800_write_txwi(entry->skb, txdesc);
-
- return 0;
+ rt2800_write_txwi((__le32 *) entry->skb->data, txdesc);
}
@@ -684,49 +708,6 @@ static void rt2800pci_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
-static void rt2800pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- unsigned int beacon_base;
- u32 reg;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Add the TXWI for the beacon to the skb.
- */
- rt2800_write_txwi(entry->skb, txdesc);
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
- * Write entire beacon with TXWI to register.
- */
- beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2800_register_multiwrite(rt2x00dev, beacon_base,
- entry->skb->data, entry->skb->len);
-
- /*
- * Enable beaconing again.
- */
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Clean up beacon skb.
- */
- dev_kfree_skb_any(entry->skb);
- entry->skb = NULL;
-}
-
static void rt2800pci_kick_tx_queue(struct rt2x00_dev *rt2x00dev,
const enum data_queue_qid queue_idx)
{
@@ -880,8 +861,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
/* Check if we got a match by looking at WCID/ACK/PID
* fields */
- txwi = (__le32 *)(entry->skb->data -
- rt2x00dev->ops->extra_tx_headroom);
+ txwi = (__le32 *) entry->skb->data;
rt2x00_desc_read(txwi, 1, &word);
tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
@@ -926,7 +906,7 @@ static void rt2800pci_txdone(struct rt2x00_dev *rt2x00dev)
__set_bit(TXDONE_FALLBACK, &txdesc.flags);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
@@ -996,6 +976,8 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = {
.register_multiwrite = rt2x00pci_register_multiwrite,
.regbusy_read = rt2x00pci_regbusy_read,
+
+ .drv_init_registers = rt2800pci_init_registers,
};
static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -1063,8 +1045,9 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
.reset_tuner = rt2800_reset_tuner,
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800pci_write_tx_desc,
- .write_tx_data = rt2800pci_write_tx_data,
- .write_beacon = rt2800pci_write_beacon,
+ .write_tx_data = rt2x00pci_write_tx_data,
+ .write_tx_datadesc = rt2800pci_write_tx_datadesc,
+ .write_beacon = rt2800_write_beacon,
.kick_tx_queue = rt2800pci_kick_tx_queue,
.kill_tx_queue = rt2800pci_kill_tx_queue,
.fill_rxdone = rt2800pci_fill_rxdone,
diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h
index afc8e7da27cb..5a8dda9b5b5a 100644
--- a/drivers/net/wireless/rt2x00/rt2800pci.h
+++ b/drivers/net/wireless/rt2x00/rt2800pci.h
@@ -35,25 +35,6 @@
#define RT2800PCI_H
/*
- * PCI registers.
- */
-
-/*
- * E2PROM_CSR: EEPROM control register.
- * RELOAD: Write 1 to reload eeprom content.
- * TYPE: 0: 93c46, 1:93c66.
- * LOAD_STATUS: 1:loading, 0:done.
- */
-#define E2PROM_CSR 0x0004
-#define E2PROM_CSR_DATA_CLOCK FIELD32(0x00000001)
-#define E2PROM_CSR_CHIP_SELECT FIELD32(0x00000002)
-#define E2PROM_CSR_DATA_IN FIELD32(0x00000004)
-#define E2PROM_CSR_DATA_OUT FIELD32(0x00000008)
-#define E2PROM_CSR_TYPE FIELD32(0x00000030)
-#define E2PROM_CSR_LOAD_STATUS FIELD32(0x00000040)
-#define E2PROM_CSR_RELOAD FIELD32(0x00000080)
-
-/*
* Queue register offset macros
*/
#define TX_QUEUE_REG_OFFSET 0x10
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 699161327d65..c437960de3ed 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -169,11 +169,8 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Write firmware to device.
*/
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE,
- data + offset, length,
- REGISTER_TIMEOUT32(length));
+ rt2800_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE,
+ data + offset, length);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_CID, ~0);
rt2800_register_write(rt2x00dev, H2M_MAILBOX_STATUS, ~0);
@@ -196,7 +193,7 @@ static int rt2800usb_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Send signal to firmware during boot time.
*/
- rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0xff, 0, 0);
+ rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
if (rt2x00_rt(rt2x00dev, RT3070) ||
rt2x00_rt(rt2x00dev, RT3071) ||
@@ -246,6 +243,44 @@ static void rt2800usb_toggle_rx(struct rt2x00_dev *rt2x00dev,
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
}
+static int rt2800usb_init_registers(struct rt2x00_dev *rt2x00dev)
+{
+ u32 reg;
+ int i;
+
+ /*
+ * Wait until BBP and RF are ready.
+ */
+ for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+ rt2800_register_read(rt2x00dev, MAC_CSR0, &reg);
+ if (reg && reg != ~0)
+ break;
+ msleep(1);
+ }
+
+ if (i == REGISTER_BUSY_COUNT) {
+ ERROR(rt2x00dev, "Unstable hardware.\n");
+ return -EBUSY;
+ }
+
+ rt2800_register_read(rt2x00dev, PBF_SYS_CTRL, &reg);
+ rt2800_register_write(rt2x00dev, PBF_SYS_CTRL, reg & ~0x00002000);
+
+ rt2800_register_read(rt2x00dev, MAC_SYS_CTRL, &reg);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_CSR, 1);
+ rt2x00_set_field32(&reg, MAC_SYS_CTRL_RESET_BBP, 1);
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, reg);
+
+ rt2800_register_write(rt2x00dev, USB_DMA_CFG, 0x00000000);
+
+ rt2x00usb_vendor_request_sw(rt2x00dev, USB_DEVICE_MODE, 0,
+ USB_MODE_RESET, REGISTER_TIMEOUT);
+
+ rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00000000);
+
+ return 0;
+}
+
static int rt2800usb_enable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
@@ -400,13 +435,14 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txi = (__le32 *)(skb->data - TXWI_DESC_SIZE - TXINFO_DESC_SIZE);
+ __le32 *txi = (__le32 *) skb->data;
+ __le32 *txwi = (__le32 *) (skb->data + TXINFO_DESC_SIZE);
u32 word;
/*
* Initialize TXWI descriptor
*/
- rt2800_write_txwi(skb, txdesc);
+ rt2800_write_txwi(txwi, txdesc);
/*
* Initialize TXINFO descriptor
@@ -426,6 +462,7 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txi;
skbdesc->desc_len = TXINFO_DESC_SIZE + TXWI_DESC_SIZE;
}
@@ -433,51 +470,6 @@ static void rt2800usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* TX data initialization
*/
-static void rt2800usb_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
-{
- struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- unsigned int beacon_base;
- u32 reg;
-
- /*
- * Disable beaconing while we are reloading the beacon data,
- * otherwise we might be sending out invalid data.
- */
- rt2800_register_read(rt2x00dev, BCN_TIME_CFG, &reg);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 0);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Add the TXWI for the beacon to the skb.
- */
- rt2800_write_txwi(entry->skb, txdesc);
- skb_push(entry->skb, TXWI_DESC_SIZE);
-
- /*
- * Write entire beacon with descriptor to register.
- */
- beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base,
- entry->skb->data, entry->skb->len,
- REGISTER_TIMEOUT32(entry->skb->len));
-
- /*
- * Enable beaconing again.
- */
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TSF_TICKING, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_TBTT_ENABLE, 1);
- rt2x00_set_field32(&reg, BCN_TIME_CFG_BEACON_GEN, 1);
- rt2800_register_write(rt2x00dev, BCN_TIME_CFG, reg);
-
- /*
- * Clean up the beacon skb.
- */
- dev_kfree_skb(entry->skb);
- entry->skb = NULL;
-}
-
static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
{
int length;
@@ -595,6 +587,8 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = {
.register_multiwrite = rt2x00usb_register_multiwrite,
.regbusy_read = rt2x00usb_regbusy_read,
+
+ .drv_init_registers = rt2800usb_init_registers,
};
static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev)
@@ -659,7 +653,7 @@ static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {
.link_tuner = rt2800_link_tuner,
.write_tx_desc = rt2800usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
- .write_beacon = rt2800usb_write_beacon,
+ .write_beacon = rt2800_write_beacon,
.get_tx_data_len = rt2800usb_get_tx_data_len,
.kick_tx_queue = rt2x00usb_kick_tx_queue,
.kill_tx_queue = rt2x00usb_kill_tx_queue,
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.h b/drivers/net/wireless/rt2x00/rt2800usb.h
index 2bca6a71a7f5..0722badccf86 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.h
+++ b/drivers/net/wireless/rt2x00/rt2800usb.h
@@ -32,43 +32,6 @@
#define RT2800USB_H
/*
- * USB registers.
- */
-
-/*
- * USB_DMA_CFG
- * RX_BULK_AGG_TIMEOUT: Rx Bulk Aggregation TimeOut in unit of 33ns.
- * RX_BULK_AGG_LIMIT: Rx Bulk Aggregation Limit in unit of 256 bytes.
- * PHY_CLEAR: phy watch dog enable.
- * TX_CLEAR: Clear USB DMA TX path.
- * TXOP_HALT: Halt TXOP count down when TX buffer is full.
- * RX_BULK_AGG_EN: Enable Rx Bulk Aggregation.
- * RX_BULK_EN: Enable USB DMA Rx.
- * TX_BULK_EN: Enable USB DMA Tx.
- * EP_OUT_VALID: OUT endpoint data valid.
- * RX_BUSY: USB DMA RX FSM busy.
- * TX_BUSY: USB DMA TX FSM busy.
- */
-#define USB_DMA_CFG 0x02a0
-#define USB_DMA_CFG_RX_BULK_AGG_TIMEOUT FIELD32(0x000000ff)
-#define USB_DMA_CFG_RX_BULK_AGG_LIMIT FIELD32(0x0000ff00)
-#define USB_DMA_CFG_PHY_CLEAR FIELD32(0x00010000)
-#define USB_DMA_CFG_TX_CLEAR FIELD32(0x00080000)
-#define USB_DMA_CFG_TXOP_HALT FIELD32(0x00100000)
-#define USB_DMA_CFG_RX_BULK_AGG_EN FIELD32(0x00200000)
-#define USB_DMA_CFG_RX_BULK_EN FIELD32(0x00400000)
-#define USB_DMA_CFG_TX_BULK_EN FIELD32(0x00800000)
-#define USB_DMA_CFG_EP_OUT_VALID FIELD32(0x3f000000)
-#define USB_DMA_CFG_RX_BUSY FIELD32(0x40000000)
-#define USB_DMA_CFG_TX_BUSY FIELD32(0x80000000)
-
-/*
- * USB_CYC_CFG
- */
-#define USB_CYC_CFG 0x02a4
-#define USB_CYC_CFG_CLOCK_CYCLE FIELD32(0x000000ff)
-
-/*
* 8051 firmware image.
*/
#define FIRMWARE_RT2870 "rt2870.bin"
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 6c1ff4c15c84..e7acc6abfd89 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -39,6 +39,7 @@
#include <net/mac80211.h>
#include "rt2x00debug.h"
+#include "rt2x00dump.h"
#include "rt2x00leds.h"
#include "rt2x00reg.h"
#include "rt2x00queue.h"
@@ -159,6 +160,7 @@ struct avg_val {
enum rt2x00_chip_intf {
RT2X00_CHIP_INTF_PCI,
+ RT2X00_CHIP_INTF_PCIE,
RT2X00_CHIP_INTF_USB,
RT2X00_CHIP_INTF_SOC,
};
@@ -175,8 +177,7 @@ struct rt2x00_chip {
#define RT2570 0x2570
#define RT2661 0x2661
#define RT2573 0x2573
-#define RT2860 0x2860 /* 2.4GHz PCI/CB */
-#define RT2870 0x2870
+#define RT2860 0x2860 /* 2.4GHz */
#define RT2872 0x2872 /* WSOC */
#define RT2883 0x2883 /* WSOC */
#define RT3070 0x3070
@@ -551,6 +552,8 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
int (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
+ void (*write_tx_datadesc) (struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void (*write_beacon) (struct queue_entry *entry,
struct txentry_desc *txdesc);
int (*get_tx_data_len) (struct queue_entry *entry);
@@ -978,7 +981,13 @@ static inline bool rt2x00_intf(struct rt2x00_dev *rt2x00dev,
static inline bool rt2x00_is_pci(struct rt2x00_dev *rt2x00dev)
{
- return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI) ||
+ rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+}
+
+static inline bool rt2x00_is_pcie(struct rt2x00_dev *rt2x00dev)
+{
+ return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
}
static inline bool rt2x00_is_usb(struct rt2x00_dev *rt2x00dev)
@@ -999,6 +1008,13 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
/**
+ * rt2x00queue_unmap_skb - Unmap a skb from DMA.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @skb: The skb to unmap.
+ */
+void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
+
+/**
* rt2x00queue_get_queue - Convert queue index to queue pointer
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @queue: rt2x00 queue index (see &enum data_queue_qid).
@@ -1015,6 +1031,26 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
enum queue_index index);
/*
+ * Debugfs handlers.
+ */
+/**
+ * rt2x00debug_dump_frame - Dump a frame to userspace through debugfs.
+ * @rt2x00dev: Pointer to &struct rt2x00_dev.
+ * @type: The type of frame that is being dumped.
+ * @skb: The skb containing the frame to be dumped.
+ */
+#ifdef CONFIG_RT2X00_LIB_DEBUGFS
+void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type, struct sk_buff *skb);
+#else
+static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
+ enum rt2x00_dump_type type,
+ struct sk_buff *skb)
+{
+}
+#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
+
+/*
* Interrupt context handlers.
*/
void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev);
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 098315a271ca..8dbd634dae27 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -170,23 +170,27 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
unsigned int ieee80211_flags)
{
struct rt2x00lib_conf libconf;
+ u16 hw_value;
memset(&libconf, 0, sizeof(libconf));
libconf.conf = conf;
if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) {
- if (conf_is_ht40(conf))
+ if (conf_is_ht40(conf)) {
__set_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
- else
+ hw_value = rt2x00ht_center_channel(rt2x00dev, conf);
+ } else {
__clear_bit(CONFIG_CHANNEL_HT40, &rt2x00dev->flags);
+ hw_value = conf->channel->hw_value;
+ }
memcpy(&libconf.rf,
- &rt2x00dev->spec.channels[conf->channel->hw_value],
+ &rt2x00dev->spec.channels[hw_value],
sizeof(libconf.rf));
memcpy(&libconf.channel,
- &rt2x00dev->spec.channels_info[conf->channel->hw_value],
+ &rt2x00dev->spec.channels_info[hw_value],
sizeof(libconf.channel));
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index e9fe93fd8042..b0498e7e7aae 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -211,6 +211,7 @@ void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
if (!test_bit(FRAME_DUMP_FILE_OPEN, &intf->frame_dump_flags))
skb_queue_purge(&intf->frame_dump_skbqueue);
}
+EXPORT_SYMBOL_GPL(rt2x00debug_dump_frame);
static int rt2x00debug_file_open(struct inode *inode, struct file *file)
{
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 3ae468c4d760..0b8efe8e6785 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -211,11 +211,6 @@ void rt2x00lib_txdone(struct queue_entry *entry,
bool success;
/*
- * Unmap the skb.
- */
- rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
-
- /*
* Remove L2 padding which was added during
*/
if (test_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags))
@@ -224,7 +219,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* If the IV/EIV data was stripped from the frame before it was
* passed to the hardware, we should now reinsert it again because
- * mac80211 will expect the the same data to be present it the
+ * mac80211 will expect the same data to be present it the
* frame as it was passed to us.
*/
if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags))
diff --git a/drivers/net/wireless/rt2x00/rt2x00dump.h b/drivers/net/wireless/rt2x00/rt2x00dump.h
index ed303b423e41..6df2e0b746b8 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dump.h
+++ b/drivers/net/wireless/rt2x00/rt2x00dump.h
@@ -20,7 +20,12 @@
/*
Module: rt2x00dump
- Abstract: Data structures for the rt2x00debug & userspace.
+ Abstract:
+ Data structures for the rt2x00debug & userspace.
+
+ The declarations in this file can be used by both rt2x00
+ and userspace and therefore should be kept together in
+ this file.
*/
#ifndef RT2X00DUMP_H
diff --git a/drivers/net/wireless/rt2x00/rt2x00ht.c b/drivers/net/wireless/rt2x00/rt2x00ht.c
index 5a407602ce3e..c004cd3a8847 100644
--- a/drivers/net/wireless/rt2x00/rt2x00ht.c
+++ b/drivers/net/wireless/rt2x00/rt2x00ht.c
@@ -44,11 +44,22 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
txdesc->mpdu_density = 0;
txdesc->ba_size = 7; /* FIXME: What value is needed? */
- txdesc->stbc = 0; /* FIXME: What value is needed? */
- txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
- if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- txdesc->mcs |= 0x08;
+ txdesc->stbc =
+ (tx_info->flags & IEEE80211_TX_CTL_STBC) >> IEEE80211_TX_CTL_STBC_SHIFT;
+
+ /*
+ * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the
+ * mcs rate to be used
+ */
+ if (txrate->flags & IEEE80211_TX_RC_MCS) {
+ txdesc->mcs = txrate->idx;
+ } else {
+ txdesc->mcs = rt2x00_get_rate_mcs(hwrate->mcs);
+ if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ txdesc->mcs |= 0x08;
+ }
+
/*
* Convert flags
@@ -84,3 +95,31 @@ void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
else
txdesc->txop = TXOP_HTTXOP;
}
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf)
+{
+ struct hw_mode_spec *spec = &rt2x00dev->spec;
+ int center_channel;
+ u16 i;
+
+ /*
+ * Initialize center channel to current channel.
+ */
+ center_channel = spec->channels[conf->channel->hw_value].channel;
+
+ /*
+ * Adjust center channel to HT40+ and HT40- operation.
+ */
+ if (conf_is_ht40_plus(conf))
+ center_channel += 2;
+ else if (conf_is_ht40_minus(conf))
+ center_channel -= (center_channel == 14) ? 1 : 2;
+
+ for (i = 0; i < spec->num_channels; i++)
+ if (spec->channels[i].channel == center_channel)
+ return i;
+
+ WARN_ON(1);
+ return conf->channel->hw_value;
+}
diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h
index be2e37fb4071..ed27de1de57b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00lib.h
+++ b/drivers/net/wireless/rt2x00/rt2x00lib.h
@@ -27,8 +27,6 @@
#ifndef RT2X00LIB_H
#define RT2X00LIB_H
-#include "rt2x00dump.h"
-
/*
* Interval defines
*/
@@ -107,13 +105,6 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev,
struct queue_entry *entry);
/**
- * rt2x00queue_unmap_skb - Unmap a skb from DMA.
- * @rt2x00dev: Pointer to &struct rt2x00_dev.
- * @skb: The skb to unmap.
- */
-void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb);
-
-/**
* rt2x00queue_free_skb - free a skb
* @rt2x00dev: Pointer to &struct rt2x00_dev.
* @skb: The skb to free.
@@ -296,8 +287,6 @@ static inline void rt2x00lib_free_firmware(struct rt2x00_dev *rt2x00dev)
#ifdef CONFIG_RT2X00_LIB_DEBUGFS
void rt2x00debug_register(struct rt2x00_dev *rt2x00dev);
void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev);
-void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type, struct sk_buff *skb);
void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc);
#else
@@ -309,12 +298,6 @@ static inline void rt2x00debug_deregister(struct rt2x00_dev *rt2x00dev)
{
}
-static inline void rt2x00debug_dump_frame(struct rt2x00_dev *rt2x00dev,
- enum rt2x00_dump_type type,
- struct sk_buff *skb)
-{
-}
-
static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev,
struct rxdone_entry_desc *rxdesc)
{
@@ -384,12 +367,21 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb,
void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate);
+
+u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf);
#else
static inline void rt2x00ht_create_tx_descriptor(struct queue_entry *entry,
struct txentry_desc *txdesc,
const struct rt2x00_rate *hwrate)
{
}
+
+static inline u16 rt2x00ht_center_channel(struct rt2x00_dev *rt2x00dev,
+ struct ieee80211_conf *conf)
+{
+ return conf->channel->hw_value;
+}
#endif /* CONFIG_RT2X00_LIB_HT */
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c
index f71eee67f977..10eaffd12b1b 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.c
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.c
@@ -81,6 +81,24 @@ int rt2x00pci_write_tx_data(struct queue_entry *entry,
return -EINVAL;
}
+ /*
+ * Add the requested extra tx headroom in front of the skb.
+ */
+ skb_push(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+ memset(entry->skb->data, 0, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
+ * Call the driver's write_tx_datadesc function, if it exists.
+ */
+ if (rt2x00dev->ops->lib->write_tx_datadesc)
+ rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
+
+ /*
+ * Map the skb to DMA.
+ */
+ if (test_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags))
+ rt2x00queue_map_txskb(rt2x00dev, entry->skb);
+
return 0;
}
EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
@@ -88,6 +106,34 @@ EXPORT_SYMBOL_GPL(rt2x00pci_write_tx_data);
/*
* TX/RX data handlers.
*/
+void rt2x00pci_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc)
+{
+ struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
+ struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
+
+ /*
+ * Unmap the skb.
+ */
+ rt2x00queue_unmap_skb(rt2x00dev, entry->skb);
+
+ /*
+ * Remove the extra tx headroom from the skb.
+ */
+ skb_pull(entry->skb, rt2x00dev->ops->extra_tx_headroom);
+
+ /*
+ * Signal that the TX descriptor is no longer in the skb.
+ */
+ skbdesc->flags &= ~SKBDESC_DESC_IN_SKB;
+
+ /*
+ * Pass on to rt2x00lib.
+ */
+ rt2x00lib_txdone(entry, txdesc);
+}
+EXPORT_SYMBOL_GPL(rt2x00pci_txdone);
+
void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev)
{
struct data_queue *queue = rt2x00dev->rx;
@@ -305,7 +351,10 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
rt2x00dev->irq = pci_dev->irq;
rt2x00dev->name = pci_name(pci_dev);
- rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
+ if (pci_dev->is_pcie)
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
+ else
+ rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCI);
retval = rt2x00pci_alloc_reg(rt2x00dev);
if (retval)
diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h
index 51bcef3839ce..00528b8a754d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00pci.h
+++ b/drivers/net/wireless/rt2x00/rt2x00pci.h
@@ -109,6 +109,14 @@ struct queue_entry_priv_pci {
};
/**
+ * rt2x00pci_txdone - Handle TX done events.
+ * @entry: The queue entry for which a TX done event was received.
+ * @txdesc: The TX done descriptor for the entry.
+ */
+void rt2x00pci_txdone(struct queue_entry *entry,
+ struct txdone_entry_desc *txdesc);
+
+/**
* rt2x00pci_rxdone - Handle RX done events
* @rt2x00dev: Device pointer, see &struct rt2x00_dev.
*/
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 20dbdd6fb904..35858b178e8f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -100,21 +100,8 @@ void rt2x00queue_map_txskb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- /*
- * If device has requested headroom, we should make sure that
- * is also mapped to the DMA so it can be used for transfering
- * additional descriptor information to the hardware.
- */
- skb_push(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->skb_dma =
dma_map_single(rt2x00dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
-
- /*
- * Restore data pointer to original location again.
- */
- skb_pull(skb, rt2x00dev->ops->extra_tx_headroom);
-
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
@@ -130,16 +117,12 @@ void rt2x00queue_unmap_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
}
if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
- /*
- * Add headroom to the skb length, it has been removed
- * by the driver, but it was actually mapped to DMA.
- */
- dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma,
- skb->len + rt2x00dev->ops->extra_tx_headroom,
+ dma_unmap_single(rt2x00dev->dev, skbdesc->skb_dma, skb->len,
DMA_TO_DEVICE);
skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
}
}
+EXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
void rt2x00queue_free_skb(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb)
{
@@ -421,7 +404,6 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
{
struct data_queue *queue = entry->queue;
struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
- enum rt2x00_dump_type dump_type;
rt2x00dev->ops->lib->write_tx_desc(rt2x00dev, entry->skb, txdesc);
@@ -429,9 +411,7 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
* All processing on the frame has been completed, this means
* it is now ready to be dumped to userspace through debugfs.
*/
- dump_type = (txdesc->queue == QID_BEACON) ?
- DUMP_FRAME_BEACON : DUMP_FRAME_TX;
- rt2x00debug_dump_frame(rt2x00dev, dump_type, entry->skb);
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_TX, entry->skb);
}
static void rt2x00queue_kick_tx_queue(struct queue_entry *entry,
@@ -537,9 +517,6 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
return -EIO;
}
- if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags))
- rt2x00queue_map_txskb(queue->rt2x00dev, skb);
-
set_bit(ENTRY_DATA_PENDING, &entry->flags);
rt2x00queue_index_inc(queue, Q_INDEX);
@@ -595,11 +572,6 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
skbdesc->entry = intf->beacon;
/*
- * Write TX descriptor into reserved room in front of the beacon.
- */
- rt2x00queue_write_tx_descriptor(intf->beacon, &txdesc);
-
- /*
* Send beacon to hardware and enable beacon genaration..
*/
rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index bd1546ba7ad2..b45bc24c3dae 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -113,26 +113,6 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev,
const u16 offset, void *buffer,
const u16 buffer_length, const int timeout)
{
- int status;
-
- mutex_lock(&rt2x00dev->csr_mutex);
-
- status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request,
- requesttype, offset, buffer,
- buffer_length, timeout);
-
- mutex_unlock(&rt2x00dev->csr_mutex);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
-
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
- const u8 request, const u8 requesttype,
- const u16 offset, const void *buffer,
- const u16 buffer_length,
- const int timeout)
-{
int status = 0;
unsigned char *tb;
u16 off, len, bsize;
@@ -157,7 +137,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
return status;
}
-EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff);
+EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_buff);
int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev,
const unsigned int offset,
@@ -198,6 +178,11 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
return;
/*
+ * Remove the descriptor from the front of the skb.
+ */
+ skb_pull(entry->skb, entry->queue->desc_size);
+
+ /*
* Obtain the status about this packet.
* Note that when the status is 0 it does not mean the
* frame was send out correctly. It only means the frame
@@ -243,10 +228,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry,
rt2x00usb_interrupt_txdone, entry);
/*
- * Make sure the skb->data pointer points to the frame, not the
- * descriptor.
+ * Call the driver's write_tx_datadesc function, if it exists.
*/
- skb_pull(entry->skb, entry->queue->desc_size);
+ if (rt2x00dev->ops->lib->write_tx_datadesc)
+ rt2x00dev->ops->lib->write_tx_datadesc(entry, txdesc);
return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h
index 621d0f829251..255b81ef9530 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.h
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.h
@@ -167,25 +167,6 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev,
const u16 buffer_length, const int timeout);
/**
- * rt2x00usb_vendor_request_large_buff - Send register command to device (buffered)
- * @rt2x00dev: Pointer to &struct rt2x00_dev
- * @request: USB vendor command (See &enum rt2x00usb_vendor_request)
- * @requesttype: Request type &USB_VENDOR_REQUEST_*
- * @offset: Register start offset to perform action on
- * @buffer: Buffer where information will be read/written to by device
- * @buffer_length: Size of &buffer
- * @timeout: Operation timeout
- *
- * This function is used to transfer register data in blocks larger
- * then CSR_CACHE_SIZE. Use for firmware upload, keys and beacons.
- */
-int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev,
- const u8 request, const u8 requesttype,
- const u16 offset, const void *buffer,
- const u16 buffer_length,
- const int timeout);
-
-/**
* rt2x00usb_vendor_request_sw - Send single register command to device
* @rt2x00dev: Pointer to &struct rt2x00_dev
* @request: USB vendor command (See &enum rt2x00usb_vendor_request)
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index 6a74baf4e934..243df08ae910 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1874,6 +1874,16 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
+ * Write the TX descriptor for the beacon.
+ */
+ rt61pci_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
+
+ /*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -2100,7 +2110,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
__set_bit(TXDONE_UNKNOWN, &txdesc.flags);
txdesc.retry = 0;
- rt2x00lib_txdone(entry_done, &txdesc);
+ rt2x00pci_txdone(entry_done, &txdesc);
entry_done = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
}
@@ -2120,7 +2130,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
}
txdesc.retry = rt2x00_get_field32(reg, STA_CSR4_RETRY_COUNT);
- rt2x00lib_txdone(entry, &txdesc);
+ rt2x00pci_txdone(entry, &txdesc);
}
}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h
index df80f1af22a4..e2e728ab0b2e 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.h
+++ b/drivers/net/wireless/rt2x00/rt61pci.h
@@ -153,13 +153,13 @@ struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct hw_pairwise_ta_entry {
u8 address[6];
u8 cipher;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* Other on-chip shared memory space.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index 6e0d82efe924..113ad690f9d3 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -270,7 +270,6 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
{
struct hw_key_entry key_entry;
struct rt2x00_field32 field;
- int timeout;
u32 mask;
u32 reg;
@@ -306,12 +305,8 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));
reg = SHARED_KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- &key_entry,
- sizeof(key_entry),
- timeout);
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
/*
* The cipher types are stored over 2 registers.
@@ -372,7 +367,6 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
{
struct hw_pairwise_ta_entry addr_entry;
struct hw_key_entry key_entry;
- int timeout;
u32 mask;
u32 reg;
@@ -407,17 +401,11 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev,
sizeof(key_entry.rx_mic));
reg = PAIRWISE_KEY_ENTRY(key->hw_key_idx);
- timeout = REGISTER_TIMEOUT32(sizeof(key_entry));
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, reg,
- &key_entry,
- sizeof(key_entry),
- timeout);
+ rt2x00usb_register_multiwrite(rt2x00dev, reg,
+ &key_entry, sizeof(key_entry));
/*
* Send the address and cipher type to the hardware register.
- * This data fits within the CSR cache size, so we can use
- * rt2x00usb_register_multiwrite() directly.
*/
memset(&addr_entry, 0, sizeof(addr_entry));
memcpy(&addr_entry, crypto->address, ETH_ALEN);
@@ -1092,11 +1080,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev,
/*
* Write firmware to device.
*/
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT,
- FIRMWARE_IMAGE_BASE,
- data, len,
- REGISTER_TIMEOUT32(len));
+ rt2x00usb_register_multiwrite(rt2x00dev, FIRMWARE_IMAGE_BASE, data, len);
/*
* Send firmware request to device to load firmware,
@@ -1442,7 +1426,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
struct txentry_desc *txdesc)
{
struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb);
- __le32 *txd = (__le32 *)(skb->data - TXD_DESC_SIZE);
+ __le32 *txd = (__le32 *) skb->data;
u32 word;
/*
@@ -1505,6 +1489,7 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev,
/*
* Register descriptor details in skb frame descriptor.
*/
+ skbdesc->flags |= SKBDESC_DESC_IN_SKB;
skbdesc->desc = txd;
skbdesc->desc_len = TXD_DESC_SIZE;
}
@@ -1528,18 +1513,27 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg);
/*
- * Take the descriptor in front of the skb into account.
+ * Add space for the descriptor in front of the skb.
*/
skb_push(entry->skb, TXD_DESC_SIZE);
+ memset(entry->skb->data, 0, TXD_DESC_SIZE);
+
+ /*
+ * Write the TX descriptor for the beacon.
+ */
+ rt73usb_write_tx_desc(rt2x00dev, entry->skb, txdesc);
+
+ /*
+ * Dump beacon to userspace through debugfs.
+ */
+ rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_BEACON, entry->skb);
/*
* Write entire beacon with descriptor to register.
*/
beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
- rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE,
- USB_VENDOR_REQUEST_OUT, beacon_base,
- entry->skb->data, entry->skb->len,
- REGISTER_TIMEOUT32(entry->skb->len));
+ rt2x00usb_register_multiwrite(rt2x00dev, beacon_base,
+ entry->skb->data, entry->skb->len);
/*
* Enable beaconing again.
diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h
index 7abe7eb14555..44d5b2bebd39 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.h
+++ b/drivers/net/wireless/rt2x00/rt73usb.h
@@ -108,13 +108,13 @@ struct hw_key_entry {
u8 key[16];
u8 tx_mic[8];
u8 rx_mic[8];
-} __attribute__ ((packed));
+} __packed;
struct hw_pairwise_ta_entry {
u8 address[6];
u8 cipher;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
/*
* Since NULL frame won't be that long (256 byte),
diff --git a/drivers/net/wireless/rtl818x/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h
index 4baf0cf0826f..30523314da43 100644
--- a/drivers/net/wireless/rtl818x/rtl8180.h
+++ b/drivers/net/wireless/rtl818x/rtl8180.h
@@ -36,7 +36,7 @@ struct rtl8180_tx_desc {
u8 agc;
u8 flags2;
u32 reserved[2];
-} __attribute__ ((packed));
+} __packed;
struct rtl8180_rx_desc {
__le32 flags;
@@ -45,7 +45,7 @@ struct rtl8180_rx_desc {
__le32 rx_buf;
__le64 tsft;
};
-} __attribute__ ((packed));
+} __packed;
struct rtl8180_tx_ring {
struct rtl8180_tx_desc *desc;
diff --git a/drivers/net/wireless/rtl818x/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h
index 6bb32112e65c..98878160a65a 100644
--- a/drivers/net/wireless/rtl818x/rtl8187.h
+++ b/drivers/net/wireless/rtl818x/rtl8187.h
@@ -47,7 +47,7 @@ struct rtl8187_rx_hdr {
u8 agc;
u8 reserved;
__le64 mac_time;
-} __attribute__((packed));
+} __packed;
struct rtl8187b_rx_hdr {
__le32 flags;
@@ -59,7 +59,7 @@ struct rtl8187b_rx_hdr {
__le16 snr_long2end;
s8 pwdb_g12;
u8 fot;
-} __attribute__((packed));
+} __packed;
/* {rtl8187,rtl8187b}_tx_info is in skb */
@@ -68,7 +68,7 @@ struct rtl8187_tx_hdr {
__le16 rts_duration;
__le16 len;
__le32 retry;
-} __attribute__((packed));
+} __packed;
struct rtl8187b_tx_hdr {
__le32 flags;
@@ -80,7 +80,7 @@ struct rtl8187b_tx_hdr {
__le32 unused_3;
__le32 retry;
__le32 unused_4[2];
-} __attribute__((packed));
+} __packed;
enum {
DEVICE_RTL8187,
diff --git a/drivers/net/wireless/rtl818x/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h
index 8522490d2e29..978519d1ff4c 100644
--- a/drivers/net/wireless/rtl818x/rtl818x.h
+++ b/drivers/net/wireless/rtl818x/rtl818x.h
@@ -185,7 +185,7 @@ struct rtl818x_csr {
u8 reserved_22[4];
__le16 TALLY_CNT;
u8 TALLY_SEL;
-} __attribute__((packed));
+} __packed;
struct rtl818x_rf_ops {
char *name;
diff --git a/drivers/net/wireless/wl12xx/Kconfig b/drivers/net/wireless/wl12xx/Kconfig
index 337fc7bec5a5..2f98058be451 100644
--- a/drivers/net/wireless/wl12xx/Kconfig
+++ b/drivers/net/wireless/wl12xx/Kconfig
@@ -41,7 +41,7 @@ config WL1251_SDIO
config WL1271
tristate "TI wl1271 support"
- depends on WL12XX && SPI_MASTER && GENERIC_HARDIRQS
+ depends on WL12XX && GENERIC_HARDIRQS
depends on INET
select FW_LOADER
select CRC7
@@ -65,7 +65,7 @@ config WL1271_SPI
config WL1271_SDIO
tristate "TI wl1271 SDIO support"
- depends on WL1271 && MMC && ARM
+ depends on WL1271 && MMC
---help---
This module adds support for the SDIO interface of adapters using
TI wl1271 chipset. Select this if your platform is using
diff --git a/drivers/net/wireless/wl12xx/wl1251_acx.h b/drivers/net/wireless/wl12xx/wl1251_acx.h
index 26160c45784c..842df310d92a 100644
--- a/drivers/net/wireless/wl12xx/wl1251_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_acx.h
@@ -60,7 +60,7 @@ struct acx_error_counter {
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
u32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
struct acx_revision {
struct acx_header header;
@@ -89,7 +89,7 @@ struct acx_revision {
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
u32 hw_version;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_psm_mode {
/* Active mode */
@@ -111,7 +111,7 @@ struct acx_sleep_auth {
/* 2 - ELP mode: Deep / Max sleep*/
u8 sleep_auth;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -159,7 +159,7 @@ struct acx_data_path_params {
* complete ring until an interrupt is generated.
*/
u32 tx_complete_timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_data_path_params_resp {
@@ -180,7 +180,7 @@ struct acx_data_path_params_resp {
u32 tx_control_addr;
u32 tx_complete_addr;
-} __attribute__ ((packed));
+} __packed;
#define TX_MSDU_LIFETIME_MIN 0
#define TX_MSDU_LIFETIME_MAX 3000
@@ -197,7 +197,7 @@ struct acx_rx_msdu_lifetime {
* firmware discards the MSDU.
*/
u32 lifetime;
-} __attribute__ ((packed));
+} __packed;
/*
* RX Config Options Table
@@ -285,7 +285,7 @@ struct acx_rx_config {
u32 config_options;
u32 filter_options;
-} __attribute__ ((packed));
+} __packed;
enum {
QOS_AC_BE = 0,
@@ -325,13 +325,13 @@ struct acx_tx_queue_qos_config {
/* Lowest memory blocks guaranteed for this queue */
u16 low_threshold;
-} __attribute__ ((packed));
+} __packed;
struct acx_packet_detection {
struct acx_header header;
u32 threshold;
-} __attribute__ ((packed));
+} __packed;
enum acx_slot_type {
@@ -349,7 +349,7 @@ struct acx_slot {
u8 wone_index; /* Reserved */
u8 slot_time;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define ADDRESS_GROUP_MAX (8)
@@ -362,7 +362,7 @@ struct acx_dot11_grp_addr_tbl {
u8 num_groups;
u8 pad[2];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
#define RX_TIMEOUT_PS_POLL_MIN 0
@@ -388,7 +388,7 @@ struct acx_rx_timeout {
* from an UPSD enabled queue.
*/
u16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
#define RTS_THRESHOLD_MIN 0
#define RTS_THRESHOLD_MAX 4096
@@ -399,7 +399,7 @@ struct acx_rts_threshold {
u16 threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
@@ -415,7 +415,7 @@ struct acx_beacon_filter_option {
*/
u8 max_num_beacons;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/*
* ACXBeaconFilterEntry (not 221)
@@ -461,7 +461,7 @@ struct acx_beacon_filter_ie_table {
u8 num_ie;
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
#define SYNCH_FAIL_DEFAULT_THRESHOLD 10 /* number of beacons */
#define NO_BEACON_DEFAULT_TIMEOUT (500) /* in microseconds */
@@ -494,7 +494,7 @@ struct acx_bt_wlan_coex {
*/
u8 enable;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
#define PTA_ANTENNA_TYPE_DEF (0)
#define PTA_BT_HP_MAXTIME_DEF (2000)
@@ -648,7 +648,7 @@ struct acx_bt_wlan_coex_param {
/* range: 0 - 20 default: 1 */
u8 bt_hp_respected_num;
-} __attribute__ ((packed));
+} __packed;
#define CCA_THRSH_ENABLE_ENERGY_D 0x140A
#define CCA_THRSH_DISABLE_ENERGY_D 0xFFEF
@@ -660,7 +660,7 @@ struct acx_energy_detection {
u16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
-} __attribute__ ((packed));
+} __packed;
#define BCN_RX_TIMEOUT_DEF_VALUE 10000
#define BROADCAST_RX_TIMEOUT_DEF_VALUE 20000
@@ -679,14 +679,14 @@ struct acx_beacon_broadcast {
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_event_mask {
struct acx_header header;
u32 event_mask;
u32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
#define CFG_RX_FCS BIT(2)
#define CFG_RX_ALL_GOOD BIT(3)
@@ -729,7 +729,7 @@ struct acx_fw_gen_frame_rates {
u8 tx_ctrl_frame_mod; /* CCK_* or PBCC_* */
u8 tx_mgt_frame_rate;
u8 tx_mgt_frame_mod;
-} __attribute__ ((packed));
+} __packed;
/* STA MAC */
struct acx_dot11_station_id {
@@ -737,28 +737,28 @@ struct acx_dot11_station_id {
u8 mac[ETH_ALEN];
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_feature_config {
struct acx_header header;
u32 options;
u32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_current_tx_power {
struct acx_header header;
u8 current_tx_power;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_dot11_default_key {
struct acx_header header;
u8 id;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tsf_info {
struct acx_header header;
@@ -769,7 +769,7 @@ struct acx_tsf_info {
u32 last_TBTT_lsb;
u8 last_dtim_count;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_wake_up_event {
WAKE_UP_EVENT_BEACON_BITMAP = 0x01, /* Wake on every Beacon*/
@@ -785,7 +785,7 @@ struct acx_wake_up_condition {
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_aid {
struct acx_header header;
@@ -795,7 +795,7 @@ struct acx_aid {
*/
u16 aid;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
enum acx_preamble_type {
ACX_PREAMBLE_LONG = 0,
@@ -811,7 +811,7 @@ struct acx_preamble {
*/
u8 preamble;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_ctsprotect_type {
CTSPROTECT_DISABLE = 0,
@@ -822,11 +822,11 @@ struct acx_ctsprotect {
struct acx_header header;
u8 ctsprotect;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_statistics {
u32 internal_desc_overflow;
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_statistics {
u32 out_of_mem;
@@ -837,14 +837,14 @@ struct acx_rx_statistics {
u32 xfr_hint_trig;
u32 path_reset;
u32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
struct acx_dma_statistics {
u32 rx_requested;
u32 rx_errors;
u32 tx_requested;
u32 tx_errors;
-} __attribute__ ((packed));
+} __packed;
struct acx_isr_statistics {
/* host command complete */
@@ -903,7 +903,7 @@ struct acx_isr_statistics {
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
u32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
struct acx_wep_statistics {
/* WEP address keys configured */
@@ -925,7 +925,7 @@ struct acx_wep_statistics {
/* WEP decrypt interrupts */
u32 interrupt;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MISSED_BEACONS_SPREAD 10
@@ -985,12 +985,12 @@ struct acx_pwr_statistics {
/* the number of beacons in awake mode */
u32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
struct acx_mic_statistics {
u32 rx_pkts;
u32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
struct acx_aes_statistics {
u32 encrypt_fail;
@@ -999,7 +999,7 @@ struct acx_aes_statistics {
u32 decrypt_packets;
u32 encrypt_interrupt;
u32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
struct acx_event_statistics {
u32 heart_beat;
@@ -1010,7 +1010,7 @@ struct acx_event_statistics {
u32 oom_late;
u32 phy_transmit_error;
u32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
struct acx_ps_statistics {
u32 pspoll_timeouts;
@@ -1020,7 +1020,7 @@ struct acx_ps_statistics {
u32 pspoll_max_apturn;
u32 pspoll_utilization;
u32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
struct acx_rxpipe_statistics {
u32 rx_prep_beacon_drop;
@@ -1028,7 +1028,7 @@ struct acx_rxpipe_statistics {
u32 beacon_buffer_thres_host_int_trig_rx_data;
u32 missed_beacon_host_int_trig_rx_data;
u32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
struct acx_statistics {
struct acx_header header;
@@ -1044,7 +1044,7 @@ struct acx_statistics {
struct acx_event_statistics event;
struct acx_ps_statistics ps;
struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MAX_RATE_CLASSES 8
#define ACX_RATE_MASK_UNSPECIFIED 0
@@ -1063,7 +1063,7 @@ struct acx_rate_policy {
u32 rate_class_cnt;
struct acx_rate_class rate_class[ACX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_memory {
__le16 num_stations; /* number of STAs to be supported. */
@@ -1082,7 +1082,7 @@ struct wl1251_acx_memory {
u8 tx_min_mem_block_num;
u8 num_ssid_profiles;
__le16 debug_buffer_size;
-} __attribute__ ((packed));
+} __packed;
#define ACX_RX_DESC_MIN 1
@@ -1094,7 +1094,7 @@ struct wl1251_acx_rx_queue_config {
u8 type;
u8 priority;
__le32 dma_address;
-} __attribute__ ((packed));
+} __packed;
#define ACX_TX_DESC_MIN 1
#define ACX_TX_DESC_MAX 127
@@ -1103,7 +1103,7 @@ struct wl1251_acx_tx_queue_config {
u8 num_descs;
u8 pad[2];
u8 attributes;
-} __attribute__ ((packed));
+} __packed;
#define MAX_TX_QUEUE_CONFIGS 5
#define MAX_TX_QUEUES 4
@@ -1113,7 +1113,7 @@ struct wl1251_acx_config_memory {
struct wl1251_acx_memory mem_config;
struct wl1251_acx_rx_queue_config rx_queue_config;
struct wl1251_acx_tx_queue_config tx_queue_config[MAX_TX_QUEUE_CONFIGS];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_mem_map {
struct acx_header header;
@@ -1147,7 +1147,7 @@ struct wl1251_acx_mem_map {
/* Number of blocks FW allocated for RX packets */
u32 num_rx_mem_blocks;
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_wr_tbtt_and_dtim {
@@ -1164,7 +1164,7 @@ struct wl1251_acx_wr_tbtt_and_dtim {
*/
u8 dtim;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
struct wl1251_acx_ac_cfg {
struct acx_header header;
@@ -1194,7 +1194,7 @@ struct wl1251_acx_ac_cfg {
/* The TX Op Limit (in microseconds) for the access class. */
u16 txop_limit;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_acx_channel_type {
@@ -1245,7 +1245,7 @@ struct wl1251_acx_tid_cfg {
/* not supported */
u32 apsdconf[2];
-} __attribute__ ((packed));
+} __packed;
/*************************************************************************
diff --git a/drivers/net/wireless/wl12xx/wl1251_cmd.h b/drivers/net/wireless/wl12xx/wl1251_cmd.h
index 4ad67cae94d2..7e70dd5a21b8 100644
--- a/drivers/net/wireless/wl12xx/wl1251_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1251_cmd.h
@@ -106,7 +106,7 @@ struct wl1251_cmd_header {
u16 status;
/* payload */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_command {
struct wl1251_cmd_header header;
@@ -201,7 +201,7 @@ struct wl1251_scan_parameters {
u8 ssid_len;
u8 ssid[32];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_scan_ch_parameters {
u32 min_duration; /* in TU */
@@ -218,7 +218,7 @@ struct wl1251_scan_ch_parameters {
u8 tx_power_att;
u8 channel;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
/* SCAN parameters */
#define SCAN_MAX_NUM_OF_CHANNELS 16
@@ -228,7 +228,7 @@ struct wl1251_cmd_scan {
struct wl1251_scan_parameters params;
struct wl1251_scan_ch_parameters channels[SCAN_MAX_NUM_OF_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
enum {
BSS_TYPE_IBSS = 0,
@@ -276,14 +276,14 @@ struct cmd_join {
u8 tx_mgt_frame_rate; /* OBSOLETE */
u8 tx_mgt_frame_mod; /* OBSOLETE */
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct cmd_enabledisable_path {
struct wl1251_cmd_header header;
u8 channel;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define WL1251_MAX_TEMPLATE_SIZE 300
@@ -292,7 +292,7 @@ struct wl1251_cmd_packet_template {
__le16 size;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define TIM_ELE_ID 5
#define PARTIAL_VBM_MAX 251
@@ -304,7 +304,7 @@ struct wl1251_tim {
u8 dtim_period;
u8 bitmap_ctrl;
u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
/* Virtual Bit Map update */
struct wl1251_cmd_vbm_update {
@@ -312,7 +312,7 @@ struct wl1251_cmd_vbm_update {
__le16 len;
u8 padding[2];
struct wl1251_tim tim;
-} __attribute__ ((packed));
+} __packed;
enum wl1251_cmd_ps_mode {
STATION_ACTIVE_MODE,
@@ -333,7 +333,7 @@ struct wl1251_cmd_ps_params {
u8 hang_over_period;
u16 null_data_rate;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct wl1251_cmd_trigger_scan_to {
struct wl1251_cmd_header header;
@@ -411,7 +411,7 @@ struct wl1251_cmd_set_keys {
u8 key[MAX_KEY_SIZE];
u16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
u32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
+} __packed;
#endif /* __WL1251_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1251_event.h b/drivers/net/wireless/wl12xx/wl1251_event.h
index be0ac54d6246..f48a2b66bc5a 100644
--- a/drivers/net/wireless/wl12xx/wl1251_event.h
+++ b/drivers/net/wireless/wl12xx/wl1251_event.h
@@ -82,7 +82,7 @@ struct event_debug_report {
u32 report_1;
u32 report_2;
u32 report_3;
-} __attribute__ ((packed));
+} __packed;
struct event_mailbox {
u32 events_vector;
@@ -112,7 +112,7 @@ struct event_mailbox {
struct event_debug_report report;
u8 average_snr_level;
u8 padding[19];
-} __attribute__ ((packed));
+} __packed;
int wl1251_event_unmask(struct wl1251 *wl);
void wl1251_event_mbox_config(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 00b24282fc73..c8f268951e10 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -124,7 +124,7 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
}
wl->nvs_len = fw->size;
- wl->nvs = kmalloc(wl->nvs_len, GFP_KERNEL);
+ wl->nvs = kmemdup(fw->data, wl->nvs_len, GFP_KERNEL);
if (!wl->nvs) {
wl1251_error("could not allocate memory for the nvs file");
@@ -132,8 +132,6 @@ static int wl1251_fetch_nvs(struct wl1251 *wl)
goto out;
}
- memcpy(wl->nvs, fw->data, wl->nvs_len);
-
ret = 0;
out:
diff --git a/drivers/net/wireless/wl12xx/wl1251_rx.h b/drivers/net/wireless/wl12xx/wl1251_rx.h
index 563a3fde40fb..da4e53406a0e 100644
--- a/drivers/net/wireless/wl12xx/wl1251_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_rx.h
@@ -117,7 +117,7 @@ struct wl1251_rx_descriptor {
s8 rssi; /* in dB */
u8 rcpi; /* in dB */
u8 snr; /* in dB */
-} __attribute__ ((packed));
+} __packed;
void wl1251_rx(struct wl1251 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1251_sdio.c b/drivers/net/wireless/wl12xx/wl1251_sdio.c
index d234285c2c81..c561332e7009 100644
--- a/drivers/net/wireless/wl12xx/wl1251_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1251_sdio.c
@@ -259,6 +259,7 @@ disable:
sdio_disable_func(func);
release:
sdio_release_host(func);
+ wl1251_free_hw(wl);
return ret;
}
diff --git a/drivers/net/wireless/wl12xx/wl1251_tx.h b/drivers/net/wireless/wl12xx/wl1251_tx.h
index 55856c6bb97a..65c4be8c2e80 100644
--- a/drivers/net/wireless/wl12xx/wl1251_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1251_tx.h
@@ -109,7 +109,7 @@ struct tx_control {
unsigned xfer_pad:1;
unsigned reserved:7;
-} __attribute__ ((packed));
+} __packed;
struct tx_double_buffer_desc {
@@ -156,7 +156,7 @@ struct tx_double_buffer_desc {
u8 num_mem_blocks;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
enum {
TX_SUCCESS = 0,
@@ -208,7 +208,7 @@ struct tx_result {
/* See done_1 */
u8 done_2;
-} __attribute__ ((packed));
+} __packed;
static inline int wl1251_tx_get_queue(int queue)
{
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 6f1b6b5640c0..ec09f0d40ca2 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -33,6 +33,7 @@
#include <net/mac80211.h>
#include "wl1271_conf.h"
+#include "wl1271_ini.h"
#define DRIVER_NAME "wl1271"
#define DRIVER_PREFIX DRIVER_NAME ": "
@@ -116,33 +117,6 @@ enum {
#define WL1271_TX_SECURITY_LO16(s) ((u16)((s) & 0xffff))
#define WL1271_TX_SECURITY_HI32(s) ((u32)(((s) >> 16) & 0xffffffff))
-/* NVS data structure */
-#define WL1271_NVS_SECTION_SIZE 468
-
-#define WL1271_NVS_GENERAL_PARAMS_SIZE 57
-#define WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED \
- (WL1271_NVS_GENERAL_PARAMS_SIZE + 1)
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE 17
-#define WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED \
- (WL1271_NVS_STAT_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE 65
-#define WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED \
- (WL1271_NVS_DYN_RADIO_PARAMS_SIZE + 1)
-#define WL1271_NVS_FEM_COUNT 2
-#define WL1271_NVS_INI_SPARE_SIZE 124
-
-struct wl1271_nvs_file {
- /* NVS section */
- u8 nvs[WL1271_NVS_SECTION_SIZE];
-
- /* INI section */
- u8 general_params[WL1271_NVS_GENERAL_PARAMS_SIZE_PADDED];
- u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE_PADDED];
- u8 dyn_radio_params[WL1271_NVS_FEM_COUNT]
- [WL1271_NVS_DYN_RADIO_PARAMS_SIZE_PADDED];
- u8 ini_spare[WL1271_NVS_INI_SPARE_SIZE];
-} __attribute__ ((packed));
-
/*
* Enable/disable 802.11a support for WL1273
*/
@@ -317,7 +291,7 @@ struct wl1271_fw_status {
__le32 tx_released_blks[NUM_TX_QUEUES];
__le32 fw_localtime;
__le32 padding[2];
-} __attribute__ ((packed));
+} __packed;
struct wl1271_rx_mem_pool_addr {
u32 addr;
@@ -325,6 +299,7 @@ struct wl1271_rx_mem_pool_addr {
};
struct wl1271_scan {
+ struct cfg80211_scan_request *req;
u8 state;
u8 ssid[IW_ESSID_MAX_SIZE+1];
size_t ssid_len;
@@ -375,6 +350,7 @@ struct wl1271 {
#define WL1271_FLAG_IRQ_PENDING (9)
#define WL1271_FLAG_IRQ_RUNNING (10)
#define WL1271_FLAG_IDLE (11)
+#define WL1271_FLAG_IDLE_REQUESTED (12)
unsigned long flags;
struct wl1271_partition_set part;
@@ -421,6 +397,7 @@ struct wl1271 {
/* Pending TX frames */
struct sk_buff *tx_frames[ACX_TX_DESCRIPTORS];
+ int tx_frames_cnt;
/* Security sequence number counters */
u8 tx_security_last_seq;
diff --git a/drivers/net/wireless/wl12xx/wl1271_acx.h b/drivers/net/wireless/wl12xx/wl1271_acx.h
index 420e7e2fc021..4c87e601df2f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_acx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_acx.h
@@ -75,7 +75,7 @@ struct acx_header {
/* payload length (not including headers */
__le16 len;
-} __attribute__ ((packed));
+} __packed;
struct acx_error_counter {
struct acx_header header;
@@ -98,7 +98,7 @@ struct acx_error_counter {
/* the number of missed sequence numbers in the squentially */
/* values of frames seq numbers */
__le32 seq_num_miss;
-} __attribute__ ((packed));
+} __packed;
struct acx_revision {
struct acx_header header;
@@ -127,7 +127,7 @@ struct acx_revision {
* bits 24 - 31: Chip ID - The WiLink chip ID.
*/
__le32 hw_version;
-} __attribute__ ((packed));
+} __packed;
enum wl1271_psm_mode {
/* Active mode */
@@ -149,7 +149,7 @@ struct acx_sleep_auth {
/* 2 - ELP mode: Deep / Max sleep*/
u8 sleep_auth;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
HOSTIF_PCI_MASTER_HOST_INDIRECT,
@@ -187,7 +187,7 @@ struct acx_rx_msdu_lifetime {
* firmware discards the MSDU.
*/
__le32 lifetime;
-} __attribute__ ((packed));
+} __packed;
/*
* RX Config Options Table
@@ -275,13 +275,13 @@ struct acx_rx_config {
__le32 config_options;
__le32 filter_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_packet_detection {
struct acx_header header;
__le32 threshold;
-} __attribute__ ((packed));
+} __packed;
enum acx_slot_type {
@@ -299,7 +299,7 @@ struct acx_slot {
u8 wone_index; /* Reserved */
u8 slot_time;
u8 reserved[6];
-} __attribute__ ((packed));
+} __packed;
#define ACX_MC_ADDRESS_GROUP_MAX (8)
@@ -312,21 +312,21 @@ struct acx_dot11_grp_addr_tbl {
u8 num_groups;
u8 pad[2];
u8 mac_table[ADDRESS_GROUP_MAX_LEN];
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_timeout {
struct acx_header header;
__le16 ps_poll_timeout;
__le16 upsd_timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_rts_threshold {
struct acx_header header;
__le16 threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_filter_option {
struct acx_header header;
@@ -342,7 +342,7 @@ struct acx_beacon_filter_option {
*/
u8 max_num_beacons;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
/*
* ACXBeaconFilterEntry (not 221)
@@ -383,21 +383,21 @@ struct acx_beacon_filter_ie_table {
u8 num_ie;
u8 pad[3];
u8 table[BEACON_FILTER_TABLE_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct acx_conn_monit_params {
struct acx_header header;
__le32 synch_fail_thold; /* number of beacons missed */
__le32 bss_lose_timeout; /* number of TU's from synch fail */
-} __attribute__ ((packed));
+} __packed;
struct acx_bt_wlan_coex {
struct acx_header header;
u8 enable;
u8 pad[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_bt_wlan_coex_param {
struct acx_header header;
@@ -405,7 +405,7 @@ struct acx_bt_wlan_coex_param {
__le32 params[CONF_SG_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_dco_itrim_params {
struct acx_header header;
@@ -413,7 +413,7 @@ struct acx_dco_itrim_params {
u8 enable;
u8 padding[3];
__le32 timeout;
-} __attribute__ ((packed));
+} __packed;
struct acx_energy_detection {
struct acx_header header;
@@ -422,7 +422,7 @@ struct acx_energy_detection {
__le16 rx_cca_threshold;
u8 tx_energy_detection;
u8 pad;
-} __attribute__ ((packed));
+} __packed;
struct acx_beacon_broadcast {
struct acx_header header;
@@ -436,14 +436,14 @@ struct acx_beacon_broadcast {
/* Consecutive PS Poll failures before updating the host */
u8 ps_poll_threshold;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_event_mask {
struct acx_header header;
__le32 event_mask;
__le32 high_event_mask; /* Unused */
-} __attribute__ ((packed));
+} __packed;
#define CFG_RX_FCS BIT(2)
#define CFG_RX_ALL_GOOD BIT(3)
@@ -488,14 +488,14 @@ struct acx_feature_config {
__le32 options;
__le32 data_flow_options;
-} __attribute__ ((packed));
+} __packed;
struct acx_current_tx_power {
struct acx_header header;
u8 current_tx_power;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_wake_up_condition {
struct acx_header header;
@@ -503,7 +503,7 @@ struct acx_wake_up_condition {
u8 wake_up_event; /* Only one bit can be set */
u8 listen_interval;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_aid {
struct acx_header header;
@@ -513,7 +513,7 @@ struct acx_aid {
*/
__le16 aid;
u8 pad[2];
-} __attribute__ ((packed));
+} __packed;
enum acx_preamble_type {
ACX_PREAMBLE_LONG = 0,
@@ -529,7 +529,7 @@ struct acx_preamble {
*/
u8 preamble;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum acx_ctsprotect_type {
CTSPROTECT_DISABLE = 0,
@@ -540,11 +540,11 @@ struct acx_ctsprotect {
struct acx_header header;
u8 ctsprotect;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_statistics {
__le32 internal_desc_overflow;
-} __attribute__ ((packed));
+} __packed;
struct acx_rx_statistics {
__le32 out_of_mem;
@@ -555,14 +555,14 @@ struct acx_rx_statistics {
__le32 xfr_hint_trig;
__le32 path_reset;
__le32 reset_counter;
-} __attribute__ ((packed));
+} __packed;
struct acx_dma_statistics {
__le32 rx_requested;
__le32 rx_errors;
__le32 tx_requested;
__le32 tx_errors;
-} __attribute__ ((packed));
+} __packed;
struct acx_isr_statistics {
/* host command complete */
@@ -621,7 +621,7 @@ struct acx_isr_statistics {
/* (INT_STS_ND & INT_TRIG_LOW_RSSI) */
__le32 low_rssi;
-} __attribute__ ((packed));
+} __packed;
struct acx_wep_statistics {
/* WEP address keys configured */
@@ -643,7 +643,7 @@ struct acx_wep_statistics {
/* WEP decrypt interrupts */
__le32 interrupt;
-} __attribute__ ((packed));
+} __packed;
#define ACX_MISSED_BEACONS_SPREAD 10
@@ -703,12 +703,12 @@ struct acx_pwr_statistics {
/* the number of beacons in awake mode */
__le32 rcvd_awake_beacons;
-} __attribute__ ((packed));
+} __packed;
struct acx_mic_statistics {
__le32 rx_pkts;
__le32 calc_failure;
-} __attribute__ ((packed));
+} __packed;
struct acx_aes_statistics {
__le32 encrypt_fail;
@@ -717,7 +717,7 @@ struct acx_aes_statistics {
__le32 decrypt_packets;
__le32 encrypt_interrupt;
__le32 decrypt_interrupt;
-} __attribute__ ((packed));
+} __packed;
struct acx_event_statistics {
__le32 heart_beat;
@@ -728,7 +728,7 @@ struct acx_event_statistics {
__le32 oom_late;
__le32 phy_transmit_error;
__le32 tx_stuck;
-} __attribute__ ((packed));
+} __packed;
struct acx_ps_statistics {
__le32 pspoll_timeouts;
@@ -738,7 +738,7 @@ struct acx_ps_statistics {
__le32 pspoll_max_apturn;
__le32 pspoll_utilization;
__le32 upsd_utilization;
-} __attribute__ ((packed));
+} __packed;
struct acx_rxpipe_statistics {
__le32 rx_prep_beacon_drop;
@@ -746,7 +746,7 @@ struct acx_rxpipe_statistics {
__le32 beacon_buffer_thres_host_int_trig_rx_data;
__le32 missed_beacon_host_int_trig_rx_data;
__le32 tx_xfr_host_int_trig_rx_data;
-} __attribute__ ((packed));
+} __packed;
struct acx_statistics {
struct acx_header header;
@@ -762,7 +762,7 @@ struct acx_statistics {
struct acx_event_statistics event;
struct acx_ps_statistics ps;
struct acx_rxpipe_statistics rxpipe;
-} __attribute__ ((packed));
+} __packed;
struct acx_rate_class {
__le32 enabled_rates;
@@ -780,7 +780,7 @@ struct acx_rate_policy {
__le32 rate_class_cnt;
struct acx_rate_class rate_class[CONF_TX_MAX_RATE_CLASSES];
-} __attribute__ ((packed));
+} __packed;
struct acx_ac_cfg {
struct acx_header header;
@@ -790,7 +790,7 @@ struct acx_ac_cfg {
u8 aifsn;
u8 reserved;
__le16 tx_op_limit;
-} __attribute__ ((packed));
+} __packed;
struct acx_tid_config {
struct acx_header header;
@@ -801,19 +801,19 @@ struct acx_tid_config {
u8 ack_policy;
u8 padding[3];
__le32 apsd_conf[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_frag_threshold {
struct acx_header header;
__le16 frag_threshold;
u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
struct acx_tx_config_options {
struct acx_header header;
__le16 tx_compl_timeout; /* msec */
__le16 tx_compl_threshold; /* number of packets */
-} __attribute__ ((packed));
+} __packed;
#define ACX_RX_MEM_BLOCKS 70
#define ACX_TX_MIN_MEM_BLOCKS 40
@@ -828,7 +828,7 @@ struct wl1271_acx_config_memory {
u8 num_stations;
u8 num_ssid_profiles;
__le32 total_tx_descriptors;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_mem_map {
struct acx_header header;
@@ -872,7 +872,7 @@ struct wl1271_acx_mem_map {
u8 *rx_cbuf;
__le32 rx_ctrl;
__le32 tx_ctrl;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_rx_config_opt {
struct acx_header header;
@@ -882,7 +882,7 @@ struct wl1271_acx_rx_config_opt {
__le16 timeout;
u8 queue_type;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_bet_enable {
@@ -891,7 +891,7 @@ struct wl1271_acx_bet_enable {
u8 enable;
u8 max_consecutive;
u8 padding[2];
-} __attribute__ ((packed));
+} __packed;
#define ACX_IPV4_VERSION 4
#define ACX_IPV6_VERSION 6
@@ -905,7 +905,7 @@ struct wl1271_acx_arp_filter {
requests directed to this IP address will pass
through. For IPv4, the first four bytes are
used. */
-} __attribute__((packed));
+} __packed;
struct wl1271_acx_pm_config {
struct acx_header header;
@@ -913,14 +913,14 @@ struct wl1271_acx_pm_config {
__le32 host_clk_settling_time;
u8 host_fast_wakeup_support;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
struct wl1271_acx_keep_alive_mode {
struct acx_header header;
u8 enabled;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum {
ACX_KEEP_ALIVE_NO_TX = 0,
@@ -940,7 +940,7 @@ struct wl1271_acx_keep_alive_config {
u8 tpl_validation;
u8 trigger;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
enum {
WL1271_ACX_TRIG_TYPE_LEVEL = 0,
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 19393e236e2c..530678e45a13 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -212,8 +212,8 @@ int wl1271_cmd_general_parms(struct wl1271 *wl)
gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
- memcpy(gen_parms->params, wl->nvs->general_params,
- WL1271_NVS_GENERAL_PARAMS_SIZE);
+ memcpy(&gen_parms->general_params, &wl->nvs->general_params,
+ sizeof(struct wl1271_ini_general_params));
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), 0);
if (ret < 0)
@@ -238,13 +238,20 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl)
radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
- memcpy(radio_parms->stat_radio_params, wl->nvs->stat_radio_params,
- WL1271_NVS_STAT_RADIO_PARAMS_SIZE);
- memcpy(radio_parms->dyn_radio_params,
- wl->nvs->dyn_radio_params[rparam->fem],
- WL1271_NVS_DYN_RADIO_PARAMS_SIZE);
-
- /* FIXME: current NVS is missing 5GHz parameters */
+ /* 2.4GHz parameters */
+ memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
+ sizeof(struct wl1271_ini_band_params_2));
+ memcpy(&radio_parms->dyn_params_2,
+ &wl->nvs->dyn_radio_params_2[rparam->fem].params,
+ sizeof(struct wl1271_ini_fem_params_2));
+
+ /* 5GHz parameters */
+ memcpy(&radio_parms->static_params_5,
+ &wl->nvs->stat_radio_params_5,
+ sizeof(struct wl1271_ini_band_params_5));
+ memcpy(&radio_parms->dyn_params_5,
+ &wl->nvs->dyn_radio_params_5[rparam->fem].params,
+ sizeof(struct wl1271_ini_fem_params_5));
wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
radio_parms, sizeof(*radio_parms));
@@ -329,12 +336,6 @@ int wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
join->channel = wl->channel;
join->ssid_len = wl->ssid_len;
memcpy(join->ssid, wl->ssid, wl->ssid_len);
- join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH;
-
- /* increment the session counter */
- wl->session_counter++;
- if (wl->session_counter >= SESSION_COUNTER_MAX)
- wl->session_counter = 0;
join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
@@ -517,7 +518,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send)
ps_params->send_null_data = send;
ps_params->retries = 5;
ps_params->hang_over_period = 1;
- ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */
+ ps_params->null_data_rate = cpu_to_le32(wl->basic_rate_set);
ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
sizeof(*ps_params), 0);
@@ -567,7 +568,7 @@ out:
}
int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 active_scan,
+ struct cfg80211_scan_request *req, u8 active_scan,
u8 high_prio, u8 band, u8 probe_requests)
{
@@ -648,7 +649,7 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
}
ret = wl1271_cmd_build_probe_req(wl, ssid, ssid_len,
- ie, ie_len, ieee_band);
+ req->ie, req->ie_len, ieee_band);
if (ret < 0) {
wl1271_error("PROBE request template failed");
goto out;
@@ -684,7 +685,9 @@ int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
memcpy(wl->scan.ssid, ssid, ssid_len);
} else
wl->scan.ssid_len = 0;
- }
+ wl->scan.req = req;
+ } else
+ wl->scan.req = NULL;
}
ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params), 0);
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.h b/drivers/net/wireless/wl12xx/wl1271_cmd.h
index f2820b42a943..f5745d829c9b 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.h
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.h
@@ -42,7 +42,7 @@ int wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode, bool send);
int wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer,
size_t len);
int wl1271_cmd_scan(struct wl1271 *wl, const u8 *ssid, size_t ssid_len,
- const u8 *ie, size_t ie_len, u8 active_scan,
+ struct cfg80211_scan_request *req, u8 active_scan,
u8 high_prio, u8 band, u8 probe_requests);
int wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
void *buf, size_t buf_len, int index, u32 rates);
@@ -136,14 +136,14 @@ struct wl1271_cmd_header {
__le16 status;
/* payload */
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
#define WL1271_CMD_MAX_PARAMS 572
struct wl1271_command {
struct wl1271_cmd_header header;
u8 parameters[WL1271_CMD_MAX_PARAMS];
-} __attribute__ ((packed));
+} __packed;
enum {
CMD_MAILBOX_IDLE = 0,
@@ -196,7 +196,7 @@ struct cmd_read_write_memory {
of this field is the Host in WRITE command or the Wilink in READ
command. */
u8 value[MAX_READ_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define CMDMBOX_HEADER_LEN 4
#define CMDMBOX_INFO_ELEM_HEADER_LEN 4
@@ -243,14 +243,14 @@ struct wl1271_cmd_join {
u8 ssid[IW_ESSID_MAX_SIZE];
u8 ctrl; /* JOIN_CMD_CTRL_* */
u8 reserved[3];
-} __attribute__ ((packed));
+} __packed;
struct cmd_enabledisable_path {
struct wl1271_cmd_header header;
u8 channel;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define WL1271_RATE_AUTOMATIC 0
@@ -266,7 +266,7 @@ struct wl1271_cmd_template_set {
u8 aflags;
u8 reserved;
u8 template_data[WL1271_CMD_TEMPL_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
#define TIM_ELE_ID 5
#define PARTIAL_VBM_MAX 251
@@ -278,7 +278,7 @@ struct wl1271_tim {
u8 dtim_period;
u8 bitmap_ctrl;
u8 pvb_field[PARTIAL_VBM_MAX]; /* Partial Virtual Bitmap */
-} __attribute__ ((packed));
+} __packed;
enum wl1271_cmd_ps_mode {
STATION_ACTIVE_MODE,
@@ -298,7 +298,7 @@ struct wl1271_cmd_ps_params {
*/
u8 hang_over_period;
__le32 null_data_rate;
-} __attribute__ ((packed));
+} __packed;
/* HW encryption keys */
#define NUM_ACCESS_CATEGORIES_COPY 4
@@ -348,7 +348,7 @@ struct wl1271_cmd_set_keys {
u8 key[MAX_KEY_SIZE];
__le16 ac_seq_num16[NUM_ACCESS_CATEGORIES_COPY];
__le32 ac_seq_num32[NUM_ACCESS_CATEGORIES_COPY];
-} __attribute__ ((packed));
+} __packed;
#define WL1271_SCAN_MAX_CHANNELS 24
@@ -385,7 +385,7 @@ struct basic_scan_params {
u8 use_ssid_list;
u8 scan_tag;
u8 padding2;
-} __attribute__ ((packed));
+} __packed;
struct basic_scan_channel_params {
/* Duration in TU to wait for frames on a channel for active scan */
@@ -400,25 +400,25 @@ struct basic_scan_channel_params {
u8 dfs_candidate;
u8 activity_detected;
u8 pad;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_scan {
struct wl1271_cmd_header header;
struct basic_scan_params params;
struct basic_scan_channel_params channels[WL1271_SCAN_MAX_CHANNELS];
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_trigger_scan_to {
struct wl1271_cmd_header header;
__le32 timeout;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_test_header {
u8 id;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
enum wl1271_channel_tune_bands {
WL1271_CHANNEL_TUNE_BAND_2_4,
@@ -439,25 +439,31 @@ struct wl1271_general_parms_cmd {
struct wl1271_cmd_test_header test;
- u8 params[WL1271_NVS_GENERAL_PARAMS_SIZE];
- s8 reserved[23];
-} __attribute__ ((packed));
+ struct wl1271_ini_general_params general_params;
-#define WL1271_STAT_RADIO_PARAMS_5_SIZE 29
-#define WL1271_DYN_RADIO_PARAMS_5_SIZE 104
+ u8 sr_debug_table[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 sr_sen_n_p;
+ u8 sr_sen_n_p_gain;
+ u8 sr_sen_nrn;
+ u8 sr_sen_prn;
+ u8 padding[3];
+} __packed;
struct wl1271_radio_parms_cmd {
struct wl1271_cmd_header header;
struct wl1271_cmd_test_header test;
- u8 stat_radio_params[WL1271_NVS_STAT_RADIO_PARAMS_SIZE];
- u8 stat_radio_params_5[WL1271_STAT_RADIO_PARAMS_5_SIZE];
+ /* Static radio parameters */
+ struct wl1271_ini_band_params_2 static_params_2;
+ struct wl1271_ini_band_params_5 static_params_5;
- u8 dyn_radio_params[WL1271_NVS_DYN_RADIO_PARAMS_SIZE];
- u8 reserved;
- u8 dyn_radio_params_5[WL1271_DYN_RADIO_PARAMS_5_SIZE];
-} __attribute__ ((packed));
+ /* Dynamic radio parameters */
+ struct wl1271_ini_fem_params_2 dyn_params_2;
+ u8 padding2;
+ struct wl1271_ini_fem_params_5 dyn_params_5;
+ u8 padding3[2];
+} __packed;
struct wl1271_cmd_cal_channel_tune {
struct wl1271_cmd_header header;
@@ -468,7 +474,7 @@ struct wl1271_cmd_cal_channel_tune {
u8 channel;
__le16 radio_status;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_cmd_cal_update_ref_point {
struct wl1271_cmd_header header;
@@ -479,7 +485,7 @@ struct wl1271_cmd_cal_update_ref_point {
__le32 ref_detector;
u8 sub_band;
u8 padding[3];
-} __attribute__ ((packed));
+} __packed;
#define MAX_TLV_LENGTH 400
#define MAX_NVS_VERSION_LENGTH 12
@@ -501,7 +507,7 @@ struct wl1271_cmd_cal_p2g {
u8 sub_band_mask;
u8 padding2;
-} __attribute__ ((packed));
+} __packed;
/*
@@ -529,6 +535,6 @@ struct wl1271_cmd_disconnect {
u8 type;
u8 padding;
-} __attribute__ ((packed));
+} __packed;
#endif /* __WL1271_CMD_H__ */
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.c b/drivers/net/wireless/wl12xx/wl1271_event.c
index cf37aa6eb137..ca52cdec7a8f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.c
+++ b/drivers/net/wireless/wl12xx/wl1271_event.c
@@ -43,11 +43,11 @@ static int wl1271_event_scan_complete(struct wl1271 *wl,
clear_bit(WL1271_FLAG_SCANNING, &wl->flags);
/* FIXME: ie missing! */
wl1271_cmd_scan(wl, wl->scan.ssid, wl->scan.ssid_len,
- NULL, 0,
- wl->scan.active,
- wl->scan.high_prio,
- WL1271_SCAN_BAND_5_GHZ,
- wl->scan.probe_requests);
+ wl->scan.req,
+ wl->scan.active,
+ wl->scan.high_prio,
+ WL1271_SCAN_BAND_5_GHZ,
+ wl->scan.probe_requests);
} else {
mutex_unlock(&wl->mutex);
ieee80211_scan_completed(wl->hw, false);
diff --git a/drivers/net/wireless/wl12xx/wl1271_event.h b/drivers/net/wireless/wl12xx/wl1271_event.h
index 58371008f270..43d5aeae1783 100644
--- a/drivers/net/wireless/wl12xx/wl1271_event.h
+++ b/drivers/net/wireless/wl12xx/wl1271_event.h
@@ -85,7 +85,7 @@ struct event_debug_report {
__le32 report_1;
__le32 report_2;
__le32 report_3;
-} __attribute__ ((packed));
+} __packed;
#define NUM_OF_RSSI_SNR_TRIGGERS 8
@@ -116,7 +116,7 @@ struct event_mailbox {
u8 ps_status;
u8 reserved_5[29];
-} __attribute__ ((packed));
+} __packed;
int wl1271_event_unmask(struct wl1271 *wl);
void wl1271_event_mbox_config(struct wl1271 *wl);
diff --git a/drivers/net/wireless/wl12xx/wl1271_ini.h b/drivers/net/wireless/wl12xx/wl1271_ini.h
new file mode 100644
index 000000000000..0fb156a5af12
--- /dev/null
+++ b/drivers/net/wireless/wl12xx/wl1271_ini.h
@@ -0,0 +1,123 @@
+/*
+ * This file is part of wl1271
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ *
+ * Contact: Luciano Coelho <luciano.coelho@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __WL1271_INI_H__
+#define __WL1271_INI_H__
+
+#define WL1271_INI_MAX_SMART_REFLEX_PARAM 16
+
+struct wl1271_ini_general_params {
+ u8 ref_clock;
+ u8 settling_time;
+ u8 clk_valid_on_wakeup;
+ u8 dc2dc_mode;
+ u8 dual_mode_select;
+ u8 tx_bip_fem_auto_detect;
+ u8 tx_bip_fem_manufacturer;
+ u8 general_settings;
+ u8 sr_state;
+ u8 srf1[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 srf2[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+ u8 srf3[WL1271_INI_MAX_SMART_REFLEX_PARAM];
+} __attribute__ ((packed));
+
+#define WL1271_INI_RSSI_PROCESS_COMPENS_SIZE 15
+
+struct wl1271_ini_band_params_2 {
+ u8 rx_trace_insertion_loss;
+ u8 tx_trace_loss;
+ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__ ((packed));
+
+#define WL1271_INI_RATE_GROUP_COUNT 6
+#define WL1271_INI_CHANNEL_COUNT_2 14
+
+struct wl1271_ini_fem_params_2 {
+ __le16 tx_bip_ref_pd_voltage;
+ u8 tx_bip_ref_power;
+ u8 tx_bip_ref_offset;
+ u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_chan_pwr_limits_11b[WL1271_INI_CHANNEL_COUNT_2];
+ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_2];
+ u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ u8 rx_fem_insertion_loss;
+ u8 degraded_low_to_normal_thr;
+ u8 normal_to_degraded_high_thr;
+} __attribute__ ((packed));
+
+#define WL1271_INI_CHANNEL_COUNT_5 35
+#define WL1271_INI_SUB_BAND_COUNT_5 7
+
+struct wl1271_ini_band_params_5 {
+ u8 rx_trace_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_trace_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 rx_rssi_process_compens[WL1271_INI_RSSI_PROCESS_COMPENS_SIZE];
+} __attribute__ ((packed));
+
+struct wl1271_ini_fem_params_5 {
+ __le16 tx_bip_ref_pd_voltage[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_bip_ref_power[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_bip_ref_offset[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 tx_per_rate_pwr_limits_normal[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_degraded[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_rate_pwr_limits_extreme[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_per_chan_pwr_limits_ofdm[WL1271_INI_CHANNEL_COUNT_5];
+ u8 tx_pd_vs_rate_offsets[WL1271_INI_RATE_GROUP_COUNT];
+ u8 tx_ibias[WL1271_INI_RATE_GROUP_COUNT];
+ u8 rx_fem_insertion_loss[WL1271_INI_SUB_BAND_COUNT_5];
+ u8 degraded_low_to_normal_thr;
+ u8 normal_to_degraded_high_thr;
+} __attribute__ ((packed));
+
+
+/* NVS data structure */
+#define WL1271_INI_NVS_SECTION_SIZE 468
+#define WL1271_INI_FEM_MODULE_COUNT 2
+
+#define WL1271_INI_LEGACY_NVS_FILE_SIZE 800
+
+struct wl1271_nvs_file {
+ /* NVS section */
+ u8 nvs[WL1271_INI_NVS_SECTION_SIZE];
+
+ /* INI section */
+ struct wl1271_ini_general_params general_params;
+ u8 padding1;
+ struct wl1271_ini_band_params_2 stat_radio_params_2;
+ u8 padding2;
+ struct {
+ struct wl1271_ini_fem_params_2 params;
+ u8 padding;
+ } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT];
+ struct wl1271_ini_band_params_5 stat_radio_params_5;
+ u8 padding3;
+ struct {
+ struct wl1271_ini_fem_params_5 params;
+ u8 padding;
+ } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT];
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index b7d9137851ac..7a14da506d78 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -566,14 +566,21 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret;
}
- if (fw->size != sizeof(struct wl1271_nvs_file)) {
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+ * configurations) can be removed when those NVS files stop floating
+ * around.
+ */
+ if (fw->size != sizeof(struct wl1271_nvs_file) &&
+ (fw->size != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
fw->size, sizeof(struct wl1271_nvs_file));
ret = -EILSEQ;
goto out;
}
- wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
@@ -581,7 +588,7 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
goto out;
}
- memcpy(wl->nvs, fw->data, sizeof(struct wl1271_nvs_file));
+ memcpy(wl->nvs, fw->data, fw->size);
out:
release_firmware(fw);
@@ -1044,7 +1051,7 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl1271_tx_flush(wl);
+ wl1271_tx_reset(wl);
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
@@ -1241,6 +1248,42 @@ static u32 wl1271_min_rate_get(struct wl1271 *wl)
return rate;
}
+static int wl1271_handle_idle(struct wl1271 *wl, bool idle)
+{
+ int ret;
+
+ if (idle) {
+ if (test_bit(WL1271_FLAG_JOINED, &wl->flags)) {
+ ret = wl1271_unjoin(wl);
+ if (ret < 0)
+ goto out;
+ }
+ wl->rate_set = wl1271_min_rate_get(wl);
+ wl->sta_rate_set = 0;
+ ret = wl1271_acx_rate_policies(wl);
+ if (ret < 0)
+ goto out;
+ ret = wl1271_acx_keep_alive_config(
+ wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
+ ACX_KEEP_ALIVE_TPL_INVALID);
+ if (ret < 0)
+ goto out;
+ set_bit(WL1271_FLAG_IDLE, &wl->flags);
+ } else {
+ /* increment the session counter */
+ wl->session_counter++;
+ if (wl->session_counter >= SESSION_COUNTER_MAX)
+ wl->session_counter = 0;
+ ret = wl1271_dummy_join(wl);
+ if (ret < 0)
+ goto out;
+ clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+ }
+
+out:
+ return ret;
+}
+
static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
{
struct wl1271 *wl = hw->priv;
@@ -1255,6 +1298,15 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
conf->power_level,
conf->flags & IEEE80211_CONF_IDLE ? "idle" : "in use");
+ /*
+ * mac80211 will go to idle nearly immediately after transmitting some
+ * frames, such as the deauth. To make sure those frames reach the air,
+ * wait here until the TX queue is fully flushed.
+ */
+ if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
+ (conf->flags & IEEE80211_CONF_IDLE))
+ wl1271_tx_flush(wl);
+
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
@@ -1295,22 +1347,9 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_IDLE) {
- if (conf->flags & IEEE80211_CONF_IDLE &&
- test_bit(WL1271_FLAG_JOINED, &wl->flags))
- wl1271_unjoin(wl);
- else if (!(conf->flags & IEEE80211_CONF_IDLE))
- wl1271_dummy_join(wl);
-
- if (conf->flags & IEEE80211_CONF_IDLE) {
- wl->rate_set = wl1271_min_rate_get(wl);
- wl->sta_rate_set = 0;
- wl1271_acx_rate_policies(wl);
- wl1271_acx_keep_alive_config(
- wl, CMD_TEMPL_KLV_IDX_NULL_DATA,
- ACX_KEEP_ALIVE_TPL_INVALID);
- set_bit(WL1271_FLAG_IDLE, &wl->flags);
- } else
- clear_bit(WL1271_FLAG_IDLE, &wl->flags);
+ ret = wl1271_handle_idle(wl, conf->flags & IEEE80211_CONF_IDLE);
+ if (ret < 0)
+ wl1271_warning("idle mode change failed %d", ret);
}
if (conf->flags & IEEE80211_CONF_PS &&
@@ -1595,13 +1634,11 @@ static int wl1271_op_hw_scan(struct ieee80211_hw *hw,
goto out;
if (wl1271_11a_enabled())
- ret = wl1271_cmd_scan(hw->priv, ssid, len,
- req->ie, req->ie_len, 1, 0,
- WL1271_SCAN_BAND_DUAL, 3);
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
+ 1, 0, WL1271_SCAN_BAND_DUAL, 3);
else
- ret = wl1271_cmd_scan(hw->priv, ssid, len,
- req->ie, req->ie_len, 1, 0,
- WL1271_SCAN_BAND_2_4_GHZ, 3);
+ ret = wl1271_cmd_scan(hw->priv, ssid, len, req,
+ 1, 0, WL1271_SCAN_BAND_2_4_GHZ, 3);
wl1271_ps_elp_sleep(wl);
@@ -1991,7 +2028,7 @@ static struct ieee80211_channel wl1271_channels[] = {
};
/* mapping to indexes for wl1271_rates */
-const static u8 wl1271_rate_to_idx_2ghz[] = {
+static const u8 wl1271_rate_to_idx_2ghz[] = {
/* MCS rates are used only with 11n */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2103,7 +2140,7 @@ static struct ieee80211_channel wl1271_channels_5ghz[] = {
};
/* mapping to indexes for wl1271_rates_5ghz */
-const static u8 wl1271_rate_to_idx_5ghz[] = {
+static const u8 wl1271_rate_to_idx_5ghz[] = {
/* MCS rates are used only with 11n */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS7 */
CONF_HW_RXTX_RATE_UNSUPPORTED, /* CONF_HW_RXTX_RATE_MCS6 */
@@ -2139,7 +2176,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = {
.n_bitrates = ARRAY_SIZE(wl1271_rates_5ghz),
};
-const static u8 *wl1271_band_rate_to_idx[] = {
+static const u8 *wl1271_band_rate_to_idx[] = {
[IEEE80211_BAND_2GHZ] = wl1271_rate_to_idx_2ghz,
[IEEE80211_BAND_5GHZ] = wl1271_rate_to_idx_5ghz
};
diff --git a/drivers/net/wireless/wl12xx/wl1271_rx.h b/drivers/net/wireless/wl12xx/wl1271_rx.h
index b89be4758e78..13a232333b13 100644
--- a/drivers/net/wireless/wl12xx/wl1271_rx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_rx.h
@@ -113,7 +113,7 @@ struct wl1271_rx_descriptor {
u8 process_id;
u8 pad_len;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
void wl1271_rx(struct wl1271 *wl, struct wl1271_fw_status *status);
u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
diff --git a/drivers/net/wireless/wl12xx/wl1271_sdio.c b/drivers/net/wireless/wl12xx/wl1271_sdio.c
index d3d6f302f705..7059b5cccf0f 100644
--- a/drivers/net/wireless/wl12xx/wl1271_sdio.c
+++ b/drivers/net/wireless/wl12xx/wl1271_sdio.c
@@ -28,7 +28,7 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio_ids.h>
#include <linux/mmc/card.h>
-#include <plat/gpio.h>
+#include <linux/gpio.h>
#include "wl1271.h"
#include "wl12xx_80211.h"
diff --git a/drivers/net/wireless/wl12xx/wl1271_testmode.c b/drivers/net/wireless/wl12xx/wl1271_testmode.c
index 554deb4d024e..6e0952f79e9a 100644
--- a/drivers/net/wireless/wl12xx/wl1271_testmode.c
+++ b/drivers/net/wireless/wl12xx/wl1271_testmode.c
@@ -199,7 +199,14 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
len = nla_len(tb[WL1271_TM_ATTR_DATA]);
- if (len != sizeof(struct wl1271_nvs_file)) {
+ /*
+ * FIXME: the LEGACY NVS image support (NVS's missing the 5GHz band
+ * configurations) can be removed when those NVS files stop floating
+ * around.
+ */
+ if (len != sizeof(struct wl1271_nvs_file) &&
+ (len != WL1271_INI_LEGACY_NVS_FILE_SIZE ||
+ wl1271_11a_enabled())) {
wl1271_error("nvs size is not as expected: %zu != %zu",
len, sizeof(struct wl1271_nvs_file));
return -EMSGSIZE;
@@ -209,7 +216,7 @@ static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
kfree(wl->nvs);
- wl->nvs = kmalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
+ wl->nvs = kzalloc(sizeof(struct wl1271_nvs_file), GFP_KERNEL);
if (!wl->nvs) {
wl1271_error("could not allocate memory for the nvs file");
ret = -ENOMEM;
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.c b/drivers/net/wireless/wl12xx/wl1271_tx.c
index 62db79508ddf..c592cc2e9fe8 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.c
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.c
@@ -36,6 +36,7 @@ static int wl1271_tx_id(struct wl1271 *wl, struct sk_buff *skb)
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
if (wl->tx_frames[i] == NULL) {
wl->tx_frames[i] = skb;
+ wl->tx_frames_cnt++;
return i;
}
@@ -73,8 +74,10 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra)
wl1271_debug(DEBUG_TX,
"tx_allocate: size: %d, blocks: %d, id: %d",
total_len, total_blocks, id);
- } else
+ } else {
wl->tx_frames[id] = NULL;
+ wl->tx_frames_cnt--;
+ }
return ret;
}
@@ -358,6 +361,7 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl,
/* return the packet to the stack */
ieee80211_tx_status(wl->hw, skb);
wl->tx_frames[result->id] = NULL;
+ wl->tx_frames_cnt--;
}
/* Called upon reception of a TX complete interrupt */
@@ -412,7 +416,7 @@ void wl1271_tx_complete(struct wl1271 *wl)
}
/* caller must hold wl->mutex */
-void wl1271_tx_flush(struct wl1271 *wl)
+void wl1271_tx_reset(struct wl1271 *wl)
{
int i;
struct sk_buff *skb;
@@ -421,7 +425,7 @@ void wl1271_tx_flush(struct wl1271 *wl)
/* control->flags = 0; FIXME */
while ((skb = skb_dequeue(&wl->tx_queue))) {
- wl1271_debug(DEBUG_TX, "flushing skb 0x%p", skb);
+ wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
}
@@ -429,6 +433,32 @@ void wl1271_tx_flush(struct wl1271 *wl)
if (wl->tx_frames[i] != NULL) {
skb = wl->tx_frames[i];
wl->tx_frames[i] = NULL;
+ wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
ieee80211_tx_status(wl->hw, skb);
}
+ wl->tx_frames_cnt = 0;
+}
+
+#define WL1271_TX_FLUSH_TIMEOUT 500000
+
+/* caller must *NOT* hold wl->mutex */
+void wl1271_tx_flush(struct wl1271 *wl)
+{
+ unsigned long timeout;
+ timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
+
+ while (!time_after(jiffies, timeout)) {
+ mutex_lock(&wl->mutex);
+ wl1271_debug(DEBUG_TX, "flushing tx buffer: %d",
+ wl->tx_frames_cnt);
+ if ((wl->tx_frames_cnt == 0) &&
+ skb_queue_empty(&wl->tx_queue)) {
+ mutex_unlock(&wl->mutex);
+ return;
+ }
+ mutex_unlock(&wl->mutex);
+ msleep(1);
+ }
+
+ wl1271_warning("Unable to flush all TX buffers, timed out.");
}
diff --git a/drivers/net/wireless/wl12xx/wl1271_tx.h b/drivers/net/wireless/wl12xx/wl1271_tx.h
index 3b8b7ac253fd..48bf92621c03 100644
--- a/drivers/net/wireless/wl12xx/wl1271_tx.h
+++ b/drivers/net/wireless/wl12xx/wl1271_tx.h
@@ -80,7 +80,7 @@ struct wl1271_tx_hw_descr {
/* Identifier of the remote STA in IBSS, 1 in infra-BSS */
u8 aid;
u8 reserved;
-} __attribute__ ((packed));
+} __packed;
enum wl1271_tx_hw_res_status {
TX_SUCCESS = 0,
@@ -115,13 +115,13 @@ struct wl1271_tx_hw_res_descr {
u8 rate_class_index;
/* for 4-byte alignment. */
u8 spare;
-} __attribute__ ((packed));
+} __packed;
struct wl1271_tx_hw_res_if {
__le32 tx_result_fw_counter;
__le32 tx_result_host_counter;
struct wl1271_tx_hw_res_descr tx_results_queue[TX_HW_RESULT_QUEUE_LEN];
-} __attribute__ ((packed));
+} __packed;
static inline int wl1271_tx_get_queue(int queue)
{
@@ -158,6 +158,7 @@ static inline int wl1271_tx_ac_to_tid(int ac)
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_complete(struct wl1271 *wl);
+void wl1271_tx_reset(struct wl1271 *wl);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(struct wl1271 *wl, int rate);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
diff --git a/drivers/net/wireless/wl12xx/wl12xx_80211.h b/drivers/net/wireless/wl12xx/wl12xx_80211.h
index 055d7bc6f592..184628027213 100644
--- a/drivers/net/wireless/wl12xx/wl12xx_80211.h
+++ b/drivers/net/wireless/wl12xx/wl12xx_80211.h
@@ -66,41 +66,41 @@ struct ieee80211_header {
u8 bssid[ETH_ALEN];
__le16 seq_ctl;
u8 payload[0];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_header {
u8 id;
u8 len;
-} __attribute__ ((packed));
+} __packed;
/* IEs */
struct wl12xx_ie_ssid {
struct wl12xx_ie_header header;
char ssid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_rates {
struct wl12xx_ie_header header;
u8 rates[MAX_SUPPORTED_RATES];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_ds_params {
struct wl12xx_ie_header header;
u8 channel;
-} __attribute__ ((packed));
+} __packed;
struct country_triplet {
u8 channel;
u8 num_channels;
u8 max_tx_power;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ie_country {
struct wl12xx_ie_header header;
u8 country_string[COUNTRY_STRING_LEN];
struct country_triplet triplets[MAX_COUNTRY_TRIPLETS];
-} __attribute__ ((packed));
+} __packed;
/* Templates */
@@ -115,30 +115,30 @@ struct wl12xx_beacon_template {
struct wl12xx_ie_rates ext_rates;
struct wl12xx_ie_ds_params ds_params;
struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_null_data_template {
struct ieee80211_header header;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_ps_poll_template {
__le16 fc;
__le16 aid;
u8 bssid[ETH_ALEN];
u8 ta[ETH_ALEN];
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_qos_null_data_template {
struct ieee80211_header header;
__le16 qos_ctl;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_probe_req_template {
struct ieee80211_header header;
struct wl12xx_ie_ssid ssid;
struct wl12xx_ie_rates rates;
struct wl12xx_ie_rates ext_rates;
-} __attribute__ ((packed));
+} __packed;
struct wl12xx_probe_resp_template {
@@ -151,6 +151,6 @@ struct wl12xx_probe_resp_template {
struct wl12xx_ie_rates ext_rates;
struct wl12xx_ie_ds_params ds_params;
struct wl12xx_ie_country country;
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h
index 8816e371fd0e..3fbfd19818f1 100644
--- a/drivers/net/wireless/wl3501.h
+++ b/drivers/net/wireless/wl3501.h
@@ -231,12 +231,12 @@ struct iw_mgmt_info_element {
but sizeof(enum) > sizeof(u8) :-( */
u8 len;
u8 data[0];
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_essid_pset {
struct iw_mgmt_info_element el;
u8 essid[IW_ESSID_MAX_SIZE];
-} __attribute__ ((packed));
+} __packed;
/*
* According to 802.11 Wireless Netowors, the definitive guide - O'Reilly
@@ -247,12 +247,12 @@ struct iw_mgmt_essid_pset {
struct iw_mgmt_data_rset {
struct iw_mgmt_info_element el;
u8 data_rate_labels[IW_DATA_RATE_MAX_LABELS];
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_ds_pset {
struct iw_mgmt_info_element el;
u8 chan;
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_cf_pset {
struct iw_mgmt_info_element el;
@@ -260,12 +260,12 @@ struct iw_mgmt_cf_pset {
u8 cfp_period;
u16 cfp_max_duration;
u16 cfp_dur_remaining;
-} __attribute__ ((packed));
+} __packed;
struct iw_mgmt_ibss_pset {
struct iw_mgmt_info_element el;
u16 atim_window;
-} __attribute__ ((packed));
+} __packed;
struct wl3501_tx_hdr {
u16 tx_cnt;
@@ -544,12 +544,12 @@ struct wl3501_80211_tx_plcp_hdr {
u8 service;
u16 len;
u16 crc16;
-} __attribute__ ((packed));
+} __packed;
struct wl3501_80211_tx_hdr {
struct wl3501_80211_tx_plcp_hdr pclp_hdr;
struct ieee80211_hdr mac_hdr;
-} __attribute__ ((packed));
+} __packed;
/*
Reserve the beginning Tx space for descriptor use.
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index b0b666019a93..163a8a06b22d 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -855,7 +855,7 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length)
if (skb == NULL)
return -ENOMEM;
if (need_padding) {
- /* Make sure the the payload data is 4 byte aligned. */
+ /* Make sure the payload data is 4 byte aligned. */
skb_reserve(skb, 2);
}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 630c298a730e..e4c70e359ced 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -35,7 +35,7 @@ struct zd_ctrlset {
__le16 current_length;
u8 service;
__le16 next_frame_length;
-} __attribute__((packed));
+} __packed;
#define ZD_CS_RESERVED_SIZE 25
@@ -106,7 +106,7 @@ struct zd_ctrlset {
struct rx_length_info {
__le16 length[3];
__le16 tag;
-} __attribute__((packed));
+} __packed;
#define RX_LENGTH_INFO_TAG 0x697e
@@ -117,7 +117,7 @@ struct rx_status {
u8 signal_quality_ofdm;
u8 decryption_type;
u8 frame_status;
-} __attribute__((packed));
+} __packed;
/* rx_status field decryption_type */
#define ZD_RX_NO_WEP 0
@@ -153,7 +153,7 @@ struct tx_status {
u8 mac[ETH_ALEN];
u8 retry;
u8 failure;
-} __attribute__((packed));
+} __packed;
enum mac_flags {
MAC_FIXED_CHANNEL = 0x01,
@@ -225,7 +225,7 @@ enum {
struct ofdm_plcp_header {
u8 prefix[3];
__le16 service;
-} __attribute__((packed));
+} __packed;
static inline u8 zd_ofdm_plcp_header_rate(const struct ofdm_plcp_header *header)
{
@@ -252,7 +252,7 @@ struct cck_plcp_header {
u8 service;
__le16 length;
__le16 crc16;
-} __attribute__((packed));
+} __packed;
static inline u8 zd_cck_plcp_header_signal(const struct cck_plcp_header *header)
{
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index c257940b71b6..818e1480ca93 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -844,7 +844,7 @@ out:
* @usb: a &struct zd_usb pointer
* @urb: URB to be freed
*
- * Frees the the transmission URB, which means to put it on the free URB
+ * Frees the transmission URB, which means to put it on the free URB
* list.
*/
static void free_tx_urb(struct zd_usb *usb, struct urb *urb)
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index 049f8b91f020..1b1655cb7cb4 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -79,17 +79,17 @@ enum control_requests {
struct usb_req_read_regs {
__le16 id;
__le16 addr[0];
-} __attribute__((packed));
+} __packed;
struct reg_data {
__le16 addr;
__le16 value;
-} __attribute__((packed));
+} __packed;
struct usb_req_write_regs {
__le16 id;
struct reg_data reg_writes[0];
-} __attribute__((packed));
+} __packed;
enum {
RF_IF_LE = 0x02,
@@ -106,7 +106,7 @@ struct usb_req_rfwrite {
/* RF2595: 24 */
__le16 bit_values[0];
/* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
-} __attribute__((packed));
+} __packed;
/* USB interrupt */
@@ -123,12 +123,12 @@ enum usb_int_flags {
struct usb_int_header {
u8 type; /* must always be 1 */
u8 id;
-} __attribute__((packed));
+} __packed;
struct usb_int_regs {
struct usb_int_header hdr;
struct reg_data regs[0];
-} __attribute__((packed));
+} __packed;
struct usb_int_retry_fail {
struct usb_int_header hdr;
@@ -136,7 +136,7 @@ struct usb_int_retry_fail {
u8 _dummy;
u8 addr[ETH_ALEN];
u8 ibss_wakeup_dest;
-} __attribute__((packed));
+} __packed;
struct read_regs_int {
struct completion completion;
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d504e2b60257..b50fedcef8ac 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -1621,6 +1621,7 @@ static void backend_changed(struct xenbus_device *dev,
if (xennet_connect(netdev) != 0)
break;
xenbus_switch_state(dev, XenbusStateConnected);
+ netif_notify_peers(netdev);
break;
case XenbusStateClosing:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 5f5e8d2e3552..d3985e7deab7 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -113,7 +113,7 @@
#define CON_PFAULT_INTR_MASK (1 << 28)
#define MRL_CHANGE_SERR_MASK (1 << 29)
#define CON_PFAULT_SERR_MASK (1 << 30)
-#define SLOT_REG_RSVDZ_MASK (1 << 15) | (7 << 21)
+#define SLOT_REG_RSVDZ_MASK ((1 << 15) | (7 << 21))
/*
* SHPC Command Code definitnions
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
index 8af4f619bba2..fc0b5a93e1de 100644
--- a/drivers/pci/pcie/aer/aerdrv_core.c
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -727,20 +727,21 @@ static void aer_isr_one_error(struct pcie_device *p_device,
static int get_e_source(struct aer_rpc *rpc, struct aer_err_source *e_src)
{
unsigned long flags;
- int ret = 0;
/* Lock access to Root error producer/consumer index */
spin_lock_irqsave(&rpc->e_lock, flags);
- if (rpc->prod_idx != rpc->cons_idx) {
- *e_src = rpc->e_sources[rpc->cons_idx];
- rpc->cons_idx++;
- if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
- rpc->cons_idx = 0;
- ret = 1;
+ if (rpc->prod_idx == rpc->cons_idx) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return 0;
}
+
+ *e_src = rpc->e_sources[rpc->cons_idx];
+ rpc->cons_idx++;
+ if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
+ rpc->cons_idx = 0;
spin_unlock_irqrestore(&rpc->e_lock, flags);
- return ret;
+ return 1;
}
/**
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index b7512cf08c58..3a81d9d44019 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1457,7 +1457,8 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
conf5 &= ~(1 << 24); /* Clear bit 24 */
switch (pdev->device) {
- case PCI_DEVICE_ID_JMICRON_JMB360:
+ case PCI_DEVICE_ID_JMICRON_JMB360: /* SATA single port */
+ case PCI_DEVICE_ID_JMICRON_JMB362: /* SATA dual ports */
/* The controller should be in single function ahci mode */
conf1 |= 0x0002A100; /* Set 8, 13, 15, 17 */
break;
@@ -1493,12 +1494,14 @@ static void quirk_jmicron_ata(struct pci_dev *pdev)
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB360, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, quirk_jmicron_ata);
+DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB362, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, quirk_jmicron_ata);
DECLARE_PCI_FIXUP_RESUME_EARLY(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, quirk_jmicron_ata);
@@ -2112,6 +2115,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS480, quirk_disabl
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3336, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3351, quirk_disable_all_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT3364, quirk_disable_all_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8380_0, quirk_disable_all_msi);
/* Disable MSI on chipsets that are known to not support it */
static void __devinit quirk_disable_msi(struct pci_dev *dev)
@@ -2123,12 +2127,29 @@ static void __devinit quirk_disable_msi(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9602, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASUSTEK, 0x9602, quirk_disable_msi);
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AI, 0x9602, quirk_disable_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, 0xa238, quirk_disable_msi);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x5a3f, quirk_disable_msi);
+/*
+ * The APC bridge device in AMD 780 family northbridges has some random
+ * OEM subsystem ID in its vendor ID register (erratum 18), so instead
+ * we use the possible vendor/device IDs of the host bridge for the
+ * declared quirk, and search for the APC bridge by slot number.
+ */
+static void __devinit quirk_amd_780_apc_msi(struct pci_dev *host_bridge)
+{
+ struct pci_dev *apc_bridge;
+
+ apc_bridge = pci_get_slot(host_bridge->bus, PCI_DEVFN(1, 0));
+ if (apc_bridge) {
+ if (apc_bridge->device == 0x9602)
+ quirk_disable_msi(apc_bridge);
+ pci_dev_put(apc_bridge);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9600, quirk_amd_780_apc_msi);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x9601, quirk_amd_780_apc_msi);
+
/* Go through the list of Hypertransport capabilities and
* return 1 if a HT MSI capability is found and enabled */
static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 1a648b90b634..25e5e30a18af 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -1157,7 +1157,7 @@ static int __init m8xx_probe(struct of_device *ofdev,
unsigned int i, m, hwirq;
pcmconf8xx_t *pcmcia;
int status;
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
pcmcia_info("%s\n", version);
@@ -1301,7 +1301,7 @@ static struct of_platform_driver m8xx_pcmcia_driver = {
.driver = {
.name = driver_name,
.owner = THIS_MODULE,
- .match_table = m8xx_pcmcia_match,
+ .of_match_table = m8xx_pcmcia_match,
},
.probe = m8xx_probe,
.remove = m8xx_remove,
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 576c3ed92435..40658e3385b4 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -524,7 +524,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
for (i = 0; i < inlen; i++)
ipc_data_writel(*in++, 4 * i);
- ipc_command(cmd << 12 | sub);
+ ipc_command((cmd << 12) | sub | (inlen << 18));
err = busy_loop();
for (i = 0; i < outlen; i++)
diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c
index f3e22c9fe20a..2f2f9a6f54fa 100644
--- a/drivers/power/max17040_battery.c
+++ b/drivers/power/max17040_battery.c
@@ -225,7 +225,6 @@ static int __devinit max17040_probe(struct i2c_client *client,
ret = power_supply_register(&client->dev, &chip->battery);
if (ret) {
dev_err(&client->dev, "failed: power supply register\n");
- i2c_set_clientdata(client, NULL);
kfree(chip);
return ret;
}
@@ -245,7 +244,6 @@ static int __devexit max17040_remove(struct i2c_client *client)
power_supply_unregister(&chip->battery);
cancel_delayed_work(&chip->work);
- i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 04f2e085116a..679ea3759449 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -201,5 +201,11 @@ config REGULATOR_88PM8607
help
This driver supports 88PM8607 voltage regulator chips.
+config REGULATOR_AD5398
+ tristate "Analog Devices AD5398/AD5821 regulators"
+ depends on I2C
+ help
+ This driver supports AD5398 and AD5821 current regulator chips.
+ If building into module, its name is ad5398.ko.
endif
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 4e7feece22d5..c256668300a6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
+obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c
new file mode 100644
index 000000000000..6de6bdaeff7c
--- /dev/null
+++ b/drivers/regulator/ad5398.c
@@ -0,0 +1,288 @@
+/*
+ * Voltage and current regulation for AD5398 and AD5821
+ *
+ * Copyright 2010 Analog Devices Inc.
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+#define AD5398_CURRENT_EN_MASK 0x8000
+
+struct ad5398_chip_info {
+ struct i2c_client *client;
+ int min_uA;
+ int max_uA;
+ unsigned int current_level;
+ unsigned int current_mask;
+ unsigned int current_offset;
+ struct regulator_dev rdev;
+};
+
+static int ad5398_calc_current(struct ad5398_chip_info *chip,
+ unsigned selector)
+{
+ unsigned range_uA = chip->max_uA - chip->min_uA;
+
+ return chip->min_uA + (selector * range_uA / chip->current_level);
+}
+
+static int ad5398_read_reg(struct i2c_client *client, unsigned short *data)
+{
+ unsigned short val;
+ int ret;
+
+ ret = i2c_master_recv(client, (char *)&val, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "I2C read error\n");
+ return ret;
+ }
+ *data = be16_to_cpu(val);
+
+ return ret;
+}
+
+static int ad5398_write_reg(struct i2c_client *client, const unsigned short data)
+{
+ unsigned short val;
+ int ret;
+
+ val = cpu_to_be16(data);
+ ret = i2c_master_send(client, (char *)&val, 2);
+ if (ret < 0)
+ dev_err(&client->dev, "I2C write error\n");
+
+ return ret;
+}
+
+static int ad5398_get_current_limit(struct regulator_dev *rdev)
+{
+ struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+ struct i2c_client *client = chip->client;
+ unsigned short data;
+ int ret;
+
+ ret = ad5398_read_reg(client, &data);
+ if (ret < 0)
+ return ret;
+
+ ret = (data & chip->current_mask) >> chip->current_offset;
+
+ return ad5398_calc_current(chip, ret);
+}
+
+static int ad5398_set_current_limit(struct regulator_dev *rdev, int min_uA, int max_uA)
+{
+ struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+ struct i2c_client *client = chip->client;
+ unsigned range_uA = chip->max_uA - chip->min_uA;
+ unsigned selector;
+ unsigned short data;
+ int ret;
+
+ if (min_uA > chip->max_uA || min_uA < chip->min_uA)
+ return -EINVAL;
+ if (max_uA > chip->max_uA || max_uA < chip->min_uA)
+ return -EINVAL;
+
+ selector = ((min_uA - chip->min_uA) * chip->current_level +
+ range_uA - 1) / range_uA;
+ if (ad5398_calc_current(chip, selector) > max_uA)
+ return -EINVAL;
+
+ dev_dbg(&client->dev, "changing current %dmA\n",
+ ad5398_calc_current(chip, selector) / 1000);
+
+ /* read chip enable bit */
+ ret = ad5398_read_reg(client, &data);
+ if (ret < 0)
+ return ret;
+
+ /* prepare register data */
+ selector = (selector << chip->current_offset) & chip->current_mask;
+ data = (unsigned short)selector | (data & AD5398_CURRENT_EN_MASK);
+
+ /* write the new current value back as well as enable bit */
+ ret = ad5398_write_reg(client, data);
+
+ return ret;
+}
+
+static int ad5398_is_enabled(struct regulator_dev *rdev)
+{
+ struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+ struct i2c_client *client = chip->client;
+ unsigned short data;
+ int ret;
+
+ ret = ad5398_read_reg(client, &data);
+ if (ret < 0)
+ return ret;
+
+ if (data & AD5398_CURRENT_EN_MASK)
+ return 1;
+ else
+ return 0;
+}
+
+static int ad5398_enable(struct regulator_dev *rdev)
+{
+ struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+ struct i2c_client *client = chip->client;
+ unsigned short data;
+ int ret;
+
+ ret = ad5398_read_reg(client, &data);
+ if (ret < 0)
+ return ret;
+
+ if (data & AD5398_CURRENT_EN_MASK)
+ return 0;
+
+ data |= AD5398_CURRENT_EN_MASK;
+
+ ret = ad5398_write_reg(client, data);
+
+ return ret;
+}
+
+static int ad5398_disable(struct regulator_dev *rdev)
+{
+ struct ad5398_chip_info *chip = rdev_get_drvdata(rdev);
+ struct i2c_client *client = chip->client;
+ unsigned short data;
+ int ret;
+
+ ret = ad5398_read_reg(client, &data);
+ if (ret < 0)
+ return ret;
+
+ if (!(data & AD5398_CURRENT_EN_MASK))
+ return 0;
+
+ data &= ~AD5398_CURRENT_EN_MASK;
+
+ ret = ad5398_write_reg(client, data);
+
+ return ret;
+}
+
+static struct regulator_ops ad5398_ops = {
+ .get_current_limit = ad5398_get_current_limit,
+ .set_current_limit = ad5398_set_current_limit,
+ .enable = ad5398_enable,
+ .disable = ad5398_disable,
+ .is_enabled = ad5398_is_enabled,
+};
+
+static struct regulator_desc ad5398_reg = {
+ .name = "isink",
+ .id = 0,
+ .ops = &ad5398_ops,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+};
+
+struct ad5398_current_data_format {
+ int current_bits;
+ int current_offset;
+ int min_uA;
+ int max_uA;
+};
+
+static const struct ad5398_current_data_format df_10_4_120 = {10, 4, 0, 120000};
+
+static const struct i2c_device_id ad5398_id[] = {
+ { "ad5398", (kernel_ulong_t)&df_10_4_120 },
+ { "ad5821", (kernel_ulong_t)&df_10_4_120 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ad5398_id);
+
+static int __devinit ad5398_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regulator_dev *rdev;
+ struct regulator_init_data *init_data = client->dev.platform_data;
+ struct ad5398_chip_info *chip;
+ const struct ad5398_current_data_format *df =
+ (struct ad5398_current_data_format *)id->driver_data;
+ int ret;
+
+ if (!init_data)
+ return -EINVAL;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->client = client;
+
+ chip->min_uA = df->min_uA;
+ chip->max_uA = df->max_uA;
+ chip->current_level = 1 << df->current_bits;
+ chip->current_offset = df->current_offset;
+ chip->current_mask = (chip->current_level - 1) << chip->current_offset;
+
+ rdev = regulator_register(&ad5398_reg, &client->dev, init_data, chip);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
+ dev_err(&client->dev, "failed to register %s %s\n",
+ id->name, ad5398_reg.name);
+ goto err;
+ }
+
+ i2c_set_clientdata(client, chip);
+ dev_dbg(&client->dev, "%s regulator driver is registered.\n", id->name);
+ return 0;
+
+err:
+ kfree(chip);
+ return ret;
+}
+
+static int __devexit ad5398_remove(struct i2c_client *client)
+{
+ struct ad5398_chip_info *chip = i2c_get_clientdata(client);
+
+ regulator_unregister(&chip->rdev);
+ kfree(chip);
+ i2c_set_clientdata(client, NULL);
+
+ return 0;
+}
+
+static struct i2c_driver ad5398_driver = {
+ .probe = ad5398_probe,
+ .remove = __devexit_p(ad5398_remove),
+ .driver = {
+ .name = "ad5398",
+ },
+ .id_table = ad5398_id,
+};
+
+static int __init ad5398_init(void)
+{
+ return i2c_add_driver(&ad5398_driver);
+}
+module_init(ad5398_init);
+
+static void __exit ad5398_exit(void)
+{
+ i2c_del_driver(&ad5398_driver);
+}
+module_exit(ad5398_exit);
+
+MODULE_DESCRIPTION("AD5398 and AD5821 current regulator driver");
+MODULE_AUTHOR("Sonic Zhang");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("i2c:ad5398-regulator");
diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c
index 671a7d1f1f0e..8ae3732eb24b 100644
--- a/drivers/regulator/lp3971.c
+++ b/drivers/regulator/lp3971.c
@@ -519,8 +519,6 @@ static int __devexit lp3971_i2c_remove(struct i2c_client *i2c)
struct lp3971 *lp3971 = i2c_get_clientdata(i2c);
int i;
- i2c_set_clientdata(i2c, NULL);
-
for (i = 0; i < lp3971->num_regulators; i++)
regulator_unregister(lp3971->rdev[i]);
diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c
index b3c1afc16889..2b54d9d75f11 100644
--- a/drivers/regulator/max1586.c
+++ b/drivers/regulator/max1586.c
@@ -244,7 +244,6 @@ static int __devexit max1586_pmic_remove(struct i2c_client *client)
for (i = 0; i <= MAX1586_V6; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
- i2c_set_clientdata(client, NULL);
kfree(rdev);
return 0;
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index bfc4c5ffdc96..4520ace3f7e7 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -357,7 +357,6 @@ static int __devinit max8649_regulator_probe(struct i2c_client *client,
dev_info(info->dev, "Max8649 regulator device is detected.\n");
return 0;
out:
- i2c_set_clientdata(client, NULL);
kfree(info);
return ret;
}
@@ -369,7 +368,6 @@ static int __devexit max8649_regulator_remove(struct i2c_client *client)
if (info) {
if (info->regulator)
regulator_unregister(info->regulator);
- i2c_set_clientdata(client, NULL);
kfree(info);
}
diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c
index 3790b21879ff..d97220efae5a 100644
--- a/drivers/regulator/max8660.c
+++ b/drivers/regulator/max8660.c
@@ -471,7 +471,6 @@ static int __devexit max8660_remove(struct i2c_client *client)
for (i = 0; i < MAX8660_V_END; i++)
if (rdev[i])
regulator_unregister(rdev[i]);
- i2c_set_clientdata(client, NULL);
kfree(rdev);
return 0;
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 8e2f2098b005..f50afc9f287a 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -538,9 +538,6 @@ static int __devexit tps_65023_remove(struct i2c_client *client)
struct tps_pmic *tps = i2c_get_clientdata(client);
int i;
- /* clear the client data in i2c */
- i2c_set_clientdata(client, NULL);
-
for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
regulator_unregister(tps->rdev[i]);
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 92a8f6cacda9..34647fc1ee98 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -29,6 +29,7 @@
#include <linux/bcd.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/slab.h>
/*
* The DaVinci RTC is a simple RTC with the following
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 61945734ad00..1f0007fd4431 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -403,7 +403,6 @@ out_irq:
free_irq(client->irq, client);
out_free:
- i2c_set_clientdata(client, NULL);
kfree(ds1374);
return ret;
}
@@ -422,7 +421,6 @@ static int __devexit ds1374_remove(struct i2c_client *client)
}
rtc_device_unregister(ds1374->rtc);
- i2c_set_clientdata(client, NULL);
kfree(ds1374);
return 0;
}
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
index f0dbf9cb8f9c..db5d8c416d26 100644
--- a/drivers/rtc/rtc-mpc5121.c
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -279,7 +279,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
if (!rtc)
return -ENOMEM;
- rtc->regs = of_iomap(op->node, 0);
+ rtc->regs = of_iomap(op->dev.of_node, 0);
if (!rtc->regs) {
dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
err = -ENOSYS;
@@ -290,7 +290,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
dev_set_drvdata(&op->dev, rtc);
- rtc->irq = irq_of_parse_and_map(op->node, 1);
+ rtc->irq = irq_of_parse_and_map(op->dev.of_node, 1);
err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
"mpc5121-rtc", &op->dev);
if (err) {
@@ -299,7 +299,7 @@ static int __devinit mpc5121_rtc_probe(struct of_device *op,
goto out_dispose;
}
- rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
+ rtc->irq_periodic = irq_of_parse_and_map(op->dev.of_node, 0);
err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
if (err) {
@@ -365,9 +365,11 @@ static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
};
static struct of_platform_driver mpc5121_rtc_driver = {
- .owner = THIS_MODULE,
- .name = "mpc5121-rtc",
- .match_table = mpc5121_rtc_match,
+ .driver = {
+ .name = "mpc5121-rtc",
+ .owner = THIS_MODULE,
+ .of_match_table = mpc5121_rtc_match,
+ },
.probe = mpc5121_rtc_probe,
.remove = __devexit_p(mpc5121_rtc_remove),
};
diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c
index b65c82f792d9..789f62f9b47d 100644
--- a/drivers/rtc/rtc-rx8025.c
+++ b/drivers/rtc/rtc-rx8025.c
@@ -632,7 +632,6 @@ errout_reg:
rtc_device_unregister(rx8025->rtc);
errout_free:
- i2c_set_clientdata(client, NULL);
kfree(rx8025);
errout:
@@ -656,7 +655,6 @@ static int __devexit rx8025_remove(struct i2c_client *client)
rx8025_sysfs_unregister(&client->dev);
rtc_device_unregister(rx8025->rtc);
- i2c_set_clientdata(client, NULL);
kfree(rx8025);
return 0;
}
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index def4d396d0b0..f789e002c9b0 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -275,7 +275,6 @@ exit_dummy:
if (s35390a->client[i])
i2c_unregister_device(s35390a->client[i]);
kfree(s35390a);
- i2c_set_clientdata(client, NULL);
exit:
return err;
@@ -292,7 +291,6 @@ static int s35390a_remove(struct i2c_client *client)
rtc_device_unregister(s35390a->rtc);
kfree(s35390a);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index e5972b2c17b7..70b68d35f969 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -495,8 +495,6 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
pr_debug("s3c2410_rtc: RTCCON=%02x\n",
readb(s3c_rtc_base + S3C2410_RTCCON));
- s3c_rtc_setfreq(&pdev->dev, 1);
-
device_init_wakeup(&pdev->dev, 1);
/* register RTC and exit */
@@ -510,14 +508,17 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)
goto err_nortc;
}
+ s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
+
if (s3c_rtc_cpu_type == TYPE_S3C64XX)
rtc->max_user_freq = 32768;
else
rtc->max_user_freq = 128;
- s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;
-
platform_set_drvdata(pdev, rtc);
+
+ s3c_rtc_setfreq(&pdev->dev, 1);
+
return 0;
err_nortc:
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index ce7cb87479fe..2596a94f7739 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -29,6 +29,7 @@
#include "chsc.h"
static void *sei_page;
+static DEFINE_SPINLOCK(siosl_lock);
static DEFINE_SPINLOCK(sda_lock);
/**
@@ -48,6 +49,7 @@ int chsc_error_from_response(int response)
case 0x0007:
case 0x0008:
case 0x000a:
+ case 0x0104:
return -EINVAL;
case 0x0004:
return -EOPNOTSUPP;
@@ -974,3 +976,50 @@ int chsc_sstpi(void *page, void *result, size_t size)
return (rr->response.code == 0x0001) ? 0 : -EIO;
}
+static struct {
+ struct chsc_header request;
+ u32 word1;
+ struct subchannel_id sid;
+ u32 word3;
+ struct chsc_header response;
+ u32 word[11];
+} __attribute__ ((packed)) siosl_area __attribute__ ((__aligned__(PAGE_SIZE)));
+
+int chsc_siosl(struct subchannel_id schid)
+{
+ unsigned long flags;
+ int ccode;
+ int rc;
+
+ spin_lock_irqsave(&siosl_lock, flags);
+ memset(&siosl_area, 0, sizeof(siosl_area));
+ siosl_area.request.length = 0x0010;
+ siosl_area.request.code = 0x0046;
+ siosl_area.word1 = 0x80000000;
+ siosl_area.sid = schid;
+
+ ccode = chsc(&siosl_area);
+ if (ccode > 0) {
+ if (ccode == 3)
+ rc = -ENODEV;
+ else
+ rc = -EBUSY;
+ CIO_MSG_EVENT(2, "chsc: chsc failed for 0.%x.%04x (ccode=%d)\n",
+ schid.ssid, schid.sch_no, ccode);
+ goto out;
+ }
+ rc = chsc_error_from_response(siosl_area.response.code);
+ if (rc)
+ CIO_MSG_EVENT(2, "chsc: siosl failed for 0.%x.%04x (rc=%04x)\n",
+ schid.ssid, schid.sch_no,
+ siosl_area.response.code);
+ else
+ CIO_MSG_EVENT(4, "chsc: siosl succeeded for 0.%x.%04x\n",
+ schid.ssid, schid.sch_no);
+out:
+ spin_unlock_irqrestore(&siosl_lock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(chsc_siosl);
+
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 37aa611d4ac5..5453013f094b 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -80,4 +80,6 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp);
int chsc_error_from_response(int response);
+int chsc_siosl(struct subchannel_id schid);
+
#endif
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 6d229f3523a0..75acec3b2d6b 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -36,6 +36,7 @@
#include "ioasm.h"
#include "io_sch.h"
#include "blacklist.h"
+#include "chsc.h"
static struct timer_list recovery_timer;
static DEFINE_SPINLOCK(recovery_lock);
@@ -598,6 +599,25 @@ available_show (struct device *dev, struct device_attribute *attr, char *buf)
}
}
+static ssize_t
+initiate_logging(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct subchannel *sch = to_subchannel(dev);
+ int rc;
+
+ rc = chsc_siosl(sch->schid);
+ if (rc < 0) {
+ pr_warning("Logging for subchannel 0.%x.%04x failed with "
+ "errno=%d\n",
+ sch->schid.ssid, sch->schid.sch_no, rc);
+ return rc;
+ }
+ pr_notice("Logging for subchannel 0.%x.%04x was triggered\n",
+ sch->schid.ssid, sch->schid.sch_no);
+ return count;
+}
+
static DEVICE_ATTR(chpids, 0444, chpids_show, NULL);
static DEVICE_ATTR(pimpampom, 0444, pimpampom_show, NULL);
static DEVICE_ATTR(devtype, 0444, devtype_show, NULL);
@@ -605,10 +625,12 @@ static DEVICE_ATTR(cutype, 0444, cutype_show, NULL);
static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
static DEVICE_ATTR(online, 0644, online_show, online_store);
static DEVICE_ATTR(availability, 0444, available_show, NULL);
+static DEVICE_ATTR(logging, 0200, NULL, initiate_logging);
static struct attribute *io_subchannel_attrs[] = {
&dev_attr_chpids.attr,
&dev_attr_pimpampom.attr,
+ &dev_attr_logging.attr,
NULL,
};
@@ -2036,6 +2058,21 @@ void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo)
}
}
+/**
+ * ccw_device_siosl() - initiate logging
+ * @cdev: ccw device
+ *
+ * This function is used to invoke model-dependent logging within the channel
+ * subsystem.
+ */
+int ccw_device_siosl(struct ccw_device *cdev)
+{
+ struct subchannel *sch = to_subchannel(cdev->dev.parent);
+
+ return chsc_siosl(sch->schid);
+}
+EXPORT_SYMBOL_GPL(ccw_device_siosl);
+
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccw_device_set_online);
EXPORT_SYMBOL(ccw_device_set_offline);
diff --git a/drivers/s390/cio/itcw.c b/drivers/s390/cio/itcw.c
index 17da9ab932ed..a0ae29564774 100644
--- a/drivers/s390/cio/itcw.c
+++ b/drivers/s390/cio/itcw.c
@@ -42,7 +42,7 @@
* size_t size;
*
* size = itcw_calc_size(1, 2, 0);
- * buffer = kmalloc(size, GFP_DMA);
+ * buffer = kmalloc(size, GFP_KERNEL | GFP_DMA);
* if (!buffer)
* return -ENOMEM;
* itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0);
diff --git a/drivers/s390/net/smsgiucv_app.c b/drivers/s390/net/smsgiucv_app.c
index 137688790207..4d2ea4000422 100644
--- a/drivers/s390/net/smsgiucv_app.c
+++ b/drivers/s390/net/smsgiucv_app.c
@@ -180,6 +180,13 @@ static int __init smsgiucv_app_init(void)
goto fail_put_driver;
}
+ /* convert sender to uppercase characters */
+ if (sender) {
+ int len = strlen(sender);
+ while (len--)
+ sender[len] = toupper(sender[len]);
+ }
+
/* register with the smsgiucv device driver */
rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
if (rc) {
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
index d4fc4287ebd3..24d015241e5b 100644
--- a/drivers/scsi/bfa/bfad.c
+++ b/drivers/scsi/bfa/bfad.c
@@ -729,6 +729,7 @@ bfad_drv_init(struct bfad_s *bfad)
memset(&driver_info, 0, sizeof(driver_info));
strncpy(driver_info.version, BFAD_DRIVER_VERSION,
sizeof(driver_info.version) - 1);
+ __kernel_param_lock();
if (host_name)
strncpy(driver_info.host_machine_name, host_name,
sizeof(driver_info.host_machine_name) - 1);
@@ -738,6 +739,7 @@ bfad_drv_init(struct bfad_s *bfad)
if (os_patch)
strncpy(driver_info.host_os_patch, os_patch,
sizeof(driver_info.host_os_patch) - 1);
+ __kernel_param_unlock();
strncpy(driver_info.os_device_name, bfad->pci_name,
sizeof(driver_info.os_device_name - 1));
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 18735b39b3d3..3ddb4dc62d5d 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -542,8 +542,11 @@ MODULE_DEVICE_TABLE (of, mac53c94_match);
static struct macio_driver mac53c94_driver =
{
- .name = "mac53c94",
- .match_table = mac53c94_match,
+ .driver = {
+ .name = "mac53c94",
+ .owner = THIS_MODULE,
+ .of_match_table = mac53c94_match,
+ },
.probe = mac53c94_probe,
.remove = mac53c94_remove,
};
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index a1c97e88068a..1f784fde2510 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -2036,8 +2036,11 @@ MODULE_DEVICE_TABLE (of, mesh_match);
static struct macio_driver mesh_driver =
{
- .name = "mesh",
- .match_table = mesh_match,
+ .driver = {
+ .name = "mesh",
+ .owner = THIS_MODULE,
+ .of_match_table = mesh_match,
+ },
.probe = mesh_probe,
.remove = mesh_remove,
.shutdown = mesh_shutdown,
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 829cc37abc41..8802e48bc063 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -97,6 +97,7 @@ MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);
#endif
static int sd_revalidate_disk(struct gendisk *);
+static void sd_unlock_native_capacity(struct gendisk *disk);
static int sd_probe(struct device *);
static int sd_remove(struct device *);
static void sd_shutdown(struct device *);
@@ -1101,6 +1102,7 @@ static const struct block_device_operations sd_fops = {
#endif
.media_changed = sd_media_changed,
.revalidate_disk = sd_revalidate_disk,
+ .unlock_native_capacity = sd_unlock_native_capacity,
};
static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd)
@@ -2121,6 +2123,26 @@ static int sd_revalidate_disk(struct gendisk *disk)
}
/**
+ * sd_unlock_native_capacity - unlock native capacity
+ * @disk: struct gendisk to set capacity for
+ *
+ * Block layer calls this function if it detects that partitions
+ * on @disk reach beyond the end of the device. If the SCSI host
+ * implements ->unlock_native_capacity() method, it's invoked to
+ * give it a chance to adjust the device capacity.
+ *
+ * CONTEXT:
+ * Defined by block layer. Might sleep.
+ */
+static void sd_unlock_native_capacity(struct gendisk *disk)
+{
+ struct scsi_device *sdev = scsi_disk(disk)->device;
+
+ if (sdev->host->hostt->unlock_native_capacity)
+ sdev->host->hostt->unlock_native_capacity(sdev);
+}
+
+/**
* sd_format_disk_name - format disk name
* @prefix: name prefix - ie. "sd" for SCSI disks
* @index: index of the disk to format name for
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 30463862603b..9330edb323e2 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -78,10 +78,6 @@ struct m68k_serial *m68k_consinfo = 0;
#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
-#ifdef CONFIG_CONSOLE
-extern wait_queue_head_t keypress_wait;
-#endif
-
struct tty_driver *serial_driver;
/* number of characters left in xmit buffer before we ask for more */
@@ -300,10 +296,6 @@ static void receive_chars(struct m68k_serial *info, unsigned short rx)
return;
#endif /* CONFIG_MAGIC_SYSRQ */
}
- /* It is a 'keyboard interrupt' ;-) */
-#ifdef CONFIG_CONSOLE
- wake_up(&keypress_wait);
-#endif
}
if(!tty)
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 01c012da4e26..746a44621d91 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -982,6 +982,18 @@ static int skip_tx_en_setup(struct serial_private *priv,
#define PCI_SUBDEVICE_ID_POCTAL422 0x0408
#define PCI_VENDOR_ID_ADVANTECH 0x13fe
#define PCI_DEVICE_ID_ADVANTECH_PCI3620 0x3620
+#define PCI_DEVICE_ID_TITAN_200I 0x8028
+#define PCI_DEVICE_ID_TITAN_400I 0x8048
+#define PCI_DEVICE_ID_TITAN_800I 0x8088
+#define PCI_DEVICE_ID_TITAN_800EH 0xA007
+#define PCI_DEVICE_ID_TITAN_800EHB 0xA008
+#define PCI_DEVICE_ID_TITAN_400EH 0xA009
+#define PCI_DEVICE_ID_TITAN_100E 0xA010
+#define PCI_DEVICE_ID_TITAN_200E 0xA012
+#define PCI_DEVICE_ID_TITAN_400E 0xA013
+#define PCI_DEVICE_ID_TITAN_800E 0xA014
+#define PCI_DEVICE_ID_TITAN_200EI 0xA016
+#define PCI_DEVICE_ID_TITAN_200EISI 0xA017
/* Unknown vendors/cards - this should not be in linux/pci_ids.h */
#define PCI_SUBDEVICE_ID_UNKNOWN_0x1584 0x1584
@@ -1541,6 +1553,10 @@ enum pci_board_num_t {
pbn_b3_4_115200,
pbn_b3_8_115200,
+ pbn_b4_bt_2_921600,
+ pbn_b4_bt_4_921600,
+ pbn_b4_bt_8_921600,
+
/*
* Board-specific versions.
*/
@@ -1995,6 +2011,25 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.uart_offset = 8,
},
+ [pbn_b4_bt_2_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 2,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_4_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 4,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+ [pbn_b4_bt_8_921600] = {
+ .flags = FL_BASE4,
+ .num_ports = 8,
+ .base_baud = 921600,
+ .uart_offset = 8,
+ },
+
/*
* Entries following this are board-specific.
*/
@@ -3043,6 +3078,42 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_2_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800I,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b4_bt_8_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EH,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800EHB,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_4_921600 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_1_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_4_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800E,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_8_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
+ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200EISI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_oxsemi_2_4000000 },
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c
index bcee156d2f2e..0f1189605d21 100644
--- a/drivers/serial/altera_uart.c
+++ b/drivers/serial/altera_uart.c
@@ -89,15 +89,12 @@ static unsigned int altera_uart_tx_empty(struct uart_port *port)
static unsigned int altera_uart_get_mctrl(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
- unsigned long flags;
unsigned int sigs;
- spin_lock_irqsave(&port->lock, flags);
sigs =
(readl(port->membase + ALTERA_UART_STATUS_REG) &
ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0;
sigs |= (pp->sigs & TIOCM_RTS);
- spin_unlock_irqrestore(&port->lock, flags);
return sigs;
}
@@ -105,49 +102,37 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port)
static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
pp->sigs = sigs;
if (sigs & TIOCM_RTS)
pp->imr |= ALTERA_UART_CONTROL_RTS_MSK;
else
pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
- spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_start_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
- spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_tx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
- spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_stop_rx(struct uart_port *port)
{
struct altera_uart *pp = container_of(port, struct altera_uart, port);
- unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK;
writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG);
- spin_unlock_irqrestore(&port->lock, flags);
}
static void altera_uart_break_ctl(struct uart_port *port, int break_state)
@@ -272,10 +257,14 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data)
unsigned int isr;
isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr;
+
+ spin_lock(&port->lock);
if (isr & ALTERA_UART_STATUS_RRDY_MSK)
altera_uart_rx_chars(pp);
if (isr & ALTERA_UART_STATUS_TRDY_MSK)
altera_uart_tx_chars(pp);
+ spin_unlock(&port->lock);
+
return IRQ_RETVAL(isr);
}
@@ -402,31 +391,24 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp)
return 0;
}
-static void altera_uart_console_putc(struct console *co, const char c)
+static void altera_uart_console_putc(struct uart_port *port, const char c)
{
- struct uart_port *port = &(altera_uart_ports + co->index)->port;
- int i;
+ while (!(readl(port->membase + ALTERA_UART_STATUS_REG) &
+ ALTERA_UART_STATUS_TRDY_MSK))
+ cpu_relax();
- for (i = 0; i < 0x10000; i++) {
- if (readl(port->membase + ALTERA_UART_STATUS_REG) &
- ALTERA_UART_STATUS_TRDY_MSK)
- break;
- }
writel(c, port->membase + ALTERA_UART_TXDATA_REG);
- for (i = 0; i < 0x10000; i++) {
- if (readl(port->membase + ALTERA_UART_STATUS_REG) &
- ALTERA_UART_STATUS_TRDY_MSK)
- break;
- }
}
static void altera_uart_console_write(struct console *co, const char *s,
unsigned int count)
{
+ struct uart_port *port = &(altera_uart_ports + co->index)->port;
+
for (; count; count--, s++) {
- altera_uart_console_putc(co, *s);
+ altera_uart_console_putc(port, *s);
if (*s == '\n')
- altera_uart_console_putc(co, '\r');
+ altera_uart_console_putc(port, '\r');
}
}
@@ -516,7 +498,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev)
return 0;
}
-static int altera_uart_remove(struct platform_device *pdev)
+static int __devexit altera_uart_remove(struct platform_device *pdev)
{
struct uart_port *port;
int i;
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 96f7e7484fee..511cbf687877 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -797,7 +797,7 @@ static void bfin_serial_shutdown(struct uart_port *port)
gpio_free(uart->rts_pin);
#endif
#ifdef CONFIG_SERIAL_BFIN_HARD_CTSRTS
- if (UART_GET_IER(uart) && EDSSI)
+ if (UART_GET_IER(uart) & EDSSI)
free_irq(uart->status_irq, uart);
#endif
}
@@ -869,7 +869,12 @@ bfin_serial_set_termios(struct uart_port *port, struct ktermios *termios,
}
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud) - ANOMALY_05000230;
+ quot = uart_get_divisor(port, baud);
+
+ /* If discipline is not IRDA, apply ANOMALY_05000230 */
+ if (termios->c_line != N_IRDA)
+ quot -= ANOMALY_05000230;
+
spin_lock_irqsave(&uart->port.lock, flags);
UART_SET_ANOMALY_THRESHOLD(uart, USEC_PER_SEC / baud * 15);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 84a35f699016..1a88b363005c 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -113,7 +113,9 @@ struct psc_ops {
unsigned char (*read_char)(struct uart_port *port);
void (*cw_disable_ints)(struct uart_port *port);
void (*cw_restore_ints)(struct uart_port *port);
- unsigned long (*getuartclk)(void *p);
+ unsigned int (*set_baudrate)(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old);
int (*clock)(struct uart_port *port, int enable);
int (*fifoc_init)(void);
void (*fifoc_uninit)(void);
@@ -121,6 +123,16 @@ struct psc_ops {
irqreturn_t (*handle_irq)(struct uart_port *port);
};
+/* setting the prescaler and divisor reg is common for all chips */
+static inline void mpc52xx_set_divisor(struct mpc52xx_psc __iomem *psc,
+ u16 prescaler, unsigned int divisor)
+{
+ /* select prescaler */
+ out_be16(&psc->mpc52xx_psc_clock_select, prescaler);
+ out_8(&psc->ctur, divisor >> 8);
+ out_8(&psc->ctlr, divisor & 0xff);
+}
+
#ifdef CONFIG_PPC_MPC52xx
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
static void mpc52xx_psc_fifo_init(struct uart_port *port)
@@ -128,9 +140,6 @@ static void mpc52xx_psc_fifo_init(struct uart_port *port)
struct mpc52xx_psc __iomem *psc = PSC(port);
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
- /* /32 prescaler */
- out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
-
out_8(&fifo->rfcntl, 0x00);
out_be16(&fifo->rfalarm, 0x1ff);
out_8(&fifo->tfcntl, 0x07);
@@ -219,15 +228,47 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
}
-/* Search for bus-frequency property in this node or a parent */
-static unsigned long mpc52xx_getuartclk(void *p)
+static unsigned int mpc5200_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
{
- /*
- * 5200 UARTs have a / 32 prescaler
- * but the generic serial code assumes 16
- * so return ipb freq / 2
- */
- return mpc5xxx_get_bus_frequency(p) / 2;
+ unsigned int baud;
+ unsigned int divisor;
+
+ /* The 5200 has a fixed /32 prescaler, uartclk contains the ipb freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (32 * 0xffff) + 1,
+ port->uartclk / 32);
+ divisor = (port->uartclk + 16 * baud) / (32 * baud);
+
+ /* enable the /32 prescaler and set the divisor */
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+ return baud;
+}
+
+static unsigned int mpc5200b_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
+{
+ unsigned int baud;
+ unsigned int divisor;
+ u16 prescaler;
+
+ /* The 5200B has a selectable /4 or /32 prescaler, uartclk contains the
+ * ipb freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (32 * 0xffff) + 1,
+ port->uartclk / 4);
+ divisor = (port->uartclk + 2 * baud) / (4 * baud);
+
+ /* select the proper prescaler and set the divisor */
+ if (divisor > 0xffff) {
+ divisor = (divisor + 4) / 8;
+ prescaler = 0xdd00; /* /32 */
+ } else
+ prescaler = 0xff00; /* /4 */
+ mpc52xx_set_divisor(PSC(port), prescaler, divisor);
+ return baud;
}
static void mpc52xx_psc_get_irq(struct uart_port *port, struct device_node *np)
@@ -258,7 +299,28 @@ static struct psc_ops mpc52xx_psc_ops = {
.read_char = mpc52xx_psc_read_char,
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
- .getuartclk = mpc52xx_getuartclk,
+ .set_baudrate = mpc5200_psc_set_baudrate,
+ .get_irq = mpc52xx_psc_get_irq,
+ .handle_irq = mpc52xx_psc_handle_irq,
+};
+
+static struct psc_ops mpc5200b_psc_ops = {
+ .fifo_init = mpc52xx_psc_fifo_init,
+ .raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
+ .raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
+ .rx_rdy = mpc52xx_psc_rx_rdy,
+ .tx_rdy = mpc52xx_psc_tx_rdy,
+ .tx_empty = mpc52xx_psc_tx_empty,
+ .stop_rx = mpc52xx_psc_stop_rx,
+ .start_tx = mpc52xx_psc_start_tx,
+ .stop_tx = mpc52xx_psc_stop_tx,
+ .rx_clr_irq = mpc52xx_psc_rx_clr_irq,
+ .tx_clr_irq = mpc52xx_psc_tx_clr_irq,
+ .write_char = mpc52xx_psc_write_char,
+ .read_char = mpc52xx_psc_read_char,
+ .cw_disable_ints = mpc52xx_psc_cw_disable_ints,
+ .cw_restore_ints = mpc52xx_psc_cw_restore_ints,
+ .set_baudrate = mpc5200b_psc_set_baudrate,
.get_irq = mpc52xx_psc_get_irq,
.handle_irq = mpc52xx_psc_handle_irq,
};
@@ -392,9 +454,35 @@ static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
}
-static unsigned long mpc512x_getuartclk(void *p)
+static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
+ struct ktermios *new,
+ struct ktermios *old)
{
- return mpc5xxx_get_bus_frequency(p);
+ unsigned int baud;
+ unsigned int divisor;
+
+ /*
+ * The "MPC5121e Microcontroller Reference Manual, Rev. 3" says on
+ * pg. 30-10 that the chip supports a /32 and a /10 prescaler.
+ * Furthermore, it states that "After reset, the prescaler by 10
+ * for the UART mode is selected", but the reset register value is
+ * 0x0000 which means a /32 prescaler. This is wrong.
+ *
+ * In reality using /32 prescaler doesn't work, as it is not supported!
+ * Use /16 or /10 prescaler, see "MPC5121e Hardware Design Guide",
+ * Chapter 4.1 PSC in UART Mode.
+ * Calculate with a /16 prescaler here.
+ */
+
+ /* uartclk contains the ips freq */
+ baud = uart_get_baud_rate(port, new, old,
+ port->uartclk / (16 * 0xffff) + 1,
+ port->uartclk / 16);
+ divisor = (port->uartclk + 8 * baud) / (16 * baud);
+
+ /* enable the /16 prescaler and set the divisor */
+ mpc52xx_set_divisor(PSC(port), 0xdd00, divisor);
+ return baud;
}
/* Init PSC FIFO Controller */
@@ -498,7 +586,7 @@ static struct psc_ops mpc512x_psc_ops = {
.read_char = mpc512x_psc_read_char,
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
- .getuartclk = mpc512x_getuartclk,
+ .set_baudrate = mpc512x_psc_set_baudrate,
.clock = mpc512x_psc_clock,
.fifoc_init = mpc512x_psc_fifoc_init,
.fifoc_uninit = mpc512x_psc_fifoc_uninit,
@@ -666,8 +754,8 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
struct mpc52xx_psc __iomem *psc = PSC(port);
unsigned long flags;
unsigned char mr1, mr2;
- unsigned short ctr;
- unsigned int j, baud, quot;
+ unsigned int j;
+ unsigned int baud;
/* Prepare what we're gonna write */
mr1 = 0;
@@ -704,16 +792,9 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
mr2 |= MPC52xx_PSC_MODE_TXCTS;
}
- baud = uart_get_baud_rate(port, new, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud);
- ctr = quot & 0xffff;
-
/* Get the lock */
spin_lock_irqsave(&port->lock, flags);
- /* Update the per-port timeout */
- uart_update_timeout(port, new->c_cflag, baud);
-
/* Do our best to flush TX & RX, so we don't lose anything */
/* But we don't wait indefinitely ! */
j = 5000000; /* Maximum wait */
@@ -737,8 +818,10 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
out_8(&psc->mode, mr1);
out_8(&psc->mode, mr2);
- out_8(&psc->ctur, ctr >> 8);
- out_8(&psc->ctlr, ctr & 0xff);
+ baud = psc_ops->set_baudrate(port, new, old);
+
+ /* Update the per-port timeout */
+ uart_update_timeout(port, new->c_cflag, baud);
if (UART_ENABLE_MS(port, new->c_cflag))
mpc52xx_uart_enable_ms(port);
@@ -1118,7 +1201,7 @@ mpc52xx_console_setup(struct console *co, char *options)
return ret;
}
- uartclk = psc_ops->getuartclk(np);
+ uartclk = mpc5xxx_get_bus_frequency(np);
if (uartclk == 0) {
pr_debug("Could not find uart clock frequency!\n");
return -EINVAL;
@@ -1201,6 +1284,7 @@ static struct uart_driver mpc52xx_uart_driver = {
static struct of_device_id mpc52xx_uart_of_match[] = {
#ifdef CONFIG_PPC_MPC52xx
+ { .compatible = "fsl,mpc5200b-psc-uart", .data = &mpc5200b_psc_ops, },
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
/* binding used by old lite5200 device trees: */
{ .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
@@ -1233,7 +1317,10 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
pr_debug("Found %s assigned to ttyPSC%x\n",
mpc52xx_uart_nodes[idx]->full_name, idx);
- uartclk = psc_ops->getuartclk(op->dev.of_node);
+ /* set the uart clock to the input clock of the psc, the different
+ * prescalers are taken into account in the set_baudrate() methods
+ * of the respective chip */
+ uartclk = mpc5xxx_get_bus_frequency(op->dev.of_node);
if (uartclk == 0) {
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
return -EINVAL;
diff --git a/drivers/serial/msm_serial.c b/drivers/serial/msm_serial.c
index ecdc0facf7ee..f8c816e7725d 100644
--- a/drivers/serial/msm_serial.c
+++ b/drivers/serial/msm_serial.c
@@ -41,19 +41,6 @@ struct msm_port {
unsigned int imr;
};
-#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
-
-static inline void msm_write(struct uart_port *port, unsigned int val,
- unsigned int off)
-{
- __raw_writel(val, port->membase + off);
-}
-
-static inline unsigned int msm_read(struct uart_port *port, unsigned int off)
-{
- return __raw_readl(port->membase + off);
-}
-
static void msm_stop_tx(struct uart_port *port)
{
struct msm_port *msm_port = UART_TO_MSM(port);
@@ -320,11 +307,7 @@ static void msm_init_clock(struct uart_port *port)
struct msm_port *msm_port = UART_TO_MSM(port);
clk_enable(msm_port->clk);
-
- msm_write(port, 0xC0, UART_MREG);
- msm_write(port, 0xB2, UART_NREG);
- msm_write(port, 0x7D, UART_DREG);
- msm_write(port, 0x1C, UART_MNDREG);
+ msm_serial_set_mnd_regs(port);
}
static int msm_startup(struct uart_port *port)
@@ -706,6 +689,8 @@ static int __init msm_serial_probe(struct platform_device *pdev)
if (unlikely(IS_ERR(msm_port->clk)))
return PTR_ERR(msm_port->clk);
port->uartclk = clk_get_rate(msm_port->clk);
+ printk(KERN_INFO "uartclk = %d\n", port->uartclk);
+
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(!resource))
diff --git a/drivers/serial/msm_serial.h b/drivers/serial/msm_serial.h
index 689f1fa0e84e..f6ca9ca79e98 100644
--- a/drivers/serial/msm_serial.h
+++ b/drivers/serial/msm_serial.h
@@ -114,4 +114,60 @@
#define UART_MISR 0x0010
#define UART_ISR 0x0014
+#define UART_TO_MSM(uart_port) ((struct msm_port *) uart_port)
+
+static inline
+void msm_write(struct uart_port *port, unsigned int val, unsigned int off)
+{
+ __raw_writel(val, port->membase + off);
+}
+
+static inline
+unsigned int msm_read(struct uart_port *port, unsigned int off)
+{
+ return __raw_readl(port->membase + off);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock.
+ */
+static inline void msm_serial_set_mnd_regs_tcxo(struct uart_port *port)
+{
+ msm_write(port, 0x06, UART_MREG);
+ msm_write(port, 0xF1, UART_NREG);
+ msm_write(port, 0x0F, UART_DREG);
+ msm_write(port, 0x1A, UART_MNDREG);
+}
+
+/*
+ * Setup the MND registers to use the TCXO clock divided by 4.
+ */
+static inline void msm_serial_set_mnd_regs_tcxoby4(struct uart_port *port)
+{
+ msm_write(port, 0x18, UART_MREG);
+ msm_write(port, 0xF6, UART_NREG);
+ msm_write(port, 0x0F, UART_DREG);
+ msm_write(port, 0x0A, UART_MNDREG);
+}
+
+static inline
+void msm_serial_set_mnd_regs_from_uartclk(struct uart_port *port)
+{
+ if (port->uartclk == 19200000)
+ msm_serial_set_mnd_regs_tcxo(port);
+ else
+ msm_serial_set_mnd_regs_tcxoby4(port);
+}
+
+/*
+ * TROUT has a specific defect that makes it report it's uartclk
+ * as 19.2Mhz (TCXO) when it's actually 4.8Mhz (TCXO/4). This special
+ * cases TROUT to use the right clock.
+ */
+#ifdef CONFIG_MACH_TROUT
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_tcxoby4
+#else
+#define msm_serial_set_mnd_regs msm_serial_set_mnd_regs_from_uartclk
+#endif
+
#endif /* __DRIVERS_SERIAL_MSM_SERIAL_H */
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index cabbdc7ba583..5b9cde79e4ea 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -2005,8 +2005,11 @@ static struct of_device_id pmz_match[] =
MODULE_DEVICE_TABLE (of, pmz_match);
static struct macio_driver pmz_driver = {
- .name = "pmac_zilog",
- .match_table = pmz_match,
+ .driver = {
+ .name = "pmac_zilog",
+ .owner = THIS_MODULE,
+ .of_match_table = pmz_match,
+ },
.probe = pmz_attach,
.remove = pmz_detach,
.suspend = pmz_suspend,
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index dadd686c9801..526307368f8b 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -715,6 +715,8 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
@@ -724,8 +726,6 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
- PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
- PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
@@ -768,17 +768,26 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x0276),
PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0101), /* TDK DF2814 */
+ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x100a), /* Xircom CM-56G */
+ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x3e0a), /* TDK DF5660 */
PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+ PCMCIA_DEVICE_MANF_CARD(0x0107, 0x0002), /* USRobotics 14,400 */
PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+ PCMCIA_DEVICE_MANF_CARD(0x0115, 0x3330), /* USRobotics/SUN 14,400 */
+ PCMCIA_DEVICE_MANF_CARD(0x0124, 0x0100), /* Nokia DTP-2 ver II */
+ PCMCIA_DEVICE_MANF_CARD(0x0134, 0x5600), /* LASAT COMMUNICATIONS A/S */
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+ PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0006), /* Psion 56K+Fax */
+ PCMCIA_DEVICE_MANF_CARD(0x0200, 0x0001), /* MultiMobile */
PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
@@ -792,16 +801,21 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "ISDN/56K/GSM", 0xb569a6e5, 0xfee5297b),
PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400+", 0x816cc815, 0x412729fb),
+ PCMCIA_DEVICE_PROD_ID12("Intertex", "IX34-PCMCIA", 0xf8a097e3, 0x97880447),
PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
+ PCMCIA_DEVICE_PROD_ID12("Option International", "V34bis GSM/PSTN Data/Fax Modem", 0x9d7cd6f5, 0x5cb8bf41),
PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "Dual RS-232 Serial Port PC Card", 0xc4420b35, 0x031a380d),
+ PCMCIA_DEVICE_PROD_ID12("Telia", "SurfinBird 560P/A+", 0xe2cdd5e, 0xc9314b38),
+ PCMCIA_DEVICE_PROD_ID1("Smart Serial Port", 0x2d8ce292),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 5f90fcd7d107..c291b3add1d2 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -346,6 +346,27 @@ static int scif_rxfill(struct uart_port *port)
return sci_in(port, SCFDR) & SCIF2_RFDC_MASK;
}
}
+#elif defined(CONFIG_ARCH_SH7372)
+static int scif_txfill(struct uart_port *port)
+{
+ if (port->type == PORT_SCIFA)
+ return sci_in(port, SCFDR) >> 8;
+ else
+ return sci_in(port, SCTFDR);
+}
+
+static int scif_txroom(struct uart_port *port)
+{
+ return port->fifosize - scif_txfill(port);
+}
+
+static int scif_rxfill(struct uart_port *port)
+{
+ if (port->type == PORT_SCIFA)
+ return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+ else
+ return sci_in(port, SCRFDR);
+}
#else
static int scif_txfill(struct uart_port *port)
{
@@ -683,7 +704,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr)
u16 ssr = sci_in(port, SCxSR);
/* Disable future Rx interrupts */
- if (port->type == PORT_SCIFA) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
disable_irq_nosync(irq);
scr |= 0x4000;
} else {
@@ -928,7 +949,7 @@ static void sci_dma_tx_complete(void *arg)
if (!uart_circ_empty(xmit)) {
schedule_work(&s->work_tx);
- } else if (port->type == PORT_SCIFA) {
+ } else if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 ctrl = sci_in(port, SCSCR);
sci_out(port, SCSCR, ctrl & ~SCI_CTRL_FLAGS_TIE);
}
@@ -1184,7 +1205,7 @@ static void sci_start_tx(struct uart_port *port)
unsigned short ctrl;
#ifdef CONFIG_SERIAL_SH_SCI_DMA
- if (port->type == PORT_SCIFA) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
u16 new, scr = sci_in(port, SCSCR);
if (s->chan_tx)
new = scr | 0x8000;
@@ -1197,7 +1218,7 @@ static void sci_start_tx(struct uart_port *port)
s->cookie_tx < 0)
schedule_work(&s->work_tx);
#endif
- if (!s->chan_tx || port->type == PORT_SCIFA) {
+ if (!s->chan_tx || port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
/* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
sci_out(port, SCSCR, ctrl | SCI_CTRL_FLAGS_TIE);
@@ -1210,7 +1231,7 @@ static void sci_stop_tx(struct uart_port *port)
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
- if (port->type == PORT_SCIFA)
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x8000;
ctrl &= ~SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
@@ -1222,7 +1243,7 @@ static void sci_start_rx(struct uart_port *port)
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl |= sci_in(port, SCSCR);
- if (port->type == PORT_SCIFA)
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x4000;
sci_out(port, SCSCR, ctrl);
}
@@ -1233,7 +1254,7 @@ static void sci_stop_rx(struct uart_port *port)
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
ctrl = sci_in(port, SCSCR);
- if (port->type == PORT_SCIFA)
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB)
ctrl &= ~0x4000;
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
sci_out(port, SCSCR, ctrl);
@@ -1271,7 +1292,7 @@ static void rx_timer_fn(unsigned long arg)
struct uart_port *port = &s->port;
u16 scr = sci_in(port, SCSCR);
- if (port->type == PORT_SCIFA) {
+ if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) {
scr &= ~0x4000;
enable_irq(s->irqs[1]);
}
@@ -1524,6 +1545,8 @@ static const char *sci_type(struct uart_port *port)
return "scif";
case PORT_SCIFA:
return "scifa";
+ case PORT_SCIFB:
+ return "scifb";
}
return NULL;
@@ -1612,6 +1635,9 @@ static int __devinit sci_init_single(struct platform_device *dev,
port->line = index;
switch (p->type) {
+ case PORT_SCIFB:
+ port->fifosize = 256;
+ break;
case PORT_SCIFA:
port->fifosize = 64;
break;
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index f70c49f915fa..9b52f77a9305 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -322,7 +322,7 @@
#define CPU_SCIx_FNS(name, sci_offset, sci_size, scif_offset, scif_size)\
static inline unsigned int sci_##name##_in(struct uart_port *port) \
{ \
- if (port->type == PORT_SCIF) { \
+ if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \
SCI_IN(scif_size, scif_offset) \
} else { /* PORT_SCI or PORT_SCIFA */ \
SCI_IN(sci_size, sci_offset); \
@@ -330,7 +330,7 @@
} \
static inline void sci_##name##_out(struct uart_port *port, unsigned int value) \
{ \
- if (port->type == PORT_SCIF) { \
+ if (port->type == PORT_SCIF || port->type == PORT_SCIFB) { \
SCI_OUT(scif_size, scif_offset, value) \
} else { /* PORT_SCI or PORT_SCIFA */ \
SCI_OUT(sci_size, sci_offset, value); \
@@ -384,8 +384,12 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372)
+ defined(CONFIG_ARCH_SH7377)
+#define SCIF_FNS(name, scif_offset, scif_size) \
+ CPU_SCIF_FNS(name, scif_offset, scif_size)
+#elif defined(CONFIG_ARCH_SH7372)
+#define SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size) \
+ CPU_SCIx_FNS(name, sh4_scifa_offset, sh4_scifa_size, sh4_scifb_offset, sh4_scifb_size)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -422,8 +426,7 @@
defined(CONFIG_CPU_SUBTYPE_SH7720) || \
defined(CONFIG_CPU_SUBTYPE_SH7721) || \
defined(CONFIG_ARCH_SH7367) || \
- defined(CONFIG_ARCH_SH7377) || \
- defined(CONFIG_ARCH_SH7372)
+ defined(CONFIG_ARCH_SH7377)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
@@ -436,6 +439,20 @@ SCIF_FNS(SCFDR, 0x1c, 16)
SCIF_FNS(SCxTDR, 0x20, 8)
SCIF_FNS(SCxRDR, 0x24, 8)
SCIF_FNS(SCLSR, 0x00, 0)
+#elif defined(CONFIG_ARCH_SH7372)
+SCIF_FNS(SCSMR, 0x00, 16)
+SCIF_FNS(SCBRR, 0x04, 8)
+SCIF_FNS(SCSCR, 0x08, 16)
+SCIF_FNS(SCTDSR, 0x0c, 16)
+SCIF_FNS(SCFER, 0x10, 16)
+SCIF_FNS(SCxSR, 0x14, 16)
+SCIF_FNS(SCFCR, 0x18, 16)
+SCIF_FNS(SCFDR, 0x1c, 16)
+SCIF_FNS(SCTFDR, 0x38, 16)
+SCIF_FNS(SCRFDR, 0x3c, 16)
+SCIx_FNS(SCxTDR, 0x20, 8, 0x40, 8)
+SCIx_FNS(SCxRDR, 0x24, 8, 0x60, 8)
+SCIF_FNS(SCLSR, 0x00, 0)
#elif defined(CONFIG_CPU_SUBTYPE_SH7723) ||\
defined(CONFIG_CPU_SUBTYPE_SH7724)
SCIx_FNS(SCSMR, 0x00, 16, 0x00, 16)
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index 005195958647..ceba593dc84f 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -441,8 +441,10 @@ struct sfi_table_attr __init *sfi_sysfs_install_table(u64 pa)
ret = sysfs_create_bin_file(tables_kobj,
&tbl_attr->attr);
- if (ret)
+ if (ret) {
kfree(tbl_attr);
+ tbl_attr = NULL;
+ }
sfi_unmap_table(th);
return tbl_attr;
diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile
index 78bb5127abd0..08fc653a825c 100644
--- a/drivers/sh/Makefile
+++ b/drivers/sh/Makefile
@@ -1,9 +1,10 @@
#
# Makefile for the SuperH specific drivers.
#
+obj-y := clk.o intc.o
+
obj-$(CONFIG_SUPERHYWAY) += superhyway/
obj-$(CONFIG_MAPLE) += maple/
+
obj-$(CONFIG_GENERIC_GPIO) += pfc.o
-obj-$(CONFIG_SUPERH) += clk.o
obj-$(CONFIG_SH_CLK_CPG) += clk-cpg.o
-obj-y += intc.o
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index c585574b9aed..e91a23e5ffd8 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -16,6 +16,8 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/module.h>
@@ -855,8 +857,8 @@ static void __init intc_register_irq(struct intc_desc *desc,
primary = 1;
if (!data[0] && !data[1])
- pr_warning("intc: missing unique irq mask for "
- "irq %d (vect 0x%04x)\n", irq, irq2evt(irq));
+ pr_warning("missing unique irq mask for irq %d (vect 0x%04x)\n",
+ irq, irq2evt(irq));
data[0] = data[0] ? data[0] : intc_mask_data(desc, d, enum_id, 1);
data[1] = data[1] ? data[1] : intc_prio_data(desc, d, enum_id, 1);
@@ -952,7 +954,7 @@ int __init register_intc_controller(struct intc_desc *desc)
struct intc_desc_int *d;
struct resource *res;
- pr_info("intc: Registered controller '%s' with %u IRQs\n",
+ pr_info("Registered controller '%s' with %u IRQs\n",
desc->name, hw->nr_vectors);
d = kzalloc(sizeof(*d), GFP_NOWAIT);
@@ -1148,7 +1150,7 @@ int register_intc_userimask(unsigned long addr)
if (unlikely(!uimask))
return -ENOMEM;
- pr_info("intc: userimask support registered for levels 0 -> %d\n",
+ pr_info("userimask support registered for levels 0 -> %d\n",
default_prio_level - 1);
return 0;
@@ -1286,7 +1288,7 @@ static int __init register_intc_sysdevs(void)
}
if (error)
- pr_err("intc: sysdev registration error\n");
+ pr_err("sysdev registration error\n");
return error;
}
diff --git a/drivers/spi/mpc512x_psc_spi.c b/drivers/spi/mpc512x_psc_spi.c
index 28a126d2742b..2534b1ec3edd 100644
--- a/drivers/spi/mpc512x_psc_spi.c
+++ b/drivers/spi/mpc512x_psc_spi.c
@@ -512,29 +512,29 @@ static int __init mpc512x_psc_spi_of_probe(struct of_device *op,
u64 regaddr64, size64;
s16 id = -1;
- regaddr_p = of_get_address(op->node, 0, &size64, NULL);
+ regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL);
if (!regaddr_p) {
dev_err(&op->dev, "Invalid PSC address\n");
return -EINVAL;
}
- regaddr64 = of_translate_address(op->node, regaddr_p);
+ regaddr64 = of_translate_address(op->dev.of_node, regaddr_p);
/* get PSC id (0..11, used by port_config) */
if (op->dev.platform_data == NULL) {
const u32 *psc_nump;
- psc_nump = of_get_property(op->node, "cell-index", NULL);
+ psc_nump = of_get_property(op->dev.of_node, "cell-index", NULL);
if (!psc_nump || *psc_nump > 11) {
dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
"has invalid cell-index property\n",
- op->node->full_name);
+ op->dev.of_node->full_name);
return -EINVAL;
}
id = *psc_nump;
}
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
- irq_of_parse_and_map(op->node, 0), id);
+ irq_of_parse_and_map(op->dev.of_node, 0), id);
}
static int __exit mpc512x_psc_spi_of_remove(struct of_device *op)
@@ -550,12 +550,12 @@ static struct of_device_id mpc512x_psc_spi_of_match[] = {
MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match);
static struct of_platform_driver mpc512x_psc_spi_of_driver = {
- .match_table = mpc512x_psc_spi_of_match,
.probe = mpc512x_psc_spi_of_probe,
.remove = __exit_p(mpc512x_psc_spi_of_remove),
.driver = {
.name = "mpc512x-psc-spi",
.owner = THIS_MODULE,
+ .of_match_table = mpc512x_psc_spi_of_match,
},
};
diff --git a/drivers/spi/spi_ppc4xx.c b/drivers/spi/spi_ppc4xx.c
index 19c0b3b34fce..d53466a249d9 100644
--- a/drivers/spi/spi_ppc4xx.c
+++ b/drivers/spi/spi_ppc4xx.c
@@ -397,7 +397,7 @@ static int __init spi_ppc4xx_of_probe(struct of_device *op,
struct spi_master *master;
struct spi_bitbang *bbp;
struct resource resource;
- struct device_node *np = op->node;
+ struct device_node *np = op->dev.of_node;
struct device *dev = &op->dev;
struct device_node *opbnp;
int ret;
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c
index 59ae76bace14..7c031fdc8205 100644
--- a/drivers/ssb/driver_chipcommon.c
+++ b/drivers/ssb/driver_chipcommon.c
@@ -209,6 +209,24 @@ static void chipco_powercontrol_init(struct ssb_chipcommon *cc)
}
}
+/* http://bcm-v4.sipsolutions.net/802.11/PmuFastPwrupDelay */
+static u16 pmu_fast_powerup_delay(struct ssb_chipcommon *cc)
+{
+ struct ssb_bus *bus = cc->dev->bus;
+
+ switch (bus->chip_id) {
+ case 0x4312:
+ case 0x4322:
+ case 0x4328:
+ return 7000;
+ case 0x4325:
+ /* TODO: */
+ default:
+ return 15000;
+ }
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/ClkctlFastPwrupDelay */
static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
{
struct ssb_bus *bus = cc->dev->bus;
@@ -218,6 +236,12 @@ static void calc_fast_powerup_delay(struct ssb_chipcommon *cc)
if (bus->bustype != SSB_BUSTYPE_PCI)
return;
+
+ if (cc->capabilities & SSB_CHIPCO_CAP_PMU) {
+ cc->fast_pwrup_delay = pmu_fast_powerup_delay(cc);
+ return;
+ }
+
if (!(cc->capabilities & SSB_CHIPCO_CAP_PCTL))
return;
@@ -235,6 +259,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc)
return; /* We don't have a ChipCommon */
if (cc->dev->id.revision >= 11)
cc->status = chipco_read32(cc, SSB_CHIPCO_CHIPSTAT);
+ ssb_dprintk(KERN_INFO PFX "chipcommon status is 0x%x\n", cc->status);
ssb_pmu_init(cc);
chipco_powercontrol_init(cc);
ssb_chipco_set_clockmode(cc, SSB_CLKMODE_FAST);
diff --git a/drivers/ssb/driver_chipcommon_pmu.c b/drivers/ssb/driver_chipcommon_pmu.c
index 3d551245a4e2..5732bb2c3578 100644
--- a/drivers/ssb/driver_chipcommon_pmu.c
+++ b/drivers/ssb/driver_chipcommon_pmu.c
@@ -502,9 +502,9 @@ static void ssb_pmu_resources_init(struct ssb_chipcommon *cc)
chipco_write32(cc, SSB_CHIPCO_PMU_MAXRES_MSK, max_msk);
}
+/* http://bcm-v4.sipsolutions.net/802.11/SSB/PmuInit */
void ssb_pmu_init(struct ssb_chipcommon *cc)
{
- struct ssb_bus *bus = cc->dev->bus;
u32 pmucap;
if (!(cc->capabilities & SSB_CHIPCO_CAP_PMU))
@@ -516,15 +516,12 @@ void ssb_pmu_init(struct ssb_chipcommon *cc)
ssb_dprintk(KERN_DEBUG PFX "Found rev %u PMU (capabilities 0x%08X)\n",
cc->pmu.rev, pmucap);
- if (cc->pmu.rev >= 1) {
- if ((bus->chip_id == 0x4325) && (bus->chip_rev < 2)) {
- chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
- ~SSB_CHIPCO_PMU_CTL_NOILPONW);
- } else {
- chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
- SSB_CHIPCO_PMU_CTL_NOILPONW);
- }
- }
+ if (cc->pmu.rev == 1)
+ chipco_mask32(cc, SSB_CHIPCO_PMU_CTL,
+ ~SSB_CHIPCO_PMU_CTL_NOILPONW);
+ else
+ chipco_set32(cc, SSB_CHIPCO_PMU_CTL,
+ SSB_CHIPCO_PMU_CTL_NOILPONW);
ssb_pmu_pll_init(cc);
ssb_pmu_resources_init(cc);
}
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 51275aac5b34..7cee7f4eb60b 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -486,6 +486,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
#ifdef CONFIG_SSB_PCIHOST
sdev->irq = bus->host_pci->irq;
dev->parent = &bus->host_pci->dev;
+ sdev->dma_dev = dev->parent;
#endif
break;
case SSB_BUSTYPE_PCMCIA:
@@ -501,6 +502,7 @@ static int ssb_devices_register(struct ssb_bus *bus)
break;
case SSB_BUSTYPE_SSB:
dev->dma_mask = &dev->coherent_dma_mask;
+ sdev->dma_dev = dev;
break;
}
@@ -1226,80 +1228,6 @@ u32 ssb_dma_translation(struct ssb_device *dev)
}
EXPORT_SYMBOL(ssb_dma_translation);
-int ssb_dma_set_mask(struct ssb_device *dev, u64 mask)
-{
-#ifdef CONFIG_SSB_PCIHOST
- int err;
-#endif
-
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- err = pci_set_dma_mask(dev->bus->host_pci, mask);
- if (err)
- return err;
- err = pci_set_consistent_dma_mask(dev->bus->host_pci, mask);
- return err;
-#endif
- case SSB_BUSTYPE_SSB:
- return dma_set_mask(dev->dev, mask);
- default:
- __ssb_dma_not_implemented(dev);
- }
- return -ENOSYS;
-}
-EXPORT_SYMBOL(ssb_dma_set_mask);
-
-void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp_flags)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- if (gfp_flags & GFP_DMA) {
- /* Workaround: The PCI API does not support passing
- * a GFP flag. */
- return dma_alloc_coherent(&dev->bus->host_pci->dev,
- size, dma_handle, gfp_flags);
- }
- return pci_alloc_consistent(dev->bus->host_pci, size, dma_handle);
-#endif
- case SSB_BUSTYPE_SSB:
- return dma_alloc_coherent(dev->dev, size, dma_handle, gfp_flags);
- default:
- __ssb_dma_not_implemented(dev);
- }
- return NULL;
-}
-EXPORT_SYMBOL(ssb_dma_alloc_consistent);
-
-void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- gfp_t gfp_flags)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- if (gfp_flags & GFP_DMA) {
- /* Workaround: The PCI API does not support passing
- * a GFP flag. */
- dma_free_coherent(&dev->bus->host_pci->dev,
- size, vaddr, dma_handle);
- return;
- }
- pci_free_consistent(dev->bus->host_pci, size,
- vaddr, dma_handle);
- return;
-#endif
- case SSB_BUSTYPE_SSB:
- dma_free_coherent(dev->dev, size, vaddr, dma_handle);
- return;
- default:
- __ssb_dma_not_implemented(dev);
- }
-}
-EXPORT_SYMBOL(ssb_dma_free_consistent);
-
int ssb_bus_may_powerdown(struct ssb_bus *bus)
{
struct ssb_chipcommon *cc;
diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c
index 989e2752cc36..6e88d2b603b4 100644
--- a/drivers/ssb/pci.c
+++ b/drivers/ssb/pci.c
@@ -625,9 +625,23 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
ssb_printk(KERN_ERR PFX "No SPROM available!\n");
return -ENODEV;
}
-
- bus->sprom_offset = (bus->chipco.dev->id.revision < 31) ?
- SSB_SPROM_BASE1 : SSB_SPROM_BASE31;
+ if (bus->chipco.dev) { /* can be unavailible! */
+ /*
+ * get SPROM offset: SSB_SPROM_BASE1 except for
+ * chipcommon rev >= 31 or chip ID is 0x4312 and
+ * chipcommon status & 3 == 2
+ */
+ if (bus->chipco.dev->id.revision >= 31)
+ bus->sprom_offset = SSB_SPROM_BASE31;
+ else if (bus->chip_id == 0x4312 &&
+ (bus->chipco.status & 0x03) == 2)
+ bus->sprom_offset = SSB_SPROM_BASE31;
+ else
+ bus->sprom_offset = SSB_SPROM_BASE1;
+ } else {
+ bus->sprom_offset = SSB_SPROM_BASE1;
+ }
+ ssb_dprintk(KERN_INFO PFX "SPROM offset is 0x%x\n", bus->sprom_offset);
buf = kcalloc(SSB_SPROMSIZE_WORDS_R123, sizeof(u16), GFP_KERNEL);
if (!buf)
diff --git a/drivers/ssb/sprom.c b/drivers/ssb/sprom.c
index 007bc3a03486..4f7cc8d13277 100644
--- a/drivers/ssb/sprom.c
+++ b/drivers/ssb/sprom.c
@@ -185,6 +185,7 @@ bool ssb_is_sprom_available(struct ssb_bus *bus)
/* this routine differs from specs as we do not access SPROM directly
on PCMCIA */
if (bus->bustype == SSB_BUSTYPE_PCI &&
+ bus->chipco.dev && /* can be unavailible! */
bus->chipco.dev->id.revision >= 31)
return bus->chipco.capabilities & SSB_CHIPCO_CAP_SPROM;
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index b5c3b3013037..984a75440710 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -141,5 +141,11 @@ source "drivers/staging/ti-st/Kconfig"
source "drivers/staging/adis16255/Kconfig"
+source "drivers/staging/xgifb/Kconfig"
+
+source "drivers/staging/mrst-touchscreen/Kconfig"
+
+source "drivers/staging/msm/Kconfig"
+
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index e330dd5e843d..9fa25133874a 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -51,3 +51,6 @@ obj-$(CONFIG_CRYSTALHD) += crystalhd/
obj-$(CONFIG_CXT1E1) += cxt1e1/
obj-$(CONFIG_TI_ST) += ti-st/
obj-$(CONFIG_ADIS16255) += adis16255/
+obj-$(CONFIG_FB_XGI) += xgifb/
+obj-$(CONFIG_TOUCHSCREEN_MRSTOUCH) += mrst-touchscreen/
+obj-$(CONFIG_MSM_STAGING) += msm/
diff --git a/drivers/staging/adis16255/Kconfig b/drivers/staging/adis16255/Kconfig
index a642be66adea..a883c1f4478b 100644
--- a/drivers/staging/adis16255/Kconfig
+++ b/drivers/staging/adis16255/Kconfig
@@ -1,5 +1,5 @@
config ADIS16255
- tristate "Ananlog Devices ADIS16250/16255"
+ tristate "Analog Devices ADIS16250/16255"
depends on SPI && SYSFS
---help---
If you say yes here you get support for the Analog Devices
diff --git a/drivers/staging/adis16255/adis16255.c b/drivers/staging/adis16255/adis16255.c
index 1ba11f00b2e7..55d66e290f7d 100644
--- a/drivers/staging/adis16255/adis16255.c
+++ b/drivers/staging/adis16255/adis16255.c
@@ -361,7 +361,7 @@ err:
/*-------------------------------------------------------------------------*/
-static int spi_adis16255_probe(struct spi_device *spi)
+static int __devinit spi_adis16255_probe(struct spi_device *spi)
{
struct adis16255_init_data *init_data = spi->dev.platform_data;
@@ -421,7 +421,7 @@ err:
return status;
}
-static int spi_adis16255_remove(struct spi_device *spi)
+static int __devexit spi_adis16255_remove(struct spi_device *spi)
{
struct spi_adis16255_data *spiadis = dev_get_drvdata(&spi->dev);
diff --git a/drivers/staging/batman-adv/device.c b/drivers/staging/batman-adv/device.c
index ad82ec4a4856..7eb6559e0315 100644
--- a/drivers/staging/batman-adv/device.c
+++ b/drivers/staging/batman-adv/device.c
@@ -309,7 +309,7 @@ void bat_device_add_packet(struct device_client *device_client,
struct device_packet *device_packet;
unsigned long flags;
- device_packet = kmalloc(sizeof(struct device_packet), GFP_KERNEL);
+ device_packet = kmalloc(sizeof(struct device_packet), GFP_ATOMIC);
if (!device_packet)
return;
diff --git a/drivers/staging/batman-adv/main.c b/drivers/staging/batman-adv/main.c
index 9d13979c2d8e..74c70d589a93 100644
--- a/drivers/staging/batman-adv/main.c
+++ b/drivers/staging/batman-adv/main.c
@@ -127,7 +127,10 @@ int init_module(void)
return 0;
unreg_soft_device:
- unregister_netdevice(soft_device);
+ unregister_netdev(soft_device);
+ soft_device = NULL;
+ return -ENOMEM;
+
free_soft_device:
free_netdev(soft_device);
soft_device = NULL;
diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c
index d8536e277a26..ac69ed871a76 100644
--- a/drivers/staging/batman-adv/send.c
+++ b/drivers/staging/batman-adv/send.c
@@ -440,6 +440,9 @@ void send_outstanding_bcast_packet(struct work_struct *work)
hlist_del(&forw_packet->list);
spin_unlock_irqrestore(&forw_bcast_list_lock, flags);
+ if (atomic_read(&module_state) == MODULE_DEACTIVATING)
+ goto out;
+
/* rebroadcast packet */
rcu_read_lock();
list_for_each_entry_rcu(batman_if, &if_list, list) {
@@ -453,15 +456,15 @@ void send_outstanding_bcast_packet(struct work_struct *work)
forw_packet->num_packets++;
- /* if we still have some more bcasts to send and we are not shutting
- * down */
- if ((forw_packet->num_packets < 3) &&
- (atomic_read(&module_state) != MODULE_DEACTIVATING))
+ /* if we still have some more bcasts to send */
+ if (forw_packet->num_packets < 3) {
_add_bcast_packet_to_list(forw_packet, ((5 * HZ) / 1000));
- else {
- forw_packet_free(forw_packet);
- atomic_inc(&bcast_queue_left);
+ return;
}
+
+out:
+ forw_packet_free(forw_packet);
+ atomic_inc(&bcast_queue_left);
}
void send_outstanding_bat_packet(struct work_struct *work)
@@ -476,6 +479,9 @@ void send_outstanding_bat_packet(struct work_struct *work)
hlist_del(&forw_packet->list);
spin_unlock_irqrestore(&forw_bat_list_lock, flags);
+ if (atomic_read(&module_state) == MODULE_DEACTIVATING)
+ goto out;
+
send_packet(forw_packet);
/**
@@ -483,10 +489,10 @@ void send_outstanding_bat_packet(struct work_struct *work)
* to determine the queues wake up time unless we are
* shutting down
*/
- if ((forw_packet->own) &&
- (atomic_read(&module_state) != MODULE_DEACTIVATING))
+ if (forw_packet->own)
schedule_own_packet(forw_packet->if_incoming);
+out:
/* don't count own packet */
if (!forw_packet->own)
atomic_inc(&batman_queue_left);
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index 8ce307e64b58..aad47326d6dc 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -100,15 +100,6 @@ menuconfig COMEDI_ISA_DRIVERS
if COMEDI_ISA_DRIVERS && ISA
-config COMEDI_8255
- tristate "Generic 8255 support"
- default N
- ---help---
- Enable generic 8255 support.
-
- To compile this driver as a module, choose M here: the module will be
- called 8255.
-
config COMEDI_ACL7225B
tristate "ADlink NuDAQ ACL-7225b and compatibles support"
default N
@@ -130,6 +121,7 @@ config COMEDI_PCL711
config COMEDI_PCL724
tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO"
+ select COMEDI_8255
default N
---help---
Enable support for Advantech PCL-724, PCL-722, PCL-731 and
@@ -198,6 +190,7 @@ config COMEDI_PCL818
config COMEDI_PCM3724
tristate "Advantech PCM-3724 PC/104 card support"
+ select COMEDI_8255
default N
---help---
Enable support for Advantech PCM-3724 PC/104 cards.
@@ -232,18 +225,9 @@ config COMEDI_RTI802
To compile this driver as a module, choose M here: the module will be
called rti802.
-config COMEDI_DAS08
- tristate "DAS-08 compatible ISA, PC/104 and PCMCIA card support"
- default N
- ---help---
- Enable support for Keithley Metrabyte/ComputerBoards DAS08
- and compatible ISA and PC/104 cards
-
- To compile this driver as a module, choose M here: the module will be
- called das08.
-
config COMEDI_DAS16M1
tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support"
+ select COMEDI_8255
select COMEDI_FC
default N
---help---
@@ -254,6 +238,7 @@ config COMEDI_DAS16M1
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
+ select COMEDI_8255
select COMEDI_FC
default N
---help---
@@ -385,6 +370,7 @@ config COMEDI_FL512
config COMEDI_AIO_AIO12_8
tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support"
+ select COMEDI_8255
default N
---help---
Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board
@@ -466,6 +452,7 @@ config COMEDI_NI_ATMIO
config COMEDI_NI_ATMIO16D
tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support"
depends on ISAPNP && COMEDI_NI_COMMON
+ select COMEDI_8255
default N
---help---
Enable support for National Instruments AT-MIO16/AT-MIO16D cards.
@@ -667,6 +654,7 @@ config COMEDI_ADDI_APCI_3XXX
config COMEDI_ADL_PCI6208
tristate "ADLink PCI-6208A support"
+ select COMEDI_8255
default N
---help---
Enable support for ADLink PCI-6208A cards
@@ -751,6 +739,7 @@ config COMEDI_ADV_PCI1723
config COMEDI_ADV_PCI_DIO
tristate "Advantech PCI DIO card support"
+ select COMEDI_8255
default N
---help---
Enable support for Advantech PCI DIO cards
@@ -762,6 +751,7 @@ config COMEDI_ADV_PCI_DIO
config COMEDI_AMPLC_DIO200
tristate "Amplicon PC272E and PCI272 DIO board support"
+ select COMEDI_8255
default N
---help---
Enable support for Amplicon PC272E and PCI272 DIO boards
@@ -771,6 +761,7 @@ config COMEDI_AMPLC_DIO200
config COMEDI_AMPLC_PC236
tristate "Amplicon PC36AT and PCI236 DIO board support"
+ select COMEDI_8255
default N
---help---
Enable support for Amplicon PC36AT and PCI236 DIO boards
@@ -799,6 +790,7 @@ config COMEDI_AMPLC_PCI224
config COMEDI_AMPLC_PCI230
tristate "Amplicon PCI230 and PCI260 support"
+ select COMEDI_8255
default N
---help---
Enable support for Amplicon PCI230 and PCI260 Multifunction I/O
@@ -869,6 +861,7 @@ config COMEDI_II_PCI20KC
config COMEDI_DAQBOARD2000
tristate "IOtech DAQboard/2000 support"
+ select COMEDI_8255
default N
---help---
Enable support for the IOtech DAQboard/2000
@@ -896,6 +889,7 @@ config COMEDI_KE_COUNTER
config COMEDI_CB_PCIDAS64
tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support"
+ select COMEDI_8255
select COMEDI_FC
default N
---help---
@@ -907,6 +901,7 @@ config COMEDI_CB_PCIDAS64
config COMEDI_CB_PCIDAS
tristate "MeasurementComputing PCI-DAS support"
+ select COMEDI_8255
select COMEDI_FC
default N
---help---
@@ -920,6 +915,7 @@ config COMEDI_CB_PCIDAS
config COMEDI_CB_PCIDDA
tristate "MeasurementComputing PCI-DDA series support"
+ select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DDA
@@ -931,6 +927,7 @@ config COMEDI_CB_PCIDDA
config COMEDI_CB_PCIDIO
tristate "MeasurementComputing PCI-DIO series support"
+ select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI-DIO series
@@ -941,6 +938,7 @@ config COMEDI_CB_PCIDIO
config COMEDI_CB_PCIMDAS
tristate "MeasurementComputing PCIM-DAS1602/16 support"
+ select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCI Migration
@@ -951,6 +949,7 @@ config COMEDI_CB_PCIMDAS
config COMEDI_CB_PCIMDDA
tristate "MeasurementComputing PCIM-DDA06-16 support"
+ select COMEDI_8255
default N
---help---
Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16
@@ -1026,6 +1025,7 @@ config COMEDI_NI_670X
config COMEDI_NI_PCIDIO
tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support"
depends on COMEDI_MITE
+ select COMEDI_8255
default N
---help---
Enable support for National Instruments PCI-DIO-32HS, PXI-6533,
@@ -1058,6 +1058,7 @@ config COMEDI_NI_PCIMIO
config COMEDI_RTD520
tristate "Real Time Devices PCI4520/DM7520 support"
+ select COMEDI_8255
default N
---help---
Enable support for Real Time Devices PCI4520/DM7520
@@ -1097,7 +1098,7 @@ endif # COMEDI_PCI_DRIVERS
menuconfig COMEDI_PCMCIA_DRIVERS
tristate "Comedi PCMCIA drivers"
- depends on COMEDI && PCMCIA && PCCARD
+ depends on COMEDI && (PCMCIA || PCCARD)
default N
---help---
Enable comedi PCMCIA and PCCARD drivers to be built
@@ -1142,6 +1143,7 @@ config COMEDI_NI_DAQ_700_CS
config COMEDI_NI_DAQ_DIO24_CS
tristate "NI DAQ-Card DIO-24 PCMCIA support"
depends on COMEDI_NI_COMMON
+ select COMEDI_8255
default N
---help---
Enable support for the National Instruments PCMCIA DAQ-Card DIO-24
@@ -1162,8 +1164,8 @@ config COMEDI_NI_LABPC_CS
config COMEDI_NI_MIO_CS
tristate "NI DAQCard E series PCMCIA support"
depends on COMEDI_NI_TIO && COMEDI_NI_COMMON
- default N
select COMEDI_FC
+ default N
---help---
Enable support for the National Instruments PCMCIA DAQCard E series
DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E
@@ -1265,7 +1267,8 @@ config COMEDI_MITE
config COMEDI_NI_TIO
tristate "NI general purpose counter support"
- select COMEDI_MITE
+ depends on COMEDI_MITE
+ select COMEDI_8255
default N
---help---
Enable support for National Instruments general purpose counters.
@@ -1278,6 +1281,8 @@ config COMEDI_NI_TIO
config COMEDI_NI_LABPC
tristate "NI Lab-PC and compatibles ISA and PCI support"
+ depends on COMEDI_MITE
+ select COMEDI_8255
select COMEDI_FC
default N
---help---
@@ -1291,8 +1296,40 @@ config COMEDI_NI_LABPC
endif # COMEDI_NI_COMMON
+config COMEDI_8255
+ tristate "Generic 8255 support"
+ depends on COMEDI
+ default N
+ ---help---
+ Enable generic 8255 support.
+
+ You should enable compilation this driver if you plan to use a board
+ that has an 8255 chip. For multifunction boards, the main driver will
+ configure the 8255 subdevice automatically.
+
+ Note that most PCI 8255 boards do NOT work with this driver, and
+ need a separate driver as a wrapper.
+
+ To compile this driver as a module, choose M here: the module will be
+ called 8255.
+
+config COMEDI_DAS08
+ tristate "DAS-08 compatible support"
+ depends on COMEDI
+ select COMEDI_8255
+ default N
+ ---help---
+ Enable support for DAS08 and compatible ISA, PC/104 and PCI cards.
+
+ Note that PCMCIA DAS08 cards are not directly supported by this
+ driver, and need a separate driver as a wrapper.
+
+ To compile this driver as a module, choose M here: the module will be
+ called das08.
+
config COMEDI_FC
tristate "Comedi shared functions for low-level driver support"
+ depends on COMEDI
default N
---help---
Enable support for shared functions for low-level drivers.
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index aced00e5cd10..aeb2c00875cd 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -83,7 +83,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
static int do_chaninfo_ioctl(struct comedi_device *dev,
struct comedi_chaninfo __user *arg);
static int do_bufinfo_ioctl(struct comedi_device *dev,
- struct comedi_bufinfo __user *arg);
+ struct comedi_bufinfo __user *arg, void *file);
static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file);
static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg,
@@ -169,7 +169,8 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
break;
case COMEDI_BUFINFO:
rc = do_bufinfo_ioctl(dev,
- (struct comedi_bufinfo __user *)arg);
+ (struct comedi_bufinfo __user *)arg,
+ file);
break;
case COMEDI_LOCK:
rc = do_lock_ioctl(dev, arg, file);
@@ -563,7 +564,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
*/
static int do_bufinfo_ioctl(struct comedi_device *dev,
- struct comedi_bufinfo __user *arg)
+ struct comedi_bufinfo __user *arg, void *file)
{
struct comedi_bufinfo bi;
struct comedi_subdevice *s;
@@ -576,6 +577,10 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
return -EINVAL;
s = dev->subdevices + bi.subdevice;
+
+ if (s->lock && s->lock != file)
+ return -EACCES;
+
async = s->async;
if (!async) {
@@ -584,8 +589,17 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
bi.buf_read_ptr = 0;
bi.buf_write_count = 0;
bi.buf_read_count = 0;
+ bi.bytes_read = 0;
+ bi.bytes_written = 0;
goto copyback;
}
+ if (!s->busy) {
+ bi.bytes_read = 0;
+ bi.bytes_written = 0;
+ goto copyback_position;
+ }
+ if (s->busy != file)
+ return -EACCES;
if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) {
bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read);
@@ -604,6 +618,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev,
comedi_buf_write_free(async, bi.bytes_written);
}
+copyback_position:
bi.buf_write_count = async->buf_write_count;
bi.buf_write_ptr = async->buf_write_ptr;
bi.buf_read_count = async->buf_read_count;
@@ -1576,6 +1591,19 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
while (nbytes > 0 && !retval) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
+ if (count == 0) {
+ if (comedi_get_subdevice_runflags(s) &
+ SRF_ERROR) {
+ retval = -EPIPE;
+ } else {
+ retval = 0;
+ }
+ do_become_nonbusy(dev, s);
+ }
+ break;
+ }
+
n = nbytes;
m = n;
@@ -1588,16 +1616,6 @@ static ssize_t comedi_write(struct file *file, const char __user *buf,
n = m;
if (n == 0) {
- if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) {
- if (comedi_get_subdevice_runflags(s) &
- SRF_ERROR) {
- retval = -EPIPE;
- } else {
- retval = 0;
- }
- do_become_nonbusy(dev, s);
- break;
- }
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
break;
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 5ccf246e2526..354fb7d29841 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o
obj-$(CONFIG_COMEDI_SKEL) += skel.o
# Comedi ISA drivers
-obj-$(CONFIG_COMEDI_8255) += 8255.o
obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o
obj-$(CONFIG_COMEDI_PCL711) += pcl711.o
obj-$(CONFIG_COMEDI_PCL724) += pcl724.o
@@ -26,7 +25,6 @@ obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o
obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o
obj-$(CONFIG_COMEDI_RTI800) += rti800.o
obj-$(CONFIG_COMEDI_RTI802) += rti802.o
-obj-$(CONFIG_COMEDI_DAS08) += das08.o
obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o
obj-$(CONFIG_COMEDI_DAS16) += das16.o
obj-$(CONFIG_COMEDI_DAS800) += das800.o
@@ -135,4 +133,6 @@ obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o
obj-$(CONFIG_COMEDI_NI_TIO) += ni_tiocmd.o
obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.o
+obj-$(CONFIG_COMEDI_8255) += 8255.o
+obj-$(CONFIG_COMEDI_DAS08) += das08.o
obj-$(CONFIG_COMEDI_FC) += comedi_fc.o
diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c
index 2c986413a81a..b18e81d8cf8a 100644
--- a/drivers/staging/comedi/drivers/addi-data/addi_common.c
+++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c
@@ -68,6 +68,10 @@ You should also find the complete GPL in the COPYING file accompanying this sour
#include "addi_common.h"
#include "addi_amcc_s5933.h"
+#ifndef ADDIDATA_DRIVER_NAME
+#define ADDIDATA_DRIVER_NAME "addi_common"
+#endif
+
/* Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>"); */
/* Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); */
/* Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); */
@@ -2528,7 +2532,7 @@ static const struct addi_board boardtypes[] = {
#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board))
static struct comedi_driver driver_addi = {
- .driver_name = "addi_common",
+ .driver_name = ADDIDATA_DRIVER_NAME,
.module = THIS_MODULE,
.attach = i_ADDI_Attach,
.detach = i_ADDI_Detach,
@@ -2570,10 +2574,6 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
struct pcilst_struct *card = NULL;
unsigned char pci_bus, pci_slot, pci_func;
int i_Dma = 0;
- static char c_Identifier[150];
-
- sprintf(c_Identifier, "Addi-Data GmbH Comedi %s",
- this_board->pc_DriverName);
ret = alloc_private(dev, sizeof(struct addi_private));
if (ret < 0)
@@ -2583,7 +2583,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
v_pci_card_list_init(this_board->i_VendorId, 1); /* 1 for displaying the list.. */
pci_list_builded = 1;
}
- /* printk("comedi%d: addi_common: board=%s",dev->minor,this_board->pc_DriverName); */
+ /* printk("comedi%d: "ADDIDATA_DRIVER_NAME": board=%s",dev->minor,this_board->pc_DriverName); */
if ((this_board->i_Dma) && (it->options[2] == 0)) {
i_Dma = 1;
@@ -2648,7 +2648,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (irq > 0) {
if (request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED,
- c_Identifier, dev) < 0) {
+ this_board->pc_DriverName, dev) < 0) {
printk(", unable to allocate IRQ %u, DISABLING IT",
irq);
irq = 0; /* Can't use IRQ */
diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c
index da454e854c4c..6dfcbe803f2d 100644
--- a/drivers/staging/comedi/drivers/addi_apci_035.c
+++ b/drivers/staging/comedi/drivers/addi_apci_035.c
@@ -2,4 +2,6 @@
#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */
+#define ADDIDATA_DRIVER_NAME "addi_apci_035"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index fa2056e8aa0e..4722ec834f7b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_1032 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_1032"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 7a5cae599ef8..db3dafdcf691 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_1500 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_1500"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c
index 8d414844009f..f591baff6a0b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1516.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1516.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_1516 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_1516"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c
index 0351cdde1026..6f5c923ac226 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1564.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1564.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_1564 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_1564"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c
index 506799041294..1d926add9e6d 100644
--- a/drivers/staging/comedi/drivers/addi_apci_16xx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_16XX 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_16xx"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c
index c433445913dd..df6ba8ccf56f 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1710.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1710.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_1710 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_1710"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_2016.c b/drivers/staging/comedi/drivers/addi_apci_2016.c
index 271c47c8cad3..7266e412f0a6 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2016.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2016.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_2016 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_2016"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c
index 5108ea2a3924..f67da94119e8 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2032.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_2032 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_2032"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c
index e439f835cf4f..bc7f7d653503 100644
--- a/drivers/staging/comedi/drivers/addi_apci_2200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_2200.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_2200 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_2200"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3001.c b/drivers/staging/comedi/drivers/addi_apci_3001.c
index df97c305828b..d86c4209cb90 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3001.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3001.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3001 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3001"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c
index 9183125ddde4..0b22cf10415d 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3120.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3120.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3120 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3120"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c
index f25a70b3290b..159313997dcf 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3200.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3200.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3200 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3200"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3300.c b/drivers/staging/comedi/drivers/addi_apci_3300.c
index 1ee4778ad45b..733c69abc43a 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3300.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3300.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3300 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3300"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index 1049e20237e8..d8a01b154e35 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3501 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3501"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
index fb9deb7083bd..942bc9e259a8 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c
@@ -1,3 +1,5 @@
#define CONFIG_APCI_3XXX 1
+#define ADDIDATA_DRIVER_NAME "addi_apci_3xxx"
+
#include "addi-data/addi_common.c"
diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c
index 40eeecf5347f..e424a0c7d34f 100644
--- a/drivers/staging/comedi/drivers/adv_pci_dio.c
+++ b/drivers/staging/comedi/drivers/adv_pci_dio.c
@@ -7,17 +7,17 @@
*/
/*
Driver: adv_pci_dio
-Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1736UP,
- PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754,
- PCI-1756, PCI-1762
+Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
+ PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
+ PCI-1754, PCI-1756, PCI-1762
Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
- PCI-1734, PCI-1736UP, PCI-1750,
+ PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
PCI-1751, PCI-1752, PCI-1753,
PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
PCI-1760, PCI-1762
Status: untested
-Updated: Mon, 14 Apr 2008 10:43:08 +0100
+Updated: Tue, 04 May 2010 13:00:00 +0000
This driver supports now only insn interface for DI/DO/DIO.
@@ -35,6 +35,7 @@ Configuration options:
#include "comedi_pci.h"
#include "8255.h"
+#include "8253.h"
#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */
@@ -49,7 +50,7 @@ Configuration options:
/* hardware types of the cards */
enum hw_cards_id {
- TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1736,
+ TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
TYPE_PCI1750,
TYPE_PCI1751,
TYPE_PCI1752,
@@ -67,7 +68,10 @@ enum hw_io_access {
#define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
#define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
#define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per card */
+#define MAX_8254_SUBDEVS 1 /* max number of 8254 counter subdevs per card */
+ /* (could be more than one 8254 per subdevice) */
+#define SIZE_8254 4 /* 8254 IO space length */
#define SIZE_8255 4 /* 8255 IO space length */
#define PCIDIO_MAINREG 2 /* main I/O region for all Advantech cards? */
@@ -85,6 +89,12 @@ enum hw_io_access {
#define PCI1734_IDO 0 /* W: Isolated digital output 0-31 */
#define PCI173x_BOARDID 4 /* R: Board I/D switch for 1730/3/4 */
+/* Advantech PCI-1735U */
+#define PCI1735_DI 0 /* R: Digital input 0-31 */
+#define PCI1735_DO 0 /* W: Digital output 0-31 */
+#define PCI1735_C8254 4 /* R/W: 8254 counter */
+#define PCI1735_BOARDID 8 /* R: Board I/D switch for 1735U */
+
/* Advantech PCI-1736UP */
#define PCI1736_IDI 0 /* R: Isolated digital input 0-15 */
#define PCI1736_IDO 0 /* W: Isolated digital output 0-15 */
@@ -192,7 +202,8 @@ static int pci_dio_detach(struct comedi_device *dev);
struct diosubd_data {
int chans; /* num of chans */
int addr; /* PCI address ofset */
- int regs; /* number of registers to read or 8255 subdevices */
+ int regs; /* number of registers to read or 8255
+ subdevices or 8254 chips */
unsigned int specflags; /* addon subdevice flags */
};
@@ -206,6 +217,7 @@ struct dio_boardtype {
struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */
struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */
struct diosubd_data boardid; /* card supports board ID switch */
+ struct diosubd_data s8254[MAX_8254_SUBDEVS]; /* 8254 subdevices */
enum hw_io_access io_access;
};
@@ -214,6 +226,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
PCI_VENDOR_ID_ADVANTECH, 0x1730, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1733, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1734, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
+ PCI_VENDOR_ID_ADVANTECH, 0x1735, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1750, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_ADVANTECH, 0x1751, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
@@ -235,14 +248,15 @@ static const struct dio_boardtype boardtypes[] = {
{{16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
- IO_8b,
- },
+ {{0, 0, 0, 0}},
+ IO_8b},
{"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG,
TYPE_PCI1733,
{{0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG,
TYPE_PCI1734,
@@ -250,6 +264,15 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI173x_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
+ IO_8b},
+ {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG,
+ TYPE_PCI1735,
+ {{32, PCI1735_DI, 4, 0}, {0, 0, 0, 0}},
+ {{32, PCI1735_DO, 4, 0}, {0, 0, 0, 0}},
+ {{0, 0, 0, 0}, {0, 0, 0, 0}},
+ { 4, PCI1735_BOARDID, 1, SDF_INTERNAL},
+ {{3, PCI1735_C8254, 1, 0}},
IO_8b},
{"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG,
TYPE_PCI1736,
@@ -257,14 +280,15 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI1736_BOARDID, 1, SDF_INTERNAL},
- IO_8b,
- },
+ {{0, 0, 0, 0}},
+ IO_8b},
{"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
TYPE_PCI1750,
{{0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0}},
{{0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG,
TYPE_PCI1751,
@@ -272,6 +296,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG,
TYPE_PCI1752,
@@ -279,6 +304,7 @@ static const struct dio_boardtype boardtypes[] = {
{{32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
IO_16b},
{"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753,
@@ -286,6 +312,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG,
TYPE_PCI1753E,
@@ -293,6 +320,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0}},
{0, 0, 0, 0},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG,
TYPE_PCI1754,
@@ -300,6 +328,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
IO_16b},
{"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG,
TYPE_PCI1756,
@@ -307,6 +336,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI175x_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
IO_16b},
{"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0,
TYPE_PCI1760,
@@ -314,6 +344,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{0, 0, 0, 0},
+ {{0, 0, 0, 0}},
IO_8b},
{"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG,
TYPE_PCI1762,
@@ -321,6 +352,7 @@ static const struct dio_boardtype boardtypes[] = {
{{0, 0, 0, 0}, {16, PCI1762_RO, 1, 0}},
{{0, 0, 0, 0}, {0, 0, 0, 0}},
{4, PCI1762_BOARDID, 1, SDF_INTERNAL},
+ {{0, 0, 0, 0}},
IO_16b}
};
@@ -440,6 +472,83 @@ static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
/*
==============================================================================
*/
+static int pci_8254_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ const struct diosubd_data *d = (const struct diosubd_data *)s->private;
+ unsigned int chan, chip, chipchan;
+ unsigned long flags;
+
+ chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
+ chip = chan / 3; /* chip on subdevice */
+ chipchan = chan - (3 * chip); /* channel on chip on subdevice */
+ spin_lock_irqsave(&s->spin_lock, flags);
+ data[0] = i8254_read(dev->iobase + d->addr + (SIZE_8254 * chip),
+ 0, chipchan);
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ return 1;
+}
+
+/*
+==============================================================================
+*/
+static int pci_8254_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ const struct diosubd_data *d = (const struct diosubd_data *)s->private;
+ unsigned int chan, chip, chipchan;
+ unsigned long flags;
+
+ chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
+ chip = chan / 3; /* chip on subdevice */
+ chipchan = chan - (3 * chip); /* channel on chip on subdevice */
+ spin_lock_irqsave(&s->spin_lock, flags);
+ i8254_write(dev->iobase + d->addr + (SIZE_8254 * chip),
+ 0, chipchan, data[0]);
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ return 1;
+}
+
+/*
+==============================================================================
+*/
+static int pci_8254_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn, unsigned int *data)
+{
+ const struct diosubd_data *d = (const struct diosubd_data *)s->private;
+ unsigned int chan, chip, chipchan;
+ unsigned long iobase;
+ int ret = 0;
+ unsigned long flags;
+
+ chan = CR_CHAN(insn->chanspec); /* channel on subdevice */
+ chip = chan / 3; /* chip on subdevice */
+ chipchan = chan - (3 * chip); /* channel on chip on subdevice */
+ iobase = dev->iobase + d->addr + (SIZE_8254 * chip);
+ spin_lock_irqsave(&s->spin_lock, flags);
+ switch (data[0]) {
+ case INSN_CONFIG_SET_COUNTER_MODE:
+ ret = i8254_set_mode(iobase, 0, chipchan, data[1]);
+ if (ret < 0)
+ ret = -EINVAL;
+ break;
+ case INSN_CONFIG_8254_READ_STATUS:
+ data[1] = i8254_status(iobase, 0, chipchan);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ spin_unlock_irqrestore(&s->spin_lock, flags);
+ return ret < 0 ? ret : insn->n;
+}
+
+/*
+==============================================================================
+*/
static int pci1760_unchecked_mbxrequest(struct comedi_device *dev,
unsigned char *omb, unsigned char *imb,
int repeats)
@@ -708,6 +817,15 @@ static int pci_dio_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCI1734_IDO + 2);
outb(0, dev->iobase + PCI1734_IDO + 3);
break;
+ case TYPE_PCI1735:
+ outb(0, dev->iobase + PCI1735_DO); /* clear outputs */
+ outb(0, dev->iobase + PCI1735_DO + 1);
+ outb(0, dev->iobase + PCI1735_DO + 2);
+ outb(0, dev->iobase + PCI1735_DO + 3);
+ i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 0, I8254_MODE0);
+ i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 1, I8254_MODE0);
+ i8254_set_mode(dev->iobase + PCI1735_C8254, 0, 2, I8254_MODE0);
+ break;
case TYPE_PCI1736:
outb(0, dev->iobase + PCI1736_IDO);
@@ -877,6 +995,26 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s,
/*
==============================================================================
*/
+static int pci_dio_add_8254(struct comedi_device *dev,
+ struct comedi_subdevice * s,
+ const struct diosubd_data *d, int subdev)
+{
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = d->chans;
+ s->maxdata = 65535;
+ s->len_chanlist = d->chans;
+ s->insn_read = pci_8254_insn_read;
+ s->insn_write = pci_8254_insn_write;
+ s->insn_config = pci_8254_insn_config;
+ s->private = (void *)d;
+
+ return 0;
+}
+
+/*
+==============================================================================
+*/
static int CheckAndAllocCard(struct comedi_device *dev,
struct comedi_devconfig *it,
struct pci_dev *pcidev)
@@ -979,6 +1117,9 @@ static int pci_dio_attach(struct comedi_device *dev,
n_subdevices += this_board->sdio[i].regs;
if (this_board->boardid.chans)
n_subdevices++;
+ for (i = 0; i < MAX_8254_SUBDEVS; i++)
+ if (this_board->s8254[i].chans)
+ n_subdevices++;
}
ret = alloc_subdevices(dev, n_subdevices);
@@ -1022,6 +1163,13 @@ static int pci_dio_attach(struct comedi_device *dev,
subdev++;
}
+ for (i = 0; i < MAX_8254_SUBDEVS; i++)
+ if (this_board->s8254[i].chans) {
+ s = dev->subdevices + subdev;
+ pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev);
+ subdev++;
+ }
+
if (this_board->cardtype == TYPE_PCI1760)
pci1760_attach(dev, it);
@@ -1067,6 +1215,16 @@ static int pci_dio_detach(struct comedi_device *dev)
}
}
+ if (this_board->boardid.chans) {
+ subdev++;
+ }
+
+ for (i = 0; i < MAX_8254_SUBDEVS; i++) {
+ if (this_board->s8254[i].chans) {
+ subdev++;
+ }
+ }
+
for (i = 0; i < dev->n_subdevices; i++) {
s = dev->subdevices + i;
s->private = NULL;
diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c
index 8eb67651486a..bf27617aa62d 100644
--- a/drivers/staging/comedi/drivers/amplc_dio200.c
+++ b/drivers/staging/comedi/drivers/amplc_dio200.c
@@ -460,6 +460,7 @@ struct dio200_subdev_8254 {
int has_clk_gat_sce;
unsigned clock_src[3]; /* Current clock sources */
unsigned gate_src[3]; /* Current gate sources */
+ spinlock_t spinlock;
};
struct dio200_subdev_intr {
@@ -1042,8 +1043,11 @@ dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+ spin_lock_irqsave(&subpriv->spinlock, flags);
data[0] = i8254_read(subpriv->iobase, 0, chan);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
@@ -1057,8 +1061,11 @@ dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
{
struct dio200_subdev_8254 *subpriv = s->private;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+ spin_lock_irqsave(&subpriv->spinlock, flags);
i8254_write(subpriv->iobase, 0, chan, data[0]);
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
return 1;
}
@@ -1151,14 +1158,16 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
struct dio200_subdev_8254 *subpriv = s->private;
- int ret;
+ int ret = 0;
int chan = CR_CHAN(insn->chanspec);
+ unsigned long flags;
+ spin_lock_irqsave(&subpriv->spinlock, flags);
switch (data[0]) {
case INSN_CONFIG_SET_COUNTER_MODE:
ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]);
if (ret < 0)
- return -EINVAL;
+ ret = -EINVAL;
break;
case INSN_CONFIG_8254_READ_STATUS:
data[1] = i8254_status(subpriv->iobase, 0, chan);
@@ -1166,30 +1175,35 @@ dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
case INSN_CONFIG_SET_GATE_SRC:
ret = dio200_set_gate_src(subpriv, chan, data[2]);
if (ret < 0)
- return -EINVAL;
+ ret = -EINVAL;
break;
case INSN_CONFIG_GET_GATE_SRC:
ret = dio200_get_gate_src(subpriv, chan);
- if (ret < 0)
- return -EINVAL;
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[2] = ret;
break;
case INSN_CONFIG_SET_CLOCK_SRC:
ret = dio200_set_clock_src(subpriv, chan, data[1]);
if (ret < 0)
- return -EINVAL;
+ ret = -EINVAL;
break;
case INSN_CONFIG_GET_CLOCK_SRC:
ret = dio200_get_clock_src(subpriv, chan, &data[2]);
- if (ret < 0)
- return -EINVAL;
+ if (ret < 0) {
+ ret = -EINVAL;
+ break;
+ }
data[1] = ret;
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
break;
}
- return insn->n;
+ spin_unlock_irqrestore(&subpriv->spinlock, flags);
+ return ret < 0 ? ret : insn->n;
}
/*
@@ -1222,6 +1236,7 @@ dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
s->insn_write = dio200_subdev_8254_write;
s->insn_config = dio200_subdev_8254_config;
+ spin_lock_init(&subpriv->spinlock);
subpriv->iobase = offset + iobase;
subpriv->has_clk_gat_sce = has_clk_gat_sce;
if (has_clk_gat_sce) {
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index cedb02d40f95..3a46f0c0bff9 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -123,7 +123,7 @@ static const struct ni_board_struct ni_boards[] = {
.adbits = 12,
.ai_fifo_depth = 1024,
.alwaysdither = 0,
- .gainlkup = ai_gain_16,
+ .gainlkup = ai_gain_4,
.ai_speed = 5000,
.n_aochan = 2,
.aobits = 12,
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 86f035d00675..27b4cb2e2ec2 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -351,8 +351,7 @@ static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink)
int ret = 0;
if (!this_usbduxsub) {
- dev_err(&this_usbduxsub->interface->dev,
- "comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
+ pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n");
return -EFAULT;
}
dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n");
diff --git a/drivers/staging/dream/synaptics_i2c_rmi.c b/drivers/staging/dream/synaptics_i2c_rmi.c
index 1f020dad6234..3320359408a9 100644
--- a/drivers/staging/dream/synaptics_i2c_rmi.c
+++ b/drivers/staging/dream/synaptics_i2c_rmi.c
@@ -519,7 +519,6 @@ err_input_register_device_failed:
err_input_dev_alloc_failed:
err_detect_failed:
err_power_failed:
- i2c_set_clientdata(client, NULL);
kfree(ts);
err_alloc_data_failed:
err_check_functionality_failed:
@@ -537,7 +536,6 @@ static int synaptics_ts_remove(struct i2c_client *client)
else
hrtimer_cancel(&ts->timer);
input_unregister_device(ts->input_dev);
- i2c_set_clientdata(client, NULL);
kfree(ts);
return 0;
}
diff --git a/drivers/staging/dt3155/allocator.c b/drivers/staging/dt3155/allocator.c
index bd5adbc2a238..d33947b0378f 100644
--- a/drivers/staging/dt3155/allocator.c
+++ b/drivers/staging/dt3155/allocator.c
@@ -176,9 +176,7 @@ int allocator_free_dma(unsigned long address)
prev = ptr; ptr = ptr->next;
if (!ptr) {
- printk(KERN_ERR ALL_MSG
- "free_dma(0x%08lx) but add. not allocated\n",
- ptr->address);
+ pr_err(ALL_MSG "free_dma but add. not allocated\n");
return -EINVAL;
}
PDEBUGG("freeing: %08lx (%li) next %08lx\n", ptr->address, ptr->size,
diff --git a/drivers/staging/go7007/wis-saa7113.c b/drivers/staging/go7007/wis-saa7113.c
index bd925457f8b7..72f5c1f56d19 100644
--- a/drivers/staging/go7007/wis-saa7113.c
+++ b/drivers/staging/go7007/wis-saa7113.c
@@ -289,7 +289,6 @@ static int wis_saa7113_probe(struct i2c_client *client,
if (write_regs(client, initial_registers) < 0) {
printk(KERN_ERR
"wis-saa7113: error initializing SAA7113\n");
- i2c_set_clientdata(client, NULL);
kfree(dec);
return -ENODEV;
}
@@ -301,7 +300,6 @@ static int wis_saa7113_remove(struct i2c_client *client)
{
struct wis_saa7113 *dec = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(dec);
return 0;
}
diff --git a/drivers/staging/go7007/wis-saa7115.c b/drivers/staging/go7007/wis-saa7115.c
index b2eb804c1954..cd950b61cf70 100644
--- a/drivers/staging/go7007/wis-saa7115.c
+++ b/drivers/staging/go7007/wis-saa7115.c
@@ -422,7 +422,6 @@ static int wis_saa7115_probe(struct i2c_client *client,
if (write_regs(client, initial_registers) < 0) {
printk(KERN_ERR
"wis-saa7115: error initializing SAA7115\n");
- i2c_set_clientdata(client, NULL);
kfree(dec);
return -ENODEV;
}
@@ -434,7 +433,6 @@ static int wis_saa7115_remove(struct i2c_client *client)
{
struct wis_saa7115 *dec = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(dec);
return 0;
}
diff --git a/drivers/staging/go7007/wis-sony-tuner.c b/drivers/staging/go7007/wis-sony-tuner.c
index b1013291190f..981c9b311b8b 100644
--- a/drivers/staging/go7007/wis-sony-tuner.c
+++ b/drivers/staging/go7007/wis-sony-tuner.c
@@ -684,7 +684,6 @@ static int wis_sony_tuner_remove(struct i2c_client *client)
{
struct wis_sony_tuner *t = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(t);
return 0;
}
diff --git a/drivers/staging/go7007/wis-tw2804.c b/drivers/staging/go7007/wis-tw2804.c
index 315268d130dd..ee28a99dc388 100644
--- a/drivers/staging/go7007/wis-tw2804.c
+++ b/drivers/staging/go7007/wis-tw2804.c
@@ -323,7 +323,6 @@ static int wis_tw2804_remove(struct i2c_client *client)
{
struct wis_tw2804 *dec = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(dec);
return 0;
}
diff --git a/drivers/staging/go7007/wis-tw9903.c b/drivers/staging/go7007/wis-tw9903.c
index 2afea09091b9..80d47269b1c0 100644
--- a/drivers/staging/go7007/wis-tw9903.c
+++ b/drivers/staging/go7007/wis-tw9903.c
@@ -294,7 +294,6 @@ static int wis_tw9903_probe(struct i2c_client *client,
if (write_regs(client, initial_registers) < 0) {
printk(KERN_ERR "wis-tw9903: error initializing TW9903\n");
- i2c_set_clientdata(client, NULL);
kfree(dec);
return -ENODEV;
}
@@ -306,7 +305,6 @@ static int wis_tw9903_remove(struct i2c_client *client)
{
struct wis_tw9903 *dec = i2c_get_clientdata(client);
- i2c_set_clientdata(client, NULL);
kfree(dec);
return 0;
}
diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h
index a4555e6f133f..014f6684faba 100644
--- a/drivers/staging/iio/Documentation/iio_utils.h
+++ b/drivers/staging/iio/Documentation/iio_utils.h
@@ -62,9 +62,8 @@ inline int find_type_by_name(const char *name, const char *type)
1) != 0) {
filename = malloc(strlen(iio_dir)
+ strlen(type)
- + 1
+ numstrlen
- + 1);
+ + 6);
if (filename == NULL)
return -ENOMEM;
sprintf(filename, "%s%s%d/name",
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index 20e267448d1f..905f8560d31f 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -1011,7 +1011,6 @@ error_put_reg:
if (!IS_ERR(st->reg))
regulator_put(st->reg);
error_free_st:
- i2c_set_clientdata(client, NULL);
kfree(st);
error_ret:
@@ -1030,7 +1029,6 @@ static int max1363_remove(struct i2c_client *client)
regulator_disable(st->reg);
regulator_put(st->reg);
}
- i2c_set_clientdata(client, NULL);
kfree(st);
return 0;
diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c
index 43aaacff4e74..e4b0a5ef1c1f 100644
--- a/drivers/staging/iio/light/tsl2563.c
+++ b/drivers/staging/iio/light/tsl2563.c
@@ -694,7 +694,6 @@ static int __devinit tsl2563_probe(struct i2c_client *client,
fail2:
iio_device_unregister(chip->indio_dev);
fail1:
- i2c_set_clientdata(client, NULL);
kfree(chip);
return err;
}
@@ -705,7 +704,6 @@ static int tsl2563_remove(struct i2c_client *client)
iio_device_unregister(chip->indio_dev);
- i2c_set_clientdata(client, NULL);
kfree(chip);
return 0;
}
diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c
index 1f14cd4770e7..294272d0619f 100644
--- a/drivers/staging/iio/ring_sw.c
+++ b/drivers/staging/iio/ring_sw.c
@@ -20,7 +20,7 @@ static inline int __iio_allocate_sw_ring_buffer(struct iio_sw_ring_buffer *ring,
if ((length == 0) || (bytes_per_datum == 0))
return -EINVAL;
__iio_update_ring_buffer(&ring->buf, bytes_per_datum, length);
- ring->data = kmalloc(length*ring->buf.bpd, GFP_KERNEL);
+ ring->data = kmalloc(length*ring->buf.bpd, GFP_ATOMIC);
ring->read_p = NULL;
ring->write_p = NULL;
ring->last_written_p = NULL;
diff --git a/drivers/staging/mrst-touchscreen/Kconfig b/drivers/staging/mrst-touchscreen/Kconfig
new file mode 100644
index 000000000000..c2af49217084
--- /dev/null
+++ b/drivers/staging/mrst-touchscreen/Kconfig
@@ -0,0 +1,7 @@
+config TOUCHSCREEN_INTEL_MID
+ tristate "Intel MID platform resistive touchscreen"
+ depends on INTEL_SCU_IPC
+ default y
+ help
+ Say Y here if you have a Intel MID based touchscreen
+ If unsure, say N.
diff --git a/drivers/staging/mrst-touchscreen/Makefile b/drivers/staging/mrst-touchscreen/Makefile
new file mode 100644
index 000000000000..2d638b0d70bf
--- /dev/null
+++ b/drivers/staging/mrst-touchscreen/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) := intel_mid_touch.o
+
+
diff --git a/drivers/staging/mrst-touchscreen/TODO b/drivers/staging/mrst-touchscreen/TODO
new file mode 100644
index 000000000000..7157028d634a
--- /dev/null
+++ b/drivers/staging/mrst-touchscreen/TODO
@@ -0,0 +1,2 @@
+- Move the driver to not think it is SPI (requires fixing some of the SFI
+ and firmware side)
diff --git a/drivers/staging/mrst-touchscreen/intel-mid-touch.c b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
new file mode 100644
index 000000000000..1db00975a594
--- /dev/null
+++ b/drivers/staging/mrst-touchscreen/intel-mid-touch.c
@@ -0,0 +1,864 @@
+/*
+ * intel_mid_touch.c - Intel MID Resistive Touch Screen Driver
+ *
+ * Copyright (C) 2008 Intel Corp
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; ifnot, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Questions/Comments/Bug fixes to Sreedhara (sreedhara.ds@intel.com)
+ * Ramesh Agarwal (ramesh.agarwal@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TODO:
+ * kill off mrstouch_debug eventually
+ * review conversion of r/m/w sequences
+ * Replace interrupt mutex abuse
+ * Kill of mrstouchdevp pointer
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/param.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <asm/intel_scu_ipc.h>
+
+
+#if defined(MRSTOUCH_DEBUG)
+#define mrstouch_debug(fmt, args...)\
+ do { \
+ printk(KERN_DEBUG "\n[MRSTOUCH(%d)] - ", __LINE__); \
+ printk(KERN_DEBUG fmt, ##args); \
+ } while (0);
+#else
+#define mrstouch_debug(fmt, args...)
+#endif
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_ID1 0x00 /*PMIC ID1 register */
+
+/* PMIC Interrupt registers */
+#define PMIC_REG_INT 0x04 /*PMIC interrupt register */
+#define PMIC_REG_MINT 0x05 /*PMIC interrupt mask register */
+
+/* ADC Interrupt registers */
+#define PMIC_REG_ADCINT 0x5F /*ADC interrupt register */
+#define PMIC_REG_MADCINT 0x60 /*ADC interrupt mask register */
+
+/* ADC Control registers */
+#define PMIC_REG_ADCCNTL1 0x61 /*ADC control register */
+
+/* ADC Channel Selection registers */
+#define PMICADDR0 0xA4
+#define END_OF_CHANNEL 0x1F
+
+/* ADC Result register */
+#define PMIC_REG_ADCSNS0H 0x64
+
+/* ADC channels for touch screen */
+#define MRST_TS_CHAN10 0xA /* Touch screen X+ connection */
+#define MRST_TS_CHAN11 0xB /* Touch screen X- connection */
+#define MRST_TS_CHAN12 0xC /* Touch screen Y+ connection */
+#define MRST_TS_CHAN13 0xD /* Touch screen Y- connection */
+
+/* Touch screen coordinate constants */
+#define TOUCH_PRESSURE 50
+#define TOUCH_PRESSURE_FS 100
+
+#define XMOVE_LIMIT 5
+#define YMOVE_LIMIT 5
+#define XYMOVE_CNT 3
+
+#define MAX_10BIT ((1<<10)-1)
+
+/* Touch screen channel BIAS constants */
+#define XBIAS 0x20
+#define YBIAS 0x40
+#define ZBIAS 0x80
+
+/* Touch screen coordinates */
+#define MIN_X 10
+#define MAX_X 1024
+#define MIN_Y 10
+#define MAX_Y 1024
+#define WAIT_ADC_COMPLETION 10
+
+/* PMIC ADC round robin delays */
+#define ADC_LOOP_DELAY0 0x0 /* Continuous loop */
+#define ADC_LOOP_DELAY1 0x1 /* 4.5 ms approximate */
+
+/* PMIC Vendor Identifiers */
+#define PMIC_VENDOR_FS 0 /* PMIC vendor FreeScale */
+#define PMIC_VENDOR_MAXIM 1 /* PMIC vendor MAXIM */
+#define PMIC_VENDOR_NEC 2 /* PMIC vendor NEC */
+#define MRSTOUCH_MAX_CHANNELS 32 /* Maximum ADC channels */
+
+/* Touch screen device structure */
+struct mrstouch_dev {
+ struct spi_device *spi; /* SPI device associated with touch screen */
+ struct input_dev *input; /* input device for touchscreen*/
+ char phys[32]; /* Device name */
+ struct task_struct *pendet_thrd; /* PENDET interrupt handler */
+ struct mutex lock; /* Sync between interrupt and PENDET handler */
+ bool busy; /* Busy flag */
+ u16 asr; /* Address selection register */
+ int irq; /* Touch screen IRQ # */
+ uint vendor; /* PMIC vendor */
+ uint rev; /* PMIC revision */
+ bool suspended; /* Device suspended status */
+ bool disabled; /* Device disabled status */
+ u16 x; /* X coordinate */
+ u16 y; /* Y coordinate */
+ bool pendown; /* PEN position */
+} ;
+
+
+/* Global Pointer to Touch screen device */
+static struct mrstouch_dev *mrstouchdevp;
+
+/* Utility to read PMIC ID */
+static int mrstouch_pmic_id(uint *vendor, uint *rev)
+{
+ int err;
+ u8 r;
+
+ err = intel_scu_ipc_ioread8(PMIC_REG_ID1, &r);
+ if (err)
+ return err;
+
+ *vendor = r & 0x7;
+ *rev = (r >> 3) & 0x7;
+
+ return 0;
+}
+
+/*
+ * Parse ADC channels to find end of the channel configured by other ADC user
+ * NEC and MAXIM requires 4 channels and FreeScale needs 18 channels
+ */
+static int mrstouch_chan_parse(struct mrstouch_dev *tsdev)
+{
+ int err, i, j, found;
+ u32 r32;
+
+ found = -1;
+
+ for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) {
+ if (found >= 0)
+ break;
+
+ err = intel_scu_ipc_ioread32(PMICADDR0, &r32);
+ if (err)
+ return err;
+
+ for (j = 0; j < 32; j+= 8) {
+ if (((r32 >> j) & 0xFF) == END_OF_CHANNEL) {
+ found = i;
+ break;
+ }
+ }
+ }
+ if (found < 0)
+ return 0;
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 18))
+ return -ENOSPC;
+ } else {
+ if (found && found > (MRSTOUCH_MAX_CHANNELS - 4))
+ return -ENOSPC;
+ }
+ return found;
+}
+
+/* Utility to enable/disable pendet.
+ * pendet set to true enables PENDET interrupt
+ * pendet set to false disables PENDET interrupt
+ * Also clears RND mask bit
+*/
+static int pendet_enable(struct mrstouch_dev *tsdev, bool pendet)
+{
+ u16 reg;
+ u8 r;
+ u8 pendet_enabled = 0;
+ int retry = 0;
+ int err;
+
+ err = intel_scu_ipc_ioread16(PMIC_REG_MADCINT, &reg);
+ if (err)
+ return err;
+
+ if (pendet) {
+ reg &= ~0x0005;
+ reg |= 0x2000; /* Enable pendet */
+ } else
+ reg &= 0xDFFF; /* Disable pendet */
+
+ /* Set MADCINT and update ADCCNTL1 (next reg byte) */
+ err = intel_scu_ipc_iowrite16(PMIC_REG_MADCINT, reg);
+ if (!pendet || err)
+ return err;
+
+ /*
+ * Sometimes even after the register write succeeds
+ * the PMIC register value is not updated. Retry few iterations
+ * to enable pendet.
+ */
+
+ err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
+ pendet_enabled = (r >> 5) & 0x01;
+
+ retry = 0;
+ while (!err && !pendet_enabled) {
+ retry++;
+ msleep(10);
+ err = intel_scu_ipc_iowrite8(PMIC_REG_ADCCNTL1, reg >> 8);
+ if (err)
+ break;
+ err = intel_scu_ipc_ioread8(PMIC_REG_ADCCNTL1, &r);
+ if (err == 0)
+ pendet_enabled = (r >> 5) & 0x01;
+ if (retry >= 10) {
+ dev_err(&tsdev->spi->dev, "Touch screen disabled.\n");
+ return -EIO;
+ }
+ }
+ return 0;
+}
+
+/* To read PMIC ADC touch screen result
+ * Reads ADC storage registers for higher 7 and lower 3 bits
+ * converts the two readings to single value and turns off gain bit
+ */
+static int mrstouch_ts_chan_read(u16 offset, u16 chan, u16 *vp, u16 *vm)
+{
+ int err;
+ u16 result;
+ u32 res;
+
+ result = PMIC_REG_ADCSNS0H + offset;
+
+ if (chan == MRST_TS_CHAN12)
+ result += 4;
+
+ err = intel_scu_ipc_ioread32(result, &res);
+ if (err)
+ return err;
+
+ /* Mash the bits up */
+
+ *vp = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vp |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vp &= 0x3FF;
+
+ res >>= 16;
+
+ *vm = (res & 0xFF) << 3; /* Highest 7 bits */
+ *vm |= (res >> 8) & 0x07; /* Lower 3 bits */
+ *vm &= 0x3FF;
+
+ return 0;
+}
+
+/* To configure touch screen channels
+ * Writes touch screen channels to ADC address selection registers
+ */
+static int mrstouch_ts_chan_set(uint offset)
+{
+ int count;
+ u16 chan;
+ u16 reg[5];
+ u8 data[5];
+
+ chan = PMICADDR0 + offset;
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = MRST_TS_CHAN10 + count;
+ }
+ reg[count] = chan;
+ data[count] = END_OF_CHANNEL;
+
+ return intel_scu_ipc_writev(reg, data, 5);
+}
+
+/* Initialize ADC */
+static int mrstouch_adc_init(struct mrstouch_dev *tsdev)
+{
+ int err, start;
+ u8 ra, rm;
+
+ err = mrstouch_pmic_id(&tsdev->vendor, &tsdev->rev);
+ if (err) {
+ dev_err(&tsdev->spi->dev, "Unable to read PMIC id\n");
+ return err;
+ }
+
+ start = mrstouch_chan_parse(tsdev);
+ if (start < 0) {
+ dev_err(&tsdev->spi->dev, "Unable to parse channels\n");
+ return start;
+ }
+
+ tsdev->asr = start;
+
+ mrstouch_debug("Channel offset(%d): 0x%X\n", tsdev->asr, tsdev->vendor);
+
+ /* ADC power on, start, enable PENDET and set loop delay
+ * ADC loop delay is set to 4.5 ms approximately
+ * Loop delay more than this results in jitter in adc readings
+ * Setting loop delay to 0 (continous loop) in MAXIM stops PENDET
+ * interrupt generation sometimes.
+ */
+
+ if (tsdev->vendor == PMIC_VENDOR_FS) {
+ ra = 0xE0 | ADC_LOOP_DELAY0;
+ rm = 0x5;
+ } else {
+ /* NEC and MAXIm not consistent with loop delay 0 */
+ ra = 0xE0 | ADC_LOOP_DELAY1;
+ rm = 0x0;
+
+ /* configure touch screen channels */
+ err = mrstouch_ts_chan_set(tsdev->asr);
+ if (err)
+ return err;
+ }
+ err = intel_scu_ipc_update_register(PMIC_REG_ADCCNTL1, ra, 0xE7);
+ if (err == 0)
+ err = intel_scu_ipc_update_register(PMIC_REG_MADCINT, rm, 0x03);
+ return err;
+}
+
+/* Reports x,y coordinates to event subsystem */
+static void mrstouch_report_xy(struct mrstouch_dev *tsdev, u16 x, u16 y, u16 z)
+{
+ int xdiff, ydiff;
+
+ if (tsdev->pendown && z <= TOUCH_PRESSURE) {
+ /* Pen removed, report button release */
+ mrstouch_debug("BTN REL(%d)", z);
+ input_report_key(tsdev->input, BTN_TOUCH, 0);
+ tsdev->pendown = false;
+ }
+
+ xdiff = abs(x - tsdev->x);
+ ydiff = abs(y - tsdev->y);
+
+ /*
+ if x and y values changes for XYMOVE_CNT readings it is considered
+ as stylus is moving. This is required to differentiate between stylus
+ movement and jitter
+ */
+ if (x < MIN_X || x > MAX_X || y < MIN_Y || y > MAX_Y) {
+ /* Spurious values, release button if touched and return */
+ if (tsdev->pendown) {
+ mrstouch_debug("BTN REL(%d)", z);
+ input_report_key(tsdev->input, BTN_TOUCH, 0);
+ tsdev->pendown = false;
+ }
+ return;
+ } else if (xdiff >= XMOVE_LIMIT || ydiff >= YMOVE_LIMIT) {
+ tsdev->x = x;
+ tsdev->y = y;
+
+ input_report_abs(tsdev->input, ABS_X, x);
+ input_report_abs(tsdev->input, ABS_Y, y);
+ input_sync(tsdev->input);
+ }
+
+
+ if (!tsdev->pendown && z > TOUCH_PRESSURE) {
+ /* Pen touched, report button touch */
+ mrstouch_debug("BTN TCH(%d, %d, %d)", x, y, z);
+ input_report_key(tsdev->input, BTN_TOUCH, 1);
+ tsdev->pendown = true;
+ }
+}
+
+
+/* Utility to start ADC, used by freescale handler */
+static int pendet_mask(void)
+{
+ return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x02, 0x02);
+}
+
+/* Utility to stop ADC, used by freescale handler */
+static int pendet_umask(void)
+{
+ return intel_scu_ipc_update_register(PMIC_REG_MADCINT, 0x00, 0x02);
+}
+
+/* Utility to read ADC, used by freescale handler */
+static int mrstouch_pmic_fs_adc_read(struct mrstouch_dev *tsdev)
+{
+ int err;
+ u16 x, y, z, result;
+ u16 reg[4];
+ u8 data[4];
+
+ result = PMIC_REG_ADCSNS0H + tsdev->asr;
+
+ reg[0] = result + 4;
+ reg[1] = result + 5;
+ reg[2] = result + 16;
+ reg[3] = result + 17;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ x = data[0] << 3; /* Higher 7 bits */
+ x |= data[1] & 0x7; /* Lower 3 bits */
+ x &= 0x3FF;
+
+ y = data[2] << 3; /* Higher 7 bits */
+ y |= data[3] & 0x7; /* Lower 3 bits */
+ y &= 0x3FF;
+
+ /* Read Z value */
+ reg[0] = result + 28;
+ reg[1] = result + 29;
+
+ err = intel_scu_ipc_readv(reg, data, 4);
+ if (err)
+ goto ipc_error;
+
+ z = data[0] << 3; /* Higher 7 bits */
+ z |= data[1] & 0x7; /* Lower 3 bits */
+ z &= 0x3FF;
+
+#if defined(MRSTOUCH_PRINT_XYZP)
+ mrstouch_debug("X: %d, Y: %d, Z: %d", x, y, z);
+#endif
+
+ if (z >= TOUCH_PRESSURE_FS) {
+ mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE - 1); /* Pen Removed */
+ return TOUCH_PRESSURE - 1;
+ } else {
+ mrstouch_report_xy(tsdev, x, y, TOUCH_PRESSURE + 1); /* Pen Touched */
+ return TOUCH_PRESSURE + 1;
+ }
+
+ return 0;
+
+ipc_error:
+ dev_err(&tsdev->spi->dev, "ipc error during fs_adc read\n");
+ return err;
+}
+
+/* To handle free scale pmic pendet interrupt */
+static int pmic0_pendet(void *dev_id)
+{
+ int err, count;
+ u16 chan;
+ unsigned int touched;
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)dev_id;
+ u16 reg[5];
+ u8 data[5];
+
+ chan = PMICADDR0 + tsdev->asr;
+
+ /* Set X BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x2A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Y BIAS */
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = 0x4A;
+ }
+ reg[count] = chan++; /* Dummy */
+ data[count] = 0;
+
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* Set Z BIAS */
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x8A8A8A8A);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /*Read touch screen channels till pen removed
+ * Freescale reports constant value of z for all points
+ * z is high when screen is not touched and low when touched
+ * Map high z value to not touched and low z value to pen touched
+ */
+ touched = mrstouch_pmic_fs_adc_read(tsdev);
+ while (touched > TOUCH_PRESSURE) {
+ touched = mrstouch_pmic_fs_adc_read(tsdev);
+ msleep(WAIT_ADC_COMPLETION);
+ }
+
+ /* Clear all TS channels */
+ chan = PMICADDR0 + tsdev->asr;
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ for (count = 0; count <= 4; count++) {
+ reg[count] = chan++;
+ data[count] = 0;
+ }
+ err = intel_scu_ipc_writev(reg, data, 5);
+ if (err)
+ goto ipc_error;
+
+ err = intel_scu_ipc_iowrite32(chan + 2, 0x00000000);
+ if (err)
+ goto ipc_error;
+
+ return 0;
+
+ipc_error:
+ dev_err(&tsdev->spi->dev, "ipc error during pendet\n");
+ return err;
+}
+
+
+/* To enable X, Y and Z bias values
+ * Enables YPYM for X channels and XPXM for Y channels
+ */
+static int mrstouch_ts_bias_set(uint offset, uint bias)
+{
+ int count;
+ u16 chan, start;
+ u16 reg[4];
+ u8 data[4];
+
+ chan = PMICADDR0 + offset;
+ start = MRST_TS_CHAN10;
+
+ for (count = 0; count <= 3; count++) {
+ reg[count] = chan++;
+ data[count] = bias | (start + count);
+ }
+ return intel_scu_ipc_writev(reg, data, 4);
+}
+
+/* To read touch screen channel values */
+static int mrstouch_adc_read(struct mrstouch_dev *tsdev)
+{
+ int err;
+ u16 xp, xm, yp, ym, zp, zm;
+
+ /* configure Y bias for X channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, YBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read x+ and x- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &xp, &xm);
+ if (err)
+ goto ipc_error;
+
+ /* configure x bias for y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, XBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read y+ and y- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN12, &yp, &ym);
+ if (err)
+ goto ipc_error;
+
+ /* configure z bias for x and y channels */
+ err = mrstouch_ts_bias_set(tsdev->asr, ZBIAS);
+ if (err)
+ goto ipc_error;
+
+ msleep(WAIT_ADC_COMPLETION);
+
+ /* read z+ and z- channels */
+ err = mrstouch_ts_chan_read(tsdev->asr, MRST_TS_CHAN10, &zp, &zm);
+ if (err)
+ goto ipc_error;
+
+#if defined(MRSTOUCH_PRINT_XYZP)
+ printk(KERN_INFO "X+: %d, Y+: %d, Z+: %d\n", xp, yp, zp);
+#endif
+
+#if defined(MRSTOUCH_PRINT_XYZM)
+ printk(KERN_INFO "X-: %d, Y-: %d, Z-: %d\n", xm, ym, zm);
+#endif
+
+ mrstouch_report_xy(tsdev, xp, yp, zp); /* report x and y to eventX */
+
+ return zp;
+
+ipc_error:
+ dev_err(&tsdev->spi->dev, "ipc error during adc read\n");
+ return err;
+}
+
+/* PENDET interrupt handler function for NEC and MAXIM */
+static void pmic12_pendet(void *data)
+{
+ unsigned int touched;
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
+
+ /* read touch screen channels till pen removed */
+ do {
+ touched = mrstouch_adc_read(tsdev);
+ } while (touched > TOUCH_PRESSURE);
+}
+
+/* Handler to process PENDET interrupt */
+int mrstouch_pendet(void *data)
+{
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)data;
+ while (1) {
+ /* Wait for PENDET interrupt */
+ if (mutex_lock_interruptible(&tsdev->lock)) {
+ msleep(WAIT_ADC_COMPLETION);
+ continue;
+ }
+
+ if (tsdev->busy)
+ return 0;
+
+ tsdev->busy = true;
+
+ if (tsdev->vendor == PMIC_VENDOR_NEC ||
+ tsdev->vendor == PMIC_VENDOR_MAXIM) {
+ /* PENDET must be disabled in NEC before reading ADC */
+ pendet_enable(tsdev,false); /* Disbale PENDET */
+ pmic12_pendet(tsdev);
+ pendet_enable(tsdev, true); /*Enable PENDET */
+ } else if (tsdev->vendor == PMIC_VENDOR_FS) {
+ pendet_umask(); /* Stop ADC */
+ pmic0_pendet(tsdev);
+ pendet_mask(); /* Stop ADC */
+ } else
+ dev_err(&tsdev->spi->dev, "Unsupported touchscreen: %d\n",
+ tsdev->vendor);
+
+ tsdev->busy = false;
+
+ }
+ return 0;
+}
+
+/* PENDET interrupt handler */
+static irqreturn_t pendet_intr_handler(int irq, void *handle)
+{
+ struct mrstouch_dev *tsdev = (struct mrstouch_dev *)handle;
+
+ mutex_unlock(&tsdev->lock);
+ return IRQ_HANDLED;
+}
+
+/* Intializes input device and registers with input subsystem */
+static int ts_input_dev_init(struct mrstouch_dev *tsdev, struct spi_device *spi)
+{
+ int err = 0;
+
+ mrstouch_debug("%s", __func__);
+
+ tsdev->input = input_allocate_device();
+ if (!tsdev->input) {
+ dev_err(&tsdev->spi->dev, "Unable to allocate input device.\n");
+ return -EINVAL;
+ }
+
+ tsdev->input->name = "mrst_touchscreen";
+ snprintf(tsdev->phys, sizeof(tsdev->phys),
+ "%s/input0", dev_name(&spi->dev));
+ tsdev->input->phys = tsdev->phys;
+ tsdev->input->dev.parent = &spi->dev;
+
+ tsdev->input->id.vendor = tsdev->vendor;
+ tsdev->input->id.version = tsdev->rev;
+
+ tsdev->input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ tsdev->input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(tsdev->input, ABS_X, MIN_X, MIN_Y, 0, 0);
+ input_set_abs_params(tsdev->input, ABS_Y, MIN_X, MIN_Y, 0, 0);
+
+ err = input_register_device(tsdev->input);
+ if (err) {
+ dev_err(&tsdev->spi->dev, "unable to register input device\n");
+ input_free_device(tsdev->input);
+ return err;
+ }
+
+ mrstouch_debug("%s", "mrstouch initialized");
+
+ return 0;
+
+}
+
+/* Probe function for touch screen driver */
+static int __devinit mrstouch_probe(struct spi_device *mrstouch_spi)
+{
+ int err;
+ unsigned int myirq;
+ struct mrstouch_dev *tsdev;
+
+ mrstouch_debug("%s(%p)", __func__, mrstouch_spi);
+
+ mrstouchdevp = NULL;
+ myirq = mrstouch_spi->irq;
+
+ if (!mrstouch_spi->irq) {
+ dev_err(&mrstouch_spi->dev, "no interrupt assigned\n");
+ return -EINVAL;
+ }
+
+ tsdev = kzalloc(sizeof(struct mrstouch_dev), GFP_KERNEL);
+ if (!tsdev) {
+ dev_err(&mrstouch_spi->dev, "unable to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ tsdev->irq = myirq;
+ mrstouchdevp = tsdev;
+
+ err = mrstouch_adc_init(tsdev);
+ if (err) {
+ dev_err(&mrstouch_spi->dev, "ADC init failed\n");
+ goto mrstouch_err_free_mem;
+ }
+
+ dev_set_drvdata(&mrstouch_spi->dev, tsdev);
+ tsdev->spi = mrstouch_spi;
+
+ err = ts_input_dev_init(tsdev, mrstouch_spi);
+ if (err) {
+ dev_err(&tsdev->spi->dev, "ts_input_dev_init failed");
+ goto mrstouch_err_free_mem;
+ }
+
+ mutex_init(&tsdev->lock);
+ mutex_lock(&tsdev->lock)
+
+ mrstouch_debug("Requesting IRQ-%d", myirq);
+ err = request_irq(myirq, pendet_intr_handler,
+ 0, "mrstouch", tsdev);
+ if (err) {
+ dev_err(&tsdev->spi->dev, "unable to allocate irq\n");
+ goto mrstouch_err_free_mem;
+ }
+
+ tsdev->pendet_thrd = kthread_run(mrstouch_pendet,
+ (void *)tsdev, "pendet handler");
+ if (IS_ERR(tsdev->pendet_thrd)) {
+ dev_err(&tsdev->spi->dev, "kthread_run failed\n");
+ err = PTR_ERR(tsdev->pendet_thrd);
+ goto mrstouch_err_free_mem;
+ }
+ mrstouch_debug("%s", "Driver initialized");
+ return 0;
+
+mrstouch_err_free_mem:
+ kfree(tsdev);
+ return err;
+}
+
+static int mrstouch_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ mrstouch_debug("%s", __func__);
+ mrstouchdevp->suspended = 1;
+ return 0;
+}
+
+static int mrstouch_resume(struct spi_device *spi)
+{
+ mrstouch_debug("%s", __func__);
+ mrstouchdevp->suspended = 0;
+ return 0;
+}
+
+static int mrstouch_remove(struct spi_device *spi)
+{
+ mrstouch_debug("%s", __func__);
+ free_irq(mrstouchdevp->irq, mrstouchdevp);
+ input_unregister_device(mrstouchdevp->input);
+ input_free_device(mrstouchdevp->input);
+ kfree(mrstouchdevp);
+ if (mrstouchdevp->pendet_thrd)
+ kthread_stop(mrstouchdevp->pendet_thrd);
+ return 0;
+}
+
+static struct spi_driver mrstouch_driver = {
+ .driver = {
+ .name = "pmic_touch",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = mrstouch_probe,
+ .suspend = mrstouch_suspend,
+ .resume = mrstouch_resume,
+ .remove = mrstouch_remove,
+};
+
+static int __init mrstouch_module_init(void)
+{
+ int err;
+
+ mrstouch_debug("%s", __func__);
+ err = spi_register_driver(&mrstouch_driver);
+ if (err) {
+ mrstouch_debug("%s(%d)", "SPI PENDET failed", err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void __exit mrstouch_module_exit(void)
+{
+ mrstouch_debug("%s", __func__);
+ spi_unregister_driver(&mrstouch_driver);
+ return;
+}
+
+module_init(mrstouch_module_init);
+module_exit(mrstouch_module_exit);
+
+MODULE_AUTHOR("Sreedhara Murthy. D.S, sreedhara.ds@intel.com");
+MODULE_DESCRIPTION("Intel Moorestown Resistive Touch Screen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/msm/Kconfig b/drivers/staging/msm/Kconfig
new file mode 100644
index 000000000000..c57039f2060b
--- /dev/null
+++ b/drivers/staging/msm/Kconfig
@@ -0,0 +1,134 @@
+config MSM_STAGING
+ tristate "MSM Frame Buffer Support"
+ depends on FB && ARCH_MSM && !FB_MSM
+ select FB_BACKLIGHT if FB_MSM_BACKLIGHT
+ select NEW_LEDS
+ select LEDS_CLASS
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Support for MSM Framebuffer.
+
+if MSM_STAGING
+
+config FB_MSM_LCDC_HW
+ bool
+ default n
+
+choice
+ prompt "MDP HW version"
+ default FB_MSM_MDP31
+
+config FB_MSM_MDP31
+ select FB_MSM_LCDC_HW
+ bool "MDP HW ver3.1"
+ ---help---
+ Support for MSM MDP HW revision 3.1
+ Say Y here if this is msm8x50 variant platform.
+endchoice
+
+config FB_MSM_LCDC
+ bool
+ default n
+
+config FB_MSM_TVOUT
+ bool
+ default n
+
+config FB_MSM_LCDC_PANEL
+ bool
+ select FB_MSM_LCDC
+ default n
+
+config FB_MSM_LCDC_PRISM_WVGA
+ bool
+ select FB_MSM_LCDC_PANEL
+ default n
+
+config FB_MSM_LCDC_ST1_WXGA
+ bool
+ select FB_MSM_LCDC_PANEL
+ default n
+
+config FB_MSM_LCDC_ST15_WXGA
+ bool
+ select FB_MSM_LCDC_PANEL
+ default n
+
+config FB_MSM_LCDC_WXGA
+ bool
+ select FB_MSM_LCDC_PANEL
+ default n
+
+choice
+ prompt "LCD Panel"
+ default FB_MSM_LCDC_ST15_PANEL
+
+config FB_MSM_LCDC_PRISM_WVGA_PANEL
+ depends on FB_MSM_LCDC_HW
+ bool "LCDC Prism WVGA Panel"
+ select FB_MSM_LCDC_PRISM_WVGA
+ ---help---
+ Support for LCDC Prism WVGA (800x480) panel
+
+
+config FB_MSM_LCDC_ST15_PANEL
+ depends on FB_MSM_LCDC_HW
+ bool "LCDC ST1.5 Panel"
+ select FB_MSM_LCDC_ST15_WXGA
+ ---help---
+ Support for ST1.5 WXGA (1366x768) panel
+
+config FB_MSM_PANEL_NONE
+ bool "NONE"
+ ---help---
+ This will disable LCD panel
+endchoice
+
+choice
+ prompt "Secondary LCD Panel"
+ depends on FB_MSM_MDP31
+ default FB_MSM_SECONDARY_PANEL_NONE
+
+config FB_MSM_SECONDARY_PANEL_NONE
+ bool "NONE"
+ ---help---
+ No secondary panel
+endchoice
+
+config FB_MSM_TVOUT_NTSC
+ bool
+ select FB_MSM_TVOUT
+ default n
+
+config FB_MSM_TVOUT_PAL
+ bool
+ select FB_MSM_TVOUT
+ default n
+
+choice
+ depends on (FB_MSM_MDP22 || FB_MSM_MDP31)
+ prompt "TVOut Region"
+ default FB_MSM_TVOUT_NTSC_M
+
+config FB_MSM_TVOUT_NTSC_M
+ bool "NTSC M"
+ select FB_MSM_TVOUT_NTSC
+ ---help---
+ Support for NTSC M region (North American and Korea)
+
+config FB_MSM_TVOUT_NONE
+ bool "NONE"
+ ---help---
+ This will disable TV Out functionality.
+endchoice
+
+config PMEM_KERNEL_SIZE
+ int "PMEM for kernel components (in MB)"
+ default 2
+ depends on ARCH_QSD8X50
+ help
+ Configures the amount of PMEM for use by kernel components
+ (in MB; minimum 2MB)
+endif
diff --git a/drivers/staging/msm/Makefile b/drivers/staging/msm/Makefile
new file mode 100644
index 000000000000..98a0ce177cb2
--- /dev/null
+++ b/drivers/staging/msm/Makefile
@@ -0,0 +1,93 @@
+obj-y := msm_fb.o staging-devices.o memory.o
+
+obj-$(CONFIG_FB_MSM_LOGO) += logo.o
+obj-$(CONFIG_FB_BACKLIGHT) += msm_fb_bl.o
+
+# MDP
+obj-y += mdp.o
+
+ifeq ($(CONFIG_FB_MSM_MDP40),y)
+obj-y += mdp4_util.o
+obj-$(CONFIG_DEBUG_FS) += mdp4_debugfs.o
+else
+obj-y += mdp_hw_init.o
+obj-y += mdp_ppp.o
+ifeq ($(CONFIG_FB_MSM_MDP31),y)
+obj-y += mdp_ppp_v31.o
+obj-$(CONFIG_MDP_PPP_ASYNC_OP) += mdp_ppp_dq.o
+else
+obj-y += mdp_ppp_v20.o
+endif
+endif
+
+ifeq ($(CONFIG_FB_MSM_OVERLAY),y)
+obj-y += mdp4_overlay.o
+obj-y += mdp4_overlay_lcdc.o
+obj-y += mdp4_overlay_mddi.o
+else
+obj-y += mdp_dma_lcdc.o
+endif
+
+obj-y += mdp_dma.o
+obj-y += mdp_dma_s.o
+obj-y += mdp_vsync.o
+obj-y += mdp_cursor.o
+obj-y += mdp_dma_tv.o
+
+# EBI2
+obj-$(CONFIG_FB_MSM_EBI2) += ebi2_lcd.o
+
+# LCDC
+obj-$(CONFIG_FB_MSM_LCDC) += lcdc.o
+
+# MDDI
+msm_mddi-objs := mddi.o mddihost.o mddihosti.o
+obj-$(CONFIG_FB_MSM_MDDI) += msm_mddi.o
+
+# External MDDI
+msm_mddi_ext-objs := mddihost_e.o mddi_ext.o
+obj-$(CONFIG_FB_MSM_EXTMDDI) += msm_mddi_ext.o
+
+# TVEnc
+obj-$(CONFIG_FB_MSM_TVOUT) += tvenc.o
+
+# MSM FB Panel
+obj-y += msm_fb_panel.o
+obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_tmd20.o
+obj-$(CONFIG_FB_MSM_EBI2_TMD_QVGA_EPSON_QCIF) += ebi2_l2f.o
+
+ifeq ($(CONFIG_FB_MSM_MDDI_AUTO_DETECT),y)
+obj-y += mddi_prism.o
+obj-y += mddi_toshiba.o
+obj-y += mddi_toshiba_vga.o
+obj-y += mddi_toshiba_wvga_pt.o
+obj-y += mddi_toshiba_wvga.o
+obj-y += mddi_sharp.o
+else
+obj-$(CONFIG_FB_MSM_MDDI_PRISM_WVGA) += mddi_prism.o
+obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON) += mddi_toshiba.o
+obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_COMMON_VGA) += mddi_toshiba_vga.o
+obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA_PORTRAIT) += mddi_toshiba_wvga_pt.o
+obj-$(CONFIG_FB_MSM_MDDI_TOSHIBA_WVGA) += mddi_toshiba_wvga.o
+obj-$(CONFIG_FB_MSM_MDDI_SHARP_QVGA_128x128) += mddi_sharp.o
+endif
+
+obj-$(CONFIG_FB_MSM_LCDC_PANEL) += lcdc_panel.o
+obj-$(CONFIG_FB_MSM_LCDC_PRISM_WVGA) += lcdc_prism.o
+obj-$(CONFIG_FB_MSM_LCDC_EXTERNAL_WXGA) += lcdc_external.o
+obj-$(CONFIG_FB_MSM_LCDC_GORDON_VGA) += lcdc_gordon.o
+obj-$(CONFIG_FB_MSM_LCDC_WXGA) += lcdc_wxga.o
+obj-$(CONFIG_FB_MSM_LCDC_TOSHIBA_WVGA_PT) += lcdc_toshiba_wvga_pt.o
+obj-$(CONFIG_FB_MSM_LCDC_SHARP_WVGA_PT) += lcdc_sharp_wvga_pt.o
+obj-$(CONFIG_FB_MSM_LCDC_GRAPEFRUIT_VGA) += lcdc_grapefruit.o
+obj-$(CONFIG_FB_MSM_LCDC_ST1_WXGA) += lcdc_st1_wxga.o
+obj-$(CONFIG_FB_MSM_LCDC_ST15_WXGA) += lcdc_st15.o
+obj-$(CONFIG_FB_MSM_HDMI_SII_EXTERNAL_720P) += hdmi_sii9022.o
+
+obj-$(CONFIG_FB_MSM_TVOUT_NTSC) += tv_ntsc.o
+obj-$(CONFIG_FB_MSM_TVOUT_PAL) += tv_pal.o
+
+obj-$(CONFIG_FB_MSM_EXTMDDI_SVGA) += mddi_ext_lcd.o
+
+clean:
+ rm *.o .*cmd
diff --git a/drivers/staging/msm/TODO b/drivers/staging/msm/TODO
new file mode 100644
index 000000000000..05107a7d516a
--- /dev/null
+++ b/drivers/staging/msm/TODO
@@ -0,0 +1,3 @@
+- Merge this code with the existing MSM framebuffer
+- General style clean ups.
+
diff --git a/drivers/staging/msm/ebi2_l2f.c b/drivers/staging/msm/ebi2_l2f.c
new file mode 100644
index 000000000000..eea891d8f0f8
--- /dev/null
+++ b/drivers/staging/msm/ebi2_l2f.c
@@ -0,0 +1,569 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+#include <linux/memory.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+/* The following are for MSM5100 on Gator
+*/
+#ifdef FEATURE_PM1000
+#include "pm1000.h"
+#endif /* FEATURE_PM1000 */
+/* The following are for MSM6050 on Bambi
+*/
+#ifdef FEATURE_PMIC_LCDKBD_LED_DRIVER
+#include "pm.h"
+#endif /* FEATURE_PMIC_LCDKBD_LED_DRIVER */
+
+#ifdef DISP_DEVICE_18BPP
+#undef DISP_DEVICE_18BPP
+#define DISP_DEVICE_16BPP
+#endif
+
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 220
+
+static void *DISP_CMD_PORT;
+static void *DISP_DATA_PORT;
+
+#define DISP_CMD_DISON 0xaf
+#define DISP_CMD_DISOFF 0xae
+#define DISP_CMD_DISNOR 0xa6
+#define DISP_CMD_DISINV 0xa7
+#define DISP_CMD_DISCTL 0xca
+#define DISP_CMD_GCP64 0xcb
+#define DISP_CMD_GCP16 0xcc
+#define DISP_CMD_GSSET 0xcd
+#define DISP_GS_2 0x02
+#define DISP_GS_16 0x01
+#define DISP_GS_64 0x00
+#define DISP_CMD_SLPIN 0x95
+#define DISP_CMD_SLPOUT 0x94
+#define DISP_CMD_SD_PSET 0x75
+#define DISP_CMD_MD_PSET 0x76
+#define DISP_CMD_SD_CSET 0x15
+#define DISP_CMD_MD_CSET 0x16
+#define DISP_CMD_DATCTL 0xbc
+#define DISP_DATCTL_666 0x08
+#define DISP_DATCTL_565 0x28
+#define DISP_DATCTL_444 0x38
+#define DISP_CMD_RAMWR 0x5c
+#define DISP_CMD_RAMRD 0x5d
+#define DISP_CMD_PTLIN 0xa8
+#define DISP_CMD_PTLOUT 0xa9
+#define DISP_CMD_ASCSET 0xaa
+#define DISP_CMD_SCSTART 0xab
+#define DISP_CMD_VOLCTL 0xc6
+#define DISP_VOLCTL_TONE 0x80
+#define DISP_CMD_NOp 0x25
+#define DISP_CMD_OSSEL 0xd0
+#define DISP_CMD_3500KSET 0xd1
+#define DISP_CMD_3500KEND 0xd2
+#define DISP_CMD_14MSET 0xd3
+#define DISP_CMD_14MEND 0xd4
+
+#define DISP_CMD_OUT(cmd) outpw(DISP_CMD_PORT, cmd);
+
+#define DISP_DATA_OUT(data) outpw(DISP_DATA_PORT, data);
+
+#define DISP_DATA_IN() inpw(DISP_DATA_PORT);
+
+/* Epson device column number starts at 2
+*/
+#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
+ DISP_CMD_OUT(DISP_CMD_SD_PSET) \
+ DISP_DATA_OUT((ulhc_row) & 0xFF) \
+ DISP_DATA_OUT((ulhc_row) >> 8) \
+ DISP_DATA_OUT((lrhc_row) & 0xFF) \
+ DISP_DATA_OUT((lrhc_row) >> 8) \
+ DISP_CMD_OUT(DISP_CMD_SD_CSET) \
+ DISP_DATA_OUT(((ulhc_col)+2) & 0xFF) \
+ DISP_DATA_OUT(((ulhc_col)+2) >> 8) \
+ DISP_DATA_OUT(((lrhc_col)+2) & 0xFF) \
+ DISP_DATA_OUT(((lrhc_col)+2) >> 8)
+
+#define DISP_MIN_CONTRAST 0
+#define DISP_MAX_CONTRAST 127
+#define DISP_DEFAULT_CONTRAST 80
+
+#define DISP_MIN_BACKLIGHT 0
+#define DISP_MAX_BACKLIGHT 15
+#define DISP_DEFAULT_BACKLIGHT 2
+
+#define WAIT_SEC(sec) mdelay((sec)/1000)
+
+static word disp_area_start_row;
+static word disp_area_end_row;
+static byte disp_contrast = DISP_DEFAULT_CONTRAST;
+static boolean disp_powered_up;
+static boolean disp_initialized = FALSE;
+/* For some reason the contrast set at init time is not good. Need to do
+ * it again
+ */
+static boolean display_on = FALSE;
+static void epsonQcif_disp_init(struct platform_device *pdev);
+static void epsonQcif_disp_set_contrast(word contrast);
+static void epsonQcif_disp_set_display_area(word start_row, word end_row);
+static int epsonQcif_disp_off(struct platform_device *pdev);
+static int epsonQcif_disp_on(struct platform_device *pdev);
+static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres);
+
+volatile word databack;
+static void epsonQcif_disp_init(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ int i;
+
+ if (disp_initialized)
+ return;
+
+ mfd = platform_get_drvdata(pdev);
+
+ DISP_CMD_PORT = mfd->cmd_port;
+ DISP_DATA_PORT = mfd->data_port;
+
+ /* Sleep in */
+ DISP_CMD_OUT(DISP_CMD_SLPIN);
+
+ /* Display off */
+ DISP_CMD_OUT(DISP_CMD_DISOFF);
+
+ /* Display normal */
+ DISP_CMD_OUT(DISP_CMD_DISNOR);
+
+ /* Set data mode */
+ DISP_CMD_OUT(DISP_CMD_DATCTL);
+ DISP_DATA_OUT(DISP_DATCTL_565);
+
+ /* Set display timing */
+ DISP_CMD_OUT(DISP_CMD_DISCTL);
+ DISP_DATA_OUT(0x1c); /* p1 */
+ DISP_DATA_OUT(0x02); /* p1 */
+ DISP_DATA_OUT(0x82); /* p2 */
+ DISP_DATA_OUT(0x00); /* p3 */
+ DISP_DATA_OUT(0x00); /* p4 */
+ DISP_DATA_OUT(0xe0); /* p5 */
+ DISP_DATA_OUT(0x00); /* p5 */
+ DISP_DATA_OUT(0xdc); /* p6 */
+ DISP_DATA_OUT(0x00); /* p6 */
+ DISP_DATA_OUT(0x02); /* p7 */
+ DISP_DATA_OUT(0x00); /* p8 */
+
+ /* Set 64 gray scale level */
+ DISP_CMD_OUT(DISP_CMD_GCP64);
+ DISP_DATA_OUT(0x08); /* p01 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x2a); /* p02 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x4e); /* p03 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x6b); /* p04 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x88); /* p05 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0xa3); /* p06 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0xba); /* p07 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0xd1); /* p08 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0xe5); /* p09 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0xf3); /* p10 */
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x03); /* p11 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x13); /* p12 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x22); /* p13 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x2f); /* p14 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x3b); /* p15 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x46); /* p16 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x51); /* p17 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x5b); /* p18 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x64); /* p19 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x6c); /* p20 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x74); /* p21 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x7c); /* p22 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x83); /* p23 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x8a); /* p24 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x91); /* p25 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x98); /* p26 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x9f); /* p27 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xa6); /* p28 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xac); /* p29 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xb2); /* p30 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xb7); /* p31 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xbc); /* p32 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xc1); /* p33 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xc6); /* p34 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xcb); /* p35 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xd0); /* p36 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xd4); /* p37 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xd8); /* p38 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xdc); /* p39 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xe0); /* p40 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xe4); /* p41 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xe8); /* p42 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xec); /* p43 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xf0); /* p44 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xf4); /* p45 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xf8); /* p46 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xfb); /* p47 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xfe); /* p48 */
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0x01); /* p49 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x03); /* p50 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x05); /* p51 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x07); /* p52 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x09); /* p53 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x0b); /* p54 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x0d); /* p55 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x0f); /* p56 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x11); /* p57 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x13); /* p58 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x15); /* p59 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x17); /* p60 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x19); /* p61 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x1b); /* p62 */
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x1c); /* p63 */
+ DISP_DATA_OUT(0x02);
+
+ /* Set 16 gray scale level */
+ DISP_CMD_OUT(DISP_CMD_GCP16);
+ DISP_DATA_OUT(0x1a); /* p01 */
+ DISP_DATA_OUT(0x32); /* p02 */
+ DISP_DATA_OUT(0x42); /* p03 */
+ DISP_DATA_OUT(0x4c); /* p04 */
+ DISP_DATA_OUT(0x58); /* p05 */
+ DISP_DATA_OUT(0x5f); /* p06 */
+ DISP_DATA_OUT(0x66); /* p07 */
+ DISP_DATA_OUT(0x6b); /* p08 */
+ DISP_DATA_OUT(0x70); /* p09 */
+ DISP_DATA_OUT(0x74); /* p10 */
+ DISP_DATA_OUT(0x78); /* p11 */
+ DISP_DATA_OUT(0x7b); /* p12 */
+ DISP_DATA_OUT(0x7e); /* p13 */
+ DISP_DATA_OUT(0x80); /* p14 */
+ DISP_DATA_OUT(0x82); /* p15 */
+
+ /* Set DSP column */
+ DISP_CMD_OUT(DISP_CMD_MD_CSET);
+ DISP_DATA_OUT(0xff);
+ DISP_DATA_OUT(0x03);
+ DISP_DATA_OUT(0xff);
+ DISP_DATA_OUT(0x03);
+
+ /* Set DSP page */
+ DISP_CMD_OUT(DISP_CMD_MD_PSET);
+ DISP_DATA_OUT(0xff);
+ DISP_DATA_OUT(0x01);
+ DISP_DATA_OUT(0xff);
+ DISP_DATA_OUT(0x01);
+
+ /* Set ARM column */
+ DISP_CMD_OUT(DISP_CMD_SD_CSET);
+ DISP_DATA_OUT(0x02);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT((QCIF_WIDTH + 1) & 0xFF);
+ DISP_DATA_OUT((QCIF_WIDTH + 1) >> 8);
+
+ /* Set ARM page */
+ DISP_CMD_OUT(DISP_CMD_SD_PSET);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT(0x00);
+ DISP_DATA_OUT((QCIF_HEIGHT - 1) & 0xFF);
+ DISP_DATA_OUT((QCIF_HEIGHT - 1) >> 8);
+
+ /* Set 64 gray scales */
+ DISP_CMD_OUT(DISP_CMD_GSSET);
+ DISP_DATA_OUT(DISP_GS_64);
+
+ DISP_CMD_OUT(DISP_CMD_OSSEL);
+ DISP_DATA_OUT(0);
+
+ /* Sleep out */
+ DISP_CMD_OUT(DISP_CMD_SLPOUT);
+
+ WAIT_SEC(40000);
+
+ /* Initialize power IC */
+ DISP_CMD_OUT(DISP_CMD_VOLCTL);
+ DISP_DATA_OUT(DISP_VOLCTL_TONE);
+
+ WAIT_SEC(40000);
+
+ /* Set electronic volume, d'xx */
+ DISP_CMD_OUT(DISP_CMD_VOLCTL);
+ DISP_DATA_OUT(DISP_DEFAULT_CONTRAST); /* value from 0 to 127 */
+
+ /* Initialize display data */
+ DISP_SET_RECT(0, (QCIF_HEIGHT - 1), 0, (QCIF_WIDTH - 1));
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+ for (i = 0; i < QCIF_HEIGHT * QCIF_WIDTH; i++)
+ DISP_DATA_OUT(0xffff);
+
+ DISP_CMD_OUT(DISP_CMD_RAMRD);
+ databack = DISP_DATA_IN();
+ databack = DISP_DATA_IN();
+ databack = DISP_DATA_IN();
+ databack = DISP_DATA_IN();
+
+ WAIT_SEC(80000);
+
+ DISP_CMD_OUT(DISP_CMD_DISON);
+
+ disp_area_start_row = 0;
+ disp_area_end_row = QCIF_HEIGHT - 1;
+ disp_powered_up = TRUE;
+ disp_initialized = TRUE;
+ epsonQcif_disp_set_display_area(0, QCIF_HEIGHT - 1);
+ display_on = TRUE;
+}
+
+static void epsonQcif_disp_set_rect(int x, int y, int xres, int yres)
+{
+ if (!disp_initialized)
+ return;
+
+ DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1);
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+}
+
+static void epsonQcif_disp_set_display_area(word start_row, word end_row)
+{
+ if (!disp_initialized)
+ return;
+
+ if ((start_row == disp_area_start_row)
+ && (end_row == disp_area_end_row))
+ return;
+ disp_area_start_row = start_row;
+ disp_area_end_row = end_row;
+
+ /* Range checking
+ */
+ if (end_row >= QCIF_HEIGHT)
+ end_row = QCIF_HEIGHT - 1;
+ if (start_row > end_row)
+ start_row = end_row;
+
+ /* When display is not the full screen, gray scale is set to
+ ** 2; otherwise it is set to 64.
+ */
+ if ((start_row == 0) && (end_row == (QCIF_HEIGHT - 1))) {
+ /* The whole screen */
+ DISP_CMD_OUT(DISP_CMD_PTLOUT);
+ WAIT_SEC(10000);
+ DISP_CMD_OUT(DISP_CMD_DISOFF);
+ WAIT_SEC(100000);
+ DISP_CMD_OUT(DISP_CMD_GSSET);
+ DISP_DATA_OUT(DISP_GS_64);
+ WAIT_SEC(100000);
+ DISP_CMD_OUT(DISP_CMD_DISON);
+ } else {
+ /* partial screen */
+ DISP_CMD_OUT(DISP_CMD_PTLIN);
+ DISP_DATA_OUT(start_row);
+ DISP_DATA_OUT(start_row >> 8);
+ DISP_DATA_OUT(end_row);
+ DISP_DATA_OUT(end_row >> 8);
+ DISP_CMD_OUT(DISP_CMD_GSSET);
+ DISP_DATA_OUT(DISP_GS_2);
+ }
+}
+
+static int epsonQcif_disp_off(struct platform_device *pdev)
+{
+ if (!disp_initialized)
+ epsonQcif_disp_init(pdev);
+
+ if (display_on) {
+ DISP_CMD_OUT(DISP_CMD_DISOFF);
+ DISP_CMD_OUT(DISP_CMD_SLPIN);
+ display_on = FALSE;
+ }
+
+ return 0;
+}
+
+static int epsonQcif_disp_on(struct platform_device *pdev)
+{
+ if (!disp_initialized)
+ epsonQcif_disp_init(pdev);
+
+ if (!display_on) {
+ DISP_CMD_OUT(DISP_CMD_SLPOUT);
+ WAIT_SEC(40000);
+ DISP_CMD_OUT(DISP_CMD_DISON);
+ epsonQcif_disp_set_contrast(disp_contrast);
+ display_on = TRUE;
+ }
+
+ return 0;
+}
+
+static void epsonQcif_disp_set_contrast(word contrast)
+{
+ if (!disp_initialized)
+ return;
+
+ /* Initialize power IC, d'24 */
+ DISP_CMD_OUT(DISP_CMD_VOLCTL);
+ DISP_DATA_OUT(DISP_VOLCTL_TONE);
+
+ WAIT_SEC(40000);
+
+ /* Set electronic volume, d'xx */
+ DISP_CMD_OUT(DISP_CMD_VOLCTL);
+ if (contrast > 127)
+ contrast = 127;
+ DISP_DATA_OUT(contrast); /* value from 0 to 127 */
+ disp_contrast = (byte) contrast;
+} /* End disp_set_contrast */
+
+static void epsonQcif_disp_clear_screen_area(
+ word start_row, word end_row, word start_column, word end_column) {
+ int32 i;
+
+ /* Clear the display screen */
+ DISP_SET_RECT(start_row, end_row, start_column, end_column);
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+ i = (end_row - start_row + 1) * (end_column - start_column + 1);
+ for (; i > 0; i--)
+ DISP_DATA_OUT(0xffff);
+}
+
+static int __init epsonQcif_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = epsonQcif_probe,
+ .driver = {
+ .name = "ebi2_epson_qcif",
+ },
+};
+
+static struct msm_fb_panel_data epsonQcif_panel_data = {
+ .on = epsonQcif_disp_on,
+ .off = epsonQcif_disp_off,
+ .set_rect = epsonQcif_disp_set_rect,
+};
+
+static struct platform_device this_device = {
+ .name = "ebi2_epson_qcif",
+ .id = 0,
+ .dev = {
+ .platform_data = &epsonQcif_panel_data,
+ }
+};
+
+static int __init epsonQcif_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &epsonQcif_panel_data.panel_info;
+ pinfo->xres = QCIF_WIDTH;
+ pinfo->yres = QCIF_HEIGHT;
+ pinfo->type = EBI2_PANEL;
+ pinfo->pdest = DISPLAY_2;
+ pinfo->wait_cycle = 0x808000;
+ pinfo->bpp = 16;
+ pinfo->fb_num = 2;
+ pinfo->lcd.vsync_enable = FALSE;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(epsonQcif_init);
diff --git a/drivers/staging/msm/ebi2_lcd.c b/drivers/staging/msm/ebi2_lcd.c
new file mode 100644
index 000000000000..b41e1230ceca
--- /dev/null
+++ b/drivers/staging/msm/ebi2_lcd.c
@@ -0,0 +1,250 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+
+#include "msm_fb.h"
+
+static int ebi2_lcd_probe(struct platform_device *pdev);
+static int ebi2_lcd_remove(struct platform_device *pdev);
+
+static struct platform_driver ebi2_lcd_driver = {
+ .probe = ebi2_lcd_probe,
+ .remove = ebi2_lcd_remove,
+ .suspend = NULL,
+ .suspend_late = NULL,
+ .resume_early = NULL,
+ .resume = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "ebi2_lcd",
+ },
+};
+
+static void *ebi2_base;
+static void *ebi2_lcd_cfg0;
+static void *ebi2_lcd_cfg1;
+static void __iomem *lcd01_base;
+static void __iomem *lcd02_base;
+static int ebi2_lcd_resource_initialized;
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static int ebi2_lcd_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc, i;
+
+ if (pdev->id == 0) {
+ for (i = 0; i < pdev->num_resources; i++) {
+ if (!strncmp(pdev->resource[i].name, "base", 4)) {
+ ebi2_base = ioremap(pdev->resource[i].start,
+ pdev->resource[i].end -
+ pdev->resource[i].start + 1);
+ if (!ebi2_base) {
+ printk(KERN_ERR
+ "ebi2_base ioremap failed!\n");
+ return -ENOMEM;
+ }
+ ebi2_lcd_cfg0 = (void *)(ebi2_base + 0x20);
+ ebi2_lcd_cfg1 = (void *)(ebi2_base + 0x24);
+ } else if (!strncmp(pdev->resource[i].name,
+ "lcd01", 5)) {
+ lcd01_base = ioremap(pdev->resource[i].start,
+ pdev->resource[i].end -
+ pdev->resource[i].start + 1);
+ if (!lcd01_base) {
+ printk(KERN_ERR
+ "lcd01_base ioremap failed!\n");
+ return -ENOMEM;
+ }
+ } else if (!strncmp(pdev->resource[i].name,
+ "lcd02", 5)) {
+ lcd02_base = ioremap(pdev->resource[i].start,
+ pdev->resource[i].end -
+ pdev->resource[i].start + 1);
+ if (!lcd02_base) {
+ printk(KERN_ERR
+ "lcd02_base ioremap failed!\n");
+ return -ENOMEM;
+ }
+ }
+ }
+ ebi2_lcd_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!ebi2_lcd_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ if (ebi2_base == NULL)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /* link to the latest pdev */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_LCD;
+
+ /* add panel data */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "ebi2_lcd_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+
+ /* data chain */
+ pdata = mdp_dev->dev.platform_data;
+ pdata->on = panel_next_on;
+ pdata->off = panel_next_off;
+ pdata->next = pdev;
+
+ /* get/set panel specific fb info */
+ mfd->panel_info = pdata->panel_info;
+
+ if (mfd->panel_info.bpp == 24)
+ mfd->fb_imgType = MDP_RGB_888;
+ else
+ mfd->fb_imgType = MDP_RGB_565;
+
+ /* config msm ebi2 lcd register */
+ if (mfd->panel_info.pdest == DISPLAY_1) {
+ outp32(ebi2_base,
+ (inp32(ebi2_base) & (~(EBI2_PRIM_LCD_CLR))) |
+ EBI2_PRIM_LCD_SEL);
+ /*
+ * current design has one set of cfg0/1 register to control
+ * both EBI2 channels. so, we're using the PRIM channel to
+ * configure both.
+ */
+ outp32(ebi2_lcd_cfg0, mfd->panel_info.wait_cycle);
+ if (mfd->panel_info.bpp == 18)
+ outp32(ebi2_lcd_cfg1, 0x01000000);
+ else
+ outp32(ebi2_lcd_cfg1, 0x0);
+ } else {
+#ifdef DEBUG_EBI2_LCD
+ /*
+ * confliting with QCOM SURF FPGA CS.
+ * OEM should enable below for their CS mapping
+ */
+ outp32(ebi2_base, (inp32(ebi2_base)&(~(EBI2_SECD_LCD_CLR)))
+ |EBI2_SECD_LCD_SEL);
+#endif
+ }
+
+ /*
+ * map cs (chip select) address
+ */
+ if (mfd->panel_info.pdest == DISPLAY_1) {
+ mfd->cmd_port = lcd01_base;
+ mfd->data_port =
+ (void *)((uint32) mfd->cmd_port + EBI2_PRIM_LCD_RS_PIN);
+ mfd->data_port_phys =
+ (void *)(LCD_PRIM_BASE_PHYS + EBI2_PRIM_LCD_RS_PIN);
+ } else {
+ mfd->cmd_port = lcd01_base;
+ mfd->data_port =
+ (void *)((uint32) mfd->cmd_port + EBI2_SECD_LCD_RS_PIN);
+ mfd->data_port_phys =
+ (void *)(LCD_SECD_BASE_PHYS + EBI2_SECD_LCD_RS_PIN);
+ }
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc) {
+ goto ebi2_lcd_probe_err;
+ }
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+
+ ebi2_lcd_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int ebi2_lcd_remove(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return 0;
+
+ if (mfd->key != MFD_KEY)
+ return 0;
+
+ iounmap(mfd->cmd_port);
+
+ return 0;
+}
+
+static int ebi2_lcd_register_driver(void)
+{
+ return platform_driver_register(&ebi2_lcd_driver);
+}
+
+static int __init ebi2_lcd_driver_init(void)
+{
+ return ebi2_lcd_register_driver();
+}
+
+module_init(ebi2_lcd_driver_init); \ No newline at end of file
diff --git a/drivers/staging/msm/ebi2_tmd20.c b/drivers/staging/msm/ebi2_tmd20.c
new file mode 100644
index 000000000000..d66d03978253
--- /dev/null
+++ b/drivers/staging/msm/ebi2_tmd20.c
@@ -0,0 +1,1122 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+#include <linux/memory.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+/* #define TMD20QVGA_LCD_18BPP */
+#define QVGA_WIDTH 240
+#define QVGA_HEIGHT 320
+
+#ifdef TMD20QVGA_LCD_18BPP
+#define DISP_QVGA_18BPP(x) ((((x)<<2) & 0x3FC00)|(( (x)<<1)& 0x1FE))
+#define DISP_REG(name) uint32 register_##name;
+#define OUTPORT(x, y) outpdw(x, y)
+#define INPORT(x) inpdw(x)
+#else
+#define DISP_QVGA_18BPP(x) (x)
+#define DISP_REG(name) uint16 register_##name;
+#define OUTPORT(x, y) outpw(x, y)
+#define INPORT(x) intpw(x)
+#endif
+
+static void *DISP_CMD_PORT;
+static void *DISP_DATA_PORT;
+
+#define DISP_RNTI 0x10
+
+#define DISP_CMD_OUT(cmd) OUTPORT(DISP_CMD_PORT, DISP_QVGA_18BPP(cmd))
+#define DISP_DATA_OUT(data) OUTPORT(DISP_DATA_PORT, data)
+#define DISP_DATA_IN() INPORT(DISP_DATA_PORT)
+
+#if (defined(TMD20QVGA_LCD_18BPP))
+#define DISP_DATA_OUT_16TO18BPP(x) \
+ DISP_DATA_OUT((((x)&0xf800)<<2|((x)&0x80000)>>3) \
+ | (((x)&0x7e0)<<1) \
+ | (((x)&0x1F)<<1|((x)&0x10)>>4))
+#else
+#define DISP_DATA_OUT_16TO18BPP(x) \
+ DISP_DATA_OUT(x)
+#endif
+
+#define DISP_WRITE_OUT(addr, data) \
+ register_##addr = DISP_QVGA_18BPP(data); \
+ DISP_CMD_OUT(addr); \
+ DISP_DATA_OUT(register_##addr);
+
+#define DISP_UPDATE_VALUE(addr, bitmask, data) \
+ DISP_WRITE_OUT(##addr, (register_##addr & ~(bitmask)) | (data));
+
+#define DISP_VAL_IF(bitvalue, bitmask) \
+ ((bitvalue) ? (bitmask) : 0)
+
+/* QVGA = 256 x 320 */
+/* actual display is 240 x 320...offset by 0x10 */
+#define DISP_ROW_COL_TO_ADDR(row, col) ((row) * 0x100 + col)
+#define DISP_SET_RECT(ulhc_row, lrhc_row, ulhc_col, lrhc_col) \
+ { \
+ DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \
+ DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, (lrhc_col) + tmd20qvga_panel_offset); \
+ DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, (ulhc_row)); \
+ DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, (lrhc_row)); \
+ DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, (ulhc_col) + tmd20qvga_panel_offset); \
+ DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, (ulhc_row)); \
+ }
+
+#define WAIT_MSEC(msec) mdelay(msec)
+
+/*
+ * TMD QVGA Address
+ */
+/* Display Control */
+#define DISP_START_OSCILLATION_ADDR 0x000
+DISP_REG(DISP_START_OSCILLATION_ADDR)
+#define DISP_DRIVER_OUTPUT_CTL_ADDR 0x001
+ DISP_REG(DISP_DRIVER_OUTPUT_CTL_ADDR)
+#define DISP_LCD_DRIVING_SIG_ADDR 0x002
+ DISP_REG(DISP_LCD_DRIVING_SIG_ADDR)
+#define DISP_ENTRY_MODE_ADDR 0x003
+ DISP_REG(DISP_ENTRY_MODE_ADDR)
+#define DISP_DISPLAY_CTL_1_ADDR 0x007
+ DISP_REG(DISP_DISPLAY_CTL_1_ADDR)
+#define DISP_DISPLAY_CTL_2_ADDR 0x008
+ DISP_REG(DISP_DISPLAY_CTL_2_ADDR)
+
+/* DISPLAY MODE 0x009 partial display not supported */
+#define DISP_POWER_SUPPLY_INTF_ADDR 0x00A
+ DISP_REG(DISP_POWER_SUPPLY_INTF_ADDR)
+
+/* DISPLAY MODE 0x00B xZoom feature is not supported */
+#define DISP_EXT_DISPLAY_CTL_1_ADDR 0x00C
+ DISP_REG(DISP_EXT_DISPLAY_CTL_1_ADDR)
+
+#define DISP_FRAME_CYCLE_CTL_ADDR 0x00D
+ DISP_REG(DISP_FRAME_CYCLE_CTL_ADDR)
+
+#define DISP_EXT_DISPLAY_CTL_2_ADDR 0x00E
+ DISP_REG(DISP_EXT_DISPLAY_CTL_2_ADDR)
+
+#define DISP_EXT_DISPLAY_CTL_3_ADDR 0x00F
+ DISP_REG(DISP_EXT_DISPLAY_CTL_3_ADDR)
+
+#define DISP_LTPS_CTL_1_ADDR 0x012
+ DISP_REG(DISP_LTPS_CTL_1_ADDR)
+#define DISP_LTPS_CTL_2_ADDR 0x013
+ DISP_REG(DISP_LTPS_CTL_2_ADDR)
+#define DISP_LTPS_CTL_3_ADDR 0x014
+ DISP_REG(DISP_LTPS_CTL_3_ADDR)
+#define DISP_LTPS_CTL_4_ADDR 0x018
+ DISP_REG(DISP_LTPS_CTL_4_ADDR)
+#define DISP_LTPS_CTL_5_ADDR 0x019
+ DISP_REG(DISP_LTPS_CTL_5_ADDR)
+#define DISP_LTPS_CTL_6_ADDR 0x01A
+ DISP_REG(DISP_LTPS_CTL_6_ADDR)
+#define DISP_AMP_SETTING_ADDR 0x01C
+ DISP_REG(DISP_AMP_SETTING_ADDR)
+#define DISP_MODE_SETTING_ADDR 0x01D
+ DISP_REG(DISP_MODE_SETTING_ADDR)
+#define DISP_POFF_LN_SETTING_ADDR 0x01E
+ DISP_REG(DISP_POFF_LN_SETTING_ADDR)
+/* Power Contol */
+#define DISP_POWER_CTL_1_ADDR 0x100
+ DISP_REG(DISP_POWER_CTL_1_ADDR)
+#define DISP_POWER_CTL_2_ADDR 0x101
+ DISP_REG(DISP_POWER_CTL_2_ADDR)
+#define DISP_POWER_CTL_3_ADDR 0x102
+ DISP_REG(DISP_POWER_CTL_3_ADDR)
+#define DISP_POWER_CTL_4_ADDR 0x103
+ DISP_REG(DISP_POWER_CTL_4_ADDR)
+#define DISP_POWER_CTL_5_ADDR 0x104
+ DISP_REG(DISP_POWER_CTL_5_ADDR)
+#define DISP_POWER_CTL_6_ADDR 0x105
+ DISP_REG(DISP_POWER_CTL_6_ADDR)
+#define DISP_POWER_CTL_7_ADDR 0x106
+ DISP_REG(DISP_POWER_CTL_7_ADDR)
+/* RAM Access */
+#define DISP_RAM_ADDR_SET_1_ADDR 0x200
+ DISP_REG(DISP_RAM_ADDR_SET_1_ADDR)
+#define DISP_RAM_ADDR_SET_2_ADDR 0x201
+ DISP_REG(DISP_RAM_ADDR_SET_2_ADDR)
+#define DISP_CMD_RAMRD DISP_CMD_RAMWR
+#define DISP_CMD_RAMWR 0x202
+ DISP_REG(DISP_CMD_RAMWR)
+#define DISP_RAM_DATA_MASK_1_ADDR 0x203
+ DISP_REG(DISP_RAM_DATA_MASK_1_ADDR)
+#define DISP_RAM_DATA_MASK_2_ADDR 0x204
+ DISP_REG(DISP_RAM_DATA_MASK_2_ADDR)
+/* Gamma Control, Contrast, Gray Scale Setting */
+#define DISP_GAMMA_CONTROL_1_ADDR 0x300
+ DISP_REG(DISP_GAMMA_CONTROL_1_ADDR)
+#define DISP_GAMMA_CONTROL_2_ADDR 0x301
+ DISP_REG(DISP_GAMMA_CONTROL_2_ADDR)
+#define DISP_GAMMA_CONTROL_3_ADDR 0x302
+ DISP_REG(DISP_GAMMA_CONTROL_3_ADDR)
+#define DISP_GAMMA_CONTROL_4_ADDR 0x303
+ DISP_REG(DISP_GAMMA_CONTROL_4_ADDR)
+#define DISP_GAMMA_CONTROL_5_ADDR 0x304
+ DISP_REG(DISP_GAMMA_CONTROL_5_ADDR)
+/* Coordinate Control */
+#define DISP_VERT_SCROLL_CTL_1_ADDR 0x400
+ DISP_REG(DISP_VERT_SCROLL_CTL_1_ADDR)
+#define DISP_VERT_SCROLL_CTL_2_ADDR 0x401
+ DISP_REG(DISP_VERT_SCROLL_CTL_2_ADDR)
+#define DISP_SCREEN_1_DRV_POS_1_ADDR 0x402
+ DISP_REG(DISP_SCREEN_1_DRV_POS_1_ADDR)
+#define DISP_SCREEN_1_DRV_POS_2_ADDR 0x403
+ DISP_REG(DISP_SCREEN_1_DRV_POS_2_ADDR)
+#define DISP_SCREEN_2_DRV_POS_1_ADDR 0x404
+ DISP_REG(DISP_SCREEN_2_DRV_POS_1_ADDR)
+#define DISP_SCREEN_2_DRV_POS_2_ADDR 0x405
+ DISP_REG(DISP_SCREEN_2_DRV_POS_2_ADDR)
+#define DISP_HORZ_RAM_ADDR_POS_1_ADDR 0x406
+ DISP_REG(DISP_HORZ_RAM_ADDR_POS_1_ADDR)
+#define DISP_HORZ_RAM_ADDR_POS_2_ADDR 0x407
+ DISP_REG(DISP_HORZ_RAM_ADDR_POS_2_ADDR)
+#define DISP_VERT_RAM_ADDR_POS_1_ADDR 0x408
+ DISP_REG(DISP_VERT_RAM_ADDR_POS_1_ADDR)
+#define DISP_VERT_RAM_ADDR_POS_2_ADDR 0x409
+ DISP_REG(DISP_VERT_RAM_ADDR_POS_2_ADDR)
+#define DISP_TMD_700_ADDR 0x700 /* 0x700 */
+ DISP_REG(DISP_TMD_700_ADDR)
+#define DISP_TMD_015_ADDR 0x015 /* 0x700 */
+ DISP_REG(DISP_TMD_015_ADDR)
+#define DISP_TMD_305_ADDR 0x305 /* 0x700 */
+ DISP_REG(DISP_TMD_305_ADDR)
+
+/*
+ * TMD QVGA Bit Definations
+ */
+
+#define DISP_BIT_IB15 0x8000
+#define DISP_BIT_IB14 0x4000
+#define DISP_BIT_IB13 0x2000
+#define DISP_BIT_IB12 0x1000
+#define DISP_BIT_IB11 0x0800
+#define DISP_BIT_IB10 0x0400
+#define DISP_BIT_IB09 0x0200
+#define DISP_BIT_IB08 0x0100
+#define DISP_BIT_IB07 0x0080
+#define DISP_BIT_IB06 0x0040
+#define DISP_BIT_IB05 0x0020
+#define DISP_BIT_IB04 0x0010
+#define DISP_BIT_IB03 0x0008
+#define DISP_BIT_IB02 0x0004
+#define DISP_BIT_IB01 0x0002
+#define DISP_BIT_IB00 0x0001
+/*
+ * Display Control
+ * DISP_START_OSCILLATION_ADDR Start Oscillation
+ * DISP_DRIVER_OUTPUT_CTL_ADDR Driver Output Control
+ */
+#define DISP_BITMASK_SS DISP_BIT_IB08
+#define DISP_BITMASK_NL5 DISP_BIT_IB05
+#define DISP_BITMASK_NL4 DISP_BIT_IB04
+#define DISP_BITMASK_NL3 DISP_BIT_IB03
+#define DISP_BITMASK_NL2 DISP_BIT_IB02
+#define DISP_BITMASK_NL1 DISP_BIT_IB01
+#define DISP_BITMASK_NL0 DISP_BIT_IB00
+/* DISP_LCD_DRIVING_SIG_ADDR LCD Driving Signal Setting */
+#define DISP_BITMASK_BC DISP_BIT_IB09
+/* DISP_ENTRY_MODE_ADDR Entry Mode */
+#define DISP_BITMASK_TRI DISP_BIT_IB15
+#define DISP_BITMASK_DFM1 DISP_BIT_IB14
+#define DISP_BITMASK_DFM0 DISP_BIT_IB13
+#define DISP_BITMASK_BGR DISP_BIT_IB12
+#define DISP_BITMASK_HWM0 DISP_BIT_IB08
+#define DISP_BITMASK_ID1 DISP_BIT_IB05
+#define DISP_BITMASK_ID0 DISP_BIT_IB04
+#define DISP_BITMASK_AM DISP_BIT_IB03
+/* DISP_DISPLAY_CTL_1_ADDR Display Control (1) */
+#define DISP_BITMASK_COL1 DISP_BIT_IB15
+#define DISP_BITMASK_COL0 DISP_BIT_IB14
+#define DISP_BITMASK_VLE2 DISP_BIT_IB10
+#define DISP_BITMASK_VLE1 DISP_BIT_IB09
+#define DISP_BITMASK_SPT DISP_BIT_IB08
+#define DISP_BITMASK_PT1 DISP_BIT_IB07
+#define DISP_BITMASK_PT0 DISP_BIT_IB06
+#define DISP_BITMASK_REV DISP_BIT_IB02
+/* DISP_DISPLAY_CTL_2_ADDR Display Control (2) */
+#define DISP_BITMASK_FP3 DISP_BIT_IB11
+#define DISP_BITMASK_FP2 DISP_BIT_IB10
+#define DISP_BITMASK_FP1 DISP_BIT_IB09
+#define DISP_BITMASK_FP0 DISP_BIT_IB08
+#define DISP_BITMASK_BP3 DISP_BIT_IB03
+#define DISP_BITMASK_BP2 DISP_BIT_IB02
+#define DISP_BITMASK_BP1 DISP_BIT_IB01
+#define DISP_BITMASK_BP0 DISP_BIT_IB00
+/* DISP_POWER_SUPPLY_INTF_ADDR Power Supply IC Interface Control */
+#define DISP_BITMASK_CSE DISP_BIT_IB12
+#define DISP_BITMASK_TE DISP_BIT_IB08
+#define DISP_BITMASK_IX3 DISP_BIT_IB03
+#define DISP_BITMASK_IX2 DISP_BIT_IB02
+#define DISP_BITMASK_IX1 DISP_BIT_IB01
+#define DISP_BITMASK_IX0 DISP_BIT_IB00
+/* DISP_EXT_DISPLAY_CTL_1_ADDR External Display Interface Control (1) */
+#define DISP_BITMASK_RM DISP_BIT_IB08
+#define DISP_BITMASK_DM1 DISP_BIT_IB05
+#define DISP_BITMASK_DM0 DISP_BIT_IB04
+#define DISP_BITMASK_RIM1 DISP_BIT_IB01
+#define DISP_BITMASK_RIM0 DISP_BIT_IB00
+/* DISP_FRAME_CYCLE_CTL_ADDR Frame Frequency Adjustment Control */
+#define DISP_BITMASK_DIVI1 DISP_BIT_IB09
+#define DISP_BITMASK_DIVI0 DISP_BIT_IB08
+#define DISP_BITMASK_RTNI4 DISP_BIT_IB04
+#define DISP_BITMASK_RTNI3 DISP_BIT_IB03
+#define DISP_BITMASK_RTNI2 DISP_BIT_IB02
+#define DISP_BITMASK_RTNI1 DISP_BIT_IB01
+#define DISP_BITMASK_RTNI0 DISP_BIT_IB00
+/* DISP_EXT_DISPLAY_CTL_2_ADDR External Display Interface Control (2) */
+#define DISP_BITMASK_DIVE1 DISP_BIT_IB09
+#define DISP_BITMASK_DIVE0 DISP_BIT_IB08
+#define DISP_BITMASK_RTNE7 DISP_BIT_IB07
+#define DISP_BITMASK_RTNE6 DISP_BIT_IB06
+#define DISP_BITMASK_RTNE5 DISP_BIT_IB05
+#define DISP_BITMASK_RTNE4 DISP_BIT_IB04
+#define DISP_BITMASK_RTNE3 DISP_BIT_IB03
+#define DISP_BITMASK_RTNE2 DISP_BIT_IB02
+#define DISP_BITMASK_RTNE1 DISP_BIT_IB01
+#define DISP_BITMASK_RTNE0 DISP_BIT_IB00
+/* DISP_EXT_DISPLAY_CTL_3_ADDR External Display Interface Control (3) */
+#define DISP_BITMASK_VSPL DISP_BIT_IB04
+#define DISP_BITMASK_HSPL DISP_BIT_IB03
+#define DISP_BITMASK_VPL DISP_BIT_IB02
+#define DISP_BITMASK_EPL DISP_BIT_IB01
+#define DISP_BITMASK_DPL DISP_BIT_IB00
+/* DISP_LTPS_CTL_1_ADDR LTPS Interface Control (1) */
+#define DISP_BITMASK_CLWI3 DISP_BIT_IB11
+#define DISP_BITMASK_CLWI2 DISP_BIT_IB10
+#define DISP_BITMASK_CLWI1 DISP_BIT_IB09
+#define DISP_BITMASK_CLWI0 DISP_BIT_IB08
+#define DISP_BITMASK_CLTI1 DISP_BIT_IB01
+#define DISP_BITMASK_CLTI0 DISP_BIT_IB00
+/* DISP_LTPS_CTL_2_ADDR LTPS Interface Control (2) */
+#define DISP_BITMASK_OEVBI1 DISP_BIT_IB09
+#define DISP_BITMASK_OEVBI0 DISP_BIT_IB08
+#define DISP_BITMASK_OEVFI1 DISP_BIT_IB01
+#define DISP_BITMASK_OEVFI0 DISP_BIT_IB00
+/* DISP_LTPS_CTL_3_ADDR LTPS Interface Control (3) */
+#define DISP_BITMASK_SHI1 DISP_BIT_IB01
+#define DISP_BITMASK_SHI0 DISP_BIT_IB00
+/* DISP_LTPS_CTL_4_ADDR LTPS Interface Control (4) */
+#define DISP_BITMASK_CLWE5 DISP_BIT_IB13
+#define DISP_BITMASK_CLWE4 DISP_BIT_IB12
+#define DISP_BITMASK_CLWE3 DISP_BIT_IB11
+#define DISP_BITMASK_CLWE2 DISP_BIT_IB10
+#define DISP_BITMASK_CLWE1 DISP_BIT_IB09
+#define DISP_BITMASK_CLWE0 DISP_BIT_IB08
+#define DISP_BITMASK_CLTE3 DISP_BIT_IB03
+#define DISP_BITMASK_CLTE2 DISP_BIT_IB02
+#define DISP_BITMASK_CLTE1 DISP_BIT_IB01
+#define DISP_BITMASK_CLTE0 DISP_BIT_IB00
+/* DISP_LTPS_CTL_5_ADDR LTPS Interface Control (5) */
+#define DISP_BITMASK_OEVBE3 DISP_BIT_IB11
+#define DISP_BITMASK_OEVBE2 DISP_BIT_IB10
+#define DISP_BITMASK_OEVBE1 DISP_BIT_IB09
+#define DISP_BITMASK_OEVBE0 DISP_BIT_IB08
+#define DISP_BITMASK_OEVFE3 DISP_BIT_IB03
+#define DISP_BITMASK_OEVFE2 DISP_BIT_IB02
+#define DISP_BITMASK_OEVFE1 DISP_BIT_IB01
+#define DISP_BITMASK_OEVFE0 DISP_BIT_IB00
+/* DISP_LTPS_CTL_6_ADDR LTPS Interface Control (6) */
+#define DISP_BITMASK_SHE3 DISP_BIT_IB03
+#define DISP_BITMASK_SHE2 DISP_BIT_IB02
+#define DISP_BITMASK_SHE1 DISP_BIT_IB01
+#define DISP_BITMASK_SHE0 DISP_BIT_IB00
+/* DISP_AMP_SETTING_ADDR Amplify Setting */
+#define DISP_BITMASK_ABSW1 DISP_BIT_IB01
+#define DISP_BITMASK_ABSW0 DISP_BIT_IB00
+/* DISP_MODE_SETTING_ADDR Mode Setting */
+#define DISP_BITMASK_DSTB DISP_BIT_IB02
+#define DISP_BITMASK_STB DISP_BIT_IB00
+/* DISP_POFF_LN_SETTING_ADDR Power Off Line Setting */
+#define DISP_BITMASK_POFH3 DISP_BIT_IB03
+#define DISP_BITMASK_POFH2 DISP_BIT_IB02
+#define DISP_BITMASK_POFH1 DISP_BIT_IB01
+#define DISP_BITMASK_POFH0 DISP_BIT_IB00
+
+/* Power Contol */
+/* DISP_POWER_CTL_1_ADDR Power Control (1) */
+#define DISP_BITMASK_PO DISP_BIT_IB11
+#define DISP_BITMASK_VCD DISP_BIT_IB09
+#define DISP_BITMASK_VSC DISP_BIT_IB08
+#define DISP_BITMASK_CON DISP_BIT_IB07
+#define DISP_BITMASK_ASW1 DISP_BIT_IB06
+#define DISP_BITMASK_ASW0 DISP_BIT_IB05
+#define DISP_BITMASK_OEV DISP_BIT_IB04
+#define DISP_BITMASK_OEVE DISP_BIT_IB03
+#define DISP_BITMASK_FR DISP_BIT_IB02
+#define DISP_BITMASK_D1 DISP_BIT_IB01
+#define DISP_BITMASK_D0 DISP_BIT_IB00
+/* DISP_POWER_CTL_2_ADDR Power Control (2) */
+#define DISP_BITMASK_DC4 DISP_BIT_IB15
+#define DISP_BITMASK_DC3 DISP_BIT_IB14
+#define DISP_BITMASK_SAP2 DISP_BIT_IB13
+#define DISP_BITMASK_SAP1 DISP_BIT_IB12
+#define DISP_BITMASK_SAP0 DISP_BIT_IB11
+#define DISP_BITMASK_BT2 DISP_BIT_IB10
+#define DISP_BITMASK_BT1 DISP_BIT_IB09
+#define DISP_BITMASK_BT0 DISP_BIT_IB08
+#define DISP_BITMASK_DC2 DISP_BIT_IB07
+#define DISP_BITMASK_DC1 DISP_BIT_IB06
+#define DISP_BITMASK_DC0 DISP_BIT_IB05
+#define DISP_BITMASK_AP2 DISP_BIT_IB04
+#define DISP_BITMASK_AP1 DISP_BIT_IB03
+#define DISP_BITMASK_AP0 DISP_BIT_IB02
+/* DISP_POWER_CTL_3_ADDR Power Control (3) */
+#define DISP_BITMASK_VGL4 DISP_BIT_IB10
+#define DISP_BITMASK_VGL3 DISP_BIT_IB09
+#define DISP_BITMASK_VGL2 DISP_BIT_IB08
+#define DISP_BITMASK_VGL1 DISP_BIT_IB07
+#define DISP_BITMASK_VGL0 DISP_BIT_IB06
+#define DISP_BITMASK_VGH4 DISP_BIT_IB04
+#define DISP_BITMASK_VGH3 DISP_BIT_IB03
+#define DISP_BITMASK_VGH2 DISP_BIT_IB02
+#define DISP_BITMASK_VGH1 DISP_BIT_IB01
+#define DISP_BITMASK_VGH0 DISP_BIT_IB00
+/* DISP_POWER_CTL_4_ADDR Power Control (4) */
+#define DISP_BITMASK_VC2 DISP_BIT_IB02
+#define DISP_BITMASK_VC1 DISP_BIT_IB01
+#define DISP_BITMASK_VC0 DISP_BIT_IB00
+/* DISP_POWER_CTL_5_ADDR Power Control (5) */
+#define DISP_BITMASK_VRL3 DISP_BIT_IB11
+#define DISP_BITMASK_VRL2 DISP_BIT_IB10
+#define DISP_BITMASK_VRL1 DISP_BIT_IB09
+#define DISP_BITMASK_VRL0 DISP_BIT_IB08
+#define DISP_BITMASK_PON DISP_BIT_IB04
+#define DISP_BITMASK_VRH3 DISP_BIT_IB03
+#define DISP_BITMASK_VRH2 DISP_BIT_IB02
+#define DISP_BITMASK_VRH1 DISP_BIT_IB01
+#define DISP_BITMASK_VRH0 DISP_BIT_IB00
+/* DISP_POWER_CTL_6_ADDR Power Control (6) */
+#define DISP_BITMASK_VCOMG DISP_BIT_IB13
+#define DISP_BITMASK_VDV4 DISP_BIT_IB12
+#define DISP_BITMASK_VDV3 DISP_BIT_IB11
+#define DISP_BITMASK_VDV2 DISP_BIT_IB10
+#define DISP_BITMASK_VDV1 DISP_BIT_IB09
+#define DISP_BITMASK_VDV0 DISP_BIT_IB08
+#define DISP_BITMASK_VCM4 DISP_BIT_IB04
+#define DISP_BITMASK_VCM3 DISP_BIT_IB03
+#define DISP_BITMASK_VCM2 DISP_BIT_IB02
+#define DISP_BITMASK_VCM1 DISP_BIT_IB01
+#define DISP_BITMASK_VCM0 DISP_BIT_IB00
+/* RAM Access */
+/* DISP_RAM_ADDR_SET_1_ADDR RAM Address Set (1) */
+#define DISP_BITMASK_AD7 DISP_BIT_IB07
+#define DISP_BITMASK_AD6 DISP_BIT_IB06
+#define DISP_BITMASK_AD5 DISP_BIT_IB05
+#define DISP_BITMASK_AD4 DISP_BIT_IB04
+#define DISP_BITMASK_AD3 DISP_BIT_IB03
+#define DISP_BITMASK_AD2 DISP_BIT_IB02
+#define DISP_BITMASK_AD1 DISP_BIT_IB01
+#define DISP_BITMASK_AD0 DISP_BIT_IB00
+/* DISP_RAM_ADDR_SET_2_ADDR RAM Address Set (2) */
+#define DISP_BITMASK_AD16 DISP_BIT_IB08
+#define DISP_BITMASK_AD15 DISP_BIT_IB07
+#define DISP_BITMASK_AD14 DISP_BIT_IB06
+#define DISP_BITMASK_AD13 DISP_BIT_IB05
+#define DISP_BITMASK_AD12 DISP_BIT_IB04
+#define DISP_BITMASK_AD11 DISP_BIT_IB03
+#define DISP_BITMASK_AD10 DISP_BIT_IB02
+#define DISP_BITMASK_AD9 DISP_BIT_IB01
+#define DISP_BITMASK_AD8 DISP_BIT_IB00
+/*
+ * DISP_CMD_RAMWR RAM Data Read/Write
+ * Use Data Bit Configuration
+ */
+/* DISP_RAM_DATA_MASK_1_ADDR RAM Write Data Mask (1) */
+#define DISP_BITMASK_WM11 DISP_BIT_IB13
+#define DISP_BITMASK_WM10 DISP_BIT_IB12
+#define DISP_BITMASK_WM9 DISP_BIT_IB11
+#define DISP_BITMASK_WM8 DISP_BIT_IB10
+#define DISP_BITMASK_WM7 DISP_BIT_IB09
+#define DISP_BITMASK_WM6 DISP_BIT_IB08
+#define DISP_BITMASK_WM5 DISP_BIT_IB05
+#define DISP_BITMASK_WM4 DISP_BIT_IB04
+#define DISP_BITMASK_WM3 DISP_BIT_IB03
+#define DISP_BITMASK_WM2 DISP_BIT_IB02
+#define DISP_BITMASK_WM1 DISP_BIT_IB01
+#define DISP_BITMASK_WM0 DISP_BIT_IB00
+/* DISP_RAM_DATA_MASK_2_ADDR RAM Write Data Mask (2) */
+#define DISP_BITMASK_WM17 DISP_BIT_IB05
+#define DISP_BITMASK_WM16 DISP_BIT_IB04
+#define DISP_BITMASK_WM15 DISP_BIT_IB03
+#define DISP_BITMASK_WM14 DISP_BIT_IB02
+#define DISP_BITMASK_WM13 DISP_BIT_IB01
+#define DISP_BITMASK_WM12 DISP_BIT_IB00
+/*Gamma Control */
+/* DISP_GAMMA_CONTROL_1_ADDR Gamma Control (1) */
+#define DISP_BITMASK_PKP12 DISP_BIT_IB10
+#define DISP_BITMASK_PKP11 DISP_BIT_IB08
+#define DISP_BITMASK_PKP10 DISP_BIT_IB09
+#define DISP_BITMASK_PKP02 DISP_BIT_IB02
+#define DISP_BITMASK_PKP01 DISP_BIT_IB01
+#define DISP_BITMASK_PKP00 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_2_ADDR Gamma Control (2) */
+#define DISP_BITMASK_PKP32 DISP_BIT_IB10
+#define DISP_BITMASK_PKP31 DISP_BIT_IB09
+#define DISP_BITMASK_PKP30 DISP_BIT_IB08
+#define DISP_BITMASK_PKP22 DISP_BIT_IB02
+#define DISP_BITMASK_PKP21 DISP_BIT_IB01
+#define DISP_BITMASK_PKP20 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_3_ADDR Gamma Control (3) */
+#define DISP_BITMASK_PKP52 DISP_BIT_IB10
+#define DISP_BITMASK_PKP51 DISP_BIT_IB09
+#define DISP_BITMASK_PKP50 DISP_BIT_IB08
+#define DISP_BITMASK_PKP42 DISP_BIT_IB02
+#define DISP_BITMASK_PKP41 DISP_BIT_IB01
+#define DISP_BITMASK_PKP40 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_4_ADDR Gamma Control (4) */
+#define DISP_BITMASK_PRP12 DISP_BIT_IB10
+#define DISP_BITMASK_PRP11 DISP_BIT_IB08
+#define DISP_BITMASK_PRP10 DISP_BIT_IB09
+#define DISP_BITMASK_PRP02 DISP_BIT_IB02
+#define DISP_BITMASK_PRP01 DISP_BIT_IB01
+#define DISP_BITMASK_PRP00 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_5_ADDR Gamma Control (5) */
+#define DISP_BITMASK_VRP14 DISP_BIT_IB12
+#define DISP_BITMASK_VRP13 DISP_BIT_IB11
+#define DISP_BITMASK_VRP12 DISP_BIT_IB10
+#define DISP_BITMASK_VRP11 DISP_BIT_IB08
+#define DISP_BITMASK_VRP10 DISP_BIT_IB09
+#define DISP_BITMASK_VRP03 DISP_BIT_IB03
+#define DISP_BITMASK_VRP02 DISP_BIT_IB02
+#define DISP_BITMASK_VRP01 DISP_BIT_IB01
+#define DISP_BITMASK_VRP00 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_6_ADDR Gamma Control (6) */
+#define DISP_BITMASK_PKN12 DISP_BIT_IB10
+#define DISP_BITMASK_PKN11 DISP_BIT_IB08
+#define DISP_BITMASK_PKN10 DISP_BIT_IB09
+#define DISP_BITMASK_PKN02 DISP_BIT_IB02
+#define DISP_BITMASK_PKN01 DISP_BIT_IB01
+#define DISP_BITMASK_PKN00 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_7_ADDR Gamma Control (7) */
+#define DISP_BITMASK_PKN32 DISP_BIT_IB10
+#define DISP_BITMASK_PKN31 DISP_BIT_IB08
+#define DISP_BITMASK_PKN30 DISP_BIT_IB09
+#define DISP_BITMASK_PKN22 DISP_BIT_IB02
+#define DISP_BITMASK_PKN21 DISP_BIT_IB01
+#define DISP_BITMASK_PKN20 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_8_ADDR Gamma Control (8) */
+#define DISP_BITMASK_PKN52 DISP_BIT_IB10
+#define DISP_BITMASK_PKN51 DISP_BIT_IB08
+#define DISP_BITMASK_PKN50 DISP_BIT_IB09
+#define DISP_BITMASK_PKN42 DISP_BIT_IB02
+#define DISP_BITMASK_PKN41 DISP_BIT_IB01
+#define DISP_BITMASK_PKN40 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_9_ADDR Gamma Control (9) */
+#define DISP_BITMASK_PRN12 DISP_BIT_IB10
+#define DISP_BITMASK_PRN11 DISP_BIT_IB08
+#define DISP_BITMASK_PRN10 DISP_BIT_IB09
+#define DISP_BITMASK_PRN02 DISP_BIT_IB02
+#define DISP_BITMASK_PRN01 DISP_BIT_IB01
+#define DISP_BITMASK_PRN00 DISP_BIT_IB00
+/* DISP_GAMMA_CONTROL_10_ADDR Gamma Control (10) */
+#define DISP_BITMASK_VRN14 DISP_BIT_IB12
+#define DISP_BITMASK_VRN13 DISP_BIT_IB11
+#define DISP_BITMASK_VRN12 DISP_BIT_IB10
+#define DISP_BITMASK_VRN11 DISP_BIT_IB08
+#define DISP_BITMASK_VRN10 DISP_BIT_IB09
+#define DISP_BITMASK_VRN03 DISP_BIT_IB03
+#define DISP_BITMASK_VRN02 DISP_BIT_IB02
+#define DISP_BITMASK_VRN01 DISP_BIT_IB01
+#define DISP_BITMASK_VRN00 DISP_BIT_IB00
+/* Coordinate Control */
+/* DISP_VERT_SCROLL_CTL_1_ADDR Vertical Scroll Control (1) */
+#define DISP_BITMASK_VL18 DISP_BIT_IB08
+#define DISP_BITMASK_VL17 DISP_BIT_IB07
+#define DISP_BITMASK_VL16 DISP_BIT_IB06
+#define DISP_BITMASK_VL15 DISP_BIT_IB05
+#define DISP_BITMASK_VL14 DISP_BIT_IB04
+#define DISP_BITMASK_VL13 DISP_BIT_IB03
+#define DISP_BITMASK_VL12 DISP_BIT_IB02
+#define DISP_BITMASK_VL11 DISP_BIT_IB01
+#define DISP_BITMASK_VL10 DISP_BIT_IB00
+/* DISP_VERT_SCROLL_CTL_2_ADDR Vertical Scroll Control (2) */
+#define DISP_BITMASK_VL28 DISP_BIT_IB08
+#define DISP_BITMASK_VL27 DISP_BIT_IB07
+#define DISP_BITMASK_VL26 DISP_BIT_IB06
+#define DISP_BITMASK_VL25 DISP_BIT_IB05
+#define DISP_BITMASK_VL24 DISP_BIT_IB04
+#define DISP_BITMASK_VL23 DISP_BIT_IB03
+#define DISP_BITMASK_VL22 DISP_BIT_IB02
+#define DISP_BITMASK_VL21 DISP_BIT_IB01
+#define DISP_BITMASK_VL20 DISP_BIT_IB00
+/* DISP_SCREEN_1_DRV_POS_1_ADDR First Screen Driving Position (1) */
+#define DISP_BITMASK_SS18 DISP_BIT_IB08
+#define DISP_BITMASK_SS17 DISP_BIT_IB07
+#define DISP_BITMASK_SS16 DISP_BIT_IB06
+#define DISP_BITMASK_SS15 DISP_BIT_IB05
+#define DISP_BITMASK_SS14 DISP_BIT_IB04
+#define DISP_BITMASK_SS13 DISP_BIT_IB03
+#define DISP_BITMASK_SS12 DISP_BIT_IB02
+#define DISP_BITMASK_SS11 DISP_BIT_IB01
+#define DISP_BITMASK_SS10 DISP_BIT_IB00
+/* DISP_SCREEN_1_DRV_POS_2_ADDR First Screen Driving Position (2) */
+#define DISP_BITMASK_SE18 DISP_BIT_IB08
+#define DISP_BITMASK_SE17 DISP_BIT_IB07
+#define DISP_BITMASK_SE16 DISP_BIT_IB06
+#define DISP_BITMASK_SE15 DISP_BIT_IB05
+#define DISP_BITMASK_SE14 DISP_BIT_IB04
+#define DISP_BITMASK_SE13 DISP_BIT_IB03
+#define DISP_BITMASK_SE12 DISP_BIT_IB02
+#define DISP_BITMASK_SE11 DISP_BIT_IB01
+#define DISP_BITMASK_SE10 DISP_BIT_IB00
+/* DISP_SCREEN_2_DRV_POS_1_ADDR Second Screen Driving Position (1) */
+#define DISP_BITMASK_SS28 DISP_BIT_IB08
+#define DISP_BITMASK_SS27 DISP_BIT_IB07
+#define DISP_BITMASK_SS26 DISP_BIT_IB06
+#define DISP_BITMASK_SS25 DISP_BIT_IB05
+#define DISP_BITMASK_SS24 DISP_BIT_IB04
+#define DISP_BITMASK_SS23 DISP_BIT_IB03
+#define DISP_BITMASK_SS22 DISP_BIT_IB02
+#define DISP_BITMASK_SS21 DISP_BIT_IB01
+#define DISP_BITMASK_SS20 DISP_BIT_IB00
+/* DISP_SCREEN_3_DRV_POS_2_ADDR Second Screen Driving Position (2) */
+#define DISP_BITMASK_SE28 DISP_BIT_IB08
+#define DISP_BITMASK_SE27 DISP_BIT_IB07
+#define DISP_BITMASK_SE26 DISP_BIT_IB06
+#define DISP_BITMASK_SE25 DISP_BIT_IB05
+#define DISP_BITMASK_SE24 DISP_BIT_IB04
+#define DISP_BITMASK_SE23 DISP_BIT_IB03
+#define DISP_BITMASK_SE22 DISP_BIT_IB02
+#define DISP_BITMASK_SE21 DISP_BIT_IB01
+#define DISP_BITMASK_SE20 DISP_BIT_IB00
+/* DISP_HORZ_RAM_ADDR_POS_1_ADDR Horizontal RAM Address Position (1) */
+#define DISP_BITMASK_HSA7 DISP_BIT_IB07
+#define DISP_BITMASK_HSA6 DISP_BIT_IB06
+#define DISP_BITMASK_HSA5 DISP_BIT_IB05
+#define DISP_BITMASK_HSA4 DISP_BIT_IB04
+#define DISP_BITMASK_HSA3 DISP_BIT_IB03
+#define DISP_BITMASK_HSA2 DISP_BIT_IB02
+#define DISP_BITMASK_HSA1 DISP_BIT_IB01
+#define DISP_BITMASK_HSA0 DISP_BIT_IB00
+/* DISP_HORZ_RAM_ADDR_POS_2_ADDR Horizontal RAM Address Position (2) */
+#define DISP_BITMASK_HEA7 DISP_BIT_IB07
+#define DISP_BITMASK_HEA6 DISP_BIT_IB06
+#define DISP_BITMASK_HEA5 DISP_BIT_IB05
+#define DISP_BITMASK_HEA4 DISP_BIT_IB04
+#define DISP_BITMASK_HEA3 DISP_BIT_IB03
+#define DISP_BITMASK_HEA2 DISP_BIT_IB02
+#define DISP_BITMASK_HEA1 DISP_BIT_IB01
+#define DISP_BITMASK_HEA0 DISP_BIT_IB00
+/* DISP_VERT_RAM_ADDR_POS_1_ADDR Vertical RAM Address Position (1) */
+#define DISP_BITMASK_VSA8 DISP_BIT_IB08
+#define DISP_BITMASK_VSA7 DISP_BIT_IB07
+#define DISP_BITMASK_VSA6 DISP_BIT_IB06
+#define DISP_BITMASK_VSA5 DISP_BIT_IB05
+#define DISP_BITMASK_VSA4 DISP_BIT_IB04
+#define DISP_BITMASK_VSA3 DISP_BIT_IB03
+#define DISP_BITMASK_VSA2 DISP_BIT_IB02
+#define DISP_BITMASK_VSA1 DISP_BIT_IB01
+#define DISP_BITMASK_VSA0 DISP_BIT_IB00
+/* DISP_VERT_RAM_ADDR_POS_2_ADDR Vertical RAM Address Position (2) */
+#define DISP_BITMASK_VEA8 DISP_BIT_IB08
+#define DISP_BITMASK_VEA7 DISP_BIT_IB07
+#define DISP_BITMASK_VEA6 DISP_BIT_IB06
+#define DISP_BITMASK_VEA5 DISP_BIT_IB05
+#define DISP_BITMASK_VEA4 DISP_BIT_IB04
+#define DISP_BITMASK_VEA3 DISP_BIT_IB03
+#define DISP_BITMASK_VEA2 DISP_BIT_IB02
+#define DISP_BITMASK_VEA1 DISP_BIT_IB01
+#define DISP_BITMASK_VEA0 DISP_BIT_IB00
+static word disp_area_start_row;
+static word disp_area_end_row;
+static boolean disp_initialized = FALSE;
+/* For some reason the contrast set at init time is not good. Need to do
+* it again
+*/
+static boolean display_on = FALSE;
+
+static uint32 tmd20qvga_lcd_rev;
+uint16 tmd20qvga_panel_offset;
+
+#ifdef DISP_DEVICE_8BPP
+static word convert_8_to_16_tbl[256] = {
+ 0x0000, 0x2000, 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000,
+ 0x0100, 0x2100, 0x4100, 0x6100, 0x8100, 0xA100, 0xC100, 0xE100,
+ 0x0200, 0x2200, 0x4200, 0x6200, 0x8200, 0xA200, 0xC200, 0xE200,
+ 0x0300, 0x2300, 0x4300, 0x6300, 0x8300, 0xA300, 0xC300, 0xE300,
+ 0x0400, 0x2400, 0x4400, 0x6400, 0x8400, 0xA400, 0xC400, 0xE400,
+ 0x0500, 0x2500, 0x4500, 0x6500, 0x8500, 0xA500, 0xC500, 0xE500,
+ 0x0600, 0x2600, 0x4600, 0x6600, 0x8600, 0xA600, 0xC600, 0xE600,
+ 0x0700, 0x2700, 0x4700, 0x6700, 0x8700, 0xA700, 0xC700, 0xE700,
+ 0x0008, 0x2008, 0x4008, 0x6008, 0x8008, 0xA008, 0xC008, 0xE008,
+ 0x0108, 0x2108, 0x4108, 0x6108, 0x8108, 0xA108, 0xC108, 0xE108,
+ 0x0208, 0x2208, 0x4208, 0x6208, 0x8208, 0xA208, 0xC208, 0xE208,
+ 0x0308, 0x2308, 0x4308, 0x6308, 0x8308, 0xA308, 0xC308, 0xE308,
+ 0x0408, 0x2408, 0x4408, 0x6408, 0x8408, 0xA408, 0xC408, 0xE408,
+ 0x0508, 0x2508, 0x4508, 0x6508, 0x8508, 0xA508, 0xC508, 0xE508,
+ 0x0608, 0x2608, 0x4608, 0x6608, 0x8608, 0xA608, 0xC608, 0xE608,
+ 0x0708, 0x2708, 0x4708, 0x6708, 0x8708, 0xA708, 0xC708, 0xE708,
+ 0x0010, 0x2010, 0x4010, 0x6010, 0x8010, 0xA010, 0xC010, 0xE010,
+ 0x0110, 0x2110, 0x4110, 0x6110, 0x8110, 0xA110, 0xC110, 0xE110,
+ 0x0210, 0x2210, 0x4210, 0x6210, 0x8210, 0xA210, 0xC210, 0xE210,
+ 0x0310, 0x2310, 0x4310, 0x6310, 0x8310, 0xA310, 0xC310, 0xE310,
+ 0x0410, 0x2410, 0x4410, 0x6410, 0x8410, 0xA410, 0xC410, 0xE410,
+ 0x0510, 0x2510, 0x4510, 0x6510, 0x8510, 0xA510, 0xC510, 0xE510,
+ 0x0610, 0x2610, 0x4610, 0x6610, 0x8610, 0xA610, 0xC610, 0xE610,
+ 0x0710, 0x2710, 0x4710, 0x6710, 0x8710, 0xA710, 0xC710, 0xE710,
+ 0x0018, 0x2018, 0x4018, 0x6018, 0x8018, 0xA018, 0xC018, 0xE018,
+ 0x0118, 0x2118, 0x4118, 0x6118, 0x8118, 0xA118, 0xC118, 0xE118,
+ 0x0218, 0x2218, 0x4218, 0x6218, 0x8218, 0xA218, 0xC218, 0xE218,
+ 0x0318, 0x2318, 0x4318, 0x6318, 0x8318, 0xA318, 0xC318, 0xE318,
+ 0x0418, 0x2418, 0x4418, 0x6418, 0x8418, 0xA418, 0xC418, 0xE418,
+ 0x0518, 0x2518, 0x4518, 0x6518, 0x8518, 0xA518, 0xC518, 0xE518,
+ 0x0618, 0x2618, 0x4618, 0x6618, 0x8618, 0xA618, 0xC618, 0xE618,
+ 0x0718, 0x2718, 0x4718, 0x6718, 0x8718, 0xA718, 0xC718, 0xE718
+};
+#endif /* DISP_DEVICE_8BPP */
+
+static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres);
+static void tmd20qvga_disp_init(struct platform_device *pdev);
+static void tmd20qvga_disp_set_contrast(void);
+static void tmd20qvga_disp_set_display_area(word start_row, word end_row);
+static int tmd20qvga_disp_off(struct platform_device *pdev);
+static int tmd20qvga_disp_on(struct platform_device *pdev);
+static void tmd20qvga_set_revId(int);
+
+/* future use */
+void tmd20qvga_disp_clear_screen_area(word start_row, word end_row,
+ word start_column, word end_column);
+
+static void tmd20qvga_set_revId(int id)
+{
+
+ tmd20qvga_lcd_rev = id;
+
+ if (tmd20qvga_lcd_rev == 1)
+ tmd20qvga_panel_offset = 0x10;
+ else
+ tmd20qvga_panel_offset = 0;
+}
+
+static void tmd20qvga_disp_init(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ if (disp_initialized)
+ return;
+
+ mfd = platform_get_drvdata(pdev);
+
+ DISP_CMD_PORT = mfd->cmd_port;
+ DISP_DATA_PORT = mfd->data_port;
+
+#ifdef TMD20QVGA_LCD_18BPP
+ tmd20qvga_set_revId(2);
+#else
+ tmd20qvga_set_revId(1);
+#endif
+
+ disp_initialized = TRUE;
+ tmd20qvga_disp_set_contrast();
+ tmd20qvga_disp_set_display_area(0, QVGA_HEIGHT - 1);
+}
+
+static void tmd20qvga_disp_set_rect(int x, int y, int xres, int yres)
+{
+ if (!disp_initialized)
+ return;
+
+ DISP_SET_RECT(y, y + yres - 1, x, x + xres - 1);
+
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+}
+
+static void tmd20qvga_disp_set_display_area(word start_row, word end_row)
+{
+ word start_driving = start_row;
+ word end_driving = end_row;
+
+ if (!disp_initialized)
+ return;
+
+ /* Range checking
+ */
+ if (end_driving >= QVGA_HEIGHT)
+ end_driving = QVGA_HEIGHT - 1;
+ if (start_driving > end_driving) {
+ /* Probably Backwards Switch */
+ start_driving = end_driving;
+ end_driving = start_row; /* Has not changed */
+ if (end_driving >= QVGA_HEIGHT)
+ end_driving = QVGA_HEIGHT - 1;
+ }
+
+ if ((start_driving == disp_area_start_row)
+ && (end_driving == disp_area_end_row))
+ return;
+
+ disp_area_start_row = start_driving;
+ disp_area_end_row = end_driving;
+
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR,
+ DISP_VAL_IF(start_driving & 0x100,
+ DISP_BITMASK_SS18) |
+ DISP_VAL_IF(start_driving & 0x080,
+ DISP_BITMASK_SS17) |
+ DISP_VAL_IF(start_driving & 0x040,
+ DISP_BITMASK_SS16) |
+ DISP_VAL_IF(start_driving & 0x020,
+ DISP_BITMASK_SS15) |
+ DISP_VAL_IF(start_driving & 0x010,
+ DISP_BITMASK_SS14) |
+ DISP_VAL_IF(start_driving & 0x008,
+ DISP_BITMASK_SS13) |
+ DISP_VAL_IF(start_driving & 0x004,
+ DISP_BITMASK_SS12) |
+ DISP_VAL_IF(start_driving & 0x002,
+ DISP_BITMASK_SS11) |
+ DISP_VAL_IF(start_driving & 0x001, DISP_BITMASK_SS10));
+
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR,
+ DISP_VAL_IF(end_driving & 0x100, DISP_BITMASK_SE18) |
+ DISP_VAL_IF(end_driving & 0x080, DISP_BITMASK_SE17) |
+ DISP_VAL_IF(end_driving & 0x040, DISP_BITMASK_SE16) |
+ DISP_VAL_IF(end_driving & 0x020, DISP_BITMASK_SE15) |
+ DISP_VAL_IF(end_driving & 0x010, DISP_BITMASK_SE14) |
+ DISP_VAL_IF(end_driving & 0x008, DISP_BITMASK_SE13) |
+ DISP_VAL_IF(end_driving & 0x004, DISP_BITMASK_SE12) |
+ DISP_VAL_IF(end_driving & 0x002, DISP_BITMASK_SE11) |
+ DISP_VAL_IF(end_driving & 0x001, DISP_BITMASK_SE10));
+}
+
+static int tmd20qvga_disp_off(struct platform_device *pdev)
+{
+ if (!disp_initialized)
+ tmd20qvga_disp_init(pdev);
+
+ if (display_on) {
+ if (tmd20qvga_lcd_rev == 2) {
+ DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000A);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFEE);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xF812);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xE811);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC011);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x4011);
+ WAIT_MSEC(20);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0010);
+
+ } else {
+ DISP_WRITE_OUT(DISP_POFF_LN_SETTING_ADDR, 0x000F);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFE);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BED);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(40);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x00CD);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(20);
+ DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0);
+ }
+
+ DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0004);
+ DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0000);
+
+ display_on = FALSE;
+ }
+
+ return 0;
+}
+
+static int tmd20qvga_disp_on(struct platform_device *pdev)
+{
+ if (!disp_initialized)
+ tmd20qvga_disp_init(pdev);
+
+ if (!display_on) {
+ /* Deep Stand-by -> Stand-by */
+ DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR);
+ WAIT_MSEC(1);
+ DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR);
+ WAIT_MSEC(1);
+ DISP_CMD_OUT(DISP_START_OSCILLATION_ADDR);
+ WAIT_MSEC(1);
+
+ /* OFF -> Deep Stan-By -> Stand-by */
+ /* let's change the state from "Stand-by" to "Sleep" */
+ DISP_WRITE_OUT(DISP_MODE_SETTING_ADDR, 0x0005);
+ WAIT_MSEC(1);
+
+ /* Sleep -> Displaying */
+ DISP_WRITE_OUT(DISP_START_OSCILLATION_ADDR, 0x0001);
+ DISP_WRITE_OUT(DISP_DRIVER_OUTPUT_CTL_ADDR, 0x0127);
+ DISP_WRITE_OUT(DISP_LCD_DRIVING_SIG_ADDR, 0x200);
+ /* fast write mode */
+ DISP_WRITE_OUT(DISP_ENTRY_MODE_ADDR, 0x0130);
+ if (tmd20qvga_lcd_rev == 2)
+ DISP_WRITE_OUT(DISP_TMD_700_ADDR, 0x0003);
+ /* back porch = 14 + front porch = 2 --> 16 lines */
+ if (tmd20qvga_lcd_rev == 2) {
+#ifdef TMD20QVGA_LCD_18BPP
+ /* 256k color */
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0000);
+#else
+ /* 65k color */
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4000);
+#endif
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x0302);
+ } else {
+#ifdef TMD20QVGA_LCD_18BPP
+ /* 256k color */
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x0004);
+#else
+ /* 65k color */
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_1_ADDR, 0x4004);
+#endif
+ DISP_WRITE_OUT(DISP_DISPLAY_CTL_2_ADDR, 0x020E);
+ }
+ /* 16 bit one transfer */
+ if (tmd20qvga_lcd_rev == 2) {
+ DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0302);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0102);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_TMD_015_ADDR, 0x2000);
+
+ DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0304);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0101);
+ DISP_WRITE_OUT(DISP_TMD_305_ADDR, 0);
+
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x077D);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0005);
+ DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0015);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xC010);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x0001);
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0xFFFE);
+ WAIT_MSEC(60);
+ } else {
+ DISP_WRITE_OUT(DISP_EXT_DISPLAY_CTL_1_ADDR, 0x0001);
+ DISP_WRITE_OUT(DISP_FRAME_CYCLE_CTL_ADDR, 0x0010);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_1_ADDR, 0x0301);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_2_ADDR, 0x0001);
+ DISP_WRITE_OUT(DISP_LTPS_CTL_3_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_AMP_SETTING_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0507);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0405);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0607);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0502);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0301);
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_1_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_SCREEN_1_DRV_POS_2_ADDR, 0x013F);
+ DISP_WRITE_OUT(DISP_POWER_CTL_3_ADDR, 0x0795);
+
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0102);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_4_ADDR, 0x0450);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0103);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_5_ADDR, 0x0008);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0104);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_6_ADDR, 0x0C00);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0105);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_7_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0106);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0801);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(1);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x001F);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101);
+ WAIT_MSEC(60);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_2_ADDR, 0x009F);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0101);
+ WAIT_MSEC(10);
+
+ DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_1_ADDR, 0x0010);
+ DISP_WRITE_OUT(DISP_HORZ_RAM_ADDR_POS_2_ADDR, 0x00FF);
+ DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_1_ADDR, 0x0000);
+ DISP_WRITE_OUT(DISP_VERT_RAM_ADDR_POS_2_ADDR, 0x013F);
+ /* RAM starts at address 0x10 */
+ DISP_WRITE_OUT(DISP_RAM_ADDR_SET_1_ADDR, 0x0010);
+ DISP_WRITE_OUT(DISP_RAM_ADDR_SET_2_ADDR, 0x0000);
+
+ /* lcd controller uses internal clock, not ext. vsync */
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0881);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(40);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BE1);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ WAIT_MSEC(40);
+
+ DISP_WRITE_OUT(DISP_POWER_CTL_1_ADDR, 0x0BFF);
+ DISP_WRITE_OUT(DISP_POWER_SUPPLY_INTF_ADDR, 0x0100);
+ }
+ display_on = TRUE;
+ }
+
+ return 0;
+}
+
+static void tmd20qvga_disp_set_contrast(void)
+{
+#if (defined(TMD20QVGA_LCD_18BPP))
+
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR, 0x0302);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR, 0x0403);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07);
+
+#else
+ int newcontrast = 0x46;
+
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_1_ADDR, 0x0403);
+
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_2_ADDR,
+ DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP20) |
+ DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP21) |
+ DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP22) |
+ DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP30) |
+ DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP31) |
+ DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP32));
+
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_3_ADDR,
+ DISP_VAL_IF(newcontrast & 0x0010, DISP_BITMASK_PKP40) |
+ DISP_VAL_IF(newcontrast & 0x0020, DISP_BITMASK_PKP41) |
+ DISP_VAL_IF(newcontrast & 0x0040, DISP_BITMASK_PKP42) |
+ DISP_VAL_IF(newcontrast & 0x0001, DISP_BITMASK_PKP50) |
+ DISP_VAL_IF(newcontrast & 0x0002, DISP_BITMASK_PKP51) |
+ DISP_VAL_IF(newcontrast & 0x0004, DISP_BITMASK_PKP52));
+
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_4_ADDR, 0x0303);
+ DISP_WRITE_OUT(DISP_GAMMA_CONTROL_5_ADDR, 0x0F07);
+
+#endif /* defined(TMD20QVGA_LCD_18BPP) */
+
+} /* End disp_set_contrast */
+
+void tmd20qvga_disp_clear_screen_area
+ (word start_row, word end_row, word start_column, word end_column) {
+ int32 i;
+
+ /* Clear the display screen */
+ DISP_SET_RECT(start_row, end_row, start_column, end_column);
+ DISP_CMD_OUT(DISP_CMD_RAMWR);
+ i = (end_row - start_row + 1) * (end_column - start_column + 1);
+ for (; i > 0; i--)
+ DISP_DATA_OUT_16TO18BPP(0x0);
+}
+
+static int __init tmd20qvga_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = tmd20qvga_probe,
+ .driver = {
+ .name = "ebi2_tmd_qvga",
+ },
+};
+
+static struct msm_fb_panel_data tmd20qvga_panel_data = {
+ .on = tmd20qvga_disp_on,
+ .off = tmd20qvga_disp_off,
+ .set_rect = tmd20qvga_disp_set_rect,
+};
+
+static struct platform_device this_device = {
+ .name = "ebi2_tmd_qvga",
+ .id = 0,
+ .dev = {
+ .platform_data = &tmd20qvga_panel_data,
+ }
+};
+
+static int __init tmd20qvga_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &tmd20qvga_panel_data.panel_info;
+ pinfo->xres = 240;
+ pinfo->yres = 320;
+ pinfo->type = EBI2_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0x808000;
+#ifdef TMD20QVGA_LCD_18BPP
+ pinfo->bpp = 18;
+#else
+ pinfo->bpp = 16;
+#endif
+ pinfo->fb_num = 2;
+ pinfo->lcd.vsync_enable = TRUE;
+ pinfo->lcd.refx100 = 6000;
+ pinfo->lcd.v_back_porch = 16;
+ pinfo->lcd.v_front_porch = 4;
+ pinfo->lcd.v_pulse_width = 0;
+ pinfo->lcd.hw_vsync_mode = FALSE;
+ pinfo->lcd.vsync_notifier_period = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(tmd20qvga_init);
diff --git a/drivers/staging/msm/hdmi_sii9022.c b/drivers/staging/msm/hdmi_sii9022.c
new file mode 100644
index 000000000000..6b82b56a77b6
--- /dev/null
+++ b/drivers/staging/msm/hdmi_sii9022.c
@@ -0,0 +1,248 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include "msm_fb.h"
+
+#define DEVICE_NAME "sii9022"
+#define SII9022_DEVICE_ID 0xB0
+
+struct sii9022_i2c_addr_data{
+ u8 addr;
+ u8 data;
+};
+
+/* video mode data */
+static u8 video_mode_data[] = {
+ 0x00,
+ 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
+};
+
+static u8 avi_io_format[] = {
+ 0x09,
+ 0x00, 0x00,
+};
+
+/* power state */
+static struct sii9022_i2c_addr_data regset0[] = {
+ { 0x60, 0x04 },
+ { 0x63, 0x00 },
+ { 0x1E, 0x00 },
+};
+
+static u8 video_infoframe[] = {
+ 0x0C,
+ 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
+ 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
+};
+
+/* configure audio */
+static struct sii9022_i2c_addr_data regset1[] = {
+ { 0x26, 0x90 },
+ { 0x20, 0x90 },
+ { 0x1F, 0x80 },
+ { 0x26, 0x80 },
+ { 0x24, 0x02 },
+ { 0x25, 0x0B },
+ { 0xBC, 0x02 },
+ { 0xBD, 0x24 },
+ { 0xBE, 0x02 },
+};
+
+/* enable audio */
+static u8 misc_infoframe[] = {
+ 0xBF,
+ 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* set HDMI, active */
+static struct sii9022_i2c_addr_data regset2[] = {
+ { 0x1A, 0x01 },
+ { 0x3D, 0x00 },
+};
+
+static int send_i2c_data(struct i2c_client *client,
+ struct sii9022_i2c_addr_data *regset,
+ int size)
+{
+ int i;
+ int rc = 0;
+
+ for (i = 0; i < size; i++) {
+ rc = i2c_smbus_write_byte_data(
+ client,
+ regset[i].addr, regset[i].data);
+ if (rc)
+ break;
+ }
+ return rc;
+}
+
+static int hdmi_sii_enable(struct i2c_client *client)
+{
+ int rc;
+ int retries = 10;
+ int count;
+
+ rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
+ if (rc)
+ goto enable_exit;
+
+ do {
+ msleep(1);
+ rc = i2c_smbus_read_byte_data(client, 0x1B);
+ } while ((rc != SII9022_DEVICE_ID) && retries--);
+
+ if (rc != SII9022_DEVICE_ID)
+ return -ENODEV;
+
+ rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(video_mode_data);
+ rc = i2c_master_send(client, video_mode_data, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
+ if (rc)
+ goto enable_exit;
+ count = ARRAY_SIZE(avi_io_format);
+ rc = i2c_master_send(client, avi_io_format, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(video_infoframe);
+ rc = i2c_master_send(client, video_infoframe, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(misc_infoframe);
+ rc = i2c_master_send(client, misc_infoframe, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
+ if (rc)
+ goto enable_exit;
+
+ return 0;
+enable_exit:
+ printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
+ return rc;
+}
+
+static const struct i2c_device_id hmdi_sii_id[] = {
+ { DEVICE_NAME, 0 },
+ { }
+};
+
+static int hdmi_sii_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+ rc = hdmi_sii_enable(client);
+ return rc;
+}
+
+
+static struct i2c_driver hdmi_sii_i2c_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hdmi_sii_probe,
+ .remove = __exit_p(hdmi_sii_remove),
+ .id_table = hmdi_sii_id,
+};
+
+static int __init hdmi_sii_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+ if (msm_fb_detect_client("hdmi_sii9022"))
+ return 0;
+
+ pinfo.xres = 1280;
+ pinfo.yres = 720;
+ pinfo.type = HDMI_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 74250000;
+
+ pinfo.lcdc.h_back_porch = 124;
+ pinfo.lcdc.h_front_porch = 110;
+ pinfo.lcdc.h_pulse_width = 136;
+ pinfo.lcdc.v_back_porch = 19;
+ pinfo.lcdc.v_front_porch = 5;
+ pinfo.lcdc.v_pulse_width = 6;
+ pinfo.lcdc.border_clr = 0;
+ pinfo.lcdc.underflow_clr = 0xff;
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device\n", __func__);
+ goto init_exit;
+ }
+
+ ret = i2c_add_driver(&hdmi_sii_i2c_driver);
+ if (ret)
+ printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
+
+init_exit:
+ return ret;
+}
+
+static void __exit hdmi_sii_exit(void)
+{
+ i2c_del_driver(&hdmi_sii_i2c_driver);
+}
+
+module_init(hdmi_sii_init);
+module_exit(hdmi_sii_exit);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION("0.1");
+MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
+MODULE_DESCRIPTION("SiI9022 HDMI driver");
+MODULE_ALIAS("platform:hdmi-sii9022");
diff --git a/drivers/staging/msm/lcdc.c b/drivers/staging/msm/lcdc.c
new file mode 100644
index 000000000000..735280ab72cb
--- /dev/null
+++ b/drivers/staging/msm/lcdc.c
@@ -0,0 +1,239 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos_params.h>
+
+#include "msm_fb.h"
+
+static int lcdc_probe(struct platform_device *pdev);
+static int lcdc_remove(struct platform_device *pdev);
+
+static int lcdc_off(struct platform_device *pdev);
+static int lcdc_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static struct clk *mdp_lcdc_pclk_clk;
+static struct clk *mdp_lcdc_pad_pclk_clk;
+
+int mdp_lcdc_pclk_clk_rate;
+int mdp_lcdc_pad_pclk_clk_rate;
+
+static struct platform_driver lcdc_driver = {
+ .probe = lcdc_probe,
+ .remove = lcdc_remove,
+ .suspend = NULL,
+ .resume = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "lcdc",
+ },
+};
+
+static struct lcdc_platform_data *lcdc_pdata;
+
+static int lcdc_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ ret = panel_next_off(pdev);
+
+ clk_disable(mdp_lcdc_pclk_clk);
+ clk_disable(mdp_lcdc_pad_pclk_clk);
+
+ if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
+ lcdc_pdata->lcdc_power_save(0);
+
+ if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
+ ret = lcdc_pdata->lcdc_gpio_config(0);
+
+// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
+// PM_QOS_DEFAULT_VALUE);
+
+ return ret;
+}
+
+static int lcdc_on(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+ unsigned long panel_pixclock_freq , pm_qos_freq;
+
+ mfd = platform_get_drvdata(pdev);
+ panel_pixclock_freq = mfd->fbi->var.pixclock;
+
+ if (panel_pixclock_freq > 58000000)
+ /* pm_qos_freq should be in Khz */
+ pm_qos_freq = panel_pixclock_freq / 1000 ;
+ else
+ pm_qos_freq = 58000;
+
+// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
+// pm_qos_freq);
+ mfd = platform_get_drvdata(pdev);
+
+ clk_enable(mdp_lcdc_pclk_clk);
+ clk_enable(mdp_lcdc_pad_pclk_clk);
+
+ if (lcdc_pdata && lcdc_pdata->lcdc_power_save)
+ lcdc_pdata->lcdc_power_save(1);
+ if (lcdc_pdata && lcdc_pdata->lcdc_gpio_config)
+ ret = lcdc_pdata->lcdc_gpio_config(1);
+
+ clk_set_rate(mdp_lcdc_pclk_clk, mfd->fbi->var.pixclock);
+ clk_set_rate(mdp_lcdc_pad_pclk_clk, mfd->fbi->var.pixclock);
+ mdp_lcdc_pclk_clk_rate = clk_get_rate(mdp_lcdc_pclk_clk);
+ mdp_lcdc_pad_pclk_clk_rate = clk_get_rate(mdp_lcdc_pad_pclk_clk);
+
+ ret = panel_next_on(pdev);
+ return ret;
+}
+
+static int lcdc_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct fb_info *fbi;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+
+ if (pdev->id == 0) {
+ lcdc_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /*
+ * link to the latest pdev
+ */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_LCDC;
+
+ /*
+ * alloc panel device data
+ */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "lcdc_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+ /*
+ * data chain
+ */
+ pdata = (struct msm_fb_panel_data *)mdp_dev->dev.platform_data;
+ pdata->on = lcdc_on;
+ pdata->off = lcdc_off;
+ pdata->next = pdev;
+
+ /*
+ * get/set panel specific fb info
+ */
+ mfd->panel_info = pdata->panel_info;
+ mfd->fb_imgType = MDP_RGB_565;
+
+ fbi = mfd->fbi;
+ fbi->var.pixclock = mfd->panel_info.clk_rate;
+ fbi->var.left_margin = mfd->panel_info.lcdc.h_back_porch;
+ fbi->var.right_margin = mfd->panel_info.lcdc.h_front_porch;
+ fbi->var.upper_margin = mfd->panel_info.lcdc.v_back_porch;
+ fbi->var.lower_margin = mfd->panel_info.lcdc.v_front_porch;
+ fbi->var.hsync_len = mfd->panel_info.lcdc.h_pulse_width;
+ fbi->var.vsync_len = mfd->panel_info.lcdc.v_pulse_width;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc)
+ goto lcdc_probe_err;
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+
+lcdc_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int lcdc_remove(struct platform_device *pdev)
+{
+// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc");
+ return 0;
+}
+
+static int lcdc_register_driver(void)
+{
+ return platform_driver_register(&lcdc_driver);
+}
+
+static int __init lcdc_driver_init(void)
+{
+ mdp_lcdc_pclk_clk = clk_get(NULL, "mdp_lcdc_pclk_clk");
+ if (IS_ERR(mdp_lcdc_pclk_clk)) {
+ printk(KERN_ERR "error: can't get mdp_lcdc_pclk_clk!\n");
+ return IS_ERR(mdp_lcdc_pclk_clk);
+ }
+ mdp_lcdc_pad_pclk_clk = clk_get(NULL, "mdp_lcdc_pad_pclk_clk");
+ if (IS_ERR(mdp_lcdc_pad_pclk_clk)) {
+ printk(KERN_ERR "error: can't get mdp_lcdc_pad_pclk_clk!\n");
+ return IS_ERR(mdp_lcdc_pad_pclk_clk);
+ }
+// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "lcdc",
+// PM_QOS_DEFAULT_VALUE);
+ return lcdc_register_driver();
+}
+
+module_init(lcdc_driver_init);
diff --git a/drivers/staging/msm/lcdc_external.c b/drivers/staging/msm/lcdc_external.c
new file mode 100644
index 000000000000..45ff78527111
--- /dev/null
+++ b/drivers/staging/msm/lcdc_external.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+static int __init lcdc_external_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+ if (msm_fb_detect_client("lcdc_external"))
+ return 0;
+
+ pinfo.xres = 1280;
+ pinfo.yres = 720;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 74250000;
+
+ pinfo.lcdc.h_back_porch = 124;
+ pinfo.lcdc.h_front_porch = 110;
+ pinfo.lcdc.h_pulse_width = 136;
+ pinfo.lcdc.v_back_porch = 19;
+ pinfo.lcdc.v_front_porch = 5;
+ pinfo.lcdc.v_pulse_width = 6;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(lcdc_external_init);
diff --git a/drivers/staging/msm/lcdc_gordon.c b/drivers/staging/msm/lcdc_gordon.c
new file mode 100644
index 000000000000..399ec8c791ec
--- /dev/null
+++ b/drivers/staging/msm/lcdc_gordon.c
@@ -0,0 +1,446 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <mach/gpio.h>
+#include "msm_fb.h"
+
+/* registers */
+#define GORDON_REG_NOP 0x00
+#define GORDON_REG_IMGCTL1 0x10
+#define GORDON_REG_IMGCTL2 0x11
+#define GORDON_REG_IMGSET1 0x12
+#define GORDON_REG_IMGSET2 0x13
+#define GORDON_REG_IVBP1 0x14
+#define GORDON_REG_IHBP1 0x15
+#define GORDON_REG_IVNUM1 0x16
+#define GORDON_REG_IHNUM1 0x17
+#define GORDON_REG_IVBP2 0x18
+#define GORDON_REG_IHBP2 0x19
+#define GORDON_REG_IVNUM2 0x1A
+#define GORDON_REG_IHNUM2 0x1B
+#define GORDON_REG_LCDIFCTL1 0x30
+#define GORDON_REG_VALTRAN 0x31
+#define GORDON_REG_AVCTL 0x33
+#define GORDON_REG_LCDIFCTL2 0x34
+#define GORDON_REG_LCDIFCTL3 0x35
+#define GORDON_REG_LCDIFSET1 0x36
+#define GORDON_REG_PCCTL 0x3C
+#define GORDON_REG_TPARAM1 0x40
+#define GORDON_REG_TLCDIF1 0x41
+#define GORDON_REG_TSSPB_ST1 0x42
+#define GORDON_REG_TSSPB_ED1 0x43
+#define GORDON_REG_TSCK_ST1 0x44
+#define GORDON_REG_TSCK_WD1 0x45
+#define GORDON_REG_TGSPB_VST1 0x46
+#define GORDON_REG_TGSPB_VED1 0x47
+#define GORDON_REG_TGSPB_CH1 0x48
+#define GORDON_REG_TGCK_ST1 0x49
+#define GORDON_REG_TGCK_ED1 0x4A
+#define GORDON_REG_TPCTL_ST1 0x4B
+#define GORDON_REG_TPCTL_ED1 0x4C
+#define GORDON_REG_TPCHG_ED1 0x4D
+#define GORDON_REG_TCOM_CH1 0x4E
+#define GORDON_REG_THBP1 0x4F
+#define GORDON_REG_TPHCTL1 0x50
+#define GORDON_REG_EVPH1 0x51
+#define GORDON_REG_EVPL1 0x52
+#define GORDON_REG_EVNH1 0x53
+#define GORDON_REG_EVNL1 0x54
+#define GORDON_REG_TBIAS1 0x55
+#define GORDON_REG_TPARAM2 0x56
+#define GORDON_REG_TLCDIF2 0x57
+#define GORDON_REG_TSSPB_ST2 0x58
+#define GORDON_REG_TSSPB_ED2 0x59
+#define GORDON_REG_TSCK_ST2 0x5A
+#define GORDON_REG_TSCK_WD2 0x5B
+#define GORDON_REG_TGSPB_VST2 0x5C
+#define GORDON_REG_TGSPB_VED2 0x5D
+#define GORDON_REG_TGSPB_CH2 0x5E
+#define GORDON_REG_TGCK_ST2 0x5F
+#define GORDON_REG_TGCK_ED2 0x60
+#define GORDON_REG_TPCTL_ST2 0x61
+#define GORDON_REG_TPCTL_ED2 0x62
+#define GORDON_REG_TPCHG_ED2 0x63
+#define GORDON_REG_TCOM_CH2 0x64
+#define GORDON_REG_THBP2 0x65
+#define GORDON_REG_TPHCTL2 0x66
+#define GORDON_REG_POWCTL 0x80
+
+static int lcdc_gordon_panel_off(struct platform_device *pdev);
+
+static int spi_cs;
+static int spi_sclk;
+static int spi_sdo;
+static int spi_sdi;
+static int spi_dac;
+static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
+ (1 << 6),
+ (1 << 5),
+ (1 << 4),
+ (1 << 3),
+ (1 << 2),
+ (1 << 1),
+ (1 << 0) /* LSB */
+};
+
+struct gordon_state_type{
+ boolean disp_initialized;
+ boolean display_on;
+ boolean disp_powered_up;
+};
+
+static struct gordon_state_type gordon_state = { 0 };
+static struct msm_panel_common_pdata *lcdc_gordon_pdata;
+
+static void serigo(uint16 reg, uint8 data)
+{
+ unsigned int tx_val = ((0x00FF & reg) << 8) | data;
+ unsigned char i, val = 0;
+
+ /* Enable the Chip Select */
+ gpio_set_value(spi_cs, 1);
+ udelay(33);
+
+ /* Transmit it in two parts, Higher Byte first, then Lower Byte */
+ val = (unsigned char)((tx_val & 0xFF00) >> 8);
+
+ /* Clock should be Low before entering ! */
+ for (i = 0; i < 8; i++) {
+ /* #1: Drive the Data (High or Low) */
+ if (val & bit_shift[i])
+ gpio_set_value(spi_sdi, 1);
+ else
+ gpio_set_value(spi_sdi, 0);
+
+ /* #2: Drive the Clk High and then Low */
+ udelay(33);
+ gpio_set_value(spi_sclk, 1);
+ udelay(33);
+ gpio_set_value(spi_sclk, 0);
+ }
+
+ /* Idle state of SDO (MOSI) is Low */
+ gpio_set_value(spi_sdi, 0);
+ /* ..then Lower Byte */
+ val = (uint8) (tx_val & 0x00FF);
+ /* Before we enter here the Clock should be Low ! */
+
+ for (i = 0; i < 8; i++) {
+ /* #1: Drive the Data (High or Low) */
+ if (val & bit_shift[i])
+ gpio_set_value(spi_sdi, 1);
+ else
+ gpio_set_value(spi_sdi, 0);
+
+ /* #2: Drive the Clk High and then Low */
+ udelay(33);
+
+ gpio_set_value(spi_sclk, 1);
+ udelay(33);
+ gpio_set_value(spi_sclk, 0);
+ }
+
+ /* Idle state of SDO (MOSI) is Low */
+ gpio_set_value(spi_sdi, 0);
+
+ /* Now Disable the Chip Select */
+ udelay(33);
+ gpio_set_value(spi_cs, 0);
+}
+
+static void spi_init(void)
+{
+ /* Setting the Default GPIO's */
+ spi_sclk = *(lcdc_gordon_pdata->gpio_num);
+ spi_cs = *(lcdc_gordon_pdata->gpio_num + 1);
+ spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2);
+ spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3);
+
+ /* Set the output so that we dont disturb the slave device */
+ gpio_set_value(spi_sclk, 0);
+ gpio_set_value(spi_sdi, 0);
+
+ /* Set the Chip Select De-asserted */
+ gpio_set_value(spi_cs, 0);
+
+}
+
+static void gordon_disp_powerup(void)
+{
+ if (!gordon_state.disp_powered_up && !gordon_state.display_on) {
+ /* Reset the hardware first */
+ /* Include DAC power up implementation here */
+ gordon_state.disp_powered_up = TRUE;
+ }
+}
+
+static void gordon_init(void)
+{
+ /* Image interface settings */
+ serigo(GORDON_REG_IMGCTL2, 0x00);
+ serigo(GORDON_REG_IMGSET1, 0x00);
+
+ /* Exchange the RGB signal for J510(Softbank mobile) */
+ serigo(GORDON_REG_IMGSET2, 0x12);
+ serigo(GORDON_REG_LCDIFSET1, 0x00);
+
+ /* Pre-charge settings */
+ serigo(GORDON_REG_PCCTL, 0x09);
+ serigo(GORDON_REG_LCDIFCTL2, 0x7B);
+
+ mdelay(1);
+}
+
+static void gordon_disp_on(void)
+{
+ if (gordon_state.disp_powered_up && !gordon_state.display_on) {
+ gordon_init();
+ mdelay(20);
+ /* gordon_dispmode setting */
+ serigo(GORDON_REG_TPARAM1, 0x30);
+ serigo(GORDON_REG_TLCDIF1, 0x00);
+ serigo(GORDON_REG_TSSPB_ST1, 0x8B);
+ serigo(GORDON_REG_TSSPB_ED1, 0x93);
+ serigo(GORDON_REG_TSCK_ST1, 0x88);
+ serigo(GORDON_REG_TSCK_WD1, 0x00);
+ serigo(GORDON_REG_TGSPB_VST1, 0x01);
+ serigo(GORDON_REG_TGSPB_VED1, 0x02);
+ serigo(GORDON_REG_TGSPB_CH1, 0x5E);
+ serigo(GORDON_REG_TGCK_ST1, 0x80);
+ serigo(GORDON_REG_TGCK_ED1, 0x3C);
+ serigo(GORDON_REG_TPCTL_ST1, 0x50);
+ serigo(GORDON_REG_TPCTL_ED1, 0x74);
+ serigo(GORDON_REG_TPCHG_ED1, 0x78);
+ serigo(GORDON_REG_TCOM_CH1, 0x50);
+ serigo(GORDON_REG_THBP1, 0x84);
+ serigo(GORDON_REG_TPHCTL1, 0x00);
+ serigo(GORDON_REG_EVPH1, 0x70);
+ serigo(GORDON_REG_EVPL1, 0x64);
+ serigo(GORDON_REG_EVNH1, 0x56);
+ serigo(GORDON_REG_EVNL1, 0x48);
+ serigo(GORDON_REG_TBIAS1, 0x88);
+
+ /* QVGA settings */
+ serigo(GORDON_REG_TPARAM2, 0x28);
+ serigo(GORDON_REG_TLCDIF2, 0x14);
+ serigo(GORDON_REG_TSSPB_ST2, 0x49);
+ serigo(GORDON_REG_TSSPB_ED2, 0x4B);
+ serigo(GORDON_REG_TSCK_ST2, 0x4A);
+ serigo(GORDON_REG_TSCK_WD2, 0x02);
+ serigo(GORDON_REG_TGSPB_VST2, 0x02);
+ serigo(GORDON_REG_TGSPB_VED2, 0x03);
+ serigo(GORDON_REG_TGSPB_CH2, 0x2F);
+ serigo(GORDON_REG_TGCK_ST2, 0x40);
+ serigo(GORDON_REG_TGCK_ED2, 0x1E);
+ serigo(GORDON_REG_TPCTL_ST2, 0x2C);
+ serigo(GORDON_REG_TPCTL_ED2, 0x3A);
+ serigo(GORDON_REG_TPCHG_ED2, 0x3C);
+ serigo(GORDON_REG_TCOM_CH2, 0x28);
+ serigo(GORDON_REG_THBP2, 0x4D);
+ serigo(GORDON_REG_TPHCTL2, 0x1A);
+
+ /* VGA settings */
+ serigo(GORDON_REG_IVBP1, 0x02);
+ serigo(GORDON_REG_IHBP1, 0x90);
+ serigo(GORDON_REG_IVNUM1, 0xA0);
+ serigo(GORDON_REG_IHNUM1, 0x78);
+
+ /* QVGA settings */
+ serigo(GORDON_REG_IVBP2, 0x02);
+ serigo(GORDON_REG_IHBP2, 0x48);
+ serigo(GORDON_REG_IVNUM2, 0x50);
+ serigo(GORDON_REG_IHNUM2, 0x3C);
+
+ /* Gordon Charge pump settings and ON */
+ serigo(GORDON_REG_POWCTL, 0x03);
+ mdelay(15);
+ serigo(GORDON_REG_POWCTL, 0x07);
+ mdelay(15);
+
+ serigo(GORDON_REG_POWCTL, 0x0F);
+ mdelay(15);
+
+ serigo(GORDON_REG_AVCTL, 0x03);
+ mdelay(15);
+
+ serigo(GORDON_REG_POWCTL, 0x1F);
+ mdelay(15);
+
+ serigo(GORDON_REG_POWCTL, 0x5F);
+ mdelay(15);
+
+ serigo(GORDON_REG_POWCTL, 0x7F);
+ mdelay(15);
+
+ serigo(GORDON_REG_LCDIFCTL1, 0x02);
+ mdelay(15);
+
+ serigo(GORDON_REG_IMGCTL1, 0x00);
+ mdelay(15);
+
+ serigo(GORDON_REG_LCDIFCTL3, 0x00);
+ mdelay(15);
+
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ mdelay(15);
+
+ serigo(GORDON_REG_LCDIFCTL1, 0x03);
+ mdelay(1);
+ gordon_state.display_on = TRUE;
+ }
+}
+
+static int lcdc_gordon_panel_on(struct platform_device *pdev)
+{
+ if (!gordon_state.disp_initialized) {
+ /* Configure reset GPIO that drives DAC */
+ lcdc_gordon_pdata->panel_config_gpio(1);
+ spi_dac = *(lcdc_gordon_pdata->gpio_num + 4);
+ gpio_set_value(spi_dac, 0);
+ udelay(15);
+ gpio_set_value(spi_dac, 1);
+ spi_init(); /* LCD needs SPI */
+ gordon_disp_powerup();
+ gordon_disp_on();
+ gordon_state.disp_initialized = TRUE;
+ }
+ return 0;
+}
+
+static int lcdc_gordon_panel_off(struct platform_device *pdev)
+{
+ if (gordon_state.disp_powered_up && gordon_state.display_on) {
+ serigo(GORDON_REG_LCDIFCTL2, 0x7B);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ serigo(GORDON_REG_LCDIFCTL1, 0x02);
+ serigo(GORDON_REG_LCDIFCTL3, 0x01);
+ mdelay(20);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ serigo(GORDON_REG_IMGCTL1, 0x01);
+ serigo(GORDON_REG_LCDIFCTL1, 0x00);
+ mdelay(20);
+
+ serigo(GORDON_REG_POWCTL, 0x1F);
+ mdelay(40);
+
+ serigo(GORDON_REG_POWCTL, 0x07);
+ mdelay(40);
+
+ serigo(GORDON_REG_POWCTL, 0x03);
+ mdelay(40);
+
+ serigo(GORDON_REG_POWCTL, 0x00);
+ mdelay(40);
+ lcdc_gordon_pdata->panel_config_gpio(0);
+ gordon_state.display_on = FALSE;
+ gordon_state.disp_initialized = FALSE;
+ }
+ return 0;
+}
+
+static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd)
+{
+ int bl_level = mfd->bl_level;
+
+ if (bl_level <= 1) {
+ /* keep back light OFF */
+ serigo(GORDON_REG_LCDIFCTL2, 0x0B);
+ udelay(15);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ } else {
+ /* keep back light ON */
+ serigo(GORDON_REG_LCDIFCTL2, 0x7B);
+ udelay(15);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ }
+}
+
+static int __init gordon_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ lcdc_gordon_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+ msm_fb_add_device(pdev);
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = gordon_probe,
+ .driver = {
+ .name = "lcdc_gordon_vga",
+ },
+};
+
+static struct msm_fb_panel_data gordon_panel_data = {
+ .on = lcdc_gordon_panel_on,
+ .off = lcdc_gordon_panel_off,
+ .set_backlight = lcdc_gordon_set_backlight,
+};
+
+static struct platform_device this_device = {
+ .name = "lcdc_gordon_vga",
+ .id = 1,
+ .dev = {
+ .platform_data = &gordon_panel_data,
+ }
+};
+
+static int __init lcdc_gordon_panel_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+ if (msm_fb_detect_client("lcdc_gordon_vga"))
+ return 0;
+#endif
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ return ret;
+
+ pinfo = &gordon_panel_data.panel_info;
+ pinfo->xres = 480;
+ pinfo->yres = 640;
+ pinfo->type = LCDC_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 24;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 24500000;
+ pinfo->bl_max = 4;
+ pinfo->bl_min = 1;
+
+ pinfo->lcdc.h_back_porch = 84;
+ pinfo->lcdc.h_front_porch = 33;
+ pinfo->lcdc.h_pulse_width = 60;
+ pinfo->lcdc.v_back_porch = 0;
+ pinfo->lcdc.v_front_porch = 2;
+ pinfo->lcdc.v_pulse_width = 2;
+ pinfo->lcdc.border_clr = 0; /* blk */
+ pinfo->lcdc.underflow_clr = 0xff; /* blue */
+ pinfo->lcdc.hsync_skew = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ return ret;
+}
+
+module_init(lcdc_gordon_panel_init);
diff --git a/drivers/staging/msm/lcdc_grapefruit.c b/drivers/staging/msm/lcdc_grapefruit.c
new file mode 100644
index 000000000000..7284649ea0ae
--- /dev/null
+++ b/drivers/staging/msm/lcdc_grapefruit.c
@@ -0,0 +1,60 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+#include "mddihosti.h"
+#endif
+
+static int __init lcdc_grapefruit_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+ if (msm_fb_detect_client("lcdc_grapefruit_vga"))
+ return 0;
+#endif
+
+ pinfo.xres = 1024;
+ pinfo.yres = 600;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 40000000;
+
+ pinfo.lcdc.h_back_porch = 88;
+ pinfo.lcdc.h_front_porch = 40;
+ pinfo.lcdc.h_pulse_width = 128;
+ pinfo.lcdc.v_back_porch = 23;
+ pinfo.lcdc.v_front_porch = 1;
+ pinfo.lcdc.v_pulse_width = 4;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(lcdc_grapefruit_init);
diff --git a/drivers/staging/msm/lcdc_panel.c b/drivers/staging/msm/lcdc_panel.c
new file mode 100644
index 000000000000..b40974e1f27c
--- /dev/null
+++ b/drivers/staging/msm/lcdc_panel.c
@@ -0,0 +1,88 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+static int lcdc_panel_on(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int lcdc_panel_off(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __init lcdc_panel_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = lcdc_panel_probe,
+ .driver = {
+ .name = "lcdc_panel",
+ },
+};
+
+static struct msm_fb_panel_data lcdc_panel_data = {
+ .on = lcdc_panel_on,
+ .off = lcdc_panel_off,
+};
+
+static int lcdc_dev_id;
+
+int lcdc_device_register(struct msm_panel_info *pinfo)
+{
+ struct platform_device *pdev = NULL;
+ int ret;
+
+ pdev = platform_device_alloc("lcdc_panel", ++lcdc_dev_id);
+ if (!pdev)
+ return -ENOMEM;
+
+ lcdc_panel_data.panel_info = *pinfo;
+ ret = platform_device_add_data(pdev, &lcdc_panel_data,
+ sizeof(lcdc_panel_data));
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_add_data failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_register failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ return 0;
+
+err_device_put:
+ platform_device_put(pdev);
+ return ret;
+}
+
+static int __init lcdc_panel_init(void)
+{
+ return platform_driver_register(&this_driver);
+}
+
+module_init(lcdc_panel_init);
diff --git a/drivers/staging/msm/lcdc_prism.c b/drivers/staging/msm/lcdc_prism.c
new file mode 100644
index 000000000000..d102c98447c1
--- /dev/null
+++ b/drivers/staging/msm/lcdc_prism.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+#include "mddihosti.h"
+#endif
+
+static int __init lcdc_prism_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+ ret = msm_fb_detect_client("lcdc_prism_wvga");
+ if (ret == -ENODEV)
+ return 0;
+
+ if (ret && (mddi_get_client_id() != 0))
+ return 0;
+#endif
+
+ pinfo.xres = 800;
+ pinfo.yres = 480;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 38460000;
+
+ pinfo.lcdc.h_back_porch = 21;
+ pinfo.lcdc.h_front_porch = 81;
+ pinfo.lcdc.h_pulse_width = 60;
+ pinfo.lcdc.v_back_porch = 18;
+ pinfo.lcdc.v_front_porch = 27;
+ pinfo.lcdc.v_pulse_width = 2;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(lcdc_prism_init);
diff --git a/drivers/staging/msm/lcdc_sharp_wvga_pt.c b/drivers/staging/msm/lcdc_sharp_wvga_pt.c
new file mode 100644
index 000000000000..1f08cf9bc217
--- /dev/null
+++ b/drivers/staging/msm/lcdc_sharp_wvga_pt.c
@@ -0,0 +1,290 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#ifdef CONFIG_ARCH_MSM7X30
+#include <linux/mfd/pmic8058.h>
+#endif
+#include <mach/gpio.h>
+#include "msm_fb.h"
+
+static int lcdc_sharp_panel_off(struct platform_device *pdev);
+
+static int spi_cs;
+static int spi_sclk;
+static int spi_mosi;
+static int spi_miso;
+static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
+ (1 << 6),
+ (1 << 5),
+ (1 << 4),
+ (1 << 3),
+ (1 << 2),
+ (1 << 1),
+ (1 << 0) /* LSB */
+};
+
+struct sharp_state_type {
+ boolean disp_initialized;
+ boolean display_on;
+ boolean disp_powered_up;
+};
+
+struct sharp_spi_data {
+ u8 addr;
+ u8 data;
+};
+
+static struct sharp_spi_data init_sequence[] = {
+ { 15, 0x01 },
+ { 5, 0x01 },
+ { 7, 0x10 },
+ { 9, 0x1E },
+ { 10, 0x04 },
+ { 17, 0xFF },
+ { 21, 0x8A },
+ { 22, 0x00 },
+ { 23, 0x82 },
+ { 24, 0x24 },
+ { 25, 0x22 },
+ { 26, 0x6D },
+ { 27, 0xEB },
+ { 28, 0xB9 },
+ { 29, 0x3A },
+ { 49, 0x1A },
+ { 50, 0x16 },
+ { 51, 0x05 },
+ { 55, 0x7F },
+ { 56, 0x15 },
+ { 57, 0x7B },
+ { 60, 0x05 },
+ { 61, 0x0C },
+ { 62, 0x80 },
+ { 63, 0x00 },
+ { 92, 0x90 },
+ { 97, 0x01 },
+ { 98, 0xFF },
+ { 113, 0x11 },
+ { 114, 0x02 },
+ { 115, 0x08 },
+ { 123, 0xAB },
+ { 124, 0x04 },
+ { 6, 0x02 },
+ { 133, 0x00 },
+ { 134, 0xFE },
+ { 135, 0x22 },
+ { 136, 0x0B },
+ { 137, 0xFF },
+ { 138, 0x0F },
+ { 139, 0x00 },
+ { 140, 0xFE },
+ { 141, 0x22 },
+ { 142, 0x0B },
+ { 143, 0xFF },
+ { 144, 0x0F },
+ { 145, 0x00 },
+ { 146, 0xFE },
+ { 147, 0x22 },
+ { 148, 0x0B },
+ { 149, 0xFF },
+ { 150, 0x0F },
+ { 202, 0x30 },
+ { 30, 0x01 },
+ { 4, 0x01 },
+ { 31, 0x41 },
+};
+
+static struct sharp_state_type sharp_state = { 0 };
+static struct msm_panel_common_pdata *lcdc_sharp_pdata;
+
+static void sharp_spi_write_byte(u8 val)
+{
+ int i;
+
+ /* Clock should be Low before entering */
+ for (i = 0; i < 8; i++) {
+ /* #1: Drive the Data (High or Low) */
+ if (val & bit_shift[i])
+ gpio_set_value(spi_mosi, 1);
+ else
+ gpio_set_value(spi_mosi, 0);
+
+ /* #2: Drive the Clk High and then Low */
+ gpio_set_value(spi_sclk, 1);
+ gpio_set_value(spi_sclk, 0);
+ }
+}
+
+static void serigo(u8 reg, u8 data)
+{
+ /* Enable the Chip Select - low */
+ gpio_set_value(spi_cs, 0);
+ udelay(1);
+
+ /* Transmit register address first, then data */
+ sharp_spi_write_byte(reg);
+
+ /* Idle state of MOSI is Low */
+ gpio_set_value(spi_mosi, 0);
+ udelay(1);
+ sharp_spi_write_byte(data);
+
+ gpio_set_value(spi_mosi, 0);
+ gpio_set_value(spi_cs, 1);
+}
+
+static void sharp_spi_init(void)
+{
+ spi_sclk = *(lcdc_sharp_pdata->gpio_num);
+ spi_cs = *(lcdc_sharp_pdata->gpio_num + 1);
+ spi_mosi = *(lcdc_sharp_pdata->gpio_num + 2);
+ spi_miso = *(lcdc_sharp_pdata->gpio_num + 3);
+
+ /* Set the output so that we don't disturb the slave device */
+ gpio_set_value(spi_sclk, 0);
+ gpio_set_value(spi_mosi, 0);
+
+ /* Set the Chip Select deasserted (active low) */
+ gpio_set_value(spi_cs, 1);
+}
+
+static void sharp_disp_powerup(void)
+{
+ if (!sharp_state.disp_powered_up && !sharp_state.display_on)
+ sharp_state.disp_powered_up = TRUE;
+}
+
+static void sharp_disp_on(void)
+{
+ int i;
+
+ if (sharp_state.disp_powered_up && !sharp_state.display_on) {
+ for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
+ serigo(init_sequence[i].addr,
+ init_sequence[i].data);
+ }
+ mdelay(10);
+ serigo(31, 0xC1);
+ mdelay(10);
+ serigo(31, 0xD9);
+ serigo(31, 0xDF);
+
+ sharp_state.display_on = TRUE;
+ }
+}
+
+static int lcdc_sharp_panel_on(struct platform_device *pdev)
+{
+ if (!sharp_state.disp_initialized) {
+ lcdc_sharp_pdata->panel_config_gpio(1);
+ sharp_spi_init();
+ sharp_disp_powerup();
+ sharp_disp_on();
+ sharp_state.disp_initialized = TRUE;
+ }
+ return 0;
+}
+
+static int lcdc_sharp_panel_off(struct platform_device *pdev)
+{
+ if (sharp_state.disp_powered_up && sharp_state.display_on) {
+ serigo(4, 0x00);
+ mdelay(40);
+ serigo(31, 0xC1);
+ mdelay(40);
+ serigo(31, 0x00);
+ mdelay(100);
+ sharp_state.display_on = FALSE;
+ sharp_state.disp_initialized = FALSE;
+ }
+ return 0;
+}
+
+static int __init sharp_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ lcdc_sharp_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+ msm_fb_add_device(pdev);
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = sharp_probe,
+ .driver = {
+ .name = "lcdc_sharp_wvga",
+ },
+};
+
+static struct msm_fb_panel_data sharp_panel_data = {
+ .on = lcdc_sharp_panel_on,
+ .off = lcdc_sharp_panel_off,
+};
+
+static struct platform_device this_device = {
+ .name = "lcdc_sharp_wvga",
+ .id = 1,
+ .dev = {
+ .platform_data = &sharp_panel_data,
+ }
+};
+
+static int __init lcdc_sharp_panel_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ if (msm_fb_detect_client("lcdc_sharp_wvga_pt"))
+ return 0;
+#endif
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ return ret;
+
+ pinfo = &sharp_panel_data.panel_info;
+ pinfo->xres = 480;
+ pinfo->yres = 800;
+ pinfo->type = LCDC_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 18;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 24500000;
+ pinfo->bl_max = 4;
+ pinfo->bl_min = 1;
+
+ pinfo->lcdc.h_back_porch = 20;
+ pinfo->lcdc.h_front_porch = 10;
+ pinfo->lcdc.h_pulse_width = 10;
+ pinfo->lcdc.v_back_porch = 2;
+ pinfo->lcdc.v_front_porch = 2;
+ pinfo->lcdc.v_pulse_width = 2;
+ pinfo->lcdc.border_clr = 0;
+ pinfo->lcdc.underflow_clr = 0xff;
+ pinfo->lcdc.hsync_skew = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ return ret;
+}
+
+module_init(lcdc_sharp_panel_init);
diff --git a/drivers/staging/msm/lcdc_st15.c b/drivers/staging/msm/lcdc_st15.c
new file mode 100644
index 000000000000..fed8278eb153
--- /dev/null
+++ b/drivers/staging/msm/lcdc_st15.c
@@ -0,0 +1,237 @@
+/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include "msm_fb.h"
+
+#define DEVICE_NAME "sii9022"
+#define SII9022_DEVICE_ID 0xB0
+
+struct sii9022_i2c_addr_data{
+ u8 addr;
+ u8 data;
+};
+
+/* video mode data */
+static u8 video_mode_data[] = {
+ 0x00,
+ 0xF9, 0x1C, 0x70, 0x17, 0x72, 0x06, 0xEE, 0x02,
+};
+
+static u8 avi_io_format[] = {
+ 0x09,
+ 0x00, 0x00,
+};
+
+/* power state */
+static struct sii9022_i2c_addr_data regset0[] = {
+ { 0x60, 0x04 },
+ { 0x63, 0x00 },
+ { 0x1E, 0x00 },
+};
+
+static u8 video_infoframe[] = {
+ 0x0C,
+ 0xF0, 0x00, 0x68, 0x00, 0x04, 0x00, 0x19, 0x00,
+ 0xE9, 0x02, 0x04, 0x01, 0x04, 0x06,
+};
+
+/* configure audio */
+static struct sii9022_i2c_addr_data regset1[] = {
+ { 0x26, 0x90 },
+ { 0x20, 0x90 },
+ { 0x1F, 0x80 },
+ { 0x26, 0x80 },
+ { 0x24, 0x02 },
+ { 0x25, 0x0B },
+ { 0xBC, 0x02 },
+ { 0xBD, 0x24 },
+ { 0xBE, 0x02 },
+};
+
+/* enable audio */
+static u8 misc_infoframe[] = {
+ 0xBF,
+ 0xC2, 0x84, 0x01, 0x0A, 0x6F, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+/* set HDMI, active */
+static struct sii9022_i2c_addr_data regset2[] = {
+ { 0x1A, 0x01 },
+ { 0x3D, 0x00 },
+};
+
+static int send_i2c_data(struct i2c_client *client,
+ struct sii9022_i2c_addr_data *regset,
+ int size)
+{
+ int i;
+ int rc = 0;
+
+ for (i = 0; i < size; i++) {
+ rc = i2c_smbus_write_byte_data(
+ client,
+ regset[i].addr, regset[i].data);
+ if (rc)
+ break;
+ }
+ return rc;
+}
+
+static int hdmi_sii_enable(struct i2c_client *client)
+{
+ int rc;
+ int retries = 10;
+ int count;
+
+ rc = i2c_smbus_write_byte_data(client, 0xC7, 0x00);
+ if (rc)
+ goto enable_exit;
+
+ do {
+ msleep(1);
+ rc = i2c_smbus_read_byte_data(client, 0x1B);
+ } while ((rc != SII9022_DEVICE_ID) && retries--);
+
+ if (rc != SII9022_DEVICE_ID)
+ return -ENODEV;
+
+ rc = i2c_smbus_write_byte_data(client, 0x1A, 0x11);
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(video_mode_data);
+ rc = i2c_master_send(client, video_mode_data, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = i2c_smbus_write_byte_data(client, 0x08, 0x20);
+ if (rc)
+ goto enable_exit;
+ count = ARRAY_SIZE(avi_io_format);
+ rc = i2c_master_send(client, avi_io_format, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset0, ARRAY_SIZE(regset0));
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(video_infoframe);
+ rc = i2c_master_send(client, video_infoframe, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset1, ARRAY_SIZE(regset1));
+ if (rc)
+ goto enable_exit;
+
+ count = ARRAY_SIZE(misc_infoframe);
+ rc = i2c_master_send(client, misc_infoframe, count);
+ if (rc != count) {
+ rc = -EIO;
+ goto enable_exit;
+ }
+
+ rc = send_i2c_data(client, regset2, ARRAY_SIZE(regset2));
+ if (rc)
+ goto enable_exit;
+
+ return 0;
+enable_exit:
+ printk(KERN_ERR "%s: exited rc=%d\n", __func__, rc);
+ return rc;
+}
+
+static const struct i2c_device_id hmdi_sii_id[] = {
+ { DEVICE_NAME, 0 },
+ { }
+};
+
+static int hdmi_sii_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int rc;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE | I2C_FUNC_I2C))
+ return -ENODEV;
+ rc = hdmi_sii_enable(client);
+ return rc;
+}
+
+
+static struct i2c_driver hdmi_sii_i2c_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = hdmi_sii_probe,
+ .remove = __exit_p(hdmi_sii_remove),
+ .id_table = hmdi_sii_id,
+};
+
+static int __init lcdc_st15_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+ if (msm_fb_detect_client("lcdc_st15"))
+ return 0;
+
+ pinfo.xres = 1366;
+ pinfo.yres = 768;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 74250000;
+
+ pinfo.lcdc.h_back_porch = 120;
+ pinfo.lcdc.h_front_porch = 20;
+ pinfo.lcdc.h_pulse_width = 40;
+ pinfo.lcdc.v_back_porch = 25;
+ pinfo.lcdc.v_front_porch = 1;
+ pinfo.lcdc.v_pulse_width = 7;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+ goto init_exit;
+ }
+
+ ret = i2c_add_driver(&hdmi_sii_i2c_driver);
+ if (ret)
+ printk(KERN_ERR "%s: failed to add i2c driver\n", __func__);
+
+init_exit:
+ return ret;
+}
+
+module_init(lcdc_st15_init);
diff --git a/drivers/staging/msm/lcdc_st1_wxga.c b/drivers/staging/msm/lcdc_st1_wxga.c
new file mode 100644
index 000000000000..73760019cf2e
--- /dev/null
+++ b/drivers/staging/msm/lcdc_st1_wxga.c
@@ -0,0 +1,54 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+static int __init lcdc_st1_wxga_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+ if (msm_fb_detect_client("lcdc_st1_wxga"))
+ return 0;
+
+ pinfo.xres = 1280;
+ pinfo.yres = 720;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 74250000;
+
+ pinfo.lcdc.h_back_porch = 124;
+ pinfo.lcdc.h_front_porch = 110;
+ pinfo.lcdc.h_pulse_width = 136;
+ pinfo.lcdc.v_back_porch = 19;
+ pinfo.lcdc.v_front_porch = 5;
+ pinfo.lcdc.v_pulse_width = 6;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(lcdc_st1_wxga_init);
diff --git a/drivers/staging/msm/lcdc_toshiba_wvga_pt.c b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c
new file mode 100644
index 000000000000..864d7c18913d
--- /dev/null
+++ b/drivers/staging/msm/lcdc_toshiba_wvga_pt.c
@@ -0,0 +1,374 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <mach/gpio.h>
+#include <mach/pmic.h>
+#include "msm_fb.h"
+
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+#include "mddihosti.h"
+#endif
+
+static int spi_cs;
+static int spi_sclk;
+static int spi_mosi;
+static int spi_miso;
+
+struct toshiba_state_type{
+ boolean disp_initialized;
+ boolean display_on;
+ boolean disp_powered_up;
+};
+
+static struct toshiba_state_type toshiba_state = { 0 };
+static struct msm_panel_common_pdata *lcdc_toshiba_pdata;
+
+static void toshiba_spi_write_byte(char dc, uint8 data)
+{
+ uint32 bit;
+ int bnum;
+
+ gpio_set_value(spi_sclk, 0); /* clk low */
+ /* dc: 0 for command, 1 for parameter */
+ gpio_set_value(spi_mosi, dc);
+ udelay(1); /* at least 20 ns */
+ gpio_set_value(spi_sclk, 1); /* clk high */
+ udelay(1); /* at least 20 ns */
+ bnum = 8; /* 8 data bits */
+ bit = 0x80;
+ while (bnum) {
+ gpio_set_value(spi_sclk, 0); /* clk low */
+ if (data & bit)
+ gpio_set_value(spi_mosi, 1);
+ else
+ gpio_set_value(spi_mosi, 0);
+ udelay(1);
+ gpio_set_value(spi_sclk, 1); /* clk high */
+ udelay(1);
+ bit >>= 1;
+ bnum--;
+ }
+}
+
+static void toshiba_spi_write(char cmd, uint32 data, int num)
+{
+ char *bp;
+
+ gpio_set_value(spi_cs, 1); /* cs high */
+
+ /* command byte first */
+ toshiba_spi_write_byte(0, cmd);
+
+ /* followed by parameter bytes */
+ if (num) {
+ bp = (char *)&data;;
+ bp += (num - 1);
+ while (num) {
+ toshiba_spi_write_byte(1, *bp);
+ num--;
+ bp--;
+ }
+ }
+
+ gpio_set_value(spi_cs, 0); /* cs low */
+ udelay(1);
+}
+
+void toshiba_spi_read_bytes(char cmd, uint32 *data, int num)
+{
+ uint32 dbit, bits;
+ int bnum;
+
+ gpio_set_value(spi_cs, 1); /* cs high */
+
+ /* command byte first */
+ toshiba_spi_write_byte(0, cmd);
+
+ if (num > 1) {
+ /* extra dc bit */
+ gpio_set_value(spi_sclk, 0); /* clk low */
+ udelay(1);
+ dbit = gpio_get_value(spi_miso);/* dc bit */
+ udelay(1);
+ gpio_set_value(spi_sclk, 1); /* clk high */
+ }
+
+ /* followed by data bytes */
+ bnum = num * 8; /* number of bits */
+ bits = 0;
+ while (bnum) {
+ bits <<= 1;
+ gpio_set_value(spi_sclk, 0); /* clk low */
+ udelay(1);
+ dbit = gpio_get_value(spi_miso);
+ udelay(1);
+ gpio_set_value(spi_sclk, 1); /* clk high */
+ bits |= dbit;
+ bnum--;
+ }
+
+ *data = bits;
+
+ udelay(1);
+ gpio_set_value(spi_cs, 0); /* cs low */
+ udelay(1);
+}
+
+static void spi_pin_assign(void)
+{
+ /* Setting the Default GPIO's */
+ spi_sclk = *(lcdc_toshiba_pdata->gpio_num);
+ spi_cs = *(lcdc_toshiba_pdata->gpio_num + 1);
+ spi_mosi = *(lcdc_toshiba_pdata->gpio_num + 2);
+ spi_miso = *(lcdc_toshiba_pdata->gpio_num + 3);
+}
+
+static void toshiba_disp_powerup(void)
+{
+ if (!toshiba_state.disp_powered_up && !toshiba_state.display_on) {
+ /* Reset the hardware first */
+ /* Include DAC power up implementation here */
+ toshiba_state.disp_powered_up = TRUE;
+ }
+}
+
+static void toshiba_disp_on(void)
+{
+ uint32 data;
+
+ gpio_set_value(spi_cs, 0); /* low */
+ gpio_set_value(spi_sclk, 1); /* high */
+ gpio_set_value(spi_mosi, 0);
+ gpio_set_value(spi_miso, 0);
+
+ if (toshiba_state.disp_powered_up && !toshiba_state.display_on) {
+ toshiba_spi_write(0, 0, 0);
+ mdelay(7);
+ toshiba_spi_write(0, 0, 0);
+ mdelay(7);
+ toshiba_spi_write(0, 0, 0);
+ mdelay(7);
+ toshiba_spi_write(0xba, 0x11, 1);
+ toshiba_spi_write(0x36, 0x00, 1);
+ mdelay(1);
+ toshiba_spi_write(0x3a, 0x60, 1);
+ toshiba_spi_write(0xb1, 0x5d, 1);
+ mdelay(1);
+ toshiba_spi_write(0xb2, 0x33, 1);
+ toshiba_spi_write(0xb3, 0x22, 1);
+ mdelay(1);
+ toshiba_spi_write(0xb4, 0x02, 1);
+ toshiba_spi_write(0xb5, 0x1e, 1); /* vcs -- adjust brightness */
+ mdelay(1);
+ toshiba_spi_write(0xb6, 0x27, 1);
+ toshiba_spi_write(0xb7, 0x03, 1);
+ mdelay(1);
+ toshiba_spi_write(0xb9, 0x24, 1);
+ toshiba_spi_write(0xbd, 0xa1, 1);
+ mdelay(1);
+ toshiba_spi_write(0xbb, 0x00, 1);
+ toshiba_spi_write(0xbf, 0x01, 1);
+ mdelay(1);
+ toshiba_spi_write(0xbe, 0x00, 1);
+ toshiba_spi_write(0xc0, 0x11, 1);
+ mdelay(1);
+ toshiba_spi_write(0xc1, 0x11, 1);
+ toshiba_spi_write(0xc2, 0x11, 1);
+ mdelay(1);
+ toshiba_spi_write(0xc3, 0x3232, 2);
+ mdelay(1);
+ toshiba_spi_write(0xc4, 0x3232, 2);
+ mdelay(1);
+ toshiba_spi_write(0xc5, 0x3232, 2);
+ mdelay(1);
+ toshiba_spi_write(0xc6, 0x3232, 2);
+ mdelay(1);
+ toshiba_spi_write(0xc7, 0x6445, 2);
+ mdelay(1);
+ toshiba_spi_write(0xc8, 0x44, 1);
+ toshiba_spi_write(0xc9, 0x52, 1);
+ mdelay(1);
+ toshiba_spi_write(0xca, 0x00, 1);
+ mdelay(1);
+ toshiba_spi_write(0xec, 0x02a4, 2); /* 0x02a4 */
+ mdelay(1);
+ toshiba_spi_write(0xcf, 0x01, 1);
+ mdelay(1);
+ toshiba_spi_write(0xd0, 0xc003, 2); /* c003 */
+ mdelay(1);
+ toshiba_spi_write(0xd1, 0x01, 1);
+ mdelay(1);
+ toshiba_spi_write(0xd2, 0x0028, 2);
+ mdelay(1);
+ toshiba_spi_write(0xd3, 0x0028, 2);
+ mdelay(1);
+ toshiba_spi_write(0xd4, 0x26a4, 2);
+ mdelay(1);
+ toshiba_spi_write(0xd5, 0x20, 1);
+ mdelay(1);
+ toshiba_spi_write(0xef, 0x3200, 2);
+ mdelay(32);
+ toshiba_spi_write(0xbc, 0x80, 1); /* wvga pass through */
+ toshiba_spi_write(0x3b, 0x00, 1);
+ mdelay(1);
+ toshiba_spi_write(0xb0, 0x16, 1);
+ mdelay(1);
+ toshiba_spi_write(0xb8, 0xfff5, 2);
+ mdelay(1);
+ toshiba_spi_write(0x11, 0, 0);
+ mdelay(5);
+ toshiba_spi_write(0x29, 0, 0);
+ mdelay(5);
+ toshiba_state.display_on = TRUE;
+ }
+
+ data = 0;
+ toshiba_spi_read_bytes(0x04, &data, 3);
+ printk(KERN_INFO "toshiba_disp_on: id=%x\n", data);
+
+}
+
+static int lcdc_toshiba_panel_on(struct platform_device *pdev)
+{
+ if (!toshiba_state.disp_initialized) {
+ /* Configure reset GPIO that drives DAC */
+ if (lcdc_toshiba_pdata->panel_config_gpio)
+ lcdc_toshiba_pdata->panel_config_gpio(1);
+ toshiba_disp_powerup();
+ toshiba_disp_on();
+ toshiba_state.disp_initialized = TRUE;
+ }
+ return 0;
+}
+
+static int lcdc_toshiba_panel_off(struct platform_device *pdev)
+{
+ if (toshiba_state.disp_powered_up && toshiba_state.display_on) {
+ /* Main panel power off (Deep standby in) */
+
+ toshiba_spi_write(0x28, 0, 0); /* display off */
+ mdelay(1);
+ toshiba_spi_write(0xb8, 0x8002, 2); /* output control */
+ mdelay(1);
+ toshiba_spi_write(0x10, 0x00, 1); /* sleep mode in */
+ mdelay(85); /* wait 85 msec */
+ toshiba_spi_write(0xb0, 0x00, 1); /* deep standby in */
+ mdelay(1);
+ if (lcdc_toshiba_pdata->panel_config_gpio)
+ lcdc_toshiba_pdata->panel_config_gpio(0);
+ toshiba_state.display_on = FALSE;
+ toshiba_state.disp_initialized = FALSE;
+ }
+ return 0;
+}
+
+static void lcdc_toshiba_set_backlight(struct msm_fb_data_type *mfd)
+{
+ int bl_level;
+ int ret = -EPERM;
+
+ bl_level = mfd->bl_level;
+ ret = pmic_set_led_intensity(LED_LCD, bl_level);
+
+ if (ret)
+ printk(KERN_WARNING "%s: can't set lcd backlight!\n",
+ __func__);
+}
+
+static int __init toshiba_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ lcdc_toshiba_pdata = pdev->dev.platform_data;
+ spi_pin_assign();
+ return 0;
+ }
+ msm_fb_add_device(pdev);
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = toshiba_probe,
+ .driver = {
+ .name = "lcdc_toshiba_wvga",
+ },
+};
+
+static struct msm_fb_panel_data toshiba_panel_data = {
+ .on = lcdc_toshiba_panel_on,
+ .off = lcdc_toshiba_panel_off,
+ .set_backlight = lcdc_toshiba_set_backlight,
+};
+
+static struct platform_device this_device = {
+ .name = "lcdc_toshiba_wvga",
+ .id = 1,
+ .dev = {
+ .platform_data = &toshiba_panel_data,
+ }
+};
+
+static int __init lcdc_toshiba_panel_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+#ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM
+ if (mddi_get_client_id() != 0)
+ return 0;
+
+ ret = msm_fb_detect_client("lcdc_toshiba_wvga_pt");
+ if (ret)
+ return 0;
+
+#endif
+
+ ret = platform_driver_register(&this_driver);
+ if (ret)
+ return ret;
+
+ pinfo = &toshiba_panel_data.panel_info;
+ pinfo->xres = 480;
+ pinfo->yres = 800;
+ pinfo->type = LCDC_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 18;
+ pinfo->fb_num = 2;
+ /* 30Mhz mdp_lcdc_pclk and mdp_lcdc_pad_pcl */
+ pinfo->clk_rate = 27648000;
+ pinfo->bl_max = 15;
+ pinfo->bl_min = 1;
+
+ pinfo->lcdc.h_back_porch = 184; /* hsw = 8 + hbp=184 */
+ pinfo->lcdc.h_front_porch = 4;
+ pinfo->lcdc.h_pulse_width = 8;
+ pinfo->lcdc.v_back_porch = 2; /* vsw=1 + vbp = 2 */
+ pinfo->lcdc.v_front_porch = 3;
+ pinfo->lcdc.v_pulse_width = 1;
+ pinfo->lcdc.border_clr = 0; /* blk */
+ pinfo->lcdc.underflow_clr = 0xff; /* blue */
+ pinfo->lcdc.hsync_skew = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ return ret;
+}
+
+device_initcall(lcdc_toshiba_panel_init);
diff --git a/drivers/staging/msm/lcdc_wxga.c b/drivers/staging/msm/lcdc_wxga.c
new file mode 100644
index 000000000000..202c92c0ef54
--- /dev/null
+++ b/drivers/staging/msm/lcdc_wxga.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+
+static int __init lcdc_wxga_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ if (msm_fb_detect_client("lcdc_wxga"))
+ return 0;
+#endif
+
+ pinfo.xres = 1280;
+ pinfo.yres = 720;
+ pinfo.type = LCDC_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 24;
+ pinfo.fb_num = 2;
+ pinfo.clk_rate = 74250000;
+
+ pinfo.lcdc.h_back_porch = 124;
+ pinfo.lcdc.h_front_porch = 110;
+ pinfo.lcdc.h_pulse_width = 136;
+ pinfo.lcdc.v_back_porch = 19;
+ pinfo.lcdc.v_front_porch = 5;
+ pinfo.lcdc.v_pulse_width = 6;
+ pinfo.lcdc.border_clr = 0; /* blk */
+ pinfo.lcdc.underflow_clr = 0xff; /* blue */
+ pinfo.lcdc.hsync_skew = 0;
+
+ ret = lcdc_device_register(&pinfo);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(lcdc_wxga_init);
diff --git a/drivers/staging/msm/logo.c b/drivers/staging/msm/logo.c
new file mode 100644
index 000000000000..7272765f48cd
--- /dev/null
+++ b/drivers/staging/msm/logo.c
@@ -0,0 +1,98 @@
+/* drivers/video/msm/logo.c
+ *
+ * Show Logo in RLE 565 format
+ *
+ * Copyright (C) 2008 Google Incorporated
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/fb.h>
+#include <linux/vt_kern.h>
+#include <linux/unistd.h>
+#include <linux/syscalls.h>
+
+#include <linux/irq.h>
+#include <asm/system.h>
+
+#define fb_width(fb) ((fb)->var.xres)
+#define fb_height(fb) ((fb)->var.yres)
+#define fb_size(fb) ((fb)->var.xres * (fb)->var.yres * 2)
+
+static void memset16(void *_ptr, unsigned short val, unsigned count)
+{
+ unsigned short *ptr = _ptr;
+ count >>= 1;
+ while (count--)
+ *ptr++ = val;
+}
+
+/* 565RLE image format: [count(2 bytes), rle(2 bytes)] */
+int load_565rle_image(char *filename)
+{
+ struct fb_info *info;
+ int fd, err = 0;
+ unsigned count, max;
+ unsigned short *data, *bits, *ptr;
+
+ info = registered_fb[0];
+ if (!info) {
+ printk(KERN_WARNING "%s: Can not access framebuffer\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ fd = sys_open(filename, O_RDONLY, 0);
+ if (fd < 0) {
+ printk(KERN_WARNING "%s: Can not open %s\n",
+ __func__, filename);
+ return -ENOENT;
+ }
+ count = (unsigned)sys_lseek(fd, (off_t)0, 2);
+ if (count == 0) {
+ sys_close(fd);
+ err = -EIO;
+ goto err_logo_close_file;
+ }
+ sys_lseek(fd, (off_t)0, 0);
+ data = kmalloc(count, GFP_KERNEL);
+ if (!data) {
+ printk(KERN_WARNING "%s: Can not alloc data\n", __func__);
+ err = -ENOMEM;
+ goto err_logo_close_file;
+ }
+ if ((unsigned)sys_read(fd, (char *)data, count) != count) {
+ err = -EIO;
+ goto err_logo_free_data;
+ }
+
+ max = fb_width(info) * fb_height(info);
+ ptr = data;
+ bits = (unsigned short *)(info->screen_base);
+ while (count > 3) {
+ unsigned n = ptr[0];
+ if (n > max)
+ break;
+ memset16(bits, ptr[1], n << 1);
+ bits += n;
+ max -= n;
+ ptr += 2;
+ count -= 4;
+ }
+
+err_logo_free_data:
+ kfree(data);
+err_logo_close_file:
+ sys_close(fd);
+ return err;
+}
+EXPORT_SYMBOL(load_565rle_image);
diff --git a/drivers/staging/msm/mddi.c b/drivers/staging/msm/mddi.c
new file mode 100644
index 000000000000..132eb1adff16
--- /dev/null
+++ b/drivers/staging/msm/mddi.c
@@ -0,0 +1,375 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_fb.h"
+#include "mddihosti.h"
+#include "mddihost.h"
+#include <mach/gpio.h>
+#include <mach/clk.h>
+
+static int mddi_probe(struct platform_device *pdev);
+static int mddi_remove(struct platform_device *pdev);
+
+static int mddi_off(struct platform_device *pdev);
+static int mddi_on(struct platform_device *pdev);
+
+static int mddi_suspend(struct platform_device *pdev, pm_message_t state);
+static int mddi_resume(struct platform_device *pdev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mddi_early_suspend(struct early_suspend *h);
+static void mddi_early_resume(struct early_suspend *h);
+#endif
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+static struct clk *mddi_clk;
+static struct clk *mddi_pclk;
+static struct mddi_platform_data *mddi_pdata;
+
+static struct platform_driver mddi_driver = {
+ .probe = mddi_probe,
+ .remove = mddi_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
+ .suspend = mddi_suspend,
+ .resume = mddi_resume,
+#endif
+#endif
+ .suspend_late = NULL,
+ .resume_early = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "mddi",
+ },
+};
+
+extern int int_mddi_pri_flag;
+
+static int mddi_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ ret = panel_next_off(pdev);
+
+ if (mddi_pdata && mddi_pdata->mddi_power_save)
+ mddi_pdata->mddi_power_save(0);
+
+ return ret;
+}
+
+static int mddi_on(struct platform_device *pdev)
+{
+ int ret = 0;
+ u32 clk_rate;
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (mddi_pdata && mddi_pdata->mddi_power_save)
+ mddi_pdata->mddi_power_save(1);
+
+ clk_rate = mfd->fbi->var.pixclock;
+ clk_rate = min(clk_rate, mfd->panel_info.clk_max);
+
+ if (mddi_pdata &&
+ mddi_pdata->mddi_sel_clk &&
+ mddi_pdata->mddi_sel_clk(&clk_rate))
+ printk(KERN_ERR
+ "%s: can't select mddi io clk targate rate = %d\n",
+ __func__, clk_rate);
+
+ if (clk_set_min_rate(mddi_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ __func__);
+
+ ret = panel_next_on(pdev);
+
+ return ret;
+}
+
+static int mddi_resource_initialized;
+
+static int mddi_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+ resource_size_t size ;
+ u32 clk_rate;
+
+ if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
+ mddi_pdata = pdev->dev.platform_data;
+
+ size = resource_size(&pdev->resource[0]);
+ msm_pmdh_base = ioremap(pdev->resource[0].start, size);
+
+ MSM_FB_INFO("primary mddi base phy_addr = 0x%x virt = 0x%x\n",
+ pdev->resource[0].start, (int) msm_pmdh_base);
+
+ if (unlikely(!msm_pmdh_base))
+ return -ENOMEM;
+
+ if (mddi_pdata && mddi_pdata->mddi_power_save)
+ mddi_pdata->mddi_power_save(1);
+
+ mddi_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!mddi_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /*
+ * link to the latest pdev
+ */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_LCD;
+
+ /*
+ * alloc panel device data
+ */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "mddi_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+ /*
+ * data chain
+ */
+ pdata = mdp_dev->dev.platform_data;
+ pdata->on = mddi_on;
+ pdata->off = mddi_off;
+ pdata->next = pdev;
+
+ /*
+ * get/set panel specific fb info
+ */
+ mfd->panel_info = pdata->panel_info;
+ mfd->fb_imgType = MDP_RGB_565;
+
+ clk_rate = mfd->panel_info.clk_max;
+ if (mddi_pdata &&
+ mddi_pdata->mddi_sel_clk &&
+ mddi_pdata->mddi_sel_clk(&clk_rate))
+ printk(KERN_ERR
+ "%s: can't select mddi io clk targate rate = %d\n",
+ __func__, clk_rate);
+
+ if (clk_set_max_rate(mddi_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
+ mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc)
+ goto mddi_probe_err;
+
+ pdev_list[pdev_list_cnt++] = pdev;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ mfd->mddi_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ mfd->mddi_early_suspend.suspend = mddi_early_suspend;
+ mfd->mddi_early_suspend.resume = mddi_early_resume;
+ register_early_suspend(&mfd->mddi_early_suspend);
+#endif
+
+ return 0;
+
+mddi_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int mddi_pad_ctrl;
+static int mddi_power_locked;
+static int mddi_is_in_suspend;
+
+void mddi_disable(int lock)
+{
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+
+ if (mddi_power_locked)
+ return;
+
+ if (lock)
+ mddi_power_locked = 1;
+
+ if (mddi_host_timer.function)
+ del_timer_sync(&mddi_host_timer);
+
+ mddi_pad_ctrl = mddi_host_reg_in(PAD_CTL);
+ mddi_host_reg_out(PAD_CTL, 0x0);
+
+ if (clk_set_min_rate(mddi_clk, 0) < 0)
+ printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
+
+ clk_disable(mddi_clk);
+ if (mddi_pclk)
+ clk_disable(mddi_pclk);
+ disable_irq(INT_MDDI_PRI);
+
+ if (mddi_pdata && mddi_pdata->mddi_power_save)
+ mddi_pdata->mddi_power_save(0);
+}
+
+static int mddi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (mddi_is_in_suspend)
+ return 0;
+
+ mddi_is_in_suspend = 1;
+ mddi_disable(0);
+ return 0;
+}
+
+static int mddi_resume(struct platform_device *pdev)
+{
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+
+ if (!mddi_is_in_suspend)
+ return 0;
+
+ mddi_is_in_suspend = 0;
+
+ if (mddi_power_locked)
+ return 0;
+
+ enable_irq(INT_MDDI_PRI);
+ clk_enable(mddi_clk);
+ if (mddi_pclk)
+ clk_enable(mddi_pclk);
+ mddi_host_reg_out(PAD_CTL, mddi_pad_ctrl);
+
+ if (mddi_host_timer.function)
+ mddi_host_timer_service(0);
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mddi_early_suspend(struct early_suspend *h)
+{
+ pm_message_t state;
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ mddi_early_suspend);
+
+ state.event = PM_EVENT_SUSPEND;
+ mddi_suspend(mfd->pdev, state);
+}
+
+static void mddi_early_resume(struct early_suspend *h)
+{
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ mddi_early_suspend);
+ mddi_resume(mfd->pdev);
+}
+#endif
+
+static int mddi_remove(struct platform_device *pdev)
+{
+ if (mddi_host_timer.function)
+ del_timer_sync(&mddi_host_timer);
+
+ iounmap(msm_pmdh_base);
+
+ return 0;
+}
+
+static int mddi_register_driver(void)
+{
+ return platform_driver_register(&mddi_driver);
+}
+
+static int __init mddi_driver_init(void)
+{
+ int ret;
+
+ mddi_clk = clk_get(NULL, "mddi_clk");
+ if (IS_ERR(mddi_clk)) {
+ printk(KERN_ERR "can't find mddi_clk \n");
+ return PTR_ERR(mddi_clk);
+ }
+ clk_enable(mddi_clk);
+
+ mddi_pclk = clk_get(NULL, "mddi_pclk");
+ if (IS_ERR(mddi_pclk))
+ mddi_pclk = NULL;
+ else
+ clk_enable(mddi_pclk);
+
+ ret = mddi_register_driver();
+ if (ret) {
+ clk_disable(mddi_clk);
+ clk_put(mddi_clk);
+ if (mddi_pclk) {
+ clk_disable(mddi_pclk);
+ clk_put(mddi_pclk);
+ }
+ printk(KERN_ERR "mddi_register_driver() failed!\n");
+ return ret;
+ }
+
+ mddi_init();
+
+ return ret;
+}
+
+module_init(mddi_driver_init);
diff --git a/drivers/staging/msm/mddi_ext.c b/drivers/staging/msm/mddi_ext.c
new file mode 100644
index 000000000000..c0c168c7199d
--- /dev/null
+++ b/drivers/staging/msm/mddi_ext.c
@@ -0,0 +1,320 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <asm/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <linux/platform_device.h>
+
+#include "msm_fb.h"
+#include "mddihosti.h"
+
+static int mddi_ext_probe(struct platform_device *pdev);
+static int mddi_ext_remove(struct platform_device *pdev);
+
+static int mddi_ext_off(struct platform_device *pdev);
+static int mddi_ext_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state);
+static int mddi_ext_resume(struct platform_device *pdev);
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mddi_ext_early_suspend(struct early_suspend *h);
+static void mddi_ext_early_resume(struct early_suspend *h);
+#endif
+
+static struct platform_driver mddi_ext_driver = {
+ .probe = mddi_ext_probe,
+ .remove = mddi_ext_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+#ifdef CONFIG_PM
+ .suspend = mddi_ext_suspend,
+ .resume = mddi_ext_resume,
+#endif
+#endif
+ .resume_early = NULL,
+ .resume = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "mddi_ext",
+ },
+};
+
+static struct clk *mddi_ext_clk;
+static struct mddi_platform_data *mddi_ext_pdata;
+
+extern int int_mddi_ext_flag;
+
+static int mddi_ext_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ ret = panel_next_off(pdev);
+ mddi_host_stop_ext_display();
+
+ return ret;
+}
+
+static int mddi_ext_on(struct platform_device *pdev)
+{
+ int ret = 0;
+ u32 clk_rate;
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ clk_rate = mfd->fbi->var.pixclock;
+ clk_rate = min(clk_rate, mfd->panel_info.clk_max);
+
+ if (mddi_ext_pdata &&
+ mddi_ext_pdata->mddi_sel_clk &&
+ mddi_ext_pdata->mddi_sel_clk(&clk_rate))
+ printk(KERN_ERR
+ "%s: can't select mddi io clk targate rate = %d\n",
+ __func__, clk_rate);
+
+ if (clk_set_min_rate(mddi_ext_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_min_rate failed\n",
+ __func__);
+
+ mddi_host_start_ext_display();
+ ret = panel_next_on(pdev);
+
+ return ret;
+}
+
+static int mddi_ext_resource_initialized;
+
+static int mddi_ext_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+ resource_size_t size ;
+ u32 clk_rate;
+
+ if ((pdev->id == 0) && (pdev->num_resources >= 0)) {
+ mddi_ext_pdata = pdev->dev.platform_data;
+
+ size = resource_size(&pdev->resource[0]);
+ msm_emdh_base = ioremap(pdev->resource[0].start, size);
+
+ MSM_FB_INFO("external mddi base address = 0x%x\n",
+ pdev->resource[0].start);
+
+ if (unlikely(!msm_emdh_base))
+ return -ENOMEM;
+
+ mddi_ext_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!mddi_ext_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /*
+ * link to the latest pdev
+ */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_EXT_MDDI;
+
+ /*
+ * alloc panel device data
+ */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "mddi_ext_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+ /*
+ * data chain
+ */
+ pdata = mdp_dev->dev.platform_data;
+ pdata->on = mddi_ext_on;
+ pdata->off = mddi_ext_off;
+ pdata->next = pdev;
+
+ /*
+ * get/set panel specific fb info
+ */
+ mfd->panel_info = pdata->panel_info;
+ mfd->fb_imgType = MDP_RGB_565;
+
+ clk_rate = mfd->panel_info.clk_max;
+ if (mddi_ext_pdata &&
+ mddi_ext_pdata->mddi_sel_clk &&
+ mddi_ext_pdata->mddi_sel_clk(&clk_rate))
+ printk(KERN_ERR
+ "%s: can't select mddi io clk targate rate = %d\n",
+ __func__, clk_rate);
+
+ if (clk_set_max_rate(mddi_ext_clk, clk_rate) < 0)
+ printk(KERN_ERR "%s: clk_set_max_rate failed\n", __func__);
+ mfd->panel_info.clk_rate = mfd->panel_info.clk_min;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc)
+ goto mddi_ext_probe_err;
+
+ pdev_list[pdev_list_cnt++] = pdev;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ mfd->mddi_ext_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+ mfd->mddi_ext_early_suspend.suspend = mddi_ext_early_suspend;
+ mfd->mddi_ext_early_suspend.resume = mddi_ext_early_resume;
+ register_early_suspend(&mfd->mddi_ext_early_suspend);
+#endif
+
+ return 0;
+
+mddi_ext_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int mddi_ext_is_in_suspend;
+
+static int mddi_ext_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (mddi_ext_is_in_suspend)
+ return 0;
+
+ mddi_ext_is_in_suspend = 1;
+
+ if (clk_set_min_rate(mddi_ext_clk, 0) < 0)
+ printk(KERN_ERR "%s: clk_set_min_rate failed\n", __func__);
+
+ clk_disable(mddi_ext_clk);
+ disable_irq(INT_MDDI_EXT);
+
+ return 0;
+}
+
+static int mddi_ext_resume(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mddi_ext_is_in_suspend)
+ return 0;
+
+ mddi_ext_is_in_suspend = 0;
+ enable_irq(INT_MDDI_EXT);
+
+ clk_enable(mddi_ext_clk);
+
+ return 0;
+}
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mddi_ext_early_suspend(struct early_suspend *h)
+{
+ pm_message_t state;
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ mddi_ext_early_suspend);
+
+ state.event = PM_EVENT_SUSPEND;
+ mddi_ext_suspend(mfd->pdev, state);
+}
+
+static void mddi_ext_early_resume(struct early_suspend *h)
+{
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ mddi_ext_early_suspend);
+ mddi_ext_resume(mfd->pdev);
+}
+#endif
+
+static int mddi_ext_remove(struct platform_device *pdev)
+{
+ iounmap(msm_emdh_base);
+ return 0;
+}
+
+static int mddi_ext_register_driver(void)
+{
+ return platform_driver_register(&mddi_ext_driver);
+}
+
+static int __init mddi_ext_driver_init(void)
+{
+ int ret;
+
+ mddi_ext_clk = clk_get(NULL, "emdh_clk");
+ if (IS_ERR(mddi_ext_clk)) {
+ printk(KERN_ERR "can't find emdh_clk\n");
+ return PTR_ERR(mddi_ext_clk);
+ }
+ clk_enable(mddi_ext_clk);
+
+ ret = mddi_ext_register_driver();
+ if (ret) {
+ clk_disable(mddi_ext_clk);
+ clk_put(mddi_ext_clk);
+ printk(KERN_ERR "mddi_ext_register_driver() failed!\n");
+ return ret;
+ }
+ mddi_init();
+
+ return ret;
+}
+
+module_init(mddi_ext_driver_init);
diff --git a/drivers/staging/msm/mddi_ext_lcd.c b/drivers/staging/msm/mddi_ext_lcd.c
new file mode 100644
index 000000000000..502e80d17ec7
--- /dev/null
+++ b/drivers/staging/msm/mddi_ext_lcd.c
@@ -0,0 +1,91 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+static int mddi_ext_lcd_on(struct platform_device *pdev);
+static int mddi_ext_lcd_off(struct platform_device *pdev);
+
+static int mddi_ext_lcd_on(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int mddi_ext_lcd_off(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __init mddi_ext_lcd_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = mddi_ext_lcd_probe,
+ .driver = {
+ .name = "extmddi_svga",
+ },
+};
+
+static struct msm_fb_panel_data mddi_ext_lcd_panel_data = {
+ .panel_info.xres = 800,
+ .panel_info.yres = 600,
+ .panel_info.type = EXT_MDDI_PANEL,
+ .panel_info.pdest = DISPLAY_1,
+ .panel_info.wait_cycle = 0,
+ .panel_info.bpp = 18,
+ .panel_info.fb_num = 2,
+ .panel_info.clk_rate = 122880000,
+ .panel_info.clk_min = 120000000,
+ .panel_info.clk_max = 125000000,
+ .on = mddi_ext_lcd_on,
+ .off = mddi_ext_lcd_off,
+};
+
+static struct platform_device this_device = {
+ .name = "extmddi_svga",
+ .id = 0,
+ .dev = {
+ .platform_data = &mddi_ext_lcd_panel_data,
+ }
+};
+
+static int __init mddi_ext_lcd_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &mddi_ext_lcd_panel_data.panel_info;
+ pinfo->lcd.vsync_enable = FALSE;
+ pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(mddi_ext_lcd_init);
diff --git a/drivers/staging/msm/mddi_prism.c b/drivers/staging/msm/mddi_prism.c
new file mode 100644
index 000000000000..489d40405a5f
--- /dev/null
+++ b/drivers/staging/msm/mddi_prism.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+static int prism_lcd_on(struct platform_device *pdev);
+static int prism_lcd_off(struct platform_device *pdev);
+
+static int prism_lcd_on(struct platform_device *pdev)
+{
+ /* Set the MDP pixel data attributes for Primary Display */
+ mddi_host_write_pix_attr_reg(0x00C3);
+
+ return 0;
+}
+
+static int prism_lcd_off(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int __init prism_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = prism_probe,
+ .driver = {
+ .name = "mddi_prism_wvga",
+ },
+};
+
+static struct msm_fb_panel_data prism_panel_data = {
+ .on = prism_lcd_on,
+ .off = prism_lcd_off,
+};
+
+static struct platform_device this_device = {
+ .name = "mddi_prism_wvga",
+ .id = 0,
+ .dev = {
+ .platform_data = &prism_panel_data,
+ }
+};
+
+static int __init prism_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ u32 id;
+
+ ret = msm_fb_detect_client("mddi_prism_wvga");
+ if (ret == -ENODEV)
+ return 0;
+
+ if (ret) {
+ id = mddi_get_client_id();
+
+ if (((id >> 16) != 0x4474) || ((id & 0xffff) == 0x8960))
+ return 0;
+ }
+#endif
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &prism_panel_data.panel_info;
+ pinfo->xres = 800;
+ pinfo->yres = 480;
+ pinfo->type = MDDI_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 18;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 153600000;
+ pinfo->clk_min = 150000000;
+ pinfo->clk_max = 160000000;
+ pinfo->lcd.vsync_enable = TRUE;
+ pinfo->lcd.refx100 = 6050;
+ pinfo->lcd.v_back_porch = 23;
+ pinfo->lcd.v_front_porch = 20;
+ pinfo->lcd.v_pulse_width = 105;
+ pinfo->lcd.hw_vsync_mode = TRUE;
+ pinfo->lcd.vsync_notifier_period = 0;
+
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(prism_init);
diff --git a/drivers/staging/msm/mddi_sharp.c b/drivers/staging/msm/mddi_sharp.c
new file mode 100644
index 000000000000..1da1be4052d0
--- /dev/null
+++ b/drivers/staging/msm/mddi_sharp.c
@@ -0,0 +1,892 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+#define SHARP_QVGA_PRIM 1
+#define SHARP_128X128_SECD 2
+
+extern uint32 mddi_host_core_version;
+static boolean mddi_debug_prim_wait = FALSE;
+static boolean mddi_sharp_vsync_wake = TRUE;
+static boolean mddi_sharp_monitor_refresh_value = TRUE;
+static boolean mddi_sharp_report_refresh_measurements = FALSE;
+static uint32 mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
+static uint32 mddi_sharp_rows_per_refresh = 338;
+static uint32 mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
+static boolean mddi_sharp_debug_60hz_refresh = FALSE;
+
+extern mddi_gpio_info_type mddi_gpio;
+extern boolean mddi_vsync_detect_enabled;
+static msm_fb_vsync_handler_type mddi_sharp_vsync_handler;
+static void *mddi_sharp_vsync_handler_arg;
+static uint16 mddi_sharp_vsync_attempts;
+
+static void mddi_sharp_prim_lcd_init(void);
+static void mddi_sharp_sub_lcd_init(void);
+static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd);
+static void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler,
+ void *);
+static void mddi_sharp_lcd_vsync_detected(boolean detected);
+static struct msm_panel_common_pdata *mddi_sharp_pdata;
+
+#define REG_SYSCTL 0x0000
+#define REG_INTR 0x0006
+#define REG_CLKCNF 0x000C
+#define REG_CLKDIV1 0x000E
+#define REG_CLKDIV2 0x0010
+
+#define REG_GIOD 0x0040
+#define REG_GIOA 0x0042
+
+#define REG_AGM 0x010A
+#define REG_FLFT 0x0110
+#define REG_FRGT 0x0112
+#define REG_FTOP 0x0114
+#define REG_FBTM 0x0116
+#define REG_FSTRX 0x0118
+#define REG_FSTRY 0x011A
+#define REG_VRAM 0x0202
+#define REG_SSDCTL 0x0330
+#define REG_SSD0 0x0332
+#define REG_PSTCTL1 0x0400
+#define REG_PSTCTL2 0x0402
+#define REG_PTGCTL 0x042A
+#define REG_PTHP 0x042C
+#define REG_PTHB 0x042E
+#define REG_PTHW 0x0430
+#define REG_PTHF 0x0432
+#define REG_PTVP 0x0434
+#define REG_PTVB 0x0436
+#define REG_PTVW 0x0438
+#define REG_PTVF 0x043A
+#define REG_VBLKS 0x0458
+#define REG_VBLKE 0x045A
+#define REG_SUBCTL 0x0700
+#define REG_SUBTCMD 0x0702
+#define REG_SUBTCMDD 0x0704
+#define REG_REVBYTE 0x0A02
+#define REG_REVCNT 0x0A04
+#define REG_REVATTR 0x0A06
+#define REG_REVFMT 0x0A08
+
+#define SHARP_SUB_UNKNOWN 0xffffffff
+#define SHARP_SUB_HYNIX 1
+#define SHARP_SUB_ROHM 2
+
+static uint32 sharp_subpanel_type = SHARP_SUB_UNKNOWN;
+
+static void sub_through_write(int sub_rs, uint32 sub_data)
+{
+ mddi_queue_register_write(REG_SUBTCMDD, sub_data, FALSE, 0);
+
+ /* CS=1,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
+
+ /* CS=0,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
+
+ /* CS=0,RD=1,WE=0,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0004 | sub_rs, FALSE, 0);
+
+ /* CS=0,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
+
+ /* CS=1,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
+}
+
+static uint32 sub_through_read(int sub_rs)
+{
+ uint32 sub_data;
+
+ /* CS=1,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, FALSE, 0);
+
+ /* CS=0,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
+
+ /* CS=0,RD=1,WE=0,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0002 | sub_rs, TRUE, 0);
+
+ mddi_queue_register_read(REG_SUBTCMDD, &sub_data, TRUE, 0);
+
+ /* CS=0,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x0006 | sub_rs, FALSE, 0);
+
+ /* CS=1,RD=1,WE=1,RS=sub_rs */
+ mddi_queue_register_write(REG_SUBTCMD, 0x000e | sub_rs, TRUE, 0);
+
+ return sub_data;
+}
+
+static void serigo(uint32 ssd)
+{
+ uint32 ssdctl;
+
+ mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
+ ssdctl = ((ssdctl & 0xE7) | 0x02);
+
+ mddi_queue_register_write(REG_SSD0, ssd, FALSE, 0);
+ mddi_queue_register_write(REG_SSDCTL, ssdctl, TRUE, 0);
+
+ do {
+ mddi_queue_register_read(REG_SSDCTL, &ssdctl, TRUE, 0);
+ } while ((ssdctl & 0x0002) != 0);
+
+ if (mddi_debug_prim_wait)
+ mddi_wait(2);
+}
+
+static void mddi_sharp_lcd_powerdown(void)
+{
+ serigo(0x0131);
+ serigo(0x0300);
+ mddi_wait(40);
+ serigo(0x0135);
+ mddi_wait(20);
+ serigo(0x2122);
+ mddi_wait(20);
+ serigo(0x0201);
+ mddi_wait(20);
+ serigo(0x2100);
+ mddi_wait(20);
+ serigo(0x2000);
+ mddi_wait(20);
+
+ mddi_queue_register_write(REG_PSTCTL1, 0x1, TRUE, 0);
+ mddi_wait(100);
+ mddi_queue_register_write(REG_PSTCTL1, 0x0, TRUE, 0);
+ mddi_wait(2);
+ mddi_queue_register_write(REG_SYSCTL, 0x1, TRUE, 0);
+ mddi_wait(2);
+ mddi_queue_register_write(REG_CLKDIV1, 0x3, TRUE, 0);
+ mddi_wait(2);
+ mddi_queue_register_write(REG_SSDCTL, 0x0000, TRUE, 0); /* SSDRESET */
+ mddi_queue_register_write(REG_SYSCTL, 0x0, TRUE, 0);
+ mddi_wait(2);
+}
+
+static void mddi_sharp_lcd_set_backlight(struct msm_fb_data_type *mfd)
+{
+ uint32 regdata;
+ int32 level;
+ int max = mfd->panel_info.bl_max;
+ int min = mfd->panel_info.bl_min;
+
+ if (mddi_sharp_pdata && mddi_sharp_pdata->backlight_level) {
+ level = mddi_sharp_pdata->backlight_level(mfd->bl_level,
+ max,
+ min);
+
+ if (level < 0)
+ return;
+
+ /* use Rodem GPIO(2:0) to give 8 levels of backlight (7-0) */
+ /* Set lower 3 GPIOs as Outputs (set to 0) */
+ mddi_queue_register_read(REG_GIOA, &regdata, TRUE, 0);
+ mddi_queue_register_write(REG_GIOA, regdata & 0xfff8, TRUE, 0);
+
+ /* Set lower 3 GPIOs as level */
+ mddi_queue_register_read(REG_GIOD, &regdata, TRUE, 0);
+ mddi_queue_register_write(REG_GIOD,
+ (regdata & 0xfff8) | (0x07 & level), TRUE, 0);
+ }
+}
+
+static void mddi_sharp_prim_lcd_init(void)
+{
+ mddi_queue_register_write(REG_SYSCTL, 0x4000, TRUE, 0);
+ mddi_wait(1);
+ mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
+ mddi_wait(5);
+ mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
+ mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
+
+ /* new reg write below */
+ if (mddi_sharp_debug_60hz_refresh)
+ mddi_queue_register_write(REG_CLKCNF, 0x070d, FALSE, 0);
+ else
+ mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
+
+ mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
+ mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
+ mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
+ mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
+ mddi_queue_register_write(REG_PTHW, 240, FALSE, 0);
+ if (mddi_sharp_debug_60hz_refresh)
+ mddi_queue_register_write(REG_PTHF, 12, FALSE, 0);
+ else
+ mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
+
+ mddi_wait(1);
+
+ mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
+ mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
+ mddi_queue_register_write(REG_PTVW, 320, FALSE, 0);
+ mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
+
+ mddi_wait(1);
+
+ /* vram_color set REG_AGM???? */
+ mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
+
+ mddi_queue_register_write(REG_SSDCTL, 0x0000, FALSE, 0);
+ mddi_queue_register_write(REG_SSDCTL, 0x0001, TRUE, 0);
+ mddi_wait(1);
+ mddi_queue_register_write(REG_PSTCTL1, 0x0001, TRUE, 0);
+ mddi_wait(10);
+
+ serigo(0x0701);
+ /* software reset */
+ mddi_wait(1);
+ /* Wait over 50us */
+
+ serigo(0x0400);
+ /* DCLK~ACHSYNC~ACVSYNC polarity setting */
+ serigo(0x2900);
+ /* EEPROM start read address setting */
+ serigo(0x2606);
+ /* EEPROM start read register setting */
+ mddi_wait(20);
+ /* Wait over 20ms */
+
+ serigo(0x0503);
+ /* Horizontal timing setting */
+ serigo(0x062C);
+ /* Veritical timing setting */
+ serigo(0x2001);
+ /* power initialize setting(VDC2) */
+ mddi_wait(20);
+ /* Wait over 20ms */
+
+ serigo(0x2120);
+ /* Initialize power setting(CPS) */
+ mddi_wait(20);
+ /* Wait over 20ms */
+
+ serigo(0x2130);
+ /* Initialize power setting(CPS) */
+ mddi_wait(20);
+ /* Wait over 20ms */
+
+ serigo(0x2132);
+ /* Initialize power setting(CPS) */
+ mddi_wait(10);
+ /* Wait over 10ms */
+
+ serigo(0x2133);
+ /* Initialize power setting(CPS) */
+ mddi_wait(20);
+ /* Wait over 20ms */
+
+ serigo(0x0200);
+ /* Panel initialize release(INIT) */
+ mddi_wait(1);
+ /* Wait over 1ms */
+
+ serigo(0x0131);
+ /* Panel setting(CPS) */
+ mddi_wait(1);
+ /* Wait over 1ms */
+
+ mddi_queue_register_write(REG_PSTCTL1, 0x0003, TRUE, 0);
+
+ /* if (FFA LCD is upside down) -> serigo(0x0100); */
+ serigo(0x0130);
+
+ /* Black mask release(display ON) */
+ mddi_wait(1);
+ /* Wait over 1ms */
+
+ if (mddi_sharp_vsync_wake) {
+ mddi_queue_register_write(REG_VBLKS, 0x1001, TRUE, 0);
+ mddi_queue_register_write(REG_VBLKE, 0x1002, TRUE, 0);
+ }
+
+ /* Set the MDP pixel data attributes for Primary Display */
+ mddi_host_write_pix_attr_reg(0x00C3);
+ return;
+
+}
+
+void mddi_sharp_sub_lcd_init(void)
+{
+
+ mddi_queue_register_write(REG_SYSCTL, 0x4000, FALSE, 0);
+ mddi_queue_register_write(REG_SYSCTL, 0x0000, TRUE, 0);
+ mddi_wait(100);
+
+ mddi_queue_register_write(REG_SYSCTL, 0x0001, FALSE, 0);
+ mddi_queue_register_write(REG_CLKDIV1, 0x000b, FALSE, 0);
+ mddi_queue_register_write(REG_CLKCNF, 0x0708, FALSE, 0);
+ mddi_queue_register_write(REG_SYSCTL, 0x0201, FALSE, 0);
+ mddi_queue_register_write(REG_PTGCTL, 0x0010, FALSE, 0);
+ mddi_queue_register_write(REG_PTHP, 4, FALSE, 0);
+ mddi_queue_register_write(REG_PTHB, 40, FALSE, 0);
+ mddi_queue_register_write(REG_PTHW, 128, FALSE, 0);
+ mddi_queue_register_write(REG_PTHF, 92, FALSE, 0);
+ mddi_queue_register_write(REG_PTVP, 1, FALSE, 0);
+ mddi_queue_register_write(REG_PTVB, 2, FALSE, 0);
+ mddi_queue_register_write(REG_PTVW, 128, FALSE, 0);
+ mddi_queue_register_write(REG_PTVF, 15, FALSE, 0);
+
+ /* Now the sub display..... */
+ /* Reset High */
+ mddi_queue_register_write(REG_SUBCTL, 0x0200, FALSE, 0);
+ /* CS=1,RD=1,WE=1,RS=1 */
+ mddi_queue_register_write(REG_SUBTCMD, 0x000f, TRUE, 0);
+ mddi_wait(1);
+ /* Wait 5us */
+
+ if (sharp_subpanel_type == SHARP_SUB_UNKNOWN) {
+ uint32 data;
+
+ sub_through_write(1, 0x05);
+ sub_through_write(1, 0x6A);
+ sub_through_write(1, 0x1D);
+ sub_through_write(1, 0x05);
+ data = sub_through_read(1);
+ if (data == 0x6A) {
+ sharp_subpanel_type = SHARP_SUB_HYNIX;
+ } else {
+ sub_through_write(0, 0x36);
+ sub_through_write(1, 0xA8);
+ sub_through_write(0, 0x09);
+ data = sub_through_read(1);
+ data = sub_through_read(1);
+ if (data == 0x54) {
+ sub_through_write(0, 0x36);
+ sub_through_write(1, 0x00);
+ sharp_subpanel_type = SHARP_SUB_ROHM;
+ }
+ }
+ }
+
+ if (sharp_subpanel_type == SHARP_SUB_HYNIX) {
+ sub_through_write(1, 0x00); /* Display setting 1 */
+ sub_through_write(1, 0x04);
+ sub_through_write(1, 0x01);
+ sub_through_write(1, 0x05);
+ sub_through_write(1, 0x0280);
+ sub_through_write(1, 0x0301);
+ sub_through_write(1, 0x0402);
+ sub_through_write(1, 0x0500);
+ sub_through_write(1, 0x0681);
+ sub_through_write(1, 0x077F);
+ sub_through_write(1, 0x08C0);
+ sub_through_write(1, 0x0905);
+ sub_through_write(1, 0x0A02);
+ sub_through_write(1, 0x0B00);
+ sub_through_write(1, 0x0C00);
+ sub_through_write(1, 0x0D00);
+ sub_through_write(1, 0x0E00);
+ sub_through_write(1, 0x0F00);
+
+ sub_through_write(1, 0x100B); /* Display setting 2 */
+ sub_through_write(1, 0x1103);
+ sub_through_write(1, 0x1237);
+ sub_through_write(1, 0x1300);
+ sub_through_write(1, 0x1400);
+ sub_through_write(1, 0x1500);
+ sub_through_write(1, 0x1605);
+ sub_through_write(1, 0x1700);
+ sub_through_write(1, 0x1800);
+ sub_through_write(1, 0x192E);
+ sub_through_write(1, 0x1A00);
+ sub_through_write(1, 0x1B00);
+ sub_through_write(1, 0x1C00);
+
+ sub_through_write(1, 0x151A); /* Power setting */
+
+ sub_through_write(1, 0x2002); /* Gradation Palette setting */
+ sub_through_write(1, 0x2107);
+ sub_through_write(1, 0x220C);
+ sub_through_write(1, 0x2310);
+ sub_through_write(1, 0x2414);
+ sub_through_write(1, 0x2518);
+ sub_through_write(1, 0x261C);
+ sub_through_write(1, 0x2720);
+ sub_through_write(1, 0x2824);
+ sub_through_write(1, 0x2928);
+ sub_through_write(1, 0x2A2B);
+ sub_through_write(1, 0x2B2E);
+ sub_through_write(1, 0x2C31);
+ sub_through_write(1, 0x2D34);
+ sub_through_write(1, 0x2E37);
+ sub_through_write(1, 0x2F3A);
+ sub_through_write(1, 0x303C);
+ sub_through_write(1, 0x313E);
+ sub_through_write(1, 0x323F);
+ sub_through_write(1, 0x3340);
+ sub_through_write(1, 0x3441);
+ sub_through_write(1, 0x3543);
+ sub_through_write(1, 0x3646);
+ sub_through_write(1, 0x3749);
+ sub_through_write(1, 0x384C);
+ sub_through_write(1, 0x394F);
+ sub_through_write(1, 0x3A52);
+ sub_through_write(1, 0x3B59);
+ sub_through_write(1, 0x3C60);
+ sub_through_write(1, 0x3D67);
+ sub_through_write(1, 0x3E6E);
+ sub_through_write(1, 0x3F7F);
+ sub_through_write(1, 0x4001);
+ sub_through_write(1, 0x4107);
+ sub_through_write(1, 0x420C);
+ sub_through_write(1, 0x4310);
+ sub_through_write(1, 0x4414);
+ sub_through_write(1, 0x4518);
+ sub_through_write(1, 0x461C);
+ sub_through_write(1, 0x4720);
+ sub_through_write(1, 0x4824);
+ sub_through_write(1, 0x4928);
+ sub_through_write(1, 0x4A2B);
+ sub_through_write(1, 0x4B2E);
+ sub_through_write(1, 0x4C31);
+ sub_through_write(1, 0x4D34);
+ sub_through_write(1, 0x4E37);
+ sub_through_write(1, 0x4F3A);
+ sub_through_write(1, 0x503C);
+ sub_through_write(1, 0x513E);
+ sub_through_write(1, 0x523F);
+ sub_through_write(1, 0x5340);
+ sub_through_write(1, 0x5441);
+ sub_through_write(1, 0x5543);
+ sub_through_write(1, 0x5646);
+ sub_through_write(1, 0x5749);
+ sub_through_write(1, 0x584C);
+ sub_through_write(1, 0x594F);
+ sub_through_write(1, 0x5A52);
+ sub_through_write(1, 0x5B59);
+ sub_through_write(1, 0x5C60);
+ sub_through_write(1, 0x5D67);
+ sub_through_write(1, 0x5E6E);
+ sub_through_write(1, 0x5F7E);
+ sub_through_write(1, 0x6000);
+ sub_through_write(1, 0x6107);
+ sub_through_write(1, 0x620C);
+ sub_through_write(1, 0x6310);
+ sub_through_write(1, 0x6414);
+ sub_through_write(1, 0x6518);
+ sub_through_write(1, 0x661C);
+ sub_through_write(1, 0x6720);
+ sub_through_write(1, 0x6824);
+ sub_through_write(1, 0x6928);
+ sub_through_write(1, 0x6A2B);
+ sub_through_write(1, 0x6B2E);
+ sub_through_write(1, 0x6C31);
+ sub_through_write(1, 0x6D34);
+ sub_through_write(1, 0x6E37);
+ sub_through_write(1, 0x6F3A);
+ sub_through_write(1, 0x703C);
+ sub_through_write(1, 0x713E);
+ sub_through_write(1, 0x723F);
+ sub_through_write(1, 0x7340);
+ sub_through_write(1, 0x7441);
+ sub_through_write(1, 0x7543);
+ sub_through_write(1, 0x7646);
+ sub_through_write(1, 0x7749);
+ sub_through_write(1, 0x784C);
+ sub_through_write(1, 0x794F);
+ sub_through_write(1, 0x7A52);
+ sub_through_write(1, 0x7B59);
+ sub_through_write(1, 0x7C60);
+ sub_through_write(1, 0x7D67);
+ sub_through_write(1, 0x7E6E);
+ sub_through_write(1, 0x7F7D);
+
+ sub_through_write(1, 0x1851); /* Display on */
+
+ mddi_queue_register_write(REG_AGM, 0x0000, TRUE, 0);
+
+ /* 1 pixel / 1 post clock */
+ mddi_queue_register_write(REG_CLKDIV2, 0x3b00, FALSE, 0);
+
+ /* SUB LCD select */
+ mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
+
+ /* RS=0,command initiate number=0,select master mode */
+ mddi_queue_register_write(REG_SUBCTL, 0x0202, FALSE, 0);
+
+ /* Sub LCD Data transform start */
+ mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
+
+ } else if (sharp_subpanel_type == SHARP_SUB_ROHM) {
+
+ sub_through_write(0, 0x01); /* Display setting */
+ sub_through_write(1, 0x00);
+
+ mddi_wait(1);
+ /* Wait 100us <----- ******* Update 2005/01/24 */
+
+ sub_through_write(0, 0xB6);
+ sub_through_write(1, 0x0C);
+ sub_through_write(1, 0x4A);
+ sub_through_write(1, 0x20);
+ sub_through_write(0, 0x3A);
+ sub_through_write(1, 0x05);
+ sub_through_write(0, 0xB7);
+ sub_through_write(1, 0x01);
+ sub_through_write(0, 0xBA);
+ sub_through_write(1, 0x20);
+ sub_through_write(1, 0x02);
+ sub_through_write(0, 0x25);
+ sub_through_write(1, 0x4F);
+ sub_through_write(0, 0xBB);
+ sub_through_write(1, 0x00);
+ sub_through_write(0, 0x36);
+ sub_through_write(1, 0x00);
+ sub_through_write(0, 0xB1);
+ sub_through_write(1, 0x05);
+ sub_through_write(0, 0xBE);
+ sub_through_write(1, 0x80);
+ sub_through_write(0, 0x26);
+ sub_through_write(1, 0x01);
+ sub_through_write(0, 0x2A);
+ sub_through_write(1, 0x02);
+ sub_through_write(1, 0x81);
+ sub_through_write(0, 0x2B);
+ sub_through_write(1, 0x00);
+ sub_through_write(1, 0x7F);
+
+ sub_through_write(0, 0x2C);
+ sub_through_write(0, 0x11); /* Sleep mode off */
+
+ mddi_wait(1);
+ /* Wait 100 ms <----- ******* Update 2005/01/24 */
+
+ sub_through_write(0, 0x29); /* Display on */
+ sub_through_write(0, 0xB3);
+ sub_through_write(1, 0x20);
+ sub_through_write(1, 0xAA);
+ sub_through_write(1, 0xA0);
+ sub_through_write(1, 0x20);
+ sub_through_write(1, 0x30);
+ sub_through_write(1, 0xA6);
+ sub_through_write(1, 0xFF);
+ sub_through_write(1, 0x9A);
+ sub_through_write(1, 0x9F);
+ sub_through_write(1, 0xAF);
+ sub_through_write(1, 0xBC);
+ sub_through_write(1, 0xCF);
+ sub_through_write(1, 0xDF);
+ sub_through_write(1, 0x20);
+ sub_through_write(1, 0x9C);
+ sub_through_write(1, 0x8A);
+
+ sub_through_write(0, 0x002C); /* Display on */
+
+ /* 1 pixel / 2 post clock */
+ mddi_queue_register_write(REG_CLKDIV2, 0x7b00, FALSE, 0);
+
+ /* SUB LCD select */
+ mddi_queue_register_write(REG_PSTCTL2, 0x0080, FALSE, 0);
+
+ /* RS=1,command initiate number=0,select master mode */
+ mddi_queue_register_write(REG_SUBCTL, 0x0242, FALSE, 0);
+
+ /* Sub LCD Data transform start */
+ mddi_queue_register_write(REG_PSTCTL1, 0x0003, FALSE, 0);
+
+ }
+
+ /* Set the MDP pixel data attributes for Sub Display */
+ mddi_host_write_pix_attr_reg(0x00C0);
+}
+
+void mddi_sharp_lcd_vsync_detected(boolean detected)
+{
+ /* static timetick_type start_time = 0; */
+ static struct timeval start_time;
+ static boolean first_time = TRUE;
+ /* uint32 mdp_cnt_val = 0; */
+ /* timetick_type elapsed_us; */
+ struct timeval now;
+ uint32 elapsed_us;
+ uint32 num_vsyncs;
+
+ if ((detected) || (mddi_sharp_vsync_attempts > 5)) {
+ if ((detected) && (mddi_sharp_monitor_refresh_value)) {
+ /* if (start_time != 0) */
+ if (!first_time) {
+ jiffies_to_timeval(jiffies, &now);
+ elapsed_us =
+ (now.tv_sec - start_time.tv_sec) * 1000000 +
+ now.tv_usec - start_time.tv_usec;
+ /*
+ * LCD is configured for a refresh every usecs,
+ * so to determine the number of vsyncs that
+ * have occurred since the last measurement add
+ * half that to the time difference and divide
+ * by the refresh rate.
+ */
+ num_vsyncs = (elapsed_us +
+ (mddi_sharp_usecs_per_refresh >>
+ 1)) /
+ mddi_sharp_usecs_per_refresh;
+ /*
+ * LCD is configured for * hsyncs (rows) per
+ * refresh cycle. Calculate new rows_per_second
+ * value based upon these new measurements.
+ * MDP can update with this new value.
+ */
+ mddi_sharp_rows_per_second =
+ (mddi_sharp_rows_per_refresh * 1000 *
+ num_vsyncs) / (elapsed_us / 1000);
+ }
+ /* start_time = timetick_get(); */
+ first_time = FALSE;
+ jiffies_to_timeval(jiffies, &start_time);
+ if (mddi_sharp_report_refresh_measurements) {
+ /* mdp_cnt_val = MDP_LINE_COUNT; */
+ }
+ }
+ /* if detected = TRUE, client initiated wakeup was detected */
+ if (mddi_sharp_vsync_handler != NULL) {
+ (*mddi_sharp_vsync_handler)
+ (mddi_sharp_vsync_handler_arg);
+ mddi_sharp_vsync_handler = NULL;
+ }
+ mddi_vsync_detect_enabled = FALSE;
+ mddi_sharp_vsync_attempts = 0;
+ /* need to clear this vsync wakeup */
+ if (!mddi_queue_register_write_int(REG_INTR, 0x0000)) {
+ MDDI_MSG_ERR("Vsync interrupt clear failed!\n");
+ }
+ if (!detected) {
+ /* give up after 5 failed attempts but show error */
+ MDDI_MSG_NOTICE("Vsync detection failed!\n");
+ } else if ((mddi_sharp_monitor_refresh_value) &&
+ (mddi_sharp_report_refresh_measurements)) {
+ MDDI_MSG_NOTICE(" Lines Per Second=%d!\n",
+ mddi_sharp_rows_per_second);
+ }
+ } else
+ /* if detected = FALSE, we woke up from hibernation, but did not
+ * detect client initiated wakeup.
+ */
+ mddi_sharp_vsync_attempts++;
+}
+
+/* ISR to be executed */
+void mddi_sharp_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg)
+{
+ boolean error = FALSE;
+ unsigned long flags;
+
+ /* Disable interrupts */
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+ /* INTLOCK(); */
+
+ if (mddi_sharp_vsync_handler != NULL)
+ error = TRUE;
+
+ /* Register the handler for this particular GROUP interrupt source */
+ mddi_sharp_vsync_handler = handler;
+ mddi_sharp_vsync_handler_arg = arg;
+
+ /* Restore interrupts */
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+ /* INTFREE(); */
+
+ if (error)
+ MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n");
+
+ /* Enable the vsync wakeup */
+ mddi_queue_register_write(REG_INTR, 0x8100, FALSE, 0);
+
+ mddi_sharp_vsync_attempts = 1;
+ mddi_vsync_detect_enabled = TRUE;
+} /* mddi_sharp_vsync_set_handler */
+
+static int mddi_sharp_lcd_on(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (mfd->panel.id == SHARP_QVGA_PRIM)
+ mddi_sharp_prim_lcd_init();
+ else
+ mddi_sharp_sub_lcd_init();
+
+ return 0;
+}
+
+static int mddi_sharp_lcd_off(struct platform_device *pdev)
+{
+ mddi_sharp_lcd_powerdown();
+ return 0;
+}
+
+static int __init mddi_sharp_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ mddi_sharp_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = mddi_sharp_probe,
+ .driver = {
+ .name = "mddi_sharp_qvga",
+ },
+};
+
+static struct msm_fb_panel_data mddi_sharp_panel_data0 = {
+ .on = mddi_sharp_lcd_on,
+ .off = mddi_sharp_lcd_off,
+ .set_backlight = mddi_sharp_lcd_set_backlight,
+ .set_vsync_notifier = mddi_sharp_vsync_set_handler,
+};
+
+static struct platform_device this_device_0 = {
+ .name = "mddi_sharp_qvga",
+ .id = SHARP_QVGA_PRIM,
+ .dev = {
+ .platform_data = &mddi_sharp_panel_data0,
+ }
+};
+
+static struct msm_fb_panel_data mddi_sharp_panel_data1 = {
+ .on = mddi_sharp_lcd_on,
+ .off = mddi_sharp_lcd_off,
+};
+
+static struct platform_device this_device_1 = {
+ .name = "mddi_sharp_qvga",
+ .id = SHARP_128X128_SECD,
+ .dev = {
+ .platform_data = &mddi_sharp_panel_data1,
+ }
+};
+
+static int __init mddi_sharp_init(void)
+{
+ int ret;
+ struct msm_panel_info *pinfo;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ u32 id;
+
+ ret = msm_fb_detect_client("mddi_sharp_qvga");
+ if (ret == -ENODEV)
+ return 0;
+
+ if (ret) {
+ id = mddi_get_client_id();
+
+ if (((id >> 16) != 0x0) || ((id & 0xffff) != 0x8835))
+ return 0;
+ }
+#endif
+ if (mddi_host_core_version > 8) {
+ /* can use faster refresh with newer hw revisions */
+ mddi_sharp_debug_60hz_refresh = TRUE;
+
+ /* Timing variables for tracking vsync */
+ /* dot_clock = 6.00MHz
+ * horizontal count = 296
+ * vertical count = 338
+ * refresh rate = 6000000/(296+338) = 60Hz
+ */
+ mddi_sharp_rows_per_second = 20270; /* 6000000/296 */
+ mddi_sharp_rows_per_refresh = 338;
+ mddi_sharp_usecs_per_refresh = 16674; /* (296+338)/6000000 */
+ } else {
+ /* Timing variables for tracking vsync */
+ /* dot_clock = 5.20MHz
+ * horizontal count = 376
+ * vertical count = 338
+ * refresh rate = 5200000/(376+338) = 41Hz
+ */
+ mddi_sharp_rows_per_second = 13830; /* 5200000/376 */
+ mddi_sharp_rows_per_refresh = 338;
+ mddi_sharp_usecs_per_refresh = 24440; /* (376+338)/5200000 */
+ }
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ pinfo = &mddi_sharp_panel_data0.panel_info;
+ pinfo->xres = 240;
+ pinfo->yres = 320;
+ pinfo->type = MDDI_PANEL;
+ pinfo->pdest = DISPLAY_1;
+ pinfo->mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 18;
+ pinfo->fb_num = 2;
+ pinfo->clk_rate = 122880000;
+ pinfo->clk_min = 120000000;
+ pinfo->clk_max = 125000000;
+ pinfo->lcd.vsync_enable = TRUE;
+ pinfo->lcd.refx100 =
+ (mddi_sharp_rows_per_second * 100) /
+ mddi_sharp_rows_per_refresh;
+ pinfo->lcd.v_back_porch = 12;
+ pinfo->lcd.v_front_porch = 6;
+ pinfo->lcd.v_pulse_width = 0;
+ pinfo->lcd.hw_vsync_mode = FALSE;
+ pinfo->lcd.vsync_notifier_period = (1 * HZ);
+ pinfo->bl_max = 7;
+ pinfo->bl_min = 1;
+
+ ret = platform_device_register(&this_device_0);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+
+ pinfo = &mddi_sharp_panel_data1.panel_info;
+ pinfo->xres = 128;
+ pinfo->yres = 128;
+ pinfo->type = MDDI_PANEL;
+ pinfo->pdest = DISPLAY_2;
+ pinfo->mddi.vdopkt = 0x400;
+ pinfo->wait_cycle = 0;
+ pinfo->bpp = 18;
+ pinfo->clk_rate = 122880000;
+ pinfo->clk_min = 120000000;
+ pinfo->clk_max = 125000000;
+ pinfo->fb_num = 2;
+
+ ret = platform_device_register(&this_device_1);
+ if (ret) {
+ platform_device_unregister(&this_device_0);
+ platform_driver_unregister(&this_driver);
+ }
+ }
+
+ if (!ret)
+ mddi_lcd.vsync_detected = mddi_sharp_lcd_vsync_detected;
+
+ return ret;
+}
+
+module_init(mddi_sharp_init);
diff --git a/drivers/staging/msm/mddi_toshiba.c b/drivers/staging/msm/mddi_toshiba.c
new file mode 100644
index 000000000000..e96342d477a2
--- /dev/null
+++ b/drivers/staging/msm/mddi_toshiba.c
@@ -0,0 +1,1741 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+#include "mddi_toshiba.h"
+
+#define TM_GET_DID(id) ((id) & 0xff)
+#define TM_GET_PID(id) (((id) & 0xff00)>>8)
+
+#define MDDI_CLIENT_CORE_BASE 0x108000
+#define LCD_CONTROL_BLOCK_BASE 0x110000
+#define SPI_BLOCK_BASE 0x120000
+#define PWM_BLOCK_BASE 0x140000
+#define SYSTEM_BLOCK1_BASE 0x160000
+
+#define TTBUSSEL (MDDI_CLIENT_CORE_BASE|0x18)
+#define DPSET0 (MDDI_CLIENT_CORE_BASE|0x1C)
+#define DPSET1 (MDDI_CLIENT_CORE_BASE|0x20)
+#define DPSUS (MDDI_CLIENT_CORE_BASE|0x24)
+#define DPRUN (MDDI_CLIENT_CORE_BASE|0x28)
+#define SYSCKENA (MDDI_CLIENT_CORE_BASE|0x2C)
+
+#define BITMAP0 (MDDI_CLIENT_CORE_BASE|0x44)
+#define BITMAP1 (MDDI_CLIENT_CORE_BASE|0x48)
+#define BITMAP2 (MDDI_CLIENT_CORE_BASE|0x4C)
+#define BITMAP3 (MDDI_CLIENT_CORE_BASE|0x50)
+#define BITMAP4 (MDDI_CLIENT_CORE_BASE|0x54)
+
+#define SRST (LCD_CONTROL_BLOCK_BASE|0x00)
+#define PORT_ENB (LCD_CONTROL_BLOCK_BASE|0x04)
+#define START (LCD_CONTROL_BLOCK_BASE|0x08)
+#define PORT (LCD_CONTROL_BLOCK_BASE|0x0C)
+
+#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
+#define INTMSK (LCD_CONTROL_BLOCK_BASE|0x1C)
+#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
+
+#define PXL (LCD_CONTROL_BLOCK_BASE|0x30)
+#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
+#define HSW (LCD_CONTROL_BLOCK_BASE|0x38)
+#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
+#define HDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x40)
+#define VCYCLE (LCD_CONTROL_BLOCK_BASE|0x44)
+#define VSW (LCD_CONTROL_BLOCK_BASE|0x48)
+#define VDE_START (LCD_CONTROL_BLOCK_BASE|0x4C)
+#define VDE_SIZE (LCD_CONTROL_BLOCK_BASE|0x50)
+#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
+#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
+#define VSYNIF (LCD_CONTROL_BLOCK_BASE|0x60)
+#define WRSTB (LCD_CONTROL_BLOCK_BASE|0x64)
+#define RDSTB (LCD_CONTROL_BLOCK_BASE|0x68)
+#define ASY_DATA (LCD_CONTROL_BLOCK_BASE|0x6C)
+#define ASY_DATB (LCD_CONTROL_BLOCK_BASE|0x70)
+#define ASY_DATC (LCD_CONTROL_BLOCK_BASE|0x74)
+#define ASY_DATD (LCD_CONTROL_BLOCK_BASE|0x78)
+#define ASY_DATE (LCD_CONTROL_BLOCK_BASE|0x7C)
+#define ASY_DATF (LCD_CONTROL_BLOCK_BASE|0x80)
+#define ASY_DATG (LCD_CONTROL_BLOCK_BASE|0x84)
+#define ASY_DATH (LCD_CONTROL_BLOCK_BASE|0x88)
+#define ASY_CMDSET (LCD_CONTROL_BLOCK_BASE|0x8C)
+#define MONI (LCD_CONTROL_BLOCK_BASE|0xB0)
+#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0)
+
+#define SSICTL (SPI_BLOCK_BASE|0x00)
+#define SSITIME (SPI_BLOCK_BASE|0x04)
+#define SSITX (SPI_BLOCK_BASE|0x08)
+#define SSIINTS (SPI_BLOCK_BASE|0x14)
+
+#define TIMER0LOAD (PWM_BLOCK_BASE|0x00)
+#define TIMER0CTRL (PWM_BLOCK_BASE|0x08)
+#define PWM0OFF (PWM_BLOCK_BASE|0x1C)
+#define TIMER1LOAD (PWM_BLOCK_BASE|0x20)
+#define TIMER1CTRL (PWM_BLOCK_BASE|0x28)
+#define PWM1OFF (PWM_BLOCK_BASE|0x3C)
+#define TIMER2LOAD (PWM_BLOCK_BASE|0x40)
+#define TIMER2CTRL (PWM_BLOCK_BASE|0x48)
+#define PWM2OFF (PWM_BLOCK_BASE|0x5C)
+#define PWMCR (PWM_BLOCK_BASE|0x68)
+
+#define GPIOIS (GPIO_BLOCK_BASE|0x08)
+#define GPIOIEV (GPIO_BLOCK_BASE|0x10)
+#define GPIOIC (GPIO_BLOCK_BASE|0x20)
+
+#define WKREQ (SYSTEM_BLOCK1_BASE|0x00)
+#define CLKENB (SYSTEM_BLOCK1_BASE|0x04)
+#define DRAMPWR (SYSTEM_BLOCK1_BASE|0x08)
+#define INTMASK (SYSTEM_BLOCK1_BASE|0x0C)
+#define CNT_DIS (SYSTEM_BLOCK1_BASE|0x10)
+
+typedef enum {
+ TOSHIBA_STATE_OFF,
+ TOSHIBA_STATE_PRIM_SEC_STANDBY,
+ TOSHIBA_STATE_PRIM_SEC_READY,
+ TOSHIBA_STATE_PRIM_NORMAL_MODE,
+ TOSHIBA_STATE_SEC_NORMAL_MODE
+} mddi_toshiba_state_t;
+
+static uint32 mddi_toshiba_curr_vpos;
+static boolean mddi_toshiba_monitor_refresh_value = FALSE;
+static boolean mddi_toshiba_report_refresh_measurements = FALSE;
+
+boolean mddi_toshiba_61Hz_refresh = TRUE;
+
+/* Modifications to timing to increase refresh rate to > 60Hz.
+ * 20MHz dot clock.
+ * 646 total rows.
+ * 506 total columns.
+ * refresh rate = 61.19Hz
+ */
+static uint32 mddi_toshiba_rows_per_second = 39526;
+static uint32 mddi_toshiba_usecs_per_refresh = 16344;
+static uint32 mddi_toshiba_rows_per_refresh = 646;
+extern boolean mddi_vsync_detect_enabled;
+
+static msm_fb_vsync_handler_type mddi_toshiba_vsync_handler;
+static void *mddi_toshiba_vsync_handler_arg;
+static uint16 mddi_toshiba_vsync_attempts;
+
+static mddi_toshiba_state_t toshiba_state = TOSHIBA_STATE_OFF;
+
+static struct msm_panel_common_pdata *mddi_toshiba_pdata;
+
+static int mddi_toshiba_lcd_on(struct platform_device *pdev);
+static int mddi_toshiba_lcd_off(struct platform_device *pdev);
+
+static void mddi_toshiba_state_transition(mddi_toshiba_state_t a,
+ mddi_toshiba_state_t b)
+{
+ if (toshiba_state != a) {
+ MDDI_MSG_ERR("toshiba state trans. (%d->%d) found %d\n", a, b,
+ toshiba_state);
+ }
+ toshiba_state = b;
+}
+
+#define GORDON_REG_IMGCTL1 0x10 /* Image interface control 1 */
+#define GORDON_REG_IMGCTL2 0x11 /* Image interface control 2 */
+#define GORDON_REG_IMGSET1 0x12 /* Image interface settings 1 */
+#define GORDON_REG_IMGSET2 0x13 /* Image interface settings 2 */
+#define GORDON_REG_IVBP1 0x14 /* DM0: Vert back porch */
+#define GORDON_REG_IHBP1 0x15 /* DM0: Horiz back porch */
+#define GORDON_REG_IVNUM1 0x16 /* DM0: Num of vert lines */
+#define GORDON_REG_IHNUM1 0x17 /* DM0: Num of pixels per line */
+#define GORDON_REG_IVBP2 0x18 /* DM1: Vert back porch */
+#define GORDON_REG_IHBP2 0x19 /* DM1: Horiz back porch */
+#define GORDON_REG_IVNUM2 0x1A /* DM1: Num of vert lines */
+#define GORDON_REG_IHNUM2 0x1B /* DM1: Num of pixels per line */
+#define GORDON_REG_LCDIFCTL1 0x30 /* LCD interface control 1 */
+#define GORDON_REG_VALTRAN 0x31 /* LCD IF ctl: VALTRAN sync flag */
+#define GORDON_REG_AVCTL 0x33
+#define GORDON_REG_LCDIFCTL2 0x34 /* LCD interface control 2 */
+#define GORDON_REG_LCDIFCTL3 0x35 /* LCD interface control 3 */
+#define GORDON_REG_LCDIFSET1 0x36 /* LCD interface settings 1 */
+#define GORDON_REG_PCCTL 0x3C
+#define GORDON_REG_TPARAM1 0x40
+#define GORDON_REG_TLCDIF1 0x41
+#define GORDON_REG_TSSPB_ST1 0x42
+#define GORDON_REG_TSSPB_ED1 0x43
+#define GORDON_REG_TSCK_ST1 0x44
+#define GORDON_REG_TSCK_WD1 0x45
+#define GORDON_REG_TGSPB_VST1 0x46
+#define GORDON_REG_TGSPB_VED1 0x47
+#define GORDON_REG_TGSPB_CH1 0x48
+#define GORDON_REG_TGCK_ST1 0x49
+#define GORDON_REG_TGCK_ED1 0x4A
+#define GORDON_REG_TPCTL_ST1 0x4B
+#define GORDON_REG_TPCTL_ED1 0x4C
+#define GORDON_REG_TPCHG_ED1 0x4D
+#define GORDON_REG_TCOM_CH1 0x4E
+#define GORDON_REG_THBP1 0x4F
+#define GORDON_REG_TPHCTL1 0x50
+#define GORDON_REG_EVPH1 0x51
+#define GORDON_REG_EVPL1 0x52
+#define GORDON_REG_EVNH1 0x53
+#define GORDON_REG_EVNL1 0x54
+#define GORDON_REG_TBIAS1 0x55
+#define GORDON_REG_TPARAM2 0x56
+#define GORDON_REG_TLCDIF2 0x57
+#define GORDON_REG_TSSPB_ST2 0x58
+#define GORDON_REG_TSSPB_ED2 0x59
+#define GORDON_REG_TSCK_ST2 0x5A
+#define GORDON_REG_TSCK_WD2 0x5B
+#define GORDON_REG_TGSPB_VST2 0x5C
+#define GORDON_REG_TGSPB_VED2 0x5D
+#define GORDON_REG_TGSPB_CH2 0x5E
+#define GORDON_REG_TGCK_ST2 0x5F
+#define GORDON_REG_TGCK_ED2 0x60
+#define GORDON_REG_TPCTL_ST2 0x61
+#define GORDON_REG_TPCTL_ED2 0x62
+#define GORDON_REG_TPCHG_ED2 0x63
+#define GORDON_REG_TCOM_CH2 0x64
+#define GORDON_REG_THBP2 0x65
+#define GORDON_REG_TPHCTL2 0x66
+#define GORDON_REG_EVPH2 0x67
+#define GORDON_REG_EVPL2 0x68
+#define GORDON_REG_EVNH2 0x69
+#define GORDON_REG_EVNL2 0x6A
+#define GORDON_REG_TBIAS2 0x6B
+#define GORDON_REG_POWCTL 0x80
+#define GORDON_REG_POWOSC1 0x81
+#define GORDON_REG_POWOSC2 0x82
+#define GORDON_REG_POWSET 0x83
+#define GORDON_REG_POWTRM1 0x85
+#define GORDON_REG_POWTRM2 0x86
+#define GORDON_REG_POWTRM3 0x87
+#define GORDON_REG_POWTRMSEL 0x88
+#define GORDON_REG_POWHIZ 0x89
+
+void serigo(uint16 reg, uint8 data)
+{
+ uint32 mddi_val = 0;
+ mddi_queue_register_read(SSIINTS, &mddi_val, TRUE, 0);
+ if (mddi_val & (1 << 8))
+ mddi_wait(1);
+ /* No De-assert of CS and send 2 bytes */
+ mddi_val = 0x90000 | ((0x00FF & reg) << 8) | data;
+ mddi_queue_register_write(SSITX, mddi_val, TRUE, 0);
+}
+
+void gordon_init(void)
+{
+ /* Image interface settings ***/
+ serigo(GORDON_REG_IMGCTL2, 0x00);
+ serigo(GORDON_REG_IMGSET1, 0x01);
+
+ /* Exchange the RGB signal for J510(Softbank mobile) */
+ serigo(GORDON_REG_IMGSET2, 0x12);
+ serigo(GORDON_REG_LCDIFSET1, 0x00);
+ mddi_wait(2);
+
+ /* Pre-charge settings */
+ serigo(GORDON_REG_PCCTL, 0x09);
+ serigo(GORDON_REG_LCDIFCTL2, 0x1B);
+ mddi_wait(1);
+}
+
+void gordon_disp_on(void)
+{
+ /*gordon_dispmode setting */
+ /*VGA settings */
+ serigo(GORDON_REG_TPARAM1, 0x30);
+ serigo(GORDON_REG_TLCDIF1, 0x00);
+ serigo(GORDON_REG_TSSPB_ST1, 0x8B);
+ serigo(GORDON_REG_TSSPB_ED1, 0x93);
+ mddi_wait(2);
+ serigo(GORDON_REG_TSCK_ST1, 0x88);
+ serigo(GORDON_REG_TSCK_WD1, 0x00);
+ serigo(GORDON_REG_TGSPB_VST1, 0x01);
+ serigo(GORDON_REG_TGSPB_VED1, 0x02);
+ mddi_wait(2);
+ serigo(GORDON_REG_TGSPB_CH1, 0x5E);
+ serigo(GORDON_REG_TGCK_ST1, 0x80);
+ serigo(GORDON_REG_TGCK_ED1, 0x3C);
+ serigo(GORDON_REG_TPCTL_ST1, 0x50);
+ mddi_wait(2);
+ serigo(GORDON_REG_TPCTL_ED1, 0x74);
+ serigo(GORDON_REG_TPCHG_ED1, 0x78);
+ serigo(GORDON_REG_TCOM_CH1, 0x50);
+ serigo(GORDON_REG_THBP1, 0x84);
+ mddi_wait(2);
+ serigo(GORDON_REG_TPHCTL1, 0x00);
+ serigo(GORDON_REG_EVPH1, 0x70);
+ serigo(GORDON_REG_EVPL1, 0x64);
+ serigo(GORDON_REG_EVNH1, 0x56);
+ mddi_wait(2);
+ serigo(GORDON_REG_EVNL1, 0x48);
+ serigo(GORDON_REG_TBIAS1, 0x88);
+ mddi_wait(2);
+ serigo(GORDON_REG_TPARAM2, 0x28);
+ serigo(GORDON_REG_TLCDIF2, 0x14);
+ serigo(GORDON_REG_TSSPB_ST2, 0x49);
+ serigo(GORDON_REG_TSSPB_ED2, 0x4B);
+ mddi_wait(2);
+ serigo(GORDON_REG_TSCK_ST2, 0x4A);
+ serigo(GORDON_REG_TSCK_WD2, 0x02);
+ serigo(GORDON_REG_TGSPB_VST2, 0x02);
+ serigo(GORDON_REG_TGSPB_VED2, 0x03);
+ mddi_wait(2);
+ serigo(GORDON_REG_TGSPB_CH2, 0x2F);
+ serigo(GORDON_REG_TGCK_ST2, 0x40);
+ serigo(GORDON_REG_TGCK_ED2, 0x1E);
+ serigo(GORDON_REG_TPCTL_ST2, 0x2C);
+ mddi_wait(2);
+ serigo(GORDON_REG_TPCTL_ED2, 0x3A);
+ serigo(GORDON_REG_TPCHG_ED2, 0x3C);
+ serigo(GORDON_REG_TCOM_CH2, 0x28);
+ serigo(GORDON_REG_THBP2, 0x4D);
+ mddi_wait(2);
+ serigo(GORDON_REG_TPHCTL2, 0x1A);
+ mddi_wait(2);
+ serigo(GORDON_REG_IVBP1, 0x02);
+ serigo(GORDON_REG_IHBP1, 0x90);
+ serigo(GORDON_REG_IVNUM1, 0xA0);
+ serigo(GORDON_REG_IHNUM1, 0x78);
+ mddi_wait(2);
+ serigo(GORDON_REG_IVBP2, 0x02);
+ serigo(GORDON_REG_IHBP2, 0x48);
+ serigo(GORDON_REG_IVNUM2, 0x50);
+ serigo(GORDON_REG_IHNUM2, 0x3C);
+ mddi_wait(2);
+ serigo(GORDON_REG_POWCTL, 0x03);
+ mddi_wait(15);
+ serigo(GORDON_REG_POWCTL, 0x07);
+ mddi_wait(15);
+ serigo(GORDON_REG_POWCTL, 0x0F);
+ mddi_wait(15);
+ serigo(GORDON_REG_AVCTL, 0x03);
+ mddi_wait(15);
+ serigo(GORDON_REG_POWCTL, 0x1F);
+ mddi_wait(15);
+ serigo(GORDON_REG_POWCTL, 0x5F);
+ mddi_wait(15);
+ serigo(GORDON_REG_POWCTL, 0x7F);
+ mddi_wait(15);
+ serigo(GORDON_REG_LCDIFCTL1, 0x02);
+ mddi_wait(15);
+ serigo(GORDON_REG_IMGCTL1, 0x00);
+ mddi_wait(15);
+ serigo(GORDON_REG_LCDIFCTL3, 0x00);
+ mddi_wait(15);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ mddi_wait(15);
+ serigo(GORDON_REG_LCDIFCTL1, 0x03);
+ serigo(GORDON_REG_LCDIFCTL1, 0x03);
+ mddi_wait(1);
+}
+
+void gordon_disp_off(void)
+{
+ serigo(GORDON_REG_LCDIFCTL2, 0x7B);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ serigo(GORDON_REG_LCDIFCTL1, 0x02);
+ serigo(GORDON_REG_LCDIFCTL3, 0x01);
+ mddi_wait(20);
+ serigo(GORDON_REG_VALTRAN, 0x01);
+ serigo(GORDON_REG_IMGCTL1, 0x01);
+ serigo(GORDON_REG_LCDIFCTL1, 0x00);
+ mddi_wait(20);
+ serigo(GORDON_REG_POWCTL, 0x1F);
+ mddi_wait(40);
+ serigo(GORDON_REG_POWCTL, 0x07);
+ mddi_wait(40);
+ serigo(GORDON_REG_POWCTL, 0x03);
+ mddi_wait(40);
+ serigo(GORDON_REG_POWCTL, 0x00);
+ mddi_wait(40);
+}
+
+void gordon_disp_init(void)
+{
+ gordon_init();
+ mddi_wait(20);
+ gordon_disp_on();
+}
+
+static void toshiba_common_initial_setup(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT) {
+ write_client_reg(DPSET0 , 0x4bec0066, TRUE);
+ write_client_reg(DPSET1 , 0x00000113, TRUE);
+ write_client_reg(DPSUS , 0x00000000, TRUE);
+ write_client_reg(DPRUN , 0x00000001, TRUE);
+ mddi_wait(5);
+ write_client_reg(SYSCKENA , 0x00000001, TRUE);
+ write_client_reg(CLKENB , 0x0000a0e9, TRUE);
+
+ write_client_reg(GPIODATA , 0x03FF0000, TRUE);
+ write_client_reg(GPIODIR , 0x0000024D, TRUE);
+ write_client_reg(GPIOSEL , 0x00000173, TRUE);
+ write_client_reg(GPIOPC , 0x03C300C0, TRUE);
+ write_client_reg(WKREQ , 0x00000000, TRUE);
+ write_client_reg(GPIOIS , 0x00000000, TRUE);
+ write_client_reg(GPIOIEV , 0x00000001, TRUE);
+ write_client_reg(GPIOIC , 0x000003FF, TRUE);
+ write_client_reg(GPIODATA , 0x00040004, TRUE);
+
+ write_client_reg(GPIODATA , 0x00080008, TRUE);
+ write_client_reg(DRAMPWR , 0x00000001, TRUE);
+ write_client_reg(CLKENB , 0x0000a0eb, TRUE);
+ write_client_reg(PWMCR , 0x00000000, TRUE);
+ mddi_wait(1);
+
+ write_client_reg(SSICTL , 0x00060399, TRUE);
+ write_client_reg(SSITIME , 0x00000100, TRUE);
+ write_client_reg(CNT_DIS , 0x00000002, TRUE);
+ write_client_reg(SSICTL , 0x0006039b, TRUE);
+
+ write_client_reg(SSITX , 0x00000000, TRUE);
+ mddi_wait(7);
+ write_client_reg(SSITX , 0x00000000, TRUE);
+ mddi_wait(7);
+ write_client_reg(SSITX , 0x00000000, TRUE);
+ mddi_wait(7);
+
+ write_client_reg(SSITX , 0x000800BA, TRUE);
+ write_client_reg(SSITX , 0x00000111, TRUE);
+ write_client_reg(SSITX , 0x00080036, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x0008003A, TRUE);
+ write_client_reg(SSITX , 0x00000160, TRUE);
+ write_client_reg(SSITX , 0x000800B1, TRUE);
+ write_client_reg(SSITX , 0x0000015D, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B2, TRUE);
+ write_client_reg(SSITX , 0x00000133, TRUE);
+ write_client_reg(SSITX , 0x000800B3, TRUE);
+ write_client_reg(SSITX , 0x00000122, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B4, TRUE);
+ write_client_reg(SSITX , 0x00000102, TRUE);
+ write_client_reg(SSITX , 0x000800B5, TRUE);
+ write_client_reg(SSITX , 0x0000011E, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B6, TRUE);
+ write_client_reg(SSITX , 0x00000127, TRUE);
+ write_client_reg(SSITX , 0x000800B7, TRUE);
+ write_client_reg(SSITX , 0x00000103, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B9, TRUE);
+ write_client_reg(SSITX , 0x00000124, TRUE);
+ write_client_reg(SSITX , 0x000800BD, TRUE);
+ write_client_reg(SSITX , 0x000001A1, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800BB, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ write_client_reg(SSITX , 0x000800BF, TRUE);
+ write_client_reg(SSITX , 0x00000101, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800BE, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ write_client_reg(SSITX , 0x000800C0, TRUE);
+ write_client_reg(SSITX , 0x00000111, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C1, TRUE);
+ write_client_reg(SSITX , 0x00000111, TRUE);
+ write_client_reg(SSITX , 0x000800C2, TRUE);
+ write_client_reg(SSITX , 0x00000111, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C3, TRUE);
+ write_client_reg(SSITX , 0x00080132, TRUE);
+ write_client_reg(SSITX , 0x00000132, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C4, TRUE);
+ write_client_reg(SSITX , 0x00080132, TRUE);
+ write_client_reg(SSITX , 0x00000132, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C5, TRUE);
+ write_client_reg(SSITX , 0x00080132, TRUE);
+ write_client_reg(SSITX , 0x00000132, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C6, TRUE);
+ write_client_reg(SSITX , 0x00080132, TRUE);
+ write_client_reg(SSITX , 0x00000132, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C7, TRUE);
+ write_client_reg(SSITX , 0x00080164, TRUE);
+ write_client_reg(SSITX , 0x00000145, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800C8, TRUE);
+ write_client_reg(SSITX , 0x00000144, TRUE);
+ write_client_reg(SSITX , 0x000800C9, TRUE);
+ write_client_reg(SSITX , 0x00000152, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800CA, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800EC, TRUE);
+ write_client_reg(SSITX , 0x00080101, TRUE);
+ write_client_reg(SSITX , 0x000001FC, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800CF, TRUE);
+ write_client_reg(SSITX , 0x00000101, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D0, TRUE);
+ write_client_reg(SSITX , 0x00080110, TRUE);
+ write_client_reg(SSITX , 0x00000104, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D1, TRUE);
+ write_client_reg(SSITX , 0x00000101, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D2, TRUE);
+ write_client_reg(SSITX , 0x00080100, TRUE);
+ write_client_reg(SSITX , 0x00000128, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D3, TRUE);
+ write_client_reg(SSITX , 0x00080100, TRUE);
+ write_client_reg(SSITX , 0x00000128, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D4, TRUE);
+ write_client_reg(SSITX , 0x00080126, TRUE);
+ write_client_reg(SSITX , 0x000001A4, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800D5, TRUE);
+ write_client_reg(SSITX , 0x00000120, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800EF, TRUE);
+ write_client_reg(SSITX , 0x00080132, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ mddi_wait(1);
+
+ write_client_reg(BITMAP0 , 0x032001E0, TRUE);
+ write_client_reg(BITMAP1 , 0x032001E0, TRUE);
+ write_client_reg(BITMAP2 , 0x014000F0, TRUE);
+ write_client_reg(BITMAP3 , 0x014000F0, TRUE);
+ write_client_reg(BITMAP4 , 0x014000F0, TRUE);
+ write_client_reg(CLKENB , 0x0000A1EB, TRUE);
+ write_client_reg(PORT_ENB , 0x00000001, TRUE);
+ write_client_reg(PORT , 0x00000004, TRUE);
+ write_client_reg(PXL , 0x00000002, TRUE);
+ write_client_reg(MPLFBUF , 0x00000000, TRUE);
+ write_client_reg(HCYCLE , 0x000000FD, TRUE);
+ write_client_reg(HSW , 0x00000003, TRUE);
+ write_client_reg(HDE_START , 0x00000007, TRUE);
+ write_client_reg(HDE_SIZE , 0x000000EF, TRUE);
+ write_client_reg(VCYCLE , 0x00000325, TRUE);
+ write_client_reg(VSW , 0x00000001, TRUE);
+ write_client_reg(VDE_START , 0x00000003, TRUE);
+ write_client_reg(VDE_SIZE , 0x0000031F, TRUE);
+ write_client_reg(START , 0x00000001, TRUE);
+ mddi_wait(32);
+ write_client_reg(SSITX , 0x000800BC, TRUE);
+ write_client_reg(SSITX , 0x00000180, TRUE);
+ write_client_reg(SSITX , 0x0008003B, TRUE);
+ write_client_reg(SSITX , 0x00000100, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B0, TRUE);
+ write_client_reg(SSITX , 0x00000116, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x000800B8, TRUE);
+ write_client_reg(SSITX , 0x000801FF, TRUE);
+ write_client_reg(SSITX , 0x000001F5, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX , 0x00000011, TRUE);
+ mddi_wait(5);
+ write_client_reg(SSITX , 0x00000029, TRUE);
+ return;
+ }
+
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) {
+ write_client_reg(DPSET0, 0x4BEC0066, TRUE);
+ write_client_reg(DPSET1, 0x00000113, TRUE);
+ write_client_reg(DPSUS, 0x00000000, TRUE);
+ write_client_reg(DPRUN, 0x00000001, TRUE);
+ mddi_wait(14);
+ write_client_reg(SYSCKENA, 0x00000001, TRUE);
+ write_client_reg(CLKENB, 0x000000EF, TRUE);
+ write_client_reg(GPIO_BLOCK_BASE, 0x03FF0000, TRUE);
+ write_client_reg(GPIODIR, 0x0000024D, TRUE);
+ write_client_reg(SYSTEM_BLOCK2_BASE, 0x00000173, TRUE);
+ write_client_reg(GPIOPC, 0x03C300C0, TRUE);
+ write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000000, TRUE);
+ write_client_reg(GPIOIS, 0x00000000, TRUE);
+ write_client_reg(GPIOIEV, 0x00000001, TRUE);
+ write_client_reg(GPIOIC, 0x000003FF, TRUE);
+ write_client_reg(GPIO_BLOCK_BASE, 0x00060006, TRUE);
+ write_client_reg(GPIO_BLOCK_BASE, 0x00080008, TRUE);
+ write_client_reg(GPIO_BLOCK_BASE, 0x02000200, TRUE);
+ write_client_reg(DRAMPWR, 0x00000001, TRUE);
+ write_client_reg(TIMER0CTRL, 0x00000060, TRUE);
+ write_client_reg(PWM_BLOCK_BASE, 0x00001388, TRUE);
+ write_client_reg(PWM0OFF, 0x00001387, TRUE);
+ write_client_reg(TIMER1CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER1LOAD, 0x00001388, TRUE);
+ write_client_reg(PWM1OFF, 0x00001387, TRUE);
+ write_client_reg(TIMER0CTRL, 0x000000E0, TRUE);
+ write_client_reg(TIMER1CTRL, 0x000000E0, TRUE);
+ write_client_reg(PWMCR, 0x00000003, TRUE);
+ mddi_wait(1);
+ write_client_reg(SPI_BLOCK_BASE, 0x00063111, TRUE);
+ write_client_reg(SSITIME, 0x00000100, TRUE);
+ write_client_reg(SPI_BLOCK_BASE, 0x00063113, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(CLKENB, 0x0000A1EF, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(WRSTB, 0x0000003F, TRUE);
+ write_client_reg(RDSTB, 0x00000432, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000000, TRUE);
+ write_client_reg(ASY_DATB, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(10);
+ write_client_reg(ASY_DATA, 0x80000000, TRUE);
+ write_client_reg(ASY_DATB, 0x80000000, TRUE);
+ write_client_reg(ASY_DATC, 0x80000000, TRUE);
+ write_client_reg(ASY_DATD, 0x80000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000009, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000008, TRUE);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(20);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ } else {
+ write_client_reg(DPSET0, 0x4BEC0066, TRUE);
+ write_client_reg(DPSET1, 0x00000113, TRUE);
+ write_client_reg(DPSUS, 0x00000000, TRUE);
+ write_client_reg(DPRUN, 0x00000001, TRUE);
+ mddi_wait(14);
+ write_client_reg(SYSCKENA, 0x00000001, TRUE);
+ write_client_reg(CLKENB, 0x000000EF, TRUE);
+ write_client_reg(GPIODATA, 0x03FF0000, TRUE);
+ write_client_reg(GPIODIR, 0x0000024D, TRUE);
+ write_client_reg(GPIOSEL, 0x00000173, TRUE);
+ write_client_reg(GPIOPC, 0x03C300C0, TRUE);
+ write_client_reg(WKREQ, 0x00000000, TRUE);
+ write_client_reg(GPIOIS, 0x00000000, TRUE);
+ write_client_reg(GPIOIEV, 0x00000001, TRUE);
+ write_client_reg(GPIOIC, 0x000003FF, TRUE);
+ write_client_reg(GPIODATA, 0x00060006, TRUE);
+ write_client_reg(GPIODATA, 0x00080008, TRUE);
+ write_client_reg(GPIODATA, 0x02000200, TRUE);
+
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA) {
+ mddi_wait(400);
+ write_client_reg(DRAMPWR, 0x00000001, TRUE);
+
+ write_client_reg(CNT_DIS, 0x00000002, TRUE);
+ write_client_reg(BITMAP0, 0x01E00320, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ write_client_reg(PORT, 0x00000004, TRUE);
+ write_client_reg(PXL, 0x0000003A, TRUE);
+ write_client_reg(MPLFBUF, 0x00000000, TRUE);
+ write_client_reg(HCYCLE, 0x00000253, TRUE);
+ write_client_reg(HSW, 0x00000003, TRUE);
+ write_client_reg(HDE_START, 0x00000017, TRUE);
+ write_client_reg(HDE_SIZE, 0x0000018F, TRUE);
+ write_client_reg(VCYCLE, 0x000001FF, TRUE);
+ write_client_reg(VSW, 0x00000001, TRUE);
+ write_client_reg(VDE_START, 0x00000003, TRUE);
+ write_client_reg(VDE_SIZE, 0x000001DF, TRUE);
+ write_client_reg(START, 0x00000001, TRUE);
+ mddi_wait(1);
+ write_client_reg(TIMER0CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER0LOAD, 0x00001388, TRUE);
+ write_client_reg(TIMER1CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER1LOAD, 0x00001388, TRUE);
+ write_client_reg(PWM1OFF, 0x00000087, TRUE);
+ } else {
+ write_client_reg(DRAMPWR, 0x00000001, TRUE);
+ write_client_reg(TIMER0CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER0LOAD, 0x00001388, TRUE);
+ write_client_reg(TIMER1CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER1LOAD, 0x00001388, TRUE);
+ write_client_reg(PWM1OFF, 0x00001387, TRUE);
+ }
+
+ write_client_reg(TIMER0CTRL, 0x000000E0, TRUE);
+ write_client_reg(TIMER1CTRL, 0x000000E0, TRUE);
+ write_client_reg(PWMCR, 0x00000003, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSICTL, 0x00000799, TRUE);
+ write_client_reg(SSITIME, 0x00000100, TRUE);
+ write_client_reg(SSICTL, 0x0000079b, TRUE);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000000, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x000800BA, TRUE);
+ write_client_reg(SSITX, 0x00000111, TRUE);
+ write_client_reg(SSITX, 0x00080036, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800BB, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ write_client_reg(SSITX, 0x0008003A, TRUE);
+ write_client_reg(SSITX, 0x00000160, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800BF, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ write_client_reg(SSITX, 0x000800B1, TRUE);
+ write_client_reg(SSITX, 0x0000015D, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800B2, TRUE);
+ write_client_reg(SSITX, 0x00000133, TRUE);
+ write_client_reg(SSITX, 0x000800B3, TRUE);
+ write_client_reg(SSITX, 0x00000122, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800B4, TRUE);
+ write_client_reg(SSITX, 0x00000102, TRUE);
+ write_client_reg(SSITX, 0x000800B5, TRUE);
+ write_client_reg(SSITX, 0x0000011F, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800B6, TRUE);
+ write_client_reg(SSITX, 0x00000128, TRUE);
+ write_client_reg(SSITX, 0x000800B7, TRUE);
+ write_client_reg(SSITX, 0x00000103, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800B9, TRUE);
+ write_client_reg(SSITX, 0x00000120, TRUE);
+ write_client_reg(SSITX, 0x000800BD, TRUE);
+ write_client_reg(SSITX, 0x00000102, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800BE, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ write_client_reg(SSITX, 0x000800C0, TRUE);
+ write_client_reg(SSITX, 0x00000111, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C1, TRUE);
+ write_client_reg(SSITX, 0x00000111, TRUE);
+ write_client_reg(SSITX, 0x000800C2, TRUE);
+ write_client_reg(SSITX, 0x00000111, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C3, TRUE);
+ write_client_reg(SSITX, 0x0008010A, TRUE);
+ write_client_reg(SSITX, 0x0000010A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C4, TRUE);
+ write_client_reg(SSITX, 0x00080160, TRUE);
+ write_client_reg(SSITX, 0x00000160, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C5, TRUE);
+ write_client_reg(SSITX, 0x00080160, TRUE);
+ write_client_reg(SSITX, 0x00000160, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C6, TRUE);
+ write_client_reg(SSITX, 0x00080160, TRUE);
+ write_client_reg(SSITX, 0x00000160, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C7, TRUE);
+ write_client_reg(SSITX, 0x00080133, TRUE);
+ write_client_reg(SSITX, 0x00000143, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800C8, TRUE);
+ write_client_reg(SSITX, 0x00000144, TRUE);
+ write_client_reg(SSITX, 0x000800C9, TRUE);
+ write_client_reg(SSITX, 0x00000133, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800CA, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800EC, TRUE);
+ write_client_reg(SSITX, 0x00080102, TRUE);
+ write_client_reg(SSITX, 0x00000118, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800CF, TRUE);
+ write_client_reg(SSITX, 0x00000101, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D0, TRUE);
+ write_client_reg(SSITX, 0x00080110, TRUE);
+ write_client_reg(SSITX, 0x00000104, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D1, TRUE);
+ write_client_reg(SSITX, 0x00000101, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D2, TRUE);
+ write_client_reg(SSITX, 0x00080100, TRUE);
+ write_client_reg(SSITX, 0x0000013A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D3, TRUE);
+ write_client_reg(SSITX, 0x00080100, TRUE);
+ write_client_reg(SSITX, 0x0000013A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D4, TRUE);
+ write_client_reg(SSITX, 0x00080124, TRUE);
+ write_client_reg(SSITX, 0x0000016E, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x000800D5, TRUE);
+ write_client_reg(SSITX, 0x00000124, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800ED, TRUE);
+ write_client_reg(SSITX, 0x00080101, TRUE);
+ write_client_reg(SSITX, 0x0000010A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D6, TRUE);
+ write_client_reg(SSITX, 0x00000101, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D7, TRUE);
+ write_client_reg(SSITX, 0x00080110, TRUE);
+ write_client_reg(SSITX, 0x0000010A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D8, TRUE);
+ write_client_reg(SSITX, 0x00000101, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800D9, TRUE);
+ write_client_reg(SSITX, 0x00080100, TRUE);
+ write_client_reg(SSITX, 0x00000114, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800DE, TRUE);
+ write_client_reg(SSITX, 0x00080100, TRUE);
+ write_client_reg(SSITX, 0x00000114, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800DF, TRUE);
+ write_client_reg(SSITX, 0x00080112, TRUE);
+ write_client_reg(SSITX, 0x0000013F, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E0, TRUE);
+ write_client_reg(SSITX, 0x0000010B, TRUE);
+ write_client_reg(SSITX, 0x000800E2, TRUE);
+ write_client_reg(SSITX, 0x00000101, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E3, TRUE);
+ write_client_reg(SSITX, 0x00000136, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E4, TRUE);
+ write_client_reg(SSITX, 0x00080100, TRUE);
+ write_client_reg(SSITX, 0x00000103, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E5, TRUE);
+ write_client_reg(SSITX, 0x00080102, TRUE);
+ write_client_reg(SSITX, 0x00000104, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E6, TRUE);
+ write_client_reg(SSITX, 0x00000103, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E7, TRUE);
+ write_client_reg(SSITX, 0x00080104, TRUE);
+ write_client_reg(SSITX, 0x0000010A, TRUE);
+ mddi_wait(2);
+ write_client_reg(SSITX, 0x000800E8, TRUE);
+ write_client_reg(SSITX, 0x00000104, TRUE);
+ write_client_reg(CLKENB, 0x000001EF, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(WRSTB, 0x0000003F, TRUE);
+ write_client_reg(RDSTB, 0x00000432, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000000, TRUE);
+ write_client_reg(ASY_DATB, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(10);
+ write_client_reg(ASY_DATA, 0x80000000, TRUE);
+ write_client_reg(ASY_DATB, 0x80000000, TRUE);
+ write_client_reg(ASY_DATC, 0x80000000, TRUE);
+ write_client_reg(ASY_DATD, 0x80000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000009, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000008, TRUE);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(20);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ }
+
+ mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_STANDBY,
+ TOSHIBA_STATE_PRIM_SEC_READY);
+}
+
+static void toshiba_prim_start(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) {
+ write_client_reg(BITMAP1, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP2, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP3, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP4, 0x00DC00B0, TRUE);
+ write_client_reg(CLKENB, 0x000001EF, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ write_client_reg(PORT, 0x00000016, TRUE);
+ write_client_reg(PXL, 0x00000002, TRUE);
+ write_client_reg(MPLFBUF, 0x00000000, TRUE);
+ write_client_reg(HCYCLE, 0x00000185, TRUE);
+ write_client_reg(HSW, 0x00000018, TRUE);
+ write_client_reg(HDE_START, 0x0000004A, TRUE);
+ write_client_reg(HDE_SIZE, 0x000000EF, TRUE);
+ write_client_reg(VCYCLE, 0x0000028E, TRUE);
+ write_client_reg(VSW, 0x00000004, TRUE);
+ write_client_reg(VDE_START, 0x00000009, TRUE);
+ write_client_reg(VDE_SIZE, 0x0000027F, TRUE);
+ write_client_reg(START, 0x00000001, TRUE);
+ write_client_reg(SYSTEM_BLOCK1_BASE, 0x00000002, TRUE);
+ } else{
+
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ write_client_reg(BITMAP1, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP2, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP3, 0x01E000F0, TRUE);
+ write_client_reg(BITMAP4, 0x00DC00B0, TRUE);
+ write_client_reg(CLKENB, 0x000001EF, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ write_client_reg(PORT, 0x00000004, TRUE);
+ write_client_reg(PXL, 0x00000002, TRUE);
+ write_client_reg(MPLFBUF, 0x00000000, TRUE);
+
+ if (mddi_toshiba_61Hz_refresh) {
+ write_client_reg(HCYCLE, 0x000000FC, TRUE);
+ mddi_toshiba_rows_per_second = 39526;
+ mddi_toshiba_rows_per_refresh = 646;
+ mddi_toshiba_usecs_per_refresh = 16344;
+ } else {
+ write_client_reg(HCYCLE, 0x0000010b, TRUE);
+ mddi_toshiba_rows_per_second = 37313;
+ mddi_toshiba_rows_per_refresh = 646;
+ mddi_toshiba_usecs_per_refresh = 17313;
+ }
+
+ write_client_reg(HSW, 0x00000003, TRUE);
+ write_client_reg(HDE_START, 0x00000007, TRUE);
+ write_client_reg(HDE_SIZE, 0x000000EF, TRUE);
+ write_client_reg(VCYCLE, 0x00000285, TRUE);
+ write_client_reg(VSW, 0x00000001, TRUE);
+ write_client_reg(VDE_START, 0x00000003, TRUE);
+ write_client_reg(VDE_SIZE, 0x0000027F, TRUE);
+ write_client_reg(START, 0x00000001, TRUE);
+ mddi_wait(10);
+ write_client_reg(SSITX, 0x000800BC, TRUE);
+ write_client_reg(SSITX, 0x00000180, TRUE);
+ write_client_reg(SSITX, 0x0008003B, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x000800B0, TRUE);
+ write_client_reg(SSITX, 0x00000116, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x000800B8, TRUE);
+ write_client_reg(SSITX, 0x000801FF, TRUE);
+ write_client_reg(SSITX, 0x000001F5, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x00000011, TRUE);
+ write_client_reg(SSITX, 0x00000029, TRUE);
+ write_client_reg(WKREQ, 0x00000000, TRUE);
+ write_client_reg(WAKEUP, 0x00000000, TRUE);
+ write_client_reg(INTMSK, 0x00000001, TRUE);
+ }
+
+ mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY,
+ TOSHIBA_STATE_PRIM_NORMAL_MODE);
+}
+
+static void toshiba_sec_start(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(CLKENB, 0x000011EF, TRUE);
+ write_client_reg(BITMAP0, 0x028001E0, TRUE);
+ write_client_reg(BITMAP1, 0x00000000, TRUE);
+ write_client_reg(BITMAP2, 0x00000000, TRUE);
+ write_client_reg(BITMAP3, 0x00000000, TRUE);
+ write_client_reg(BITMAP4, 0x00DC00B0, TRUE);
+ write_client_reg(PORT, 0x00000000, TRUE);
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(MPLFBUF, 0x00000004, TRUE);
+ write_client_reg(HCYCLE, 0x0000006B, TRUE);
+ write_client_reg(HSW, 0x00000003, TRUE);
+ write_client_reg(HDE_START, 0x00000007, TRUE);
+ write_client_reg(HDE_SIZE, 0x00000057, TRUE);
+ write_client_reg(VCYCLE, 0x000000E6, TRUE);
+ write_client_reg(VSW, 0x00000001, TRUE);
+ write_client_reg(VDE_START, 0x00000003, TRUE);
+ write_client_reg(VDE_SIZE, 0x000000DB, TRUE);
+ write_client_reg(ASY_DATA, 0x80000001, TRUE);
+ write_client_reg(ASY_DATB, 0x0000011B, TRUE);
+ write_client_reg(ASY_DATC, 0x80000002, TRUE);
+ write_client_reg(ASY_DATD, 0x00000700, TRUE);
+ write_client_reg(ASY_DATE, 0x80000003, TRUE);
+ write_client_reg(ASY_DATF, 0x00000230, TRUE);
+ write_client_reg(ASY_DATG, 0x80000008, TRUE);
+ write_client_reg(ASY_DATH, 0x00000402, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000009, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_DATC, 0x8000000B, TRUE);
+ write_client_reg(ASY_DATD, 0x00000000, TRUE);
+ write_client_reg(ASY_DATE, 0x8000000C, TRUE);
+ write_client_reg(ASY_DATF, 0x00000000, TRUE);
+ write_client_reg(ASY_DATG, 0x8000000D, TRUE);
+ write_client_reg(ASY_DATH, 0x00000409, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x8000000E, TRUE);
+ write_client_reg(ASY_DATB, 0x00000409, TRUE);
+ write_client_reg(ASY_DATC, 0x80000030, TRUE);
+ write_client_reg(ASY_DATD, 0x00000000, TRUE);
+ write_client_reg(ASY_DATE, 0x80000031, TRUE);
+ write_client_reg(ASY_DATF, 0x00000100, TRUE);
+ write_client_reg(ASY_DATG, 0x80000032, TRUE);
+ write_client_reg(ASY_DATH, 0x00000104, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000033, TRUE);
+ write_client_reg(ASY_DATB, 0x00000400, TRUE);
+ write_client_reg(ASY_DATC, 0x80000034, TRUE);
+ write_client_reg(ASY_DATD, 0x00000306, TRUE);
+ write_client_reg(ASY_DATE, 0x80000035, TRUE);
+ write_client_reg(ASY_DATF, 0x00000706, TRUE);
+ write_client_reg(ASY_DATG, 0x80000036, TRUE);
+ write_client_reg(ASY_DATH, 0x00000707, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000037, TRUE);
+ write_client_reg(ASY_DATB, 0x00000004, TRUE);
+ write_client_reg(ASY_DATC, 0x80000038, TRUE);
+ write_client_reg(ASY_DATD, 0x00000000, TRUE);
+ write_client_reg(ASY_DATE, 0x80000039, TRUE);
+ write_client_reg(ASY_DATF, 0x00000000, TRUE);
+ write_client_reg(ASY_DATG, 0x8000003A, TRUE);
+ write_client_reg(ASY_DATH, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000044, TRUE);
+ write_client_reg(ASY_DATB, 0x0000AF00, TRUE);
+ write_client_reg(ASY_DATC, 0x80000045, TRUE);
+ write_client_reg(ASY_DATD, 0x0000DB00, TRUE);
+ write_client_reg(ASY_DATE, 0x08000042, TRUE);
+ write_client_reg(ASY_DATF, 0x0000DB00, TRUE);
+ write_client_reg(ASY_DATG, 0x80000021, TRUE);
+ write_client_reg(ASY_DATH, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(PXL, 0x0000000C, TRUE);
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ write_client_reg(ASY_DATA, 0x80000022, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000003, TRUE);
+ write_client_reg(START, 0x00000001, TRUE);
+ mddi_wait(60);
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000050, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_DATC, 0x80000051, TRUE);
+ write_client_reg(ASY_DATD, 0x00000E00, TRUE);
+ write_client_reg(ASY_DATE, 0x80000052, TRUE);
+ write_client_reg(ASY_DATF, 0x00000D01, TRUE);
+ write_client_reg(ASY_DATG, 0x80000053, TRUE);
+ write_client_reg(ASY_DATH, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ write_client_reg(ASY_DATA, 0x80000058, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_DATC, 0x8000005A, TRUE);
+ write_client_reg(ASY_DATD, 0x00000E01, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000009, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000008, TRUE);
+ write_client_reg(ASY_DATA, 0x80000011, TRUE);
+ write_client_reg(ASY_DATB, 0x00000812, TRUE);
+ write_client_reg(ASY_DATC, 0x80000012, TRUE);
+ write_client_reg(ASY_DATD, 0x00000003, TRUE);
+ write_client_reg(ASY_DATE, 0x80000013, TRUE);
+ write_client_reg(ASY_DATF, 0x00000909, TRUE);
+ write_client_reg(ASY_DATG, 0x80000010, TRUE);
+ write_client_reg(ASY_DATH, 0x00000040, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ mddi_wait(40);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000340, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(60);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00003340, TRUE);
+ write_client_reg(ASY_DATC, 0x80000007, TRUE);
+ write_client_reg(ASY_DATD, 0x00004007, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000009, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000008, TRUE);
+ mddi_wait(1);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004017, TRUE);
+ write_client_reg(ASY_DATC, 0x8000005B, TRUE);
+ write_client_reg(ASY_DATD, 0x00000000, TRUE);
+ write_client_reg(ASY_DATE, 0x80000059, TRUE);
+ write_client_reg(ASY_DATF, 0x00000011, TRUE);
+ write_client_reg(ASY_CMDSET, 0x0000000D, TRUE);
+ write_client_reg(ASY_CMDSET, 0x0000000C, TRUE);
+ mddi_wait(20);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ /* LTPS I/F control */
+ write_client_reg(ASY_DATB, 0x00000019, TRUE);
+ /* Direct cmd transfer enable */
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ /* Direct cmd transfer disable */
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(20);
+ /* Index setting of SUB LCDD */
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ /* LTPS I/F control */
+ write_client_reg(ASY_DATB, 0x00000079, TRUE);
+ /* Direct cmd transfer enable */
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ /* Direct cmd transfer disable */
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(20);
+ /* Index setting of SUB LCDD */
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ /* LTPS I/F control */
+ write_client_reg(ASY_DATB, 0x000003FD, TRUE);
+ /* Direct cmd transfer enable */
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ /* Direct cmd transfer disable */
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(20);
+ mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_SEC_READY,
+ TOSHIBA_STATE_SEC_NORMAL_MODE);
+}
+
+static void toshiba_prim_lcd_off(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) {
+ gordon_disp_off();
+ } else{
+
+ /* Main panel power off (Deep standby in) */
+ write_client_reg(SSITX, 0x000800BC, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ write_client_reg(SSITX, 0x00000028, TRUE);
+ mddi_wait(1);
+ write_client_reg(SSITX, 0x000800B8, TRUE);
+ write_client_reg(SSITX, 0x00000180, TRUE);
+ write_client_reg(SSITX, 0x00000102, TRUE);
+ write_client_reg(SSITX, 0x00000010, TRUE);
+ }
+ write_client_reg(PORT, 0x00000003, TRUE);
+ write_client_reg(REGENB, 0x00000001, TRUE);
+ mddi_wait(1);
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(REGENB, 0x00000001, TRUE);
+ mddi_wait(3);
+ if (TM_GET_PID(mfd->panel.id) != LCD_SHARP_2P4_VGA) {
+ write_client_reg(SSITX, 0x000800B0, TRUE);
+ write_client_reg(SSITX, 0x00000100, TRUE);
+ }
+ mddi_toshiba_state_transition(TOSHIBA_STATE_PRIM_NORMAL_MODE,
+ TOSHIBA_STATE_PRIM_SEC_STANDBY);
+}
+
+static void toshiba_sec_lcd_off(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004016, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000019, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x0000000B, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000002, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(4);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000300, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(4);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004004, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(PORT, 0x00000000, TRUE);
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ write_client_reg(PORT_ENB, 0x00000001, TRUE);
+ write_client_reg(REGENB, 0x00000001, TRUE);
+ mddi_toshiba_state_transition(TOSHIBA_STATE_SEC_NORMAL_MODE,
+ TOSHIBA_STATE_PRIM_SEC_STANDBY);
+}
+
+static void toshiba_sec_cont_update_start(struct msm_fb_data_type *mfd)
+{
+
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(INTMASK, 0x00000001, TRUE);
+ write_client_reg(TTBUSSEL, 0x0000000B, TRUE);
+ write_client_reg(MONI, 0x00000008, TRUE);
+ write_client_reg(CLKENB, 0x000000EF, TRUE);
+ write_client_reg(CLKENB, 0x000010EF, TRUE);
+ write_client_reg(CLKENB, 0x000011EF, TRUE);
+ write_client_reg(BITMAP4, 0x00DC00B0, TRUE);
+ write_client_reg(HCYCLE, 0x0000006B, TRUE);
+ write_client_reg(HSW, 0x00000003, TRUE);
+ write_client_reg(HDE_START, 0x00000002, TRUE);
+ write_client_reg(HDE_SIZE, 0x00000057, TRUE);
+ write_client_reg(VCYCLE, 0x000000E6, TRUE);
+ write_client_reg(VSW, 0x00000001, TRUE);
+ write_client_reg(VDE_START, 0x00000003, TRUE);
+ write_client_reg(VDE_SIZE, 0x000000DB, TRUE);
+ write_client_reg(WRSTB, 0x00000015, TRUE);
+ write_client_reg(MPLFBUF, 0x00000004, TRUE);
+ write_client_reg(ASY_DATA, 0x80000021, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_DATC, 0x80000022, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000007, TRUE);
+ write_client_reg(PXL, 0x00000089, TRUE);
+ write_client_reg(VSYNIF, 0x00000001, TRUE);
+ mddi_wait(2);
+}
+
+static void toshiba_sec_cont_update_stop(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ mddi_wait(3);
+ write_client_reg(SRST, 0x00000002, TRUE);
+ mddi_wait(3);
+ write_client_reg(SRST, 0x00000003, TRUE);
+}
+
+static void toshiba_sec_backlight_on(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(TIMER0CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER0LOAD, 0x00001388, TRUE);
+ write_client_reg(PWM0OFF, 0x00000001, TRUE);
+ write_client_reg(TIMER1CTRL, 0x00000060, TRUE);
+ write_client_reg(TIMER1LOAD, 0x00001388, TRUE);
+ write_client_reg(PWM1OFF, 0x00001387, TRUE);
+ write_client_reg(TIMER0CTRL, 0x000000E0, TRUE);
+ write_client_reg(TIMER1CTRL, 0x000000E0, TRUE);
+ write_client_reg(PWMCR, 0x00000003, TRUE);
+}
+
+static void toshiba_sec_sleep_in(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004016, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000019, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x0000000B, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000002, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(4);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000300, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(4);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000000, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004004, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(PORT, 0x00000000, TRUE);
+ write_client_reg(PXL, 0x00000000, TRUE);
+ write_client_reg(START, 0x00000000, TRUE);
+ write_client_reg(REGENB, 0x00000001, TRUE);
+ /* Sleep in sequence */
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000302, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+}
+
+static void toshiba_sec_sleep_out(struct msm_fb_data_type *mfd)
+{
+ if (TM_GET_PID(mfd->panel.id) == LCD_TOSHIBA_2P4_WVGA_PT)
+ return;
+
+ write_client_reg(VSYNIF, 0x00000000, TRUE);
+ write_client_reg(PORT_ENB, 0x00000002, TRUE);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000300, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ /* Display ON sequence */
+ write_client_reg(ASY_DATA, 0x80000011, TRUE);
+ write_client_reg(ASY_DATB, 0x00000812, TRUE);
+ write_client_reg(ASY_DATC, 0x80000012, TRUE);
+ write_client_reg(ASY_DATD, 0x00000003, TRUE);
+ write_client_reg(ASY_DATE, 0x80000013, TRUE);
+ write_client_reg(ASY_DATF, 0x00000909, TRUE);
+ write_client_reg(ASY_DATG, 0x80000010, TRUE);
+ write_client_reg(ASY_DATH, 0x00000040, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000001, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000000, TRUE);
+ mddi_wait(4);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00000340, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(6);
+ write_client_reg(ASY_DATA, 0x80000010, TRUE);
+ write_client_reg(ASY_DATB, 0x00003340, TRUE);
+ write_client_reg(ASY_DATC, 0x80000007, TRUE);
+ write_client_reg(ASY_DATD, 0x00004007, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000009, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000008, TRUE);
+ mddi_wait(1);
+ write_client_reg(ASY_DATA, 0x80000007, TRUE);
+ write_client_reg(ASY_DATB, 0x00004017, TRUE);
+ write_client_reg(ASY_DATC, 0x8000005B, TRUE);
+ write_client_reg(ASY_DATD, 0x00000000, TRUE);
+ write_client_reg(ASY_DATE, 0x80000059, TRUE);
+ write_client_reg(ASY_DATF, 0x00000011, TRUE);
+ write_client_reg(ASY_CMDSET, 0x0000000D, TRUE);
+ write_client_reg(ASY_CMDSET, 0x0000000C, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000019, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x00000079, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+ write_client_reg(ASY_DATA, 0x80000059, TRUE);
+ write_client_reg(ASY_DATB, 0x000003FD, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000005, TRUE);
+ write_client_reg(ASY_CMDSET, 0x00000004, TRUE);
+ mddi_wait(2);
+}
+
+static void mddi_toshiba_lcd_set_backlight(struct msm_fb_data_type *mfd)
+{
+ int32 level;
+ int ret = -EPERM;
+ int max = mfd->panel_info.bl_max;
+ int min = mfd->panel_info.bl_min;
+
+ if (mddi_toshiba_pdata && mddi_toshiba_pdata->pmic_backlight) {
+ ret = mddi_toshiba_pdata->pmic_backlight(mfd->bl_level);
+ if (!ret)
+ return;
+ }
+
+ if (ret && mddi_toshiba_pdata && mddi_toshiba_pdata->backlight_level) {
+ level = mddi_toshiba_pdata->backlight_level(mfd->bl_level,
+ max, min);
+
+ if (level < 0)
+ return;
+
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA)
+ write_client_reg(TIMER0LOAD, 0x00001388, TRUE);
+ } else {
+ if (!max)
+ level = 0;
+ else
+ level = (mfd->bl_level * 4999) / max;
+ }
+
+ write_client_reg(PWM0OFF, level, TRUE);
+}
+
+static void mddi_toshiba_vsync_set_handler(msm_fb_vsync_handler_type handler, /* ISR to be executed */
+ void *arg)
+{
+ boolean error = FALSE;
+ unsigned long flags;
+
+ /* Disable interrupts */
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+ /* INTLOCK(); */
+
+ if (mddi_toshiba_vsync_handler != NULL) {
+ error = TRUE;
+ } else {
+ /* Register the handler for this particular GROUP interrupt source */
+ mddi_toshiba_vsync_handler = handler;
+ mddi_toshiba_vsync_handler_arg = arg;
+ }
+
+ /* Restore interrupts */
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+ /* MDDI_INTFREE(); */
+ if (error) {
+ MDDI_MSG_ERR("MDDI: Previous Vsync handler never called\n");
+ } else {
+ /* Enable the vsync wakeup */
+ mddi_queue_register_write(INTMSK, 0x0000, FALSE, 0);
+
+ mddi_toshiba_vsync_attempts = 1;
+ mddi_vsync_detect_enabled = TRUE;
+ }
+} /* mddi_toshiba_vsync_set_handler */
+
+static void mddi_toshiba_lcd_vsync_detected(boolean detected)
+{
+ /* static timetick_type start_time = 0; */
+ static struct timeval start_time;
+ static boolean first_time = TRUE;
+ /* uint32 mdp_cnt_val = 0; */
+ /* timetick_type elapsed_us; */
+ struct timeval now;
+ uint32 elapsed_us;
+ uint32 num_vsyncs;
+
+ if ((detected) || (mddi_toshiba_vsync_attempts > 5)) {
+ if ((detected) && (mddi_toshiba_monitor_refresh_value)) {
+ /* if (start_time != 0) */
+ if (!first_time) {
+ jiffies_to_timeval(jiffies, &now);
+ elapsed_us =
+ (now.tv_sec - start_time.tv_sec) * 1000000 +
+ now.tv_usec - start_time.tv_usec;
+ /*
+ * LCD is configured for a refresh every usecs,
+ * so to determine the number of vsyncs that
+ * have occurred since the last measurement
+ * add half that to the time difference and
+ * divide by the refresh rate.
+ */
+ num_vsyncs = (elapsed_us +
+ (mddi_toshiba_usecs_per_refresh >>
+ 1)) /
+ mddi_toshiba_usecs_per_refresh;
+ /*
+ * LCD is configured for * hsyncs (rows) per
+ * refresh cycle. Calculate new rows_per_second
+ * value based upon these new measurements.
+ * MDP can update with this new value.
+ */
+ mddi_toshiba_rows_per_second =
+ (mddi_toshiba_rows_per_refresh * 1000 *
+ num_vsyncs) / (elapsed_us / 1000);
+ }
+ /* start_time = timetick_get(); */
+ first_time = FALSE;
+ jiffies_to_timeval(jiffies, &start_time);
+ if (mddi_toshiba_report_refresh_measurements) {
+ (void)mddi_queue_register_read_int(VPOS,
+ &mddi_toshiba_curr_vpos);
+ /* mdp_cnt_val = MDP_LINE_COUNT; */
+ }
+ }
+ /* if detected = TRUE, client initiated wakeup was detected */
+ if (mddi_toshiba_vsync_handler != NULL) {
+ (*mddi_toshiba_vsync_handler)
+ (mddi_toshiba_vsync_handler_arg);
+ mddi_toshiba_vsync_handler = NULL;
+ }
+ mddi_vsync_detect_enabled = FALSE;
+ mddi_toshiba_vsync_attempts = 0;
+ /* need to disable the interrupt wakeup */
+ if (!mddi_queue_register_write_int(INTMSK, 0x0001))
+ MDDI_MSG_ERR("Vsync interrupt disable failed!\n");
+ if (!detected) {
+ /* give up after 5 failed attempts but show error */
+ MDDI_MSG_NOTICE("Vsync detection failed!\n");
+ } else if ((mddi_toshiba_monitor_refresh_value) &&
+ (mddi_toshiba_report_refresh_measurements)) {
+ MDDI_MSG_NOTICE(" Last Line Counter=%d!\n",
+ mddi_toshiba_curr_vpos);
+ /* MDDI_MSG_NOTICE(" MDP Line Counter=%d!\n",mdp_cnt_val); */
+ MDDI_MSG_NOTICE(" Lines Per Second=%d!\n",
+ mddi_toshiba_rows_per_second);
+ }
+ /* clear the interrupt */
+ if (!mddi_queue_register_write_int(INTFLG, 0x0001))
+ MDDI_MSG_ERR("Vsync interrupt clear failed!\n");
+ } else {
+ /* if detected = FALSE, we woke up from hibernation, but did not
+ * detect client initiated wakeup.
+ */
+ mddi_toshiba_vsync_attempts++;
+ }
+}
+
+static void mddi_toshiba_prim_init(struct msm_fb_data_type *mfd)
+{
+
+ switch (toshiba_state) {
+ case TOSHIBA_STATE_PRIM_SEC_READY:
+ break;
+ case TOSHIBA_STATE_OFF:
+ toshiba_state = TOSHIBA_STATE_PRIM_SEC_STANDBY;
+ toshiba_common_initial_setup(mfd);
+ break;
+ case TOSHIBA_STATE_PRIM_SEC_STANDBY:
+ toshiba_common_initial_setup(mfd);
+ break;
+ case TOSHIBA_STATE_SEC_NORMAL_MODE:
+ toshiba_sec_cont_update_stop(mfd);
+ toshiba_sec_sleep_in(mfd);
+ toshiba_sec_sleep_out(mfd);
+ toshiba_sec_lcd_off(mfd);
+ toshiba_common_initial_setup(mfd);
+ break;
+ default:
+ MDDI_MSG_ERR("mddi_toshiba_prim_init from state %d\n",
+ toshiba_state);
+ }
+
+ toshiba_prim_start(mfd);
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA)
+ gordon_disp_init();
+ mddi_host_write_pix_attr_reg(0x00C3);
+}
+
+static void mddi_toshiba_sec_init(struct msm_fb_data_type *mfd)
+{
+
+ switch (toshiba_state) {
+ case TOSHIBA_STATE_PRIM_SEC_READY:
+ break;
+ case TOSHIBA_STATE_PRIM_SEC_STANDBY:
+ toshiba_common_initial_setup(mfd);
+ break;
+ case TOSHIBA_STATE_PRIM_NORMAL_MODE:
+ toshiba_prim_lcd_off(mfd);
+ toshiba_common_initial_setup(mfd);
+ break;
+ default:
+ MDDI_MSG_ERR("mddi_toshiba_sec_init from state %d\n",
+ toshiba_state);
+ }
+
+ toshiba_sec_start(mfd);
+ toshiba_sec_backlight_on(mfd);
+ toshiba_sec_cont_update_start(mfd);
+ mddi_host_write_pix_attr_reg(0x0400);
+}
+
+static void mddi_toshiba_lcd_powerdown(struct msm_fb_data_type *mfd)
+{
+ switch (toshiba_state) {
+ case TOSHIBA_STATE_PRIM_SEC_READY:
+ mddi_toshiba_prim_init(mfd);
+ mddi_toshiba_lcd_powerdown(mfd);
+ return;
+ case TOSHIBA_STATE_PRIM_SEC_STANDBY:
+ break;
+ case TOSHIBA_STATE_PRIM_NORMAL_MODE:
+ toshiba_prim_lcd_off(mfd);
+ break;
+ case TOSHIBA_STATE_SEC_NORMAL_MODE:
+ toshiba_sec_cont_update_stop(mfd);
+ toshiba_sec_sleep_in(mfd);
+ toshiba_sec_sleep_out(mfd);
+ toshiba_sec_lcd_off(mfd);
+ break;
+ default:
+ MDDI_MSG_ERR("mddi_toshiba_lcd_powerdown from state %d\n",
+ toshiba_state);
+ }
+}
+
+static int mddi_sharpgordon_firsttime = 1;
+
+static int mddi_toshiba_lcd_on(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ mfd = platform_get_drvdata(pdev);
+ if (!mfd)
+ return -ENODEV;
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (TM_GET_DID(mfd->panel.id) == TOSHIBA_VGA_PRIM)
+ mddi_toshiba_prim_init(mfd);
+ else
+ mddi_toshiba_sec_init(mfd);
+ if (TM_GET_PID(mfd->panel.id) == LCD_SHARP_2P4_VGA) {
+ if (mddi_sharpgordon_firsttime) {
+ mddi_sharpgordon_firsttime = 0;
+ write_client_reg(REGENB, 0x00000001, TRUE);
+ }
+ }
+ return 0;
+}
+
+static int mddi_toshiba_lcd_off(struct platform_device *pdev)
+{
+ mddi_toshiba_lcd_powerdown(platform_get_drvdata(pdev));
+ return 0;
+}
+
+static int __init mddi_toshiba_lcd_probe(struct platform_device *pdev)
+{
+ if (pdev->id == 0) {
+ mddi_toshiba_pdata = pdev->dev.platform_data;
+ return 0;
+ }
+
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = mddi_toshiba_lcd_probe,
+ .driver = {
+ .name = "mddi_toshiba",
+ },
+};
+
+static struct msm_fb_panel_data toshiba_panel_data = {
+ .on = mddi_toshiba_lcd_on,
+ .off = mddi_toshiba_lcd_off,
+};
+
+static int ch_used[3];
+
+int mddi_toshiba_device_register(struct msm_panel_info *pinfo,
+ u32 channel, u32 panel)
+{
+ struct platform_device *pdev = NULL;
+ int ret;
+
+ if ((channel >= 3) || ch_used[channel])
+ return -ENODEV;
+
+ if ((channel != TOSHIBA_VGA_PRIM) &&
+ mddi_toshiba_pdata && mddi_toshiba_pdata->panel_num)
+ if (mddi_toshiba_pdata->panel_num() < 2)
+ return -ENODEV;
+
+ ch_used[channel] = TRUE;
+
+ pdev = platform_device_alloc("mddi_toshiba", (panel << 8)|channel);
+ if (!pdev)
+ return -ENOMEM;
+
+ if (channel == TOSHIBA_VGA_PRIM) {
+ toshiba_panel_data.set_backlight =
+ mddi_toshiba_lcd_set_backlight;
+
+ if (pinfo->lcd.vsync_enable) {
+ toshiba_panel_data.set_vsync_notifier =
+ mddi_toshiba_vsync_set_handler;
+ mddi_lcd.vsync_detected =
+ mddi_toshiba_lcd_vsync_detected;
+ }
+ } else {
+ toshiba_panel_data.set_backlight = NULL;
+ toshiba_panel_data.set_vsync_notifier = NULL;
+ }
+
+ toshiba_panel_data.panel_info = *pinfo;
+
+ ret = platform_device_add_data(pdev, &toshiba_panel_data,
+ sizeof(toshiba_panel_data));
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_add_data failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ ret = platform_device_add(pdev);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: platform_device_register failed!\n", __func__);
+ goto err_device_put;
+ }
+
+ return 0;
+
+err_device_put:
+ platform_device_put(pdev);
+ return ret;
+}
+
+static int __init mddi_toshiba_lcd_init(void)
+{
+ return platform_driver_register(&this_driver);
+}
+
+module_init(mddi_toshiba_lcd_init);
diff --git a/drivers/staging/msm/mddi_toshiba.h b/drivers/staging/msm/mddi_toshiba.h
new file mode 100644
index 000000000000..2d22b9a2c413
--- /dev/null
+++ b/drivers/staging/msm/mddi_toshiba.h
@@ -0,0 +1,52 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDDI_TOSHIBA_H
+#define MDDI_TOSHIBA_H
+
+#define TOSHIBA_VGA_PRIM 1
+#define TOSHIBA_VGA_SECD 2
+
+#define LCD_TOSHIBA_2P4_VGA 0
+#define LCD_TOSHIBA_2P4_WVGA 1
+#define LCD_TOSHIBA_2P4_WVGA_PT 2
+#define LCD_SHARP_2P4_VGA 3
+
+#define GPIO_BLOCK_BASE 0x150000
+#define SYSTEM_BLOCK2_BASE 0x170000
+
+#define GPIODIR (GPIO_BLOCK_BASE|0x04)
+#define GPIOSEL (SYSTEM_BLOCK2_BASE|0x00)
+#define GPIOPC (GPIO_BLOCK_BASE|0x28)
+#define GPIODATA (GPIO_BLOCK_BASE|0x00)
+
+#define write_client_reg(__X, __Y, __Z) {\
+ mddi_queue_register_write(__X, __Y, TRUE, 0);\
+}
+
+#endif /* MDDI_TOSHIBA_H */
diff --git a/drivers/staging/msm/mddi_toshiba_vga.c b/drivers/staging/msm/mddi_toshiba_vga.c
new file mode 100644
index 000000000000..7e61d3a5b8f1
--- /dev/null
+++ b/drivers/staging/msm/mddi_toshiba_vga.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+#include "mddi_toshiba.h"
+
+static uint32 read_client_reg(uint32 addr)
+{
+ uint32 val;
+ mddi_queue_register_read(addr, &val, TRUE, 0);
+ return val;
+}
+
+static uint32 toshiba_lcd_gpio_read(void)
+{
+ uint32 val;
+
+ write_client_reg(GPIODIR, 0x0000000C, TRUE);
+ write_client_reg(GPIOSEL, 0x00000000, TRUE);
+ write_client_reg(GPIOSEL, 0x00000000, TRUE);
+ write_client_reg(GPIOPC, 0x03CF00C0, TRUE);
+ val = read_client_reg(GPIODATA) & 0x2C0;
+
+ return val;
+}
+
+static u32 mddi_toshiba_panel_detect(void)
+{
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+ uint32 lcd_gpio;
+ u32 mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
+
+ /* Toshiba display requires larger drive_lo value */
+ mddi_host_reg_out(DRIVE_LO, 0x0050);
+
+ lcd_gpio = toshiba_lcd_gpio_read();
+ switch (lcd_gpio) {
+ case 0x0080:
+ mddi_toshiba_lcd = LCD_SHARP_2P4_VGA;
+ break;
+
+ case 0x00C0:
+ default:
+ mddi_toshiba_lcd = LCD_TOSHIBA_2P4_VGA;
+ break;
+ }
+
+ return mddi_toshiba_lcd;
+}
+
+static int __init mddi_toshiba_vga_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+ u32 panel;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ u32 id;
+
+ ret = msm_fb_detect_client("mddi_toshiba_vga");
+ if (ret == -ENODEV)
+ return 0;
+
+ if (ret) {
+ id = mddi_get_client_id();
+ if ((id >> 16) != 0xD263)
+ return 0;
+ }
+#endif
+
+ panel = mddi_toshiba_panel_detect();
+
+ pinfo.xres = 480;
+ pinfo.yres = 640;
+ pinfo.type = MDDI_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.lcd.vsync_enable = TRUE;
+ pinfo.lcd.refx100 = 6118;
+ pinfo.lcd.v_back_porch = 6;
+ pinfo.lcd.v_front_porch = 0;
+ pinfo.lcd.v_pulse_width = 0;
+ pinfo.lcd.hw_vsync_mode = FALSE;
+ pinfo.lcd.vsync_notifier_period = (1 * HZ);
+ pinfo.bl_max = 99;
+ pinfo.bl_min = 1;
+ pinfo.clk_rate = 122880000;
+ pinfo.clk_min = 120000000;
+ pinfo.clk_max = 200000000;
+ pinfo.fb_num = 2;
+
+ ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM, panel);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+ return ret;
+ }
+
+ pinfo.xres = 176;
+ pinfo.yres = 220;
+ pinfo.type = MDDI_PANEL;
+ pinfo.pdest = DISPLAY_2;
+ pinfo.mddi.vdopkt = 0x400;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.clk_rate = 122880000;
+ pinfo.clk_min = 120000000;
+ pinfo.clk_max = 200000000;
+ pinfo.fb_num = 2;
+
+ ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_SECD, panel);
+ if (ret)
+ printk(KERN_WARNING
+ "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(mddi_toshiba_vga_init);
diff --git a/drivers/staging/msm/mddi_toshiba_wvga.c b/drivers/staging/msm/mddi_toshiba_wvga.c
new file mode 100644
index 000000000000..557b0f08faf8
--- /dev/null
+++ b/drivers/staging/msm/mddi_toshiba_wvga.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddi_toshiba.h"
+
+static int __init mddi_toshiba_wvga_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ if (msm_fb_detect_client("mddi_toshiba_wvga"))
+ return 0;
+#endif
+
+ pinfo.xres = 800;
+ pinfo.yres = 480;
+ pinfo.pdest = DISPLAY_2;
+ pinfo.type = MDDI_PANEL;
+ pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.lcd.vsync_enable = TRUE;
+ pinfo.lcd.refx100 = 6118;
+ pinfo.lcd.v_back_porch = 6;
+ pinfo.lcd.v_front_porch = 0;
+ pinfo.lcd.v_pulse_width = 0;
+ pinfo.lcd.hw_vsync_mode = FALSE;
+ pinfo.lcd.vsync_notifier_period = (1 * HZ);
+ pinfo.bl_max = 4;
+ pinfo.bl_min = 1;
+ pinfo.clk_rate = 192000000;
+ pinfo.clk_min = 190000000;
+ pinfo.clk_max = 200000000;
+ pinfo.fb_num = 2;
+
+ ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
+ LCD_TOSHIBA_2P4_WVGA);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+ return ret;
+ }
+
+ return ret;
+}
+
+module_init(mddi_toshiba_wvga_init);
diff --git a/drivers/staging/msm/mddi_toshiba_wvga_pt.c b/drivers/staging/msm/mddi_toshiba_wvga_pt.c
new file mode 100644
index 000000000000..fc7d4e0d294f
--- /dev/null
+++ b/drivers/staging/msm/mddi_toshiba_wvga_pt.c
@@ -0,0 +1,64 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+#include "mddi_toshiba.h"
+
+static int __init mddi_toshiba_wvga_pt_init(void)
+{
+ int ret;
+ struct msm_panel_info pinfo;
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ uint id;
+
+ ret = msm_fb_detect_client("mddi_toshiba_wvga_pt");
+ if (ret == -ENODEV)
+ return 0;
+
+ if (ret) {
+ id = mddi_get_client_id();
+ if (id != 0xd2638722)
+ return 0;
+ }
+#endif
+
+ pinfo.xres = 480;
+ pinfo.yres = 800;
+ pinfo.type = MDDI_PANEL;
+ pinfo.pdest = DISPLAY_1;
+ pinfo.mddi.vdopkt = MDDI_DEFAULT_PRIM_PIX_ATTR;
+ pinfo.wait_cycle = 0;
+ pinfo.bpp = 18;
+ pinfo.lcd.vsync_enable = FALSE;
+ pinfo.bl_max = 15;
+ pinfo.bl_min = 1;
+ pinfo.clk_rate = 192000000;
+ pinfo.clk_min = 190000000;
+ pinfo.clk_max = 200000000;
+ pinfo.fb_num = 2;
+
+ ret = mddi_toshiba_device_register(&pinfo, TOSHIBA_VGA_PRIM,
+ LCD_TOSHIBA_2P4_WVGA_PT);
+ if (ret)
+ printk(KERN_ERR "%s: failed to register device!\n", __func__);
+
+ return ret;
+}
+
+module_init(mddi_toshiba_wvga_pt_init);
diff --git a/drivers/staging/msm/mddihost.c b/drivers/staging/msm/mddihost.c
new file mode 100644
index 000000000000..c6c1ee4eda05
--- /dev/null
+++ b/drivers/staging/msm/mddihost.c
@@ -0,0 +1,377 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+#include <linux/clk.h>
+#include <mach/clk.h>
+
+struct semaphore mddi_host_mutex;
+
+struct clk *mddi_io_clk;
+static boolean mddi_host_powered = FALSE;
+static boolean mddi_host_initialized = FALSE;
+extern uint32 *mddi_reg_read_value_ptr;
+
+mddi_lcd_func_type mddi_lcd;
+
+extern mddi_client_capability_type mddi_client_capability_pkt;
+
+#ifdef FEATURE_MDDI_HITACHI
+extern void mddi_hitachi_window_adjust(uint16 x1,
+ uint16 x2, uint16 y1, uint16 y2);
+#endif
+
+extern void mddi_toshiba_lcd_init(void);
+
+#ifdef FEATURE_MDDI_S6D0142
+extern void mddi_s6d0142_lcd_init(void);
+extern void mddi_s6d0142_window_adjust(uint16 x1,
+ uint16 x2,
+ uint16 y1,
+ uint16 y2,
+ mddi_llist_done_cb_type done_cb);
+#endif
+
+void mddi_init(void)
+{
+ if (mddi_host_initialized)
+ return;
+
+ mddi_host_initialized = TRUE;
+
+ init_MUTEX(&mddi_host_mutex);
+
+ if (!mddi_host_powered) {
+ down(&mddi_host_mutex);
+ mddi_host_init(MDDI_HOST_PRIM);
+ mddi_host_powered = TRUE;
+ up(&mddi_host_mutex);
+ mdelay(10);
+ }
+}
+
+int mddi_host_register_read(uint32 reg_addr,
+ uint32 *reg_value_ptr, boolean wait, mddi_host_type host) {
+ mddi_linked_list_type *curr_llist_ptr;
+ mddi_register_access_packet_type *regacc_pkt_ptr;
+ uint16 curr_llist_idx;
+ int ret = 0;
+
+ if (in_interrupt())
+ MDDI_MSG_CRIT("Called from ISR context\n");
+
+ if (!mddi_host_powered) {
+ MDDI_MSG_ERR("MDDI powered down!\n");
+ mddi_init();
+ }
+
+ down(&mddi_host_mutex);
+
+ mddi_reg_read_value_ptr = reg_value_ptr;
+ curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE);
+ if (curr_llist_idx == UNASSIGNED_INDEX) {
+ up(&mddi_host_mutex);
+
+ /* need to change this to some sort of wait */
+ MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n");
+ return -EINVAL;
+ }
+
+ curr_llist_ptr = &llist_extern[host][curr_llist_idx];
+ curr_llist_ptr->link_controller_flags = 0x11;
+ curr_llist_ptr->packet_header_count = 14;
+ curr_llist_ptr->packet_data_count = 0;
+
+ curr_llist_ptr->next_packet_pointer = NULL;
+ curr_llist_ptr->packet_data_pointer = NULL;
+ curr_llist_ptr->reserved = 0;
+
+ regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
+
+ regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
+ regacc_pkt_ptr->packet_type = 146; /* register access packet */
+ regacc_pkt_ptr->bClient_ID = 0;
+ regacc_pkt_ptr->read_write_info = 0x8001;
+ regacc_pkt_ptr->register_address = reg_addr;
+
+ /* now adjust pointers */
+ mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
+ NULL, host);
+ /* need to check if we can write the pointer or not */
+
+ up(&mddi_host_mutex);
+
+ if (wait) {
+ int wait_ret;
+
+ mddi_linked_list_notify_type *llist_notify_ptr;
+ llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
+ wait_ret = wait_for_completion_timeout(
+ &(llist_notify_ptr->done_comp), 5 * HZ);
+
+ if (wait_ret <= 0)
+ ret = -EBUSY;
+
+ if (wait_ret < 0)
+ printk(KERN_ERR "%s: failed to wait for completion!\n",
+ __func__);
+ else if (!wait_ret)
+ printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
+ }
+
+ MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr);
+
+ return ret;
+} /* mddi_host_register_read */
+
+int mddi_host_register_write(uint32 reg_addr,
+ uint32 reg_val, enum mddi_data_packet_size_type packet_size,
+ boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
+ mddi_linked_list_type *curr_llist_ptr;
+ mddi_linked_list_type *curr_llist_dma_ptr;
+ mddi_register_access_packet_type *regacc_pkt_ptr;
+ uint16 curr_llist_idx;
+ int ret = 0;
+
+ if (in_interrupt())
+ MDDI_MSG_CRIT("Called from ISR context\n");
+
+ if (!mddi_host_powered) {
+ MDDI_MSG_ERR("MDDI powered down!\n");
+ mddi_init();
+ }
+
+ down(&mddi_host_mutex);
+
+ curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE);
+ curr_llist_ptr = &llist_extern[host][curr_llist_idx];
+ curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
+
+ curr_llist_ptr->link_controller_flags = 1;
+ curr_llist_ptr->packet_header_count = 14;
+ curr_llist_ptr->packet_data_count = 4;
+
+ curr_llist_ptr->next_packet_pointer = NULL;
+ curr_llist_ptr->reserved = 0;
+
+ regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
+
+ regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count +
+ (uint16)packet_size;
+ regacc_pkt_ptr->packet_type = 146; /* register access packet */
+ regacc_pkt_ptr->bClient_ID = 0;
+ regacc_pkt_ptr->read_write_info = 0x0001;
+ regacc_pkt_ptr->register_address = reg_addr;
+ regacc_pkt_ptr->register_data_list = reg_val;
+
+ MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n",
+ regacc_pkt_ptr->register_address,
+ regacc_pkt_ptr->register_data_list);
+
+ regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
+ curr_llist_ptr->packet_data_pointer =
+ (void *)(&regacc_pkt_ptr->register_data_list);
+
+ /* now adjust pointers */
+ mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait,
+ done_cb, host);
+
+ up(&mddi_host_mutex);
+
+ if (wait) {
+ int wait_ret;
+
+ mddi_linked_list_notify_type *llist_notify_ptr;
+ llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx];
+ wait_ret = wait_for_completion_timeout(
+ &(llist_notify_ptr->done_comp), 5 * HZ);
+
+ if (wait_ret <= 0)
+ ret = -EBUSY;
+
+ if (wait_ret < 0)
+ printk(KERN_ERR "%s: failed to wait for completion!\n",
+ __func__);
+ else if (!wait_ret)
+ printk(KERN_ERR "%s: Timed out waiting!\n", __func__);
+ }
+
+ return ret;
+} /* mddi_host_register_write */
+
+boolean mddi_host_register_read_int
+ (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) {
+ mddi_linked_list_type *curr_llist_ptr;
+ mddi_register_access_packet_type *regacc_pkt_ptr;
+ uint16 curr_llist_idx;
+
+ if (!in_interrupt())
+ MDDI_MSG_CRIT("Called from TASK context\n");
+
+ if (!mddi_host_powered) {
+ MDDI_MSG_ERR("MDDI powered down!\n");
+ return FALSE;
+ }
+
+ if (down_trylock(&mddi_host_mutex) != 0)
+ return FALSE;
+
+ mddi_reg_read_value_ptr = reg_value_ptr;
+ curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE);
+ if (curr_llist_idx == UNASSIGNED_INDEX) {
+ up(&mddi_host_mutex);
+ return FALSE;
+ }
+
+ curr_llist_ptr = &llist_extern[host][curr_llist_idx];
+ curr_llist_ptr->link_controller_flags = 0x11;
+ curr_llist_ptr->packet_header_count = 14;
+ curr_llist_ptr->packet_data_count = 0;
+
+ curr_llist_ptr->next_packet_pointer = NULL;
+ curr_llist_ptr->packet_data_pointer = NULL;
+ curr_llist_ptr->reserved = 0;
+
+ regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
+
+ regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count;
+ regacc_pkt_ptr->packet_type = 146; /* register access packet */
+ regacc_pkt_ptr->bClient_ID = 0;
+ regacc_pkt_ptr->read_write_info = 0x8001;
+ regacc_pkt_ptr->register_address = reg_addr;
+
+ /* now adjust pointers */
+ mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
+ NULL, host);
+ /* need to check if we can write the pointer or not */
+
+ up(&mddi_host_mutex);
+
+ return TRUE;
+
+} /* mddi_host_register_read */
+
+boolean mddi_host_register_write_int
+ (uint32 reg_addr,
+ uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) {
+ mddi_linked_list_type *curr_llist_ptr;
+ mddi_linked_list_type *curr_llist_dma_ptr;
+ mddi_register_access_packet_type *regacc_pkt_ptr;
+ uint16 curr_llist_idx;
+
+ if (!in_interrupt())
+ MDDI_MSG_CRIT("Called from TASK context\n");
+
+ if (!mddi_host_powered) {
+ MDDI_MSG_ERR("MDDI powered down!\n");
+ return FALSE;
+ }
+
+ if (down_trylock(&mddi_host_mutex) != 0)
+ return FALSE;
+
+ curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE);
+ if (curr_llist_idx == UNASSIGNED_INDEX) {
+ up(&mddi_host_mutex);
+ return FALSE;
+ }
+
+ curr_llist_ptr = &llist_extern[host][curr_llist_idx];
+ curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx];
+
+ curr_llist_ptr->link_controller_flags = 1;
+ curr_llist_ptr->packet_header_count = 14;
+ curr_llist_ptr->packet_data_count = 4;
+
+ curr_llist_ptr->next_packet_pointer = NULL;
+ curr_llist_ptr->reserved = 0;
+
+ regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt;
+
+ regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4;
+ regacc_pkt_ptr->packet_type = 146; /* register access packet */
+ regacc_pkt_ptr->bClient_ID = 0;
+ regacc_pkt_ptr->read_write_info = 0x0001;
+ regacc_pkt_ptr->register_address = reg_addr;
+ regacc_pkt_ptr->register_data_list = reg_val;
+
+ regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt;
+ curr_llist_ptr->packet_data_pointer =
+ (void *)(&(regacc_pkt_ptr->register_data_list));
+
+ /* now adjust pointers */
+ mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE,
+ done_cb, host);
+ up(&mddi_host_mutex);
+
+ return TRUE;
+
+} /* mddi_host_register_write */
+
+void mddi_wait(uint16 time_ms)
+{
+ mdelay(time_ms);
+}
+
+void mddi_client_lcd_vsync_detected(boolean detected)
+{
+ if (mddi_lcd.vsync_detected)
+ (*mddi_lcd.vsync_detected) (detected);
+}
+
+/* extended version of function includes done callback */
+void mddi_window_adjust_ext(struct msm_fb_data_type *mfd,
+ uint16 x1,
+ uint16 x2,
+ uint16 y1,
+ uint16 y2, mddi_llist_done_cb_type done_cb)
+{
+#ifdef FEATURE_MDDI_HITACHI
+ if (mfd->panel.id == HITACHI)
+ mddi_hitachi_window_adjust(x1, x2, y1, y2);
+#elif defined(FEATURE_MDDI_S6D0142)
+ if (mfd->panel.id == MDDI_LCD_S6D0142)
+ mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb);
+#else
+ /* Do nothing then... except avoid lint/compiler warnings */
+ (void)x1;
+ (void)x2;
+ (void)y1;
+ (void)y2;
+ (void)done_cb;
+#endif
+}
+
+void mddi_window_adjust(struct msm_fb_data_type *mfd,
+ uint16 x1, uint16 x2, uint16 y1, uint16 y2)
+{
+ mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL);
+}
diff --git a/drivers/staging/msm/mddihost.h b/drivers/staging/msm/mddihost.h
new file mode 100644
index 000000000000..20b817841c4a
--- /dev/null
+++ b/drivers/staging/msm/mddihost.h
@@ -0,0 +1,225 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDDIHOST_H
+#define MDDIHOST_H
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+
+#include "msm_fb_panel.h"
+
+#undef FEATURE_MDDI_MC4
+#undef FEATURE_MDDI_S6D0142
+#undef FEATURE_MDDI_HITACHI
+#define FEATURE_MDDI_SHARP
+#define FEATURE_MDDI_TOSHIBA
+#undef FEATURE_MDDI_E751
+#define FEATURE_MDDI_CORONA
+#define FEATURE_MDDI_PRISM
+
+#define T_MSM7500
+
+typedef enum {
+ format_16bpp,
+ format_18bpp,
+ format_24bpp
+} mddi_video_format;
+
+typedef enum {
+ MDDI_LCD_NONE = 0,
+ MDDI_LCD_MC4,
+ MDDI_LCD_S6D0142,
+ MDDI_LCD_SHARP,
+ MDDI_LCD_E751,
+ MDDI_LCD_CORONA,
+ MDDI_LCD_HITACHI,
+ MDDI_LCD_TOSHIBA,
+ MDDI_LCD_PRISM,
+ MDDI_LCD_TP2,
+ MDDI_NUM_LCD_TYPES,
+ MDDI_LCD_DEFAULT = MDDI_LCD_TOSHIBA
+} mddi_lcd_type;
+
+typedef enum {
+ MDDI_HOST_PRIM = 0,
+ MDDI_HOST_EXT,
+ MDDI_NUM_HOST_CORES
+} mddi_host_type;
+
+typedef enum {
+ MDDI_DRIVER_RESET, /* host core registers have not been written. */
+ MDDI_DRIVER_DISABLED, /* registers written, interrupts disabled. */
+ MDDI_DRIVER_ENABLED /* registers written, interrupts enabled. */
+} mddi_host_driver_state_type;
+
+typedef enum {
+ MDDI_GPIO_INT_0 = 0,
+ MDDI_GPIO_INT_1,
+ MDDI_GPIO_INT_2,
+ MDDI_GPIO_INT_3,
+ MDDI_GPIO_INT_4,
+ MDDI_GPIO_INT_5,
+ MDDI_GPIO_INT_6,
+ MDDI_GPIO_INT_7,
+ MDDI_GPIO_INT_8,
+ MDDI_GPIO_INT_9,
+ MDDI_GPIO_INT_10,
+ MDDI_GPIO_INT_11,
+ MDDI_GPIO_INT_12,
+ MDDI_GPIO_INT_13,
+ MDDI_GPIO_INT_14,
+ MDDI_GPIO_INT_15,
+ MDDI_GPIO_NUM_INTS
+} mddi_gpio_int_type;
+
+enum mddi_data_packet_size_type {
+ MDDI_DATA_PACKET_4_BYTES = 4,
+ MDDI_DATA_PACKET_8_BYTES = 8,
+ MDDI_DATA_PACKET_12_BYTES = 12,
+ MDDI_DATA_PACKET_16_BYTES = 16,
+ MDDI_DATA_PACKET_24_BYTES = 24
+};
+
+typedef struct {
+ uint32 addr;
+ uint32 value;
+} mddi_reg_write_type;
+
+boolean mddi_vsync_set_handler(msm_fb_vsync_handler_type handler, void *arg);
+
+typedef void (*mddi_llist_done_cb_type) (void);
+
+typedef void (*mddi_rev_handler_type) (void *);
+
+boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type);
+
+#define MDDI_DEFAULT_PRIM_PIX_ATTR 0xC3
+#define MDDI_DEFAULT_SECD_PIX_ATTR 0xC0
+
+typedef int gpio_int_polarity_type;
+typedef int gpio_int_handler_type;
+
+typedef struct {
+ void (*vsync_detected) (boolean);
+} mddi_lcd_func_type;
+
+extern mddi_lcd_func_type mddi_lcd;
+void mddi_init(void);
+
+void mddi_powerdown(void);
+
+void mddi_host_start_ext_display(void);
+void mddi_host_stop_ext_display(void);
+
+extern spinlock_t mddi_host_spin_lock;
+#ifdef T_MSM7500
+void mddi_reset(void);
+#ifdef FEATURE_DUAL_PROC_MODEM_DISPLAY
+void mddi_host_switch_proc_control(boolean on);
+#endif
+#endif
+void mddi_host_exit_power_collapse(void);
+
+void mddi_queue_splash_screen
+ (void *buf_ptr,
+ boolean clear_area,
+ int16 src_width,
+ int16 src_starting_row,
+ int16 src_starting_column,
+ int16 num_of_rows,
+ int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
+
+void mddi_queue_image
+ (void *buf_ptr,
+ uint8 stereo_video,
+ boolean clear_area,
+ int16 src_width,
+ int16 src_starting_row,
+ int16 src_starting_column,
+ int16 num_of_rows,
+ int16 num_of_columns, int16 dst_starting_row, int16 dst_starting_column);
+
+int mddi_host_register_read
+ (uint32 reg_addr,
+ uint32 *reg_value_ptr, boolean wait, mddi_host_type host_idx);
+int mddi_host_register_write
+ (uint32 reg_addr, uint32 reg_val,
+ enum mddi_data_packet_size_type packet_size,
+ boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host);
+boolean mddi_host_register_write_int
+ (uint32 reg_addr,
+ uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host);
+boolean mddi_host_register_read_int
+ (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host_idx);
+void mddi_queue_register_write_static
+ (uint32 reg_addr,
+ uint32 reg_val, boolean wait, mddi_llist_done_cb_type done_cb);
+void mddi_queue_static_window_adjust
+ (const mddi_reg_write_type *reg_write,
+ uint16 num_writes, mddi_llist_done_cb_type done_cb);
+
+#define mddi_queue_register_read(reg, val_ptr, wait, sig) \
+ mddi_host_register_read(reg, val_ptr, wait, MDDI_HOST_PRIM)
+#define mddi_queue_register_write(reg, val, wait, sig) \
+ mddi_host_register_write(reg, val, MDDI_DATA_PACKET_4_BYTES,\
+ wait, NULL, MDDI_HOST_PRIM)
+#define mddi_queue_register_write_extn(reg, val, pkt_size, wait, sig) \
+ mddi_host_register_write(reg, val, pkt_size, \
+ wait, NULL, MDDI_HOST_PRIM)
+#define mddi_queue_register_write_int(reg, val) \
+ mddi_host_register_write_int(reg, val, NULL, MDDI_HOST_PRIM)
+#define mddi_queue_register_read_int(reg, val_ptr) \
+ mddi_host_register_read_int(reg, val_ptr, MDDI_HOST_PRIM)
+#define mddi_queue_register_writes(reg_ptr, val, wait, sig) \
+ mddi_host_register_writes(reg_ptr, val, wait, sig, MDDI_HOST_PRIM)
+
+void mddi_wait(uint16 time_ms);
+void mddi_assign_max_pkt_dimensions(uint16 image_cols,
+ uint16 image_rows,
+ uint16 bpp,
+ uint16 *max_cols, uint16 * max_rows);
+uint16 mddi_assign_pkt_height(uint16 pkt_width, uint16 pkt_height, uint16 bpp);
+void mddi_queue_reverse_encapsulation(boolean wait);
+void mddi_disable(int lock);
+#endif /* MDDIHOST_H */
diff --git a/drivers/staging/msm/mddihost_e.c b/drivers/staging/msm/mddihost_e.c
new file mode 100644
index 000000000000..7de5eda71ce3
--- /dev/null
+++ b/drivers/staging/msm/mddihost_e.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+#include <linux/clk.h>
+#include <mach/clk.h>
+
+extern struct semaphore mddi_host_mutex;
+static boolean mddi_host_ext_powered = FALSE;
+
+void mddi_host_start_ext_display(void)
+{
+ down(&mddi_host_mutex);
+
+ if (!mddi_host_ext_powered) {
+ mddi_host_init(MDDI_HOST_EXT);
+
+ mddi_host_ext_powered = TRUE;
+ }
+
+ up(&mddi_host_mutex);
+}
+
+void mddi_host_stop_ext_display(void)
+{
+ down(&mddi_host_mutex);
+
+ if (mddi_host_ext_powered) {
+ mddi_host_powerdown(MDDI_HOST_EXT);
+
+ mddi_host_ext_powered = FALSE;
+ }
+
+ up(&mddi_host_mutex);
+}
diff --git a/drivers/staging/msm/mddihosti.c b/drivers/staging/msm/mddihosti.c
new file mode 100644
index 000000000000..f9d6e91e8d5d
--- /dev/null
+++ b/drivers/staging/msm/mddihosti.c
@@ -0,0 +1,2239 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+
+#include "msm_fb_panel.h"
+#include "mddihost.h"
+#include "mddihosti.h"
+
+#define FEATURE_MDDI_UNDERRUN_RECOVERY
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+static void mddi_read_rev_packet(byte *data_ptr);
+#endif
+
+struct timer_list mddi_host_timer;
+
+#define MDDI_DEFAULT_TIMER_LENGTH 5000 /* 5 seconds */
+uint32 mddi_rtd_frequency = 60000; /* send RTD every 60 seconds */
+uint32 mddi_client_status_frequency = 60000; /* get status pkt every 60 secs */
+
+boolean mddi_vsync_detect_enabled = FALSE;
+mddi_gpio_info_type mddi_gpio;
+
+uint32 mddi_host_core_version;
+boolean mddi_debug_log_statistics = FALSE;
+/* #define FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION */
+/* default to TRUE in case MDP does not vote */
+static boolean mddi_host_mdp_active_flag = TRUE;
+static uint32 mddi_log_stats_counter;
+uint32 mddi_log_stats_frequency = 4000;
+
+#define MDDI_DEFAULT_REV_PKT_SIZE 0x20
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+static boolean mddi_rev_ptr_workaround = TRUE;
+static uint32 mddi_reg_read_retry;
+static uint32 mddi_reg_read_retry_max = 20;
+static boolean mddi_enable_reg_read_retry = TRUE;
+static boolean mddi_enable_reg_read_retry_once = FALSE;
+
+#define MDDI_MAX_REV_PKT_SIZE 0x60
+
+#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60
+
+#define MDDI_VIDEO_REV_PKT_SIZE 0x40
+#define MDDI_REV_BUFFER_SIZE MDDI_MAX_REV_PKT_SIZE
+static byte rev_packet_data[MDDI_MAX_REV_PKT_SIZE];
+#endif /* FEATURE_MDDI_DISABLE_REVERSE */
+/* leave these variables so graphics will compile */
+
+#define MDDI_MAX_REV_DATA_SIZE 128
+/*lint -d__align(x) */
+boolean mddi_debug_clear_rev_data = TRUE;
+
+uint32 *mddi_reg_read_value_ptr;
+
+mddi_client_capability_type mddi_client_capability_pkt;
+static boolean mddi_client_capability_request = FALSE;
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+
+#define MAX_MDDI_REV_HANDLERS 2
+#define INVALID_PKT_TYPE 0xFFFF
+
+typedef struct {
+ mddi_rev_handler_type handler; /* ISR to be executed */
+ uint16 pkt_type;
+} mddi_rev_pkt_handler_type;
+static mddi_rev_pkt_handler_type mddi_rev_pkt_handler[MAX_MDDI_REV_HANDLERS] =
+ { {NULL, INVALID_PKT_TYPE}, {NULL, INVALID_PKT_TYPE} };
+
+static boolean mddi_rev_encap_user_request = FALSE;
+static mddi_linked_list_notify_type mddi_rev_user;
+
+spinlock_t mddi_host_spin_lock;
+extern uint32 mdp_in_processing;
+#endif
+
+typedef enum {
+ MDDI_REV_IDLE
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ , MDDI_REV_REG_READ_ISSUED,
+ MDDI_REV_REG_READ_SENT,
+ MDDI_REV_ENCAP_ISSUED,
+ MDDI_REV_STATUS_REQ_ISSUED,
+ MDDI_REV_CLIENT_CAP_ISSUED
+#endif
+} mddi_rev_link_state_type;
+
+typedef enum {
+ MDDI_LINK_DISABLED,
+ MDDI_LINK_HIBERNATING,
+ MDDI_LINK_ACTIVATING,
+ MDDI_LINK_ACTIVE
+} mddi_host_link_state_type;
+
+typedef struct {
+ uint32 count;
+ uint32 in_count;
+ uint32 disp_req_count;
+ uint32 state_change_count;
+ uint32 ll_done_count;
+ uint32 rev_avail_count;
+ uint32 error_count;
+ uint32 rev_encap_count;
+ uint32 llist_ptr_write_1;
+ uint32 llist_ptr_write_2;
+} mddi_host_int_type;
+
+typedef struct {
+ uint32 fwd_crc_count;
+ uint32 rev_crc_count;
+ uint32 pri_underflow;
+ uint32 sec_underflow;
+ uint32 rev_overflow;
+ uint32 pri_overwrite;
+ uint32 sec_overwrite;
+ uint32 rev_overwrite;
+ uint32 dma_failure;
+ uint32 rtd_failure;
+ uint32 reg_read_failure;
+#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
+ uint32 pri_underrun_detected;
+#endif
+} mddi_host_stat_type;
+
+typedef struct {
+ uint32 rtd_cnt;
+ uint32 rev_enc_cnt;
+ uint32 vid_cnt;
+ uint32 reg_acc_cnt;
+ uint32 cli_stat_cnt;
+ uint32 cli_cap_cnt;
+ uint32 reg_read_cnt;
+ uint32 link_active_cnt;
+ uint32 link_hibernate_cnt;
+ uint32 vsync_response_cnt;
+ uint32 fwd_crc_cnt;
+ uint32 rev_crc_cnt;
+} mddi_log_params_struct_type;
+
+typedef struct {
+ uint32 rtd_value;
+ uint32 rtd_counter;
+ uint32 client_status_cnt;
+ boolean rev_ptr_written;
+ uint8 *rev_ptr_start;
+ uint8 *rev_ptr_curr;
+ uint32 mddi_rev_ptr_write_val;
+ dma_addr_t rev_data_dma_addr;
+ uint16 rev_pkt_size;
+ mddi_rev_link_state_type rev_state;
+ mddi_host_link_state_type link_state;
+ mddi_host_driver_state_type driver_state;
+ boolean disable_hibernation;
+ uint32 saved_int_reg;
+ uint32 saved_int_en;
+ mddi_linked_list_type *llist_ptr;
+ dma_addr_t llist_dma_addr;
+ mddi_linked_list_type *llist_dma_ptr;
+ uint32 *rev_data_buf;
+ struct completion mddi_llist_avail_comp;
+ boolean mddi_waiting_for_llist_avail;
+ mddi_host_int_type int_type;
+ mddi_host_stat_type stats;
+ mddi_log_params_struct_type log_parms;
+ mddi_llist_info_type llist_info;
+ mddi_linked_list_notify_type llist_notify[MDDI_MAX_NUM_LLIST_ITEMS];
+} mddi_host_cntl_type;
+
+static mddi_host_type mddi_curr_host = MDDI_HOST_PRIM;
+static mddi_host_cntl_type mhctl[MDDI_NUM_HOST_CORES];
+mddi_linked_list_type *llist_extern[MDDI_NUM_HOST_CORES];
+mddi_linked_list_type *llist_dma_extern[MDDI_NUM_HOST_CORES];
+mddi_linked_list_notify_type *llist_extern_notify[MDDI_NUM_HOST_CORES];
+static mddi_log_params_struct_type prev_parms[MDDI_NUM_HOST_CORES];
+
+extern uint32 mdp_total_vdopkts;
+
+static boolean mddi_host_io_clock_on = FALSE;
+static boolean mddi_host_hclk_on = FALSE;
+
+int int_mddi_pri_flag = FALSE;
+int int_mddi_ext_flag = FALSE;
+
+static void mddi_report_errors(uint32 int_reg)
+{
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if (int_reg & MDDI_INT_PRI_UNDERFLOW) {
+ pmhctl->stats.pri_underflow++;
+ MDDI_MSG_ERR("!!! MDDI Primary Underflow !!!\n");
+ }
+ if (int_reg & MDDI_INT_SEC_UNDERFLOW) {
+ pmhctl->stats.sec_underflow++;
+ MDDI_MSG_ERR("!!! MDDI Secondary Underflow !!!\n");
+ }
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (int_reg & MDDI_INT_REV_OVERFLOW) {
+ pmhctl->stats.rev_overflow++;
+ MDDI_MSG_ERR("!!! MDDI Reverse Overflow !!!\n");
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val);
+
+ }
+ if (int_reg & MDDI_INT_CRC_ERROR)
+ MDDI_MSG_ERR("!!! MDDI Reverse CRC Error !!!\n");
+#endif
+ if (int_reg & MDDI_INT_PRI_OVERWRITE) {
+ pmhctl->stats.pri_overwrite++;
+ MDDI_MSG_ERR("!!! MDDI Primary Overwrite !!!\n");
+ }
+ if (int_reg & MDDI_INT_SEC_OVERWRITE) {
+ pmhctl->stats.sec_overwrite++;
+ MDDI_MSG_ERR("!!! MDDI Secondary Overwrite !!!\n");
+ }
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (int_reg & MDDI_INT_REV_OVERWRITE) {
+ pmhctl->stats.rev_overwrite++;
+ /* This will show up normally and is not a problem */
+ MDDI_MSG_DEBUG("MDDI Reverse Overwrite!\n");
+ }
+ if (int_reg & MDDI_INT_RTD_FAILURE) {
+ mddi_host_reg_outm(INTEN, MDDI_INT_RTD_FAILURE, 0);
+ pmhctl->stats.rtd_failure++;
+ MDDI_MSG_ERR("!!! MDDI RTD Failure !!!\n");
+ }
+#endif
+ if (int_reg & MDDI_INT_DMA_FAILURE) {
+ pmhctl->stats.dma_failure++;
+ MDDI_MSG_ERR("!!! MDDI DMA Abort !!!\n");
+ }
+}
+
+static void mddi_host_enable_io_clock(void)
+{
+ if (!MDDI_HOST_IS_IO_CLOCK_ON)
+ MDDI_HOST_ENABLE_IO_CLOCK;
+}
+
+static void mddi_host_enable_hclk(void)
+{
+
+ if (!MDDI_HOST_IS_HCLK_ON)
+ MDDI_HOST_ENABLE_HCLK;
+}
+
+static void mddi_host_disable_io_clock(void)
+{
+#ifndef FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE
+ if (MDDI_HOST_IS_IO_CLOCK_ON)
+ MDDI_HOST_DISABLE_IO_CLOCK;
+#endif
+}
+
+static void mddi_host_disable_hclk(void)
+{
+#ifndef FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
+ if (MDDI_HOST_IS_HCLK_ON)
+ MDDI_HOST_DISABLE_HCLK;
+#endif
+}
+
+static void mddi_vote_to_sleep(mddi_host_type host_idx, boolean sleep)
+{
+ uint16 vote_mask;
+
+ if (host_idx == MDDI_HOST_PRIM)
+ vote_mask = 0x01;
+ else
+ vote_mask = 0x02;
+}
+
+static void mddi_report_state_change(uint32 int_reg)
+{
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if ((pmhctl->saved_int_reg & MDDI_INT_IN_HIBERNATION) &&
+ (pmhctl->saved_int_reg & MDDI_INT_LINK_ACTIVE)) {
+ /* recover from condition where the io_clock was turned off by the
+ clock driver during a transition to hibernation. The io_clock
+ disable is to prevent MDP/MDDI underruns when changing ARM
+ clock speeds. In the process of halting the ARM, the hclk
+ divider needs to be set to 1. When it is set to 1, there is
+ a small time (usecs) when hclk is off or slow, and this can
+ cause an underrun. To prevent the underrun, clock driver turns
+ off the MDDI io_clock before making the change. */
+ mddi_host_reg_out(CMD, MDDI_CMD_POWERUP);
+ }
+
+ if (int_reg & MDDI_INT_LINK_ACTIVE) {
+ pmhctl->link_state = MDDI_LINK_ACTIVE;
+ pmhctl->log_parms.link_active_cnt++;
+ pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL);
+ MDDI_MSG_DEBUG("!!! MDDI Active RTD:0x%x!!!\n",
+ pmhctl->rtd_value);
+ /* now interrupt on hibernation */
+ mddi_host_reg_outm(INTEN,
+ (MDDI_INT_IN_HIBERNATION |
+ MDDI_INT_LINK_ACTIVE),
+ MDDI_INT_IN_HIBERNATION);
+
+#ifdef DEBUG_MDDIHOSTI
+ /* if gpio interrupt is enabled, start polling at fastest
+ * registered rate
+ */
+ if (mddi_gpio.polling_enabled) {
+ timer_reg(&mddi_gpio_poll_timer,
+ mddi_gpio_poll_timer_cb, 0, mddi_gpio.polling_interval, 0);
+ }
+#endif
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (mddi_rev_ptr_workaround) {
+ /* HW CR: need to reset reverse register stuff */
+ pmhctl->rev_ptr_written = FALSE;
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ }
+#endif
+ /* vote on sleep */
+ mddi_vote_to_sleep(host_idx, FALSE);
+
+ if (host_idx == MDDI_HOST_PRIM) {
+ if (mddi_vsync_detect_enabled) {
+ /*
+ * Indicate to client specific code that vsync
+ * was enabled, but we did not detect a client
+ * intiated wakeup. The client specific
+ * handler can either reassert vsync detection,
+ * or treat this as a valid vsync.
+ */
+ mddi_client_lcd_vsync_detected(FALSE);
+ pmhctl->log_parms.vsync_response_cnt++;
+ }
+ }
+ }
+ if (int_reg & MDDI_INT_IN_HIBERNATION) {
+ pmhctl->link_state = MDDI_LINK_HIBERNATING;
+ pmhctl->log_parms.link_hibernate_cnt++;
+ MDDI_MSG_DEBUG("!!! MDDI Hibernating !!!\n");
+ /* now interrupt on link_active */
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ mddi_host_reg_outm(INTEN,
+ (MDDI_INT_MDDI_IN |
+ MDDI_INT_IN_HIBERNATION |
+ MDDI_INT_LINK_ACTIVE),
+ MDDI_INT_LINK_ACTIVE);
+#else
+ mddi_host_reg_outm(INTEN,
+ (MDDI_INT_MDDI_IN |
+ MDDI_INT_IN_HIBERNATION |
+ MDDI_INT_LINK_ACTIVE),
+ (MDDI_INT_MDDI_IN | MDDI_INT_LINK_ACTIVE));
+
+ pmhctl->rtd_counter = mddi_rtd_frequency;
+
+ if (pmhctl->rev_state != MDDI_REV_IDLE) {
+ /* a rev_encap will not wake up the link, so we do that here */
+ pmhctl->link_state = MDDI_LINK_ACTIVATING;
+ mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
+ }
+#endif
+
+ if (pmhctl->disable_hibernation) {
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
+ mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
+ pmhctl->link_state = MDDI_LINK_ACTIVATING;
+ }
+#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
+ if ((pmhctl->llist_info.transmitting_start_idx !=
+ UNASSIGNED_INDEX)
+ &&
+ ((pmhctl->
+ saved_int_reg & (MDDI_INT_PRI_LINK_LIST_DONE |
+ MDDI_INT_PRI_PTR_READ)) ==
+ MDDI_INT_PRI_PTR_READ)) {
+ mddi_linked_list_type *llist_dma;
+ llist_dma = pmhctl->llist_dma_ptr;
+ /*
+ * All indications are that we have not received a
+ * linked list done interrupt, due to an underrun
+ * condition. Recovery attempt is to send again.
+ */
+ dma_coherent_pre_ops();
+ /* Write to primary pointer register again */
+ mddi_host_reg_out(PRI_PTR,
+ &llist_dma[pmhctl->llist_info.
+ transmitting_start_idx]);
+ pmhctl->stats.pri_underrun_detected++;
+ }
+#endif
+
+ /* vote on sleep */
+ if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
+ mddi_vote_to_sleep(host_idx, TRUE);
+ }
+
+#ifdef DEBUG_MDDIHOSTI
+ /* need to stop polling timer */
+ if (mddi_gpio.polling_enabled) {
+ (void) timer_clr(&mddi_gpio_poll_timer, T_NONE);
+ }
+#endif
+ }
+}
+
+void mddi_host_timer_service(unsigned long data)
+{
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ unsigned long flags;
+#endif
+ mddi_host_type host_idx;
+ mddi_host_cntl_type *pmhctl;
+
+ unsigned long time_ms = MDDI_DEFAULT_TIMER_LENGTH;
+ init_timer(&mddi_host_timer);
+ mddi_host_timer.function = mddi_host_timer_service;
+ mddi_host_timer.data = 0;
+
+ mddi_host_timer.expires = jiffies + ((time_ms * HZ) / 1000);
+ add_timer(&mddi_host_timer);
+
+ for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES;
+ host_idx++) {
+ pmhctl = &(mhctl[host_idx]);
+ mddi_log_stats_counter += (uint32) time_ms;
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ pmhctl->rtd_counter += (uint32) time_ms;
+ pmhctl->client_status_cnt += (uint32) time_ms;
+
+ if (host_idx == MDDI_HOST_PRIM) {
+ if (pmhctl->client_status_cnt >=
+ mddi_client_status_frequency) {
+ if ((pmhctl->link_state ==
+ MDDI_LINK_HIBERNATING)
+ && (pmhctl->client_status_cnt >
+ mddi_client_status_frequency)) {
+ /*
+ * special case where we are hibernating
+ * and mddi_host_isr is not firing, so
+ * kick the link so that the status can
+ * be retrieved
+ */
+
+ /* need to wake up link before issuing
+ * rev encap command
+ */
+ MDDI_MSG_INFO("wake up link!\n");
+ spin_lock_irqsave(&mddi_host_spin_lock,
+ flags);
+ mddi_host_enable_hclk();
+ mddi_host_enable_io_clock();
+ pmhctl->link_state =
+ MDDI_LINK_ACTIVATING;
+ mddi_host_reg_out(CMD,
+ MDDI_CMD_LINK_ACTIVE);
+ spin_unlock_irqrestore
+ (&mddi_host_spin_lock, flags);
+ } else
+ if ((pmhctl->link_state == MDDI_LINK_ACTIVE)
+ && pmhctl->disable_hibernation) {
+ /*
+ * special case where we have disabled
+ * hibernation and mddi_host_isr
+ * is not firing, so enable interrupt
+ * for no pkts pending, which will
+ * generate an interrupt
+ */
+ MDDI_MSG_INFO("kick isr!\n");
+ spin_lock_irqsave(&mddi_host_spin_lock,
+ flags);
+ mddi_host_enable_hclk();
+ mddi_host_reg_outm(INTEN,
+ MDDI_INT_NO_CMD_PKTS_PEND,
+ MDDI_INT_NO_CMD_PKTS_PEND);
+ spin_unlock_irqrestore
+ (&mddi_host_spin_lock, flags);
+ }
+ }
+ }
+#endif /* #ifndef FEATURE_MDDI_DISABLE_REVERSE */
+ }
+
+ /* Check if logging is turned on */
+ for (host_idx = MDDI_HOST_PRIM; host_idx < MDDI_NUM_HOST_CORES;
+ host_idx++) {
+ mddi_log_params_struct_type *prev_ptr = &(prev_parms[host_idx]);
+ pmhctl = &(mhctl[host_idx]);
+
+ if (mddi_debug_log_statistics) {
+
+ /* get video pkt count from MDP, since MDDI sw cannot know this */
+ pmhctl->log_parms.vid_cnt = mdp_total_vdopkts;
+
+ if (mddi_log_stats_counter >= mddi_log_stats_frequency) {
+ /* mddi_log_stats_counter = 0; */
+ if (mddi_debug_log_statistics) {
+ MDDI_MSG_NOTICE
+ ("MDDI Statistics since last report:\n");
+ MDDI_MSG_NOTICE(" Packets sent:\n");
+ MDDI_MSG_NOTICE
+ (" %d RTD packet(s)\n",
+ pmhctl->log_parms.rtd_cnt -
+ prev_ptr->rtd_cnt);
+ if (prev_ptr->rtd_cnt !=
+ pmhctl->log_parms.rtd_cnt) {
+ unsigned long flags;
+ spin_lock_irqsave
+ (&mddi_host_spin_lock,
+ flags);
+ mddi_host_enable_hclk();
+ pmhctl->rtd_value =
+ mddi_host_reg_in(RTD_VAL);
+ spin_unlock_irqrestore
+ (&mddi_host_spin_lock,
+ flags);
+ MDDI_MSG_NOTICE
+ (" RTD value=%d\n",
+ pmhctl->rtd_value);
+ }
+ MDDI_MSG_NOTICE
+ (" %d VIDEO packets\n",
+ pmhctl->log_parms.vid_cnt -
+ prev_ptr->vid_cnt);
+ MDDI_MSG_NOTICE
+ (" %d Register Access packets\n",
+ pmhctl->log_parms.reg_acc_cnt -
+ prev_ptr->reg_acc_cnt);
+ MDDI_MSG_NOTICE
+ (" %d Reverse Encapsulation packet(s)\n",
+ pmhctl->log_parms.rev_enc_cnt -
+ prev_ptr->rev_enc_cnt);
+ if (prev_ptr->rev_enc_cnt !=
+ pmhctl->log_parms.rev_enc_cnt) {
+ /* report # of reverse CRC errors */
+ MDDI_MSG_NOTICE
+ (" %d reverse CRC errors detected\n",
+ pmhctl->log_parms.
+ rev_crc_cnt -
+ prev_ptr->rev_crc_cnt);
+ }
+ MDDI_MSG_NOTICE
+ (" Packets received:\n");
+ MDDI_MSG_NOTICE
+ (" %d Client Status packets",
+ pmhctl->log_parms.cli_stat_cnt -
+ prev_ptr->cli_stat_cnt);
+ if (prev_ptr->cli_stat_cnt !=
+ pmhctl->log_parms.cli_stat_cnt) {
+ MDDI_MSG_NOTICE
+ (" %d forward CRC errors reported\n",
+ pmhctl->log_parms.
+ fwd_crc_cnt -
+ prev_ptr->fwd_crc_cnt);
+ }
+ MDDI_MSG_NOTICE
+ (" %d Register Access Read packets\n",
+ pmhctl->log_parms.reg_read_cnt -
+ prev_ptr->reg_read_cnt);
+
+ if (pmhctl->link_state ==
+ MDDI_LINK_ACTIVE) {
+ MDDI_MSG_NOTICE
+ (" Current Link Status: Active\n");
+ } else
+ if ((pmhctl->link_state ==
+ MDDI_LINK_HIBERNATING)
+ || (pmhctl->link_state ==
+ MDDI_LINK_ACTIVATING)) {
+ MDDI_MSG_NOTICE
+ (" Current Link Status: Hibernation\n");
+ } else {
+ MDDI_MSG_NOTICE
+ (" Current Link Status: Inactive\n");
+ }
+ MDDI_MSG_NOTICE
+ (" Active state entered %d times\n",
+ pmhctl->log_parms.link_active_cnt -
+ prev_ptr->link_active_cnt);
+ MDDI_MSG_NOTICE
+ (" Hibernation state entered %d times\n",
+ pmhctl->log_parms.
+ link_hibernate_cnt -
+ prev_ptr->link_hibernate_cnt);
+ }
+ }
+ prev_parms[host_idx] = pmhctl->log_parms;
+ }
+ }
+ if (mddi_log_stats_counter >= mddi_log_stats_frequency)
+ mddi_log_stats_counter = 0;
+
+ return;
+} /* mddi_host_timer_cb */
+
+static void mddi_process_link_list_done(void)
+{
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ /* normal forward linked list packet(s) were sent */
+ if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) {
+ MDDI_MSG_ERR("**** getting LL done, but no list ****\n");
+ } else {
+ uint16 idx;
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (pmhctl->rev_state == MDDI_REV_REG_READ_ISSUED) {
+ /* special case where a register read packet was sent */
+ pmhctl->rev_state = MDDI_REV_REG_READ_SENT;
+ if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) {
+ MDDI_MSG_ERR
+ ("**** getting LL done, but no list ****\n");
+ }
+ }
+#endif
+ for (idx = pmhctl->llist_info.transmitting_start_idx;;) {
+ uint16 next_idx = pmhctl->llist_notify[idx].next_idx;
+ /* with reg read we don't release the waiting tcb until after
+ * the reverse encapsulation has completed.
+ */
+ if (idx != pmhctl->llist_info.reg_read_idx) {
+ /* notify task that may be waiting on this completion */
+ if (pmhctl->llist_notify[idx].waiting) {
+ complete(&
+ (pmhctl->llist_notify[idx].
+ done_comp));
+ }
+ if (pmhctl->llist_notify[idx].done_cb != NULL) {
+ (*(pmhctl->llist_notify[idx].done_cb))
+ ();
+ }
+
+ pmhctl->llist_notify[idx].in_use = FALSE;
+ pmhctl->llist_notify[idx].waiting = FALSE;
+ pmhctl->llist_notify[idx].done_cb = NULL;
+ if (idx < MDDI_NUM_DYNAMIC_LLIST_ITEMS) {
+ /* static LLIST items are configured only once */
+ pmhctl->llist_notify[idx].next_idx =
+ UNASSIGNED_INDEX;
+ }
+ /*
+ * currently, all linked list packets are
+ * register access, so we can increment the
+ * counter for that packet type here.
+ */
+ pmhctl->log_parms.reg_acc_cnt++;
+ }
+ if (idx == pmhctl->llist_info.transmitting_end_idx)
+ break;
+ idx = next_idx;
+ if (idx == UNASSIGNED_INDEX)
+ MDDI_MSG_CRIT("MDDI linked list corruption!\n");
+ }
+
+ pmhctl->llist_info.transmitting_start_idx = UNASSIGNED_INDEX;
+ pmhctl->llist_info.transmitting_end_idx = UNASSIGNED_INDEX;
+
+ if (pmhctl->mddi_waiting_for_llist_avail) {
+ if (!
+ (pmhctl->
+ llist_notify[pmhctl->llist_info.next_free_idx].
+ in_use)) {
+ pmhctl->mddi_waiting_for_llist_avail = FALSE;
+ complete(&(pmhctl->mddi_llist_avail_comp));
+ }
+ }
+ }
+
+ /* Turn off MDDI_INT_PRI_LINK_LIST_DONE interrupt */
+ mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE, 0);
+
+}
+
+static void mddi_queue_forward_linked_list(void)
+{
+ uint16 first_pkt_index;
+ mddi_linked_list_type *llist_dma;
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+ llist_dma = pmhctl->llist_dma_ptr;
+
+ first_pkt_index = UNASSIGNED_INDEX;
+
+ if (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) {
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (pmhctl->llist_info.reg_read_waiting) {
+ if (pmhctl->rev_state == MDDI_REV_IDLE) {
+ /*
+ * we have a register read to send and
+ * can send it now
+ */
+ pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED;
+ mddi_reg_read_retry = 0;
+ first_pkt_index =
+ pmhctl->llist_info.waiting_start_idx;
+ pmhctl->llist_info.reg_read_waiting = FALSE;
+ }
+ } else
+#endif
+ {
+ /*
+ * not register read to worry about, go ahead and write
+ * anything that may be on the waiting list.
+ */
+ first_pkt_index = pmhctl->llist_info.waiting_start_idx;
+ }
+ }
+
+ if (first_pkt_index != UNASSIGNED_INDEX) {
+ pmhctl->llist_info.transmitting_start_idx =
+ pmhctl->llist_info.waiting_start_idx;
+ pmhctl->llist_info.transmitting_end_idx =
+ pmhctl->llist_info.waiting_end_idx;
+ pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX;
+ pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX;
+
+ /* write to the primary pointer register */
+ MDDI_MSG_DEBUG("MDDI writing primary ptr with idx=%d\n",
+ first_pkt_index);
+
+ pmhctl->int_type.llist_ptr_write_2++;
+
+ dma_coherent_pre_ops();
+ mddi_host_reg_out(PRI_PTR, &llist_dma[first_pkt_index]);
+
+ /* enable interrupt when complete */
+ mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
+ MDDI_INT_PRI_LINK_LIST_DONE);
+
+ }
+
+}
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+static void mddi_read_rev_packet(byte *data_ptr)
+{
+ uint16 i, length;
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ uint8 *rev_ptr_overflow =
+ (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE);
+
+ /* first determine the length and handle invalid lengths */
+ length = *pmhctl->rev_ptr_curr++;
+ if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ length |= ((*pmhctl->rev_ptr_curr++) << 8);
+ if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ if (length > (pmhctl->rev_pkt_size - 2)) {
+ MDDI_MSG_ERR("Invalid rev pkt length %d\n", length);
+ /* rev_pkt_size should always be <= rev_ptr_size so limit to packet size */
+ length = pmhctl->rev_pkt_size - 2;
+ }
+
+ /* If the data pointer is NULL, just increment the pmhctl->rev_ptr_curr.
+ * Loop around if necessary. Don't bother reading the data.
+ */
+ if (data_ptr == NULL) {
+ pmhctl->rev_ptr_curr += length;
+ if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
+ pmhctl->rev_ptr_curr -= MDDI_REV_BUFFER_SIZE;
+ return;
+ }
+
+ data_ptr[0] = length & 0x0ff;
+ data_ptr[1] = length >> 8;
+ data_ptr += 2;
+ /* copy the data to data_ptr byte-at-a-time */
+ for (i = 0; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow);
+ i++)
+ *data_ptr++ = *pmhctl->rev_ptr_curr++;
+ if (pmhctl->rev_ptr_curr >= rev_ptr_overflow)
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ for (; (i < length) && (pmhctl->rev_ptr_curr < rev_ptr_overflow); i++)
+ *data_ptr++ = *pmhctl->rev_ptr_curr++;
+}
+
+static void mddi_process_rev_packets(void)
+{
+ uint32 rev_packet_count;
+ word i;
+ uint32 crc_errors;
+ boolean mddi_reg_read_successful = FALSE;
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ pmhctl->log_parms.rev_enc_cnt++;
+ if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) &&
+ (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED) &&
+ (pmhctl->rev_state != MDDI_REV_CLIENT_CAP_ISSUED)) {
+ MDDI_MSG_ERR("Wrong state %d for reverse int\n",
+ pmhctl->rev_state);
+ }
+ /* Turn off MDDI_INT_REV_AVAIL interrupt */
+ mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL, 0);
+
+ /* Clear rev data avail int */
+ mddi_host_reg_out(INT, MDDI_INT_REV_DATA_AVAIL);
+
+ /* Get Number of packets */
+ rev_packet_count = mddi_host_reg_in(REV_PKT_CNT);
+
+#ifndef T_MSM7500
+ /* Clear out rev packet counter */
+ mddi_host_reg_out(REV_PKT_CNT, 0x0000);
+#endif
+
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
+ if ((pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) &&
+ (rev_packet_count > 0) &&
+ (mddi_host_core_version == 0x28 ||
+ mddi_host_core_version == 0x30)) {
+
+ uint32 int_reg;
+ uint32 max_count = 0;
+
+ mddi_host_reg_out(REV_PTR, pmhctl->mddi_rev_ptr_write_val);
+ int_reg = mddi_host_reg_in(INT);
+ while ((int_reg & 0x100000) == 0) {
+ udelay(3);
+ int_reg = mddi_host_reg_in(INT);
+ if (++max_count > 100)
+ break;
+ }
+ }
+#endif
+
+ /* Get CRC error count */
+ crc_errors = mddi_host_reg_in(REV_CRC_ERR);
+ if (crc_errors != 0) {
+ pmhctl->log_parms.rev_crc_cnt += crc_errors;
+ pmhctl->stats.rev_crc_count += crc_errors;
+ MDDI_MSG_ERR("!!! MDDI %d Reverse CRC Error(s) !!!\n",
+ crc_errors);
+#ifndef T_MSM7500
+ /* Clear CRC error count */
+ mddi_host_reg_out(REV_CRC_ERR, 0x0000);
+#endif
+ /* also issue an RTD to attempt recovery */
+ pmhctl->rtd_counter = mddi_rtd_frequency;
+ }
+
+ pmhctl->rtd_value = mddi_host_reg_in(RTD_VAL);
+
+ MDDI_MSG_DEBUG("MDDI rev pkt cnt=%d, ptr=0x%x, RTD:0x%x\n",
+ rev_packet_count,
+ pmhctl->rev_ptr_curr - pmhctl->rev_ptr_start,
+ pmhctl->rtd_value);
+
+ if (rev_packet_count >= 1) {
+ mddi_invalidate_cache_lines((uint32 *) pmhctl->rev_ptr_start,
+ MDDI_REV_BUFFER_SIZE);
+ }
+ /* order the reads */
+ dma_coherent_post_ops();
+ for (i = 0; i < rev_packet_count; i++) {
+ mddi_rev_packet_type *rev_pkt_ptr;
+
+ mddi_read_rev_packet(rev_packet_data);
+
+ rev_pkt_ptr = (mddi_rev_packet_type *) rev_packet_data;
+
+ if (rev_pkt_ptr->packet_length > pmhctl->rev_pkt_size) {
+ MDDI_MSG_ERR("!!!invalid packet size: %d\n",
+ rev_pkt_ptr->packet_length);
+ }
+
+ MDDI_MSG_DEBUG("MDDI rev pkt 0x%x size 0x%x\n",
+ rev_pkt_ptr->packet_type,
+ rev_pkt_ptr->packet_length);
+
+ /* Do whatever you want to do with the data based on the packet type */
+ switch (rev_pkt_ptr->packet_type) {
+ case 66: /* Client Capability */
+ {
+ mddi_client_capability_type
+ *client_capability_pkt_ptr;
+
+ client_capability_pkt_ptr =
+ (mddi_client_capability_type *)
+ rev_packet_data;
+ MDDI_MSG_NOTICE
+ ("Client Capability: Week=%d, Year=%d\n",
+ client_capability_pkt_ptr->
+ Week_of_Manufacture,
+ client_capability_pkt_ptr->
+ Year_of_Manufacture);
+ memcpy((void *)&mddi_client_capability_pkt,
+ (void *)rev_packet_data,
+ sizeof(mddi_client_capability_type));
+ pmhctl->log_parms.cli_cap_cnt++;
+ }
+ break;
+
+ case 70: /* Display Status */
+ {
+ mddi_client_status_type *client_status_pkt_ptr;
+
+ client_status_pkt_ptr =
+ (mddi_client_status_type *) rev_packet_data;
+ if ((client_status_pkt_ptr->crc_error_count !=
+ 0)
+ || (client_status_pkt_ptr->
+ reverse_link_request != 0)) {
+ MDDI_MSG_ERR
+ ("Client Status: RevReq=%d, CrcErr=%d\n",
+ client_status_pkt_ptr->
+ reverse_link_request,
+ client_status_pkt_ptr->
+ crc_error_count);
+ } else {
+ MDDI_MSG_DEBUG
+ ("Client Status: RevReq=%d, CrcErr=%d\n",
+ client_status_pkt_ptr->
+ reverse_link_request,
+ client_status_pkt_ptr->
+ crc_error_count);
+ }
+ pmhctl->log_parms.fwd_crc_cnt +=
+ client_status_pkt_ptr->crc_error_count;
+ pmhctl->stats.fwd_crc_count +=
+ client_status_pkt_ptr->crc_error_count;
+ pmhctl->log_parms.cli_stat_cnt++;
+ }
+ break;
+
+ case 146: /* register access packet */
+ {
+ mddi_register_access_packet_type
+ * regacc_pkt_ptr;
+
+ regacc_pkt_ptr =
+ (mddi_register_access_packet_type *)
+ rev_packet_data;
+
+ MDDI_MSG_DEBUG
+ ("Reg Acc parse reg=0x%x, value=0x%x\n",
+ regacc_pkt_ptr->register_address,
+ regacc_pkt_ptr->register_data_list);
+
+ /* Copy register value to location passed in */
+ if (mddi_reg_read_value_ptr) {
+#if defined(T_MSM6280) && !defined(T_MSM7200)
+ /* only least significant 16 bits are valid with 6280 */
+ *mddi_reg_read_value_ptr =
+ regacc_pkt_ptr->
+ register_data_list & 0x0000ffff;
+#else
+ *mddi_reg_read_value_ptr =
+ regacc_pkt_ptr->register_data_list;
+#endif
+ mddi_reg_read_successful = TRUE;
+ mddi_reg_read_value_ptr = NULL;
+ }
+
+#ifdef DEBUG_MDDIHOSTI
+ if ((mddi_gpio.polling_enabled) &&
+ (regacc_pkt_ptr->register_address ==
+ mddi_gpio.polling_reg)) {
+ /*
+ * ToDo: need to call Linux GPIO call
+ * here...
+ */
+ mddi_client_lcd_gpio_poll(
+ regacc_pkt_ptr->register_data_list);
+ }
+#endif
+ pmhctl->log_parms.reg_read_cnt++;
+ }
+ break;
+
+ default: /* any other packet */
+ {
+ uint16 hdlr;
+
+ for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS;
+ hdlr++) {
+ if (mddi_rev_pkt_handler[hdlr].
+ pkt_type ==
+ rev_pkt_ptr->packet_type) {
+ (*
+ (mddi_rev_pkt_handler[hdlr].
+ handler)) (rev_pkt_ptr);
+ /* pmhctl->rev_state = MDDI_REV_IDLE; */
+ break;
+ }
+ }
+ if (hdlr >= MAX_MDDI_REV_HANDLERS)
+ MDDI_MSG_ERR("MDDI unknown rev pkt\n");
+ }
+ break;
+ }
+ }
+ if ((pmhctl->rev_ptr_curr + pmhctl->rev_pkt_size) >=
+ (pmhctl->rev_ptr_start + MDDI_REV_BUFFER_SIZE)) {
+ pmhctl->rev_ptr_written = FALSE;
+ }
+
+ if (pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) {
+ pmhctl->rev_state = MDDI_REV_IDLE;
+ if (mddi_rev_user.waiting) {
+ mddi_rev_user.waiting = FALSE;
+ complete(&(mddi_rev_user.done_comp));
+ } else if (pmhctl->llist_info.reg_read_idx == UNASSIGNED_INDEX) {
+ MDDI_MSG_ERR
+ ("Reverse Encap state, but no reg read in progress\n");
+ } else {
+ if ((!mddi_reg_read_successful) &&
+ (mddi_reg_read_retry < mddi_reg_read_retry_max) &&
+ (mddi_enable_reg_read_retry)) {
+ /*
+ * There is a race condition that can happen
+ * where the reverse encapsulation message is
+ * sent out by the MDDI host before the register
+ * read packet is sent. As a work-around for
+ * that problem we issue the reverse
+ * encapsulation one more time before giving up.
+ */
+ if (mddi_enable_reg_read_retry_once)
+ mddi_reg_read_retry =
+ mddi_reg_read_retry_max;
+ pmhctl->rev_state = MDDI_REV_REG_READ_SENT;
+ pmhctl->stats.reg_read_failure++;
+ } else {
+ uint16 reg_read_idx =
+ pmhctl->llist_info.reg_read_idx;
+
+ mddi_reg_read_retry = 0;
+ if (pmhctl->llist_notify[reg_read_idx].waiting) {
+ complete(&
+ (pmhctl->
+ llist_notify[reg_read_idx].
+ done_comp));
+ }
+ pmhctl->llist_info.reg_read_idx =
+ UNASSIGNED_INDEX;
+ if (pmhctl->llist_notify[reg_read_idx].
+ done_cb != NULL) {
+ (*
+ (pmhctl->llist_notify[reg_read_idx].
+ done_cb)) ();
+ }
+ pmhctl->llist_notify[reg_read_idx].next_idx =
+ UNASSIGNED_INDEX;
+ pmhctl->llist_notify[reg_read_idx].in_use =
+ FALSE;
+ pmhctl->llist_notify[reg_read_idx].waiting =
+ FALSE;
+ pmhctl->llist_notify[reg_read_idx].done_cb =
+ NULL;
+ if (!mddi_reg_read_successful)
+ pmhctl->stats.reg_read_failure++;
+ }
+ }
+ } else if (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED) {
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
+ if (mddi_host_core_version == 0x28 ||
+ mddi_host_core_version == 0x30) {
+ mddi_host_reg_out(FIFO_ALLOC, 0x00);
+ pmhctl->rev_ptr_written = TRUE;
+ mddi_host_reg_out(REV_PTR,
+ pmhctl->mddi_rev_ptr_write_val);
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+ mddi_host_reg_out(CMD, 0xC00);
+ }
+#endif
+
+ if (mddi_rev_user.waiting) {
+ mddi_rev_user.waiting = FALSE;
+ complete(&(mddi_rev_user.done_comp));
+ }
+ pmhctl->rev_state = MDDI_REV_IDLE;
+ } else {
+ pmhctl->rev_state = MDDI_REV_IDLE;
+ }
+
+ /* pmhctl->rev_state = MDDI_REV_IDLE; */
+
+ /* Re-enable interrupt */
+ mddi_host_reg_outm(INTEN, MDDI_INT_REV_DATA_AVAIL,
+ MDDI_INT_REV_DATA_AVAIL);
+
+}
+
+static void mddi_issue_reverse_encapsulation(void)
+{
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+ /* Only issue a reverse encapsulation packet if:
+ * 1) another reverse is not in progress (MDDI_REV_IDLE).
+ * 2) a register read has been sent (MDDI_REV_REG_READ_SENT).
+ * 3) forward is not in progress, because of a hw bug in client that
+ * causes forward crc errors on packet immediately after rev encap.
+ */
+ if (((pmhctl->rev_state == MDDI_REV_IDLE) ||
+ (pmhctl->rev_state == MDDI_REV_REG_READ_SENT)) &&
+ (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
+ (!mdp_in_processing)) {
+ uint32 mddi_command = MDDI_CMD_SEND_REV_ENCAP;
+
+ if ((pmhctl->rev_state == MDDI_REV_REG_READ_SENT) ||
+ (mddi_rev_encap_user_request == TRUE)) {
+ mddi_host_enable_io_clock();
+ if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
+ /* need to wake up link before issuing rev encap command */
+ MDDI_MSG_DEBUG("wake up link!\n");
+ pmhctl->link_state = MDDI_LINK_ACTIVATING;
+ mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
+ } else {
+ if (pmhctl->rtd_counter >= mddi_rtd_frequency) {
+ MDDI_MSG_DEBUG
+ ("mddi sending RTD command!\n");
+ mddi_host_reg_out(CMD,
+ MDDI_CMD_SEND_RTD);
+ pmhctl->rtd_counter = 0;
+ pmhctl->log_parms.rtd_cnt++;
+ }
+ if (pmhctl->rev_state != MDDI_REV_REG_READ_SENT) {
+ /* this is generic reverse request by user, so
+ * reset the waiting flag. */
+ mddi_rev_encap_user_request = FALSE;
+ }
+ /* link is active so send reverse encap to get register read results */
+ pmhctl->rev_state = MDDI_REV_ENCAP_ISSUED;
+ mddi_command = MDDI_CMD_SEND_REV_ENCAP;
+ MDDI_MSG_DEBUG("sending rev encap!\n");
+ }
+ } else
+ if ((pmhctl->client_status_cnt >=
+ mddi_client_status_frequency)
+ || mddi_client_capability_request) {
+ mddi_host_enable_io_clock();
+ if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
+ /* only wake up the link if it client status is overdue */
+ if ((pmhctl->client_status_cnt >=
+ (mddi_client_status_frequency * 2))
+ || mddi_client_capability_request) {
+ /* need to wake up link before issuing rev encap command */
+ MDDI_MSG_DEBUG("wake up link!\n");
+ pmhctl->link_state =
+ MDDI_LINK_ACTIVATING;
+ mddi_host_reg_out(CMD,
+ MDDI_CMD_LINK_ACTIVE);
+ }
+ } else {
+ if (pmhctl->rtd_counter >= mddi_rtd_frequency) {
+ MDDI_MSG_DEBUG
+ ("mddi sending RTD command!\n");
+ mddi_host_reg_out(CMD,
+ MDDI_CMD_SEND_RTD);
+ pmhctl->rtd_counter = 0;
+ pmhctl->log_parms.rtd_cnt++;
+ }
+ /* periodically get client status */
+ MDDI_MSG_DEBUG
+ ("mddi sending rev enc! (get status)\n");
+ if (mddi_client_capability_request) {
+ pmhctl->rev_state =
+ MDDI_REV_CLIENT_CAP_ISSUED;
+ mddi_command = MDDI_CMD_GET_CLIENT_CAP;
+ mddi_client_capability_request = FALSE;
+ } else {
+ pmhctl->rev_state =
+ MDDI_REV_STATUS_REQ_ISSUED;
+ pmhctl->client_status_cnt = 0;
+ mddi_command =
+ MDDI_CMD_GET_CLIENT_STATUS;
+ }
+ }
+ }
+ if ((pmhctl->rev_state == MDDI_REV_ENCAP_ISSUED) ||
+ (pmhctl->rev_state == MDDI_REV_STATUS_REQ_ISSUED) ||
+ (pmhctl->rev_state == MDDI_REV_CLIENT_CAP_ISSUED)) {
+ pmhctl->int_type.rev_encap_count++;
+#if defined(T_MSM6280) && !defined(T_MSM7200)
+ mddi_rev_pointer_written = TRUE;
+ mddi_host_reg_out(REV_PTR, mddi_rev_ptr_write_val);
+ mddi_rev_ptr_curr = mddi_rev_ptr_start;
+ /* force new rev ptr command */
+ mddi_host_reg_out(CMD, 0xC00);
+#else
+ if (!pmhctl->rev_ptr_written) {
+ MDDI_MSG_DEBUG("writing reverse pointer!\n");
+ pmhctl->rev_ptr_written = TRUE;
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
+ if ((pmhctl->rev_state ==
+ MDDI_REV_CLIENT_CAP_ISSUED) &&
+ (mddi_host_core_version == 0x28 ||
+ mddi_host_core_version == 0x30)) {
+ pmhctl->rev_ptr_written = FALSE;
+ mddi_host_reg_out(FIFO_ALLOC, 0x02);
+ } else
+ mddi_host_reg_out(REV_PTR,
+ pmhctl->
+ mddi_rev_ptr_write_val);
+#else
+ mddi_host_reg_out(REV_PTR,
+ pmhctl->
+ mddi_rev_ptr_write_val);
+#endif
+ }
+#endif
+ if (mddi_debug_clear_rev_data) {
+ uint16 i;
+ for (i = 0; i < MDDI_MAX_REV_DATA_SIZE / 4; i++)
+ pmhctl->rev_data_buf[i] = 0xdddddddd;
+ /* clean cache */
+ mddi_flush_cache_lines(pmhctl->rev_data_buf,
+ MDDI_MAX_REV_DATA_SIZE);
+ }
+
+ /* send reverse encapsulation to get needed data */
+ mddi_host_reg_out(CMD, mddi_command);
+ }
+ }
+
+}
+
+static void mddi_process_client_initiated_wakeup(void)
+{
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ /* Disable MDDI_INT Interrupt, we detect client initiated wakeup one
+ * time for each entry into hibernation */
+ mddi_host_reg_outm(INTEN, MDDI_INT_MDDI_IN, 0);
+
+ if (host_idx == MDDI_HOST_PRIM) {
+ if (mddi_vsync_detect_enabled) {
+ mddi_host_enable_io_clock();
+#ifndef MDDI_HOST_DISP_LISTEN
+ /* issue command to bring up link */
+ /* need to do this to clear the vsync condition */
+ if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
+ pmhctl->link_state = MDDI_LINK_ACTIVATING;
+ mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
+ }
+#endif
+ /*
+ * Indicate to client specific code that vsync was
+ * enabled, and we did not detect a client initiated
+ * wakeup. The client specific handler can clear the
+ * condition if necessary to prevent subsequent
+ * client initiated wakeups.
+ */
+ mddi_client_lcd_vsync_detected(TRUE);
+ pmhctl->log_parms.vsync_response_cnt++;
+ MDDI_MSG_NOTICE("MDDI_INT_IN condition\n");
+
+ }
+ }
+
+ if (mddi_gpio.polling_enabled) {
+ mddi_host_enable_io_clock();
+ /* check interrupt status now */
+ (void)mddi_queue_register_read_int(mddi_gpio.polling_reg,
+ &mddi_gpio.polling_val);
+ }
+}
+#endif /* FEATURE_MDDI_DISABLE_REVERSE */
+
+static void mddi_host_isr(void)
+{
+ uint32 int_reg, int_en;
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ uint32 status_reg;
+#endif
+ mddi_host_type host_idx = mddi_curr_host;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if (!MDDI_HOST_IS_HCLK_ON) {
+ MDDI_HOST_ENABLE_HCLK;
+ MDDI_MSG_DEBUG("HCLK disabled, but isr is firing\n");
+ }
+ int_reg = mddi_host_reg_in(INT);
+ int_en = mddi_host_reg_in(INTEN);
+ pmhctl->saved_int_reg = int_reg;
+ pmhctl->saved_int_en = int_en;
+ int_reg = int_reg & int_en;
+ pmhctl->int_type.count++;
+
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ status_reg = mddi_host_reg_in(STAT);
+
+ if ((int_reg & MDDI_INT_MDDI_IN) ||
+ ((int_en & MDDI_INT_MDDI_IN) &&
+ ((int_reg == 0) || (status_reg & MDDI_STAT_CLIENT_WAKEUP_REQ)))) {
+ /*
+ * The MDDI_IN condition will clear itself, and so it is
+ * possible that MDDI_IN was the reason for the isr firing,
+ * even though the interrupt register does not have the
+ * MDDI_IN bit set. To check if this was the case we need to
+ * look at the status register bit that signifies a client
+ * initiated wakeup. If the status register bit is set, as well
+ * as the MDDI_IN interrupt enabled, then we treat this as a
+ * client initiated wakeup.
+ */
+ if (int_reg & MDDI_INT_MDDI_IN)
+ pmhctl->int_type.in_count++;
+ mddi_process_client_initiated_wakeup();
+ }
+#endif
+
+ if (int_reg & MDDI_INT_LINK_STATE_CHANGES) {
+ pmhctl->int_type.state_change_count++;
+ mddi_report_state_change(int_reg);
+ }
+
+ if (int_reg & MDDI_INT_PRI_LINK_LIST_DONE) {
+ pmhctl->int_type.ll_done_count++;
+ mddi_process_link_list_done();
+ }
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (int_reg & MDDI_INT_REV_DATA_AVAIL) {
+ pmhctl->int_type.rev_avail_count++;
+ mddi_process_rev_packets();
+ }
+#endif
+
+ if (int_reg & MDDI_INT_ERROR_CONDITIONS) {
+ pmhctl->int_type.error_count++;
+ mddi_report_errors(int_reg);
+
+ mddi_host_reg_out(INT, int_reg & MDDI_INT_ERROR_CONDITIONS);
+ }
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ mddi_issue_reverse_encapsulation();
+
+ if ((pmhctl->rev_state != MDDI_REV_ENCAP_ISSUED) &&
+ (pmhctl->rev_state != MDDI_REV_STATUS_REQ_ISSUED))
+#endif
+ /* don't want simultaneous reverse and forward with Eagle */
+ mddi_queue_forward_linked_list();
+
+ if (int_reg & MDDI_INT_NO_CMD_PKTS_PEND) {
+ /* this interrupt is used to kick the isr when hibernation is disabled */
+ mddi_host_reg_outm(INTEN, MDDI_INT_NO_CMD_PKTS_PEND, 0);
+ }
+
+ if ((!mddi_host_mdp_active_flag) &&
+ (!mddi_vsync_detect_enabled) &&
+ (pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
+ (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) &&
+ (pmhctl->rev_state == MDDI_REV_IDLE)) {
+ if (pmhctl->link_state == MDDI_LINK_HIBERNATING) {
+ mddi_host_disable_io_clock();
+ mddi_host_disable_hclk();
+ }
+#ifdef FEATURE_MDDI_HOST_ENABLE_EARLY_HIBERNATION
+ else if ((pmhctl->link_state == MDDI_LINK_ACTIVE) &&
+ (!pmhctl->disable_hibernation)) {
+ mddi_host_reg_out(CMD, MDDI_CMD_POWERDOWN);
+ }
+#endif
+ }
+}
+
+static void mddi_host_isr_primary(void)
+{
+ mddi_curr_host = MDDI_HOST_PRIM;
+ mddi_host_isr();
+}
+
+irqreturn_t mddi_pmdh_isr_proxy(int irq, void *ptr)
+{
+ mddi_host_isr_primary();
+ return IRQ_HANDLED;
+}
+
+static void mddi_host_isr_external(void)
+{
+ mddi_curr_host = MDDI_HOST_EXT;
+ mddi_host_isr();
+ mddi_curr_host = MDDI_HOST_PRIM;
+}
+
+irqreturn_t mddi_emdh_isr_proxy(int irq, void *ptr)
+{
+ mddi_host_isr_external();
+ return IRQ_HANDLED;
+}
+
+static void mddi_host_initialize_registers(mddi_host_type host_idx)
+{
+ uint32 pad_reg_val;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if (pmhctl->driver_state == MDDI_DRIVER_ENABLED)
+ return;
+
+ /* turn on HCLK to MDDI host core */
+ mddi_host_enable_hclk();
+
+ /* MDDI Reset command */
+ mddi_host_reg_out(CMD, MDDI_CMD_RESET);
+
+ /* Version register (= 0x01) */
+ mddi_host_reg_out(VERSION, 0x0001);
+
+ /* Bytes per subframe register */
+ mddi_host_reg_out(BPS, MDDI_HOST_BYTES_PER_SUBFRAME);
+
+ /* Subframes per media frames register (= 0x03) */
+ mddi_host_reg_out(SPM, 0x0003);
+
+ /* Turn Around 1 register (= 0x05) */
+ mddi_host_reg_out(TA1_LEN, 0x0005);
+
+ /* Turn Around 2 register (= 0x0C) */
+ mddi_host_reg_out(TA2_LEN, MDDI_HOST_TA2_LEN);
+
+ /* Drive hi register (= 0x96) */
+ mddi_host_reg_out(DRIVE_HI, 0x0096);
+
+ /* Drive lo register (= 0x32) */
+ mddi_host_reg_out(DRIVE_LO, 0x0032);
+
+ /* Display wakeup count register (= 0x3c) */
+ mddi_host_reg_out(DISP_WAKE, 0x003c);
+
+ /* Reverse Rate Divisor register (= 0x2) */
+ mddi_host_reg_out(REV_RATE_DIV, MDDI_HOST_REV_RATE_DIV);
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ /* Reverse Pointer Size */
+ mddi_host_reg_out(REV_SIZE, MDDI_REV_BUFFER_SIZE);
+
+ /* Rev Encap Size */
+ mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
+#endif
+
+ /* Periodic Rev Encap */
+ /* don't send periodically */
+ mddi_host_reg_out(CMD, MDDI_CMD_PERIODIC_REV_ENCAP);
+
+ pad_reg_val = mddi_host_reg_in(PAD_CTL);
+ if (pad_reg_val == 0) {
+ /* If we are turning on band gap, need to wait 5us before turning
+ * on the rest of the PAD */
+ mddi_host_reg_out(PAD_CTL, 0x08000);
+ udelay(5);
+ }
+#ifdef T_MSM7200
+ /* Recommendation from PAD hw team */
+ mddi_host_reg_out(PAD_CTL, 0xa850a);
+#else
+ /* Recommendation from PAD hw team */
+ mddi_host_reg_out(PAD_CTL, 0xa850f);
+#endif
+
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
+ mddi_host_reg_out(PAD_IO_CTL, 0x00320000);
+ mddi_host_reg_out(PAD_CAL, 0x00220020);
+#endif
+
+ mddi_host_core_version = mddi_host_reg_inm(CORE_VER, 0xffff);
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (mddi_host_core_version >= 8)
+ mddi_rev_ptr_workaround = FALSE;
+ pmhctl->rev_ptr_curr = pmhctl->rev_ptr_start;
+#endif
+
+ if ((mddi_host_core_version > 8) && (mddi_host_core_version < 0x19))
+ mddi_host_reg_out(TEST, 0x2);
+
+ /* Need an even number for counts */
+ mddi_host_reg_out(DRIVER_START_CNT, 0x60006);
+
+#ifndef T_MSM7500
+ /* Setup defaults for MDP related register */
+ mddi_host_reg_out(MDP_VID_FMT_DES, 0x5666);
+ mddi_host_reg_out(MDP_VID_PIX_ATTR, 0x00C3);
+ mddi_host_reg_out(MDP_VID_CLIENTID, 0);
+#endif
+
+ /* automatically hibernate after 1 empty subframe */
+ if (pmhctl->disable_hibernation)
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
+ else
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
+
+ /* Bring up link if display (client) requests it */
+#ifdef MDDI_HOST_DISP_LISTEN
+ mddi_host_reg_out(CMD, MDDI_CMD_DISP_LISTEN);
+#else
+ mddi_host_reg_out(CMD, MDDI_CMD_DISP_IGNORE);
+#endif
+
+}
+
+void mddi_host_configure_interrupts(mddi_host_type host_idx, boolean enable)
+{
+ unsigned long flags;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+
+ /* turn on HCLK to MDDI host core if it has been disabled */
+ mddi_host_enable_hclk();
+ /* Clear MDDI Interrupt enable reg */
+ mddi_host_reg_out(INTEN, 0);
+
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ if (enable) {
+ pmhctl->driver_state = MDDI_DRIVER_ENABLED;
+
+ if (host_idx == MDDI_HOST_PRIM) {
+ if (request_irq
+ (INT_MDDI_PRI, mddi_pmdh_isr_proxy, IRQF_DISABLED,
+ "PMDH", 0) != 0)
+ printk(KERN_ERR
+ "a mddi: unable to request_irq\n");
+ else
+ int_mddi_pri_flag = TRUE;
+ } else {
+ if (request_irq
+ (INT_MDDI_EXT, mddi_emdh_isr_proxy, IRQF_DISABLED,
+ "EMDH", 0) != 0)
+ printk(KERN_ERR
+ "b mddi: unable to request_irq\n");
+ else
+ int_mddi_ext_flag = TRUE;
+ }
+
+ /* Set MDDI Interrupt enable reg -- Enable Reverse data avail */
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ mddi_host_reg_out(INTEN,
+ MDDI_INT_ERROR_CONDITIONS |
+ MDDI_INT_LINK_STATE_CHANGES);
+#else
+ /* Reverse Pointer register */
+ pmhctl->rev_ptr_written = FALSE;
+
+ mddi_host_reg_out(INTEN,
+ MDDI_INT_REV_DATA_AVAIL |
+ MDDI_INT_ERROR_CONDITIONS |
+ MDDI_INT_LINK_STATE_CHANGES);
+ pmhctl->rtd_counter = mddi_rtd_frequency;
+ pmhctl->client_status_cnt = 0;
+#endif
+ } else {
+ if (pmhctl->driver_state == MDDI_DRIVER_ENABLED)
+ pmhctl->driver_state = MDDI_DRIVER_DISABLED;
+ }
+
+}
+
+static void mddi_host_powerup(mddi_host_type host_idx)
+{
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if (pmhctl->link_state != MDDI_LINK_DISABLED)
+ return;
+
+ /* enable IO_CLK and hclk to MDDI host core */
+ mddi_host_enable_io_clock();
+
+ mddi_host_initialize_registers(host_idx);
+ mddi_host_configure_interrupts(host_idx, TRUE);
+
+ pmhctl->link_state = MDDI_LINK_ACTIVATING;
+
+ /* Link activate command */
+ mddi_host_reg_out(CMD, MDDI_CMD_LINK_ACTIVE);
+
+#ifdef CLKRGM_MDDI_IO_CLOCK_IN_MHZ
+ MDDI_MSG_NOTICE("MDDI Host: Activating Link %d Mbps\n",
+ CLKRGM_MDDI_IO_CLOCK_IN_MHZ * 2);
+#else
+ MDDI_MSG_NOTICE("MDDI Host: Activating Link\n");
+#endif
+
+ /* Initialize the timer */
+ if (host_idx == MDDI_HOST_PRIM)
+ mddi_host_timer_service(0);
+}
+
+void mddi_host_init(mddi_host_type host_idx)
+/* Write out the MDDI configuration registers */
+{
+ static boolean initialized = FALSE;
+ mddi_host_cntl_type *pmhctl;
+
+ if (host_idx >= MDDI_NUM_HOST_CORES) {
+ MDDI_MSG_ERR("Invalid host core index\n");
+ return;
+ }
+
+ if (!initialized) {
+ uint16 idx;
+ mddi_host_type host;
+ for (host = MDDI_HOST_PRIM; host < MDDI_NUM_HOST_CORES; host++) {
+ pmhctl = &(mhctl[host]);
+ initialized = TRUE;
+
+ pmhctl->llist_ptr =
+ dma_alloc_coherent(NULL, MDDI_LLIST_POOL_SIZE,
+ &(pmhctl->llist_dma_addr),
+ GFP_KERNEL);
+ pmhctl->llist_dma_ptr =
+ (mddi_linked_list_type *) (void *)pmhctl->
+ llist_dma_addr;
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ pmhctl->rev_data_buf = NULL;
+ if (pmhctl->llist_ptr == NULL)
+#else
+ mddi_rev_user.waiting = FALSE;
+ init_completion(&(mddi_rev_user.done_comp));
+ pmhctl->rev_data_buf =
+ dma_alloc_coherent(NULL, MDDI_MAX_REV_DATA_SIZE,
+ &(pmhctl->rev_data_dma_addr),
+ GFP_KERNEL);
+ if ((pmhctl->llist_ptr == NULL)
+ || (pmhctl->rev_data_buf == NULL))
+#endif
+ {
+ MDDI_MSG_CRIT
+ ("unable to alloc non-cached memory\n");
+ }
+ llist_extern[host] = pmhctl->llist_ptr;
+ llist_dma_extern[host] = pmhctl->llist_dma_ptr;
+ llist_extern_notify[host] = pmhctl->llist_notify;
+
+ for (idx = 0; idx < UNASSIGNED_INDEX; idx++) {
+ init_completion(&
+ (pmhctl->llist_notify[idx].
+ done_comp));
+ }
+ init_completion(&(pmhctl->mddi_llist_avail_comp));
+ spin_lock_init(&mddi_host_spin_lock);
+ pmhctl->mddi_waiting_for_llist_avail = FALSE;
+ pmhctl->mddi_rev_ptr_write_val =
+ (uint32) (void *)(pmhctl->rev_data_dma_addr);
+ pmhctl->rev_ptr_start = (void *)pmhctl->rev_data_buf;
+
+ pmhctl->rev_pkt_size = MDDI_DEFAULT_REV_PKT_SIZE;
+ pmhctl->rev_state = MDDI_REV_IDLE;
+#ifdef IMAGE_MODEM_PROC
+ /* assume hibernation state is last state from APPS proc, so that
+ * we don't reinitialize the host core */
+ pmhctl->link_state = MDDI_LINK_HIBERNATING;
+#else
+ pmhctl->link_state = MDDI_LINK_DISABLED;
+#endif
+ pmhctl->driver_state = MDDI_DRIVER_DISABLED;
+ pmhctl->disable_hibernation = FALSE;
+
+ /* initialize llist variables */
+ pmhctl->llist_info.transmitting_start_idx =
+ UNASSIGNED_INDEX;
+ pmhctl->llist_info.transmitting_end_idx =
+ UNASSIGNED_INDEX;
+ pmhctl->llist_info.waiting_start_idx = UNASSIGNED_INDEX;
+ pmhctl->llist_info.waiting_end_idx = UNASSIGNED_INDEX;
+ pmhctl->llist_info.reg_read_idx = UNASSIGNED_INDEX;
+ pmhctl->llist_info.next_free_idx =
+ MDDI_FIRST_DYNAMIC_LLIST_IDX;
+ pmhctl->llist_info.reg_read_waiting = FALSE;
+
+ mddi_vsync_detect_enabled = FALSE;
+ mddi_gpio.polling_enabled = FALSE;
+
+ pmhctl->int_type.count = 0;
+ pmhctl->int_type.in_count = 0;
+ pmhctl->int_type.disp_req_count = 0;
+ pmhctl->int_type.state_change_count = 0;
+ pmhctl->int_type.ll_done_count = 0;
+ pmhctl->int_type.rev_avail_count = 0;
+ pmhctl->int_type.error_count = 0;
+ pmhctl->int_type.rev_encap_count = 0;
+ pmhctl->int_type.llist_ptr_write_1 = 0;
+ pmhctl->int_type.llist_ptr_write_2 = 0;
+
+ pmhctl->stats.fwd_crc_count = 0;
+ pmhctl->stats.rev_crc_count = 0;
+ pmhctl->stats.pri_underflow = 0;
+ pmhctl->stats.sec_underflow = 0;
+ pmhctl->stats.rev_overflow = 0;
+ pmhctl->stats.pri_overwrite = 0;
+ pmhctl->stats.sec_overwrite = 0;
+ pmhctl->stats.rev_overwrite = 0;
+ pmhctl->stats.dma_failure = 0;
+ pmhctl->stats.rtd_failure = 0;
+ pmhctl->stats.reg_read_failure = 0;
+#ifdef FEATURE_MDDI_UNDERRUN_RECOVERY
+ pmhctl->stats.pri_underrun_detected = 0;
+#endif
+
+ pmhctl->log_parms.rtd_cnt = 0;
+ pmhctl->log_parms.rev_enc_cnt = 0;
+ pmhctl->log_parms.vid_cnt = 0;
+ pmhctl->log_parms.reg_acc_cnt = 0;
+ pmhctl->log_parms.cli_stat_cnt = 0;
+ pmhctl->log_parms.cli_cap_cnt = 0;
+ pmhctl->log_parms.reg_read_cnt = 0;
+ pmhctl->log_parms.link_active_cnt = 0;
+ pmhctl->log_parms.link_hibernate_cnt = 0;
+ pmhctl->log_parms.fwd_crc_cnt = 0;
+ pmhctl->log_parms.rev_crc_cnt = 0;
+ pmhctl->log_parms.vsync_response_cnt = 0;
+
+ prev_parms[host_idx] = pmhctl->log_parms;
+ mddi_client_capability_pkt.packet_length = 0;
+ }
+
+#ifndef T_MSM7500
+ /* tell clock driver we are user of this PLL */
+ MDDI_HOST_ENABLE_IO_CLOCK;
+#endif
+ }
+
+ mddi_host_powerup(host_idx);
+ pmhctl = &(mhctl[host_idx]);
+}
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+static uint32 mddi_client_id;
+
+uint32 mddi_get_client_id(void)
+{
+
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+ static boolean client_detection_try = FALSE;
+ mddi_host_cntl_type *pmhctl;
+ unsigned long flags;
+ uint16 saved_rev_pkt_size;
+
+ if (!client_detection_try) {
+ /* Toshiba display requires larger drive_lo value */
+ mddi_host_reg_out(DRIVE_LO, 0x0050);
+
+ pmhctl = &(mhctl[MDDI_HOST_PRIM]);
+
+ saved_rev_pkt_size = pmhctl->rev_pkt_size;
+
+ /* Increase Rev Encap Size */
+ pmhctl->rev_pkt_size = MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE;
+ mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
+
+ /* disable hibernation temporarily */
+ if (!pmhctl->disable_hibernation)
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE);
+
+ mddi_rev_user.waiting = TRUE;
+ INIT_COMPLETION(mddi_rev_user.done_comp);
+
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+
+ /* turn on clock(s), if they have been disabled */
+ mddi_host_enable_hclk();
+ mddi_host_enable_io_clock();
+
+ mddi_client_capability_request = TRUE;
+
+ if (pmhctl->rev_state == MDDI_REV_IDLE) {
+ /* attempt to send the reverse encapsulation now */
+ mddi_issue_reverse_encapsulation();
+ }
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ wait_for_completion_killable(&(mddi_rev_user.done_comp));
+
+ /* Set Rev Encap Size back to its original value */
+ pmhctl->rev_pkt_size = saved_rev_pkt_size;
+ mddi_host_reg_out(REV_ENCAP_SZ, pmhctl->rev_pkt_size);
+
+ /* reenable auto-hibernate */
+ if (!pmhctl->disable_hibernation)
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
+
+ mddi_host_reg_out(DRIVE_LO, 0x0032);
+ client_detection_try = TRUE;
+
+ mddi_client_id = (mddi_client_capability_pkt.Mfr_Name<<16) |
+ mddi_client_capability_pkt.Product_Code;
+
+ if (!mddi_client_id)
+ mddi_disable(1);
+ }
+
+#if 0
+ switch (mddi_client_capability_pkt.Mfr_Name) {
+ case 0x4474:
+ if ((mddi_client_capability_pkt.Product_Code != 0x8960) &&
+ (target == DISPLAY_1)) {
+ ret = PRISM_WVGA;
+ }
+ break;
+
+ case 0xD263:
+ if (target == DISPLAY_1)
+ ret = TOSHIBA_VGA_PRIM;
+ else if (target == DISPLAY_2)
+ ret = TOSHIBA_QCIF_SECD;
+ break;
+
+ case 0:
+ if (mddi_client_capability_pkt.Product_Code == 0x8835) {
+ if (target == DISPLAY_1)
+ ret = SHARP_QVGA_PRIM;
+ else if (target == DISPLAY_2)
+ ret = SHARP_128x128_SECD;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if ((!client_detection_try) && (ret != TOSHIBA_VGA_PRIM)
+ && (ret != TOSHIBA_QCIF_SECD)) {
+ /* Not a Toshiba display, so change drive_lo back to default value */
+ mddi_host_reg_out(DRIVE_LO, 0x0032);
+ }
+#endif
+
+#endif
+
+ return mddi_client_id;
+}
+#endif
+
+void mddi_host_powerdown(mddi_host_type host_idx)
+{
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if (host_idx >= MDDI_NUM_HOST_CORES) {
+ MDDI_MSG_ERR("Invalid host core index\n");
+ return;
+ }
+
+ if (pmhctl->driver_state == MDDI_DRIVER_RESET) {
+ return;
+ }
+
+ if (host_idx == MDDI_HOST_PRIM) {
+ /* disable timer */
+ del_timer(&mddi_host_timer);
+ }
+
+ mddi_host_configure_interrupts(host_idx, FALSE);
+
+ /* turn on HCLK to MDDI host core if it has been disabled */
+ mddi_host_enable_hclk();
+
+ /* MDDI Reset command */
+ mddi_host_reg_out(CMD, MDDI_CMD_RESET);
+
+ /* Pad Control Register */
+ mddi_host_reg_out(PAD_CTL, 0x0);
+
+ /* disable IO_CLK and hclk to MDDI host core */
+ mddi_host_disable_io_clock();
+ mddi_host_disable_hclk();
+
+ pmhctl->link_state = MDDI_LINK_DISABLED;
+ pmhctl->driver_state = MDDI_DRIVER_RESET;
+
+ MDDI_MSG_NOTICE("MDDI Host: Disabling Link\n");
+
+}
+
+uint16 mddi_get_next_free_llist_item(mddi_host_type host_idx, boolean wait)
+{
+ unsigned long flags;
+ uint16 ret_idx;
+ boolean forced_wait = FALSE;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ ret_idx = pmhctl->llist_info.next_free_idx;
+
+ pmhctl->llist_info.next_free_idx++;
+ if (pmhctl->llist_info.next_free_idx >= MDDI_NUM_DYNAMIC_LLIST_ITEMS)
+ pmhctl->llist_info.next_free_idx = MDDI_FIRST_DYNAMIC_LLIST_IDX;
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+ if (pmhctl->llist_notify[ret_idx].in_use) {
+ if (!wait) {
+ pmhctl->llist_info.next_free_idx = ret_idx;
+ ret_idx = UNASSIGNED_INDEX;
+ } else {
+ forced_wait = TRUE;
+ INIT_COMPLETION(pmhctl->mddi_llist_avail_comp);
+ }
+ }
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ if (forced_wait) {
+ wait_for_completion_killable(&
+ (pmhctl->
+ mddi_llist_avail_comp));
+ MDDI_MSG_ERR("task waiting on mddi llist item\n");
+ }
+
+ if (ret_idx != UNASSIGNED_INDEX) {
+ pmhctl->llist_notify[ret_idx].waiting = FALSE;
+ pmhctl->llist_notify[ret_idx].done_cb = NULL;
+ pmhctl->llist_notify[ret_idx].in_use = TRUE;
+ pmhctl->llist_notify[ret_idx].next_idx = UNASSIGNED_INDEX;
+ }
+
+ return ret_idx;
+}
+
+uint16 mddi_get_reg_read_llist_item(mddi_host_type host_idx, boolean wait)
+{
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ MDDI_MSG_CRIT("No reverse link available\n");
+ (void)wait;
+ return FALSE;
+#else
+ unsigned long flags;
+ uint16 ret_idx;
+ boolean error = FALSE;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+ if (pmhctl->llist_info.reg_read_idx != UNASSIGNED_INDEX) {
+ /* need to block here or is this an error condition? */
+ error = TRUE;
+ ret_idx = UNASSIGNED_INDEX;
+ }
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ if (!error) {
+ ret_idx = pmhctl->llist_info.reg_read_idx =
+ mddi_get_next_free_llist_item(host_idx, wait);
+ /* clear the reg_read_waiting flag */
+ pmhctl->llist_info.reg_read_waiting = FALSE;
+ }
+
+ if (error)
+ MDDI_MSG_ERR("***** Reg read still in progress! ****\n");
+ return ret_idx;
+#endif
+
+}
+
+void mddi_queue_forward_packets(uint16 first_llist_idx,
+ uint16 last_llist_idx,
+ boolean wait,
+ mddi_llist_done_cb_type llist_done_cb,
+ mddi_host_type host_idx)
+{
+ unsigned long flags;
+ mddi_linked_list_type *llist;
+ mddi_linked_list_type *llist_dma;
+ mddi_host_cntl_type *pmhctl = &(mhctl[host_idx]);
+
+ if ((first_llist_idx >= UNASSIGNED_INDEX) ||
+ (last_llist_idx >= UNASSIGNED_INDEX)) {
+ MDDI_MSG_ERR("MDDI queueing invalid linked list\n");
+ return;
+ }
+
+ if (pmhctl->link_state == MDDI_LINK_DISABLED)
+ MDDI_MSG_CRIT("MDDI host powered down!\n");
+
+ llist = pmhctl->llist_ptr;
+ llist_dma = pmhctl->llist_dma_ptr;
+
+ /* clean cache so MDDI host can read data */
+ memory_barrier();
+
+ pmhctl->llist_notify[last_llist_idx].waiting = wait;
+ if (wait)
+ INIT_COMPLETION(pmhctl->llist_notify[last_llist_idx].done_comp);
+ pmhctl->llist_notify[last_llist_idx].done_cb = llist_done_cb;
+
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+
+ if ((pmhctl->llist_info.transmitting_start_idx == UNASSIGNED_INDEX) &&
+ (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) &&
+ (pmhctl->rev_state == MDDI_REV_IDLE)) {
+ /* no packets are currently transmitting */
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
+ /* This is the special case where the packet is a register read. */
+ pmhctl->rev_state = MDDI_REV_REG_READ_ISSUED;
+ mddi_reg_read_retry = 0;
+ /* mddi_rev_reg_read_attempt = 1; */
+ }
+#endif
+ /* assign transmitting index values */
+ pmhctl->llist_info.transmitting_start_idx = first_llist_idx;
+ pmhctl->llist_info.transmitting_end_idx = last_llist_idx;
+
+ /* turn on clock(s), if they have been disabled */
+ mddi_host_enable_hclk();
+ mddi_host_enable_io_clock();
+ pmhctl->int_type.llist_ptr_write_1++;
+ /* Write to primary pointer register */
+ dma_coherent_pre_ops();
+ mddi_host_reg_out(PRI_PTR, &llist_dma[first_llist_idx]);
+
+ /* enable interrupt when complete */
+ mddi_host_reg_outm(INTEN, MDDI_INT_PRI_LINK_LIST_DONE,
+ MDDI_INT_PRI_LINK_LIST_DONE);
+
+ } else if (pmhctl->llist_info.waiting_start_idx == UNASSIGNED_INDEX) {
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
+ /*
+ * we have a register read to send but need to wait
+ * for current reverse activity to end or there are
+ * packets currently transmitting
+ */
+ /* mddi_rev_reg_read_attempt = 0; */
+ pmhctl->llist_info.reg_read_waiting = TRUE;
+ }
+#endif
+
+ /* assign waiting index values */
+ pmhctl->llist_info.waiting_start_idx = first_llist_idx;
+ pmhctl->llist_info.waiting_end_idx = last_llist_idx;
+ } else {
+ uint16 prev_end_idx = pmhctl->llist_info.waiting_end_idx;
+#ifndef FEATURE_MDDI_DISABLE_REVERSE
+ if (first_llist_idx == pmhctl->llist_info.reg_read_idx) {
+ /*
+ * we have a register read to send but need to wait
+ * for current reverse activity to end or there are
+ * packets currently transmitting
+ */
+ /* mddi_rev_reg_read_attempt = 0; */
+ pmhctl->llist_info.reg_read_waiting = TRUE;
+ }
+#endif
+
+ llist = pmhctl->llist_ptr;
+
+ /* clear end flag in previous last packet */
+ llist[prev_end_idx].link_controller_flags = 0;
+ pmhctl->llist_notify[prev_end_idx].next_idx = first_llist_idx;
+
+ /* set the next_packet_pointer of the previous last packet */
+ llist[prev_end_idx].next_packet_pointer =
+ (void *)(&llist_dma[first_llist_idx]);
+
+ /* clean cache so MDDI host can read data */
+ memory_barrier();
+
+ /* assign new waiting last index value */
+ pmhctl->llist_info.waiting_end_idx = last_llist_idx;
+ }
+
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+}
+
+void mddi_host_write_pix_attr_reg(uint32 value)
+{
+ (void)value;
+}
+
+void mddi_queue_reverse_encapsulation(boolean wait)
+{
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ MDDI_MSG_CRIT("No reverse link available\n");
+ (void)wait;
+#else
+ unsigned long flags;
+ boolean error = FALSE;
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+ mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
+
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+
+ /* turn on clock(s), if they have been disabled */
+ mddi_host_enable_hclk();
+ mddi_host_enable_io_clock();
+
+ if (wait) {
+ if (!mddi_rev_user.waiting) {
+ mddi_rev_user.waiting = TRUE;
+ INIT_COMPLETION(mddi_rev_user.done_comp);
+ } else
+ error = TRUE;
+ }
+ mddi_rev_encap_user_request = TRUE;
+
+ if (pmhctl->rev_state == MDDI_REV_IDLE) {
+ /* attempt to send the reverse encapsulation now */
+ mddi_host_type orig_host_idx = mddi_curr_host;
+ mddi_curr_host = host_idx;
+ mddi_issue_reverse_encapsulation();
+ mddi_curr_host = orig_host_idx;
+ }
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ if (error) {
+ MDDI_MSG_ERR("Reverse Encap request already in progress\n");
+ } else if (wait)
+ wait_for_completion_killable(&(mddi_rev_user.done_comp));
+#endif
+}
+
+/* ISR to be executed */
+boolean mddi_set_rev_handler(mddi_rev_handler_type handler, uint16 pkt_type)
+{
+#ifdef FEATURE_MDDI_DISABLE_REVERSE
+ MDDI_MSG_CRIT("No reverse link available\n");
+ (void)handler;
+ (void)pkt_type;
+ return (FALSE);
+#else
+ unsigned long flags;
+ uint16 hdlr;
+ boolean handler_set = FALSE;
+ boolean overwrite = FALSE;
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+ mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
+
+ /* Disable interrupts */
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+
+ for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) {
+ if (mddi_rev_pkt_handler[hdlr].pkt_type == pkt_type) {
+ mddi_rev_pkt_handler[hdlr].handler = handler;
+ if (handler == NULL) {
+ /* clearing handler from table */
+ mddi_rev_pkt_handler[hdlr].pkt_type =
+ INVALID_PKT_TYPE;
+ handler_set = TRUE;
+ if (pkt_type == 0x10) { /* video stream packet */
+ /* ensure HCLK on to MDDI host core before register write */
+ mddi_host_enable_hclk();
+ /* No longer getting video, so reset rev encap size to default */
+ pmhctl->rev_pkt_size =
+ MDDI_DEFAULT_REV_PKT_SIZE;
+ mddi_host_reg_out(REV_ENCAP_SZ,
+ pmhctl->rev_pkt_size);
+ }
+ } else {
+ /* already a handler for this packet */
+ overwrite = TRUE;
+ }
+ break;
+ }
+ }
+ if ((hdlr >= MAX_MDDI_REV_HANDLERS) && (handler != NULL)) {
+ /* assigning new handler */
+ for (hdlr = 0; hdlr < MAX_MDDI_REV_HANDLERS; hdlr++) {
+ if (mddi_rev_pkt_handler[hdlr].pkt_type ==
+ INVALID_PKT_TYPE) {
+ if ((pkt_type == 0x10) && /* video stream packet */
+ (pmhctl->rev_pkt_size <
+ MDDI_VIDEO_REV_PKT_SIZE)) {
+ /* ensure HCLK on to MDDI host core before register write */
+ mddi_host_enable_hclk();
+ /* Increase Rev Encap Size */
+ pmhctl->rev_pkt_size =
+ MDDI_VIDEO_REV_PKT_SIZE;
+ mddi_host_reg_out(REV_ENCAP_SZ,
+ pmhctl->rev_pkt_size);
+ }
+ mddi_rev_pkt_handler[hdlr].handler = handler;
+ mddi_rev_pkt_handler[hdlr].pkt_type = pkt_type;
+ handler_set = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Restore interrupts */
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+
+ if (overwrite)
+ MDDI_MSG_ERR("Overwriting previous rev packet handler\n");
+
+ return handler_set;
+
+#endif
+} /* mddi_set_rev_handler */
+
+void mddi_host_disable_hibernation(boolean disable)
+{
+ mddi_host_type host_idx = MDDI_HOST_PRIM;
+ mddi_host_cntl_type *pmhctl = &(mhctl[MDDI_HOST_PRIM]);
+
+ if (disable) {
+ pmhctl->disable_hibernation = TRUE;
+ /* hibernation will be turned off by isr next time it is entered */
+ } else {
+ if (pmhctl->disable_hibernation) {
+ unsigned long flags;
+ spin_lock_irqsave(&mddi_host_spin_lock, flags);
+ if (!MDDI_HOST_IS_HCLK_ON)
+ MDDI_HOST_ENABLE_HCLK;
+ mddi_host_reg_out(CMD, MDDI_CMD_HIBERNATE | 1);
+ spin_unlock_irqrestore(&mddi_host_spin_lock, flags);
+ pmhctl->disable_hibernation = FALSE;
+ }
+ }
+}
+
+void mddi_mhctl_remove(mddi_host_type host_idx)
+{
+ mddi_host_cntl_type *pmhctl;
+
+ pmhctl = &(mhctl[host_idx]);
+
+ dma_free_coherent(NULL, MDDI_LLIST_POOL_SIZE, (void *)pmhctl->llist_ptr,
+ pmhctl->llist_dma_addr);
+
+ dma_free_coherent(NULL, MDDI_MAX_REV_DATA_SIZE,
+ (void *)pmhctl->rev_data_buf,
+ pmhctl->rev_data_dma_addr);
+}
diff --git a/drivers/staging/msm/mddihosti.h b/drivers/staging/msm/mddihosti.h
new file mode 100644
index 000000000000..7b26a4253896
--- /dev/null
+++ b/drivers/staging/msm/mddihosti.h
@@ -0,0 +1,547 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDDIHOSTI_H
+#define MDDIHOSTI_H
+
+#include "msm_fb.h"
+#include "mddihost.h"
+#include <linux/clk.h>
+
+/* Register offsets in MDDI, applies to both msm_pmdh_base and
+ * (u32)msm_emdh_base. */
+#define MDDI_CMD 0x0000
+#define MDDI_VERSION 0x0004
+#define MDDI_PRI_PTR 0x0008
+#define MDDI_BPS 0x0010
+#define MDDI_SPM 0x0014
+#define MDDI_INT 0x0018
+#define MDDI_INTEN 0x001c
+#define MDDI_REV_PTR 0x0020
+#define MDDI_REV_SIZE 0x0024
+#define MDDI_STAT 0x0028
+#define MDDI_REV_RATE_DIV 0x002c
+#define MDDI_REV_CRC_ERR 0x0030
+#define MDDI_TA1_LEN 0x0034
+#define MDDI_TA2_LEN 0x0038
+#define MDDI_TEST 0x0040
+#define MDDI_REV_PKT_CNT 0x0044
+#define MDDI_DRIVE_HI 0x0048
+#define MDDI_DRIVE_LO 0x004c
+#define MDDI_DISP_WAKE 0x0050
+#define MDDI_REV_ENCAP_SZ 0x0054
+#define MDDI_RTD_VAL 0x0058
+#define MDDI_PAD_CTL 0x0068
+#define MDDI_DRIVER_START_CNT 0x006c
+#define MDDI_CORE_VER 0x008c
+#define MDDI_FIFO_ALLOC 0x0090
+#define MDDI_PAD_IO_CTL 0x00a0
+#define MDDI_PAD_CAL 0x00a4
+
+extern u32 mddi_msg_level;
+
+/* No longer need to write to clear these registers */
+#define xxxx_mddi_host_reg_outm(reg, mask, val) \
+do { \
+ if (host_idx == MDDI_HOST_PRIM) \
+ mddi_host_reg_outm_pmdh(reg, mask, val); \
+ else \
+ mddi_host_reg_outm_emdh(reg, mask, val); \
+} while (0)
+
+#define mddi_host_reg_outm(reg, mask, val) \
+do { \
+ unsigned long __addr; \
+ if (host_idx == MDDI_HOST_PRIM) \
+ __addr = (u32)msm_pmdh_base + MDDI_##reg; \
+ else \
+ __addr = (u32)msm_emdh_base + MDDI_##reg; \
+ writel((readl(__addr) & ~(mask)) | ((val) & (mask)), __addr); \
+} while (0)
+
+#define xxxx_mddi_host_reg_out(reg, val) \
+do { \
+ if (host_idx == MDDI_HOST_PRIM) \
+ mddi_host_reg_out_pmdh(reg, val); \
+ else \
+ mddi_host_reg_out_emdh(reg, val); \
+ } while (0)
+
+#define mddi_host_reg_out(reg, val) \
+do { \
+ if (host_idx == MDDI_HOST_PRIM) \
+ writel(val, (u32)msm_pmdh_base + MDDI_##reg); \
+ else \
+ writel(val, (u32)msm_emdh_base + MDDI_##reg); \
+} while (0)
+
+#define xxxx_mddi_host_reg_in(reg) \
+ ((host_idx) ? \
+ mddi_host_reg_in_emdh(reg) : mddi_host_reg_in_pmdh(reg));
+
+#define mddi_host_reg_in(reg) \
+((host_idx) ? \
+ readl((u32)msm_emdh_base + MDDI_##reg) : \
+ readl((u32)msm_pmdh_base + MDDI_##reg)) \
+
+#define xxxx_mddi_host_reg_inm(reg, mask) \
+ ((host_idx) ? \
+ mddi_host_reg_inm_emdh(reg, mask) : \
+ mddi_host_reg_inm_pmdh(reg, mask);)
+
+#define mddi_host_reg_inm(reg, mask) \
+((host_idx) ? \
+ readl((u32)msm_emdh_base + MDDI_##reg) & (mask) : \
+ readl((u32)msm_pmdh_base + MDDI_##reg) & (mask)) \
+
+/* Using non-cacheable pmem, so do nothing */
+#define mddi_invalidate_cache_lines(addr_start, num_bytes)
+/*
+ * Using non-cacheable pmem, so do nothing with cache
+ * but, ensure write goes out to memory
+ */
+#define mddi_flush_cache_lines(addr_start, num_bytes) \
+ (void) addr_start; \
+ (void) num_bytes; \
+ memory_barrier()
+
+/* Since this translates to Remote Procedure Calls to check on clock status
+* just use a local variable to keep track of io_clock */
+#define MDDI_HOST_IS_IO_CLOCK_ON mddi_host_io_clock_on
+#define MDDI_HOST_ENABLE_IO_CLOCK
+#define MDDI_HOST_DISABLE_IO_CLOCK
+#define MDDI_HOST_IS_HCLK_ON mddi_host_hclk_on
+#define MDDI_HOST_ENABLE_HCLK
+#define MDDI_HOST_DISABLE_HCLK
+#define FEATURE_MDDI_HOST_IO_CLOCK_CONTROL_DISABLE
+#define FEATURE_MDDI_HOST_HCLK_CONTROL_DISABLE
+
+#define TRAMP_MDDI_HOST_ISR TRAMP_MDDI_PRI_ISR
+#define TRAMP_MDDI_HOST_EXT_ISR TRAMP_MDDI_EXT_ISR
+#define MDP_LINE_COUNT_BMSK 0x3ff
+#define MDP_SYNC_STATUS 0x000c
+#define MDP_LINE_COUNT \
+(readl(msm_mdp_base + MDP_SYNC_STATUS) & MDP_LINE_COUNT_BMSK)
+
+/* MDP sends 256 pixel packets, so lower value hibernates more without
+* significantly increasing latency of waiting for next subframe */
+#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00
+
+#if defined(CONFIG_FB_MSM_MDP31) || defined(CONFIG_FB_MSM_MDP40)
+#define MDDI_HOST_TA2_LEN 0x001a
+#define MDDI_HOST_REV_RATE_DIV 0x0004
+#else
+#define MDDI_HOST_TA2_LEN 0x000c
+#define MDDI_HOST_REV_RATE_DIV 0x0002
+#endif
+
+#define MDDI_MSG_EMERG(msg, ...) \
+ if (mddi_msg_level > 0) \
+ printk(KERN_EMERG msg, ## __VA_ARGS__);
+#define MDDI_MSG_ALERT(msg, ...) \
+ if (mddi_msg_level > 1) \
+ printk(KERN_ALERT msg, ## __VA_ARGS__);
+#define MDDI_MSG_CRIT(msg, ...) \
+ if (mddi_msg_level > 2) \
+ printk(KERN_CRIT msg, ## __VA_ARGS__);
+#define MDDI_MSG_ERR(msg, ...) \
+ if (mddi_msg_level > 3) \
+ printk(KERN_ERR msg, ## __VA_ARGS__);
+#define MDDI_MSG_WARNING(msg, ...) \
+ if (mddi_msg_level > 4) \
+ printk(KERN_WARNING msg, ## __VA_ARGS__);
+#define MDDI_MSG_NOTICE(msg, ...) \
+ if (mddi_msg_level > 5) \
+ printk(KERN_NOTICE msg, ## __VA_ARGS__);
+#define MDDI_MSG_INFO(msg, ...) \
+ if (mddi_msg_level > 6) \
+ printk(KERN_INFO msg, ## __VA_ARGS__);
+#define MDDI_MSG_DEBUG(msg, ...) \
+ if (mddi_msg_level > 7) \
+ printk(KERN_DEBUG msg, ## __VA_ARGS__);
+
+#define GCC_PACKED __attribute__((packed))
+typedef struct GCC_PACKED {
+ uint16 packet_length;
+ /* total # of bytes in the packet not including
+ the packet_length field. */
+
+ uint16 packet_type;
+ /* A Packet Type of 70 identifies the packet as
+ a Client status Packet. */
+
+ uint16 bClient_ID;
+ /* This field is reserved for future use and shall
+ be set to zero. */
+
+} mddi_rev_packet_type;
+
+typedef struct GCC_PACKED {
+ uint16 packet_length;
+ /* total # of bytes in the packet not including
+ the packet_length field. */
+
+ uint16 packet_type;
+ /* A Packet Type of 70 identifies the packet as
+ a Client status Packet. */
+
+ uint16 bClient_ID;
+ /* This field is reserved for future use and shall
+ be set to zero. */
+
+ uint16 reverse_link_request;
+ /* 16 bit unsigned integer with number of bytes client
+ needs in the * reverse encapsulation message
+ to transmit data. */
+
+ uint8 crc_error_count;
+ uint8 capability_change;
+ uint16 graphics_busy_flags;
+
+ uint16 parameter_CRC;
+ /* 16-bit CRC of all the bytes in the packet
+ including Packet Length. */
+
+} mddi_client_status_type;
+
+typedef struct GCC_PACKED {
+ uint16 packet_length;
+ /* total # of bytes in the packet not including
+ the packet_length field. */
+
+ uint16 packet_type;
+ /* A Packet Type of 66 identifies the packet as
+ a Client Capability Packet. */
+
+ uint16 bClient_ID;
+ /* This field is reserved for future use and
+ shall be set to zero. */
+
+ uint16 Protocol_Version;
+ uint16 Minimum_Protocol_Version;
+ uint16 Data_Rate_Capability;
+ uint8 Interface_Type_Capability;
+ uint8 Number_of_Alt_Displays;
+ uint16 PostCal_Data_Rate;
+ uint16 Bitmap_Width;
+ uint16 Bitmap_Height;
+ uint16 Display_Window_Width;
+ uint16 Display_Window_Height;
+ uint32 Color_Map_Size;
+ uint16 Color_Map_RGB_Width;
+ uint16 RGB_Capability;
+ uint8 Monochrome_Capability;
+ uint8 Reserved_1;
+ uint16 Y_Cb_Cr_Capability;
+ uint16 Bayer_Capability;
+ uint16 Alpha_Cursor_Image_Planes;
+ uint32 Client_Feature_Capability_Indicators;
+ uint8 Maximum_Video_Frame_Rate_Capability;
+ uint8 Minimum_Video_Frame_Rate_Capability;
+ uint16 Minimum_Sub_frame_Rate;
+ uint16 Audio_Buffer_Depth;
+ uint16 Audio_Channel_Capability;
+ uint16 Audio_Sample_Rate_Capability;
+ uint8 Audio_Sample_Resolution;
+ uint8 Mic_Audio_Sample_Resolution;
+ uint16 Mic_Sample_Rate_Capability;
+ uint8 Keyboard_Data_Format;
+ uint8 pointing_device_data_format;
+ uint16 content_protection_type;
+ uint16 Mfr_Name;
+ uint16 Product_Code;
+ uint16 Reserved_3;
+ uint32 Serial_Number;
+ uint8 Week_of_Manufacture;
+ uint8 Year_of_Manufacture;
+
+ uint16 parameter_CRC;
+ /* 16-bit CRC of all the bytes in the packet including Packet Length. */
+
+} mddi_client_capability_type;
+
+typedef struct GCC_PACKED {
+ uint16 packet_length;
+ /* total # of bytes in the packet not including the packet_length field. */
+
+ uint16 packet_type;
+ /* A Packet Type of 16 identifies the packet as a Video Stream Packet. */
+
+ uint16 bClient_ID;
+ /* This field is reserved for future use and shall be set to zero. */
+
+ uint16 video_data_format_descriptor;
+ /* format of each pixel in the Pixel Data in the present stream in the
+ * present packet.
+ * If bits [15:13] = 000 monochrome
+ * If bits [15:13] = 001 color pixels (palette).
+ * If bits [15:13] = 010 color pixels in raw RGB
+ * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format
+ * If bits [15:13] = 100 Bayer pixels
+ */
+
+ uint16 pixel_data_attributes;
+ /* interpreted as follows:
+ * Bits [1:0] = 11 pixel data is displayed to both eyes
+ * Bits [1:0] = 10 pixel data is routed to the left eye only.
+ * Bits [1:0] = 01 pixel data is routed to the right eye only.
+ * Bits [1:0] = 00 pixel data is routed to the alternate display.
+ * Bit 2 is 0 Pixel Data is in the standard progressive format.
+ * Bit 2 is 1 Pixel Data is in interlace format.
+ * Bit 3 is 0 Pixel Data is in the standard progressive format.
+ * Bit 3 is 1 Pixel Data is in alternate pixel format.
+ * Bit 4 is 0 Pixel Data is to or from the display frame buffer.
+ * Bit 4 is 1 Pixel Data is to or from the camera.
+ * Bit 5 is 0 pixel data contains the next consecutive row of pixels.
+ * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge,
+ * X Start, and Y Start parameters are not defined and
+ * shall be ignored by the client.
+ * Bits [7:6] = 01 Pixel data is written to the offline image buffer.
+ * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display.
+ * Bits [7:6] = 11 Pixel data is written to all image buffers.
+ * Bits [7:6] = 10 Invalid. Reserved for future use.
+ * Bits 8 through 11 alternate display number.
+ * Bits 12 through 14 are reserved for future use and shall be set to zero.
+ * Bit 15 is 1 the row of pixels is the last row of pixels in a frame.
+ */
+
+ uint16 x_left_edge;
+ uint16 y_top_edge;
+ /* X,Y coordinate of the top left edge of the screen window */
+
+ uint16 x_right_edge;
+ uint16 y_bottom_edge;
+ /* X,Y coordinate of the bottom right edge of the window being updated. */
+
+ uint16 x_start;
+ uint16 y_start;
+ /* (X Start, Y Start) is the first pixel in the Pixel Data field below. */
+
+ uint16 pixel_count;
+ /* number of pixels in the Pixel Data field below. */
+
+ uint16 parameter_CRC;
+ /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */
+
+ uint16 reserved;
+ /* 16-bit variable to make structure align on 4 byte boundary */
+
+} mddi_video_stream_packet_type;
+
+typedef struct GCC_PACKED {
+ uint16 packet_length;
+ /* total # of bytes in the packet not including the packet_length field. */
+
+ uint16 packet_type;
+ /* A Packet Type of 146 identifies the packet as a Register Access Packet. */
+
+ uint16 bClient_ID;
+ /* This field is reserved for future use and shall be set to zero. */
+
+ uint16 read_write_info;
+ /* Bits 13:0 a 14-bit unsigned integer that specifies the number of
+ * 32-bit Register Data List items to be transferred in the
+ * Register Data List field.
+ * Bits[15:14] = 00 Write to register(s);
+ * Bits[15:14] = 10 Read from register(s);
+ * Bits[15:14] = 11 Response to a Read.
+ * Bits[15:14] = 01 this value is reserved for future use. */
+
+ uint32 register_address;
+ /* the register address that is to be written to or read from. */
+
+ uint16 parameter_CRC;
+ /* 16-bit CRC of all bytes from the Packet Length to the Register Address. */
+
+ uint32 register_data_list;
+ /* list of 4-byte register data values for/from client registers */
+
+} mddi_register_access_packet_type;
+
+typedef union GCC_PACKED {
+ mddi_video_stream_packet_type video_pkt;
+ mddi_register_access_packet_type register_pkt;
+ /* add 48 byte pad to ensure 64 byte llist struct, that can be
+ * manipulated easily with cache */
+ uint32 alignment_pad[12]; /* 48 bytes */
+} mddi_packet_header_type;
+
+typedef struct GCC_PACKED mddi_host_llist_struct {
+ uint16 link_controller_flags;
+ uint16 packet_header_count;
+ uint16 packet_data_count;
+ void *packet_data_pointer;
+ struct mddi_host_llist_struct *next_packet_pointer;
+ uint16 reserved;
+ mddi_packet_header_type packet_header;
+} mddi_linked_list_type;
+
+typedef struct {
+ struct completion done_comp;
+ mddi_llist_done_cb_type done_cb;
+ uint16 next_idx;
+ boolean waiting;
+ boolean in_use;
+} mddi_linked_list_notify_type;
+
+#define MDDI_LLIST_POOL_SIZE 0x1000
+#define MDDI_MAX_NUM_LLIST_ITEMS (MDDI_LLIST_POOL_SIZE / \
+ sizeof(mddi_linked_list_type))
+#define UNASSIGNED_INDEX MDDI_MAX_NUM_LLIST_ITEMS
+#define MDDI_FIRST_DYNAMIC_LLIST_IDX 0
+
+/* Static llist items can be used for applications that frequently send
+ * the same set of packets using the linked list interface. */
+/* Here we configure for 6 static linked list items:
+ * The 1st is used for a the adaptive backlight setting.
+ * and the remaining 5 are used for sending window adjustments for
+ * MDDI clients that need windowing info sent separate from video
+ * packets. */
+#define MDDI_NUM_STATIC_ABL_ITEMS 1
+#define MDDI_NUM_STATIC_WINDOW_ITEMS 5
+#define MDDI_NUM_STATIC_LLIST_ITEMS (MDDI_NUM_STATIC_ABL_ITEMS + \
+ MDDI_NUM_STATIC_WINDOW_ITEMS)
+#define MDDI_NUM_DYNAMIC_LLIST_ITEMS (MDDI_MAX_NUM_LLIST_ITEMS - \
+ MDDI_NUM_STATIC_LLIST_ITEMS)
+
+#define MDDI_FIRST_STATIC_LLIST_IDX MDDI_NUM_DYNAMIC_LLIST_ITEMS
+#define MDDI_FIRST_STATIC_ABL_IDX MDDI_FIRST_STATIC_LLIST_IDX
+#define MDDI_FIRST_STATIC_WINDOW_IDX (MDDI_FIRST_STATIC_LLIST_IDX + \
+ MDDI_NUM_STATIC_ABL_ITEMS)
+
+/* GPIO registers */
+#define VSYNC_WAKEUP_REG 0x80
+#define GPIO_REG 0x81
+#define GPIO_OUTPUT_REG 0x82
+#define GPIO_INTERRUPT_REG 0x83
+#define GPIO_INTERRUPT_ENABLE_REG 0x84
+#define GPIO_POLARITY_REG 0x85
+
+/* Interrupt Bits */
+#define MDDI_INT_PRI_PTR_READ 0x0001
+#define MDDI_INT_SEC_PTR_READ 0x0002
+#define MDDI_INT_REV_DATA_AVAIL 0x0004
+#define MDDI_INT_DISP_REQ 0x0008
+#define MDDI_INT_PRI_UNDERFLOW 0x0010
+#define MDDI_INT_SEC_UNDERFLOW 0x0020
+#define MDDI_INT_REV_OVERFLOW 0x0040
+#define MDDI_INT_CRC_ERROR 0x0080
+#define MDDI_INT_MDDI_IN 0x0100
+#define MDDI_INT_PRI_OVERWRITE 0x0200
+#define MDDI_INT_SEC_OVERWRITE 0x0400
+#define MDDI_INT_REV_OVERWRITE 0x0800
+#define MDDI_INT_DMA_FAILURE 0x1000
+#define MDDI_INT_LINK_ACTIVE 0x2000
+#define MDDI_INT_IN_HIBERNATION 0x4000
+#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000
+#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000
+#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000
+#define MDDI_INT_RTD_FAILURE 0x40000
+
+#define MDDI_INT_ERROR_CONDITIONS ( \
+ MDDI_INT_PRI_UNDERFLOW | MDDI_INT_SEC_UNDERFLOW | \
+ MDDI_INT_REV_OVERFLOW | MDDI_INT_CRC_ERROR | \
+ MDDI_INT_PRI_OVERWRITE | MDDI_INT_SEC_OVERWRITE | \
+ MDDI_INT_RTD_FAILURE | \
+ MDDI_INT_REV_OVERWRITE | MDDI_INT_DMA_FAILURE)
+
+#define MDDI_INT_LINK_STATE_CHANGES ( \
+ MDDI_INT_LINK_ACTIVE | MDDI_INT_IN_HIBERNATION)
+
+/* Status Bits */
+#define MDDI_STAT_LINK_ACTIVE 0x0001
+#define MDDI_STAT_NEW_REV_PTR 0x0002
+#define MDDI_STAT_NEW_PRI_PTR 0x0004
+#define MDDI_STAT_NEW_SEC_PTR 0x0008
+#define MDDI_STAT_IN_HIBERNATION 0x0010
+#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020
+#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040
+#define MDDI_STAT_PENDING_TIMING_PKT 0x0080
+#define MDDI_STAT_PENDING_REV_ENCAP 0x0100
+#define MDDI_STAT_PENDING_POWERDOWN 0x0200
+#define MDDI_STAT_RTD_MEAS_FAIL 0x0800
+#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000
+
+/* Command Bits */
+#define MDDI_CMD_POWERDOWN 0x0100
+#define MDDI_CMD_POWERUP 0x0200
+#define MDDI_CMD_HIBERNATE 0x0300
+#define MDDI_CMD_RESET 0x0400
+#define MDDI_CMD_DISP_IGNORE 0x0501
+#define MDDI_CMD_DISP_LISTEN 0x0500
+#define MDDI_CMD_SEND_REV_ENCAP 0x0600
+#define MDDI_CMD_GET_CLIENT_CAP 0x0601
+#define MDDI_CMD_GET_CLIENT_STATUS 0x0602
+#define MDDI_CMD_SEND_RTD 0x0700
+#define MDDI_CMD_LINK_ACTIVE 0x0900
+#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00
+
+extern void mddi_host_init(mddi_host_type host);
+extern void mddi_host_powerdown(mddi_host_type host);
+extern uint16 mddi_get_next_free_llist_item(mddi_host_type host, boolean wait);
+extern uint16 mddi_get_reg_read_llist_item(mddi_host_type host, boolean wait);
+extern void mddi_queue_forward_packets(uint16 first_llist_idx,
+ uint16 last_llist_idx,
+ boolean wait,
+ mddi_llist_done_cb_type llist_done_cb,
+ mddi_host_type host);
+
+extern void mddi_host_write_pix_attr_reg(uint32 value);
+extern void mddi_client_lcd_gpio_poll(uint32 poll_reg_val);
+extern void mddi_client_lcd_vsync_detected(boolean detected);
+extern void mddi_host_disable_hibernation(boolean disable);
+
+extern mddi_linked_list_type *llist_extern[];
+extern mddi_linked_list_type *llist_dma_extern[];
+extern mddi_linked_list_notify_type *llist_extern_notify[];
+extern struct timer_list mddi_host_timer;
+
+typedef struct {
+ uint16 transmitting_start_idx;
+ uint16 transmitting_end_idx;
+ uint16 waiting_start_idx;
+ uint16 waiting_end_idx;
+ uint16 reg_read_idx;
+ uint16 next_free_idx;
+ boolean reg_read_waiting;
+} mddi_llist_info_type;
+
+extern mddi_llist_info_type mddi_llist;
+
+#define MDDI_GPIO_DEFAULT_POLLING_INTERVAL 200
+typedef struct {
+ uint32 polling_reg;
+ uint32 polling_val;
+ uint32 polling_interval;
+ boolean polling_enabled;
+} mddi_gpio_info_type;
+
+uint32 mddi_get_client_id(void);
+void mddi_mhctl_remove(mddi_host_type host_idx);
+void mddi_host_timer_service(unsigned long data);
+#endif /* MDDIHOSTI_H */
diff --git a/drivers/staging/msm/mdp.c b/drivers/staging/msm/mdp.c
new file mode 100644
index 000000000000..36053afdebe2
--- /dev/null
+++ b/drivers/staging/msm/mdp.c
@@ -0,0 +1,1113 @@
+/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#ifdef CONFIG_FB_MSM_MDP40
+#include "mdp4.h"
+#endif
+
+static struct clk *mdp_clk;
+static struct clk *mdp_pclk;
+
+struct completion mdp_ppp_comp;
+struct semaphore mdp_ppp_mutex;
+struct semaphore mdp_pipe_ctrl_mutex;
+
+unsigned long mdp_timer_duration = (HZ); /* 1 sec */
+/* unsigned long mdp_mdp_timer_duration=0; */
+
+boolean mdp_ppp_waiting = FALSE;
+uint32 mdp_tv_underflow_cnt;
+uint32 mdp_lcdc_underflow_cnt;
+
+boolean mdp_current_clk_on = FALSE;
+boolean mdp_is_in_isr = FALSE;
+
+/*
+ * legacy mdp_in_processing is only for DMA2-MDDI
+ * this applies to DMA2 block only
+ */
+uint32 mdp_in_processing = FALSE;
+
+#ifdef CONFIG_FB_MSM_MDP40
+uint32 mdp_intr_mask = MDP4_ANY_INTR_MASK;
+#else
+uint32 mdp_intr_mask = MDP_ANY_INTR_MASK;
+#endif
+
+MDP_BLOCK_TYPE mdp_debug[MDP_MAX_BLOCK];
+
+int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
+
+spinlock_t mdp_spin_lock;
+struct workqueue_struct *mdp_dma_wq; /*mdp dma wq */
+struct workqueue_struct *mdp_vsync_wq; /*mdp vsync wq */
+
+static struct workqueue_struct *mdp_pipe_ctrl_wq; /* mdp mdp pipe ctrl wq */
+static struct delayed_work mdp_pipe_ctrl_worker;
+
+#ifdef CONFIG_FB_MSM_MDP40
+struct mdp_dma_data dma2_data;
+struct mdp_dma_data dma_s_data;
+struct mdp_dma_data dma_e_data;
+#else
+static struct mdp_dma_data dma2_data;
+static struct mdp_dma_data dma_s_data;
+static struct mdp_dma_data dma_e_data;
+#endif
+static struct mdp_dma_data dma3_data;
+
+extern ktime_t mdp_dma2_last_update_time;
+
+extern uint32 mdp_dma2_update_time_in_usec;
+extern int mdp_lcd_rd_cnt_offset_slow;
+extern int mdp_lcd_rd_cnt_offset_fast;
+extern int mdp_usec_diff_threshold;
+
+#ifdef CONFIG_FB_MSM_LCDC
+extern int mdp_lcdc_pclk_clk_rate;
+extern int mdp_lcdc_pad_pclk_clk_rate;
+extern int first_pixel_start_x;
+extern int first_pixel_start_y;
+#endif
+
+#ifdef MSM_FB_ENABLE_DBGFS
+struct dentry *mdp_dir;
+#endif
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int mdp_suspend(struct platform_device *pdev, pm_message_t state);
+#else
+#define mdp_suspend NULL
+#endif
+
+struct timeval mdp_dma2_timeval;
+struct timeval mdp_ppp_timeval;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static struct early_suspend early_suspend;
+#endif
+
+#ifndef CONFIG_FB_MSM_MDP22
+DEFINE_MUTEX(mdp_lut_push_sem);
+static int mdp_lut_i;
+static int mdp_lut_hw_update(struct fb_cmap *cmap)
+{
+ int i;
+ u16 *c[3];
+ u16 r, g, b;
+
+ c[0] = cmap->green;
+ c[1] = cmap->blue;
+ c[2] = cmap->red;
+
+ for (i = 0; i < cmap->len; i++) {
+ if (copy_from_user(&r, cmap->red++, sizeof(r)) ||
+ copy_from_user(&g, cmap->green++, sizeof(g)) ||
+ copy_from_user(&b, cmap->blue++, sizeof(b)))
+ return -EFAULT;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ MDP_OUTP(MDP_BASE + 0x94800 +
+#else
+ MDP_OUTP(MDP_BASE + 0x93800 +
+#endif
+ (0x400*mdp_lut_i) + cmap->start*4 + i*4,
+ ((g & 0xff) |
+ ((b & 0xff) << 8) |
+ ((r & 0xff) << 16)));
+ }
+
+ return 0;
+}
+
+static int mdp_lut_push;
+static int mdp_lut_push_i;
+static int mdp_lut_update_nonlcdc(struct fb_info *info, struct fb_cmap *cmap)
+{
+ int ret;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ ret = mdp_lut_hw_update(cmap);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ if (ret)
+ return ret;
+
+ mutex_lock(&mdp_lut_push_sem);
+ mdp_lut_push = 1;
+ mdp_lut_push_i = mdp_lut_i;
+ mutex_unlock(&mdp_lut_push_sem);
+
+ mdp_lut_i = (mdp_lut_i + 1)%2;
+
+ return 0;
+}
+
+static int mdp_lut_update_lcdc(struct fb_info *info, struct fb_cmap *cmap)
+{
+ int ret;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ ret = mdp_lut_hw_update(cmap);
+
+ if (ret) {
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ return ret;
+ }
+
+ MDP_OUTP(MDP_BASE + 0x90070, (mdp_lut_i << 10) | 0x17);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_lut_i = (mdp_lut_i + 1)%2;
+
+ return 0;
+}
+
+#define MDP_HIST_MAX_BIN 32
+static __u32 mdp_hist_r[MDP_HIST_MAX_BIN];
+static __u32 mdp_hist_g[MDP_HIST_MAX_BIN];
+static __u32 mdp_hist_b[MDP_HIST_MAX_BIN];
+
+#ifdef CONFIG_FB_MSM_MDP40
+struct mdp_histogram mdp_hist;
+struct completion mdp_hist_comp;
+#else
+static struct mdp_histogram mdp_hist;
+static struct completion mdp_hist_comp;
+#endif
+
+static int mdp_do_histogram(struct fb_info *info, struct mdp_histogram *hist)
+{
+ int ret = 0;
+
+ if (!hist->frame_cnt || (hist->bin_cnt == 0) ||
+ (hist->bin_cnt > MDP_HIST_MAX_BIN))
+ return -EINVAL;
+
+ INIT_COMPLETION(mdp_hist_comp);
+
+ mdp_hist.bin_cnt = hist->bin_cnt;
+ mdp_hist.r = (hist->r) ? mdp_hist_r : 0;
+ mdp_hist.g = (hist->g) ? mdp_hist_g : 0;
+ mdp_hist.b = (hist->b) ? mdp_hist_b : 0;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ MDP_OUTP(MDP_BASE + 0x95004, hist->frame_cnt);
+ MDP_OUTP(MDP_BASE + 0x95000, 1);
+#else
+ MDP_OUTP(MDP_BASE + 0x94004, hist->frame_cnt);
+ MDP_OUTP(MDP_BASE + 0x94000, 1);
+#endif
+ wait_for_completion_killable(&mdp_hist_comp);
+
+ if (hist->r) {
+ ret = copy_to_user(hist->r, mdp_hist.r, hist->bin_cnt*4);
+ if (ret)
+ goto hist_err;
+ }
+ if (hist->g) {
+ ret = copy_to_user(hist->g, mdp_hist.g, hist->bin_cnt*4);
+ if (ret)
+ goto hist_err;
+ }
+ if (hist->b) {
+ ret = copy_to_user(hist->b, mdp_hist.b, hist->bin_cnt*4);
+ if (ret)
+ goto hist_err;
+ }
+ return 0;
+
+hist_err:
+ printk(KERN_ERR "%s: invalid hist buffer\n", __func__);
+ return ret;
+}
+#endif
+
+/* Returns < 0 on error, 0 on timeout, or > 0 on successful wait */
+
+int mdp_ppp_pipe_wait(void)
+{
+ int ret = 1;
+
+ /* wait 5 seconds for the operation to complete before declaring
+ the MDP hung */
+
+ if (mdp_ppp_waiting == TRUE) {
+ ret = wait_for_completion_interruptible_timeout(&mdp_ppp_comp,
+ 5 * HZ);
+
+ if (!ret)
+ printk(KERN_ERR "%s: Timed out waiting for the MDP.\n",
+ __func__);
+ }
+
+ return ret;
+}
+
+static DEFINE_SPINLOCK(mdp_lock);
+static int mdp_irq_mask;
+static int mdp_irq_enabled;
+
+void mdp_enable_irq(uint32 term)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (mdp_irq_mask & term) {
+ printk(KERN_ERR "MDP IRQ term-0x%x is already set\n", term);
+ } else {
+ mdp_irq_mask |= term;
+ if (mdp_irq_mask && !mdp_irq_enabled) {
+ mdp_irq_enabled = 1;
+ enable_irq(INT_MDP);
+ }
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdp_disable_irq(uint32 term)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&mdp_lock, irq_flags);
+ if (!(mdp_irq_mask & term)) {
+ printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term);
+ } else {
+ mdp_irq_mask &= ~term;
+ if (!mdp_irq_mask && mdp_irq_enabled) {
+ mdp_irq_enabled = 0;
+ disable_irq(INT_MDP);
+ }
+ }
+ spin_unlock_irqrestore(&mdp_lock, irq_flags);
+}
+
+void mdp_disable_irq_nolock(uint32 term)
+{
+
+ if (!(mdp_irq_mask & term)) {
+ printk(KERN_ERR "MDP IRQ term-0x%x is not set\n", term);
+ } else {
+ mdp_irq_mask &= ~term;
+ if (!mdp_irq_mask && mdp_irq_enabled) {
+ mdp_irq_enabled = 0;
+ disable_irq(INT_MDP);
+ }
+ }
+}
+
+void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd)
+{
+
+ dmb(); /* memory barrier */
+
+ /* kick off PPP engine */
+ if (term == MDP_PPP_TERM) {
+ if (mdp_debug[MDP_PPP_BLOCK])
+ jiffies_to_timeval(jiffies, &mdp_ppp_timeval);
+
+ /* let's turn on PPP block */
+ mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ mdp_enable_irq(term);
+ INIT_COMPLETION(mdp_ppp_comp);
+ mdp_ppp_waiting = TRUE;
+ outpdw(MDP_BASE + 0x30, 0x1000);
+ wait_for_completion_killable(&mdp_ppp_comp);
+ mdp_disable_irq(term);
+
+ if (mdp_debug[MDP_PPP_BLOCK]) {
+ struct timeval now;
+
+ jiffies_to_timeval(jiffies, &now);
+ mdp_ppp_timeval.tv_usec =
+ now.tv_usec - mdp_ppp_timeval.tv_usec;
+ MSM_FB_INFO("MDP-PPP: %d\n",
+ (int)mdp_ppp_timeval.tv_usec);
+ }
+ } else if (term == MDP_DMA2_TERM) {
+ if (mdp_debug[MDP_DMA2_BLOCK]) {
+ MSM_FB_INFO("MDP-DMA2: %d\n",
+ (int)mdp_dma2_timeval.tv_usec);
+ jiffies_to_timeval(jiffies, &mdp_dma2_timeval);
+ }
+ /* DMA update timestamp */
+ mdp_dma2_last_update_time = ktime_get_real();
+ /* let's turn on DMA2 block */
+#if 0
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+#endif
+#ifdef CONFIG_FB_MSM_MDP22
+ outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x0044, 0x0);/* start DMA */
+#else
+ if (mdp_lut_push) {
+ mutex_lock(&mdp_lut_push_sem);
+ mdp_lut_push = 0;
+ MDP_OUTP(MDP_BASE + 0x90070,
+ (mdp_lut_push_i << 10) | 0x17);
+ mutex_unlock(&mdp_lut_push_sem);
+ }
+#ifdef CONFIG_FB_MSM_MDP40
+ outpdw(MDP_BASE + 0x000c, 0x0); /* start DMA */
+#else
+ outpdw(MDP_BASE + 0x0044, 0x0); /* start DMA */
+#endif
+#endif
+#ifdef CONFIG_FB_MSM_MDP40
+ } else if (term == MDP_DMA_S_TERM) {
+ mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ outpdw(MDP_BASE + 0x0010, 0x0); /* start DMA */
+ } else if (term == MDP_DMA_E_TERM) {
+ mdp_pipe_ctrl(MDP_DMA_E_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ outpdw(MDP_BASE + 0x0014, 0x0); /* start DMA */
+ } else if (term == MDP_OVERLAY0_TERM) {
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ outpdw(MDP_BASE + 0x0004, 0);
+ } else if (term == MDP_OVERLAY1_TERM) {
+ mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ outpdw(MDP_BASE + 0x0008, 0);
+ }
+#else
+ } else if (term == MDP_DMA_S_TERM) {
+ mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ outpdw(MDP_BASE + 0x0048, 0x0); /* start DMA */
+ }
+#endif
+}
+
+static void mdp_pipe_ctrl_workqueue_handler(struct work_struct *work)
+{
+ mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
+ boolean isr)
+{
+ boolean mdp_all_blocks_off = TRUE;
+ int i;
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (MDP_BLOCK_POWER_ON == state) {
+ mdp_block_power_cnt[block]++;
+
+ if (MDP_DMA2_BLOCK == block)
+ mdp_in_processing = TRUE;
+ } else {
+ mdp_block_power_cnt[block]--;
+
+ if (mdp_block_power_cnt[block] < 0) {
+ /*
+ * Master has to serve a request to power off MDP always
+ * It also has a timer to power off. So, in case of
+ * timer expires first and DMA2 finishes later,
+ * master has to power off two times
+ * There shouldn't be multiple power-off request for
+ * other blocks
+ */
+ if (block != MDP_MASTER_BLOCK) {
+ MSM_FB_INFO("mdp_block_power_cnt[block=%d] \
+ multiple power-off request\n", block);
+ }
+ mdp_block_power_cnt[block] = 0;
+ }
+
+ if (MDP_DMA2_BLOCK == block)
+ mdp_in_processing = FALSE;
+ }
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ /*
+ * If it's in isr, we send our request to workqueue.
+ * Otherwise, processing happens in the current context
+ */
+ if (isr) {
+ /* checking all blocks power state */
+ for (i = 0; i < MDP_MAX_BLOCK; i++) {
+ if (mdp_block_power_cnt[i] > 0)
+ mdp_all_blocks_off = FALSE;
+ }
+
+ if ((mdp_all_blocks_off) && (mdp_current_clk_on)) {
+ /* send workqueue to turn off mdp power */
+ queue_delayed_work(mdp_pipe_ctrl_wq,
+ &mdp_pipe_ctrl_worker,
+ mdp_timer_duration);
+ }
+ } else {
+ down(&mdp_pipe_ctrl_mutex);
+ /* checking all blocks power state */
+ for (i = 0; i < MDP_MAX_BLOCK; i++) {
+ if (mdp_block_power_cnt[i] > 0)
+ mdp_all_blocks_off = FALSE;
+ }
+
+ /*
+ * find out whether a delayable work item is currently
+ * pending
+ */
+
+ if (delayed_work_pending(&mdp_pipe_ctrl_worker)) {
+ /*
+ * try to cancel the current work if it fails to
+ * stop (which means del_timer can't delete it
+ * from the list, it's about to expire and run),
+ * we have to let it run. queue_delayed_work won't
+ * accept the next job which is same as
+ * queue_delayed_work(mdp_timer_duration = 0)
+ */
+ cancel_delayed_work(&mdp_pipe_ctrl_worker);
+ }
+
+ if ((mdp_all_blocks_off) && (mdp_current_clk_on)) {
+ if (block == MDP_MASTER_BLOCK) {
+ mdp_current_clk_on = FALSE;
+ /* turn off MDP clks */
+ if (mdp_clk != NULL) {
+ clk_disable(mdp_clk);
+ MSM_FB_DEBUG("MDP CLK OFF\n");
+ }
+ if (mdp_pclk != NULL) {
+ clk_disable(mdp_pclk);
+ MSM_FB_DEBUG("MDP PCLK OFF\n");
+ }
+ } else {
+ /* send workqueue to turn off mdp power */
+ queue_delayed_work(mdp_pipe_ctrl_wq,
+ &mdp_pipe_ctrl_worker,
+ mdp_timer_duration);
+ }
+ } else if ((!mdp_all_blocks_off) && (!mdp_current_clk_on)) {
+ mdp_current_clk_on = TRUE;
+ /* turn on MDP clks */
+ if (mdp_clk != NULL) {
+ clk_enable(mdp_clk);
+ MSM_FB_DEBUG("MDP CLK ON\n");
+ }
+ if (mdp_pclk != NULL) {
+ clk_enable(mdp_pclk);
+ MSM_FB_DEBUG("MDP PCLK ON\n");
+ }
+ }
+ up(&mdp_pipe_ctrl_mutex);
+ }
+}
+
+#ifndef CONFIG_FB_MSM_MDP40
+irqreturn_t mdp_isr(int irq, void *ptr)
+{
+ uint32 mdp_interrupt = 0;
+ struct mdp_dma_data *dma;
+
+ mdp_is_in_isr = TRUE;
+ do {
+ mdp_interrupt = inp32(MDP_INTR_STATUS);
+ outp32(MDP_INTR_CLEAR, mdp_interrupt);
+
+ mdp_interrupt &= mdp_intr_mask;
+
+ if (mdp_interrupt & TV_ENC_UNDERRUN) {
+ mdp_interrupt &= ~(TV_ENC_UNDERRUN);
+ mdp_tv_underflow_cnt++;
+ }
+
+ if (!mdp_interrupt)
+ break;
+
+ /* DMA3 TV-Out Start */
+ if (mdp_interrupt & TV_OUT_DMA3_START) {
+ /* let's disable TV out interrupt */
+ mdp_intr_mask &= ~TV_OUT_DMA3_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+
+ dma = &dma3_data;
+ if (dma->waiting) {
+ dma->waiting = FALSE;
+ complete(&dma->comp);
+ }
+ }
+#ifndef CONFIG_FB_MSM_MDP22
+ if (mdp_interrupt & MDP_HIST_DONE) {
+ outp32(MDP_BASE + 0x94018, 0x3);
+ outp32(MDP_INTR_CLEAR, MDP_HIST_DONE);
+ if (mdp_hist.r)
+ memcpy(mdp_hist.r, MDP_BASE + 0x94100,
+ mdp_hist.bin_cnt*4);
+ if (mdp_hist.g)
+ memcpy(mdp_hist.g, MDP_BASE + 0x94200,
+ mdp_hist.bin_cnt*4);
+ if (mdp_hist.b)
+ memcpy(mdp_hist.b, MDP_BASE + 0x94300,
+ mdp_hist.bin_cnt*4);
+ complete(&mdp_hist_comp);
+ }
+
+ /* LCDC UnderFlow */
+ if (mdp_interrupt & LCDC_UNDERFLOW) {
+ mdp_lcdc_underflow_cnt++;
+ }
+ /* LCDC Frame Start */
+ if (mdp_interrupt & LCDC_FRAME_START) {
+ /* let's disable LCDC interrupt */
+ mdp_intr_mask &= ~LCDC_FRAME_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+
+ dma = &dma2_data;
+ if (dma->waiting) {
+ dma->waiting = FALSE;
+ complete(&dma->comp);
+ }
+ }
+
+ /* DMA2 LCD-Out Complete */
+ if (mdp_interrupt & MDP_DMA_S_DONE) {
+ dma = &dma_s_data;
+ dma->busy = FALSE;
+ mdp_pipe_ctrl(MDP_DMA_S_BLOCK, MDP_BLOCK_POWER_OFF,
+ TRUE);
+ complete(&dma->comp);
+ }
+#endif
+
+ /* DMA2 LCD-Out Complete */
+ if (mdp_interrupt & MDP_DMA_P_DONE) {
+ struct timeval now;
+ ktime_t now_k;
+
+ now_k = ktime_get_real();
+ mdp_dma2_last_update_time.tv.sec =
+ now_k.tv.sec - mdp_dma2_last_update_time.tv.sec;
+ mdp_dma2_last_update_time.tv.nsec =
+ now_k.tv.nsec - mdp_dma2_last_update_time.tv.nsec;
+
+ if (mdp_debug[MDP_DMA2_BLOCK]) {
+ jiffies_to_timeval(jiffies, &now);
+ mdp_dma2_timeval.tv_usec =
+ now.tv_usec - mdp_dma2_timeval.tv_usec;
+ }
+
+ dma = &dma2_data;
+ dma->busy = FALSE;
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF,
+ TRUE);
+ complete(&dma->comp);
+ }
+ /* PPP Complete */
+ if (mdp_interrupt & MDP_PPP_DONE) {
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+ mdp_ppp_djob_done();
+#else
+ mdp_pipe_ctrl(MDP_PPP_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ if (mdp_ppp_waiting) {
+ mdp_ppp_waiting = FALSE;
+ complete(&mdp_ppp_comp);
+ }
+#endif
+ }
+ } while (1);
+
+ mdp_is_in_isr = FALSE;
+
+ return IRQ_HANDLED;
+}
+#endif
+
+static void mdp_drv_init(void)
+{
+ int i;
+
+ for (i = 0; i < MDP_MAX_BLOCK; i++) {
+ mdp_debug[i] = 0;
+ }
+
+ /* initialize spin lock and workqueue */
+ spin_lock_init(&mdp_spin_lock);
+ mdp_dma_wq = create_singlethread_workqueue("mdp_dma_wq");
+ mdp_vsync_wq = create_singlethread_workqueue("mdp_vsync_wq");
+ mdp_pipe_ctrl_wq = create_singlethread_workqueue("mdp_pipe_ctrl_wq");
+ INIT_DELAYED_WORK(&mdp_pipe_ctrl_worker,
+ mdp_pipe_ctrl_workqueue_handler);
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+ mdp_ppp_dq_init();
+#endif
+
+ /* initialize semaphore */
+ init_completion(&mdp_ppp_comp);
+ init_MUTEX(&mdp_ppp_mutex);
+ init_MUTEX(&mdp_pipe_ctrl_mutex);
+
+ dma2_data.busy = FALSE;
+ dma2_data.waiting = FALSE;
+ init_completion(&dma2_data.comp);
+ init_MUTEX(&dma2_data.mutex);
+ mutex_init(&dma2_data.ov_mutex);
+
+ dma3_data.busy = FALSE;
+ dma3_data.waiting = FALSE;
+ init_completion(&dma3_data.comp);
+ init_MUTEX(&dma3_data.mutex);
+
+ dma_s_data.busy = FALSE;
+ dma_s_data.waiting = FALSE;
+ init_completion(&dma_s_data.comp);
+ init_MUTEX(&dma_s_data.mutex);
+
+ dma_e_data.busy = FALSE;
+ dma_e_data.waiting = FALSE;
+ init_completion(&dma_e_data.comp);
+
+#ifndef CONFIG_FB_MSM_MDP22
+ init_completion(&mdp_hist_comp);
+#endif
+
+ /* initializing mdp power block counter to 0 */
+ for (i = 0; i < MDP_MAX_BLOCK; i++) {
+ mdp_block_power_cnt[i] = 0;
+ }
+
+#ifdef MSM_FB_ENABLE_DBGFS
+ {
+ struct dentry *root;
+ char sub_name[] = "mdp";
+
+ root = msm_fb_get_debugfs_root();
+ if (root != NULL) {
+ mdp_dir = debugfs_create_dir(sub_name, root);
+
+ if (mdp_dir) {
+ msm_fb_debugfs_file_create(mdp_dir,
+ "dma2_update_time_in_usec",
+ (u32 *) &mdp_dma2_update_time_in_usec);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "vs_rdcnt_slow",
+ (u32 *) &mdp_lcd_rd_cnt_offset_slow);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "vs_rdcnt_fast",
+ (u32 *) &mdp_lcd_rd_cnt_offset_fast);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "mdp_usec_diff_threshold",
+ (u32 *) &mdp_usec_diff_threshold);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "mdp_current_clk_on",
+ (u32 *) &mdp_current_clk_on);
+#ifdef CONFIG_FB_MSM_LCDC
+ msm_fb_debugfs_file_create(mdp_dir,
+ "lcdc_start_x",
+ (u32 *) &first_pixel_start_x);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "lcdc_start_y",
+ (u32 *) &first_pixel_start_y);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "mdp_lcdc_pclk_clk_rate",
+ (u32 *) &mdp_lcdc_pclk_clk_rate);
+ msm_fb_debugfs_file_create(mdp_dir,
+ "mdp_lcdc_pad_pclk_clk_rate",
+ (u32 *) &mdp_lcdc_pad_pclk_clk_rate);
+#endif
+ }
+ }
+ }
+#endif
+}
+
+static int mdp_probe(struct platform_device *pdev);
+static int mdp_remove(struct platform_device *pdev);
+
+static struct platform_driver mdp_driver = {
+ .probe = mdp_probe,
+ .remove = mdp_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = mdp_suspend,
+ .resume = NULL,
+#endif
+ .shutdown = NULL,
+ .driver = {
+ /*
+ * Driver name must match the device name added in
+ * platform.c.
+ */
+ .name = "mdp",
+ },
+};
+
+static int mdp_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+#ifdef MDP_HW_VSYNC
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+#endif
+
+ ret = panel_next_off(pdev);
+
+#ifdef MDP_HW_VSYNC
+ mdp_hw_vsync_clk_disable(mfd);
+#endif
+
+ return ret;
+}
+
+static int mdp_on(struct platform_device *pdev)
+{
+#ifdef MDP_HW_VSYNC
+ struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+#endif
+
+ int ret = 0;
+
+#ifdef MDP_HW_VSYNC
+ mdp_hw_vsync_clk_enable(mfd);
+#endif
+
+ ret = panel_next_on(pdev);
+
+ return ret;
+}
+
+static int mdp_irq_clk_setup(void)
+{
+ int ret;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ ret = request_irq(INT_MDP, mdp4_isr, IRQF_DISABLED, "MDP", 0);
+#else
+ ret = request_irq(INT_MDP, mdp_isr, IRQF_DISABLED, "MDP", 0);
+#endif
+ if (ret) {
+ printk(KERN_ERR "mdp request_irq() failed!\n");
+ return ret;
+ }
+ disable_irq(INT_MDP);
+
+ mdp_clk = clk_get(NULL, "mdp_clk");
+
+ if (IS_ERR(mdp_clk)) {
+ ret = PTR_ERR(mdp_clk);
+ printk(KERN_ERR "can't get mdp_clk error:%d!\n", ret);
+ free_irq(INT_MDP, 0);
+ return ret;
+ }
+
+ mdp_pclk = clk_get(NULL, "mdp_pclk");
+ if (IS_ERR(mdp_pclk))
+ mdp_pclk = NULL;
+
+
+#ifdef CONFIG_FB_MSM_MDP40
+ /*
+ * mdp_clk should greater than mdp_pclk always
+ */
+ clk_set_rate(mdp_clk, 122880000); /* 122.88 Mhz */
+ printk(KERN_INFO "mdp_clk: mdp_clk=%d mdp_pclk=%d\n",
+ (int)clk_get_rate(mdp_clk), (int)clk_get_rate(mdp_pclk));
+#endif
+
+ return 0;
+}
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+static int mdp_resource_initialized;
+static struct msm_panel_common_pdata *mdp_pdata;
+
+static int mdp_probe(struct platform_device *pdev)
+{
+ struct platform_device *msm_fb_dev = NULL;
+ struct msm_fb_data_type *mfd;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+ resource_size_t size ;
+#ifdef CONFIG_FB_MSM_MDP40
+ int intf, if_no;
+#else
+ unsigned long flag;
+#endif
+
+ if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+ mdp_pdata = pdev->dev.platform_data;
+
+ size = resource_size(&pdev->resource[0]);
+ msm_mdp_base = ioremap(pdev->resource[0].start, size);
+
+ MSM_FB_INFO("MDP HW Base phy_Address = 0x%x virt = 0x%x\n",
+ (int)pdev->resource[0].start, (int)msm_mdp_base);
+
+ if (unlikely(!msm_mdp_base))
+ return -ENOMEM;
+
+ printk("irq clk setup\n");
+ rc = mdp_irq_clk_setup();
+ printk("irq clk setup done\n");
+ if (rc)
+ return rc;
+
+ /* initializing mdp hw */
+#ifdef CONFIG_FB_MSM_MDP40
+ mdp4_hw_init();
+#else
+ mdp_hw_init();
+#endif
+
+ mdp_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!mdp_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ msm_fb_dev = platform_device_alloc("msm_fb", pdev->id);
+ if (!msm_fb_dev)
+ return -ENOMEM;
+
+ /* link to the latest pdev */
+ mfd->pdev = msm_fb_dev;
+
+ /* add panel data */
+ if (platform_device_add_data
+ (msm_fb_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "mdp_probe: platform_device_add_data failed!\n");
+ rc = -ENOMEM;
+ goto mdp_probe_err;
+ }
+ /* data chain */
+ pdata = msm_fb_dev->dev.platform_data;
+ pdata->on = mdp_on;
+ pdata->off = mdp_off;
+ pdata->next = pdev;
+
+ switch (mfd->panel.type) {
+ case EXT_MDDI_PANEL:
+ case MDDI_PANEL:
+ case EBI2_PANEL:
+ INIT_WORK(&mfd->dma_update_worker,
+ mdp_lcd_update_workqueue_handler);
+ INIT_WORK(&mfd->vsync_resync_worker,
+ mdp_vsync_resync_workqueue_handler);
+ mfd->hw_refresh = FALSE;
+
+ if (mfd->panel.type == EXT_MDDI_PANEL) {
+ /* 15 fps -> 66 msec */
+ mfd->refresh_timer_duration = (66 * HZ / 1000);
+ } else {
+ /* 24 fps -> 42 msec */
+ mfd->refresh_timer_duration = (42 * HZ / 1000);
+ }
+
+#ifdef CONFIG_FB_MSM_MDP22
+ mfd->dma_fnc = mdp_dma2_update;
+ mfd->dma = &dma2_data;
+#else
+ if (mfd->panel_info.pdest == DISPLAY_1) {
+#ifdef CONFIG_FB_MSM_OVERLAY
+ mfd->dma_fnc = mdp4_mddi_overlay;
+#else
+ mfd->dma_fnc = mdp_dma2_update;
+#endif
+ mfd->dma = &dma2_data;
+ mfd->lut_update = mdp_lut_update_nonlcdc;
+ mfd->do_histogram = mdp_do_histogram;
+ } else {
+ mfd->dma_fnc = mdp_dma_s_update;
+ mfd->dma = &dma_s_data;
+ }
+#endif
+ if (mdp_pdata)
+ mfd->vsync_gpio = mdp_pdata->gpio;
+ else
+ mfd->vsync_gpio = -1;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == EBI2_PANEL)
+ intf = EBI2_INTF;
+ else
+ intf = MDDI_INTF;
+
+ if (mfd->panel_info.pdest == DISPLAY_1)
+ if_no = PRIMARY_INTF_SEL;
+ else
+ if_no = SECONDARY_INTF_SEL;
+
+ mdp4_display_intf_sel(if_no, intf);
+#endif
+ mdp_config_vsync(mfd);
+ break;
+
+ case HDMI_PANEL:
+ case LCDC_PANEL:
+ pdata->on = mdp_lcdc_on;
+ pdata->off = mdp_lcdc_off;
+ mfd->hw_refresh = TRUE;
+ mfd->cursor_update = mdp_hw_cursor_update;
+#ifndef CONFIG_FB_MSM_MDP22
+ mfd->lut_update = mdp_lut_update_lcdc;
+ mfd->do_histogram = mdp_do_histogram;
+#endif
+#ifdef CONFIG_FB_MSM_OVERLAY
+ mfd->dma_fnc = mdp4_lcdc_overlay;
+#else
+ mfd->dma_fnc = mdp_lcdc_update;
+#endif
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == HDMI_PANEL) {
+ mfd->dma = &dma_e_data;
+ mdp4_display_intf_sel(EXTERNAL_INTF_SEL, LCDC_RGB_INTF);
+ } else {
+ mfd->dma = &dma2_data;
+ mdp4_display_intf_sel(PRIMARY_INTF_SEL, LCDC_RGB_INTF);
+ }
+#else
+ mfd->dma = &dma2_data;
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_intr_mask &= ~MDP_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+#endif
+ break;
+
+ case TV_PANEL:
+ pdata->on = mdp_dma3_on;
+ pdata->off = mdp_dma3_off;
+ mfd->hw_refresh = TRUE;
+ mfd->dma_fnc = mdp_dma3_update;
+ mfd->dma = &dma3_data;
+ break;
+
+ default:
+ printk(KERN_ERR "mdp_probe: unknown device type!\n");
+ rc = -ENODEV;
+ goto mdp_probe_err;
+ }
+
+ /* set driver data */
+ platform_set_drvdata(msm_fb_dev, mfd);
+
+ rc = platform_device_add(msm_fb_dev);
+ if (rc) {
+ goto mdp_probe_err;
+ }
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+
+ mdp_probe_err:
+ platform_device_put(msm_fb_dev);
+ return rc;
+}
+
+static void mdp_suspend_sub(void)
+{
+ /* cancel pipe ctrl worker */
+ cancel_delayed_work(&mdp_pipe_ctrl_worker);
+
+ /* for workder can't be cancelled... */
+ flush_workqueue(mdp_pipe_ctrl_wq);
+
+ /* let's wait for PPP completion */
+ while (mdp_block_power_cnt[MDP_PPP_BLOCK] > 0) ;
+
+ /* try to power down */
+ mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int mdp_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ mdp_suspend_sub();
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void mdp_early_suspend(struct early_suspend *h)
+{
+ mdp_suspend_sub();
+}
+#endif
+
+static int mdp_remove(struct platform_device *pdev)
+{
+ iounmap(msm_mdp_base);
+ return 0;
+}
+
+static int mdp_register_driver(void)
+{
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 1;
+ early_suspend.suspend = mdp_early_suspend;
+ register_early_suspend(&early_suspend);
+#endif
+
+ return platform_driver_register(&mdp_driver);
+}
+
+static int __init mdp_driver_init(void)
+{
+ int ret;
+
+ mdp_drv_init();
+
+ ret = mdp_register_driver();
+ if (ret) {
+ printk(KERN_ERR "mdp_register_driver() failed!\n");
+ return ret;
+ }
+
+#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_FB_MSM_MDP40)
+ mdp4_debugfs_init();
+#endif
+
+ return 0;
+
+}
+
+module_init(mdp_driver_init);
diff --git a/drivers/staging/msm/mdp.h b/drivers/staging/msm/mdp.h
new file mode 100644
index 000000000000..0a5d6ac386ac
--- /dev/null
+++ b/drivers/staging/msm/mdp.h
@@ -0,0 +1,695 @@
+/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDP_H
+#define MDP_H
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/hrtimer.h>
+#include "msm_mdp.h"
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include "msm_fb_panel.h"
+
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+#include "mdp_ppp_dq.h"
+#endif
+
+#ifdef BIT
+#undef BIT
+#endif
+
+#define BIT(x) (1<<(x))
+
+#define MDPOP_NOP 0
+#define MDPOP_LR BIT(0) /* left to right flip */
+#define MDPOP_UD BIT(1) /* up and down flip */
+#define MDPOP_ROT90 BIT(2) /* rotate image to 90 degree */
+#define MDPOP_ROT180 (MDPOP_UD|MDPOP_LR)
+#define MDPOP_ROT270 (MDPOP_ROT90|MDPOP_UD|MDPOP_LR)
+#define MDPOP_ASCALE BIT(7)
+#define MDPOP_ALPHAB BIT(8) /* enable alpha blending */
+#define MDPOP_TRANSP BIT(9) /* enable transparency */
+#define MDPOP_DITHER BIT(10) /* enable dither */
+#define MDPOP_SHARPENING BIT(11) /* enable sharpening */
+#define MDPOP_BLUR BIT(12) /* enable blur */
+#define MDPOP_FG_PM_ALPHA BIT(13)
+
+struct mdp_table_entry {
+ uint32_t reg;
+ uint32_t val;
+};
+
+extern struct mdp_ccs mdp_ccs_yuv2rgb ;
+extern struct mdp_ccs mdp_ccs_rgb2yuv ;
+
+/*
+ * MDP Image Structure
+ */
+typedef struct mdpImg_ {
+ uint32 imgType; /* Image type */
+ uint32 *bmy_addr; /* bitmap or y addr */
+ uint32 *cbcr_addr; /* cbcr addr */
+ uint32 width; /* image width */
+ uint32 mdpOp; /* image opertion (rotation,flip up/down, alpha/tp) */
+ uint32 tpVal; /* transparency color */
+ uint32 alpha; /* alpha percentage 0%(0x0) ~ 100%(0x100) */
+ int sp_value; /* sharpening strength */
+} MDPIMG;
+
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+#define MDP_OUTP(addr, data) mdp_ppp_outdw((uint32_t)(addr), \
+ (uint32_t)(data))
+#else
+#define MDP_OUTP(addr, data) outpdw((addr), (data))
+#endif
+
+#define MDP_KTIME2USEC(kt) (kt.tv.sec*1000000 + kt.tv.nsec/1000)
+
+#define MDP_BASE msm_mdp_base
+
+typedef enum {
+ MDP_BC_SCALE_POINT2_POINT4,
+ MDP_BC_SCALE_POINT4_POINT6,
+ MDP_BC_SCALE_POINT6_POINT8,
+ MDP_BC_SCALE_POINT8_1,
+ MDP_BC_SCALE_UP,
+ MDP_PR_SCALE_POINT2_POINT4,
+ MDP_PR_SCALE_POINT4_POINT6,
+ MDP_PR_SCALE_POINT6_POINT8,
+ MDP_PR_SCALE_POINT8_1,
+ MDP_PR_SCALE_UP,
+ MDP_SCALE_BLUR,
+ MDP_INIT_SCALE
+} MDP_SCALE_MODE;
+
+typedef enum {
+ MDP_BLOCK_POWER_OFF,
+ MDP_BLOCK_POWER_ON
+} MDP_BLOCK_POWER_STATE;
+
+typedef enum {
+ MDP_MASTER_BLOCK,
+ MDP_CMD_BLOCK,
+ MDP_PPP_BLOCK,
+ MDP_DMA2_BLOCK,
+ MDP_DMA3_BLOCK,
+ MDP_DMA_S_BLOCK,
+ MDP_DMA_E_BLOCK,
+ MDP_OVERLAY0_BLOCK,
+ MDP_OVERLAY1_BLOCK,
+ MDP_MAX_BLOCK
+} MDP_BLOCK_TYPE;
+
+/* Let's keep Q Factor power of 2 for optimization */
+#define MDP_SCALE_Q_FACTOR 512
+
+#ifdef CONFIG_FB_MSM_MDP31
+#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
+#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
+#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*8)
+#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/8)
+#else
+#define MDP_MAX_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_X_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+#define MDP_MAX_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR*4)
+#define MDP_MIN_Y_SCALE_FACTOR (MDP_SCALE_Q_FACTOR/4)
+#endif
+
+/* SHIM Q Factor */
+#define PHI_Q_FACTOR 29
+#define PQF_PLUS_5 (PHI_Q_FACTOR + 5) /* due to 32 phases */
+#define PQF_PLUS_4 (PHI_Q_FACTOR + 4)
+#define PQF_PLUS_2 (PHI_Q_FACTOR + 2) /* to get 4.0 */
+#define PQF_MINUS_2 (PHI_Q_FACTOR - 2) /* to get 0.25 */
+#define PQF_PLUS_5_PLUS_2 (PQF_PLUS_5 + 2)
+#define PQF_PLUS_5_MINUS_2 (PQF_PLUS_5 - 2)
+
+#define MDP_CONVTP(tpVal) (((tpVal&0xF800)<<8)|((tpVal&0x7E0)<<5)|((tpVal&0x1F)<<3))
+
+#define MDPOP_ROTATION (MDPOP_ROT90|MDPOP_LR|MDPOP_UD)
+#define MDP_CHKBIT(val, bit) ((bit) == ((val) & (bit)))
+
+/* overlay interface API defines */
+typedef enum {
+ MORE_IBUF,
+ FINAL_IBUF,
+ COMPLETE_IBUF
+} MDP_IBUF_STATE;
+
+struct mdp_dirty_region {
+ __u32 xoffset; /* source origin in the x-axis */
+ __u32 yoffset; /* source origin in the y-axis */
+ __u32 width; /* number of pixels in the x-axis */
+ __u32 height; /* number of pixels in the y-axis */
+};
+
+/*
+ * MDP extended data types
+ */
+typedef struct mdp_roi_s {
+ uint32 x;
+ uint32 y;
+ uint32 width;
+ uint32 height;
+ int32 lcd_x;
+ int32 lcd_y;
+ uint32 dst_width;
+ uint32 dst_height;
+} MDP_ROI;
+
+typedef struct mdp_ibuf_s {
+ uint8 *buf;
+ uint32 bpp;
+ uint32 ibuf_type;
+ uint32 ibuf_width;
+ uint32 ibuf_height;
+
+ MDP_ROI roi;
+ MDPIMG mdpImg;
+
+ int32 dma_x;
+ int32 dma_y;
+ uint32 dma_w;
+ uint32 dma_h;
+
+ uint32 vsync_enable;
+ uint32 visible_swapped;
+} MDPIBUF;
+
+struct mdp_dma_data {
+ boolean busy;
+ boolean waiting;
+ struct mutex ov_mutex;
+ struct semaphore mutex;
+ struct completion comp;
+};
+
+#define MDP_CMD_DEBUG_ACCESS_BASE (MDP_BASE+0x10000)
+
+#define MDP_DMA2_TERM 0x1
+#define MDP_DMA3_TERM 0x2
+#define MDP_PPP_TERM 0x4
+#define MDP_DMA_S_TERM 0x8
+#ifdef CONFIG_FB_MSM_MDP40
+#define MDP_DMA_E_TERM 0x10
+#define MDP_OVERLAY0_TERM 0x20
+#define MDP_OVERLAY1_TERM 0x40
+#endif
+
+#define ACTIVE_START_X_EN BIT(31)
+#define ACTIVE_START_Y_EN BIT(31)
+#define ACTIVE_HIGH 0
+#define ACTIVE_LOW 1
+#define MDP_DMA_S_DONE BIT(2)
+#define LCDC_FRAME_START BIT(15)
+#define LCDC_UNDERFLOW BIT(16)
+
+#ifdef CONFIG_FB_MSM_MDP22
+#define MDP_DMA_P_DONE BIT(2)
+#else
+#define MDP_DMA_P_DONE BIT(14)
+#endif
+
+#define MDP_PPP_DONE BIT(0)
+#define TV_OUT_DMA3_DONE BIT(6)
+#define TV_ENC_UNDERRUN BIT(7)
+#define TV_OUT_DMA3_START BIT(13)
+#define MDP_HIST_DONE BIT(20)
+
+#ifdef CONFIG_FB_MSM_MDP22
+#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
+ MDP_DMA_P_DONE| \
+ TV_ENC_UNDERRUN)
+#else
+#define MDP_ANY_INTR_MASK (MDP_PPP_DONE| \
+ MDP_DMA_P_DONE| \
+ MDP_DMA_S_DONE| \
+ LCDC_UNDERFLOW| \
+ MDP_HIST_DONE| \
+ TV_ENC_UNDERRUN)
+#endif
+
+#define MDP_TOP_LUMA 16
+#define MDP_TOP_CHROMA 0
+#define MDP_BOTTOM_LUMA 19
+#define MDP_BOTTOM_CHROMA 3
+#define MDP_LEFT_LUMA 22
+#define MDP_LEFT_CHROMA 6
+#define MDP_RIGHT_LUMA 25
+#define MDP_RIGHT_CHROMA 9
+
+#define CLR_G 0x0
+#define CLR_B 0x1
+#define CLR_R 0x2
+#define CLR_ALPHA 0x3
+
+#define CLR_Y CLR_G
+#define CLR_CB CLR_B
+#define CLR_CR CLR_R
+
+/* from lsb to msb */
+#define MDP_GET_PACK_PATTERN(a,x,y,z,bit) (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
+
+/*
+ * 0x0000 0x0004 0x0008 MDP sync config
+ */
+#ifdef CONFIG_FB_MSM_MDP22
+#define MDP_SYNCFG_HGT_LOC 22
+#define MDP_SYNCFG_VSYNC_EXT_EN BIT(21)
+#define MDP_SYNCFG_VSYNC_INT_EN BIT(20)
+#else
+#define MDP_SYNCFG_HGT_LOC 21
+#define MDP_SYNCFG_VSYNC_EXT_EN BIT(20)
+#define MDP_SYNCFG_VSYNC_INT_EN BIT(19)
+#define MDP_HW_VSYNC
+#endif
+
+/*
+ * 0x0018 MDP VSYNC THREASH
+ */
+#define MDP_PRIM_BELOW_LOC 0
+#define MDP_PRIM_ABOVE_LOC 8
+
+/*
+ * MDP_PRIMARY_VSYNC_OUT_CTRL
+ * 0x0080,84,88 internal vsync pulse config
+ */
+#define VSYNC_PULSE_EN BIT(31)
+#define VSYNC_PULSE_INV BIT(30)
+
+/*
+ * 0x008c MDP VSYNC CONTROL
+ */
+#define DISP0_VSYNC_MAP_VSYNC0 0
+#define DISP0_VSYNC_MAP_VSYNC1 BIT(0)
+#define DISP0_VSYNC_MAP_VSYNC2 BIT(0)|BIT(1)
+
+#define DISP1_VSYNC_MAP_VSYNC0 0
+#define DISP1_VSYNC_MAP_VSYNC1 BIT(2)
+#define DISP1_VSYNC_MAP_VSYNC2 BIT(2)|BIT(3)
+
+#define PRIMARY_LCD_SYNC_EN BIT(4)
+#define PRIMARY_LCD_SYNC_DISABLE 0
+
+#define SECONDARY_LCD_SYNC_EN BIT(5)
+#define SECONDARY_LCD_SYNC_DISABLE 0
+
+#define EXTERNAL_LCD_SYNC_EN BIT(6)
+#define EXTERNAL_LCD_SYNC_DISABLE 0
+
+/*
+ * 0x101f0 MDP VSYNC Threshold
+ */
+#define VSYNC_THRESHOLD_ABOVE_LOC 0
+#define VSYNC_THRESHOLD_BELOW_LOC 16
+#define VSYNC_ANTI_TEAR_EN BIT(31)
+
+/*
+ * 0x10004 command config
+ */
+#define MDP_CMD_DBGBUS_EN BIT(0)
+
+/*
+ * 0x10124 or 0x101d4PPP source config
+ */
+#define PPP_SRC_C0G_8BITS (BIT(1)|BIT(0))
+#define PPP_SRC_C1B_8BITS (BIT(3)|BIT(2))
+#define PPP_SRC_C2R_8BITS (BIT(5)|BIT(4))
+#define PPP_SRC_C3A_8BITS (BIT(7)|BIT(6))
+
+#define PPP_SRC_C0G_6BITS BIT(1)
+#define PPP_SRC_C1B_6BITS BIT(3)
+#define PPP_SRC_C2R_6BITS BIT(5)
+
+#define PPP_SRC_C0G_5BITS BIT(0)
+#define PPP_SRC_C1B_5BITS BIT(2)
+#define PPP_SRC_C2R_5BITS BIT(4)
+
+#define PPP_SRC_C3_ALPHA_EN BIT(8)
+
+#define PPP_SRC_BPP_INTERLVD_1BYTES 0
+#define PPP_SRC_BPP_INTERLVD_2BYTES BIT(9)
+#define PPP_SRC_BPP_INTERLVD_3BYTES BIT(10)
+#define PPP_SRC_BPP_INTERLVD_4BYTES (BIT(10)|BIT(9))
+
+#define PPP_SRC_BPP_ROI_ODD_X BIT(11)
+#define PPP_SRC_BPP_ROI_ODD_Y BIT(12)
+#define PPP_SRC_INTERLVD_2COMPONENTS BIT(13)
+#define PPP_SRC_INTERLVD_3COMPONENTS BIT(14)
+#define PPP_SRC_INTERLVD_4COMPONENTS (BIT(14)|BIT(13))
+
+/*
+ * RGB666 unpack format
+ * TIGHT means R6+G6+B6 together
+ * LOOSE means R6+2 +G6+2+ B6+2 (with MSB)
+ * or 2+R6 +2+G6 +2+B6 (with LSB)
+ */
+#define PPP_SRC_UNPACK_TIGHT BIT(17)
+#define PPP_SRC_UNPACK_LOOSE 0
+#define PPP_SRC_UNPACK_ALIGN_LSB 0
+#define PPP_SRC_UNPACK_ALIGN_MSB BIT(18)
+
+#define PPP_SRC_FETCH_PLANES_INTERLVD 0
+#define PPP_SRC_FETCH_PLANES_PSEUDOPLNR BIT(20)
+
+#define PPP_SRC_WMV9_MODE BIT(21) /* window media version 9 */
+
+/*
+ * 0x10138 PPP operation config
+ */
+#define PPP_OP_SCALE_X_ON BIT(0)
+#define PPP_OP_SCALE_Y_ON BIT(1)
+
+#define PPP_OP_CONVERT_RGB2YCBCR 0
+#define PPP_OP_CONVERT_YCBCR2RGB BIT(2)
+#define PPP_OP_CONVERT_ON BIT(3)
+
+#define PPP_OP_CONVERT_MATRIX_PRIMARY 0
+#define PPP_OP_CONVERT_MATRIX_SECONDARY BIT(4)
+
+#define PPP_OP_LUT_C0_ON BIT(5)
+#define PPP_OP_LUT_C1_ON BIT(6)
+#define PPP_OP_LUT_C2_ON BIT(7)
+
+/* rotate or blend enable */
+#define PPP_OP_ROT_ON BIT(8)
+
+#define PPP_OP_ROT_90 BIT(9)
+#define PPP_OP_FLIP_LR BIT(10)
+#define PPP_OP_FLIP_UD BIT(11)
+
+#define PPP_OP_BLEND_ON BIT(12)
+
+#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
+#define PPP_OP_BLEND_DSTPIXEL_ALPHA BIT(13)
+#define PPP_OP_BLEND_CONSTANT_ALPHA BIT(14)
+#define PPP_OP_BLEND_SRCPIXEL_TRANSP (BIT(13)|BIT(14))
+
+#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
+#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE BIT(15)
+
+#define PPP_OP_DITHER_EN BIT(16)
+
+#define PPP_OP_COLOR_SPACE_RGB 0
+#define PPP_OP_COLOR_SPACE_YCBCR BIT(17)
+
+#define PPP_OP_SRC_CHROMA_RGB 0
+#define PPP_OP_SRC_CHROMA_H2V1 BIT(18)
+#define PPP_OP_SRC_CHROMA_H1V2 BIT(19)
+#define PPP_OP_SRC_CHROMA_420 (BIT(18)|BIT(19))
+#define PPP_OP_SRC_CHROMA_COSITE 0
+#define PPP_OP_SRC_CHROMA_OFFSITE BIT(20)
+
+#define PPP_OP_DST_CHROMA_RGB 0
+#define PPP_OP_DST_CHROMA_H2V1 BIT(21)
+#define PPP_OP_DST_CHROMA_H1V2 BIT(22)
+#define PPP_OP_DST_CHROMA_420 (BIT(21)|BIT(22))
+#define PPP_OP_DST_CHROMA_COSITE 0
+#define PPP_OP_DST_CHROMA_OFFSITE BIT(23)
+
+#define PPP_BLEND_CALPHA_TRNASP BIT(24)
+
+#define PPP_OP_BG_CHROMA_RGB 0
+#define PPP_OP_BG_CHROMA_H2V1 BIT(25)
+#define PPP_OP_BG_CHROMA_H1V2 BIT(26)
+#define PPP_OP_BG_CHROMA_420 BIT(25)|BIT(26)
+#define PPP_OP_BG_CHROMA_SITE_COSITE 0
+#define PPP_OP_BG_CHROMA_SITE_OFFSITE BIT(27)
+#define PPP_OP_DEINT_EN BIT(29)
+
+#define PPP_BLEND_BG_USE_ALPHA_SEL (1 << 0)
+#define PPP_BLEND_BG_ALPHA_REVERSE (1 << 3)
+#define PPP_BLEND_BG_SRCPIXEL_ALPHA (0 << 1)
+#define PPP_BLEND_BG_DSTPIXEL_ALPHA (1 << 1)
+#define PPP_BLEND_BG_CONSTANT_ALPHA (2 << 1)
+#define PPP_BLEND_BG_CONST_ALPHA_VAL(x) ((x) << 24)
+
+#define PPP_OP_DST_RGB 0
+#define PPP_OP_DST_YCBCR BIT(30)
+/*
+ * 0x10150 PPP destination config
+ */
+#define PPP_DST_C0G_8BIT (BIT(0)|BIT(1))
+#define PPP_DST_C1B_8BIT (BIT(3)|BIT(2))
+#define PPP_DST_C2R_8BIT (BIT(5)|BIT(4))
+#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
+
+#define PPP_DST_C0G_6BIT BIT(1)
+#define PPP_DST_C1B_6BIT BIT(3)
+#define PPP_DST_C2R_6BIT BIT(5)
+
+#define PPP_DST_C0G_5BIT BIT(0)
+#define PPP_DST_C1B_5BIT BIT(2)
+#define PPP_DST_C2R_5BIT BIT(4)
+
+#define PPP_DST_C3A_8BIT (BIT(7)|BIT(6))
+#define PPP_DST_C3ALPHA_EN BIT(8)
+
+#define PPP_DST_PACKET_CNT_INTERLVD_2ELEM BIT(9)
+#define PPP_DST_PACKET_CNT_INTERLVD_3ELEM BIT(10)
+#define PPP_DST_PACKET_CNT_INTERLVD_4ELEM (BIT(10)|BIT(9))
+#define PPP_DST_PACKET_CNT_INTERLVD_6ELEM (BIT(11)|BIT(9))
+
+#define PPP_DST_PACK_LOOSE 0
+#define PPP_DST_PACK_TIGHT BIT(13)
+#define PPP_DST_PACK_ALIGN_LSB 0
+#define PPP_DST_PACK_ALIGN_MSB BIT(14)
+
+#define PPP_DST_OUT_SEL_AXI 0
+#define PPP_DST_OUT_SEL_MDDI BIT(15)
+
+#define PPP_DST_BPP_2BYTES BIT(16)
+#define PPP_DST_BPP_3BYTES BIT(17)
+#define PPP_DST_BPP_4BYTES (BIT(17)|BIT(16))
+
+#define PPP_DST_PLANE_INTERLVD 0
+#define PPP_DST_PLANE_PLANAR BIT(18)
+#define PPP_DST_PLANE_PSEUDOPLN BIT(19)
+
+#define PPP_DST_TO_TV BIT(20)
+
+#define PPP_DST_MDDI_PRIMARY 0
+#define PPP_DST_MDDI_SECONDARY BIT(21)
+#define PPP_DST_MDDI_EXTERNAL BIT(22)
+
+/*
+ * 0x10180 DMA config
+ */
+#define DMA_DSTC0G_8BITS (BIT(1)|BIT(0))
+#define DMA_DSTC1B_8BITS (BIT(3)|BIT(2))
+#define DMA_DSTC2R_8BITS (BIT(5)|BIT(4))
+
+#define DMA_DSTC0G_6BITS BIT(1)
+#define DMA_DSTC1B_6BITS BIT(3)
+#define DMA_DSTC2R_6BITS BIT(5)
+
+#define DMA_DSTC0G_5BITS BIT(0)
+#define DMA_DSTC1B_5BITS BIT(2)
+#define DMA_DSTC2R_5BITS BIT(4)
+
+#define DMA_PACK_TIGHT BIT(6)
+#define DMA_PACK_LOOSE 0
+#define DMA_PACK_ALIGN_LSB 0
+/*
+ * use DMA_PACK_ALIGN_MSB if the upper 6 bits from 8 bits output
+ * from LCDC block maps into 6 pins out to the panel
+ */
+#define DMA_PACK_ALIGN_MSB BIT(7)
+#define DMA_PACK_PATTERN_RGB \
+ (MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8)
+#define DMA_PACK_PATTERN_BGR \
+ (MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 2)<<8)
+#define DMA_OUT_SEL_AHB 0
+#define DMA_OUT_SEL_LCDC BIT(20)
+#define DMA_IBUF_FORMAT_RGB888 0
+#define DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888 BIT(26)
+
+#ifdef CONFIG_FB_MSM_MDP22
+#define DMA_OUT_SEL_MDDI BIT(14)
+#define DMA_AHBM_LCD_SEL_PRIMARY 0
+#define DMA_AHBM_LCD_SEL_SECONDARY BIT(15)
+#define DMA_IBUF_C3ALPHA_EN BIT(16)
+#define DMA_DITHER_EN BIT(17)
+#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
+#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY BIT(18)
+#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL BIT(19)
+#define DMA_IBUF_FORMAT_RGB565 BIT(20)
+#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0
+#define DMA_IBUF_NONCONTIGUOUS BIT(21)
+#else
+#define DMA_OUT_SEL_MDDI BIT(19)
+#define DMA_AHBM_LCD_SEL_PRIMARY 0
+#define DMA_AHBM_LCD_SEL_SECONDARY 0
+#define DMA_IBUF_C3ALPHA_EN 0
+#define DMA_DITHER_EN BIT(24)
+#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
+#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY 0
+#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL 0
+#define DMA_IBUF_FORMAT_RGB565 BIT(25)
+#define DMA_IBUF_NONCONTIGUOUS 0
+#endif
+
+/*
+ * MDDI Register
+ */
+#define MDDI_VDO_PACKET_DESC 0x5666
+
+#ifdef CONFIG_FB_MSM_MDP40
+#define MDP_INTR_ENABLE (msm_mdp_base + 0x0050)
+#define MDP_INTR_STATUS (msm_mdp_base + 0x0054)
+#define MDP_INTR_CLEAR (msm_mdp_base + 0x0058)
+#define MDP_EBI2_LCD0 (msm_mdp_base + 0x0060)
+#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0064)
+#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x0070)
+
+#define MDP_DMA_P_HIST_INTR_STATUS (msm_mdp_base + 0x95014)
+#define MDP_DMA_P_HIST_INTR_CLEAR (msm_mdp_base + 0x95018)
+#define MDP_DMA_P_HIST_INTR_ENABLE (msm_mdp_base + 0x9501C)
+#else
+#define MDP_INTR_ENABLE (msm_mdp_base + 0x0020)
+#define MDP_INTR_STATUS (msm_mdp_base + 0x0024)
+#define MDP_INTR_CLEAR (msm_mdp_base + 0x0028)
+#define MDP_EBI2_LCD0 (msm_mdp_base + 0x003c)
+#define MDP_EBI2_LCD1 (msm_mdp_base + 0x0040)
+#define MDP_EBI2_PORTMAP_MODE (msm_mdp_base + 0x005c)
+#endif
+
+#define MDP_FULL_BYPASS_WORD43 (msm_mdp_base + 0x101ac)
+
+#define MDP_CSC_PFMVn(n) (msm_mdp_base + 0x40400 + 4 * (n))
+#define MDP_CSC_PRMVn(n) (msm_mdp_base + 0x40440 + 4 * (n))
+#define MDP_CSC_PRE_BV1n(n) (msm_mdp_base + 0x40500 + 4 * (n))
+#define MDP_CSC_PRE_BV2n(n) (msm_mdp_base + 0x40540 + 4 * (n))
+#define MDP_CSC_POST_BV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
+#define MDP_CSC_POST_BV2n(n) (msm_mdp_base + 0x405c0 + 4 * (n))
+
+#ifdef CONFIG_FB_MSM_MDP31
+#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40600 + 4 * (n))
+#define MDP_CSC_PRE_LV2n(n) (msm_mdp_base + 0x40640 + 4 * (n))
+#define MDP_CSC_POST_LV1n(n) (msm_mdp_base + 0x40680 + 4 * (n))
+#define MDP_CSC_POST_LV2n(n) (msm_mdp_base + 0x406c0 + 4 * (n))
+#define MDP_PPP_SCALE_COEFF_LSBn(n) (msm_mdp_base + 0x50400 + 8 * (n))
+#define MDP_PPP_SCALE_COEFF_MSBn(n) (msm_mdp_base + 0x50404 + 8 * (n))
+
+#define SCALE_D0_SET 0
+#define SCALE_D1_SET BIT(0)
+#define SCALE_D2_SET BIT(1)
+#define SCALE_U1_SET (BIT(0)|BIT(1))
+
+#else
+#define MDP_CSC_PRE_LV1n(n) (msm_mdp_base + 0x40580 + 4 * (n))
+#endif
+
+#define MDP_CURSOR_WIDTH 64
+#define MDP_CURSOR_HEIGHT 64
+#define MDP_CURSOR_SIZE (MDP_CURSOR_WIDTH*MDP_CURSOR_WIDTH*4)
+
+#define MDP_DMA_P_LUT_C0_EN BIT(0)
+#define MDP_DMA_P_LUT_C1_EN BIT(1)
+#define MDP_DMA_P_LUT_C2_EN BIT(2)
+#define MDP_DMA_P_LUT_POST BIT(4)
+
+void mdp_hw_init(void);
+int mdp_ppp_pipe_wait(void);
+void mdp_pipe_kickoff(uint32 term, struct msm_fb_data_type *mfd);
+void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
+ boolean isr);
+void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
+ boolean sync);
+void mdp_dma_pan_update(struct fb_info *info);
+void mdp_refresh_screen(unsigned long data);
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
+ struct file **pp_src, struct file **pp_dest);
+void mdp_lcd_update_workqueue_handler(struct work_struct *work);
+void mdp_vsync_resync_workqueue_handler(struct work_struct *work);
+void mdp_dma2_update(struct msm_fb_data_type *mfd);
+void mdp_config_vsync(struct msm_fb_data_type *);
+uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd);
+enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht);
+void mdp_set_scale(MDPIBUF *iBuf,
+ uint32 dst_roi_width,
+ uint32 dst_roi_height,
+ boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr);
+void mdp_init_scale_table(void);
+void mdp_adjust_start_addr(uint8 **src0,
+ uint8 **src1,
+ int v_slice,
+ int h_slice,
+ int x,
+ int y,
+ uint32 width,
+ uint32 height, int bpp, MDPIBUF *iBuf, int layer);
+void mdp_set_blend_attr(MDPIBUF *iBuf,
+ uint32 *alpha,
+ uint32 *tpVal,
+ uint32 perPixelAlpha, uint32 *pppop_reg_ptr);
+
+int mdp_dma3_on(struct platform_device *pdev);
+int mdp_dma3_off(struct platform_device *pdev);
+void mdp_dma3_update(struct msm_fb_data_type *mfd);
+
+int mdp_lcdc_on(struct platform_device *pdev);
+int mdp_lcdc_off(struct platform_device *pdev);
+void mdp_lcdc_update(struct msm_fb_data_type *mfd);
+int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor);
+void mdp_enable_irq(uint32 term);
+void mdp_disable_irq(uint32 term);
+void mdp_disable_irq_nolock(uint32 term);
+uint32_t mdp_get_bytes_per_pixel(uint32_t format);
+
+#ifdef MDP_HW_VSYNC
+void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd);
+void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd);
+#endif
+
+void mdp_dma_s_update(struct msm_fb_data_type *mfd);
+
+/* Added to support flipping */
+void mdp_set_offset_info(struct fb_info *info, uint32 address, uint32 interval);
+
+int get_gem_img(struct mdp_img *img, unsigned long *start,
+ unsigned long *len);
+int get_img(struct mdp_img *img, struct fb_info *info,
+ unsigned long *start, unsigned long *len,
+ struct file **pp_file);
+
+
+/*int get_img(struct msmfb_data *img, struct fb_info *info,
+ unsigned long *start, unsigned long *len, struct file **pp_file);*/
+#endif /* MDP_H */
diff --git a/drivers/staging/msm/mdp4.h b/drivers/staging/msm/mdp4.h
new file mode 100644
index 000000000000..26ec8f12cf64
--- /dev/null
+++ b/drivers/staging/msm/mdp4.h
@@ -0,0 +1,352 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDP4_H
+#define MDP4_H
+
+extern struct mdp_dma_data dma2_data;
+extern struct mdp_dma_data dma_s_data;
+extern struct mdp_dma_data dma_e_data;
+extern struct mdp_histogram mdp_hist;
+extern struct completion mdp_hist_comp;
+extern boolean mdp_is_in_isr;
+extern uint32 mdp_intr_mask;
+extern spinlock_t mdp_spin_lock;
+
+
+#define MDP4_NONBLOCKING /* enable non blocking ioctl */
+
+#define MDP4_OVERLAYPROC0_BASE 0x10000
+#define MDP4_OVERLAYPROC1_BASE 0x18000
+
+#define MDP4_VIDEO_BASE 0x20000
+#define MDP4_VIDEO_OFF 0x10000
+
+#define MDP4_RGB_BASE 0x40000
+#define MDP4_RGB_OFF 0x10000
+
+enum { /* display */
+ PRIMARY_INTF_SEL,
+ SECONDARY_INTF_SEL,
+ EXTERNAL_INTF_SEL
+};
+
+enum {
+ LCDC_RGB_INTF,
+ DTV_INTF = LCDC_RGB_INTF,
+ MDDI_LCDC_INTF,
+ MDDI_INTF,
+ EBI2_INTF
+};
+
+enum {
+ MDDI_PRIMARY_SET,
+ MDDI_SECONDARY_SET,
+ MDDI_EXTERNAL_SET
+};
+
+enum {
+ EBI2_LCD0,
+ EBI2_LCD1
+};
+
+enum {
+ OVERLAY_MODE_NONE,
+ OVERLAY_MODE_BLT
+};
+
+enum {
+ OVERLAY_REFRESH_ON_DEMAND,
+ OVERLAY_REFRESH_VSYNC,
+ OVERLAY_REFRESH_VSYNC_HALF,
+ OVERLAY_REFRESH_VSYNC_QUARTER
+};
+
+enum {
+ OVERLAY_FRAMEBUF,
+ OVERLAY_DIRECTOUT
+};
+
+/* system interrupts */
+#define INTR_OVERLAY0_DONE BIT(0)
+#define INTR_OVERLAY1_DONE BIT(1)
+#define INTR_DMA_S_DONE BIT(2)
+#define INTR_DMA_E_DONE BIT(3)
+#define INTR_DMA_P_DONE BIT(4)
+#define INTR_VG1_HISTOGRAM BIT(5)
+#define INTR_VG2_HISTOGRAM BIT(6)
+#define INTR_PRIMARY_VSYNC BIT(7)
+#define INTR_PRIMARY_INTF_UDERRUN BIT(8)
+#define INTR_EXTERNAL_VSYNC BIT(9)
+#define INTR_EXTERNAL_INTF_UDERRUN BIT(10)
+#define INTR_DMA_P_HISTOGRAM BIT(17)
+
+/* histogram interrupts */
+#define INTR_HIST_DONE BIT(0)
+#define INTR_HIST_RESET_SEQ_DONE BIT(1)
+
+
+#ifdef CONFIG_FB_MSM_OVERLAY
+#define MDP4_ANY_INTR_MASK (INTR_OVERLAY0_DONE)
+#else
+#define MDP4_ANY_INTR_MASK (INTR_DMA_P_DONE)
+#endif
+
+enum {
+ OVERLAY_PIPE_RGB1,
+ OVERLAY_PIPE_RGB2,
+};
+
+enum {
+ OVERLAY_PIPE_VG1, /* video/graphic */
+ OVERLAY_PIPE_VG2
+};
+
+enum {
+ OVERLAY_TYPE_RGB,
+ OVERLAY_TYPE_VG /* video/graphic */
+};
+
+enum {
+ MDP4_MIXER0,
+ MDP4_MIXER1
+};
+
+#define MDP4_MAX_MIXER 2
+
+enum {
+ OVERLAY_PLANE_INTERLEAVED,
+ OVERLAY_PLANE_PLANAR,
+ OVERLAY_PLANE_PSEUDO_PLANAR
+};
+
+enum {
+ MDP4_MIXER_STAGE_UNUNSED, /* pipe not used */
+ MDP4_MIXER_STAGE_BASE,
+ MDP4_MIXER_STAGE0, /* zorder 0 */
+ MDP4_MIXER_STAGE1, /* zorder 1 */
+ MDP4_MIXER_STAGE2 /* zorder 2 */
+};
+
+#define MDP4_MAX_STAGE 4
+
+enum {
+ MDP4_FRAME_FORMAT_LINEAR,
+ MDP4_FRAME_FORMAT_ARGB_TILE,
+ MDP4_FRAME_FORMAT_VIDEO_SUPERTILE
+};
+
+enum {
+ MDP4_CHROMA_RGB,
+ MDP4_CHROMA_H2V1,
+ MDP4_CHROMA_H1V2,
+ MDP4_CHROMA_420
+};
+
+#define MDP4_BLEND_BG_TRANSP_EN BIT(9)
+#define MDP4_BLEND_FG_TRANSP_EN BIT(8)
+#define MDP4_BLEND_BG_MOD_ALPHA BIT(7)
+#define MDP4_BLEND_BG_INV_ALPHA BIT(6)
+#define MDP4_BLEND_BG_ALPHA_FG_CONST (0 << 4)
+#define MDP4_BLEND_BG_ALPHA_BG_CONST (1 << 4)
+#define MDP4_BLEND_BG_ALPHA_FG_PIXEL (2 << 4)
+#define MDP4_BLEND_BG_ALPHA_BG_PIXEL (3 << 4)
+#define MDP4_BLEND_FG_MOD_ALPHA BIT(3)
+#define MDP4_BLEND_FG_INV_ALPHA BIT(2)
+#define MDP4_BLEND_FG_ALPHA_FG_CONST (0 << 0)
+#define MDP4_BLEND_FG_ALPHA_BG_CONST (1 << 0)
+#define MDP4_BLEND_FG_ALPHA_FG_PIXEL (2 << 0)
+#define MDP4_BLEND_FG_ALPHA_BG_PIXEL (3 << 0)
+
+#define MDP4_FORMAT_SOLID_FILL BIT(22)
+#define MDP4_FORMAT_UNPACK_ALIGN_MSB BIT(18)
+#define MDP4_FORMAT_UNPACK_TIGHT BIT(17)
+#define MDP4_FORMAT_90_ROTATED BIT(12)
+#define MDP4_FORMAT_ALPHA_ENABLE BIT(8)
+
+#define MDP4_OP_DEINT_ODD_REF BIT(19)
+#define MDP4_OP_IGC_LUT_EN BIT(16)
+#define MDP4_OP_DITHER_EN BIT(15)
+#define MDP4_OP_FLIP_UD BIT(14)
+#define MDP4_OP_FLIP_LR BIT(13)
+#define MDP4_OP_CSC_EN BIT(11)
+#define MDP4_OP_SRC_DATA_YCBCR BIT(9)
+#define MDP4_OP_SCALEY_FIR (0 << 4)
+#define MDP4_OP_SCALEY_MN_PHASE (1 << 4)
+#define MDP4_OP_SCALEY_PIXEL_RPT (2 << 4)
+#define MDP4_OP_SCALEX_FIR (0 << 2)
+#define MDP4_OP_SCALEX_MN_PHASE (1 << 2)
+#define MDP4_OP_SCALEX_PIXEL_RPT (2 << 2)
+#define MDP4_OP_SCALEY_EN BIT(1)
+#define MDP4_OP_SCALEX_EN BIT(0)
+
+#define MDP4_PIPE_PER_MIXER 2
+
+#define MDP4_MAX_PLANE 4
+
+#define MDP4_MAX_VIDEO_PIPE 2
+#define MDP4_MAX_RGB_PIPE 2
+#define MDP4_MAX_OVERLAY_PIPE 16
+
+
+struct mdp4_overlay_pipe {
+ uint32 pipe_type; /* rgb, video/graphic */
+ uint32 pipe_num;
+ uint32 pipe_ndx;
+ uint32 mixer_num; /* which mixer used */
+ uint32 mixer_stage; /* which stage of mixer used */
+ uint32 src_format;
+ uint32 src_width; /* source img width */
+ uint32 src_height; /* source img height */
+ uint32 src_w; /* roi */
+ uint32 src_h; /* roi */
+ uint32 src_x; /* roi */
+ uint32 src_y; /* roi */
+ uint32 dst_w; /* roi */
+ uint32 dst_h; /* roi */
+ uint32 dst_x; /* roi */
+ uint32 dst_y; /* roi */
+ uint32 op_mode;
+ uint32 transp;
+ uint32 blend_op;
+ uint32 phasex_step;
+ uint32 phasey_step;
+ uint32 alpha;
+ uint32 is_fg; /* control alpha & color key */
+ uint32 srcp0_addr; /* interleave, luma */
+ uint32 srcp0_ystride;
+ uint32 srcp1_addr; /* pseudoplanar, chroma plane */
+ uint32 srcp1_ystride;
+ uint32 srcp2_addr; /* planar color 2*/
+ uint32 srcp2_ystride;
+ uint32 srcp3_addr; /* alpha/color 3 */
+ uint32 srcp3_ystride;
+ uint32 fetch_plane;
+ uint32 frame_format; /* video */
+ uint32 chroma_site; /* video */
+ uint32 chroma_sample; /* video */
+ uint32 solid_fill;
+ uint32 vc1_reduce; /* video */
+ uint32 fatch_planes; /* video */
+ uint32 unpack_align_msb;/* 0 to LSB, 1 to MSB */
+ uint32 unpack_tight;/* 0 for loose, 1 for tight */
+ uint32 unpack_count;/* 0 = 1 component, 1 = 2 component ... */
+ uint32 rotated_90; /* has been rotated 90 degree */
+ uint32 bpp; /* byte per pixel */
+ uint32 alpha_enable;/* source has alpha */
+ /*
+ * number of bits for source component,
+ * 0 = 1 bit, 1 = 2 bits, 2 = 6 bits, 3 = 8 bits
+ */
+ uint32 a_bit; /* component 3, alpha */
+ uint32 r_bit; /* component 2, R_Cr */
+ uint32 b_bit; /* component 1, B_Cb */
+ uint32 g_bit; /* component 0, G_lumz */
+ /*
+ * unpack pattern
+ * A = C3, R = C2, B = C1, G = C0
+ */
+ uint32 element3; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
+ uint32 element2; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
+ uint32 element1; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
+ uint32 element0; /* 0 = C0, 1 = C1, 2 = C2, 3 = C3 */
+ struct completion comp;
+ struct mdp_overlay req_data;
+};
+
+void mdp4_sw_reset(unsigned long bits);
+void mdp4_display_intf_sel(int output, unsigned long intf);
+void mdp4_overlay_cfg(int layer, int blt_mode, int refresh, int direct_out);
+void mdp4_ebi2_lcd_setup(int lcd, unsigned long base, int ystride);
+void mdp4_mddi_setup(int which, unsigned long id);
+unsigned long mdp4_display_status(void);
+void mdp4_enable_clk_irq(void);
+void mdp4_disable_clk_irq(void);
+void mdp4_dma_p_update(struct msm_fb_data_type *mfd);
+void mdp4_dma_s_update(struct msm_fb_data_type *mfd);
+void mdp_pipe_ctrl(MDP_BLOCK_TYPE block, MDP_BLOCK_POWER_STATE state,
+ boolean isr);
+void mdp4_pipe_kickoff(uint32 pipe, struct msm_fb_data_type *mfd);
+int mdp4_lcdc_on(struct platform_device *pdev);
+int mdp4_lcdc_off(struct platform_device *pdev);
+void mdp4_lcdc_update(struct msm_fb_data_type *mfd);
+void mdp4_intr_clear_set(ulong clear, ulong set);
+void mdp4_dma_p_cfg(void);
+void mdp4_hw_init(void);
+void mdp4_isr_read(int);
+void mdp4_clear_lcdc(void);
+void mdp4_mixer_blend_init(int mixer_num);
+void mdp4_vg_qseed_init(int vg_num);
+void mdp4_vg_csc_mv_setup(int vp_num);
+void mdp4_vg_csc_pre_bv_setup(int vp_num);
+void mdp4_vg_csc_post_bv_setup(int vp_num);
+void mdp4_vg_csc_pre_lv_setup(int vp_num);
+void mdp4_vg_csc_post_lv_setup(int vp_num);
+irqreturn_t mdp4_isr(int irq, void *ptr);
+void mdp4_overlay_format_to_pipe(uint32 format, struct mdp4_overlay_pipe *pipe);
+uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe);
+uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe);
+uint32 mdp4_overlay_op_mode(struct mdp4_overlay_pipe *pipe);
+void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd);
+void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all);
+void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe);
+void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe);
+int mdp4_mixer_stage_can_run(struct mdp4_overlay_pipe *pipe);
+void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe);
+void mdp4_mddi_overlay(struct msm_fb_data_type *mfd);
+int mdp4_overlay_format2type(uint32 format);
+int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe);
+int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req);
+int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req);
+int mdp4_overlay_unset(struct fb_info *info, int ndx);
+int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req,
+ struct file **pp_src_file);
+struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void);
+void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe);
+void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc);
+void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe);
+int mdp4_overlay_active(int mixer);
+void mdp4_overlay0_done_lcdc(void);
+void mdp4_overlay0_done_mddi(void);
+void mdp4_mddi_overlay_restore(void);
+void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe);
+void mdp4_rgb_igc_lut_setup(int num);
+void mdp4_vg_igc_lut_setup(int num);
+void mdp4_mixer_gc_lut_setup(int mixer_num);
+
+#ifdef CONFIG_DEBUG_FS
+int mdp4_debugfs_init(void);
+#endif
+
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
+ struct file **pp_src_file, struct file **pp_dst_file);
+
+#endif /* MDP_H */
diff --git a/drivers/staging/msm/mdp4_debugfs.c b/drivers/staging/msm/mdp4_debugfs.c
new file mode 100644
index 000000000000..844d46775ecd
--- /dev/null
+++ b/drivers/staging/msm/mdp4_debugfs.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+
+#define MDP4_DEBUG_BUF 128
+
+
+static char mdp4_debug_buf[MDP4_DEBUG_BUF];
+static ulong mdp4_debug_offset;
+static ulong mdp4_base_addr;
+
+static int mdp4_offset_set(void *data, u64 val)
+{
+ mdp4_debug_offset = (int)val;
+ return 0;
+}
+
+static int mdp4_offset_get(void *data, u64 *val)
+{
+ *val = (u64)mdp4_debug_offset;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(
+ mdp4_offset_fops,
+ mdp4_offset_get,
+ mdp4_offset_set,
+ "%llx\n");
+
+
+static int mdp4_debugfs_open(struct inode *inode, struct file *file)
+{
+ /* non-seekable */
+ file->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
+ return 0;
+}
+
+static int mdp4_debugfs_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static ssize_t mdp4_debugfs_write(
+ struct file *file,
+ const char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ int cnt;
+ unsigned int data;
+
+ printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
+ __func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
+
+ if (count > sizeof(mdp4_debug_buf))
+ return -EFAULT;
+
+ if (copy_from_user(mdp4_debug_buf, buff, count))
+ return -EFAULT;
+
+
+ mdp4_debug_buf[count] = 0; /* end of string */
+
+ cnt = sscanf(mdp4_debug_buf, "%x", &data);
+ if (cnt < 1) {
+ printk(KERN_ERR "%s: sscanf failed cnt=%d" , __func__, cnt);
+ return -EINVAL;
+ }
+
+ writel(&data, mdp4_base_addr + mdp4_debug_offset);
+
+ return 0;
+}
+
+static ssize_t mdp4_debugfs_read(
+ struct file *file,
+ char __user *buff,
+ size_t count,
+ loff_t *ppos)
+{
+ int len = 0;
+ unsigned int data;
+
+ printk(KERN_INFO "%s: offset=%d count=%d *ppos=%d\n",
+ __func__, (int)mdp4_debug_offset, (int)count, (int)*ppos);
+
+ if (*ppos)
+ return 0; /* the end */
+
+ data = readl(mdp4_base_addr + mdp4_debug_offset);
+
+ len = snprintf(mdp4_debug_buf, 4, "%x\n", data);
+
+ if (len > 0) {
+ if (len > count)
+ len = count;
+ if (copy_to_user(buff, mdp4_debug_buf, len))
+ return -EFAULT;
+ }
+
+ printk(KERN_INFO "%s: len=%d\n", __func__, len);
+
+ if (len < 0)
+ return 0;
+
+ *ppos += len; /* increase offset */
+
+ return len;
+}
+
+static const struct file_operations mdp4_debugfs_fops = {
+ .open = mdp4_debugfs_open,
+ .release = mdp4_debugfs_release,
+ .read = mdp4_debugfs_read,
+ .write = mdp4_debugfs_write,
+};
+
+int mdp4_debugfs_init(void)
+{
+ struct dentry *dent = debugfs_create_dir("mdp4", NULL);
+
+ if (IS_ERR(dent)) {
+ printk(KERN_ERR "%s(%d): debugfs_create_dir fail, error %ld\n",
+ __FILE__, __LINE__, PTR_ERR(dent));
+ return -1;
+ }
+
+ if (debugfs_create_file("offset", 0644, dent, 0, &mdp4_offset_fops)
+ == NULL) {
+ printk(KERN_ERR "%s(%d): debugfs_create_file: offset fail\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ if (debugfs_create_file("regs", 0644, dent, 0, &mdp4_debugfs_fops)
+ == NULL) {
+ printk(KERN_ERR "%s(%d): debugfs_create_file: regs fail\n",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ mdp4_debug_offset = 0;
+ mdp4_base_addr = (ulong) msm_mdp_base; /* defined at msm_fb_def.h */
+
+ return 0;
+}
diff --git a/drivers/staging/msm/mdp4_overlay.c b/drivers/staging/msm/mdp4_overlay.c
new file mode 100644
index 000000000000..304bb8297635
--- /dev/null
+++ b/drivers/staging/msm/mdp4_overlay.c
@@ -0,0 +1,1259 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+#include <linux/fb.h>
+#include <msm_mdp.h>
+#include <linux/file.h>
+#include "android_pmem.h"
+#include <linux/major.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/mutex.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+
+struct mdp4_overlay_ctrl {
+ struct mdp4_overlay_pipe plist[MDP4_MAX_OVERLAY_PIPE];
+ struct mdp4_overlay_pipe *stage[MDP4_MAX_MIXER][MDP4_MAX_STAGE];
+} mdp4_overlay_db;
+
+static struct mdp4_overlay_ctrl *ctrl = &mdp4_overlay_db;
+
+
+void mdp4_overlay_dmap_cfg(struct msm_fb_data_type *mfd, int lcdc)
+{
+ uint32 dma2_cfg_reg;
+
+ dma2_cfg_reg = DMA_DITHER_EN;
+
+ if (mfd->fb_imgType == MDP_BGR_565)
+ dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
+ else
+ dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
+
+
+ if (mfd->panel_info.bpp == 18) {
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
+ DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+ } else if (mfd->panel_info.bpp == 16) {
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
+ DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
+ } else {
+ dma2_cfg_reg |= DMA_DSTC0G_8BITS | /* 888 16BPP */
+ DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
+ }
+
+ if (lcdc)
+ dma2_cfg_reg |= DMA_PACK_ALIGN_MSB;
+
+ /* dma2 config register */
+ MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
+
+}
+
+void mdp4_overlay_dmap_xy(struct mdp4_overlay_pipe *pipe)
+{
+
+ /* dma_p source */
+ MDP_OUTP(MDP_BASE + 0x90004,
+ (pipe->src_height << 16 | pipe->src_width));
+ MDP_OUTP(MDP_BASE + 0x90008, pipe->srcp0_addr);
+ MDP_OUTP(MDP_BASE + 0x9000c, pipe->srcp0_ystride);
+
+ /* dma_p dest */
+ MDP_OUTP(MDP_BASE + 0x90010, (pipe->dst_y << 16 | pipe->dst_x));
+}
+
+#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
+#define MDP4_VG_PHASE_STEP_SHIFT 29
+
+static int mdp4_leading_0(uint32 num)
+{
+ uint32 bit = 0x80000000;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ if (bit & num)
+ return i;
+ bit >>= 1;
+ }
+
+ return i;
+}
+
+static uint32 mdp4_scale_phase_step(int f_num, uint32 src, uint32 dst)
+{
+ uint32 val;
+ int n;
+
+ n = mdp4_leading_0(src);
+ if (n > f_num)
+ n = f_num;
+ val = src << n; /* maximum to reduce lose of resolution */
+ val /= dst;
+ if (n < f_num) {
+ n = f_num - n;
+ val <<= n;
+ }
+
+ return val;
+}
+
+static void mdp4_scale_setup(struct mdp4_overlay_pipe *pipe)
+{
+
+ pipe->phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
+ pipe->phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
+
+ if (pipe->dst_h && pipe->src_h != pipe->dst_h) {
+ if (pipe->dst_h >= pipe->src_h * 8) /* too much */
+ return;
+ pipe->op_mode |= MDP4_OP_SCALEY_EN;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VG) {
+ if (pipe->dst_h <= (pipe->src_h / 4))
+ pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
+ else
+ pipe->op_mode |= MDP4_OP_SCALEY_FIR;
+ }
+
+ pipe->phasey_step = mdp4_scale_phase_step(29,
+ pipe->src_h, pipe->dst_h);
+ }
+
+ if (pipe->dst_w && pipe->src_w != pipe->dst_w) {
+ if (pipe->dst_w >= pipe->src_w * 8) /* too much */
+ return;
+ pipe->op_mode |= MDP4_OP_SCALEX_EN;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VG) {
+ if (pipe->dst_w <= (pipe->src_w / 4))
+ pipe->op_mode |= MDP4_OP_SCALEY_MN_PHASE;
+ else
+ pipe->op_mode |= MDP4_OP_SCALEY_FIR;
+ }
+
+ pipe->phasex_step = mdp4_scale_phase_step(29,
+ pipe->src_w, pipe->dst_w);
+ }
+}
+
+void mdp4_overlay_rgb_setup(struct mdp4_overlay_pipe *pipe)
+{
+ char *rgb_base;
+ uint32 src_size, src_xy, dst_size, dst_xy;
+ uint32 format, pattern;
+
+ rgb_base = MDP_BASE + MDP4_RGB_BASE;
+ rgb_base += (MDP4_RGB_OFF * pipe->pipe_num);
+
+ src_size = ((pipe->src_h << 16) | pipe->src_w);
+ src_xy = ((pipe->src_y << 16) | pipe->src_x);
+ dst_size = ((pipe->dst_h << 16) | pipe->dst_w);
+ dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);
+
+ format = mdp4_overlay_format(pipe);
+ pattern = mdp4_overlay_unpack_pattern(pipe);
+
+ pipe->op_mode |= MDP4_OP_IGC_LUT_EN;
+
+ mdp4_scale_setup(pipe);
+
+ outpdw(rgb_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */
+ outpdw(rgb_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */
+ outpdw(rgb_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */
+ outpdw(rgb_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */
+
+ outpdw(rgb_base + 0x0010, pipe->srcp0_addr);
+ outpdw(rgb_base + 0x0040, pipe->srcp0_ystride);
+
+ outpdw(rgb_base + 0x0050, format);/* MDP_RGB_SRC_FORMAT */
+ outpdw(rgb_base + 0x0054, pattern);/* MDP_RGB_SRC_UNPACK_PATTERN */
+ outpdw(rgb_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
+ outpdw(rgb_base + 0x005c, pipe->phasex_step);
+ outpdw(rgb_base + 0x0060, pipe->phasey_step);
+
+ /* 16 bytes-burst x 3 req <= 48 bytes */
+ outpdw(rgb_base + 0x1004, 0xc2); /* MDP_RGB_FETCH_CFG */
+}
+
+void mdp4_overlay_vg_setup(struct mdp4_overlay_pipe *pipe)
+{
+ char *vg_base;
+ uint32 frame_size, src_size, src_xy, dst_size, dst_xy;
+ uint32 format, pattern;
+
+ vg_base = MDP_BASE + MDP4_VIDEO_BASE;
+ vg_base += (MDP4_VIDEO_OFF * pipe->pipe_num);
+
+ frame_size = ((pipe->src_height << 16) | pipe->src_width);
+ src_size = ((pipe->src_h << 16) | pipe->src_w);
+ src_xy = ((pipe->src_y << 16) | pipe->src_x);
+ dst_size = ((pipe->dst_h << 16) | pipe->dst_w);
+ dst_xy = ((pipe->dst_y << 16) | pipe->dst_x);
+
+ format = mdp4_overlay_format(pipe);
+ pattern = mdp4_overlay_unpack_pattern(pipe);
+
+ pipe->op_mode |= (MDP4_OP_CSC_EN | MDP4_OP_SRC_DATA_YCBCR |
+ MDP4_OP_IGC_LUT_EN);
+
+ mdp4_scale_setup(pipe);
+
+ outpdw(vg_base + 0x0000, src_size); /* MDP_RGB_SRC_SIZE */
+ outpdw(vg_base + 0x0004, src_xy); /* MDP_RGB_SRC_XY */
+ outpdw(vg_base + 0x0008, dst_size); /* MDP_RGB_DST_SIZE */
+ outpdw(vg_base + 0x000c, dst_xy); /* MDP_RGB_DST_XY */
+ outpdw(vg_base + 0x0048, frame_size); /* TILE frame size */
+
+ /* luma component plane */
+ outpdw(vg_base + 0x0010, pipe->srcp0_addr);
+
+ /* chroma component plane */
+ outpdw(vg_base + 0x0014, pipe->srcp1_addr);
+
+ outpdw(vg_base + 0x0040,
+ pipe->srcp1_ystride << 16 | pipe->srcp0_ystride);
+
+ outpdw(vg_base + 0x0050, format); /* MDP_RGB_SRC_FORMAT */
+ outpdw(vg_base + 0x0054, pattern); /* MDP_RGB_SRC_UNPACK_PATTERN */
+ outpdw(vg_base + 0x0058, pipe->op_mode);/* MDP_RGB_OP_MODE */
+ outpdw(vg_base + 0x005c, pipe->phasex_step);
+ outpdw(vg_base + 0x0060, pipe->phasey_step);
+
+ if (pipe->op_mode & MDP4_OP_DITHER_EN) {
+ outpdw(vg_base + 0x0068,
+ pipe->r_bit << 4 | pipe->b_bit << 2 | pipe->g_bit);
+ }
+
+ /* 16 bytes-burst x 3 req <= 48 bytes */
+ outpdw(vg_base + 0x1004, 0xc2); /* MDP_VG_FETCH_CFG */
+}
+
+int mdp4_overlay_format2type(uint32 format)
+{
+ switch (format) {
+ case MDP_RGB_565:
+ case MDP_RGB_888:
+ case MDP_BGR_565:
+ case MDP_ARGB_8888:
+ case MDP_RGBA_8888:
+ case MDP_BGRA_8888:
+ return OVERLAY_TYPE_RGB;
+ case MDP_YCRYCB_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V2_TILE:
+ case MDP_Y_CRCB_H2V2_TILE:
+ return OVERLAY_TYPE_VG;
+ default:
+ return -ERANGE;
+ }
+
+}
+
+#define C3_ALPHA 3 /* alpha */
+#define C2_R_Cr 2 /* R/Cr */
+#define C1_B_Cb 1 /* B/Cb */
+#define C0_G_Y 0 /* G/luma */
+
+int mdp4_overlay_format2pipe(struct mdp4_overlay_pipe *pipe)
+{
+ switch (pipe->src_format) {
+ case MDP_RGB_565:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 0;
+ pipe->r_bit = 1; /* R, 5 bits */
+ pipe->b_bit = 1; /* B, 5 bits */
+ pipe->g_bit = 2; /* G, 6 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 2;
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 2; /* 2 bpp */
+ break;
+ case MDP_RGB_888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 0;
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 2;
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 3; /* 3 bpp */
+ break;
+ case MDP_BGR_565:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 0;
+ pipe->r_bit = 1; /* R, 5 bits */
+ pipe->b_bit = 1; /* B, 5 bits */
+ pipe->g_bit = 2; /* G, 6 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 2;
+ pipe->element2 = C1_B_Cb; /* B */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C2_R_Cr; /* R */
+ pipe->bpp = 2; /* 2 bpp */
+ break;
+ case MDP_ARGB_8888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 3; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 1;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C3_ALPHA; /* alpha */
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 4; /* 4 bpp */
+ break;
+ case MDP_RGBA_8888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 3; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 1;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C2_R_Cr; /* R */
+ pipe->element2 = C0_G_Y; /* G */
+ pipe->element1 = C1_B_Cb; /* B */
+ pipe->element0 = C3_ALPHA; /* alpha */
+ pipe->bpp = 4; /* 4 bpp */
+ break;
+ case MDP_BGRA_8888:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 3; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 1;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C1_B_Cb; /* B */
+ pipe->element2 = C0_G_Y; /* G */
+ pipe->element1 = C2_R_Cr; /* R */
+ pipe->element0 = C3_ALPHA; /* alpha */
+ pipe->bpp = 4; /* 4 bpp */
+ break;
+ case MDP_YCRYCB_H2V1:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_INTERLEAVED;
+ pipe->a_bit = 0; /* alpha, 4 bits */
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 3;
+ pipe->element3 = C0_G_Y; /* G */
+ pipe->element2 = C2_R_Cr; /* R */
+ pipe->element1 = C0_G_Y; /* G */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->bpp = 2; /* 2 bpp */
+ pipe->chroma_sample = MDP4_CHROMA_H2V1;
+ break;
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V2:
+ pipe->frame_format = MDP4_FRAME_FORMAT_LINEAR;
+ pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR;
+ pipe->a_bit = 0;
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 1; /* 2 */
+ pipe->element3 = C0_G_Y; /* not used */
+ pipe->element2 = C0_G_Y; /* not used */
+ if (pipe->src_format == MDP_Y_CRCB_H2V1) {
+ pipe->element1 = C2_R_Cr; /* R */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->chroma_sample = MDP4_CHROMA_H2V1;
+ } else if (pipe->src_format == MDP_Y_CBCR_H2V1) {
+ pipe->element1 = C1_B_Cb; /* B */
+ pipe->element0 = C2_R_Cr; /* R */
+ pipe->chroma_sample = MDP4_CHROMA_H2V1;
+ } else if (pipe->src_format == MDP_Y_CRCB_H2V2) {
+ pipe->element1 = C2_R_Cr; /* R */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->chroma_sample = MDP4_CHROMA_420;
+ } else if (pipe->src_format == MDP_Y_CBCR_H2V2) {
+ pipe->element1 = C1_B_Cb; /* B */
+ pipe->element0 = C2_R_Cr; /* R */
+ pipe->chroma_sample = MDP4_CHROMA_420;
+ }
+ pipe->bpp = 2; /* 2 bpp */
+ break;
+ case MDP_Y_CBCR_H2V2_TILE:
+ case MDP_Y_CRCB_H2V2_TILE:
+ pipe->frame_format = MDP4_FRAME_FORMAT_VIDEO_SUPERTILE;
+ pipe->fetch_plane = OVERLAY_PLANE_PSEUDO_PLANAR;
+ pipe->a_bit = 0;
+ pipe->r_bit = 3; /* R, 8 bits */
+ pipe->b_bit = 3; /* B, 8 bits */
+ pipe->g_bit = 3; /* G, 8 bits */
+ pipe->alpha_enable = 0;
+ pipe->unpack_tight = 1;
+ pipe->unpack_align_msb = 0;
+ pipe->unpack_count = 1; /* 2 */
+ pipe->element3 = C0_G_Y; /* not used */
+ pipe->element2 = C0_G_Y; /* not used */
+ if (pipe->src_format == MDP_Y_CRCB_H2V2_TILE) {
+ pipe->element1 = C2_R_Cr; /* R */
+ pipe->element0 = C1_B_Cb; /* B */
+ pipe->chroma_sample = MDP4_CHROMA_420;
+ } else if (pipe->src_format == MDP_Y_CBCR_H2V2_TILE) {
+ pipe->element1 = C1_B_Cb; /* B */
+ pipe->element0 = C2_R_Cr; /* R */
+ pipe->chroma_sample = MDP4_CHROMA_420;
+ }
+ pipe->bpp = 2; /* 2 bpp */
+ break;
+ default:
+ /* not likely */
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+/*
+ * color_key_convert: output with 12 bits color key
+ */
+static uint32 color_key_convert(int start, int num, uint32 color)
+{
+
+ uint32 data;
+
+ data = (color >> start) & ((1 << num) - 1);
+
+ if (num == 5)
+ data = (data << 7) + (data << 2) + (data >> 3);
+ else if (num == 6)
+ data = (data << 6) + data;
+ else /* 8 bits */
+ data = (data << 4) + (data >> 4);
+
+ return data;
+
+}
+
+void transp_color_key(int format, uint32 transp,
+ uint32 *c0, uint32 *c1, uint32 *c2)
+{
+ int b_start, g_start, r_start;
+ int b_num, g_num, r_num;
+
+ switch (format) {
+ case MDP_RGB_565:
+ b_start = 0;
+ g_start = 5;
+ r_start = 11;
+ r_num = 5;
+ g_num = 6;
+ b_num = 5;
+ break;
+ case MDP_RGB_888:
+ case MDP_XRGB_8888:
+ case MDP_ARGB_8888:
+ b_start = 0;
+ g_start = 8;
+ r_start = 16;
+ r_num = 8;
+ g_num = 8;
+ b_num = 8;
+ break;
+ case MDP_BGR_565:
+ b_start = 11;
+ g_start = 5;
+ r_start = 0;
+ r_num = 5;
+ g_num = 6;
+ b_num = 5;
+ break;
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CBCR_H2V1:
+ b_start = 8;
+ g_start = 16;
+ r_start = 0;
+ r_num = 8;
+ g_num = 8;
+ b_num = 8;
+ break;
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CRCB_H2V1:
+ b_start = 0;
+ g_start = 16;
+ r_start = 8;
+ r_num = 8;
+ g_num = 8;
+ b_num = 8;
+ break;
+ default:
+ b_start = 0;
+ g_start = 8;
+ r_start = 16;
+ r_num = 8;
+ g_num = 8;
+ b_num = 8;
+ break;
+ }
+
+ *c0 = color_key_convert(g_start, g_num, transp);
+ *c1 = color_key_convert(b_start, b_num, transp);
+ *c2 = color_key_convert(r_start, r_num, transp);
+}
+
+uint32 mdp4_overlay_format(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 format;
+
+ format = 0;
+
+ if (pipe->solid_fill)
+ format |= MDP4_FORMAT_SOLID_FILL;
+
+ if (pipe->unpack_align_msb)
+ format |= MDP4_FORMAT_UNPACK_ALIGN_MSB;
+
+ if (pipe->unpack_tight)
+ format |= MDP4_FORMAT_UNPACK_TIGHT;
+
+ if (pipe->alpha_enable)
+ format |= MDP4_FORMAT_ALPHA_ENABLE;
+
+ format |= (pipe->unpack_count << 13);
+ format |= ((pipe->bpp - 1) << 9);
+ format |= (pipe->a_bit << 6);
+ format |= (pipe->r_bit << 4);
+ format |= (pipe->b_bit << 2);
+ format |= pipe->g_bit;
+
+ format |= (pipe->frame_format << 29);
+
+ if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) {
+ /* video/graphic */
+ format |= (pipe->fetch_plane << 19);
+ format |= (pipe->chroma_site << 28);
+ format |= (pipe->chroma_sample << 26);
+ }
+
+ return format;
+}
+
+uint32 mdp4_overlay_unpack_pattern(struct mdp4_overlay_pipe *pipe)
+{
+ return (pipe->element3 << 24) | (pipe->element2 << 16) |
+ (pipe->element1 << 8) | pipe->element0;
+}
+
+void mdp4_overlayproc_cfg(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 data;
+ char *overlay_base;
+
+ if (pipe->mixer_num == MDP4_MIXER1)
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
+ else
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+
+ /* MDP_OVERLAYPROC_CFG */
+ outpdw(overlay_base + 0x0004, 0x01); /* directout */
+ data = pipe->src_height;
+ data <<= 16;
+ data |= pipe->src_width;
+ outpdw(overlay_base + 0x0008, data); /* ROI, height + width */
+ outpdw(overlay_base + 0x000c, pipe->srcp0_addr);
+ outpdw(overlay_base + 0x0010, pipe->srcp0_ystride);
+ outpdw(overlay_base + 0x0014, 0x4); /* GC_LUT_EN, 888 */
+}
+
+int mdp4_overlay_active(int mixer)
+{
+ uint32 data, mask, i;
+ int p1, p2;
+
+ data = inpdw(MDP_BASE + 0x10100);
+ p1 = 0;
+ p2 = 0;
+ for (i = 0; i < 8; i++) {
+ mask = data & 0x0f;
+ if (mask) {
+ if (mask <= 4)
+ p1++;
+ else
+ p2++;
+ }
+ data >>= 4;
+ }
+
+ if (mixer)
+ return p2;
+ else
+ return p1;
+}
+
+void mdp4_mixer_stage_up(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 data, mask, snum, stage, mixer;
+
+ stage = pipe->mixer_stage;
+ mixer = pipe->mixer_num;
+
+ /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
+ data = inpdw(MDP_BASE + 0x10100);
+
+ if (mixer == MDP4_MIXER1)
+ stage += 8;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */
+ snum = 0;
+ snum += (4 * pipe->pipe_num);
+ } else {
+ snum = 8;
+ snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */
+ }
+
+ mask = 0x0f;
+ mask <<= snum;
+ stage <<= snum;
+ data &= ~mask; /* clear old bits */
+
+ data |= stage;
+
+ outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+
+ data = inpdw(MDP_BASE + 0x10100);
+
+ ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = pipe; /* keep it */
+}
+
+void mdp4_mixer_stage_down(struct mdp4_overlay_pipe *pipe)
+{
+ uint32 data, mask, snum, stage, mixer;
+
+ stage = pipe->mixer_stage;
+ mixer = pipe->mixer_num;
+
+ if (pipe != ctrl->stage[mixer][stage]) /* not runing */
+ return;
+
+ /* MDP_LAYERMIXER_IN_CFG, shard by both mixer 0 and 1 */
+ data = inpdw(MDP_BASE + 0x10100);
+
+ if (mixer == MDP4_MIXER1)
+ stage += 8;
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VG) {/* VG1 and VG2 */
+ snum = 0;
+ snum += (4 * pipe->pipe_num);
+ } else {
+ snum = 8;
+ snum += (4 * pipe->pipe_num); /* RGB1 and RGB2 */
+ }
+
+ mask = 0x0f;
+ mask <<= snum;
+ data &= ~mask; /* clear old bits */
+
+ outpdw(MDP_BASE + 0x10100, data); /* MDP_LAYERMIXER_IN_CFG */
+
+ data = inpdw(MDP_BASE + 0x10100);
+
+ ctrl->stage[pipe->mixer_num][pipe->mixer_stage] = NULL; /* clear it */
+}
+
+void mdp4_mixer_blend_setup(struct mdp4_overlay_pipe *pipe)
+{
+ unsigned char *overlay_base;
+ uint32 c0, c1, c2, blend_op;
+ int off;
+
+ if (pipe->mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
+ else
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+
+ /* stage 0 to stage 2 */
+ off = 0x20 * (pipe->mixer_stage - MDP4_MIXER_STAGE0);
+
+ blend_op = 0;
+ if (pipe->alpha_enable) /* ARGB */
+ blend_op = MDP4_BLEND_FG_ALPHA_FG_PIXEL |
+ MDP4_BLEND_BG_ALPHA_FG_PIXEL;
+ else
+ blend_op = (MDP4_BLEND_BG_ALPHA_BG_CONST |
+ MDP4_BLEND_FG_ALPHA_FG_CONST);
+
+
+ if (pipe->alpha_enable == 0) { /* not ARGB */
+ if (pipe->is_fg) {
+ outpdw(overlay_base + off + 0x108, pipe->alpha);
+ outpdw(overlay_base + off + 0x10c, 0xff - pipe->alpha);
+ } else {
+ outpdw(overlay_base + off + 0x108, 0xff - pipe->alpha);
+ outpdw(overlay_base + off + 0x10c, pipe->alpha);
+ }
+ }
+
+ if (pipe->transp != MDP_TRANSP_NOP) {
+ transp_color_key(pipe->src_format, pipe->transp, &c0, &c1, &c2);
+ if (pipe->is_fg) {
+ blend_op |= MDP4_BLEND_FG_TRANSP_EN; /* Fg blocked */
+ /* lower limit */
+ if (c0 > 0x10)
+ c0 -= 0x10;
+ if (c1 > 0x10)
+ c1 -= 0x10;
+ if (c2 > 0x10)
+ c2 -= 0x10;
+ outpdw(overlay_base + off + 0x110,
+ (c1 << 16 | c0));/* low */
+ outpdw(overlay_base + off + 0x114, c2);/* low */
+ /* upper limit */
+ if ((c0 + 0x20) < 0x0fff)
+ c0 += 0x20;
+ else
+ c0 = 0x0fff;
+ if ((c1 + 0x20) < 0x0fff)
+ c1 += 0x20;
+ else
+ c1 = 0x0fff;
+ if ((c2 + 0x20) < 0x0fff)
+ c2 += 0x20;
+ else
+ c2 = 0x0fff;
+ outpdw(overlay_base + off + 0x118,
+ (c1 << 16 | c0));/* high */
+ outpdw(overlay_base + off + 0x11c, c2);/* high */
+ } else {
+ blend_op |= MDP4_BLEND_BG_TRANSP_EN; /* bg blocked */
+ /* lower limit */
+ if (c0 > 0x10)
+ c0 -= 0x10;
+ if (c1 > 0x10)
+ c1 -= 0x10;
+ if (c2 > 0x10)
+ c2 -= 0x10;
+ outpdw(overlay_base + 0x180,
+ (c1 << 16 | c0));/* low */
+ outpdw(overlay_base + 0x184, c2);/* low */
+ /* upper limit */
+ if ((c0 + 0x20) < 0x0fff)
+ c0 += 0x20;
+ else
+ c0 = 0x0fff;
+ if ((c1 + 0x20) < 0x0fff)
+ c1 += 0x20;
+ else
+ c1 = 0x0fff;
+ if ((c2 + 0x20) < 0x0fff)
+ c2 += 0x20;
+ else
+ c2 = 0x0fff;
+ outpdw(overlay_base + 0x188,
+ (c1 << 16 | c0));/* high */
+ outpdw(overlay_base + 0x18c, c2);/* high */
+ }
+ }
+ outpdw(overlay_base + off + 0x104, blend_op);
+}
+
+void mdp4_overlay_reg_flush(struct mdp4_overlay_pipe *pipe, int all)
+{
+ uint32 bits = 0;
+
+ if (pipe->mixer_num == MDP4_MIXER1)
+ bits |= 0x02;
+ else
+ bits |= 0x01;
+
+ if (all) {
+ if (pipe->pipe_type == OVERLAY_TYPE_RGB) {
+ if (pipe->pipe_num == OVERLAY_PIPE_RGB2)
+ bits |= 0x20;
+ else
+ bits |= 0x10;
+ } else {
+ if (pipe->pipe_num == OVERLAY_PIPE_VG2)
+ bits |= 0x08;
+ else
+ bits |= 0x04;
+ }
+ }
+
+ outpdw(MDP_BASE + 0x18000, bits); /* MDP_OVERLAY_REG_FLUSH */
+
+ while (inpdw(MDP_BASE + 0x18000) & bits) /* self clear when complete */
+ ;
+}
+
+struct mdp4_overlay_pipe *mdp4_overlay_ndx2pipe(int ndx)
+{
+ struct mdp4_overlay_pipe *pipe;
+
+ if (ndx == 0 || ndx >= MDP4_MAX_OVERLAY_PIPE)
+ return NULL;
+
+ pipe = &ctrl->plist[ndx - 1]; /* ndx start from 1 */
+
+ if (pipe->pipe_ndx == 0)
+ return NULL;
+
+ return pipe;
+}
+
+struct mdp4_overlay_pipe *mdp4_overlay_pipe_alloc(void)
+{
+ int i;
+ struct mdp4_overlay_pipe *pipe;
+
+ pipe = &ctrl->plist[0];
+ for (i = 0; i < MDP4_MAX_OVERLAY_PIPE; i++) {
+ if (pipe->pipe_ndx == 0) {
+ pipe->pipe_ndx = i + 1; /* start from 1 */
+ init_completion(&pipe->comp);
+ printk(KERN_INFO "mdp4_overlay_pipe_alloc: pipe=%x ndx=%d\n",
+ (int)pipe, pipe->pipe_ndx);
+ return pipe;
+ }
+ pipe++;
+ }
+
+ return NULL;
+}
+
+
+void mdp4_overlay_pipe_free(struct mdp4_overlay_pipe *pipe)
+{
+ printk(KERN_INFO "mdp4_overlay_pipe_free: pipe=%x ndx=%d\n",
+ (int)pipe, pipe->pipe_ndx);
+ memset(pipe, 0, sizeof(*pipe));
+}
+
+static int get_pipe_num(int ptype, int stage)
+{
+ if (ptype == OVERLAY_TYPE_RGB) {
+ if (stage == MDP4_MIXER_STAGE_BASE)
+ return OVERLAY_PIPE_RGB1;
+ else
+ return OVERLAY_PIPE_RGB2;
+ } else {
+ if (stage == MDP4_MIXER_STAGE0)
+ return OVERLAY_PIPE_VG1;
+ else
+ return OVERLAY_PIPE_VG2;
+ }
+}
+
+int mdp4_overlay_req_check(uint32 id, uint32 z_order, uint32 mixer)
+{
+ struct mdp4_overlay_pipe *pipe;
+
+ pipe = ctrl->stage[mixer][z_order];
+
+ if (pipe == NULL)
+ return 0;
+
+ if (pipe->pipe_ndx == id) /* same req, recycle */
+ return 0;
+
+ return -EPERM;
+}
+
+static int mdp4_overlay_req2pipe(struct mdp_overlay *req, int mixer,
+ struct mdp4_overlay_pipe **ppipe)
+{
+ struct mdp4_overlay_pipe *pipe;
+ int ret, ptype;
+
+ if (mixer >= MDP4_MAX_MIXER) {
+ printk(KERN_ERR "mpd_overlay_req2pipe: mixer out of range!\n");
+ return -ERANGE;
+ }
+
+ if (req->z_order < 0 || req->z_order > 2) {
+ printk(KERN_ERR "mpd_overlay_req2pipe: z_order=%d out of range!\n",
+ req->z_order);
+ return -ERANGE;
+ }
+
+ if (req->src_rect.h == 0 || req->src_rect.w == 0) {
+ printk(KERN_ERR "mpd_overlay_req2pipe: src img of zero size!\n");
+ return -EINVAL;
+ }
+
+ ret = mdp4_overlay_req_check(req->id, req->z_order, mixer);
+ if (ret < 0)
+ return ret;
+
+ ptype = mdp4_overlay_format2type(req->src.format);
+ if (ptype < 0)
+ return ptype;
+
+ if (req->id == MSMFB_NEW_REQUEST) /* new request */
+ pipe = mdp4_overlay_pipe_alloc();
+ else
+ pipe = mdp4_overlay_ndx2pipe(req->id);
+
+ if (pipe == NULL)
+ return -ENOMEM;
+
+ pipe->src_format = req->src.format;
+ ret = mdp4_overlay_format2pipe(pipe);
+
+ if (ret < 0)
+ return ret;
+
+ /*
+ * base layer == 1, reserved for frame buffer
+ * zorder 0 == stage 0 == 2
+ * zorder 1 == stage 1 == 3
+ * zorder 2 == stage 2 == 4
+ */
+ if (req->id == MSMFB_NEW_REQUEST) { /* new request */
+ pipe->mixer_stage = req->z_order + MDP4_MIXER_STAGE0;
+ pipe->pipe_type = ptype;
+ pipe->pipe_num = get_pipe_num(ptype, pipe->mixer_stage);
+ printk(KERN_INFO "mpd4_overlay_req2pipe: zorder=%d pipe_num=%d\n",
+ req->z_order, pipe->pipe_num);
+ }
+
+ pipe->src_width = req->src.width & 0x07ff; /* source img width */
+ pipe->src_height = req->src.height & 0x07ff; /* source img height */
+ pipe->src_h = req->src_rect.h & 0x07ff;
+ pipe->src_w = req->src_rect.w & 0x07ff;
+ pipe->src_y = req->src_rect.y & 0x07ff;
+ pipe->src_x = req->src_rect.x & 0x07ff;
+ pipe->dst_h = req->dst_rect.h & 0x07ff;
+ pipe->dst_w = req->dst_rect.w & 0x07ff;
+ pipe->dst_y = req->dst_rect.y & 0x07ff;
+ pipe->dst_x = req->dst_rect.x & 0x07ff;
+
+ if (req->flags & MDP_FLIP_LR)
+ pipe->op_mode |= MDP4_OP_FLIP_LR;
+
+ if (req->flags & MDP_FLIP_UD)
+ pipe->op_mode |= MDP4_OP_FLIP_UD;
+
+ if (req->flags & MDP_DITHER)
+ pipe->op_mode |= MDP4_OP_DITHER_EN;
+
+ if (req->flags & MDP_DEINTERLACE)
+ pipe->op_mode |= MDP4_OP_DEINT_ODD_REF;
+
+ pipe->is_fg = req->is_fg;/* control alpha and color key */
+
+ pipe->alpha = req->alpha & 0x0ff;
+
+ pipe->transp = req->transp_mask;
+
+ *ppipe = pipe;
+
+ return 0;
+}
+
+int get_img(struct msmfb_data *img, struct fb_info *info,
+ unsigned long *start, unsigned long *len, struct file **pp_file)
+{
+ int put_needed, ret = 0;
+ struct file *file;
+#ifdef CONFIG_ANDROID_PMEM
+ unsigned long vstart;
+#endif
+
+#ifdef CONFIG_ANDROID_PMEM
+ if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file))
+ return 0;
+#endif
+ file = fget_light(img->memory_id, &put_needed);
+ if (file == NULL)
+ return -1;
+
+ if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ *start = info->fix.smem_start;
+ *len = info->fix.smem_len;
+ *pp_file = file;
+ } else {
+ ret = -1;
+ fput_light(file, put_needed);
+ }
+ return ret;
+}
+int mdp4_overlay_get(struct fb_info *info, struct mdp_overlay *req)
+{
+ struct mdp4_overlay_pipe *pipe;
+
+ pipe = mdp4_overlay_ndx2pipe(req->id);
+ if (pipe == NULL)
+ return -ENODEV;
+
+ *req = pipe->req_data;
+
+ return 0;
+}
+
+int mdp4_overlay_set(struct fb_info *info, struct mdp_overlay *req)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int ret, mixer;
+ struct mdp4_overlay_pipe *pipe;
+ int lcdc;
+
+ if (mfd == NULL)
+ return -ENODEV;
+
+ if (req->src.format == MDP_FB_FORMAT)
+ req->src.format = mfd->fb_imgType;
+
+ if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
+ return -EINTR;
+
+ mixer = info->node; /* minor number of char device */
+
+ ret = mdp4_overlay_req2pipe(req, mixer, &pipe);
+ if (ret < 0) {
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return ret;
+ }
+
+ lcdc = inpdw(MDP_BASE + 0xc0000);
+
+ if (lcdc == 0) { /* mddi */
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ }
+
+ /* return id back to user */
+ req->id = pipe->pipe_ndx; /* pipe_ndx start from 1 */
+ pipe->req_data = *req; /* keep original req */
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+
+ return 0;
+}
+
+int mdp4_overlay_unset(struct fb_info *info, int ndx)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct mdp4_overlay_pipe *pipe;
+ int lcdc;
+
+ if (mfd == NULL)
+ return -ENODEV;
+
+ if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
+ return -EINTR;
+
+ pipe = mdp4_overlay_ndx2pipe(ndx);
+
+ if (pipe == NULL) {
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return -ENODEV;
+ }
+
+ lcdc = inpdw(MDP_BASE + 0xc0000);
+
+ mdp4_mixer_stage_down(pipe);
+
+ if (lcdc == 0) { /* mddi */
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
+
+ if (lcdc) /* LCDC mode */
+ mdp4_overlay_reg_flush(pipe, 0);
+
+ mdp4_overlay_pipe_free(pipe);
+
+ if (lcdc == 0) { /* mddi */
+ mdp4_mddi_overlay_restore();
+ }
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+
+ return 0;
+}
+
+struct tile_desc {
+ uint32 width; /* tile's width */
+ uint32 height; /* tile's height */
+ uint32 row_tile_w; /* tiles per row's width */
+ uint32 row_tile_h; /* tiles per row's height */
+};
+
+void tile_samsung(struct tile_desc *tp)
+{
+ /*
+ * each row of samsung tile consists of two tiles in height
+ * and two tiles in width which means width should align to
+ * 64 x 2 bytes and height should align to 32 x 2 bytes.
+ * video decoder generate two tiles in width and one tile
+ * in height which ends up height align to 32 X 1 bytes.
+ */
+ tp->width = 64; /* 64 bytes */
+ tp->row_tile_w = 2; /* 2 tiles per row's width */
+ tp->height = 32; /* 32 bytes */
+ tp->row_tile_h = 1; /* 1 tiles per row's height */
+}
+
+uint32 tile_mem_size(struct mdp4_overlay_pipe *pipe, struct tile_desc *tp)
+{
+ uint32 tile_w, tile_h;
+ uint32 row_num_w, row_num_h;
+
+
+ tile_w = tp->width * tp->row_tile_w;
+ tile_h = tp->height * tp->row_tile_h;
+
+ row_num_w = (pipe->src_width + tile_w - 1) / tile_w;
+ row_num_h = (pipe->src_height + tile_h - 1) / tile_h;
+
+ return row_num_w * row_num_h * tile_w * tile_h;
+}
+
+int mdp4_overlay_play(struct fb_info *info, struct msmfb_overlay_data *req,
+ struct file **pp_src_file)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msmfb_data *img;
+ struct mdp4_overlay_pipe *pipe;
+ ulong start, addr;
+ ulong len = 0;
+ struct file *p_src_file = 0;
+ int lcdc;
+
+ if (mfd == NULL)
+ return -ENODEV;
+
+ pipe = mdp4_overlay_ndx2pipe(req->id);
+ if (pipe == NULL)
+ return -ENODEV;
+
+ if (mutex_lock_interruptible(&mfd->dma->ov_mutex))
+ return -EINTR;
+
+ img = &req->data;
+ get_img(img, info, &start, &len, &p_src_file);
+ if (len == 0) {
+ mutex_unlock(&mfd->dma->ov_mutex);
+ printk(KERN_ERR "mdp_overlay_play: could not retrieve"
+ " image from memory\n");
+ return -1;
+ }
+ *pp_src_file = p_src_file;
+
+ addr = start + img->offset;
+ pipe->srcp0_addr = addr;
+ pipe->srcp0_ystride = pipe->src_width * pipe->bpp;
+
+ if (pipe->fetch_plane == OVERLAY_PLANE_PSEUDO_PLANAR) {
+ if (pipe->frame_format == MDP4_FRAME_FORMAT_VIDEO_SUPERTILE) {
+ struct tile_desc tile;
+
+ tile_samsung(&tile);
+ pipe->srcp1_addr = addr + tile_mem_size(pipe, &tile);
+ } else
+ pipe->srcp1_addr = addr +
+ pipe->src_width * pipe->src_height;
+
+ pipe->srcp0_ystride = pipe->src_width;
+ pipe->srcp1_ystride = pipe->src_width;
+ }
+
+ lcdc = inpdw(MDP_BASE + 0xc0000);
+ lcdc &= 0x01; /* LCDC mode */
+
+ if (pipe->pipe_type == OVERLAY_TYPE_VG)
+ mdp4_overlay_vg_setup(pipe); /* video/graphic pipe */
+ else
+ mdp4_overlay_rgb_setup(pipe); /* rgb pipe */
+
+ mdp4_mixer_blend_setup(pipe);
+ mdp4_mixer_stage_up(pipe);
+
+ if (lcdc) { /* LCDC mode */
+ mdp4_overlay_reg_flush(pipe, 1);
+ }
+
+ if (lcdc) { /* LCDC mode */
+ if (pipe->mixer_stage != MDP4_MIXER_STAGE_BASE) { /* done */
+ mutex_unlock(&mfd->dma->ov_mutex);
+ return 0;
+ }
+ }
+
+ if (lcdc == 0) { /* MDDI mode */
+#ifdef MDP4_NONBLOCKING
+ if (mfd->panel_power_on)
+#else
+ if (!mfd->dma->busy && mfd->panel_power_on)
+#endif
+ mdp4_mddi_overlay_kickoff(mfd, pipe);
+ }
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+
+ return 0;
+}
diff --git a/drivers/staging/msm/mdp4_overlay_lcdc.c b/drivers/staging/msm/mdp4_overlay_lcdc.c
new file mode 100644
index 000000000000..a6ab8ec83f55
--- /dev/null
+++ b/drivers/staging/msm/mdp4_overlay_lcdc.c
@@ -0,0 +1,313 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+#ifdef CONFIG_FB_MSM_MDP40
+#define LCDC_BASE 0xC0000
+#else
+#define LCDC_BASE 0xE0000
+#endif
+
+int first_pixel_start_x;
+int first_pixel_start_y;
+
+static struct mdp4_overlay_pipe *lcdc_pipe;
+
+int mdp_lcdc_on(struct platform_device *pdev)
+{
+ int lcdc_width;
+ int lcdc_height;
+ int lcdc_bpp;
+ int lcdc_border_clr;
+ int lcdc_underflow_clr;
+ int lcdc_hsync_skew;
+
+ int hsync_period;
+ int hsync_ctrl;
+ int vsync_period;
+ int display_hctl;
+ int display_v_start;
+ int display_v_end;
+ int active_hctl;
+ int active_h_start;
+ int active_h_end;
+ int active_v_start;
+ int active_v_end;
+ int ctrl_polarity;
+ int h_back_porch;
+ int h_front_porch;
+ int v_back_porch;
+ int v_front_porch;
+ int hsync_pulse_width;
+ int vsync_pulse_width;
+ int hsync_polarity;
+ int vsync_polarity;
+ int data_en_polarity;
+ int hsync_start_x;
+ int hsync_end_x;
+ uint8 *buf;
+ int bpp, ptype;
+ uint32 format;
+ struct fb_info *fbi;
+ struct fb_var_screeninfo *var;
+ struct msm_fb_data_type *mfd;
+ struct mdp4_overlay_pipe *pipe;
+ int ret;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ fbi = mfd->fbi;
+ var = &fbi->var;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+
+ if (bpp == 2)
+ format = MDP_RGB_565;
+ else if (bpp == 3)
+ format = MDP_RGB_888;
+ else
+ format = MDP_ARGB_8888;
+
+
+ if (lcdc_pipe == NULL) {
+ ptype = mdp4_overlay_format2type(format);
+ pipe = mdp4_overlay_pipe_alloc();
+ pipe->pipe_type = ptype;
+ /* use RGB1 pipe */
+ pipe->pipe_num = OVERLAY_PIPE_RGB1;
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+ pipe->mixer_num = MDP4_MIXER0;
+ pipe->src_format = format;
+ mdp4_overlay_format2pipe(pipe);
+
+ lcdc_pipe = pipe; /* keep it */
+ } else {
+ pipe = lcdc_pipe;
+ }
+
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->srcp0_addr = (uint32) buf;
+ pipe->srcp0_ystride = fbi->fix.line_length;
+
+ mdp4_overlay_dmap_xy(pipe);
+ mdp4_overlay_dmap_cfg(mfd, 1);
+
+ mdp4_overlay_rgb_setup(pipe);
+
+ mdp4_mixer_stage_up(pipe);
+
+ mdp4_overlayproc_cfg(pipe);
+
+ /*
+ * LCDC timing setting
+ */
+ h_back_porch = var->left_margin;
+ h_front_porch = var->right_margin;
+ v_back_porch = var->upper_margin;
+ v_front_porch = var->lower_margin;
+ hsync_pulse_width = var->hsync_len;
+ vsync_pulse_width = var->vsync_len;
+ lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
+ lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
+ lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
+
+ lcdc_width = mfd->panel_info.xres;
+ lcdc_height = mfd->panel_info.yres;
+ lcdc_bpp = mfd->panel_info.bpp;
+
+ hsync_period =
+ hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
+ hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
+ hsync_start_x = hsync_pulse_width + h_back_porch;
+ hsync_end_x = hsync_period - h_front_porch - 1;
+ display_hctl = (hsync_end_x << 16) | hsync_start_x;
+
+ vsync_period =
+ (vsync_pulse_width + v_back_porch + lcdc_height +
+ v_front_porch) * hsync_period;
+ display_v_start =
+ (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
+ display_v_end =
+ vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
+
+ if (lcdc_width != var->xres) {
+ active_h_start = hsync_start_x + first_pixel_start_x;
+ active_h_end = active_h_start + var->xres - 1;
+ active_hctl =
+ ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
+ } else {
+ active_hctl = 0;
+ }
+
+ if (lcdc_height != var->yres) {
+ active_v_start =
+ display_v_start + first_pixel_start_y * hsync_period;
+ active_v_end = active_v_start + (var->yres) * hsync_period - 1;
+ active_v_start |= ACTIVE_START_Y_EN;
+ } else {
+ active_v_start = 0;
+ active_v_end = 0;
+ }
+
+
+#ifdef CONFIG_FB_MSM_MDP40
+ hsync_polarity = 1;
+ vsync_polarity = 1;
+ lcdc_underflow_clr |= 0x80000000; /* enable recovery */
+#else
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+#endif
+ data_en_polarity = 0;
+
+ ctrl_polarity =
+ (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
+
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x4, hsync_ctrl);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x8, vsync_period);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0xc, vsync_pulse_width * hsync_period);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x10, display_hctl);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x14, display_v_start);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x18, display_v_end);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x28, lcdc_border_clr);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x2c, lcdc_underflow_clr);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x30, lcdc_hsync_skew);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x38, ctrl_polarity);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x1c, active_hctl);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x20, active_v_start);
+ MDP_OUTP(MDP_BASE + LCDC_BASE + 0x24, active_v_end);
+
+ ret = panel_next_on(pdev);
+ if (ret == 0) {
+ /* enable LCDC block */
+ MDP_OUTP(MDP_BASE + LCDC_BASE, 1);
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ }
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ return ret;
+}
+
+int mdp_lcdc_off(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct mdp4_overlay_pipe *pipe;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ MDP_OUTP(MDP_BASE + LCDC_BASE, 0);
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ ret = panel_next_off(pdev);
+
+ /* delay to make sure the last frame finishes */
+ mdelay(100);
+
+ /* dis-engage rgb0 from mixer */
+ pipe = lcdc_pipe;
+ mdp4_mixer_stage_down(pipe);
+
+ return ret;
+}
+
+/*
+ * mdp4_overlay0_done_lcdc: called from isr
+ */
+void mdp4_overlay0_done_lcdc()
+{
+ complete(&lcdc_pipe->comp);
+}
+
+void mdp4_lcdc_overlay(struct msm_fb_data_type *mfd)
+{
+ struct fb_info *fbi = mfd->fbi;
+ uint8 *buf;
+ int bpp;
+ unsigned long flag;
+ struct mdp4_overlay_pipe *pipe;
+
+ if (!mfd->panel_power_on)
+ return;
+
+ /* no need to power on cmd block since it's lcdc mode */
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+
+ mutex_lock(&mfd->dma->ov_mutex);
+
+ pipe = lcdc_pipe;
+ pipe->srcp0_addr = (uint32) buf;
+ mdp4_overlay_rgb_setup(pipe);
+ mdp4_overlay_reg_flush(pipe, 1); /* rgb1 and mixer0 */
+
+ /* enable irq */
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ INIT_COMPLETION(lcdc_pipe->comp);
+ mfd->dma->waiting = TRUE;
+ outp32(MDP_INTR_CLEAR, INTR_OVERLAY0_DONE);
+ mdp_intr_mask |= INTR_OVERLAY0_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+ wait_for_completion_killable(&lcdc_pipe->comp);
+ mdp_disable_irq(MDP_OVERLAY0_TERM);
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+}
diff --git a/drivers/staging/msm/mdp4_overlay_mddi.c b/drivers/staging/msm/mdp4_overlay_mddi.c
new file mode 100644
index 000000000000..be1b2874185b
--- /dev/null
+++ b/drivers/staging/msm/mdp4_overlay_mddi.c
@@ -0,0 +1,254 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+static struct mdp4_overlay_pipe *mddi_pipe;
+static struct mdp4_overlay_pipe *pending_pipe;
+static struct msm_fb_data_type *mddi_mfd;
+
+#define WHOLESCREEN
+
+void mdp4_overlay_update_lcd(struct msm_fb_data_type *mfd)
+{
+ MDPIBUF *iBuf = &mfd->ibuf;
+ uint8 *src;
+ int bpp, ptype;
+ uint32 format;
+ uint32 mddi_ld_param;
+ uint16 mddi_vdo_packet_reg;
+ struct mdp4_overlay_pipe *pipe;
+
+ if (mfd->key != MFD_KEY)
+ return;
+
+ mddi_mfd = mfd; /* keep it */
+
+ bpp = iBuf->bpp;
+
+ if (bpp == 2)
+ format = MDP_RGB_565;
+ else if (bpp == 3)
+ format = MDP_RGB_888;
+ else
+ format = MDP_ARGB_8888;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ if (mddi_pipe == NULL) {
+ ptype = mdp4_overlay_format2type(format);
+ pipe = mdp4_overlay_pipe_alloc();
+ pipe->pipe_type = ptype;
+ /* use RGB1 pipe */
+ pipe->pipe_num = OVERLAY_PIPE_RGB1;
+ pipe->mixer_num = MDP4_MIXER0;
+ pipe->src_format = format;
+ mdp4_overlay_format2pipe(pipe);
+
+ mddi_pipe = pipe; /* keep it */
+
+ mddi_ld_param = 0;
+ mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
+
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ if (mfd->panel_info.pdest == DISPLAY_1)
+ mddi_ld_param = 0;
+ else
+ mddi_ld_param = 1;
+ } else {
+ mddi_ld_param = 2;
+ }
+
+ MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
+ } else {
+ pipe = mddi_pipe;
+ }
+
+
+ src = (uint8 *) iBuf->buf;
+
+#ifdef WHOLESCREEN
+ {
+ struct fb_info *fbi;
+
+ fbi = mfd->fbi;
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
+ pipe->dst_y = 0;
+ pipe->dst_x = 0;
+ pipe->srcp0_addr = (uint32)src;
+ pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
+ }
+
+#else
+ if (mdp4_overlay_active(MDP4_MIXER0)) {
+ struct fb_info *fbi;
+
+ fbi = mfd->fbi;
+ pipe->src_height = fbi->var.yres;
+ pipe->src_width = fbi->var.xres;
+ pipe->src_h = fbi->var.yres;
+ pipe->src_w = fbi->var.xres;
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->dst_h = fbi->var.yres;
+ pipe->dst_w = fbi->var.xres;
+ pipe->dst_y = 0;
+ pipe->dst_x = 0;
+ pipe->srcp0_addr = (uint32) src;
+ pipe->srcp0_ystride = fbi->var.xres_virtual * bpp;
+ } else {
+ /* starting input address */
+ src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * bpp;
+
+ pipe->src_height = iBuf->dma_h;
+ pipe->src_width = iBuf->dma_w;
+ pipe->src_h = iBuf->dma_h;
+ pipe->src_w = iBuf->dma_w;
+ pipe->src_y = 0;
+ pipe->src_x = 0;
+ pipe->dst_h = iBuf->dma_h;
+ pipe->dst_w = iBuf->dma_w;
+ pipe->dst_y = iBuf->dma_y;
+ pipe->dst_x = iBuf->dma_x;
+ pipe->srcp0_addr = (uint32) src;
+ pipe->srcp0_ystride = iBuf->ibuf_width * bpp;
+ }
+#endif
+
+ pipe->mixer_stage = MDP4_MIXER_STAGE_BASE;
+
+ mdp4_overlay_rgb_setup(pipe);
+
+ mdp4_mixer_stage_up(pipe);
+
+ mdp4_overlayproc_cfg(pipe);
+
+ mdp4_overlay_dmap_xy(pipe);
+
+ mdp4_overlay_dmap_cfg(mfd, 0);
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+}
+
+/*
+ * mdp4_overlay0_done_mddi: called from isr
+ */
+void mdp4_overlay0_done_mddi()
+{
+ if (pending_pipe)
+ complete(&pending_pipe->comp);
+}
+
+void mdp4_mddi_overlay_restore(void)
+{
+ /* mutex holded by caller */
+ mdp4_overlay_update_lcd(mddi_mfd);
+ mdp4_mddi_overlay_kickoff(mddi_mfd, mddi_pipe);
+}
+
+void mdp4_mddi_overlay_kickoff(struct msm_fb_data_type *mfd,
+ struct mdp4_overlay_pipe *pipe)
+{
+#ifdef MDP4_NONBLOCKING
+ unsigned long flag;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ if (mfd->dma->busy == TRUE) {
+ INIT_COMPLETION(pipe->comp);
+ pending_pipe = pipe;
+ }
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (pending_pipe != NULL) {
+ /* wait until DMA finishes the current job */
+ wait_for_completion_killable(&pipe->comp);
+ pending_pipe = NULL;
+ }
+ down(&mfd->sem);
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ mfd->dma->busy = TRUE;
+ /* start OVERLAY pipe */
+ mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
+ up(&mfd->sem);
+#else
+ down(&mfd->sem);
+ mdp_enable_irq(MDP_OVERLAY0_TERM);
+ mfd->dma->busy = TRUE;
+ INIT_COMPLETION(pipe->comp);
+ pending_pipe = pipe;
+
+ /* start OVERLAY pipe */
+ mdp_pipe_kickoff(MDP_OVERLAY0_TERM, mfd);
+ up(&mfd->sem);
+
+ /* wait until DMA finishes the current job */
+ wait_for_completion_killable(&pipe->comp);
+ mdp_disable_irq(MDP_OVERLAY0_TERM);
+#endif
+
+}
+
+void mdp4_mddi_overlay(struct msm_fb_data_type *mfd)
+{
+ mutex_lock(&mfd->dma->ov_mutex);
+
+ if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+ mdp4_overlay_update_lcd(mfd);
+
+ mdp4_mddi_overlay_kickoff(mfd, mddi_pipe);
+
+ /* signal if pan function is waiting for the update completion */
+ if (mfd->pan_waiting) {
+ mfd->pan_waiting = FALSE;
+ complete(&mfd->pan_comp);
+ }
+ }
+
+ mutex_unlock(&mfd->dma->ov_mutex);
+}
diff --git a/drivers/staging/msm/mdp4_util.c b/drivers/staging/msm/mdp4_util.c
new file mode 100644
index 000000000000..fd97f5205992
--- /dev/null
+++ b/drivers/staging/msm/mdp4_util.c
@@ -0,0 +1,1686 @@
+
+/* Copyright (c) 2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/clk.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <linux/debugfs.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+void mdp4_sw_reset(ulong bits)
+{
+ bits &= 0x1f; /* 5 bits */
+ outpdw(MDP_BASE + 0x001c, bits); /* MDP_SW_RESET */
+
+ while (inpdw(MDP_BASE + 0x001c) & bits) /* self clear when complete */
+ ;
+ MSM_FB_INFO("mdp4_sw_reset: 0x%x\n", (int)bits);
+}
+
+void mdp4_overlay_cfg(int overlayer, int blt_mode, int refresh, int direct_out)
+{
+ ulong bits = 0;
+
+ if (blt_mode)
+ bits |= (1 << 3);
+ refresh &= 0x03; /* 2 bites */
+ bits |= (refresh << 1);
+ direct_out &= 0x01;
+ bits |= direct_out;
+
+ if (overlayer == MDP4_MIXER0)
+ outpdw(MDP_BASE + 0x10004, bits); /* MDP_OVERLAY0_CFG */
+ else
+ outpdw(MDP_BASE + 0x18004, bits); /* MDP_OVERLAY1_CFG */
+
+ MSM_FB_INFO("mdp4_overlay_cfg: 0x%x\n", (int)inpdw(MDP_BASE + 0x10004));
+}
+
+void mdp4_display_intf_sel(int output, ulong intf)
+{
+ ulong bits, mask;
+
+ bits = inpdw(MDP_BASE + 0x0038); /* MDP_DISP_INTF_SEL */
+
+ mask = 0x03; /* 2 bits */
+ intf &= 0x03; /* 2 bits */
+
+ switch (output) {
+ case EXTERNAL_INTF_SEL:
+ intf <<= 4;
+ mask <<= 4;
+ break;
+ case SECONDARY_INTF_SEL:
+ intf &= 0x02; /* only MDDI and EBI2 support */
+ intf <<= 2;
+ mask <<= 2;
+ break;
+ default:
+ break;
+ }
+
+
+ bits &= ~mask;
+ bits |= intf;
+
+ outpdw(MDP_BASE + 0x0038, bits); /* MDP_DISP_INTF_SEL */
+
+ MSM_FB_INFO("mdp4_display_intf_sel: 0x%x\n", (int)inpdw(MDP_BASE + 0x0038));
+}
+
+unsigned long mdp4_display_status(void)
+{
+ return inpdw(MDP_BASE + 0x0018) & 0x3ff; /* MDP_DISPLAY_STATUS */
+}
+
+void mdp4_ebi2_lcd_setup(int lcd, ulong base, int ystride)
+{
+ /* always use memory map */
+ ystride &= 0x01fff; /* 13 bits */
+ if (lcd == EBI2_LCD0) {
+ outpdw(MDP_BASE + 0x0060, base);/* MDP_EBI2_LCD0 */
+ outpdw(MDP_BASE + 0x0068, ystride);/* MDP_EBI2_LCD0_YSTRIDE */
+ } else {
+ outpdw(MDP_BASE + 0x0064, base);/* MDP_EBI2_LCD1 */
+ outpdw(MDP_BASE + 0x006c, ystride);/* MDP_EBI2_LCD1_YSTRIDE */
+ }
+}
+
+void mdp4_mddi_setup(int mddi, unsigned long id)
+{
+ ulong bits;
+
+ if (mddi == MDDI_EXTERNAL_SET)
+ bits = 0x02;
+ else if (mddi == MDDI_SECONDARY_SET)
+ bits = 0x01;
+ else
+ bits = 0; /* PRIMARY_SET */
+
+ id <<= 16;
+
+ bits |= id;
+
+ outpdw(MDP_BASE + 0x0090, bits); /* MDP_MDDI_PARAM_WR_SEL */
+}
+
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
+ struct file **pp_src_file, struct file **pp_dst_file)
+{
+
+ /* not implemented yet */
+ return -1;
+}
+
+void mdp4_hw_init(void)
+{
+ ulong bits;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+#ifdef MDP4_ERROR
+ /*
+ * Issue software reset on DMA_P will casue DMA_P dma engine stall
+ * on LCDC mode. However DMA_P does not stall at MDDI mode.
+ * This need further investigation.
+ */
+ mdp4_sw_reset(0x17);
+#endif
+
+ mdp4_clear_lcdc();
+
+ mdp4_mixer_blend_init(0);
+ mdp4_mixer_blend_init(1);
+ mdp4_vg_qseed_init(0);
+ mdp4_vg_qseed_init(1);
+ mdp4_vg_csc_mv_setup(0);
+ mdp4_vg_csc_mv_setup(1);
+ mdp4_vg_csc_pre_bv_setup(0);
+ mdp4_vg_csc_pre_bv_setup(1);
+ mdp4_vg_csc_post_bv_setup(0);
+ mdp4_vg_csc_post_bv_setup(1);
+ mdp4_vg_csc_pre_lv_setup(0);
+ mdp4_vg_csc_pre_lv_setup(1);
+ mdp4_vg_csc_post_lv_setup(0);
+ mdp4_vg_csc_post_lv_setup(1);
+
+ mdp4_mixer_gc_lut_setup(0);
+ mdp4_mixer_gc_lut_setup(1);
+
+ mdp4_vg_igc_lut_setup(0);
+ mdp4_vg_igc_lut_setup(1);
+
+ mdp4_rgb_igc_lut_setup(0);
+ mdp4_rgb_igc_lut_setup(1);
+
+ outp32(MDP_EBI2_PORTMAP_MODE, 0x3);
+
+ /* system interrupts */
+
+ bits = mdp_intr_mask;
+ outpdw(MDP_BASE + 0x0050, bits);/* enable specififed interrupts */
+
+ /* histogram */
+ MDP_OUTP(MDP_BASE + 0x95010, 1); /* auto clear HIST */
+
+ /* enable histogram interrupts */
+ outpdw(MDP_BASE + 0x9501c, INTR_HIST_DONE);
+
+ /* For the max read pending cmd config below, if the MDP clock */
+ /* is less than the AXI clock, then we must use 3 pending */
+ /* pending requests. Otherwise, we should use 8 pending requests. */
+ /* In the future we should do this detection automatically. */
+
+ /* max read pending cmd config */
+ outpdw(MDP_BASE + 0x004c, 0x02222); /* 3 pending requests */
+
+ /* dma_p fetch config */
+ outpdw(MDP_BASE + 0x91004, 0x27); /* burst size of 8 */
+
+#ifndef CONFIG_FB_MSM_OVERLAY
+ /* both REFRESH_MODE and DIRECT_OUT are ignored at BLT mode */
+ mdp4_overlay_cfg(MDP4_MIXER0, OVERLAY_MODE_BLT, 0, 0);
+ mdp4_overlay_cfg(MDP4_MIXER1, OVERLAY_MODE_BLT, 0, 0);
+#endif
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+
+void mdp4_clear_lcdc(void)
+{
+ uint32 bits;
+
+ bits = inpdw(MDP_BASE + 0xc0000);
+ if (bits & 0x01) /* enabled already */
+ return;
+
+ outpdw(MDP_BASE + 0xc0004, 0); /* vsync ctrl out */
+ outpdw(MDP_BASE + 0xc0008, 0); /* vsync period */
+ outpdw(MDP_BASE + 0xc000c, 0); /* vsync pusle width */
+ outpdw(MDP_BASE + 0xc0010, 0); /* lcdc display HCTL */
+ outpdw(MDP_BASE + 0xc0014, 0); /* lcdc display v start */
+ outpdw(MDP_BASE + 0xc0018, 0); /* lcdc display v end */
+ outpdw(MDP_BASE + 0xc001c, 0); /* lcdc active hctl */
+ outpdw(MDP_BASE + 0xc0020, 0); /* lcdc active v start */
+ outpdw(MDP_BASE + 0xc0024, 0); /* lcdc active v end */
+ outpdw(MDP_BASE + 0xc0028, 0); /* lcdc board color */
+ outpdw(MDP_BASE + 0xc002c, 0); /* lcdc underflow ctrl */
+ outpdw(MDP_BASE + 0xc0030, 0); /* lcdc hsync skew */
+ outpdw(MDP_BASE + 0xc0034, 0); /* lcdc test ctl */
+ outpdw(MDP_BASE + 0xc0038, 0); /* lcdc ctl polarity */
+}
+
+static struct mdp_dma_data overlay1_data;
+static int intr_dma_p;
+static int intr_dma_s;
+static int intr_dma_e;
+static int intr_overlay0;
+static int intr_overlay1;
+
+irqreturn_t mdp4_isr(int irq, void *ptr)
+{
+ uint32 isr, mask, lcdc;
+ struct mdp_dma_data *dma;
+
+ mdp_is_in_isr = TRUE;
+
+ while (1) {
+ isr = inpdw(MDP_INTR_STATUS);
+ if (isr == 0)
+ break;
+
+ mask = inpdw(MDP_INTR_ENABLE);
+ outpdw(MDP_INTR_CLEAR, isr);
+
+ isr &= mask;
+
+ if (unlikely(isr == 0))
+ break;
+
+ if (isr & INTR_DMA_P_DONE) {
+ intr_dma_p++;
+ lcdc = inpdw(MDP_BASE + 0xc0000);
+ dma = &dma2_data;
+ if (lcdc & 0x01) { /* LCDC enable */
+ /* disable LCDC interrupt */
+ mdp_intr_mask &= ~INTR_DMA_P_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ dma->waiting = FALSE;
+ } else {
+ dma->busy = FALSE;
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ }
+ complete(&dma->comp);
+ }
+ if (isr & INTR_DMA_S_DONE) {
+ intr_dma_s++;
+ dma = &dma_s_data;
+ dma->busy = FALSE;
+ mdp_pipe_ctrl(MDP_DMA_S_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ complete(&dma->comp);
+ }
+ if (isr & INTR_DMA_E_DONE) {
+ intr_dma_e++;
+ dma = &dma_e_data;
+ mdp_intr_mask &= ~INTR_DMA_E_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ dma->busy = FALSE;
+
+ if (dma->waiting) {
+ dma->waiting = FALSE;
+ complete(&dma->comp);
+ }
+ }
+ if (isr & INTR_OVERLAY0_DONE) {
+ intr_overlay0++;
+ lcdc = inpdw(MDP_BASE + 0xc0000);
+ dma = &dma2_data;
+ if (lcdc & 0x01) { /* LCDC enable */
+ /* disable LCDC interrupt */
+ mdp_intr_mask &= ~INTR_OVERLAY0_DONE;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ dma->waiting = FALSE;
+ mdp4_overlay0_done_lcdc();
+ } else { /* MDDI */
+ dma->busy = FALSE;
+#ifdef MDP4_NONBLOCKING
+ mdp_disable_irq_nolock(MDP_OVERLAY0_TERM);
+#endif
+ mdp_pipe_ctrl(MDP_OVERLAY0_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ mdp4_overlay0_done_mddi();
+ }
+ }
+ if (isr & INTR_OVERLAY1_DONE) {
+ intr_overlay1++;
+ dma = &overlay1_data;
+ dma->busy = FALSE;
+ mdp_pipe_ctrl(MDP_OVERLAY1_BLOCK,
+ MDP_BLOCK_POWER_OFF, TRUE);
+ complete(&dma->comp);
+ }
+ if (isr & INTR_DMA_P_HISTOGRAM) {
+ isr = inpdw(MDP_DMA_P_HIST_INTR_STATUS);
+ mask = inpdw(MDP_DMA_P_HIST_INTR_ENABLE);
+ outpdw(MDP_DMA_P_HIST_INTR_CLEAR, isr);
+ isr &= mask;
+ if (isr & INTR_HIST_DONE) {
+ if (mdp_hist.r)
+ memcpy(mdp_hist.r, MDP_BASE + 0x95100,
+ mdp_hist.bin_cnt*4);
+ if (mdp_hist.g)
+ memcpy(mdp_hist.g, MDP_BASE + 0x95200,
+ mdp_hist.bin_cnt*4);
+ if (mdp_hist.b)
+ memcpy(mdp_hist.b, MDP_BASE + 0x95300,
+ mdp_hist.bin_cnt*4);
+ complete(&mdp_hist_comp);
+ }
+ }
+ }
+
+ mdp_is_in_isr = FALSE;
+
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * QSEED tables
+ */
+
+static uint32 vg_qseed_table0[] = {
+ 0x5556aaff, 0x00000000, 0x00000000, 0x00000000
+};
+
+static uint32 vg_qseed_table1[] = {
+ 0x76543210, 0xfedcba98
+};
+
+static uint32 vg_qseed_table2[] = {
+ 0x02000000, 0x00000000, 0x02060ff2, 0x00000008,
+ 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021,
+ 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042,
+ 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068,
+ 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095,
+ 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6,
+ 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa,
+ 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d,
+ 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f,
+ 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f,
+ 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7,
+ 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc,
+ 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5,
+ 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203,
+ 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a,
+ 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206,
+ 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a,
+ 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029,
+ 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050,
+ 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c,
+ 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae,
+ 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2,
+ 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117,
+ 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148,
+ 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177,
+ 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2,
+ 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4,
+ 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2,
+ 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6,
+ 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203,
+ 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208,
+ 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205,
+ 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c,
+ 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030,
+ 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d,
+ 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e,
+ 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4,
+ 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9,
+ 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e,
+ 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d,
+ 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188,
+ 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae,
+ 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc,
+ 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7,
+ 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8,
+ 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202,
+ 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206,
+ 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204,
+ 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f,
+ 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e,
+ 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075,
+ 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad,
+ 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7,
+ 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e,
+ 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150,
+ 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b,
+ 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1,
+ 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0,
+ 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8,
+ 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed,
+ 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa,
+ 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202,
+ 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205,
+ 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203,
+ 0x02000000, 0x00000000, 0x02050ff5, 0x00000006,
+ 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a,
+ 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034,
+ 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054,
+ 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079,
+ 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3,
+ 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1,
+ 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101,
+ 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132,
+ 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163,
+ 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f,
+ 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba,
+ 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc,
+ 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3,
+ 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201,
+ 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204,
+ 0x02000000, 0x00000000, 0x02030ff5, 0x00000008,
+ 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020,
+ 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040,
+ 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065,
+ 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f,
+ 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd,
+ 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee,
+ 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d,
+ 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d,
+ 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b,
+ 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2,
+ 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6,
+ 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3,
+ 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6,
+ 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202,
+ 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203,
+ 0x02000000, 0x00000000, 0x02020ff5, 0x00000009,
+ 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026,
+ 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b,
+ 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074,
+ 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3,
+ 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3,
+ 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105,
+ 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135,
+ 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162,
+ 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c,
+ 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af,
+ 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0,
+ 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7,
+ 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7,
+ 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200,
+ 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203,
+ 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c,
+ 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032,
+ 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f,
+ 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090,
+ 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4,
+ 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8,
+ 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129,
+ 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156,
+ 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e,
+ 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3,
+ 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0,
+ 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db,
+ 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed,
+ 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa,
+ 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201,
+ 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202,
+ 0x02000000, 0x00000000, 0x02040ff7, 0x00000005,
+ 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016,
+ 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c,
+ 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046,
+ 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066,
+ 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b,
+ 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4,
+ 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0,
+ 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f,
+ 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140,
+ 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f,
+ 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e,
+ 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6,
+ 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5,
+ 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa,
+ 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202,
+ 0x02000000, 0x00000000, 0x02030ff7, 0x00000006,
+ 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b,
+ 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035,
+ 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055,
+ 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079,
+ 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2,
+ 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf,
+ 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc,
+ 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b,
+ 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a,
+ 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185,
+ 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae,
+ 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1,
+ 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea,
+ 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb,
+ 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202,
+ 0x02000000, 0x00000000, 0x02010ff7, 0x00000008,
+ 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020,
+ 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f,
+ 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062,
+ 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b,
+ 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7,
+ 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6,
+ 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114,
+ 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141,
+ 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d,
+ 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196,
+ 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb,
+ 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8,
+ 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed,
+ 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb,
+ 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201,
+ 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a,
+ 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a,
+ 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051,
+ 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b,
+ 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa,
+ 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da,
+ 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a,
+ 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138,
+ 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162,
+ 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b,
+ 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab,
+ 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9,
+ 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1,
+ 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2,
+ 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd,
+ 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201,
+ 0x02000000, 0x00000000, 0x02030ff9, 0x00000004,
+ 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010,
+ 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020,
+ 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034,
+ 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d,
+ 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a,
+ 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c,
+ 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2,
+ 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd,
+ 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c,
+ 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b,
+ 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170,
+ 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0,
+ 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8,
+ 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea,
+ 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe,
+ 0x02000000, 0x00000000, 0x02020ff9, 0x00000005,
+ 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014,
+ 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028,
+ 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040,
+ 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d,
+ 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f,
+ 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4,
+ 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd,
+ 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9,
+ 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128,
+ 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155,
+ 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185,
+ 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0,
+ 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3,
+ 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef,
+ 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff,
+ 0x02000000, 0x00000000, 0x02010ff9, 0x00000006,
+ 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018,
+ 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f,
+ 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b,
+ 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c,
+ 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091,
+ 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9,
+ 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4,
+ 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110,
+ 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f,
+ 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a,
+ 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195,
+ 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb,
+ 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9,
+ 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1,
+ 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff,
+ 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008,
+ 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020,
+ 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e,
+ 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060,
+ 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087,
+ 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1,
+ 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd,
+ 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109,
+ 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135,
+ 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160,
+ 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187,
+ 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac,
+ 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb,
+ 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3,
+ 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5,
+ 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff,
+ 0x02000000, 0x00000000, 0x02060ff2, 0x00000008,
+ 0x02090fe4, 0x00000013, 0x020a0fd9, 0x0ffc0021,
+ 0x02080fce, 0x0ffa0030, 0x02030fc5, 0x0ff60042,
+ 0x01fd0fbe, 0x0ff10054, 0x01f50fb6, 0x0fed0068,
+ 0x01e90fb1, 0x0fe60080, 0x01dc0fae, 0x0fe10095,
+ 0x01ca0fae, 0x0fda00ae, 0x01b70fad, 0x0fd600c6,
+ 0x01a40fad, 0x0fcf00e0, 0x018f0faf, 0x0fc800fa,
+ 0x01780fb1, 0x0fc30114, 0x015f0fb5, 0x0fbf012d,
+ 0x01490fb7, 0x0fb70149, 0x012d0fbf, 0x0fb5015f,
+ 0x01140fc3, 0x0fb10178, 0x00fa0fc8, 0x0faf018f,
+ 0x00e00fcf, 0x0fad01a4, 0x00c60fd6, 0x0fad01b7,
+ 0x00ae0fda, 0x0fae01ca, 0x00950fe1, 0x0fae01dc,
+ 0x00800fe6, 0x0fb101e9, 0x00680fed, 0x0fb601f5,
+ 0x00540ff1, 0x0fbe01fd, 0x00420ff6, 0x0fc50203,
+ 0x00300ffa, 0x0fce0208, 0x00210ffc, 0x0fd9020a,
+ 0x00130000, 0x0fe40209, 0x00080000, 0x0ff20206,
+ 0x02000000, 0x00000000, 0x02040ff2, 0x0000000a,
+ 0x02040fe4, 0x00000018, 0x02010fda, 0x0ffc0029,
+ 0x01fc0fcf, 0x0ffa003b, 0x01f30fc7, 0x0ff60050,
+ 0x01e90fc0, 0x0ff20065, 0x01dc0fba, 0x0fee007c,
+ 0x01cc0fb6, 0x0fe80096, 0x01ba0fb4, 0x0fe400ae,
+ 0x01a70fb4, 0x0fdd00c8, 0x018f0fb5, 0x0fda00e2,
+ 0x017a0fb5, 0x0fd400fd, 0x01630fb8, 0x0fce0117,
+ 0x014c0fba, 0x0fca0130, 0x01320fbf, 0x0fc70148,
+ 0x011b0fc1, 0x0fc10163, 0x01010fc8, 0x0fc00177,
+ 0x00e90fcd, 0x0fbd018d, 0x00d10fd1, 0x0fbc01a2,
+ 0x00ba0fd7, 0x0fbb01b4, 0x00a30fdd, 0x0fbc01c4,
+ 0x008e0fe1, 0x0fbd01d4, 0x00790fe7, 0x0fbe01e2,
+ 0x00670feb, 0x0fc001ee, 0x00540ff1, 0x0fc501f6,
+ 0x00430ff4, 0x0fcb01fe, 0x00340ff8, 0x0fd10203,
+ 0x00260ffb, 0x0fd80207, 0x001a0ffd, 0x0fe10208,
+ 0x000f0000, 0x0fea0207, 0x00060000, 0x0ff50205,
+ 0x02000000, 0x00000000, 0x02020ff2, 0x0000000c,
+ 0x02000fe4, 0x0000001c, 0x01fa0fda, 0x0ffc0030,
+ 0x01f10fd0, 0x0ffa0045, 0x01e50fc8, 0x0ff6005d,
+ 0x01d60fc3, 0x0ff30074, 0x01c60fbd, 0x0fef008e,
+ 0x01b30fba, 0x0fe900aa, 0x019e0fb9, 0x0fe500c4,
+ 0x01870fba, 0x0fe000df, 0x016f0fbb, 0x0fdd00f9,
+ 0x01580fbc, 0x0fd80114, 0x01400fbf, 0x0fd3012e,
+ 0x01280fc2, 0x0fd00146, 0x010f0fc6, 0x0fce015d,
+ 0x00f90fc9, 0x0fc90175, 0x00e00fcf, 0x0fc90188,
+ 0x00ca0fd4, 0x0fc6019c, 0x00b40fd8, 0x0fc601ae,
+ 0x009f0fdd, 0x0fc501bf, 0x008b0fe3, 0x0fc601cc,
+ 0x00780fe6, 0x0fc701db, 0x00660feb, 0x0fc801e7,
+ 0x00560fef, 0x0fcb01f0, 0x00460ff3, 0x0fcf01f8,
+ 0x00380ff6, 0x0fd401fe, 0x002c0ff9, 0x0fd90202,
+ 0x00200ffc, 0x0fdf0205, 0x00160ffe, 0x0fe60206,
+ 0x000c0000, 0x0fed0207, 0x00050000, 0x0ff70204,
+ 0x02000000, 0x00000000, 0x01fe0ff3, 0x0000000f,
+ 0x01f60fe5, 0x00000025, 0x01ea0fdb, 0x0ffd003e,
+ 0x01db0fd2, 0x0ffb0058, 0x01c80fcc, 0x0ff70075,
+ 0x01b50fc7, 0x0ff40090, 0x01a00fc3, 0x0ff000ad,
+ 0x01880fc1, 0x0feb00cc, 0x01700fc1, 0x0fe800e7,
+ 0x01550fc3, 0x0fe40104, 0x013b0fc5, 0x0fe2011e,
+ 0x01240fc6, 0x0fde0138, 0x010c0fca, 0x0fda0150,
+ 0x00f40fcd, 0x0fd90166, 0x00dd0fd1, 0x0fd7017b,
+ 0x00c80fd4, 0x0fd40190, 0x00b20fd9, 0x0fd401a1,
+ 0x009f0fdd, 0x0fd301b1, 0x008c0fe1, 0x0fd301c0,
+ 0x007b0fe5, 0x0fd301cd, 0x006a0fea, 0x0fd401d8,
+ 0x005c0fec, 0x0fd501e3, 0x004d0ff0, 0x0fd601ed,
+ 0x00410ff3, 0x0fd801f4, 0x00340ff7, 0x0fdb01fa,
+ 0x002a0ff9, 0x0fdf01fe, 0x00200ffb, 0x0fe30202,
+ 0x00180ffd, 0x0fe70204, 0x00100ffe, 0x0fed0205,
+ 0x00090000, 0x0ff20205, 0x00040000, 0x0ff90203,
+ 0x02000000, 0x00000000, 0x02050ff5, 0x00000006,
+ 0x02070fea, 0x0000000f, 0x02080fe1, 0x0ffd001a,
+ 0x02070fd8, 0x0ffb0026, 0x02030fd1, 0x0ff80034,
+ 0x01fe0fcb, 0x0ff40043, 0x01f60fc5, 0x0ff10054,
+ 0x01ee0fc0, 0x0feb0067, 0x01e20fbe, 0x0fe70079,
+ 0x01d40fbd, 0x0fe1008e, 0x01c40fbc, 0x0fdd00a3,
+ 0x01b40fbb, 0x0fd700ba, 0x01a20fbc, 0x0fd100d1,
+ 0x018d0fbd, 0x0fcd00e9, 0x01770fc0, 0x0fc80101,
+ 0x01630fc1, 0x0fc1011b, 0x01480fc7, 0x0fbf0132,
+ 0x01300fca, 0x0fba014c, 0x01170fce, 0x0fb80163,
+ 0x00fd0fd4, 0x0fb5017a, 0x00e20fda, 0x0fb5018f,
+ 0x00c80fdd, 0x0fb401a7, 0x00ae0fe4, 0x0fb401ba,
+ 0x00960fe8, 0x0fb601cc, 0x007c0fee, 0x0fba01dc,
+ 0x00650ff2, 0x0fc001e9, 0x00500ff6, 0x0fc701f3,
+ 0x003b0ffa, 0x0fcf01fc, 0x00290ffc, 0x0fda0201,
+ 0x00180000, 0x0fe40204, 0x000a0000, 0x0ff20204,
+ 0x02000000, 0x00000000, 0x02030ff5, 0x00000008,
+ 0x02030fea, 0x00000013, 0x02020fe1, 0x0ffd0020,
+ 0x01fc0fd9, 0x0ffc002f, 0x01f60fd2, 0x0ff80040,
+ 0x01ed0fcd, 0x0ff50051, 0x01e30fc7, 0x0ff10065,
+ 0x01d70fc3, 0x0fec007a, 0x01c60fc2, 0x0fe9008f,
+ 0x01b60fc1, 0x0fe300a6, 0x01a20fc1, 0x0fe000bd,
+ 0x018f0fc1, 0x0fdb00d5, 0x017b0fc2, 0x0fd500ee,
+ 0x01640fc4, 0x0fd20106, 0x014d0fc8, 0x0fce011d,
+ 0x01370fc9, 0x0fc90137, 0x011d0fce, 0x0fc8014d,
+ 0x01060fd2, 0x0fc40164, 0x00ee0fd5, 0x0fc2017b,
+ 0x00d50fdb, 0x0fc1018f, 0x00bd0fe0, 0x0fc101a2,
+ 0x00a60fe3, 0x0fc101b6, 0x008f0fe9, 0x0fc201c6,
+ 0x007a0fec, 0x0fc301d7, 0x00650ff1, 0x0fc701e3,
+ 0x00510ff5, 0x0fcd01ed, 0x00400ff8, 0x0fd201f6,
+ 0x002f0ffc, 0x0fd901fc, 0x00200ffd, 0x0fe10202,
+ 0x00130000, 0x0fea0203, 0x00080000, 0x0ff50203,
+ 0x02000000, 0x00000000, 0x02020ff5, 0x00000009,
+ 0x01ff0fea, 0x00000017, 0x01fb0fe2, 0x0ffd0026,
+ 0x01f30fda, 0x0ffc0037, 0x01ea0fd3, 0x0ff8004b,
+ 0x01df0fce, 0x0ff5005e, 0x01d10fc9, 0x0ff20074,
+ 0x01c10fc6, 0x0fed008c, 0x01ae0fc5, 0x0fea00a3,
+ 0x019b0fc5, 0x0fe500bb, 0x01850fc6, 0x0fe200d3,
+ 0x01700fc6, 0x0fde00ec, 0x015a0fc8, 0x0fd90105,
+ 0x01430fca, 0x0fd6011d, 0x012b0fcd, 0x0fd30135,
+ 0x01150fcf, 0x0fcf014d, 0x00fc0fd4, 0x0fce0162,
+ 0x00e50fd8, 0x0fcc0177, 0x00cf0fdb, 0x0fca018c,
+ 0x00b80fe0, 0x0fc9019f, 0x00a20fe5, 0x0fca01af,
+ 0x008e0fe8, 0x0fcb01bf, 0x00790fec, 0x0fcb01d0,
+ 0x00670fef, 0x0fcd01dd, 0x00550ff4, 0x0fd001e7,
+ 0x00440ff7, 0x0fd501f0, 0x00350ffa, 0x0fda01f7,
+ 0x00270ffc, 0x0fdf01fe, 0x001b0ffe, 0x0fe70200,
+ 0x00100000, 0x0fee0202, 0x00060000, 0x0ff70203,
+ 0x02000000, 0x00000000, 0x01ff0ff5, 0x0000000c,
+ 0x01f80fea, 0x0000001e, 0x01ef0fe2, 0x0ffd0032,
+ 0x01e20fdb, 0x0ffc0047, 0x01d30fd5, 0x0ff9005f,
+ 0x01c20fd1, 0x0ff60077, 0x01b00fcd, 0x0ff30090,
+ 0x019b0fcb, 0x0fef00ab, 0x01850fcb, 0x0fec00c4,
+ 0x016e0fcc, 0x0fe800de, 0x01550fcd, 0x0fe600f8,
+ 0x013f0fce, 0x0fe20111, 0x01280fd0, 0x0fdf0129,
+ 0x01110fd2, 0x0fdd0140, 0x00f90fd6, 0x0fdb0156,
+ 0x00e40fd8, 0x0fd8016c, 0x00cd0fdd, 0x0fd8017e,
+ 0x00b80fe0, 0x0fd60192, 0x00a40fe3, 0x0fd601a3,
+ 0x00910fe7, 0x0fd501b3, 0x007f0feb, 0x0fd601c0,
+ 0x006e0fed, 0x0fd701ce, 0x005d0ff1, 0x0fd701db,
+ 0x004f0ff3, 0x0fd901e5, 0x00400ff7, 0x0fdc01ed,
+ 0x00330ff9, 0x0fe001f4, 0x00280ffb, 0x0fe301fa,
+ 0x001d0ffd, 0x0fe801fe, 0x00140ffe, 0x0fed0201,
+ 0x000c0000, 0x0ff20202, 0x00050000, 0x0ff90202,
+ 0x02000000, 0x00000000, 0x02040ff7, 0x00000005,
+ 0x02070fed, 0x0000000c, 0x02060fe6, 0x0ffe0016,
+ 0x02050fdf, 0x0ffc0020, 0x02020fd9, 0x0ff9002c,
+ 0x01fe0fd4, 0x0ff60038, 0x01f80fcf, 0x0ff30046,
+ 0x01f00fcb, 0x0fef0056, 0x01e70fc8, 0x0feb0066,
+ 0x01db0fc7, 0x0fe60078, 0x01cc0fc6, 0x0fe3008b,
+ 0x01bf0fc5, 0x0fdd009f, 0x01ae0fc6, 0x0fd800b4,
+ 0x019c0fc6, 0x0fd400ca, 0x01880fc9, 0x0fcf00e0,
+ 0x01750fc9, 0x0fc900f9, 0x015d0fce, 0x0fc6010f,
+ 0x01460fd0, 0x0fc20128, 0x012e0fd3, 0x0fbf0140,
+ 0x01140fd8, 0x0fbc0158, 0x00f90fdd, 0x0fbb016f,
+ 0x00df0fe0, 0x0fba0187, 0x00c40fe5, 0x0fb9019e,
+ 0x00aa0fe9, 0x0fba01b3, 0x008e0fef, 0x0fbd01c6,
+ 0x00740ff3, 0x0fc301d6, 0x005d0ff6, 0x0fc801e5,
+ 0x00450ffa, 0x0fd001f1, 0x00300ffc, 0x0fda01fa,
+ 0x001c0000, 0x0fe40200, 0x000c0000, 0x0ff20202,
+ 0x02000000, 0x00000000, 0x02030ff7, 0x00000006,
+ 0x02020fee, 0x00000010, 0x02000fe7, 0x0ffe001b,
+ 0x01fe0fdf, 0x0ffc0027, 0x01f70fda, 0x0ffa0035,
+ 0x01f00fd5, 0x0ff70044, 0x01e70fd0, 0x0ff40055,
+ 0x01dd0fcd, 0x0fef0067, 0x01d00fcb, 0x0fec0079,
+ 0x01bf0fcb, 0x0fe8008e, 0x01af0fca, 0x0fe500a2,
+ 0x019f0fc9, 0x0fe000b8, 0x018c0fca, 0x0fdb00cf,
+ 0x01770fcc, 0x0fd800e5, 0x01620fce, 0x0fd400fc,
+ 0x014d0fcf, 0x0fcf0115, 0x01350fd3, 0x0fcd012b,
+ 0x011d0fd6, 0x0fca0143, 0x01050fd9, 0x0fc8015a,
+ 0x00ec0fde, 0x0fc60170, 0x00d30fe2, 0x0fc60185,
+ 0x00bb0fe5, 0x0fc5019b, 0x00a30fea, 0x0fc501ae,
+ 0x008c0fed, 0x0fc601c1, 0x00740ff2, 0x0fc901d1,
+ 0x005e0ff5, 0x0fce01df, 0x004b0ff8, 0x0fd301ea,
+ 0x00370ffc, 0x0fda01f3, 0x00260ffd, 0x0fe201fb,
+ 0x00170000, 0x0fea01ff, 0x00090000, 0x0ff50202,
+ 0x02000000, 0x00000000, 0x02010ff7, 0x00000008,
+ 0x01ff0fee, 0x00000013, 0x01fb0fe7, 0x0ffe0020,
+ 0x01f60fe0, 0x0ffc002e, 0x01ed0fda, 0x0ffa003f,
+ 0x01e40fd6, 0x0ff7004f, 0x01d80fd2, 0x0ff40062,
+ 0x01ca0fcf, 0x0ff00077, 0x01bb0fcd, 0x0fed008b,
+ 0x01a90fcd, 0x0fe900a1, 0x01960fcd, 0x0fe600b7,
+ 0x01830fcd, 0x0fe200ce, 0x016d0fcf, 0x0fde00e6,
+ 0x01580fd0, 0x0fdb00fd, 0x01410fd3, 0x0fd80114,
+ 0x012c0fd4, 0x0fd4012c, 0x01140fd8, 0x0fd30141,
+ 0x00fd0fdb, 0x0fd00158, 0x00e60fde, 0x0fcf016d,
+ 0x00ce0fe2, 0x0fcd0183, 0x00b70fe6, 0x0fcd0196,
+ 0x00a10fe9, 0x0fcd01a9, 0x008b0fed, 0x0fcd01bb,
+ 0x00770ff0, 0x0fcf01ca, 0x00620ff4, 0x0fd201d8,
+ 0x004f0ff7, 0x0fd601e4, 0x003f0ffa, 0x0fda01ed,
+ 0x002e0ffc, 0x0fe001f6, 0x00200ffe, 0x0fe701fb,
+ 0x00130000, 0x0fee01ff, 0x00080000, 0x0ff70201,
+ 0x02000000, 0x00000000, 0x01ff0ff7, 0x0000000a,
+ 0x01f90fee, 0x00000019, 0x01f10fe7, 0x0ffe002a,
+ 0x01e60fe1, 0x0ffd003c, 0x01d90fdc, 0x0ffa0051,
+ 0x01cc0fd8, 0x0ff70065, 0x01bb0fd5, 0x0ff5007b,
+ 0x01a80fd3, 0x0ff10094, 0x01950fd2, 0x0fef00aa,
+ 0x01800fd2, 0x0feb00c3, 0x016a0fd3, 0x0fe900da,
+ 0x01540fd3, 0x0fe600f3, 0x013f0fd5, 0x0fe2010a,
+ 0x01280fd7, 0x0fe00121, 0x01100fda, 0x0fde0138,
+ 0x00fb0fdb, 0x0fdb014f, 0x00e40fdf, 0x0fdb0162,
+ 0x00ce0fe2, 0x0fd90177, 0x00b90fe4, 0x0fd8018b,
+ 0x00a50fe8, 0x0fd8019b, 0x00910fec, 0x0fd801ab,
+ 0x007e0fee, 0x0fd801bc, 0x006c0ff2, 0x0fd901c9,
+ 0x005c0ff4, 0x0fda01d6, 0x004b0ff7, 0x0fdd01e1,
+ 0x003c0ff9, 0x0fe001eb, 0x002f0ffb, 0x0fe401f2,
+ 0x00230ffd, 0x0fe801f8, 0x00180ffe, 0x0fed01fd,
+ 0x000e0000, 0x0ff20200, 0x00060000, 0x0ff90201,
+ 0x02000000, 0x00000000, 0x02030ff9, 0x00000004,
+ 0x02050ff2, 0x00000009, 0x02050fed, 0x0ffe0010,
+ 0x02040fe7, 0x0ffd0018, 0x02020fe3, 0x0ffb0020,
+ 0x01fe0fdf, 0x0ff9002a, 0x01fa0fdb, 0x0ff70034,
+ 0x01f40fd8, 0x0ff30041, 0x01ed0fd6, 0x0ff0004d,
+ 0x01e30fd5, 0x0fec005c, 0x01d80fd4, 0x0fea006a,
+ 0x01cd0fd3, 0x0fe5007b, 0x01c00fd3, 0x0fe1008c,
+ 0x01b10fd3, 0x0fdd009f, 0x01a10fd4, 0x0fd900b2,
+ 0x01900fd4, 0x0fd400c8, 0x017b0fd7, 0x0fd100dd,
+ 0x01660fd9, 0x0fcd00f4, 0x01500fda, 0x0fca010c,
+ 0x01380fde, 0x0fc60124, 0x011e0fe2, 0x0fc5013b,
+ 0x01040fe4, 0x0fc30155, 0x00e70fe8, 0x0fc10170,
+ 0x00cc0feb, 0x0fc10188, 0x00ad0ff0, 0x0fc301a0,
+ 0x00900ff4, 0x0fc701b5, 0x00750ff7, 0x0fcc01c8,
+ 0x00580ffb, 0x0fd201db, 0x003e0ffd, 0x0fdb01ea,
+ 0x00250000, 0x0fe501f6, 0x000f0000, 0x0ff301fe,
+ 0x02000000, 0x00000000, 0x02020ff9, 0x00000005,
+ 0x02020ff2, 0x0000000c, 0x02010fed, 0x0ffe0014,
+ 0x01fe0fe8, 0x0ffd001d, 0x01fa0fe3, 0x0ffb0028,
+ 0x01f40fe0, 0x0ff90033, 0x01ed0fdc, 0x0ff70040,
+ 0x01e50fd9, 0x0ff3004f, 0x01db0fd7, 0x0ff1005d,
+ 0x01ce0fd7, 0x0fed006e, 0x01c00fd6, 0x0feb007f,
+ 0x01b30fd5, 0x0fe70091, 0x01a30fd6, 0x0fe300a4,
+ 0x01920fd6, 0x0fe000b8, 0x017e0fd8, 0x0fdd00cd,
+ 0x016c0fd8, 0x0fd800e4, 0x01560fdb, 0x0fd600f9,
+ 0x01400fdd, 0x0fd20111, 0x01290fdf, 0x0fd00128,
+ 0x01110fe2, 0x0fce013f, 0x00f80fe6, 0x0fcd0155,
+ 0x00de0fe8, 0x0fcc016e, 0x00c40fec, 0x0fcb0185,
+ 0x00ab0fef, 0x0fcb019b, 0x00900ff3, 0x0fcd01b0,
+ 0x00770ff6, 0x0fd101c2, 0x005f0ff9, 0x0fd501d3,
+ 0x00470ffc, 0x0fdb01e2, 0x00320ffd, 0x0fe201ef,
+ 0x001e0000, 0x0fea01f8, 0x000c0000, 0x0ff501ff,
+ 0x02000000, 0x00000000, 0x02010ff9, 0x00000006,
+ 0x02000ff2, 0x0000000e, 0x01fd0fed, 0x0ffe0018,
+ 0x01f80fe8, 0x0ffd0023, 0x01f20fe4, 0x0ffb002f,
+ 0x01eb0fe0, 0x0ff9003c, 0x01e10fdd, 0x0ff7004b,
+ 0x01d60fda, 0x0ff4005c, 0x01c90fd9, 0x0ff2006c,
+ 0x01bc0fd8, 0x0fee007e, 0x01ab0fd8, 0x0fec0091,
+ 0x019b0fd8, 0x0fe800a5, 0x018b0fd8, 0x0fe400b9,
+ 0x01770fd9, 0x0fe200ce, 0x01620fdb, 0x0fdf00e4,
+ 0x014f0fdb, 0x0fdb00fb, 0x01380fde, 0x0fda0110,
+ 0x01210fe0, 0x0fd70128, 0x010a0fe2, 0x0fd5013f,
+ 0x00f30fe6, 0x0fd30154, 0x00da0fe9, 0x0fd3016a,
+ 0x00c30feb, 0x0fd20180, 0x00aa0fef, 0x0fd20195,
+ 0x00940ff1, 0x0fd301a8, 0x007b0ff5, 0x0fd501bb,
+ 0x00650ff7, 0x0fd801cc, 0x00510ffa, 0x0fdc01d9,
+ 0x003c0ffd, 0x0fe101e6, 0x002a0ffe, 0x0fe701f1,
+ 0x00190000, 0x0fee01f9, 0x000a0000, 0x0ff701ff,
+ 0x02000000, 0x00000000, 0x01ff0ff9, 0x00000008,
+ 0x01fb0ff2, 0x00000013, 0x01f50fed, 0x0ffe0020,
+ 0x01ed0fe8, 0x0ffd002e, 0x01e30fe4, 0x0ffb003e,
+ 0x01d80fe1, 0x0ff9004e, 0x01cb0fde, 0x0ff70060,
+ 0x01bc0fdc, 0x0ff40074, 0x01ac0fdb, 0x0ff20087,
+ 0x019a0fdb, 0x0fef009c, 0x01870fdb, 0x0fed00b1,
+ 0x01740fdb, 0x0fea00c7, 0x01600fdc, 0x0fe700dd,
+ 0x014b0fdd, 0x0fe500f3, 0x01350fdf, 0x0fe30109,
+ 0x01200fe0, 0x0fe00120, 0x01090fe3, 0x0fdf0135,
+ 0x00f30fe5, 0x0fdd014b, 0x00dd0fe7, 0x0fdc0160,
+ 0x00c70fea, 0x0fdb0174, 0x00b10fed, 0x0fdb0187,
+ 0x009c0fef, 0x0fdb019a, 0x00870ff2, 0x0fdb01ac,
+ 0x00740ff4, 0x0fdc01bc, 0x00600ff7, 0x0fde01cb,
+ 0x004e0ff9, 0x0fe101d8, 0x003e0ffb, 0x0fe401e3,
+ 0x002e0ffd, 0x0fe801ed, 0x00200ffe, 0x0fed01f5,
+ 0x00130000, 0x0ff201fb, 0x00080000, 0x0ff901ff
+};
+
+
+#define MDP4_QSEED_TABLE0_OFF 0x8100
+#define MDP4_QSEED_TABLE1_OFF 0x8200
+#define MDP4_QSEED_TABLE2_OFF 0x9000
+
+void mdp4_vg_qseed_init(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_QSEED_TABLE0_OFF);
+ for (i = 0; i < (sizeof(vg_qseed_table0) / sizeof(uint32)); i++) {
+ outpdw(off, vg_qseed_table0[i]);
+ off++;
+ }
+
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_QSEED_TABLE1_OFF);
+ for (i = 0; i < (sizeof(vg_qseed_table1) / sizeof(uint32)); i++) {
+ outpdw(off, vg_qseed_table1[i]);
+ off++;
+ }
+
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_QSEED_TABLE2_OFF);
+ for (i = 0; i < (sizeof(vg_qseed_table2) / sizeof(uint32)); i++) {
+ outpdw(off, vg_qseed_table2[i]);
+ off++;
+ }
+
+}
+
+void mdp4_mixer_blend_init(mixer_num)
+{
+ unsigned char *overlay_base;
+ int off;
+
+ if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
+ else
+ overlay_base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+
+ /* stage 0 to stage 2 */
+ off = 0;
+ outpdw(overlay_base + off + 0x104, 0x010);
+ outpdw(overlay_base + off + 0x108, 0xff);/* FG */
+ outpdw(overlay_base + off + 0x10c, 0x00);/* BG */
+
+ off += 0x20;
+ outpdw(overlay_base + off + 0x104, 0x010);
+ outpdw(overlay_base + off + 0x108, 0xff);/* FG */
+ outpdw(overlay_base + off + 0x10c, 0x00);/* BG */
+
+ off += 0x20;
+ outpdw(overlay_base + off + 0x104, 0x010);
+ outpdw(overlay_base + off + 0x108, 0xff);/* FG */
+ outpdw(overlay_base + off + 0x10c, 0x00);/* BG */
+}
+
+
+static uint32 csc_matrix_tab[9] = {
+ 0x0254, 0x0000, 0x0331,
+ 0x0254, 0xff37, 0xfe60,
+ 0x0254, 0x0409, 0x0000
+};
+
+static uint32 csc_pre_bv_tab[3] = {0xfff0, 0xff80, 0xff80 };
+static uint32 csc_post_bv_tab[3] = {0, 0, 0 };
+
+static uint32 csc_pre_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff };
+static uint32 csc_post_lv_tab[6] = {0, 0xff, 0, 0xff, 0, 0xff };
+
+#define MDP4_CSC_MV_OFF 0x4400
+#define MDP4_CSC_PRE_BV_OFF 0x4500
+#define MDP4_CSC_POST_BV_OFF 0x4580
+#define MDP4_CSC_PRE_LV_OFF 0x4600
+#define MDP4_CSC_POST_LV_OFF 0x4680
+
+void mdp4_vg_csc_mv_setup(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_CSC_MV_OFF);
+ for (i = 0; i < 9; i++) {
+ outpdw(off, csc_matrix_tab[i]);
+ off++;
+ }
+}
+
+void mdp4_vg_csc_pre_bv_setup(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_CSC_PRE_BV_OFF);
+ for (i = 0; i < 3; i++) {
+ outpdw(off, csc_pre_bv_tab[i]);
+ off++;
+ }
+}
+
+void mdp4_vg_csc_post_bv_setup(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_CSC_POST_BV_OFF);
+ for (i = 0; i < 3; i++) {
+ outpdw(off, csc_post_bv_tab[i]);
+ off++;
+ }
+}
+
+void mdp4_vg_csc_pre_lv_setup(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_CSC_PRE_LV_OFF);
+
+ for (i = 0; i < 6; i++) {
+ outpdw(off, csc_pre_lv_tab[i]);
+ off++;
+ }
+}
+
+void mdp4_vg_csc_post_lv_setup(int vp_num)
+{
+ uint32 *off;
+ int i, voff;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ off = (uint32 *)(MDP_BASE + MDP4_VIDEO_BASE + voff +
+ MDP4_CSC_POST_LV_OFF);
+
+ for (i = 0; i < 6; i++) {
+ outpdw(off, csc_post_lv_tab[i]);
+ off++;
+ }
+}
+
+char gc_lut[] = {
+ 0x0, 0x1, 0x2, 0x2, 0x3, 0x4, 0x5, 0x6,
+ 0x6, 0x7, 0x8, 0x9, 0xA, 0xA, 0xB, 0xC,
+ 0xD, 0xD, 0xE, 0xF, 0xF, 0x10, 0x10, 0x11,
+ 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15,
+ 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x19,
+ 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C,
+ 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F,
+ 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21,
+ 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24,
+ 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26,
+ 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28,
+ 0x28, 0x29, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A,
+ 0x2A, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C,
+ 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E,
+ 0x2E, 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x2F, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
+ 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33,
+ 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x34, 0x34,
+ 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37,
+ 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39,
+ 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3B, 0x3C,
+ 0x3C, 0x3C, 0x3C, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D,
+ 0x3D, 0x3D, 0x3D, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E,
+ 0x3E, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x40,
+ 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x41, 0x41,
+ 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42,
+ 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x43, 0x43,
+ 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44,
+ 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45,
+ 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x47,
+ 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48,
+ 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49,
+ 0x49, 0x49, 0x49, 0x49, 0x49, 0x4A, 0x4A, 0x4A,
+ 0x4A, 0x4A, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B,
+ 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C,
+ 0x4C, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4D,
+ 0x4D, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4E, 0x4E,
+ 0x4E, 0x4E, 0x4E, 0x4E, 0x4E, 0x4F, 0x4F, 0x4F,
+ 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x50,
+ 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51,
+ 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52,
+ 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, 0x53, 0x53,
+ 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54,
+ 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55,
+ 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56,
+ 0x56, 0x56, 0x57, 0x57, 0x57, 0x57, 0x57, 0x57,
+ 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58,
+ 0x58, 0x58, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59,
+ 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5A, 0x5A,
+ 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A,
+ 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B, 0x5B,
+ 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
+ 0x5C, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5D,
+ 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E,
+ 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E, 0x5E,
+ 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F,
+ 0x5F, 0x5F, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61,
+ 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x62,
+ 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62,
+ 0x62, 0x62, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
+ 0x63, 0x63, 0x63, 0x63, 0x63, 0x64, 0x64, 0x64,
+ 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
+ 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65,
+ 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67,
+ 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67,
+ 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68,
+ 0x68, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69,
+ 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69,
+ 0x69, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6A,
+ 0x6A, 0x6A, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6B,
+ 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B,
+ 0x6B, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6C,
+ 0x6C, 0x6C, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D,
+ 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D, 0x6D,
+ 0x6D, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6E,
+ 0x6E, 0x6E, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F,
+ 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F, 0x6F,
+ 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
+ 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x71, 0x71,
+ 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
+ 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x72, 0x72,
+ 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
+ 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73,
+ 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74,
+ 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74,
+ 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75,
+ 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75, 0x75,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76, 0x76,
+ 0x76, 0x76, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77,
+ 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77,
+ 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+ 0x78, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
+ 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x7A, 0x7A,
+ 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A,
+ 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7B,
+ 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B, 0x7B,
+ 0x7B, 0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C,
+ 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C, 0x7C,
+ 0x7C, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
+ 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D, 0x7D,
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E,
+ 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+ 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82,
+ 0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,
+ 0x83, 0x83, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84,
+ 0x84, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85,
+ 0x85, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86,
+ 0x86, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87,
+ 0x87, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
+ 0x88, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89,
+ 0x89, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A, 0x8A,
+ 0x8A, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B, 0x8B,
+ 0x8B, 0x8B, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C, 0x8C,
+ 0x8C, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D, 0x8D,
+ 0x8D, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8E,
+ 0x8E, 0x8E, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F,
+ 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x8F, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91,
+ 0x91, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92,
+ 0x92, 0x92, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93,
+ 0x93, 0x93, 0x93, 0x93, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94,
+ 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96,
+ 0x96, 0x96, 0x96, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97,
+ 0x97, 0x97, 0x97, 0x97, 0x97, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
+ 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9A,
+ 0x9A, 0x9A, 0x9A, 0x9A, 0x9A, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B, 0x9B,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C, 0x9C,
+ 0x9C, 0x9C, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D,
+ 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9D, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E, 0x9E,
+ 0x9E, 0x9E, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F,
+ 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0x9F, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0, 0xA0,
+ 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1,
+ 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2, 0xA2,
+ 0xA2, 0xA2, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3,
+ 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4, 0xA4,
+ 0xA4, 0xA4, 0xA4, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5, 0xA5,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6,
+ 0xA6, 0xA6, 0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7, 0xA7,
+ 0xA7, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8,
+ 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA8, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9, 0xA9,
+ 0xA9, 0xA9, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+ 0xAA, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB,
+ 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAC,
+ 0xAC, 0xAC, 0xAC, 0xAC, 0xAC, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD, 0xAD,
+ 0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE, 0xAE,
+ 0xAE, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF,
+ 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xAF, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0,
+ 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1, 0xB1,
+ 0xB1, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2, 0xB2,
+ 0xB2, 0xB2, 0xB2, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3, 0xB3,
+ 0xB3, 0xB3, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4, 0xB4,
+ 0xB4, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5, 0xB5,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6, 0xB6,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7,
+ 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB7, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8,
+ 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB8, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9,
+ 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xB9, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA,
+ 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBA, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC, 0xBC,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD, 0xBD,
+ 0xBD, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE, 0xBE,
+ 0xBE, 0xBE, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF, 0xBF,
+ 0xBF, 0xBF, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0,
+ 0xC0, 0xC0, 0xC0, 0xC0, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC1,
+ 0xC1, 0xC1, 0xC1, 0xC1, 0xC1, 0xC2, 0xC2, 0xC2,
+ 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
+ 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2,
+ 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC2, 0xC3, 0xC3,
+ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+ 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3,
+ 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4,
+ 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4,
+ 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4, 0xC4,
+ 0xC4, 0xC4, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5,
+ 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5,
+ 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5, 0xC5,
+ 0xC5, 0xC5, 0xC5, 0xC5, 0xC6, 0xC6, 0xC6, 0xC6,
+ 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+ 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6,
+ 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC7, 0xC7,
+ 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
+ 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
+ 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7, 0xC7,
+ 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+ 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+ 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+ 0xC8, 0xC8, 0xC8, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9,
+ 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9,
+ 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9,
+ 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xC9, 0xCA, 0xCA,
+ 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA,
+ 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA,
+ 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA,
+ 0xCA, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB,
+ 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB,
+ 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB, 0xCB,
+ 0xCB, 0xCB, 0xCB, 0xCB, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
+ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCD,
+ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
+ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
+ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
+ 0xCD, 0xCD, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE,
+ 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE,
+ 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE,
+ 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCE, 0xCF, 0xCF,
+ 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF, 0xCF,
+ 0xCF, 0xCF, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0,
+ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0,
+ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0,
+ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD1, 0xD1, 0xD1,
+ 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1,
+ 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1,
+ 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1, 0xD1,
+ 0xD1, 0xD1, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2,
+ 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD2, 0xD3, 0xD3,
+ 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3,
+ 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3,
+ 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3, 0xD3,
+ 0xD3, 0xD3, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4,
+ 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4,
+ 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4,
+ 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD4, 0xD5,
+ 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5, 0xD5,
+ 0xD5, 0xD5, 0xD5, 0xD5, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6,
+ 0xD6, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
+ 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
+ 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7,
+ 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD7, 0xD8, 0xD8,
+ 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
+ 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
+ 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8, 0xD8,
+ 0xD8, 0xD8, 0xD8, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9, 0xD9,
+ 0xD9, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA,
+ 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDA, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB,
+ 0xDB, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xDD, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE,
+ 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE,
+ 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE,
+ 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDE, 0xDF,
+ 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF,
+ 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF,
+ 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF,
+ 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xDF, 0xE0, 0xE0,
+ 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
+ 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
+ 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0,
+ 0xE0, 0xE0, 0xE0, 0xE0, 0xE1, 0xE1, 0xE1, 0xE1,
+ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1,
+ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1,
+ 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1, 0xE1,
+ 0xE1, 0xE1, 0xE1, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2,
+ 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2,
+ 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2,
+ 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2, 0xE2,
+ 0xE2, 0xE2, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3,
+ 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3,
+ 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3,
+ 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3, 0xE3,
+ 0xE3, 0xE3, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4,
+ 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4,
+ 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4,
+ 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4, 0xE4,
+ 0xE4, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5, 0xE5,
+ 0xE5, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6,
+ 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6,
+ 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6,
+ 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6, 0xE6,
+ 0xE6, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+ 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+ 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+ 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+ 0xE7, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
+ 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
+ 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
+ 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8, 0xE8,
+ 0xE8, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9,
+ 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9,
+ 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9,
+ 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9, 0xE9,
+ 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA,
+ 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA,
+ 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA,
+ 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA, 0xEA,
+ 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
+ 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
+ 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
+ 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB, 0xEB,
+ 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC,
+ 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC,
+ 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC,
+ 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC, 0xEC,
+ 0xEC, 0xEC, 0xEC, 0xEC, 0xED, 0xED, 0xED, 0xED,
+ 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+ 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+ 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED, 0xED,
+ 0xED, 0xED, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+ 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF,
+ 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
+ 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
+ 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
+ 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF, 0xEF,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
+ 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,
+ 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,
+ 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,
+ 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1, 0xF1,
+ 0xF1, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2,
+ 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF2, 0xF3, 0xF3,
+ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3,
+ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3,
+ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3,
+ 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3, 0xF3,
+ 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4,
+ 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4,
+ 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4,
+ 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4, 0xF4,
+ 0xF4, 0xF4, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5,
+ 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5,
+ 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5,
+ 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF5,
+ 0xF5, 0xF5, 0xF5, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6,
+ 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6,
+ 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6,
+ 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6,
+ 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6, 0xF6,
+ 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
+ 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
+ 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
+ 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7, 0xF7,
+ 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+ 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+ 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+ 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8,
+ 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9,
+ 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9,
+ 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9,
+ 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9,
+ 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9, 0xF9,
+ 0xF9, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
+ 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
+ 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
+ 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFA,
+ 0xFA, 0xFA, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB,
+ 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
+ 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
+ 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
+ 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
+ 0xFB, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFC,
+ 0xFC, 0xFC, 0xFC, 0xFC, 0xFC, 0xFD, 0xFD, 0xFD,
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD,
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD,
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD,
+ 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD, 0xFD,
+ 0xFD, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+ 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+void mdp4_mixer_gc_lut_setup(int mixer_num)
+{
+ unsigned char *base;
+ uint32 data;
+ char val;
+ int i, off;
+
+ if (mixer_num) /* mixer number, /dev/fb0, /dev/fb1 */
+ base = MDP_BASE + MDP4_OVERLAYPROC1_BASE;/* 0x18000 */
+ else
+ base = MDP_BASE + MDP4_OVERLAYPROC0_BASE;/* 0x10000 */
+
+ base += 0x4000; /* GC_LUT offset */
+
+ off = 0;
+ for (i = 0; i < 4096; i++) {
+ val = gc_lut[i];
+ data = (val << 16 | val << 8 | val); /* R, B, and G are same */
+ outpdw(base + off, data);
+ off += 4;
+ }
+}
+
+uint32 igc_video_lut[] = { /* non linear */
+ 0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x7, 0x9,
+ 0xA, 0xB, 0xC, 0xE, 0xF, 0x10, 0x12, 0x14,
+ 0x15, 0x17, 0x19, 0x1B, 0x1D, 0x1F, 0x21, 0x23,
+ 0x25, 0x28, 0x2A, 0x2D, 0x30, 0x32, 0x35, 0x38,
+ 0x3B, 0x3E, 0x42, 0x45, 0x48, 0x4C, 0x4F, 0x53,
+ 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x70, 0x74,
+ 0x79, 0x7E, 0x83, 0x88, 0x8D, 0x92, 0x97, 0x9C,
+ 0xA2, 0xA8, 0xAD, 0xB3, 0xB9, 0xBF, 0xC5, 0xCC,
+ 0xD2, 0xD8, 0xDF, 0xE6, 0xED, 0xF4, 0xFB, 0x102,
+ 0x109, 0x111, 0x118, 0x120, 0x128, 0x130, 0x138, 0x140,
+ 0x149, 0x151, 0x15A, 0x162, 0x16B, 0x174, 0x17D, 0x186,
+ 0x190, 0x199, 0x1A3, 0x1AC, 0x1B6, 0x1C0, 0x1CA, 0x1D5,
+ 0x1DF, 0x1EA, 0x1F4, 0x1FF, 0x20A, 0x215, 0x220, 0x22B,
+ 0x237, 0x242, 0x24E, 0x25A, 0x266, 0x272, 0x27F, 0x28B,
+ 0x298, 0x2A4, 0x2B1, 0x2BE, 0x2CB, 0x2D8, 0x2E6, 0x2F3,
+ 0x301, 0x30F, 0x31D, 0x32B, 0x339, 0x348, 0x356, 0x365,
+ 0x374, 0x383, 0x392, 0x3A1, 0x3B1, 0x3C0, 0x3D0, 0x3E0,
+ 0x3F0, 0x400, 0x411, 0x421, 0x432, 0x443, 0x454, 0x465,
+ 0x476, 0x487, 0x499, 0x4AB, 0x4BD, 0x4CF, 0x4E1, 0x4F3,
+ 0x506, 0x518, 0x52B, 0x53E, 0x551, 0x565, 0x578, 0x58C,
+ 0x5A0, 0x5B3, 0x5C8, 0x5DC, 0x5F0, 0x605, 0x61A, 0x62E,
+ 0x643, 0x659, 0x66E, 0x684, 0x699, 0x6AF, 0x6C5, 0x6DB,
+ 0x6F2, 0x708, 0x71F, 0x736, 0x74D, 0x764, 0x77C, 0x793,
+ 0x7AB, 0x7C3, 0x7DB, 0x7F3, 0x80B, 0x824, 0x83D, 0x855,
+ 0x86F, 0x888, 0x8A1, 0x8BB, 0x8D4, 0x8EE, 0x908, 0x923,
+ 0x93D, 0x958, 0x973, 0x98E, 0x9A9, 0x9C4, 0x9DF, 0x9FB,
+ 0xA17, 0xA33, 0xA4F, 0xA6C, 0xA88, 0xAA5, 0xAC2, 0xADF,
+ 0xAFC, 0xB19, 0xB37, 0xB55, 0xB73, 0xB91, 0xBAF, 0xBCE,
+ 0xBEC, 0xC0B, 0xC2A, 0xC4A, 0xC69, 0xC89, 0xCA8, 0xCC8,
+ 0xCE8, 0xD09, 0xD29, 0xD4A, 0xD6B, 0xD8C, 0xDAD, 0xDCF,
+ 0xDF0, 0xE12, 0xE34, 0xE56, 0xE79, 0xE9B, 0xEBE, 0xEE1,
+ 0xF04, 0xF27, 0xF4B, 0xF6E, 0xF92, 0xFB6, 0xFDB, 0xFFF,
+};
+
+void mdp4_vg_igc_lut_setup(int vp_num)
+{
+ unsigned char *base;
+ int i, voff, off;
+ uint32 data, val;
+
+ voff = MDP4_VIDEO_OFF * vp_num;
+ base = MDP_BASE + MDP4_VIDEO_BASE + voff + 0x5000;
+
+ off = 0;
+ for (i = 0; i < 256; i++) {
+ val = igc_video_lut[i];
+ data = (val << 16 | val); /* color 0 and 1 */
+ outpdw(base + off, data);
+ outpdw(base + off + 0x800, val); /* color 2 */
+ off += 4;
+ }
+}
+
+uint32 igc_rgb_lut[] = { /* linear */
+ 0x0, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+ 0x101, 0x111, 0x121, 0x131, 0x141, 0x151, 0x161, 0x171,
+ 0x181, 0x191, 0x1A2, 0x1B2, 0x1C2, 0x1D2, 0x1E2, 0x1F2,
+ 0x202, 0x212, 0x222, 0x232, 0x242, 0x252, 0x262, 0x272,
+ 0x282, 0x292, 0x2A2, 0x2B3, 0x2C3, 0x2D3, 0x2E3, 0x2F3,
+ 0x303, 0x313, 0x323, 0x333, 0x343, 0x353, 0x363, 0x373,
+ 0x383, 0x393, 0x3A3, 0x3B3, 0x3C4, 0x3D4, 0x3E4, 0x3F4,
+ 0x404, 0x414, 0x424, 0x434, 0x444, 0x454, 0x464, 0x474,
+ 0x484, 0x494, 0x4A4, 0x4B4, 0x4C4, 0x4D5, 0x4E5, 0x4F5,
+ 0x505, 0x515, 0x525, 0x535, 0x545, 0x555, 0x565, 0x575,
+ 0x585, 0x595, 0x5A5, 0x5B5, 0x5C5, 0x5D5, 0x5E6, 0x5F6,
+ 0x606, 0x616, 0x626, 0x636, 0x646, 0x656, 0x666, 0x676,
+ 0x686, 0x696, 0x6A6, 0x6B6, 0x6C6, 0x6D6, 0x6E6, 0x6F7,
+ 0x707, 0x717, 0x727, 0x737, 0x747, 0x757, 0x767, 0x777,
+ 0x787, 0x797, 0x7A7, 0x7B7, 0x7C7, 0x7D7, 0x7E7, 0x7F7,
+ 0x808, 0x818, 0x828, 0x838, 0x848, 0x858, 0x868, 0x878,
+ 0x888, 0x898, 0x8A8, 0x8B8, 0x8C8, 0x8D8, 0x8E8, 0x8F8,
+ 0x908, 0x919, 0x929, 0x939, 0x949, 0x959, 0x969, 0x979,
+ 0x989, 0x999, 0x9A9, 0x9B9, 0x9C9, 0x9D9, 0x9E9, 0x9F9,
+ 0xA09, 0xA19, 0xA2A, 0xA3A, 0xA4A, 0xA5A, 0xA6A, 0xA7A,
+ 0xA8A, 0xA9A, 0xAAA, 0xABA, 0xACA, 0xADA, 0xAEA, 0xAFA,
+ 0xB0A, 0xB1A, 0xB2A, 0xB3B, 0xB4B, 0xB5B, 0xB6B, 0xB7B,
+ 0xB8B, 0xB9B, 0xBAB, 0xBBB, 0xBCB, 0xBDB, 0xBEB, 0xBFB,
+ 0xC0B, 0xC1B, 0xC2B, 0xC3B, 0xC4C, 0xC5C, 0xC6C, 0xC7C,
+ 0xC8C, 0xC9C, 0xCAC, 0xCBC, 0xCCC, 0xCDC, 0xCEC, 0xCFC,
+ 0xD0C, 0xD1C, 0xD2C, 0xD3C, 0xD4C, 0xD5D, 0xD6D, 0xD7D,
+ 0xD8D, 0xD9D, 0xDAD, 0xDBD, 0xDCD, 0xDDD, 0xDED, 0xDFD,
+ 0xE0D, 0xE1D, 0xE2D, 0xE3D, 0xE4D, 0xE5D, 0xE6E, 0xE7E,
+ 0xE8E, 0xE9E, 0xEAE, 0xEBE, 0xECE, 0xEDE, 0xEEE, 0xEFE,
+ 0xF0E, 0xF1E, 0xF2E, 0xF3E, 0xF4E, 0xF5E, 0xF6E, 0xF7F,
+ 0xF8F, 0xF9F, 0xFAF, 0xFBF, 0xFCF, 0xFDF, 0xFEF, 0xFFF,
+};
+
+void mdp4_rgb_igc_lut_setup(int num)
+{
+ unsigned char *base;
+ int i, voff, off;
+ uint32 data, val;
+
+ voff = MDP4_RGB_OFF * num;
+ base = MDP_BASE + MDP4_RGB_BASE + voff + 0x5000;
+
+ off = 0;
+ for (i = 0; i < 256; i++) {
+ val = igc_rgb_lut[i];
+ data = (val << 16 | val); /* color 0 and 1 */
+ outpdw(base + off, data);
+ outpdw(base + off + 0x800, val); /* color 2 */
+ off += 4;
+ }
+}
diff --git a/drivers/staging/msm/mdp_cursor.c b/drivers/staging/msm/mdp_cursor.c
new file mode 100644
index 000000000000..7d28f30d9313
--- /dev/null
+++ b/drivers/staging/msm/mdp_cursor.c
@@ -0,0 +1,104 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+
+#include <mach/hardware.h>
+#include <asm/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+static int cursor_enabled;
+
+int mdp_hw_cursor_update(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_image *img = &cursor->image;
+ int calpha_en, transp_en;
+ int alpha;
+ int ret = 0;
+
+ if ((img->width > MDP_CURSOR_WIDTH) ||
+ (img->height > MDP_CURSOR_HEIGHT) ||
+ (img->depth != 32))
+ return -EINVAL;
+
+ if (cursor->set & FB_CUR_SETPOS)
+ MDP_OUTP(MDP_BASE + 0x9004c, (img->dy << 16) | img->dx);
+
+ if (cursor->set & FB_CUR_SETIMAGE) {
+ ret = copy_from_user(mfd->cursor_buf, img->data,
+ img->width*img->height*4);
+ if (ret)
+ return ret;
+
+ if (img->bg_color == 0xffffffff)
+ transp_en = 0;
+ else
+ transp_en = 1;
+
+ alpha = (img->fg_color & 0xff000000) >> 24;
+
+ if (alpha)
+ calpha_en = 0x2; /* xrgb */
+ else
+ calpha_en = 0x1; /* argb */
+
+ MDP_OUTP(MDP_BASE + 0x90044, (img->height << 16) | img->width);
+ MDP_OUTP(MDP_BASE + 0x90048, mfd->cursor_buf_phys);
+ /* order the writes the cursor_buf before updating the
+ * hardware */
+// dma_coherent_pre_ops();
+ MDP_OUTP(MDP_BASE + 0x90060,
+ (transp_en << 3) | (calpha_en << 1) |
+ (inp32(MDP_BASE + 0x90060) & 0x1));
+#ifdef CONFIG_FB_MSM_MDP40
+ MDP_OUTP(MDP_BASE + 0x90064, (alpha << 24));
+ MDP_OUTP(MDP_BASE + 0x90068, (0xffffff & img->bg_color));
+ MDP_OUTP(MDP_BASE + 0x9006C, (0xffffff & img->bg_color));
+#else
+ MDP_OUTP(MDP_BASE + 0x90064,
+ (alpha << 24) | (0xffffff & img->bg_color));
+ MDP_OUTP(MDP_BASE + 0x90068, 0);
+#endif
+ }
+
+ if ((cursor->enable) && (!cursor_enabled)) {
+ cursor_enabled = 1;
+ MDP_OUTP(MDP_BASE + 0x90060, inp32(MDP_BASE + 0x90060) | 0x1);
+ } else if ((!cursor->enable) && (cursor_enabled)) {
+ cursor_enabled = 0;
+ MDP_OUTP(MDP_BASE + 0x90060,
+ inp32(MDP_BASE + 0x90060) & (~0x1));
+ }
+
+ return 0;
+}
diff --git a/drivers/staging/msm/mdp_dma.c b/drivers/staging/msm/mdp_dma.c
new file mode 100644
index 000000000000..639918b143b4
--- /dev/null
+++ b/drivers/staging/msm/mdp_dma.c
@@ -0,0 +1,561 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mddihost.h"
+
+static uint32 mdp_last_dma2_update_width;
+static uint32 mdp_last_dma2_update_height;
+static uint32 mdp_curr_dma2_update_width;
+static uint32 mdp_curr_dma2_update_height;
+
+ktime_t mdp_dma2_last_update_time = { 0 };
+
+int mdp_lcd_rd_cnt_offset_slow = 20;
+int mdp_lcd_rd_cnt_offset_fast = 20;
+int mdp_vsync_usec_wait_line_too_short = 5;
+uint32 mdp_dma2_update_time_in_usec;
+uint32 mdp_total_vdopkts;
+
+extern u32 msm_fb_debug_enabled;
+extern struct workqueue_struct *mdp_dma_wq;
+
+int vsync_start_y_adjust = 4;
+
+static void mdp_dma2_update_lcd(struct msm_fb_data_type *mfd)
+{
+ MDPIBUF *iBuf = &mfd->ibuf;
+ int mddi_dest = FALSE;
+ uint32 outBpp = iBuf->bpp;
+ uint32 dma2_cfg_reg;
+ uint8 *src;
+ uint32 mddi_ld_param;
+ uint16 mddi_vdo_packet_reg;
+ struct msm_fb_panel_data *pdata =
+ (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ uint32 ystride = mfd->fbi->fix.line_length;
+
+ dma2_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
+ DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
+
+#ifdef CONFIG_FB_MSM_MDP30
+ /*
+ * Software workaround: On 7x25/7x27, the MDP will not
+ * respond if dma_w is 1 pixel. Set the update width to
+ * 2 pixels and adjust the x offset if needed.
+ */
+ if (iBuf->dma_w == 1) {
+ iBuf->dma_w = 2;
+ if (iBuf->dma_x == (iBuf->ibuf_width - 2))
+ iBuf->dma_x--;
+ }
+#endif
+
+ if (mfd->fb_imgType == MDP_BGR_565)
+ dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
+ else
+ dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
+
+ if (outBpp == 4)
+ dma2_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
+
+ if (outBpp == 2)
+ dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
+
+ mddi_ld_param = 0;
+ mddi_vdo_packet_reg = mfd->panel_info.mddi.vdopkt;
+
+ if ((mfd->panel_info.type == MDDI_PANEL) ||
+ (mfd->panel_info.type == EXT_MDDI_PANEL)) {
+ dma2_cfg_reg |= DMA_OUT_SEL_MDDI;
+ mddi_dest = TRUE;
+
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ mdp_total_vdopkts++;
+ if (mfd->panel_info.pdest == DISPLAY_1) {
+ dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY;
+ mddi_ld_param = 0;
+#ifdef MDDI_HOST_WINDOW_WORKAROUND
+ mddi_window_adjust(mfd, iBuf->dma_x,
+ iBuf->dma_w - 1, iBuf->dma_y,
+ iBuf->dma_h - 1);
+#endif
+ } else {
+ dma2_cfg_reg |=
+ DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY;
+ mddi_ld_param = 1;
+#ifdef MDDI_HOST_WINDOW_WORKAROUND
+ mddi_window_adjust(mfd, iBuf->dma_x,
+ iBuf->dma_w - 1, iBuf->dma_y,
+ iBuf->dma_h - 1);
+#endif
+ }
+ } else {
+ dma2_cfg_reg |= DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL;
+ mddi_ld_param = 2;
+ }
+ } else {
+ if (mfd->panel_info.pdest == DISPLAY_1) {
+ dma2_cfg_reg |= DMA_AHBM_LCD_SEL_PRIMARY;
+ outp32(MDP_EBI2_LCD0, mfd->data_port_phys);
+ } else {
+ dma2_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
+ outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
+ }
+ }
+
+ dma2_cfg_reg |= DMA_DITHER_EN;
+
+ src = (uint8 *) iBuf->buf;
+ /* starting input address */
+ src += iBuf->dma_x * outBpp + iBuf->dma_y * ystride;
+
+ mdp_curr_dma2_update_width = iBuf->dma_w;
+ mdp_curr_dma2_update_height = iBuf->dma_h;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+#ifdef CONFIG_FB_MSM_MDP22
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0184,
+ (iBuf->dma_h << 16 | iBuf->dma_w));
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0188, src);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x018C, ystride);
+#else
+ MDP_OUTP(MDP_BASE + 0x90004, (iBuf->dma_h << 16 | iBuf->dma_w));
+ MDP_OUTP(MDP_BASE + 0x90008, src);
+ MDP_OUTP(MDP_BASE + 0x9000c, ystride);
+#endif
+
+ if (mfd->panel_info.bpp == 18) {
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
+ DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+ } else {
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
+ DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
+ }
+
+ if (mddi_dest) {
+#ifdef CONFIG_FB_MSM_MDP22
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0194,
+ (iBuf->dma_y << 16) | iBuf->dma_x);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0, mddi_ld_param);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4,
+ (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
+#else
+ MDP_OUTP(MDP_BASE + 0x90010, (iBuf->dma_y << 16) | iBuf->dma_x);
+ MDP_OUTP(MDP_BASE + 0x00090, mddi_ld_param);
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC << 16) | mddi_vdo_packet_reg);
+#endif
+ } else {
+ /* setting EBI2 LCDC write window */
+ pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
+ iBuf->dma_h);
+ }
+
+ /* dma2 config register */
+#ifdef MDP_HW_VSYNC
+ MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
+
+ if ((mfd->use_mdp_vsync) &&
+ (mfd->ibuf.vsync_enable) && (mfd->panel_info.lcd.vsync_enable)) {
+ uint32 start_y;
+
+ if (vsync_start_y_adjust <= iBuf->dma_y)
+ start_y = iBuf->dma_y - vsync_start_y_adjust;
+ else
+ start_y =
+ (mfd->total_lcd_lines - 1) - (vsync_start_y_adjust -
+ iBuf->dma_y);
+
+ /*
+ * MDP VSYNC clock must be On by now so, we don't have to
+ * re-enable it
+ */
+ MDP_OUTP(MDP_BASE + 0x210, start_y);
+ MDP_OUTP(MDP_BASE + 0x20c, 1); /* enable prim vsync */
+ } else {
+ MDP_OUTP(MDP_BASE + 0x20c, 0); /* disable prim vsync */
+ }
+#else
+#ifdef CONFIG_FB_MSM_MDP22
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0180, dma2_cfg_reg);
+#else
+ MDP_OUTP(MDP_BASE + 0x90000, dma2_cfg_reg);
+#endif
+#endif /* MDP_HW_VSYNC */
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+}
+
+static ktime_t vt = { 0 };
+int mdp_usec_diff_threshold = 100;
+int mdp_expected_usec_wait;
+
+enum hrtimer_restart mdp_dma2_vsync_hrtimer_handler(struct hrtimer *ht)
+{
+ struct msm_fb_data_type *mfd = NULL;
+
+ mfd = container_of(ht, struct msm_fb_data_type, dma_hrtimer);
+
+ mdp_pipe_kickoff(MDP_DMA2_TERM, mfd);
+
+ if (msm_fb_debug_enabled) {
+ ktime_t t;
+ int usec_diff;
+ int actual_wait;
+
+ t = ktime_get_real();
+
+ actual_wait =
+ (t.tv.sec - vt.tv.sec) * 1000000 + (t.tv.nsec -
+ vt.tv.nsec) / 1000;
+ usec_diff = actual_wait - mdp_expected_usec_wait;
+
+ if ((mdp_usec_diff_threshold < usec_diff) || (usec_diff < 0))
+ MSM_FB_DEBUG
+ ("HRT Diff = %d usec Exp=%d usec Act=%d usec\n",
+ usec_diff, mdp_expected_usec_wait, actual_wait);
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static void mdp_dma_schedule(struct msm_fb_data_type *mfd, uint32 term)
+{
+ /*
+ * dma2 configure VSYNC block
+ * vsync supported on Primary LCD only for now
+ */
+ int32 mdp_lcd_rd_cnt;
+ uint32 usec_wait_time;
+ uint32 start_y;
+
+ /*
+ * ToDo: if we can move HRT timer callback to workqueue, we can
+ * move DMA2 power on under mdp_pipe_kickoff().
+ * This will save a power for hrt time wait.
+ * However if the latency for context switch (hrt irq -> workqueue)
+ * is too big, we will miss the vsync timing.
+ */
+ if (term == MDP_DMA2_TERM)
+ mdp_pipe_ctrl(MDP_DMA2_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ mdp_dma2_update_time_in_usec =
+ MDP_KTIME2USEC(mdp_dma2_last_update_time);
+
+ if ((!mfd->ibuf.vsync_enable) || (!mfd->panel_info.lcd.vsync_enable)
+ || (mfd->use_mdp_vsync)) {
+ mdp_pipe_kickoff(term, mfd);
+ return;
+ }
+ /* SW vsync logic starts here */
+
+ /* get current rd counter */
+ mdp_lcd_rd_cnt = mdp_get_lcd_line_counter(mfd);
+ if (mdp_dma2_update_time_in_usec != 0) {
+ uint32 num, den;
+
+ /*
+ * roi width boundary calculation to know the size of pixel
+ * width that MDP can send faster or slower than LCD read
+ * pointer
+ */
+
+ num = mdp_last_dma2_update_width * mdp_last_dma2_update_height;
+ den =
+ (((mfd->panel_info.lcd.refx100 * mfd->total_lcd_lines) /
+ 1000) * (mdp_dma2_update_time_in_usec / 100)) / 1000;
+
+ if (den == 0)
+ mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
+ mfd->panel_info.xres + 1;
+ else
+ mfd->vsync_width_boundary[mdp_last_dma2_update_width] =
+ (int)(num / den);
+ }
+
+ if (mfd->vsync_width_boundary[mdp_last_dma2_update_width] >
+ mdp_curr_dma2_update_width) {
+ /* MDP wrp is faster than LCD rdp */
+ mdp_lcd_rd_cnt += mdp_lcd_rd_cnt_offset_fast;
+ } else {
+ /* MDP wrp is slower than LCD rdp */
+ mdp_lcd_rd_cnt -= mdp_lcd_rd_cnt_offset_slow;
+ }
+
+ if (mdp_lcd_rd_cnt < 0)
+ mdp_lcd_rd_cnt = mfd->total_lcd_lines + mdp_lcd_rd_cnt;
+ else if (mdp_lcd_rd_cnt > mfd->total_lcd_lines)
+ mdp_lcd_rd_cnt = mdp_lcd_rd_cnt - mfd->total_lcd_lines - 1;
+
+ /* get wrt pointer position */
+ start_y = mfd->ibuf.dma_y;
+
+ /* measure line difference between start_y and rd counter */
+ if (start_y > mdp_lcd_rd_cnt) {
+ /*
+ * *100 for lcd_ref_hzx100 was already multiplied by 100
+ * *1000000 is for usec conversion
+ */
+
+ if ((start_y - mdp_lcd_rd_cnt) <=
+ mdp_vsync_usec_wait_line_too_short)
+ usec_wait_time = 0;
+ else
+ usec_wait_time =
+ ((start_y -
+ mdp_lcd_rd_cnt) * 1000000) /
+ ((mfd->total_lcd_lines *
+ mfd->panel_info.lcd.refx100) / 100);
+ } else {
+ if ((start_y + (mfd->total_lcd_lines - mdp_lcd_rd_cnt)) <=
+ mdp_vsync_usec_wait_line_too_short)
+ usec_wait_time = 0;
+ else
+ usec_wait_time =
+ ((start_y +
+ (mfd->total_lcd_lines -
+ mdp_lcd_rd_cnt)) * 1000000) /
+ ((mfd->total_lcd_lines *
+ mfd->panel_info.lcd.refx100) / 100);
+ }
+
+ mdp_last_dma2_update_width = mdp_curr_dma2_update_width;
+ mdp_last_dma2_update_height = mdp_curr_dma2_update_height;
+
+ if (usec_wait_time == 0) {
+ mdp_pipe_kickoff(term, mfd);
+ } else {
+ ktime_t wait_time;
+
+ wait_time.tv.sec = 0;
+ wait_time.tv.nsec = usec_wait_time * 1000;
+
+ if (msm_fb_debug_enabled) {
+ vt = ktime_get_real();
+ mdp_expected_usec_wait = usec_wait_time;
+ }
+ hrtimer_start(&mfd->dma_hrtimer, wait_time, HRTIMER_MODE_REL);
+ }
+}
+
+#ifdef MDDI_HOST_WINDOW_WORKAROUND
+void mdp_dma2_update(struct msm_fb_data_type *mfd)
+{
+ MDPIBUF *iBuf;
+ uint32 upper_height;
+
+ if (mfd->panel.type == EXT_MDDI_PANEL) {
+ mdp_dma2_update_sub(mfd);
+ return;
+ }
+
+ iBuf = &mfd->ibuf;
+
+ upper_height =
+ (uint32) mddi_assign_pkt_height((uint16) iBuf->dma_w,
+ (uint16) iBuf->dma_h, 18);
+
+ if (upper_height >= iBuf->dma_h) {
+ mdp_dma2_update_sub(mfd);
+ } else {
+ MDPIBUF lower_height;
+
+ /* sending the upper region first */
+ lower_height = iBuf->dma_h - upper_height;
+ iBuf->dma_h = upper_height;
+ mdp_dma2_update_sub(mfd);
+
+ /* sending the lower region second */
+ iBuf->dma_h = lower_height;
+ iBuf->dma_y += lower_height;
+ iBuf->vsync_enable = FALSE;
+ mdp_dma2_update_sub(mfd);
+ }
+}
+
+void mdp_dma2_update_sub(struct msm_fb_data_type *mfd)
+#else
+void mdp_dma2_update(struct msm_fb_data_type *mfd)
+#endif
+{
+ down(&mfd->dma->mutex);
+ if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+ down(&mfd->sem);
+ mfd->ibuf_flushed = TRUE;
+ mdp_dma2_update_lcd(mfd);
+
+ mdp_enable_irq(MDP_DMA2_TERM);
+ mfd->dma->busy = TRUE;
+ INIT_COMPLETION(mfd->dma->comp);
+
+ /* schedule DMA to start */
+ mdp_dma_schedule(mfd, MDP_DMA2_TERM);
+ up(&mfd->sem);
+
+ /* wait until DMA finishes the current job */
+ wait_for_completion_killable(&mfd->dma->comp);
+ mdp_disable_irq(MDP_DMA2_TERM);
+
+ /* signal if pan function is waiting for the update completion */
+ if (mfd->pan_waiting) {
+ mfd->pan_waiting = FALSE;
+ complete(&mfd->pan_comp);
+ }
+ }
+ up(&mfd->dma->mutex);
+}
+
+void mdp_lcd_update_workqueue_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd = NULL;
+
+ mfd = container_of(work, struct msm_fb_data_type, dma_update_worker);
+ if (mfd)
+ mfd->dma_fnc(mfd);
+}
+
+void mdp_set_dma_pan_info(struct fb_info *info, struct mdp_dirty_region *dirty,
+ boolean sync)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ MDPIBUF *iBuf;
+ int bpp = info->var.bits_per_pixel / 8;
+
+ down(&mfd->sem);
+ iBuf = &mfd->ibuf;
+ iBuf->buf = (uint8 *) info->fix.smem_start;
+ iBuf->buf += info->var.xoffset * bpp +
+ info->var.yoffset * info->fix.line_length;
+
+ iBuf->ibuf_width = info->var.xres_virtual;
+ iBuf->bpp = bpp;
+
+ iBuf->vsync_enable = sync;
+
+ if (dirty) {
+ /*
+ * ToDo: dirty region check inside var.xoffset+xres
+ * <-> var.yoffset+yres
+ */
+ iBuf->dma_x = dirty->xoffset % info->var.xres;
+ iBuf->dma_y = dirty->yoffset % info->var.yres;
+ iBuf->dma_w = dirty->width;
+ iBuf->dma_h = dirty->height;
+ } else {
+ iBuf->dma_x = 0;
+ iBuf->dma_y = 0;
+ iBuf->dma_w = info->var.xres;
+ iBuf->dma_h = info->var.yres;
+ }
+ mfd->ibuf_flushed = FALSE;
+ up(&mfd->sem);
+}
+
+void mdp_set_offset_info(struct fb_info *info, uint32 addr, uint32 sync)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ MDPIBUF *iBuf;
+
+ int bpp = info->var.bits_per_pixel / 8;
+
+ down(&mfd->sem);
+ iBuf = &mfd->ibuf;
+ iBuf->ibuf_width = info->var.xres_virtual;
+ iBuf->bpp = bpp;
+ iBuf->vsync_enable = sync;
+ iBuf->dma_x = 0;
+ iBuf->dma_y = 0;
+ iBuf->dma_w = info->var.xres;
+ iBuf->dma_h = info->var.yres;
+ iBuf->buf = (uint8 *) addr;
+
+ mfd->ibuf_flushed = FALSE;
+ up(&mfd->sem);
+}
+
+void mdp_dma_pan_update(struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ MDPIBUF *iBuf;
+
+ iBuf = &mfd->ibuf;
+
+ if (mfd->sw_currently_refreshing) {
+ /* we need to wait for the pending update */
+ mfd->pan_waiting = TRUE;
+ if (!mfd->ibuf_flushed) {
+ wait_for_completion_killable(&mfd->pan_comp);
+ }
+ /* waiting for this update to complete */
+ mfd->pan_waiting = TRUE;
+ wait_for_completion_killable(&mfd->pan_comp);
+ } else
+ mfd->dma_fnc(mfd);
+}
+
+void mdp_refresh_screen(unsigned long data)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+
+ if ((mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
+ init_timer(&mfd->refresh_timer);
+ mfd->refresh_timer.function = mdp_refresh_screen;
+ mfd->refresh_timer.data = data;
+
+ if (mfd->dma->busy)
+ /* come back in 1 msec */
+ mfd->refresh_timer.expires = jiffies + (HZ / 1000);
+ else
+ mfd->refresh_timer.expires =
+ jiffies + mfd->refresh_timer_duration;
+
+ add_timer(&mfd->refresh_timer);
+
+ if (!mfd->dma->busy) {
+ if (!queue_work(mdp_dma_wq, &mfd->dma_update_worker)) {
+ MSM_FB_DEBUG("mdp_dma: can't queue_work! -> \
+ MDP/MDDI/LCD clock speed needs to be increased\n");
+ }
+ }
+ } else {
+ if (!mfd->hw_refresh)
+ complete(&mfd->refresher_comp);
+ }
+}
diff --git a/drivers/staging/msm/mdp_dma_lcdc.c b/drivers/staging/msm/mdp_dma_lcdc.c
new file mode 100644
index 000000000000..b57fa1a0ceb0
--- /dev/null
+++ b/drivers/staging/msm/mdp_dma_lcdc.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mdp4.h"
+
+#ifdef CONFIG_FB_MSM_MDP40
+#define LCDC_BASE 0xC0000
+#define DTV_BASE 0xD0000
+#define DMA_E_BASE 0xB0000
+#else
+#define LCDC_BASE 0xE0000
+#endif
+
+#define DMA_P_BASE 0x90000
+
+extern spinlock_t mdp_spin_lock;
+#ifndef CONFIG_FB_MSM_MDP40
+extern uint32 mdp_intr_mask;
+#endif
+
+int first_pixel_start_x;
+int first_pixel_start_y;
+
+int mdp_lcdc_on(struct platform_device *pdev)
+{
+ int lcdc_width;
+ int lcdc_height;
+ int lcdc_bpp;
+ int lcdc_border_clr;
+ int lcdc_underflow_clr;
+ int lcdc_hsync_skew;
+
+ int hsync_period;
+ int hsync_ctrl;
+ int vsync_period;
+ int display_hctl;
+ int display_v_start;
+ int display_v_end;
+ int active_hctl;
+ int active_h_start;
+ int active_h_end;
+ int active_v_start;
+ int active_v_end;
+ int ctrl_polarity;
+ int h_back_porch;
+ int h_front_porch;
+ int v_back_porch;
+ int v_front_porch;
+ int hsync_pulse_width;
+ int vsync_pulse_width;
+ int hsync_polarity;
+ int vsync_polarity;
+ int data_en_polarity;
+ int hsync_start_x;
+ int hsync_end_x;
+ uint8 *buf;
+ int bpp;
+ uint32 dma2_cfg_reg;
+ struct fb_info *fbi;
+ struct fb_var_screeninfo *var;
+ struct msm_fb_data_type *mfd;
+ uint32 dma_base;
+ uint32 timer_base = LCDC_BASE;
+ uint32 block = MDP_DMA2_BLOCK;
+ int ret;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ fbi = mfd->fbi;
+ var = &fbi->var;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp + fbi->var.yoffset * fbi->fix.line_length;
+
+ dma2_cfg_reg = DMA_PACK_ALIGN_LSB | DMA_DITHER_EN | DMA_OUT_SEL_LCDC;
+
+ if (mfd->fb_imgType == MDP_BGR_565)
+ dma2_cfg_reg |= DMA_PACK_PATTERN_BGR;
+ else
+ dma2_cfg_reg |= DMA_PACK_PATTERN_RGB;
+
+ if (bpp == 2)
+ dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
+ else if (bpp == 3)
+ dma2_cfg_reg |= DMA_IBUF_FORMAT_RGB888;
+ else
+ dma2_cfg_reg |= DMA_IBUF_FORMAT_xRGB8888_OR_ARGB8888;
+
+ switch (mfd->panel_info.bpp) {
+ case 24:
+ dma2_cfg_reg |= DMA_DSTC0G_8BITS |
+ DMA_DSTC1B_8BITS | DMA_DSTC2R_8BITS;
+ break;
+
+ case 18:
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS |
+ DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+ break;
+
+ case 16:
+ dma2_cfg_reg |= DMA_DSTC0G_6BITS |
+ DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
+ break;
+
+ default:
+ printk(KERN_ERR "mdp lcdc can't support format %d bpp!\n",
+ mfd->panel_info.bpp);
+ return -ENODEV;
+ }
+
+ /* DMA register config */
+
+ dma_base = DMA_P_BASE;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == HDMI_PANEL)
+ dma_base = DMA_E_BASE;
+#endif
+
+ /* starting address */
+ MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
+ /* active window width and height */
+ MDP_OUTP(MDP_BASE + dma_base + 0x4, ((fbi->var.yres) << 16) |
+ (fbi->var.xres));
+ /* buffer ystride */
+ MDP_OUTP(MDP_BASE + dma_base + 0xc, fbi->fix.line_length);
+ /* x/y coordinate = always 0 for lcdc */
+ MDP_OUTP(MDP_BASE + dma_base + 0x10, 0);
+ /* dma config */
+ MDP_OUTP(MDP_BASE + dma_base, dma2_cfg_reg);
+
+ /*
+ * LCDC timing setting
+ */
+ h_back_porch = var->left_margin;
+ h_front_porch = var->right_margin;
+ v_back_porch = var->upper_margin;
+ v_front_porch = var->lower_margin;
+ hsync_pulse_width = var->hsync_len;
+ vsync_pulse_width = var->vsync_len;
+ lcdc_border_clr = mfd->panel_info.lcdc.border_clr;
+ lcdc_underflow_clr = mfd->panel_info.lcdc.underflow_clr;
+ lcdc_hsync_skew = mfd->panel_info.lcdc.hsync_skew;
+
+ lcdc_width = mfd->panel_info.xres;
+ lcdc_height = mfd->panel_info.yres;
+ lcdc_bpp = mfd->panel_info.bpp;
+
+ hsync_period =
+ hsync_pulse_width + h_back_porch + lcdc_width + h_front_porch;
+ hsync_ctrl = (hsync_period << 16) | hsync_pulse_width;
+ hsync_start_x = hsync_pulse_width + h_back_porch;
+ hsync_end_x = hsync_period - h_front_porch - 1;
+ display_hctl = (hsync_end_x << 16) | hsync_start_x;
+
+ vsync_period =
+ (vsync_pulse_width + v_back_porch + lcdc_height +
+ v_front_porch) * hsync_period;
+ display_v_start =
+ (vsync_pulse_width + v_back_porch) * hsync_period + lcdc_hsync_skew;
+ display_v_end =
+ vsync_period - (v_front_porch * hsync_period) + lcdc_hsync_skew - 1;
+
+ if (lcdc_width != var->xres) {
+ active_h_start = hsync_start_x + first_pixel_start_x;
+ active_h_end = active_h_start + var->xres - 1;
+ active_hctl =
+ ACTIVE_START_X_EN | (active_h_end << 16) | active_h_start;
+ } else {
+ active_hctl = 0;
+ }
+
+ if (lcdc_height != var->yres) {
+ active_v_start =
+ display_v_start + first_pixel_start_y * hsync_period;
+ active_v_end = active_v_start + (var->yres) * hsync_period - 1;
+ active_v_start |= ACTIVE_START_Y_EN;
+ } else {
+ active_v_start = 0;
+ active_v_end = 0;
+ }
+
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == HDMI_PANEL) {
+ block = MDP_DMA_E_BLOCK;
+ timer_base = DTV_BASE;
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+ } else {
+ hsync_polarity = 1;
+ vsync_polarity = 1;
+ }
+
+ lcdc_underflow_clr |= 0x80000000; /* enable recovery */
+#else
+ hsync_polarity = 0;
+ vsync_polarity = 0;
+#endif
+ data_en_polarity = 0;
+
+ ctrl_polarity =
+ (data_en_polarity << 2) | (vsync_polarity << 1) | (hsync_polarity);
+
+ MDP_OUTP(MDP_BASE + timer_base + 0x4, hsync_ctrl);
+ MDP_OUTP(MDP_BASE + timer_base + 0x8, vsync_period);
+ MDP_OUTP(MDP_BASE + timer_base + 0xc, vsync_pulse_width * hsync_period);
+ if (timer_base == LCDC_BASE) {
+ MDP_OUTP(MDP_BASE + timer_base + 0x10, display_hctl);
+ MDP_OUTP(MDP_BASE + timer_base + 0x14, display_v_start);
+ MDP_OUTP(MDP_BASE + timer_base + 0x18, display_v_end);
+ MDP_OUTP(MDP_BASE + timer_base + 0x28, lcdc_border_clr);
+ MDP_OUTP(MDP_BASE + timer_base + 0x2c, lcdc_underflow_clr);
+ MDP_OUTP(MDP_BASE + timer_base + 0x30, lcdc_hsync_skew);
+ MDP_OUTP(MDP_BASE + timer_base + 0x38, ctrl_polarity);
+ MDP_OUTP(MDP_BASE + timer_base + 0x1c, active_hctl);
+ MDP_OUTP(MDP_BASE + timer_base + 0x20, active_v_start);
+ MDP_OUTP(MDP_BASE + timer_base + 0x24, active_v_end);
+ } else {
+ MDP_OUTP(MDP_BASE + timer_base + 0x18, display_hctl);
+ MDP_OUTP(MDP_BASE + timer_base + 0x1c, display_v_start);
+ MDP_OUTP(MDP_BASE + timer_base + 0x20, display_v_end);
+ MDP_OUTP(MDP_BASE + timer_base + 0x40, lcdc_border_clr);
+ MDP_OUTP(MDP_BASE + timer_base + 0x44, lcdc_underflow_clr);
+ MDP_OUTP(MDP_BASE + timer_base + 0x48, lcdc_hsync_skew);
+ MDP_OUTP(MDP_BASE + timer_base + 0x50, ctrl_polarity);
+ MDP_OUTP(MDP_BASE + timer_base + 0x2c, active_hctl);
+ MDP_OUTP(MDP_BASE + timer_base + 0x30, active_v_start);
+ MDP_OUTP(MDP_BASE + timer_base + 0x38, active_v_end);
+ }
+
+ ret = panel_next_on(pdev);
+ if (ret == 0) {
+ /* enable LCDC block */
+ MDP_OUTP(MDP_BASE + timer_base, 1);
+ mdp_pipe_ctrl(block, MDP_BLOCK_POWER_ON, FALSE);
+ }
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ return ret;
+}
+
+int mdp_lcdc_off(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+ uint32 timer_base = LCDC_BASE;
+ uint32 block = MDP_DMA2_BLOCK;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == HDMI_PANEL) {
+ block = MDP_DMA_E_BLOCK;
+ timer_base = DTV_BASE;
+ }
+#endif
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ MDP_OUTP(MDP_BASE + timer_base, 0);
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_pipe_ctrl(block, MDP_BLOCK_POWER_OFF, FALSE);
+
+ ret = panel_next_off(pdev);
+
+ /* delay to make sure the last frame finishes */
+ mdelay(100);
+
+ return ret;
+}
+
+void mdp_lcdc_update(struct msm_fb_data_type *mfd)
+{
+ struct fb_info *fbi = mfd->fbi;
+ uint8 *buf;
+ int bpp;
+ unsigned long flag;
+ uint32 dma_base;
+ int irq_block = MDP_DMA2_TERM;
+#ifdef CONFIG_FB_MSM_MDP40
+ int intr = INTR_DMA_P_DONE;
+#endif
+
+ if (!mfd->panel_power_on)
+ return;
+
+ /* no need to power on cmd block since it's lcdc mode */
+
+ if (!mfd->ibuf.visible_swapped) {
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+ } else {
+ /* we've done something to update the pointer. */
+ bpp = mfd->ibuf.bpp;
+ buf = mfd->ibuf.buf;
+ }
+
+ dma_base = DMA_P_BASE;
+
+#ifdef CONFIG_FB_MSM_MDP40
+ if (mfd->panel.type == HDMI_PANEL) {
+ intr = INTR_DMA_E_DONE;
+ irq_block = MDP_DMA_E_TERM;
+ dma_base = DMA_E_BASE;
+ }
+#endif
+
+ /* starting address */
+ MDP_OUTP(MDP_BASE + dma_base + 0x8, (uint32) buf);
+
+ /* enable LCDC irq */
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_enable_irq(irq_block);
+ INIT_COMPLETION(mfd->dma->comp);
+ mfd->dma->waiting = TRUE;
+#ifdef CONFIG_FB_MSM_MDP40
+ outp32(MDP_INTR_CLEAR, intr);
+ mdp_intr_mask |= intr;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+#else
+ outp32(MDP_INTR_CLEAR, LCDC_FRAME_START);
+ mdp_intr_mask |= LCDC_FRAME_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+#endif
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ if (mfd->ibuf.vsync_enable)
+ wait_for_completion_killable(&mfd->dma->comp);
+ mdp_disable_irq(irq_block);
+}
diff --git a/drivers/staging/msm/mdp_dma_s.c b/drivers/staging/msm/mdp_dma_s.c
new file mode 100644
index 000000000000..0c34a1010f17
--- /dev/null
+++ b/drivers/staging/msm/mdp_dma_s.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+static void mdp_dma_s_update_lcd(struct msm_fb_data_type *mfd)
+{
+ MDPIBUF *iBuf = &mfd->ibuf;
+ int mddi_dest = FALSE;
+ uint32 outBpp = iBuf->bpp;
+ uint32 dma_s_cfg_reg;
+ uint8 *src;
+ struct msm_fb_panel_data *pdata =
+ (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+
+ dma_s_cfg_reg = DMA_PACK_TIGHT | DMA_PACK_ALIGN_LSB |
+ DMA_OUT_SEL_AHB | DMA_IBUF_NONCONTIGUOUS;
+
+ if (mfd->fb_imgType == MDP_BGR_565)
+ dma_s_cfg_reg |= DMA_PACK_PATTERN_BGR;
+ else
+ dma_s_cfg_reg |= DMA_PACK_PATTERN_RGB;
+
+ if (outBpp == 4)
+ dma_s_cfg_reg |= DMA_IBUF_C3ALPHA_EN;
+
+ if (outBpp == 2)
+ dma_s_cfg_reg |= DMA_IBUF_FORMAT_RGB565;
+
+ if (mfd->panel_info.pdest != DISPLAY_2) {
+ printk(KERN_ERR "error: non-secondary type through dma_s!\n");
+ return;
+ }
+
+ if (mfd->panel_info.type == MDDI_PANEL) {
+ dma_s_cfg_reg |= DMA_OUT_SEL_MDDI;
+ mddi_dest = TRUE;
+ } else {
+ dma_s_cfg_reg |= DMA_AHBM_LCD_SEL_SECONDARY;
+ outp32(MDP_EBI2_LCD1, mfd->data_port_phys);
+ }
+
+ dma_s_cfg_reg |= DMA_DITHER_EN;
+
+ src = (uint8 *) iBuf->buf;
+ /* starting input address */
+ src += (iBuf->dma_x + iBuf->dma_y * iBuf->ibuf_width) * outBpp;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ /* PIXELSIZE */
+ MDP_OUTP(MDP_BASE + 0xa0004, (iBuf->dma_h << 16 | iBuf->dma_w));
+ MDP_OUTP(MDP_BASE + 0xa0008, src); /* ibuf address */
+ MDP_OUTP(MDP_BASE + 0xa000c, iBuf->ibuf_width * outBpp);/* ystride */
+
+ if (mfd->panel_info.bpp == 18) {
+ dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 666 18BPP */
+ DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS;
+ } else {
+ dma_s_cfg_reg |= DMA_DSTC0G_6BITS | /* 565 16BPP */
+ DMA_DSTC1B_5BITS | DMA_DSTC2R_5BITS;
+ }
+
+ if (mddi_dest) {
+ MDP_OUTP(MDP_BASE + 0xa0010, (iBuf->dma_y << 16) | iBuf->dma_x);
+ MDP_OUTP(MDP_BASE + 0x00090, 1);
+ MDP_OUTP(MDP_BASE + 0x00094,
+ (MDDI_VDO_PACKET_DESC << 16) |
+ mfd->panel_info.mddi.vdopkt);
+ } else {
+ /* setting LCDC write window */
+ pdata->set_rect(iBuf->dma_x, iBuf->dma_y, iBuf->dma_w,
+ iBuf->dma_h);
+ }
+
+ MDP_OUTP(MDP_BASE + 0xa0000, dma_s_cfg_reg);
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ mdp_pipe_kickoff(MDP_DMA_S_TERM, mfd);
+}
+
+void mdp_dma_s_update(struct msm_fb_data_type *mfd)
+{
+ down(&mfd->dma->mutex);
+ if ((mfd) && (!mfd->dma->busy) && (mfd->panel_power_on)) {
+ down(&mfd->sem);
+ mdp_enable_irq(MDP_DMA_S_TERM);
+ mfd->dma->busy = TRUE;
+ INIT_COMPLETION(mfd->dma->comp);
+ mfd->ibuf_flushed = TRUE;
+ mdp_dma_s_update_lcd(mfd);
+ up(&mfd->sem);
+
+ /* wait until DMA finishes the current job */
+ wait_for_completion_killable(&mfd->dma->comp);
+ mdp_disable_irq(MDP_DMA_S_TERM);
+
+ /* signal if pan function is waiting for the update completion */
+ if (mfd->pan_waiting) {
+ mfd->pan_waiting = FALSE;
+ complete(&mfd->pan_comp);
+ }
+ }
+ up(&mfd->dma->mutex);
+}
diff --git a/drivers/staging/msm/mdp_dma_tv.c b/drivers/staging/msm/mdp_dma_tv.c
new file mode 100644
index 000000000000..70989fb32c1d
--- /dev/null
+++ b/drivers/staging/msm/mdp_dma_tv.c
@@ -0,0 +1,142 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+
+#include <linux/fb.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+extern spinlock_t mdp_spin_lock;
+extern uint32 mdp_intr_mask;
+
+int mdp_dma3_on(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct fb_info *fbi;
+ uint8 *buf;
+ int bpp;
+ int ret = 0;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ fbi = mfd->fbi;
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+
+ /* starting address[31..8] of Video frame buffer is CS0 */
+ MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
+
+ mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ MDP_OUTP(MDP_BASE + 0xC0004, 0x4c60674); /* flicker filter enabled */
+ MDP_OUTP(MDP_BASE + 0xC0010, 0x20); /* sobel treshold */
+
+ MDP_OUTP(MDP_BASE + 0xC0018, 0xeb0010); /* Y Max, Y min */
+ MDP_OUTP(MDP_BASE + 0xC001C, 0xf00010); /* Cb Max, Cb min */
+ MDP_OUTP(MDP_BASE + 0xC0020, 0xf00010); /* Cb Max, Cb min */
+
+ MDP_OUTP(MDP_BASE + 0xC000C, 0x67686970); /* add a few chars for CC */
+ MDP_OUTP(MDP_BASE + 0xC0000, 0x1); /* MDP tv out enable */
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ ret = panel_next_on(pdev);
+
+ return ret;
+}
+
+int mdp_dma3_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ ret = panel_next_off(pdev);
+ if (ret)
+ return ret;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ MDP_OUTP(MDP_BASE + 0xC0000, 0x0);
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ mdp_pipe_ctrl(MDP_DMA3_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ /* delay to make sure the last frame finishes */
+ mdelay(100);
+
+ return ret;
+}
+
+void mdp_dma3_update(struct msm_fb_data_type *mfd)
+{
+ struct fb_info *fbi = mfd->fbi;
+ uint8 *buf;
+ int bpp;
+ unsigned long flag;
+
+ if (!mfd->panel_power_on)
+ return;
+
+ /* no need to power on cmd block since dma3 is running */
+ bpp = fbi->var.bits_per_pixel / 8;
+ buf = (uint8 *) fbi->fix.smem_start;
+ buf += fbi->var.xoffset * bpp +
+ fbi->var.yoffset * fbi->fix.line_length;
+ MDP_OUTP(MDP_BASE + 0xC0008, (uint32) buf >> 3);
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ mdp_enable_irq(MDP_DMA3_TERM);
+ INIT_COMPLETION(mfd->dma->comp);
+ mfd->dma->waiting = TRUE;
+
+ outp32(MDP_INTR_CLEAR, TV_OUT_DMA3_START);
+ mdp_intr_mask |= TV_OUT_DMA3_START;
+ outp32(MDP_INTR_ENABLE, mdp_intr_mask);
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ wait_for_completion_killable(&mfd->dma->comp);
+ mdp_disable_irq(MDP_DMA3_TERM);
+}
diff --git a/drivers/staging/msm/mdp_hw_init.c b/drivers/staging/msm/mdp_hw_init.c
new file mode 100644
index 000000000000..807362ac592c
--- /dev/null
+++ b/drivers/staging/msm/mdp_hw_init.c
@@ -0,0 +1,720 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "mdp.h"
+
+/* mdp primary csc limit vector */
+uint32 mdp_plv[] = { 0x10, 0xeb, 0x10, 0xf0 };
+
+/* Color Coefficient matrix for YUV -> RGB */
+struct mdp_ccs mdp_ccs_yuv2rgb = {
+ MDP_CCS_YUV2RGB,
+ {
+ 0x254,
+ 0x000,
+ 0x331,
+ 0x254,
+ 0xff38,
+ 0xfe61,
+ 0x254,
+ 0x409,
+ 0x000,
+ },
+ {
+#ifdef CONFIG_FB_MSM_MDP31
+ 0x1f0,
+ 0x180,
+ 0x180
+#else
+ 0x10,
+ 0x80,
+ 0x80
+#endif
+ }
+};
+
+/* Color Coefficient matrix for RGB -> YUV */
+struct mdp_ccs mdp_ccs_rgb2yuv = {
+ MDP_CCS_RGB2YUV,
+ {
+ 0x83,
+ 0x102,
+ 0x32,
+ 0xffb5,
+ 0xff6c,
+ 0xe1,
+ 0xe1,
+ 0xff45,
+ 0xffdc,
+ },
+#ifdef CONFIG_FB_MSM_MDP31
+ {
+ 0x10,
+ 0x80,
+ 0x80
+ }
+#endif
+};
+
+static void mdp_load_lut_param(void)
+{
+ outpdw(MDP_BASE + 0x40800, 0x0);
+ outpdw(MDP_BASE + 0x40804, 0x151515);
+ outpdw(MDP_BASE + 0x40808, 0x1d1d1d);
+ outpdw(MDP_BASE + 0x4080c, 0x232323);
+ outpdw(MDP_BASE + 0x40810, 0x272727);
+ outpdw(MDP_BASE + 0x40814, 0x2b2b2b);
+ outpdw(MDP_BASE + 0x40818, 0x2f2f2f);
+ outpdw(MDP_BASE + 0x4081c, 0x333333);
+ outpdw(MDP_BASE + 0x40820, 0x363636);
+ outpdw(MDP_BASE + 0x40824, 0x393939);
+ outpdw(MDP_BASE + 0x40828, 0x3b3b3b);
+ outpdw(MDP_BASE + 0x4082c, 0x3e3e3e);
+ outpdw(MDP_BASE + 0x40830, 0x404040);
+ outpdw(MDP_BASE + 0x40834, 0x434343);
+ outpdw(MDP_BASE + 0x40838, 0x454545);
+ outpdw(MDP_BASE + 0x4083c, 0x474747);
+ outpdw(MDP_BASE + 0x40840, 0x494949);
+ outpdw(MDP_BASE + 0x40844, 0x4b4b4b);
+ outpdw(MDP_BASE + 0x40848, 0x4d4d4d);
+ outpdw(MDP_BASE + 0x4084c, 0x4f4f4f);
+ outpdw(MDP_BASE + 0x40850, 0x515151);
+ outpdw(MDP_BASE + 0x40854, 0x535353);
+ outpdw(MDP_BASE + 0x40858, 0x555555);
+ outpdw(MDP_BASE + 0x4085c, 0x565656);
+ outpdw(MDP_BASE + 0x40860, 0x585858);
+ outpdw(MDP_BASE + 0x40864, 0x5a5a5a);
+ outpdw(MDP_BASE + 0x40868, 0x5b5b5b);
+ outpdw(MDP_BASE + 0x4086c, 0x5d5d5d);
+ outpdw(MDP_BASE + 0x40870, 0x5e5e5e);
+ outpdw(MDP_BASE + 0x40874, 0x606060);
+ outpdw(MDP_BASE + 0x40878, 0x616161);
+ outpdw(MDP_BASE + 0x4087c, 0x636363);
+ outpdw(MDP_BASE + 0x40880, 0x646464);
+ outpdw(MDP_BASE + 0x40884, 0x666666);
+ outpdw(MDP_BASE + 0x40888, 0x676767);
+ outpdw(MDP_BASE + 0x4088c, 0x686868);
+ outpdw(MDP_BASE + 0x40890, 0x6a6a6a);
+ outpdw(MDP_BASE + 0x40894, 0x6b6b6b);
+ outpdw(MDP_BASE + 0x40898, 0x6c6c6c);
+ outpdw(MDP_BASE + 0x4089c, 0x6e6e6e);
+ outpdw(MDP_BASE + 0x408a0, 0x6f6f6f);
+ outpdw(MDP_BASE + 0x408a4, 0x707070);
+ outpdw(MDP_BASE + 0x408a8, 0x717171);
+ outpdw(MDP_BASE + 0x408ac, 0x727272);
+ outpdw(MDP_BASE + 0x408b0, 0x747474);
+ outpdw(MDP_BASE + 0x408b4, 0x757575);
+ outpdw(MDP_BASE + 0x408b8, 0x767676);
+ outpdw(MDP_BASE + 0x408bc, 0x777777);
+ outpdw(MDP_BASE + 0x408c0, 0x787878);
+ outpdw(MDP_BASE + 0x408c4, 0x797979);
+ outpdw(MDP_BASE + 0x408c8, 0x7a7a7a);
+ outpdw(MDP_BASE + 0x408cc, 0x7c7c7c);
+ outpdw(MDP_BASE + 0x408d0, 0x7d7d7d);
+ outpdw(MDP_BASE + 0x408d4, 0x7e7e7e);
+ outpdw(MDP_BASE + 0x408d8, 0x7f7f7f);
+ outpdw(MDP_BASE + 0x408dc, 0x808080);
+ outpdw(MDP_BASE + 0x408e0, 0x818181);
+ outpdw(MDP_BASE + 0x408e4, 0x828282);
+ outpdw(MDP_BASE + 0x408e8, 0x838383);
+ outpdw(MDP_BASE + 0x408ec, 0x848484);
+ outpdw(MDP_BASE + 0x408f0, 0x858585);
+ outpdw(MDP_BASE + 0x408f4, 0x868686);
+ outpdw(MDP_BASE + 0x408f8, 0x878787);
+ outpdw(MDP_BASE + 0x408fc, 0x888888);
+ outpdw(MDP_BASE + 0x40900, 0x898989);
+ outpdw(MDP_BASE + 0x40904, 0x8a8a8a);
+ outpdw(MDP_BASE + 0x40908, 0x8b8b8b);
+ outpdw(MDP_BASE + 0x4090c, 0x8c8c8c);
+ outpdw(MDP_BASE + 0x40910, 0x8d8d8d);
+ outpdw(MDP_BASE + 0x40914, 0x8e8e8e);
+ outpdw(MDP_BASE + 0x40918, 0x8f8f8f);
+ outpdw(MDP_BASE + 0x4091c, 0x8f8f8f);
+ outpdw(MDP_BASE + 0x40920, 0x909090);
+ outpdw(MDP_BASE + 0x40924, 0x919191);
+ outpdw(MDP_BASE + 0x40928, 0x929292);
+ outpdw(MDP_BASE + 0x4092c, 0x939393);
+ outpdw(MDP_BASE + 0x40930, 0x949494);
+ outpdw(MDP_BASE + 0x40934, 0x959595);
+ outpdw(MDP_BASE + 0x40938, 0x969696);
+ outpdw(MDP_BASE + 0x4093c, 0x969696);
+ outpdw(MDP_BASE + 0x40940, 0x979797);
+ outpdw(MDP_BASE + 0x40944, 0x989898);
+ outpdw(MDP_BASE + 0x40948, 0x999999);
+ outpdw(MDP_BASE + 0x4094c, 0x9a9a9a);
+ outpdw(MDP_BASE + 0x40950, 0x9b9b9b);
+ outpdw(MDP_BASE + 0x40954, 0x9c9c9c);
+ outpdw(MDP_BASE + 0x40958, 0x9c9c9c);
+ outpdw(MDP_BASE + 0x4095c, 0x9d9d9d);
+ outpdw(MDP_BASE + 0x40960, 0x9e9e9e);
+ outpdw(MDP_BASE + 0x40964, 0x9f9f9f);
+ outpdw(MDP_BASE + 0x40968, 0xa0a0a0);
+ outpdw(MDP_BASE + 0x4096c, 0xa0a0a0);
+ outpdw(MDP_BASE + 0x40970, 0xa1a1a1);
+ outpdw(MDP_BASE + 0x40974, 0xa2a2a2);
+ outpdw(MDP_BASE + 0x40978, 0xa3a3a3);
+ outpdw(MDP_BASE + 0x4097c, 0xa4a4a4);
+ outpdw(MDP_BASE + 0x40980, 0xa4a4a4);
+ outpdw(MDP_BASE + 0x40984, 0xa5a5a5);
+ outpdw(MDP_BASE + 0x40988, 0xa6a6a6);
+ outpdw(MDP_BASE + 0x4098c, 0xa7a7a7);
+ outpdw(MDP_BASE + 0x40990, 0xa7a7a7);
+ outpdw(MDP_BASE + 0x40994, 0xa8a8a8);
+ outpdw(MDP_BASE + 0x40998, 0xa9a9a9);
+ outpdw(MDP_BASE + 0x4099c, 0xaaaaaa);
+ outpdw(MDP_BASE + 0x409a0, 0xaaaaaa);
+ outpdw(MDP_BASE + 0x409a4, 0xababab);
+ outpdw(MDP_BASE + 0x409a8, 0xacacac);
+ outpdw(MDP_BASE + 0x409ac, 0xadadad);
+ outpdw(MDP_BASE + 0x409b0, 0xadadad);
+ outpdw(MDP_BASE + 0x409b4, 0xaeaeae);
+ outpdw(MDP_BASE + 0x409b8, 0xafafaf);
+ outpdw(MDP_BASE + 0x409bc, 0xafafaf);
+ outpdw(MDP_BASE + 0x409c0, 0xb0b0b0);
+ outpdw(MDP_BASE + 0x409c4, 0xb1b1b1);
+ outpdw(MDP_BASE + 0x409c8, 0xb2b2b2);
+ outpdw(MDP_BASE + 0x409cc, 0xb2b2b2);
+ outpdw(MDP_BASE + 0x409d0, 0xb3b3b3);
+ outpdw(MDP_BASE + 0x409d4, 0xb4b4b4);
+ outpdw(MDP_BASE + 0x409d8, 0xb4b4b4);
+ outpdw(MDP_BASE + 0x409dc, 0xb5b5b5);
+ outpdw(MDP_BASE + 0x409e0, 0xb6b6b6);
+ outpdw(MDP_BASE + 0x409e4, 0xb6b6b6);
+ outpdw(MDP_BASE + 0x409e8, 0xb7b7b7);
+ outpdw(MDP_BASE + 0x409ec, 0xb8b8b8);
+ outpdw(MDP_BASE + 0x409f0, 0xb8b8b8);
+ outpdw(MDP_BASE + 0x409f4, 0xb9b9b9);
+ outpdw(MDP_BASE + 0x409f8, 0xbababa);
+ outpdw(MDP_BASE + 0x409fc, 0xbababa);
+ outpdw(MDP_BASE + 0x40a00, 0xbbbbbb);
+ outpdw(MDP_BASE + 0x40a04, 0xbcbcbc);
+ outpdw(MDP_BASE + 0x40a08, 0xbcbcbc);
+ outpdw(MDP_BASE + 0x40a0c, 0xbdbdbd);
+ outpdw(MDP_BASE + 0x40a10, 0xbebebe);
+ outpdw(MDP_BASE + 0x40a14, 0xbebebe);
+ outpdw(MDP_BASE + 0x40a18, 0xbfbfbf);
+ outpdw(MDP_BASE + 0x40a1c, 0xc0c0c0);
+ outpdw(MDP_BASE + 0x40a20, 0xc0c0c0);
+ outpdw(MDP_BASE + 0x40a24, 0xc1c1c1);
+ outpdw(MDP_BASE + 0x40a28, 0xc1c1c1);
+ outpdw(MDP_BASE + 0x40a2c, 0xc2c2c2);
+ outpdw(MDP_BASE + 0x40a30, 0xc3c3c3);
+ outpdw(MDP_BASE + 0x40a34, 0xc3c3c3);
+ outpdw(MDP_BASE + 0x40a38, 0xc4c4c4);
+ outpdw(MDP_BASE + 0x40a3c, 0xc5c5c5);
+ outpdw(MDP_BASE + 0x40a40, 0xc5c5c5);
+ outpdw(MDP_BASE + 0x40a44, 0xc6c6c6);
+ outpdw(MDP_BASE + 0x40a48, 0xc6c6c6);
+ outpdw(MDP_BASE + 0x40a4c, 0xc7c7c7);
+ outpdw(MDP_BASE + 0x40a50, 0xc8c8c8);
+ outpdw(MDP_BASE + 0x40a54, 0xc8c8c8);
+ outpdw(MDP_BASE + 0x40a58, 0xc9c9c9);
+ outpdw(MDP_BASE + 0x40a5c, 0xc9c9c9);
+ outpdw(MDP_BASE + 0x40a60, 0xcacaca);
+ outpdw(MDP_BASE + 0x40a64, 0xcbcbcb);
+ outpdw(MDP_BASE + 0x40a68, 0xcbcbcb);
+ outpdw(MDP_BASE + 0x40a6c, 0xcccccc);
+ outpdw(MDP_BASE + 0x40a70, 0xcccccc);
+ outpdw(MDP_BASE + 0x40a74, 0xcdcdcd);
+ outpdw(MDP_BASE + 0x40a78, 0xcecece);
+ outpdw(MDP_BASE + 0x40a7c, 0xcecece);
+ outpdw(MDP_BASE + 0x40a80, 0xcfcfcf);
+ outpdw(MDP_BASE + 0x40a84, 0xcfcfcf);
+ outpdw(MDP_BASE + 0x40a88, 0xd0d0d0);
+ outpdw(MDP_BASE + 0x40a8c, 0xd0d0d0);
+ outpdw(MDP_BASE + 0x40a90, 0xd1d1d1);
+ outpdw(MDP_BASE + 0x40a94, 0xd2d2d2);
+ outpdw(MDP_BASE + 0x40a98, 0xd2d2d2);
+ outpdw(MDP_BASE + 0x40a9c, 0xd3d3d3);
+ outpdw(MDP_BASE + 0x40aa0, 0xd3d3d3);
+ outpdw(MDP_BASE + 0x40aa4, 0xd4d4d4);
+ outpdw(MDP_BASE + 0x40aa8, 0xd4d4d4);
+ outpdw(MDP_BASE + 0x40aac, 0xd5d5d5);
+ outpdw(MDP_BASE + 0x40ab0, 0xd6d6d6);
+ outpdw(MDP_BASE + 0x40ab4, 0xd6d6d6);
+ outpdw(MDP_BASE + 0x40ab8, 0xd7d7d7);
+ outpdw(MDP_BASE + 0x40abc, 0xd7d7d7);
+ outpdw(MDP_BASE + 0x40ac0, 0xd8d8d8);
+ outpdw(MDP_BASE + 0x40ac4, 0xd8d8d8);
+ outpdw(MDP_BASE + 0x40ac8, 0xd9d9d9);
+ outpdw(MDP_BASE + 0x40acc, 0xd9d9d9);
+ outpdw(MDP_BASE + 0x40ad0, 0xdadada);
+ outpdw(MDP_BASE + 0x40ad4, 0xdbdbdb);
+ outpdw(MDP_BASE + 0x40ad8, 0xdbdbdb);
+ outpdw(MDP_BASE + 0x40adc, 0xdcdcdc);
+ outpdw(MDP_BASE + 0x40ae0, 0xdcdcdc);
+ outpdw(MDP_BASE + 0x40ae4, 0xdddddd);
+ outpdw(MDP_BASE + 0x40ae8, 0xdddddd);
+ outpdw(MDP_BASE + 0x40aec, 0xdedede);
+ outpdw(MDP_BASE + 0x40af0, 0xdedede);
+ outpdw(MDP_BASE + 0x40af4, 0xdfdfdf);
+ outpdw(MDP_BASE + 0x40af8, 0xdfdfdf);
+ outpdw(MDP_BASE + 0x40afc, 0xe0e0e0);
+ outpdw(MDP_BASE + 0x40b00, 0xe0e0e0);
+ outpdw(MDP_BASE + 0x40b04, 0xe1e1e1);
+ outpdw(MDP_BASE + 0x40b08, 0xe1e1e1);
+ outpdw(MDP_BASE + 0x40b0c, 0xe2e2e2);
+ outpdw(MDP_BASE + 0x40b10, 0xe3e3e3);
+ outpdw(MDP_BASE + 0x40b14, 0xe3e3e3);
+ outpdw(MDP_BASE + 0x40b18, 0xe4e4e4);
+ outpdw(MDP_BASE + 0x40b1c, 0xe4e4e4);
+ outpdw(MDP_BASE + 0x40b20, 0xe5e5e5);
+ outpdw(MDP_BASE + 0x40b24, 0xe5e5e5);
+ outpdw(MDP_BASE + 0x40b28, 0xe6e6e6);
+ outpdw(MDP_BASE + 0x40b2c, 0xe6e6e6);
+ outpdw(MDP_BASE + 0x40b30, 0xe7e7e7);
+ outpdw(MDP_BASE + 0x40b34, 0xe7e7e7);
+ outpdw(MDP_BASE + 0x40b38, 0xe8e8e8);
+ outpdw(MDP_BASE + 0x40b3c, 0xe8e8e8);
+ outpdw(MDP_BASE + 0x40b40, 0xe9e9e9);
+ outpdw(MDP_BASE + 0x40b44, 0xe9e9e9);
+ outpdw(MDP_BASE + 0x40b48, 0xeaeaea);
+ outpdw(MDP_BASE + 0x40b4c, 0xeaeaea);
+ outpdw(MDP_BASE + 0x40b50, 0xebebeb);
+ outpdw(MDP_BASE + 0x40b54, 0xebebeb);
+ outpdw(MDP_BASE + 0x40b58, 0xececec);
+ outpdw(MDP_BASE + 0x40b5c, 0xececec);
+ outpdw(MDP_BASE + 0x40b60, 0xededed);
+ outpdw(MDP_BASE + 0x40b64, 0xededed);
+ outpdw(MDP_BASE + 0x40b68, 0xeeeeee);
+ outpdw(MDP_BASE + 0x40b6c, 0xeeeeee);
+ outpdw(MDP_BASE + 0x40b70, 0xefefef);
+ outpdw(MDP_BASE + 0x40b74, 0xefefef);
+ outpdw(MDP_BASE + 0x40b78, 0xf0f0f0);
+ outpdw(MDP_BASE + 0x40b7c, 0xf0f0f0);
+ outpdw(MDP_BASE + 0x40b80, 0xf1f1f1);
+ outpdw(MDP_BASE + 0x40b84, 0xf1f1f1);
+ outpdw(MDP_BASE + 0x40b88, 0xf2f2f2);
+ outpdw(MDP_BASE + 0x40b8c, 0xf2f2f2);
+ outpdw(MDP_BASE + 0x40b90, 0xf2f2f2);
+ outpdw(MDP_BASE + 0x40b94, 0xf3f3f3);
+ outpdw(MDP_BASE + 0x40b98, 0xf3f3f3);
+ outpdw(MDP_BASE + 0x40b9c, 0xf4f4f4);
+ outpdw(MDP_BASE + 0x40ba0, 0xf4f4f4);
+ outpdw(MDP_BASE + 0x40ba4, 0xf5f5f5);
+ outpdw(MDP_BASE + 0x40ba8, 0xf5f5f5);
+ outpdw(MDP_BASE + 0x40bac, 0xf6f6f6);
+ outpdw(MDP_BASE + 0x40bb0, 0xf6f6f6);
+ outpdw(MDP_BASE + 0x40bb4, 0xf7f7f7);
+ outpdw(MDP_BASE + 0x40bb8, 0xf7f7f7);
+ outpdw(MDP_BASE + 0x40bbc, 0xf8f8f8);
+ outpdw(MDP_BASE + 0x40bc0, 0xf8f8f8);
+ outpdw(MDP_BASE + 0x40bc4, 0xf9f9f9);
+ outpdw(MDP_BASE + 0x40bc8, 0xf9f9f9);
+ outpdw(MDP_BASE + 0x40bcc, 0xfafafa);
+ outpdw(MDP_BASE + 0x40bd0, 0xfafafa);
+ outpdw(MDP_BASE + 0x40bd4, 0xfafafa);
+ outpdw(MDP_BASE + 0x40bd8, 0xfbfbfb);
+ outpdw(MDP_BASE + 0x40bdc, 0xfbfbfb);
+ outpdw(MDP_BASE + 0x40be0, 0xfcfcfc);
+ outpdw(MDP_BASE + 0x40be4, 0xfcfcfc);
+ outpdw(MDP_BASE + 0x40be8, 0xfdfdfd);
+ outpdw(MDP_BASE + 0x40bec, 0xfdfdfd);
+ outpdw(MDP_BASE + 0x40bf0, 0xfefefe);
+ outpdw(MDP_BASE + 0x40bf4, 0xfefefe);
+ outpdw(MDP_BASE + 0x40bf8, 0xffffff);
+ outpdw(MDP_BASE + 0x40bfc, 0xffffff);
+ outpdw(MDP_BASE + 0x40c00, 0x0);
+ outpdw(MDP_BASE + 0x40c04, 0x0);
+ outpdw(MDP_BASE + 0x40c08, 0x0);
+ outpdw(MDP_BASE + 0x40c0c, 0x0);
+ outpdw(MDP_BASE + 0x40c10, 0x0);
+ outpdw(MDP_BASE + 0x40c14, 0x0);
+ outpdw(MDP_BASE + 0x40c18, 0x0);
+ outpdw(MDP_BASE + 0x40c1c, 0x0);
+ outpdw(MDP_BASE + 0x40c20, 0x0);
+ outpdw(MDP_BASE + 0x40c24, 0x0);
+ outpdw(MDP_BASE + 0x40c28, 0x0);
+ outpdw(MDP_BASE + 0x40c2c, 0x0);
+ outpdw(MDP_BASE + 0x40c30, 0x0);
+ outpdw(MDP_BASE + 0x40c34, 0x0);
+ outpdw(MDP_BASE + 0x40c38, 0x0);
+ outpdw(MDP_BASE + 0x40c3c, 0x0);
+ outpdw(MDP_BASE + 0x40c40, 0x10101);
+ outpdw(MDP_BASE + 0x40c44, 0x10101);
+ outpdw(MDP_BASE + 0x40c48, 0x10101);
+ outpdw(MDP_BASE + 0x40c4c, 0x10101);
+ outpdw(MDP_BASE + 0x40c50, 0x10101);
+ outpdw(MDP_BASE + 0x40c54, 0x10101);
+ outpdw(MDP_BASE + 0x40c58, 0x10101);
+ outpdw(MDP_BASE + 0x40c5c, 0x10101);
+ outpdw(MDP_BASE + 0x40c60, 0x10101);
+ outpdw(MDP_BASE + 0x40c64, 0x10101);
+ outpdw(MDP_BASE + 0x40c68, 0x20202);
+ outpdw(MDP_BASE + 0x40c6c, 0x20202);
+ outpdw(MDP_BASE + 0x40c70, 0x20202);
+ outpdw(MDP_BASE + 0x40c74, 0x20202);
+ outpdw(MDP_BASE + 0x40c78, 0x20202);
+ outpdw(MDP_BASE + 0x40c7c, 0x20202);
+ outpdw(MDP_BASE + 0x40c80, 0x30303);
+ outpdw(MDP_BASE + 0x40c84, 0x30303);
+ outpdw(MDP_BASE + 0x40c88, 0x30303);
+ outpdw(MDP_BASE + 0x40c8c, 0x30303);
+ outpdw(MDP_BASE + 0x40c90, 0x30303);
+ outpdw(MDP_BASE + 0x40c94, 0x40404);
+ outpdw(MDP_BASE + 0x40c98, 0x40404);
+ outpdw(MDP_BASE + 0x40c9c, 0x40404);
+ outpdw(MDP_BASE + 0x40ca0, 0x40404);
+ outpdw(MDP_BASE + 0x40ca4, 0x40404);
+ outpdw(MDP_BASE + 0x40ca8, 0x50505);
+ outpdw(MDP_BASE + 0x40cac, 0x50505);
+ outpdw(MDP_BASE + 0x40cb0, 0x50505);
+ outpdw(MDP_BASE + 0x40cb4, 0x50505);
+ outpdw(MDP_BASE + 0x40cb8, 0x60606);
+ outpdw(MDP_BASE + 0x40cbc, 0x60606);
+ outpdw(MDP_BASE + 0x40cc0, 0x60606);
+ outpdw(MDP_BASE + 0x40cc4, 0x70707);
+ outpdw(MDP_BASE + 0x40cc8, 0x70707);
+ outpdw(MDP_BASE + 0x40ccc, 0x70707);
+ outpdw(MDP_BASE + 0x40cd0, 0x70707);
+ outpdw(MDP_BASE + 0x40cd4, 0x80808);
+ outpdw(MDP_BASE + 0x40cd8, 0x80808);
+ outpdw(MDP_BASE + 0x40cdc, 0x80808);
+ outpdw(MDP_BASE + 0x40ce0, 0x90909);
+ outpdw(MDP_BASE + 0x40ce4, 0x90909);
+ outpdw(MDP_BASE + 0x40ce8, 0xa0a0a);
+ outpdw(MDP_BASE + 0x40cec, 0xa0a0a);
+ outpdw(MDP_BASE + 0x40cf0, 0xa0a0a);
+ outpdw(MDP_BASE + 0x40cf4, 0xb0b0b);
+ outpdw(MDP_BASE + 0x40cf8, 0xb0b0b);
+ outpdw(MDP_BASE + 0x40cfc, 0xb0b0b);
+ outpdw(MDP_BASE + 0x40d00, 0xc0c0c);
+ outpdw(MDP_BASE + 0x40d04, 0xc0c0c);
+ outpdw(MDP_BASE + 0x40d08, 0xd0d0d);
+ outpdw(MDP_BASE + 0x40d0c, 0xd0d0d);
+ outpdw(MDP_BASE + 0x40d10, 0xe0e0e);
+ outpdw(MDP_BASE + 0x40d14, 0xe0e0e);
+ outpdw(MDP_BASE + 0x40d18, 0xe0e0e);
+ outpdw(MDP_BASE + 0x40d1c, 0xf0f0f);
+ outpdw(MDP_BASE + 0x40d20, 0xf0f0f);
+ outpdw(MDP_BASE + 0x40d24, 0x101010);
+ outpdw(MDP_BASE + 0x40d28, 0x101010);
+ outpdw(MDP_BASE + 0x40d2c, 0x111111);
+ outpdw(MDP_BASE + 0x40d30, 0x111111);
+ outpdw(MDP_BASE + 0x40d34, 0x121212);
+ outpdw(MDP_BASE + 0x40d38, 0x121212);
+ outpdw(MDP_BASE + 0x40d3c, 0x131313);
+ outpdw(MDP_BASE + 0x40d40, 0x131313);
+ outpdw(MDP_BASE + 0x40d44, 0x141414);
+ outpdw(MDP_BASE + 0x40d48, 0x151515);
+ outpdw(MDP_BASE + 0x40d4c, 0x151515);
+ outpdw(MDP_BASE + 0x40d50, 0x161616);
+ outpdw(MDP_BASE + 0x40d54, 0x161616);
+ outpdw(MDP_BASE + 0x40d58, 0x171717);
+ outpdw(MDP_BASE + 0x40d5c, 0x171717);
+ outpdw(MDP_BASE + 0x40d60, 0x181818);
+ outpdw(MDP_BASE + 0x40d64, 0x191919);
+ outpdw(MDP_BASE + 0x40d68, 0x191919);
+ outpdw(MDP_BASE + 0x40d6c, 0x1a1a1a);
+ outpdw(MDP_BASE + 0x40d70, 0x1b1b1b);
+ outpdw(MDP_BASE + 0x40d74, 0x1b1b1b);
+ outpdw(MDP_BASE + 0x40d78, 0x1c1c1c);
+ outpdw(MDP_BASE + 0x40d7c, 0x1c1c1c);
+ outpdw(MDP_BASE + 0x40d80, 0x1d1d1d);
+ outpdw(MDP_BASE + 0x40d84, 0x1e1e1e);
+ outpdw(MDP_BASE + 0x40d88, 0x1f1f1f);
+ outpdw(MDP_BASE + 0x40d8c, 0x1f1f1f);
+ outpdw(MDP_BASE + 0x40d90, 0x202020);
+ outpdw(MDP_BASE + 0x40d94, 0x212121);
+ outpdw(MDP_BASE + 0x40d98, 0x212121);
+ outpdw(MDP_BASE + 0x40d9c, 0x222222);
+ outpdw(MDP_BASE + 0x40da0, 0x232323);
+ outpdw(MDP_BASE + 0x40da4, 0x242424);
+ outpdw(MDP_BASE + 0x40da8, 0x242424);
+ outpdw(MDP_BASE + 0x40dac, 0x252525);
+ outpdw(MDP_BASE + 0x40db0, 0x262626);
+ outpdw(MDP_BASE + 0x40db4, 0x272727);
+ outpdw(MDP_BASE + 0x40db8, 0x272727);
+ outpdw(MDP_BASE + 0x40dbc, 0x282828);
+ outpdw(MDP_BASE + 0x40dc0, 0x292929);
+ outpdw(MDP_BASE + 0x40dc4, 0x2a2a2a);
+ outpdw(MDP_BASE + 0x40dc8, 0x2b2b2b);
+ outpdw(MDP_BASE + 0x40dcc, 0x2c2c2c);
+ outpdw(MDP_BASE + 0x40dd0, 0x2c2c2c);
+ outpdw(MDP_BASE + 0x40dd4, 0x2d2d2d);
+ outpdw(MDP_BASE + 0x40dd8, 0x2e2e2e);
+ outpdw(MDP_BASE + 0x40ddc, 0x2f2f2f);
+ outpdw(MDP_BASE + 0x40de0, 0x303030);
+ outpdw(MDP_BASE + 0x40de4, 0x313131);
+ outpdw(MDP_BASE + 0x40de8, 0x323232);
+ outpdw(MDP_BASE + 0x40dec, 0x333333);
+ outpdw(MDP_BASE + 0x40df0, 0x333333);
+ outpdw(MDP_BASE + 0x40df4, 0x343434);
+ outpdw(MDP_BASE + 0x40df8, 0x353535);
+ outpdw(MDP_BASE + 0x40dfc, 0x363636);
+ outpdw(MDP_BASE + 0x40e00, 0x373737);
+ outpdw(MDP_BASE + 0x40e04, 0x383838);
+ outpdw(MDP_BASE + 0x40e08, 0x393939);
+ outpdw(MDP_BASE + 0x40e0c, 0x3a3a3a);
+ outpdw(MDP_BASE + 0x40e10, 0x3b3b3b);
+ outpdw(MDP_BASE + 0x40e14, 0x3c3c3c);
+ outpdw(MDP_BASE + 0x40e18, 0x3d3d3d);
+ outpdw(MDP_BASE + 0x40e1c, 0x3e3e3e);
+ outpdw(MDP_BASE + 0x40e20, 0x3f3f3f);
+ outpdw(MDP_BASE + 0x40e24, 0x404040);
+ outpdw(MDP_BASE + 0x40e28, 0x414141);
+ outpdw(MDP_BASE + 0x40e2c, 0x424242);
+ outpdw(MDP_BASE + 0x40e30, 0x434343);
+ outpdw(MDP_BASE + 0x40e34, 0x444444);
+ outpdw(MDP_BASE + 0x40e38, 0x464646);
+ outpdw(MDP_BASE + 0x40e3c, 0x474747);
+ outpdw(MDP_BASE + 0x40e40, 0x484848);
+ outpdw(MDP_BASE + 0x40e44, 0x494949);
+ outpdw(MDP_BASE + 0x40e48, 0x4a4a4a);
+ outpdw(MDP_BASE + 0x40e4c, 0x4b4b4b);
+ outpdw(MDP_BASE + 0x40e50, 0x4c4c4c);
+ outpdw(MDP_BASE + 0x40e54, 0x4d4d4d);
+ outpdw(MDP_BASE + 0x40e58, 0x4f4f4f);
+ outpdw(MDP_BASE + 0x40e5c, 0x505050);
+ outpdw(MDP_BASE + 0x40e60, 0x515151);
+ outpdw(MDP_BASE + 0x40e64, 0x525252);
+ outpdw(MDP_BASE + 0x40e68, 0x535353);
+ outpdw(MDP_BASE + 0x40e6c, 0x545454);
+ outpdw(MDP_BASE + 0x40e70, 0x565656);
+ outpdw(MDP_BASE + 0x40e74, 0x575757);
+ outpdw(MDP_BASE + 0x40e78, 0x585858);
+ outpdw(MDP_BASE + 0x40e7c, 0x595959);
+ outpdw(MDP_BASE + 0x40e80, 0x5b5b5b);
+ outpdw(MDP_BASE + 0x40e84, 0x5c5c5c);
+ outpdw(MDP_BASE + 0x40e88, 0x5d5d5d);
+ outpdw(MDP_BASE + 0x40e8c, 0x5e5e5e);
+ outpdw(MDP_BASE + 0x40e90, 0x606060);
+ outpdw(MDP_BASE + 0x40e94, 0x616161);
+ outpdw(MDP_BASE + 0x40e98, 0x626262);
+ outpdw(MDP_BASE + 0x40e9c, 0x646464);
+ outpdw(MDP_BASE + 0x40ea0, 0x656565);
+ outpdw(MDP_BASE + 0x40ea4, 0x666666);
+ outpdw(MDP_BASE + 0x40ea8, 0x686868);
+ outpdw(MDP_BASE + 0x40eac, 0x696969);
+ outpdw(MDP_BASE + 0x40eb0, 0x6a6a6a);
+ outpdw(MDP_BASE + 0x40eb4, 0x6c6c6c);
+ outpdw(MDP_BASE + 0x40eb8, 0x6d6d6d);
+ outpdw(MDP_BASE + 0x40ebc, 0x6f6f6f);
+ outpdw(MDP_BASE + 0x40ec0, 0x707070);
+ outpdw(MDP_BASE + 0x40ec4, 0x717171);
+ outpdw(MDP_BASE + 0x40ec8, 0x737373);
+ outpdw(MDP_BASE + 0x40ecc, 0x747474);
+ outpdw(MDP_BASE + 0x40ed0, 0x767676);
+ outpdw(MDP_BASE + 0x40ed4, 0x777777);
+ outpdw(MDP_BASE + 0x40ed8, 0x797979);
+ outpdw(MDP_BASE + 0x40edc, 0x7a7a7a);
+ outpdw(MDP_BASE + 0x40ee0, 0x7c7c7c);
+ outpdw(MDP_BASE + 0x40ee4, 0x7d7d7d);
+ outpdw(MDP_BASE + 0x40ee8, 0x7f7f7f);
+ outpdw(MDP_BASE + 0x40eec, 0x808080);
+ outpdw(MDP_BASE + 0x40ef0, 0x828282);
+ outpdw(MDP_BASE + 0x40ef4, 0x838383);
+ outpdw(MDP_BASE + 0x40ef8, 0x858585);
+ outpdw(MDP_BASE + 0x40efc, 0x868686);
+ outpdw(MDP_BASE + 0x40f00, 0x888888);
+ outpdw(MDP_BASE + 0x40f04, 0x898989);
+ outpdw(MDP_BASE + 0x40f08, 0x8b8b8b);
+ outpdw(MDP_BASE + 0x40f0c, 0x8d8d8d);
+ outpdw(MDP_BASE + 0x40f10, 0x8e8e8e);
+ outpdw(MDP_BASE + 0x40f14, 0x909090);
+ outpdw(MDP_BASE + 0x40f18, 0x919191);
+ outpdw(MDP_BASE + 0x40f1c, 0x939393);
+ outpdw(MDP_BASE + 0x40f20, 0x959595);
+ outpdw(MDP_BASE + 0x40f24, 0x969696);
+ outpdw(MDP_BASE + 0x40f28, 0x989898);
+ outpdw(MDP_BASE + 0x40f2c, 0x9a9a9a);
+ outpdw(MDP_BASE + 0x40f30, 0x9b9b9b);
+ outpdw(MDP_BASE + 0x40f34, 0x9d9d9d);
+ outpdw(MDP_BASE + 0x40f38, 0x9f9f9f);
+ outpdw(MDP_BASE + 0x40f3c, 0xa1a1a1);
+ outpdw(MDP_BASE + 0x40f40, 0xa2a2a2);
+ outpdw(MDP_BASE + 0x40f44, 0xa4a4a4);
+ outpdw(MDP_BASE + 0x40f48, 0xa6a6a6);
+ outpdw(MDP_BASE + 0x40f4c, 0xa7a7a7);
+ outpdw(MDP_BASE + 0x40f50, 0xa9a9a9);
+ outpdw(MDP_BASE + 0x40f54, 0xababab);
+ outpdw(MDP_BASE + 0x40f58, 0xadadad);
+ outpdw(MDP_BASE + 0x40f5c, 0xafafaf);
+ outpdw(MDP_BASE + 0x40f60, 0xb0b0b0);
+ outpdw(MDP_BASE + 0x40f64, 0xb2b2b2);
+ outpdw(MDP_BASE + 0x40f68, 0xb4b4b4);
+ outpdw(MDP_BASE + 0x40f6c, 0xb6b6b6);
+ outpdw(MDP_BASE + 0x40f70, 0xb8b8b8);
+ outpdw(MDP_BASE + 0x40f74, 0xbababa);
+ outpdw(MDP_BASE + 0x40f78, 0xbbbbbb);
+ outpdw(MDP_BASE + 0x40f7c, 0xbdbdbd);
+ outpdw(MDP_BASE + 0x40f80, 0xbfbfbf);
+ outpdw(MDP_BASE + 0x40f84, 0xc1c1c1);
+ outpdw(MDP_BASE + 0x40f88, 0xc3c3c3);
+ outpdw(MDP_BASE + 0x40f8c, 0xc5c5c5);
+ outpdw(MDP_BASE + 0x40f90, 0xc7c7c7);
+ outpdw(MDP_BASE + 0x40f94, 0xc9c9c9);
+ outpdw(MDP_BASE + 0x40f98, 0xcbcbcb);
+ outpdw(MDP_BASE + 0x40f9c, 0xcdcdcd);
+ outpdw(MDP_BASE + 0x40fa0, 0xcfcfcf);
+ outpdw(MDP_BASE + 0x40fa4, 0xd1d1d1);
+ outpdw(MDP_BASE + 0x40fa8, 0xd3d3d3);
+ outpdw(MDP_BASE + 0x40fac, 0xd5d5d5);
+ outpdw(MDP_BASE + 0x40fb0, 0xd7d7d7);
+ outpdw(MDP_BASE + 0x40fb4, 0xd9d9d9);
+ outpdw(MDP_BASE + 0x40fb8, 0xdbdbdb);
+ outpdw(MDP_BASE + 0x40fbc, 0xdddddd);
+ outpdw(MDP_BASE + 0x40fc0, 0xdfdfdf);
+ outpdw(MDP_BASE + 0x40fc4, 0xe1e1e1);
+ outpdw(MDP_BASE + 0x40fc8, 0xe3e3e3);
+ outpdw(MDP_BASE + 0x40fcc, 0xe5e5e5);
+ outpdw(MDP_BASE + 0x40fd0, 0xe7e7e7);
+ outpdw(MDP_BASE + 0x40fd4, 0xe9e9e9);
+ outpdw(MDP_BASE + 0x40fd8, 0xebebeb);
+ outpdw(MDP_BASE + 0x40fdc, 0xeeeeee);
+ outpdw(MDP_BASE + 0x40fe0, 0xf0f0f0);
+ outpdw(MDP_BASE + 0x40fe4, 0xf2f2f2);
+ outpdw(MDP_BASE + 0x40fe8, 0xf4f4f4);
+ outpdw(MDP_BASE + 0x40fec, 0xf6f6f6);
+ outpdw(MDP_BASE + 0x40ff0, 0xf8f8f8);
+ outpdw(MDP_BASE + 0x40ff4, 0xfbfbfb);
+ outpdw(MDP_BASE + 0x40ff8, 0xfdfdfd);
+ outpdw(MDP_BASE + 0x40ffc, 0xffffff);
+}
+
+#define IRQ_EN_1__MDP_IRQ___M 0x00000800
+
+void mdp_hw_init(void)
+{
+ int i;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ /* debug interface write access */
+ outpdw(MDP_BASE + 0x60, 1);
+
+ outp32(MDP_INTR_ENABLE, MDP_ANY_INTR_MASK);
+ outp32(MDP_EBI2_PORTMAP_MODE, 0x3);
+ outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8, 0x0);
+ outpdw(MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc, 0x0);
+ outpdw(MDP_BASE + 0x60, 0x1);
+ mdp_load_lut_param();
+
+ /*
+ * clear up unused fg/main registers
+ */
+ /* comp.plane 2&3 ystride */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0120, 0x0);
+ /* unpacked pattern */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x012c, 0x0);
+ /* unpacked pattern */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0130, 0x0);
+ /* unpacked pattern */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0134, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0158, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x15c, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0160, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0170, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0174, 0x0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x017c, 0x0);
+
+ /* comp.plane 2 */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0114, 0x0);
+ /* comp.plane 3 */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0118, 0x0);
+
+ /* clear up unused bg registers */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8, 0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0, 0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc, 0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0, 0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4, 0);
+
+#ifndef CONFIG_FB_MSM_MDP22
+ MDP_OUTP(MDP_BASE + 0xE0000, 0);
+ MDP_OUTP(MDP_BASE + 0x100, 0xffffffff);
+ MDP_OUTP(MDP_BASE + 0x90070, 0);
+ MDP_OUTP(MDP_BASE + 0x94010, 1);
+ MDP_OUTP(MDP_BASE + 0x9401c, 2);
+#endif
+
+ /*
+ * limit vector
+ * pre gets applied before color matrix conversion
+ * post is after ccs
+ */
+ writel(mdp_plv[0], MDP_CSC_PRE_LV1n(0));
+ writel(mdp_plv[1], MDP_CSC_PRE_LV1n(1));
+ writel(mdp_plv[2], MDP_CSC_PRE_LV1n(2));
+ writel(mdp_plv[3], MDP_CSC_PRE_LV1n(3));
+
+#ifdef CONFIG_FB_MSM_MDP31
+ writel(mdp_plv[2], MDP_CSC_PRE_LV1n(4));
+ writel(mdp_plv[3], MDP_CSC_PRE_LV1n(5));
+
+ writel(0, MDP_CSC_POST_LV1n(0));
+ writel(0xff, MDP_CSC_POST_LV1n(1));
+ writel(0, MDP_CSC_POST_LV1n(2));
+ writel(0xff, MDP_CSC_POST_LV1n(3));
+ writel(0, MDP_CSC_POST_LV1n(4));
+ writel(0xff, MDP_CSC_POST_LV1n(5));
+
+ writel(0, MDP_CSC_PRE_LV2n(0));
+ writel(0xff, MDP_CSC_PRE_LV2n(1));
+ writel(0, MDP_CSC_PRE_LV2n(2));
+ writel(0xff, MDP_CSC_PRE_LV2n(3));
+ writel(0, MDP_CSC_PRE_LV2n(4));
+ writel(0xff, MDP_CSC_PRE_LV2n(5));
+
+ writel(mdp_plv[0], MDP_CSC_POST_LV2n(0));
+ writel(mdp_plv[1], MDP_CSC_POST_LV2n(1));
+ writel(mdp_plv[2], MDP_CSC_POST_LV2n(2));
+ writel(mdp_plv[3], MDP_CSC_POST_LV2n(3));
+ writel(mdp_plv[2], MDP_CSC_POST_LV2n(4));
+ writel(mdp_plv[3], MDP_CSC_POST_LV2n(5));
+#endif
+
+ /* primary forward matrix */
+ for (i = 0; i < MDP_CCS_SIZE; i++)
+ writel(mdp_ccs_rgb2yuv.ccs[i], MDP_CSC_PFMVn(i));
+
+#ifdef CONFIG_FB_MSM_MDP31
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ writel(mdp_ccs_rgb2yuv.bv[i], MDP_CSC_POST_BV2n(i));
+
+ writel(0, MDP_CSC_PRE_BV2n(0));
+ writel(0, MDP_CSC_PRE_BV2n(1));
+ writel(0, MDP_CSC_PRE_BV2n(2));
+#endif
+ /* primary reverse matrix */
+ for (i = 0; i < MDP_CCS_SIZE; i++)
+ writel(mdp_ccs_yuv2rgb.ccs[i], MDP_CSC_PRMVn(i));
+
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ writel(mdp_ccs_yuv2rgb.bv[i], MDP_CSC_PRE_BV1n(i));
+
+#ifdef CONFIG_FB_MSM_MDP31
+ writel(0, MDP_CSC_POST_BV1n(0));
+ writel(0, MDP_CSC_POST_BV1n(1));
+ writel(0, MDP_CSC_POST_BV1n(2));
+
+ outpdw(MDP_BASE + 0x30010, 0x03e0);
+ outpdw(MDP_BASE + 0x30014, 0x0360);
+ outpdw(MDP_BASE + 0x30018, 0x0120);
+ outpdw(MDP_BASE + 0x3001c, 0x0140);
+#endif
+ mdp_init_scale_table();
+
+#ifndef CONFIG_FB_MSM_MDP31
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0104,
+ ((16 << 6) << 16) | (16) << 6);
+#endif
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+} \ No newline at end of file
diff --git a/drivers/staging/msm/mdp_ppp.c b/drivers/staging/msm/mdp_ppp.c
new file mode 100644
index 000000000000..c35a6aebca14
--- /dev/null
+++ b/drivers/staging/msm/mdp_ppp.c
@@ -0,0 +1,1502 @@
+/* drivers/video/msm/src/drv/mdp/mdp_ppp.c
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <msm_mdp.h>
+#include <linux/file.h>
+#include <linux/major.h>
+
+#include "linux/proc_fs.h"
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+#define MDP_IS_IMGTYPE_BAD(x) (((x) >= MDP_IMGTYPE_LIMIT) && \
+ (((x) < MDP_IMGTYPE2_START) || \
+ ((x) >= MDP_IMGTYPE_LIMIT2)))
+
+static uint32_t bytes_per_pixel[] = {
+ [MDP_RGB_565] = 2,
+ [MDP_RGB_888] = 3,
+ [MDP_XRGB_8888] = 4,
+ [MDP_ARGB_8888] = 4,
+ [MDP_RGBA_8888] = 4,
+ [MDP_BGRA_8888] = 4,
+ [MDP_Y_CBCR_H2V1] = 1,
+ [MDP_Y_CBCR_H2V2] = 1,
+ [MDP_Y_CRCB_H2V1] = 1,
+ [MDP_Y_CRCB_H2V2] = 1,
+ [MDP_YCRYCB_H2V1] = 2,
+ [MDP_BGR_565] = 2
+};
+
+extern uint32 mdp_plv[];
+extern struct semaphore mdp_ppp_mutex;
+
+uint32_t mdp_get_bytes_per_pixel(uint32_t format)
+{
+ uint32_t bpp = 0;
+ if (format < ARRAY_SIZE(bytes_per_pixel))
+ bpp = bytes_per_pixel[format];
+
+ BUG_ON(!bpp);
+ return bpp;
+}
+
+static uint32 mdp_conv_matx_rgb2yuv(uint32 input_pixel,
+ uint16 *matrix_and_bias_vector,
+ uint32 *clamp_vector,
+ uint32 *look_up_table)
+{
+ uint8 input_C2, input_C0, input_C1;
+ uint32 output;
+ int32 comp_C2, comp_C1, comp_C0, temp;
+ int32 temp1, temp2, temp3;
+ int32 matrix[9];
+ int32 bias_vector[3];
+ int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
+ int32 i;
+ uint32 _is_lookup_table_enabled;
+
+ input_C2 = (input_pixel >> 16) & 0xFF;
+ input_C1 = (input_pixel >> 8) & 0xFF;
+ input_C0 = (input_pixel >> 0) & 0xFF;
+
+ comp_C0 = input_C0;
+ comp_C1 = input_C1;
+ comp_C2 = input_C2;
+
+ for (i = 0; i < 9; i++)
+ matrix[i] =
+ ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20;
+
+ bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF);
+ bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF);
+ bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF);
+
+ Y_low_limit = (int32) clamp_vector[0];
+ Y_high_limit = (int32) clamp_vector[1];
+ C_low_limit = (int32) clamp_vector[2];
+ C_high_limit = (int32) clamp_vector[3];
+
+ if (look_up_table == 0) /* check for NULL point */
+ _is_lookup_table_enabled = 0;
+ else
+ _is_lookup_table_enabled = 1;
+
+ if (_is_lookup_table_enabled == 1) {
+ comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF;
+ comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF;
+ comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF;
+ }
+ /*
+ * Color Conversion
+ * reorder input colors
+ */
+ temp = comp_C2;
+ comp_C2 = comp_C1;
+ comp_C1 = comp_C0;
+ comp_C0 = temp;
+
+ /* matrix multiplication */
+ temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2];
+ temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5];
+ temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8];
+
+ comp_C0 = temp1 + 0x100;
+ comp_C1 = temp2 + 0x100;
+ comp_C2 = temp3 + 0x100;
+
+ /* take interger part */
+ comp_C0 >>= 9;
+ comp_C1 >>= 9;
+ comp_C2 >>= 9;
+
+ /* post bias (+) */
+ comp_C0 += bias_vector[0];
+ comp_C1 += bias_vector[1];
+ comp_C2 += bias_vector[2];
+
+ /* limit pixel to 8-bit */
+ if (comp_C0 < 0)
+ comp_C0 = 0;
+
+ if (comp_C0 > 255)
+ comp_C0 = 255;
+
+ if (comp_C1 < 0)
+ comp_C1 = 0;
+
+ if (comp_C1 > 255)
+ comp_C1 = 255;
+
+ if (comp_C2 < 0)
+ comp_C2 = 0;
+
+ if (comp_C2 > 255)
+ comp_C2 = 255;
+
+ /* clamp */
+ if (comp_C0 < Y_low_limit)
+ comp_C0 = Y_low_limit;
+
+ if (comp_C0 > Y_high_limit)
+ comp_C0 = Y_high_limit;
+
+ if (comp_C1 < C_low_limit)
+ comp_C1 = C_low_limit;
+
+ if (comp_C1 > C_high_limit)
+ comp_C1 = C_high_limit;
+
+ if (comp_C2 < C_low_limit)
+ comp_C2 = C_low_limit;
+
+ if (comp_C2 > C_high_limit)
+ comp_C2 = C_high_limit;
+
+ output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
+ return output;
+}
+
+uint32 mdp_conv_matx_yuv2rgb(uint32 input_pixel,
+ uint16 *matrix_and_bias_vector,
+ uint32 *clamp_vector, uint32 *look_up_table)
+{
+ uint8 input_C2, input_C0, input_C1;
+ uint32 output;
+ int32 comp_C2, comp_C1, comp_C0, temp;
+ int32 temp1, temp2, temp3;
+ int32 matrix[9];
+ int32 bias_vector[3];
+ int32 Y_low_limit, Y_high_limit, C_low_limit, C_high_limit;
+ int32 i;
+ uint32 _is_lookup_table_enabled;
+
+ input_C2 = (input_pixel >> 16) & 0xFF;
+ input_C1 = (input_pixel >> 8) & 0xFF;
+ input_C0 = (input_pixel >> 0) & 0xFF;
+
+ comp_C0 = input_C0;
+ comp_C1 = input_C1;
+ comp_C2 = input_C2;
+
+ for (i = 0; i < 9; i++)
+ matrix[i] =
+ ((int32) (((int32) matrix_and_bias_vector[i]) << 20)) >> 20;
+
+ bias_vector[0] = (int32) (matrix_and_bias_vector[9] & 0xFF);
+ bias_vector[1] = (int32) (matrix_and_bias_vector[10] & 0xFF);
+ bias_vector[2] = (int32) (matrix_and_bias_vector[11] & 0xFF);
+
+ Y_low_limit = (int32) clamp_vector[0];
+ Y_high_limit = (int32) clamp_vector[1];
+ C_low_limit = (int32) clamp_vector[2];
+ C_high_limit = (int32) clamp_vector[3];
+
+ if (look_up_table == 0) /* check for NULL point */
+ _is_lookup_table_enabled = 0;
+ else
+ _is_lookup_table_enabled = 1;
+
+ /* clamp */
+ if (comp_C0 < Y_low_limit)
+ comp_C0 = Y_low_limit;
+
+ if (comp_C0 > Y_high_limit)
+ comp_C0 = Y_high_limit;
+
+ if (comp_C1 < C_low_limit)
+ comp_C1 = C_low_limit;
+
+ if (comp_C1 > C_high_limit)
+ comp_C1 = C_high_limit;
+
+ if (comp_C2 < C_low_limit)
+ comp_C2 = C_low_limit;
+
+ if (comp_C2 > C_high_limit)
+ comp_C2 = C_high_limit;
+
+ /*
+ * Color Conversion
+ * pre bias (-)
+ */
+ comp_C0 -= bias_vector[0];
+ comp_C1 -= bias_vector[1];
+ comp_C2 -= bias_vector[2];
+
+ /* matrix multiplication */
+ temp1 = comp_C0 * matrix[0] + comp_C1 * matrix[1] + comp_C2 * matrix[2];
+ temp2 = comp_C0 * matrix[3] + comp_C1 * matrix[4] + comp_C2 * matrix[5];
+ temp3 = comp_C0 * matrix[6] + comp_C1 * matrix[7] + comp_C2 * matrix[8];
+
+ comp_C0 = temp1 + 0x100;
+ comp_C1 = temp2 + 0x100;
+ comp_C2 = temp3 + 0x100;
+
+ /* take interger part */
+ comp_C0 >>= 9;
+ comp_C1 >>= 9;
+ comp_C2 >>= 9;
+
+ /* reorder output colors */
+ temp = comp_C0;
+ comp_C0 = comp_C1;
+ comp_C1 = comp_C2;
+ comp_C2 = temp;
+
+ /* limit pixel to 8-bit */
+ if (comp_C0 < 0)
+ comp_C0 = 0;
+
+ if (comp_C0 > 255)
+ comp_C0 = 255;
+
+ if (comp_C1 < 0)
+ comp_C1 = 0;
+
+ if (comp_C1 > 255)
+ comp_C1 = 255;
+
+ if (comp_C2 < 0)
+ comp_C2 = 0;
+
+ if (comp_C2 > 255)
+ comp_C2 = 255;
+
+ /* Look-up table */
+ if (_is_lookup_table_enabled == 1) {
+ comp_C2 = (look_up_table[comp_C2] >> 16) & 0xFF;
+ comp_C1 = (look_up_table[comp_C1] >> 8) & 0xFF;
+ comp_C0 = (look_up_table[comp_C0] >> 0) & 0xFF;
+ }
+
+ output = (comp_C2 << 16) | (comp_C1 << 8) | comp_C0;
+ return output;
+}
+
+static uint32 mdp_calc_tpval(MDPIMG *mdpImg)
+{
+ uint32 tpVal;
+ uint8 plane_tp;
+
+ tpVal = 0;
+ if ((mdpImg->imgType == MDP_RGB_565)
+ || (mdpImg->imgType == MDP_BGR_565)) {
+ /*
+ * transparent color conversion into 24 bpp
+ *
+ * C2R_8BIT
+ * left shift the entire bit and or it with the upper most bits
+ */
+ plane_tp = (uint8) ((mdpImg->tpVal & 0xF800) >> 11);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 16;
+
+ /* C1B_8BIT */
+ plane_tp = (uint8) (mdpImg->tpVal & 0x1F);
+ tpVal |= ((plane_tp << 3) | ((plane_tp & 0x1C) >> 2)) << 8;
+
+ /* C0G_8BIT */
+ plane_tp = (uint8) ((mdpImg->tpVal & 0x7E0) >> 5);
+ tpVal |= ((plane_tp << 2) | ((plane_tp & 0x30) >> 4));
+ } else {
+ /* 24bit RGB to RBG conversion */
+
+ tpVal = (mdpImg->tpVal & 0xFF00) >> 8;
+ tpVal |= (mdpImg->tpVal & 0xFF) << 8;
+ tpVal |= (mdpImg->tpVal & 0xFF0000);
+ }
+
+ return tpVal;
+}
+
+static uint8 *mdp_get_chroma_addr(MDPIBUF *iBuf)
+{
+ uint8 *dest1;
+
+ dest1 = NULL;
+ switch (iBuf->ibuf_type) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ dest1 = (uint8 *) iBuf->buf;
+ dest1 += iBuf->ibuf_width * iBuf->ibuf_height * iBuf->bpp;
+ break;
+
+ default:
+ break;
+ }
+
+ return dest1;
+}
+
+static void mdp_ppp_setbg(MDPIBUF *iBuf)
+{
+ uint8 *bg0_addr;
+ uint8 *bg1_addr;
+ uint32 bg0_ystride, bg1_ystride;
+ uint32 ppp_src_cfg_reg, unpack_pattern;
+ int v_slice, h_slice;
+
+ v_slice = h_slice = 1;
+ bg0_addr = (uint8 *) iBuf->buf;
+ bg1_addr = mdp_get_chroma_addr(iBuf);
+
+ bg0_ystride = iBuf->ibuf_width * iBuf->bpp;
+ bg1_ystride = iBuf->ibuf_width * iBuf->bpp;
+
+ switch (iBuf->ibuf_type) {
+ case MDP_BGR_565:
+ case MDP_RGB_565:
+ /* 888 = 3bytes
+ * RGB = 3Components
+ * RGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS |
+ PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ if (iBuf->ibuf_type == MDP_RGB_565)
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+ else
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8);
+ break;
+
+ case MDP_RGB_888:
+ /*
+ * 888 = 3bytes
+ * RGB = 3Components
+ * RGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES |
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+ break;
+
+ case MDP_BGRA_8888:
+ case MDP_RGBA_8888:
+ case MDP_ARGB_8888:
+ case MDP_XRGB_8888:
+ /*
+ * 8888 = 4bytes
+ * ARGB = 4Components
+ * ARGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS | PPP_SRC_C3_ALPHA_EN |
+ PPP_SRC_BPP_INTERLVD_4BYTES | PPP_SRC_INTERLVD_4COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ if (iBuf->ibuf_type == MDP_BGRA_8888)
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+ else if (iBuf->ibuf_type == MDP_RGBA_8888)
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R,
+ 8);
+ else
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS |
+ PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS |
+ PPP_SRC_C3A_8BITS |
+ PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_2COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR;
+
+ if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1)
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+ else
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+ v_slice = h_slice = 2;
+ break;
+
+ case MDP_YCRYCB_H2V1:
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS |
+ PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS |
+ PPP_SRC_C3A_8BITS |
+ PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_4COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB;
+
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8);
+ h_slice = 2;
+ break;
+
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS |
+ PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS |
+ PPP_SRC_C3A_8BITS |
+ PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_2COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR;
+
+ if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1)
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+ else
+ unpack_pattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+ h_slice = 2;
+ break;
+
+ default:
+ return;
+ }
+
+ /* starting input address adjustment */
+ mdp_adjust_start_addr(&bg0_addr, &bg1_addr, v_slice, h_slice,
+ iBuf->roi.lcd_x, iBuf->roi.lcd_y,
+ iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp,
+ iBuf, 1);
+
+ /*
+ * 0x01c0: background plane 0 addr
+ * 0x01c4: background plane 1 addr
+ * 0x01c8: background plane 2 addr
+ * 0x01cc: bg y stride for plane 0 and 1
+ * 0x01d0: bg y stride for plane 2
+ * 0x01d4: bg src PPP config
+ * 0x01d8: unpack pattern
+ */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c0, bg0_addr);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01c4, bg1_addr);
+
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01cc,
+ (bg1_ystride << 16) | bg0_ystride);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d4, ppp_src_cfg_reg);
+
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01d8, unpack_pattern);
+}
+
+#define IS_PSEUDOPLNR(img) ((img == MDP_Y_CRCB_H2V2) | \
+ (img == MDP_Y_CBCR_H2V2) | \
+ (img == MDP_Y_CRCB_H2V1) | \
+ (img == MDP_Y_CBCR_H2V1))
+
+#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp)
+
+#define Y_TO_CRCB_RATIO(format) \
+ ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ? 2 :\
+ (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ? 1 : 1)
+
+static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp,
+ uint32_t *len0, uint32_t *len1)
+{
+ *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp);
+ if (IS_PSEUDOPLNR(img->format))
+ *len1 = *len0/Y_TO_CRCB_RATIO(img->format);
+ else
+ *len1 = 0;
+}
+
+static void flush_imgs(struct mdp_blit_req *req, int src_bpp, int dst_bpp,
+ struct file *p_src_file, struct file *p_dst_file)
+{
+#ifdef CONFIG_ANDROID_PMEM
+ uint32_t src0_len, src1_len, dst0_len, dst1_len;
+
+ /* flush src images to memory before dma to mdp */
+ get_len(&req->src, &req->src_rect, src_bpp,
+ &src0_len, &src1_len);
+
+ flush_pmem_file(p_src_file,
+ req->src.offset, src0_len);
+
+ if (IS_PSEUDOPLNR(req->src.format))
+ flush_pmem_file(p_src_file,
+ req->src.offset + src0_len, src1_len);
+
+ get_len(&req->dst, &req->dst_rect, dst_bpp, &dst0_len, &dst1_len);
+ flush_pmem_file(p_dst_file, req->dst.offset, dst0_len);
+
+ if (IS_PSEUDOPLNR(req->dst.format))
+ flush_pmem_file(p_dst_file,
+ req->dst.offset + dst0_len, dst1_len);
+#endif
+}
+
+static void mdp_start_ppp(struct msm_fb_data_type *mfd, MDPIBUF *iBuf,
+struct mdp_blit_req *req, struct file *p_src_file, struct file *p_dst_file)
+{
+ uint8 *src0, *src1;
+ uint8 *dest0, *dest1;
+ uint16 inpBpp;
+ uint32 dest0_ystride;
+ uint32 src_width;
+ uint32 src_height;
+ uint32 src0_ystride;
+ uint32 dst_roi_width;
+ uint32 dst_roi_height;
+ uint32 ppp_src_cfg_reg, ppp_operation_reg, ppp_dst_cfg_reg;
+ uint32 alpha, tpVal;
+ uint32 packPattern;
+ uint32 dst_packPattern;
+ boolean inputRGB, outputRGB, pseudoplanr_output;
+ int sv_slice, sh_slice;
+ int dv_slice, dh_slice;
+ boolean perPixelAlpha = FALSE;
+ boolean ppp_lookUp_enable = FALSE;
+
+ sv_slice = sh_slice = dv_slice = dh_slice = 1;
+ alpha = tpVal = 0;
+ src_width = iBuf->mdpImg.width;
+ src_height = iBuf->roi.y + iBuf->roi.height;
+ src1 = NULL;
+ dest1 = NULL;
+
+ inputRGB = outputRGB = TRUE;
+ pseudoplanr_output = FALSE;
+ ppp_operation_reg = 0;
+ ppp_dst_cfg_reg = 0;
+ ppp_src_cfg_reg = 0;
+
+ /* Wait for the pipe to clear */
+ do { } while (mdp_ppp_pipe_wait() <= 0);
+
+ /*
+ * destination config
+ */
+ switch (iBuf->ibuf_type) {
+ case MDP_RGB_888:
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+ ppp_dst_cfg_reg =
+ PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT | PPP_DST_C2R_8BIT |
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM | PPP_DST_PACK_TIGHT |
+ PPP_DST_PACK_ALIGN_LSB | PPP_DST_OUT_SEL_AXI |
+ PPP_DST_BPP_3BYTES | PPP_DST_PLANE_INTERLVD;
+ break;
+
+ case MDP_XRGB_8888:
+ case MDP_ARGB_8888:
+ case MDP_RGBA_8888:
+ if (iBuf->ibuf_type == MDP_BGRA_8888)
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+ else if (iBuf->ibuf_type == MDP_RGBA_8888)
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R,
+ 8);
+ else
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+
+ ppp_dst_cfg_reg = PPP_DST_C0G_8BIT |
+ PPP_DST_C1B_8BIT |
+ PPP_DST_C2R_8BIT |
+ PPP_DST_C3A_8BIT |
+ PPP_DST_C3ALPHA_EN |
+ PPP_DST_PACKET_CNT_INTERLVD_4ELEM |
+ PPP_DST_PACK_TIGHT |
+ PPP_DST_PACK_ALIGN_LSB |
+ PPP_DST_OUT_SEL_AXI |
+ PPP_DST_BPP_4BYTES | PPP_DST_PLANE_INTERLVD;
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ if (iBuf->ibuf_type == MDP_Y_CBCR_H2V2)
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+ else
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+
+ ppp_dst_cfg_reg = PPP_DST_C2R_8BIT |
+ PPP_DST_C0G_8BIT |
+ PPP_DST_C1B_8BIT |
+ PPP_DST_C3A_8BIT |
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM |
+ PPP_DST_PACK_TIGHT |
+ PPP_DST_PACK_ALIGN_LSB |
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES;
+
+ ppp_operation_reg |= PPP_OP_DST_CHROMA_420;
+ outputRGB = FALSE;
+ pseudoplanr_output = TRUE;
+ /*
+ * vertically (y direction) and horizontally (x direction)
+ * sample reduction by 2
+ */
+
+ /*
+ * H2V2(YUV420) Cosite
+ *
+ * Y Y Y Y
+ * CbCr CbCr
+ * Y Y Y Y
+ * Y Y Y Y
+ * CbCr CbCr
+ * Y Y Y Y
+ */
+ dv_slice = dh_slice = 2;
+
+ /* (x,y) and (width,height) must be even numbern */
+ iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2;
+ iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2;
+ iBuf->roi.x = (iBuf->roi.x / 2) * 2;
+ iBuf->roi.width = (iBuf->roi.width / 2) * 2;
+
+ iBuf->roi.lcd_y = (iBuf->roi.lcd_y / 2) * 2;
+ iBuf->roi.dst_height = (iBuf->roi.dst_height / 2) * 2;
+ iBuf->roi.y = (iBuf->roi.y / 2) * 2;
+ iBuf->roi.height = (iBuf->roi.height / 2) * 2;
+ break;
+
+ case MDP_YCRYCB_H2V1:
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8);
+ ppp_dst_cfg_reg =
+ PPP_DST_C2R_8BIT | PPP_DST_C0G_8BIT | PPP_DST_C1B_8BIT |
+ PPP_DST_C3A_8BIT | PPP_DST_PACKET_CNT_INTERLVD_4ELEM |
+ PPP_DST_PACK_TIGHT | PPP_DST_PACK_ALIGN_LSB |
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES |
+ PPP_DST_PLANE_INTERLVD;
+
+ ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1;
+ outputRGB = FALSE;
+ /*
+ * horizontally (x direction) sample reduction by 2
+ *
+ * H2V1(YUV422) Cosite
+ *
+ * YCbCr Y YCbCr Y
+ * YCbCr Y YCbCr Y
+ * YCbCr Y YCbCr Y
+ * YCbCr Y YCbCr Y
+ */
+ dh_slice = 2;
+
+ /*
+ * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the
+ * preloaded gamma setting of 2.2 when the content is
+ * non-linear ppp_lookUp_enable = TRUE;
+ */
+
+ /* x and width must be even number */
+ iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2;
+ iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2;
+ iBuf->roi.x = (iBuf->roi.x / 2) * 2;
+ iBuf->roi.width = (iBuf->roi.width / 2) * 2;
+ break;
+
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ if (iBuf->ibuf_type == MDP_Y_CBCR_H2V1)
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+ else
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+
+ ppp_dst_cfg_reg = PPP_DST_C2R_8BIT |
+ PPP_DST_C0G_8BIT |
+ PPP_DST_C1B_8BIT |
+ PPP_DST_C3A_8BIT |
+ PPP_DST_PACKET_CNT_INTERLVD_2ELEM |
+ PPP_DST_PACK_TIGHT |
+ PPP_DST_PACK_ALIGN_LSB |
+ PPP_DST_OUT_SEL_AXI | PPP_DST_BPP_2BYTES;
+
+ ppp_operation_reg |= PPP_OP_DST_CHROMA_H2V1;
+ outputRGB = FALSE;
+ pseudoplanr_output = TRUE;
+ /* horizontally (x direction) sample reduction by 2 */
+ dh_slice = 2;
+
+ /* x and width must be even number */
+ iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2;
+ iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2;
+ iBuf->roi.x = (iBuf->roi.x / 2) * 2;
+ iBuf->roi.width = (iBuf->roi.width / 2) * 2;
+ break;
+
+ case MDP_BGR_565:
+ case MDP_RGB_565:
+ default:
+ if (iBuf->ibuf_type == MDP_RGB_565)
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+ else
+ dst_packPattern =
+ MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8);
+
+ ppp_dst_cfg_reg = PPP_DST_C0G_6BIT |
+ PPP_DST_C1B_5BIT |
+ PPP_DST_C2R_5BIT |
+ PPP_DST_PACKET_CNT_INTERLVD_3ELEM |
+ PPP_DST_PACK_TIGHT |
+ PPP_DST_PACK_ALIGN_LSB |
+ PPP_DST_OUT_SEL_AXI |
+ PPP_DST_BPP_2BYTES | PPP_DST_PLANE_INTERLVD;
+ break;
+ }
+
+ /* source config */
+ switch (iBuf->mdpImg.imgType) {
+ case MDP_RGB_888:
+ inpBpp = 3;
+ /*
+ * 565 = 2bytes
+ * RGB = 3Components
+ * RGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_3BYTES |
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ packPattern = MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+
+ ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB |
+ PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB;
+ break;
+
+ case MDP_BGRA_8888:
+ case MDP_RGBA_8888:
+ case MDP_ARGB_8888:
+ perPixelAlpha = TRUE;
+ case MDP_XRGB_8888:
+ inpBpp = 4;
+ /*
+ * 8888 = 4bytes
+ * ARGB = 4Components
+ * ARGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS | PPP_SRC_C3A_8BITS |
+ PPP_SRC_C3_ALPHA_EN | PPP_SRC_BPP_INTERLVD_4BYTES |
+ PPP_SRC_INTERLVD_4COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ if (iBuf->mdpImg.imgType == MDP_BGRA_8888)
+ packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+ else if (iBuf->mdpImg.imgType == MDP_RGBA_8888)
+ packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R,
+ 8);
+ else
+ packPattern =
+ MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B,
+ 8);
+
+ ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB |
+ PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB;
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ inpBpp = 1;
+ src1 = (uint8 *) iBuf->mdpImg.cbcr_addr;
+
+ /*
+ * CbCr = 2bytes
+ * CbCr = 2Components
+ * Y+CbCr
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS | PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS | PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_2COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_PSEUDOPLNR;
+
+ if (iBuf->mdpImg.imgType == MDP_Y_CRCB_H2V2)
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+ else
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+
+ ppp_operation_reg |= PPP_OP_COLOR_SPACE_YCBCR |
+ PPP_OP_SRC_CHROMA_420 |
+ PPP_OP_SRC_CHROMA_COSITE |
+ PPP_OP_DST_CHROMA_RGB | PPP_OP_DST_CHROMA_COSITE;
+
+ inputRGB = FALSE;
+ sh_slice = sv_slice = 2;
+ break;
+
+ case MDP_YCRYCB_H2V1:
+ inpBpp = 2;
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS |
+ PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS |
+ PPP_SRC_C3A_8BITS |
+ PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_4COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT | PPP_SRC_UNPACK_ALIGN_LSB;
+
+ packPattern =
+ MDP_GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8);
+
+ ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 |
+ PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE;
+
+ /*
+ * if it's TV-Out/MDP_YCRYCB_H2V1, let's go through the
+ * preloaded inverse gamma setting of 2.2 since they're
+ * symetric when the content is non-linear
+ * ppp_lookUp_enable = TRUE;
+ */
+
+ /* x and width must be even number */
+ iBuf->roi.lcd_x = (iBuf->roi.lcd_x / 2) * 2;
+ iBuf->roi.dst_width = (iBuf->roi.dst_width / 2) * 2;
+ iBuf->roi.x = (iBuf->roi.x / 2) * 2;
+ iBuf->roi.width = (iBuf->roi.width / 2) * 2;
+
+ inputRGB = FALSE;
+ sh_slice = 2;
+ break;
+
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ inpBpp = 1;
+ src1 = (uint8 *) iBuf->mdpImg.cbcr_addr;
+
+ ppp_src_cfg_reg = PPP_SRC_C2R_8BITS |
+ PPP_SRC_C0G_8BITS |
+ PPP_SRC_C1B_8BITS |
+ PPP_SRC_C3A_8BITS |
+ PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_2COMPONENTS |
+ PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB | PPP_SRC_FETCH_PLANES_PSEUDOPLNR;
+
+ if (iBuf->mdpImg.imgType == MDP_Y_CBCR_H2V1)
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8);
+ else
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8);
+
+ ppp_operation_reg |= PPP_OP_SRC_CHROMA_H2V1 |
+ PPP_OP_SRC_CHROMA_COSITE | PPP_OP_DST_CHROMA_COSITE;
+ inputRGB = FALSE;
+ sh_slice = 2;
+ break;
+
+ case MDP_BGR_565:
+ case MDP_RGB_565:
+ default:
+ inpBpp = 2;
+ /*
+ * 565 = 2bytes
+ * RGB = 3Components
+ * RGB interleaved
+ */
+ ppp_src_cfg_reg = PPP_SRC_C2R_5BITS | PPP_SRC_C0G_6BITS |
+ PPP_SRC_C1B_5BITS | PPP_SRC_BPP_INTERLVD_2BYTES |
+ PPP_SRC_INTERLVD_3COMPONENTS | PPP_SRC_UNPACK_TIGHT |
+ PPP_SRC_UNPACK_ALIGN_LSB |
+ PPP_SRC_FETCH_PLANES_INTERLVD;
+
+ if (iBuf->mdpImg.imgType == MDP_RGB_565)
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8);
+ else
+ packPattern =
+ MDP_GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8);
+
+ ppp_operation_reg |= PPP_OP_COLOR_SPACE_RGB |
+ PPP_OP_SRC_CHROMA_RGB | PPP_OP_DST_CHROMA_RGB;
+ break;
+
+ }
+
+ if (pseudoplanr_output)
+ ppp_dst_cfg_reg |= PPP_DST_PLANE_PSEUDOPLN;
+
+ /* YCbCr to RGB color conversion flag */
+ if ((!inputRGB) && (outputRGB)) {
+ ppp_operation_reg |= PPP_OP_CONVERT_YCBCR2RGB |
+ PPP_OP_CONVERT_ON;
+
+ /*
+ * primary/secondary is sort of misleading term...but
+ * in mdp2.2/3.0 we only use primary matrix (forward/rev)
+ * in mdp3.1 we use set1(prim) and set2(secd)
+ */
+#ifdef CONFIG_FB_MSM_MDP31
+ ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_SECONDARY |
+ PPP_OP_DST_RGB;
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0);
+#endif
+
+ if (ppp_lookUp_enable) {
+ ppp_operation_reg |= PPP_OP_LUT_C0_ON |
+ PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON;
+ }
+ }
+ /* RGB to YCbCr color conversion flag */
+ if ((inputRGB) && (!outputRGB)) {
+ ppp_operation_reg |= PPP_OP_CONVERT_RGB2YCBCR |
+ PPP_OP_CONVERT_ON;
+
+#ifdef CONFIG_FB_MSM_MDP31
+ ppp_operation_reg |= PPP_OP_CONVERT_MATRIX_PRIMARY |
+ PPP_OP_DST_YCBCR;
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0240, 0x1e);
+#endif
+
+ if (ppp_lookUp_enable) {
+ ppp_operation_reg |= PPP_OP_LUT_C0_ON |
+ PPP_OP_LUT_C1_ON | PPP_OP_LUT_C2_ON;
+ }
+ }
+ /* YCbCr to YCbCr color conversion flag */
+ if ((!inputRGB) && (!outputRGB)) {
+ if ((ppp_lookUp_enable) &&
+ (iBuf->mdpImg.imgType != iBuf->ibuf_type)) {
+ ppp_operation_reg |= PPP_OP_LUT_C0_ON;
+ }
+ }
+
+ ppp_src_cfg_reg |= (iBuf->roi.x % 2) ? PPP_SRC_BPP_ROI_ODD_X : 0;
+ ppp_src_cfg_reg |= (iBuf->roi.y % 2) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
+
+ if (req->flags & MDP_DEINTERLACE)
+ ppp_operation_reg |= PPP_OP_DEINT_EN;
+
+ /* Dither at DMA side only since iBuf format is RGB888 */
+ if (iBuf->mdpImg.mdpOp & MDPOP_DITHER)
+ ppp_operation_reg |= PPP_OP_DITHER_EN;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_ROTATION) {
+ ppp_operation_reg |= PPP_OP_ROT_ON;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
+ ppp_operation_reg |= PPP_OP_ROT_90;
+ }
+ if (iBuf->mdpImg.mdpOp & MDPOP_LR) {
+ ppp_operation_reg |= PPP_OP_FLIP_LR;
+ }
+ if (iBuf->mdpImg.mdpOp & MDPOP_UD) {
+ ppp_operation_reg |= PPP_OP_FLIP_UD;
+ }
+ }
+
+ src0_ystride = src_width * inpBpp;
+ dest0_ystride = iBuf->ibuf_width * iBuf->bpp;
+
+ /* no need to care about rotation since it's the real-XY. */
+ dst_roi_width = iBuf->roi.dst_width;
+ dst_roi_height = iBuf->roi.dst_height;
+
+ src0 = (uint8 *) iBuf->mdpImg.bmy_addr;
+ dest0 = (uint8 *) iBuf->buf;
+
+ /* Jumping from Y-Plane to Chroma Plane */
+ dest1 = mdp_get_chroma_addr(iBuf);
+
+ /* first pixel addr calculation */
+ mdp_adjust_start_addr(&src0, &src1, sv_slice, sh_slice, iBuf->roi.x,
+ iBuf->roi.y, src_width, src_height, inpBpp, iBuf,
+ 0);
+ mdp_adjust_start_addr(&dest0, &dest1, dv_slice, dh_slice,
+ iBuf->roi.lcd_x, iBuf->roi.lcd_y,
+ iBuf->ibuf_width, iBuf->ibuf_height, iBuf->bpp,
+ iBuf, 2);
+
+ /* set scale operation */
+ mdp_set_scale(iBuf, dst_roi_width, dst_roi_height,
+ inputRGB, outputRGB, &ppp_operation_reg);
+
+ /*
+ * setting background source for blending
+ */
+ mdp_set_blend_attr(iBuf, &alpha, &tpVal, perPixelAlpha,
+ &ppp_operation_reg);
+
+ if (ppp_operation_reg & PPP_OP_BLEND_ON) {
+ mdp_ppp_setbg(iBuf);
+
+ if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) {
+ ppp_operation_reg |= PPP_OP_BG_CHROMA_H2V1;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
+ tpVal = mdp_conv_matx_rgb2yuv(tpVal,
+ (uint16 *) &
+ mdp_ccs_rgb2yuv,
+ &mdp_plv[0], NULL);
+ }
+ }
+ }
+
+ /*
+ * 0x0004: enable dbg bus
+ * 0x0100: "don't care" Edge Condit until scaling is on
+ * 0x0104: xrc tile x&y size u7.6 format = 7bit.6bit
+ * 0x0108: src pixel size
+ * 0x010c: component plane 0 starting address
+ * 0x011c: component plane 0 ystride
+ * 0x0124: PPP source config register
+ * 0x0128: unpacked pattern from lsb to msb (eg. RGB->BGR)
+ */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0108, (iBuf->roi.height << 16 |
+ iBuf->roi.width));
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x010c, src0); /* comp.plane 0 */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0110, src1); /* comp.plane 1 */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x011c,
+ (src0_ystride << 16 | src0_ystride));
+
+ /* setup for rgb 565 */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0124, ppp_src_cfg_reg);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0128, packPattern);
+ /*
+ * 0x0138: PPP destination operation register
+ * 0x014c: constant_alpha|transparent_color
+ * 0x0150: PPP destination config register
+ * 0x0154: PPP packing pattern
+ */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0138, ppp_operation_reg);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x014c, alpha << 24 | tpVal);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0150, ppp_dst_cfg_reg);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0154, dst_packPattern);
+
+ /*
+ * 0x0164: ROI height and width
+ * 0x0168: Component Plane 0 starting addr
+ * 0x016c: Component Plane 1 starting addr
+ * 0x0178: Component Plane 1/0 y stride
+ */
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0164,
+ (dst_roi_height << 16 | dst_roi_width));
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0168, dest0);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x016c, dest1);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0178,
+ (dest0_ystride << 16 | dest0_ystride));
+
+ flush_imgs(req, inpBpp, iBuf->bpp, p_src_file, p_dst_file);
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+ mdp_ppp_process_curr_djob();
+#else
+ mdp_pipe_kickoff(MDP_PPP_TERM, mfd);
+#endif
+}
+
+static int mdp_ppp_verify_req(struct mdp_blit_req *req)
+{
+ u32 src_width, src_height, dst_width, dst_height;
+
+ if (req == NULL)
+ return -1;
+
+ if (MDP_IS_IMGTYPE_BAD(req->src.format) ||
+ MDP_IS_IMGTYPE_BAD(req->dst.format))
+ return -1;
+
+ if ((req->src.width == 0) || (req->src.height == 0) ||
+ (req->src_rect.w == 0) || (req->src_rect.h == 0) ||
+ (req->dst.width == 0) || (req->dst.height == 0) ||
+ (req->dst_rect.w == 0) || (req->dst_rect.h == 0))
+
+ return -1;
+
+ if (((req->src_rect.x + req->src_rect.w) > req->src.width) ||
+ ((req->src_rect.y + req->src_rect.h) > req->src.height))
+ return -1;
+
+ if (((req->dst_rect.x + req->dst_rect.w) > req->dst.width) ||
+ ((req->dst_rect.y + req->dst_rect.h) > req->dst.height))
+ return -1;
+
+ /*
+ * scaling range check
+ */
+ src_width = req->src_rect.w;
+ src_height = req->src_rect.h;
+
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ switch (req->dst.format) {
+ case MDP_Y_CRCB_H2V2:
+ case MDP_Y_CBCR_H2V2:
+ src_width = (src_width / 2) * 2;
+ src_height = (src_height / 2) * 2;
+ dst_width = (src_width / 2) * 2;
+ dst_height = (src_height / 2) * 2;
+ break;
+
+ case MDP_Y_CRCB_H2V1:
+ case MDP_Y_CBCR_H2V1:
+ case MDP_YCRYCB_H2V1:
+ src_width = (src_width / 2) * 2;
+ dst_width = (src_width / 2) * 2;
+ break;
+
+ default:
+ break;
+ }
+
+ if (((MDP_SCALE_Q_FACTOR * dst_width) / src_width >
+ MDP_MAX_X_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_width) / src_width <
+ MDP_MIN_X_SCALE_FACTOR))
+ return -1;
+
+ if (((MDP_SCALE_Q_FACTOR * dst_height) / src_height >
+ MDP_MAX_Y_SCALE_FACTOR)
+ || ((MDP_SCALE_Q_FACTOR * dst_height) / src_height <
+ MDP_MIN_Y_SCALE_FACTOR))
+ return -1;
+
+ return 0;
+}
+
+/**
+ * get_gem_img() - retrieve drm obj's start address and size
+ * @img: contains drm file descriptor and gem handle
+ * @start: repository of starting address of drm obj allocated memory
+ * @len: repository of size of drm obj alloacted memory
+ *
+ **/
+int get_gem_img(struct mdp_img *img, unsigned long *start, unsigned long *len)
+{
+ panic("waaaaaaaah");
+ //return kgsl_gem_obj_addr(img->memory_id, (int)img->priv, start, len);
+}
+
+int get_img(struct mdp_img *img, struct fb_info *info, unsigned long *start,
+ unsigned long *len, struct file **pp_file)
+{
+ int put_needed, ret = 0;
+ struct file *file;
+ unsigned long vstart;
+#ifdef CONFIG_ANDROID_PMEM
+ if (!get_pmem_file(img->memory_id, start, &vstart, len, pp_file))
+ return 0;
+#endif
+ file = fget_light(img->memory_id, &put_needed);
+ if (file == NULL)
+ return -1;
+
+ if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
+ *start = info->fix.smem_start;
+ *len = info->fix.smem_len;
+ *pp_file = file;
+ } else {
+ ret = -1;
+ fput_light(file, put_needed);
+ }
+ return ret;
+}
+
+int mdp_ppp_blit(struct fb_info *info, struct mdp_blit_req *req,
+ struct file **pp_src_file, struct file **pp_dst_file)
+{
+ unsigned long src_start, dst_start;
+ unsigned long src_len = 0;
+ unsigned long dst_len = 0;
+ MDPIBUF iBuf;
+ u32 dst_width, dst_height;
+ struct file *p_src_file = 0 , *p_dst_file = 0;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (req->dst.format == MDP_FB_FORMAT)
+ req->dst.format = mfd->fb_imgType;
+ if (req->src.format == MDP_FB_FORMAT)
+ req->src.format = mfd->fb_imgType;
+
+ if (req->flags & MDP_BLIT_SRC_GEM) {
+ if (get_gem_img(&req->src, &src_start, &src_len) < 0)
+ return -1;
+ } else {
+ get_img(&req->src, info, &src_start, &src_len, &p_src_file);
+ }
+ if (src_len == 0) {
+ printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ "memory\n");
+ return -1;
+ }
+
+ if (req->flags & MDP_BLIT_DST_GEM) {
+ if (get_gem_img(&req->dst, &dst_start, &dst_len) < 0)
+ return -1;
+ } else {
+ get_img(&req->dst, info, &dst_start, &dst_len, &p_dst_file);
+ }
+ if (dst_len == 0) {
+ printk(KERN_ERR "mdp_ppp: could not retrieve image from "
+ "memory\n");
+ return -1;
+ }
+ *pp_src_file = p_src_file;
+ *pp_dst_file = p_dst_file;
+ if (mdp_ppp_verify_req(req)) {
+ printk(KERN_ERR "mdp_ppp: invalid image!\n");
+ return -1;
+ }
+
+ iBuf.ibuf_width = req->dst.width;
+ iBuf.ibuf_height = req->dst.height;
+ iBuf.bpp = bytes_per_pixel[req->dst.format];
+
+ iBuf.ibuf_type = req->dst.format;
+ iBuf.buf = (uint8 *) dst_start;
+ iBuf.buf += req->dst.offset;
+
+ iBuf.roi.lcd_x = req->dst_rect.x;
+ iBuf.roi.lcd_y = req->dst_rect.y;
+ iBuf.roi.dst_width = req->dst_rect.w;
+ iBuf.roi.dst_height = req->dst_rect.h;
+
+ iBuf.roi.x = req->src_rect.x;
+ iBuf.roi.width = req->src_rect.w;
+ iBuf.roi.y = req->src_rect.y;
+ iBuf.roi.height = req->src_rect.h;
+
+ iBuf.mdpImg.width = req->src.width;
+ iBuf.mdpImg.imgType = req->src.format;
+
+ iBuf.mdpImg.bmy_addr = (uint32 *) (src_start + req->src.offset);
+ iBuf.mdpImg.cbcr_addr =
+ (uint32 *) ((uint32) iBuf.mdpImg.bmy_addr +
+ req->src.width * req->src.height);
+
+ iBuf.mdpImg.mdpOp = MDPOP_NOP;
+
+ /* blending check */
+ if (req->transp_mask != MDP_TRANSP_NOP) {
+ iBuf.mdpImg.mdpOp |= MDPOP_TRANSP;
+ iBuf.mdpImg.tpVal = req->transp_mask;
+ iBuf.mdpImg.tpVal = mdp_calc_tpval(&iBuf.mdpImg);
+ }
+
+ req->alpha &= 0xff;
+ if (req->alpha < MDP_ALPHA_NOP) {
+ iBuf.mdpImg.mdpOp |= MDPOP_ALPHAB;
+ iBuf.mdpImg.alpha = req->alpha;
+ }
+
+ /* rotation check */
+ if (req->flags & MDP_FLIP_LR)
+ iBuf.mdpImg.mdpOp |= MDPOP_LR;
+ if (req->flags & MDP_FLIP_UD)
+ iBuf.mdpImg.mdpOp |= MDPOP_UD;
+ if (req->flags & MDP_ROT_90)
+ iBuf.mdpImg.mdpOp |= MDPOP_ROT90;
+ if (req->flags & MDP_DITHER)
+ iBuf.mdpImg.mdpOp |= MDPOP_DITHER;
+
+ if (req->flags & MDP_BLEND_FG_PREMULT) {
+#ifdef CONFIG_FB_MSM_MDP31
+ iBuf.mdpImg.mdpOp |= MDPOP_FG_PM_ALPHA;
+#else
+ return -EINVAL;
+#endif
+ }
+
+ if (req->flags & MDP_DEINTERLACE) {
+#ifdef CONFIG_FB_MSM_MDP31
+ if ((req->src.format != MDP_Y_CBCR_H2V2) &&
+ (req->src.format != MDP_Y_CRCB_H2V2))
+#endif
+ return -EINVAL;
+ }
+
+ /* scale check */
+ if (req->flags & MDP_ROT_90) {
+ dst_width = req->dst_rect.h;
+ dst_height = req->dst_rect.w;
+ } else {
+ dst_width = req->dst_rect.w;
+ dst_height = req->dst_rect.h;
+ }
+
+ if ((iBuf.roi.width != dst_width) || (iBuf.roi.height != dst_height))
+ iBuf.mdpImg.mdpOp |= MDPOP_ASCALE;
+
+ if (req->flags & MDP_BLUR) {
+#ifdef CONFIG_FB_MSM_MDP31
+ if (req->flags & MDP_SHARPENING)
+ printk(KERN_WARNING
+ "mdp: MDP_SHARPENING is set with MDP_BLUR!\n");
+ req->flags |= MDP_SHARPENING;
+ req->sharpening_strength = -127;
+#else
+ iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_BLUR;
+
+#endif
+ }
+
+ if (req->flags & MDP_SHARPENING) {
+#ifdef CONFIG_FB_MSM_MDP31
+ if ((req->sharpening_strength > 127) ||
+ (req->sharpening_strength < -127)) {
+ printk(KERN_ERR
+ "%s: sharpening strength out of range\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ iBuf.mdpImg.mdpOp |= MDPOP_ASCALE | MDPOP_SHARPENING;
+ iBuf.mdpImg.sp_value = req->sharpening_strength & 0xff;
+#else
+ return -EINVAL;
+#endif
+ }
+
+ down(&mdp_ppp_mutex);
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+#ifdef CONFIG_FB_MSM_MDP31
+ mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file);
+#else
+ /* bg tile fetching HW workaround */
+ if (((iBuf.mdpImg.mdpOp & (MDPOP_TRANSP | MDPOP_ALPHAB)) ||
+ (req->src.format == MDP_ARGB_8888) ||
+ (req->src.format == MDP_BGRA_8888) ||
+ (req->src.format == MDP_RGBA_8888)) &&
+ (iBuf.mdpImg.mdpOp & MDPOP_ROT90) && (req->dst_rect.w <= 16)) {
+ int dst_h, src_w, i;
+
+ src_w = req->src_rect.w;
+ dst_h = iBuf.roi.dst_height;
+
+ for (i = 0; i < (req->dst_rect.h / 16); i++) {
+ /* this tile size */
+ iBuf.roi.dst_height = 16;
+ iBuf.roi.width =
+ (16 * req->src_rect.w) / req->dst_rect.h;
+
+ /* if it's out of scale range... */
+ if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR)
+ iBuf.roi.width =
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ MDP_MAX_X_SCALE_FACTOR;
+ else if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR)
+ iBuf.roi.width =
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ MDP_MIN_X_SCALE_FACTOR;
+
+ mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file);
+
+ /* next tile location */
+ iBuf.roi.lcd_y += 16;
+ iBuf.roi.x += iBuf.roi.width;
+
+ /* this is for a remainder update */
+ dst_h -= 16;
+ src_w -= iBuf.roi.width;
+ }
+
+ if ((dst_h < 0) || (src_w < 0))
+ printk
+ ("msm_fb: mdp_blt_ex() unexpected result! line:%d\n",
+ __LINE__);
+
+ /* remainder update */
+ if ((dst_h > 0) && (src_w > 0)) {
+ u32 tmp_v;
+
+ iBuf.roi.dst_height = dst_h;
+ iBuf.roi.width = src_w;
+
+ if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ iBuf.roi.width) > MDP_MAX_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ MDP_MAX_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) %
+ MDP_MAX_X_SCALE_FACTOR ? 1 : 0;
+
+ /* move x location as roi width gets bigger */
+ iBuf.roi.x -= tmp_v - iBuf.roi.width;
+ iBuf.roi.width = tmp_v;
+ } else
+ if (((MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ iBuf.roi.width) < MDP_MIN_X_SCALE_FACTOR) {
+ tmp_v =
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) /
+ MDP_MIN_X_SCALE_FACTOR +
+ (MDP_SCALE_Q_FACTOR * iBuf.roi.dst_height) %
+ MDP_MIN_X_SCALE_FACTOR ? 1 : 0;
+
+ /*
+ * we don't move x location for continuity of
+ * source image
+ */
+ iBuf.roi.width = tmp_v;
+ }
+
+ mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file);
+ }
+ } else {
+ mdp_start_ppp(mfd, &iBuf, req, p_src_file, p_dst_file);
+ }
+#endif
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ up(&mdp_ppp_mutex);
+
+ return 0;
+}
diff --git a/drivers/staging/msm/mdp_ppp_dq.c b/drivers/staging/msm/mdp_ppp_dq.c
new file mode 100644
index 000000000000..3dc1c0cc61f9
--- /dev/null
+++ b/drivers/staging/msm/mdp_ppp_dq.c
@@ -0,0 +1,347 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "mdp.h"
+
+static boolean mdp_ppp_intr_flag = FALSE;
+static boolean mdp_ppp_busy_flag = FALSE;
+
+/* Queue to keep track of the completed jobs for cleaning */
+static LIST_HEAD(mdp_ppp_djob_clnrq);
+static DEFINE_SPINLOCK(mdp_ppp_djob_clnrq_lock);
+
+/* Worker to cleanup Display Jobs */
+static struct workqueue_struct *mdp_ppp_djob_clnr;
+
+/* Display Queue (DQ) for MDP PPP Block */
+static LIST_HEAD(mdp_ppp_dq);
+static DEFINE_SPINLOCK(mdp_ppp_dq_lock);
+
+/* Current Display Job for MDP PPP */
+static struct mdp_ppp_djob *curr_djob;
+
+/* Track ret code for the last opeartion */
+static int mdp_ppp_ret_code;
+
+inline int mdp_ppp_get_ret_code(void)
+{
+ return mdp_ppp_ret_code;
+}
+
+/* Push <Reg, Val> pair into DQ (if available) to later
+ * program the MDP PPP Block */
+inline void mdp_ppp_outdw(uint32_t addr, uint32_t data)
+{
+ if (curr_djob) {
+
+ /* get the last node of the list. */
+ struct mdp_ppp_roi_cmd_set *node =
+ list_entry(curr_djob->roi_cmd_list.prev,
+ struct mdp_ppp_roi_cmd_set, node);
+
+ /* If a node is already full, create a new one and add it to
+ * the list (roi_cmd_list).
+ */
+ if (node->ncmds == MDP_PPP_ROI_NODE_SIZE) {
+ node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set),
+ GFP_KERNEL);
+ if (!node) {
+ printk(KERN_ERR
+ "MDP_PPP: not enough memory.\n");
+ mdp_ppp_ret_code = -EINVAL;
+ return;
+ }
+
+ /* no ROI commands initially */
+ node->ncmds = 0;
+
+ /* add one node to roi_cmd_list. */
+ list_add_tail(&node->node, &curr_djob->roi_cmd_list);
+ }
+
+ /* register ROI commands */
+ node->cmd[node->ncmds].reg = addr;
+ node->cmd[node->ncmds].val = data;
+ node->ncmds++;
+ } else
+ /* program MDP PPP block now */
+ outpdw((addr), (data));
+}
+
+/* Initialize DQ */
+inline void mdp_ppp_dq_init(void)
+{
+ mdp_ppp_djob_clnr = create_singlethread_workqueue("MDPDJobClnrThrd");
+}
+
+/* Release resources of a job (DJob). */
+static void mdp_ppp_del_djob(struct mdp_ppp_djob *job)
+{
+ struct mdp_ppp_roi_cmd_set *node, *tmp;
+
+ /* release mem */
+ mdp_ppp_put_img(job->p_src_file, job->p_dst_file);
+
+ /* release roi_cmd_list */
+ list_for_each_entry_safe(node, tmp, &job->roi_cmd_list, node) {
+ list_del(&node->node);
+ kfree(node);
+ }
+
+ /* release job struct */
+ kfree(job);
+}
+
+/* Worker thread to reclaim resources once a display job is done */
+static void mdp_ppp_djob_cleaner(struct work_struct *work)
+{
+ struct mdp_ppp_djob *job;
+
+ MDP_PPP_DEBUG_MSG("mdp ppp display job cleaner started \n");
+
+ /* cleanup display job */
+ job = container_of(work, struct mdp_ppp_djob, cleaner.work);
+ if (likely(work && job))
+ mdp_ppp_del_djob(job);
+}
+
+/* Create a new Display Job (DJob) */
+inline struct mdp_ppp_djob *mdp_ppp_new_djob(void)
+{
+ struct mdp_ppp_djob *job;
+ struct mdp_ppp_roi_cmd_set *node;
+
+ /* create a new djob */
+ job = kmalloc(sizeof(struct mdp_ppp_djob), GFP_KERNEL);
+ if (!job)
+ return NULL;
+
+ /* add the first node to curr_djob->roi_cmd_list */
+ node = kmalloc(sizeof(struct mdp_ppp_roi_cmd_set), GFP_KERNEL);
+ if (!node) {
+ kfree(job);
+ return NULL;
+ }
+
+ /* make this current djob container to keep track of the curr djob not
+ * used in the async path i.e. no sync needed
+ *
+ * Should not contain any references from the past djob
+ */
+ BUG_ON(curr_djob);
+ curr_djob = job;
+ INIT_LIST_HEAD(&curr_djob->roi_cmd_list);
+
+ /* no ROI commands initially */
+ node->ncmds = 0;
+ INIT_LIST_HEAD(&node->node);
+ list_add_tail(&node->node, &curr_djob->roi_cmd_list);
+
+ /* register this djob with the djob cleaner
+ * initializes 'work' data struct
+ */
+ INIT_DELAYED_WORK(&curr_djob->cleaner, mdp_ppp_djob_cleaner);
+ INIT_LIST_HEAD(&curr_djob->entry);
+
+ curr_djob->p_src_file = 0;
+ curr_djob->p_dst_file = 0;
+
+ return job;
+}
+
+/* Undo the effect of mdp_ppp_new_djob() */
+inline void mdp_ppp_clear_curr_djob(void)
+{
+ if (likely(curr_djob)) {
+ mdp_ppp_del_djob(curr_djob);
+ curr_djob = NULL;
+ }
+}
+
+/* Cleanup dirty djobs */
+static void mdp_ppp_flush_dirty_djobs(void *cond)
+{
+ unsigned long flags;
+ struct mdp_ppp_djob *job;
+
+ /* Flush the jobs from the djob clnr queue */
+ while (cond && test_bit(0, (unsigned long *)cond)) {
+
+ /* Until we are done with the cleanup queue */
+ spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
+ if (list_empty(&mdp_ppp_djob_clnrq)) {
+ spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
+ break;
+ }
+
+ MDP_PPP_DEBUG_MSG("flushing djobs ... loop \n");
+
+ /* Retrieve the job that needs to be cleaned */
+ job = list_entry(mdp_ppp_djob_clnrq.next,
+ struct mdp_ppp_djob, entry);
+ list_del_init(&job->entry);
+ spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
+
+ /* Keep mem state coherent */
+ msm_fb_ensure_mem_coherency_after_dma(job->info, &job->req, 1);
+
+ /* Schedule jobs for cleanup
+ * A seperate worker thread does this */
+ queue_delayed_work(mdp_ppp_djob_clnr, &job->cleaner,
+ mdp_timer_duration);
+ }
+}
+
+/* If MDP PPP engine is busy, wait until it is available again */
+void mdp_ppp_wait(void)
+{
+ unsigned long flags;
+ int cond = 1;
+
+ /* keep flushing dirty djobs as long as MDP PPP engine is busy */
+ mdp_ppp_flush_dirty_djobs(&mdp_ppp_busy_flag);
+
+ /* block if MDP PPP engine is still busy */
+ spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
+ if (test_bit(0, (unsigned long *)&mdp_ppp_busy_flag)) {
+
+ /* prepare for the wakeup event */
+ test_and_set_bit(0, (unsigned long *)&mdp_ppp_waiting);
+ INIT_COMPLETION(mdp_ppp_comp);
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+
+ /* block uninterruptibly until available */
+ MDP_PPP_DEBUG_MSG("waiting for mdp... \n");
+ wait_for_completion_killable(&mdp_ppp_comp);
+
+ /* if MDP PPP engine is still free,
+ * disable INT_MDP if enabled
+ */
+ spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
+ if (!test_bit(0, (unsigned long *)&mdp_ppp_busy_flag) &&
+ test_and_clear_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
+ mdp_disable_irq(MDP_PPP_TERM);
+ }
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+
+ /* flush remaining dirty djobs, if any */
+ mdp_ppp_flush_dirty_djobs(&cond);
+}
+
+/* Program MDP PPP block to process this ROI */
+static void mdp_ppp_process_roi(struct list_head *roi_cmd_list)
+{
+
+ /* program PPP engine with registered ROI commands */
+ struct mdp_ppp_roi_cmd_set *node;
+ list_for_each_entry(node, roi_cmd_list, node) {
+ int i = 0;
+ for (; i < node->ncmds; i++) {
+ MDP_PPP_DEBUG_MSG("%d: reg: 0x%x val: 0x%x \n",
+ i, node->cmd[i].reg, node->cmd[i].val);
+ outpdw(node->cmd[i].reg, node->cmd[i].val);
+ }
+ }
+
+ /* kickoff MDP PPP engine */
+ MDP_PPP_DEBUG_MSG("kicking off mdp \n");
+ outpdw(MDP_BASE + 0x30, 0x1000);
+}
+
+/* Submit this display job to MDP PPP engine */
+static void mdp_ppp_dispatch_djob(struct mdp_ppp_djob *job)
+{
+ /* enable INT_MDP if disabled */
+ if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_intr_flag))
+ mdp_enable_irq(MDP_PPP_TERM);
+
+ /* turn on PPP and CMD blocks */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ /* process this ROI */
+ mdp_ppp_process_roi(&job->roi_cmd_list);
+}
+
+/* Enqueue this display job to be cleaned up later in "mdp_ppp_djob_done" */
+static inline void mdp_ppp_enqueue_djob(struct mdp_ppp_djob *job)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
+ list_add_tail(&job->entry, &mdp_ppp_dq);
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+}
+
+/* First enqueue display job for cleanup and dispatch immediately
+ * if MDP PPP engine is free */
+void mdp_ppp_process_curr_djob(void)
+{
+ /* enqueue djob */
+ mdp_ppp_enqueue_djob(curr_djob);
+
+ /* dispatch now if MDP PPP engine is free */
+ if (!test_and_set_bit(0, (unsigned long *)&mdp_ppp_busy_flag))
+ mdp_ppp_dispatch_djob(curr_djob);
+
+ /* done with the current djob */
+ curr_djob = NULL;
+}
+
+/* Called from mdp_isr - cleanup finished job and start with next
+ * if available else set MDP PPP engine free */
+void mdp_ppp_djob_done(void)
+{
+ struct mdp_ppp_djob *curr, *next;
+ unsigned long flags;
+
+ /* dequeue current */
+ spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
+ curr = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob, entry);
+ list_del_init(&curr->entry);
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+
+ /* cleanup current - enqueue in the djob clnr queue */
+ spin_lock_irqsave(&mdp_ppp_djob_clnrq_lock, flags);
+ list_add_tail(&curr->entry, &mdp_ppp_djob_clnrq);
+ spin_unlock_irqrestore(&mdp_ppp_djob_clnrq_lock, flags);
+
+ /* grab next pending */
+ spin_lock_irqsave(&mdp_ppp_dq_lock, flags);
+ if (!list_empty(&mdp_ppp_dq)) {
+ next = list_entry(mdp_ppp_dq.next, struct mdp_ppp_djob,
+ entry);
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+
+ /* process next in the queue */
+ mdp_ppp_process_roi(&next->roi_cmd_list);
+ } else {
+ /* no pending display job */
+ spin_unlock_irqrestore(&mdp_ppp_dq_lock, flags);
+
+ /* turn off PPP and CMD blocks - "in_isr" is TRUE */
+ mdp_pipe_ctrl(MDP_PPP_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+
+ /* notify if waiting */
+ if (test_and_clear_bit(0, (unsigned long *)&mdp_ppp_waiting))
+ complete(&mdp_ppp_comp);
+
+ /* set free */
+ test_and_clear_bit(0, (unsigned long *)&mdp_ppp_busy_flag);
+ }
+}
diff --git a/drivers/staging/msm/mdp_ppp_dq.h b/drivers/staging/msm/mdp_ppp_dq.h
new file mode 100644
index 000000000000..03e4e9a5f234
--- /dev/null
+++ b/drivers/staging/msm/mdp_ppp_dq.h
@@ -0,0 +1,86 @@
+/* Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Code Aurora Forum, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MDP_PPP_DQ_H
+#define MDP_PPP_DQ_H
+
+#include "msm_fb_def.h"
+
+#define MDP_PPP_DEBUG_MSG MSM_FB_DEBUG
+
+/* The maximum number of <Reg,Val> pairs in an mdp_ppp_roi_cmd_set structure (a
+ * node)
+ */
+#define MDP_PPP_ROI_NODE_SIZE 32
+
+/* ROI config command (<Reg,Val> pair) for MDP PPP block */
+struct mdp_ppp_roi_cmd {
+ uint32_t reg;
+ uint32_t val;
+};
+
+/* ROI config commands for MDP PPP block are stored in a list of
+ * mdp_ppp_roi_cmd_set structures (nodes).
+ */
+struct mdp_ppp_roi_cmd_set {
+ struct list_head node;
+ uint32_t ncmds; /* number of commands in this set (node). */
+ struct mdp_ppp_roi_cmd cmd[MDP_PPP_ROI_NODE_SIZE];
+};
+
+/* MDP PPP Display Job (DJob) */
+struct mdp_ppp_djob {
+ struct list_head entry;
+ /* One ROI per MDP PPP DJob */
+ struct list_head roi_cmd_list;
+ struct mdp_blit_req req;
+ struct fb_info *info;
+ struct delayed_work cleaner;
+ struct file *p_src_file, *p_dst_file;
+};
+
+extern struct completion mdp_ppp_comp;
+extern boolean mdp_ppp_waiting;
+extern unsigned long mdp_timer_duration;
+
+unsigned int mdp_ppp_async_op_get(void);
+void mdp_ppp_async_op_set(unsigned int flag);
+void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info,
+ struct mdp_blit_req *req_list, int req_list_count);
+void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file);
+void mdp_ppp_dq_init(void);
+void mdp_ppp_outdw(uint32_t addr, uint32_t data);
+struct mdp_ppp_djob *mdp_ppp_new_djob(void);
+void mdp_ppp_clear_curr_djob(void);
+void mdp_ppp_process_curr_djob(void);
+int mdp_ppp_get_ret_code(void);
+void mdp_ppp_djob_done(void);
+void mdp_ppp_wait(void);
+
+#endif /* MDP_PPP_DQ_H */
diff --git a/drivers/staging/msm/mdp_ppp_v20.c b/drivers/staging/msm/mdp_ppp_v20.c
new file mode 100644
index 000000000000..b5b7271921e0
--- /dev/null
+++ b/drivers/staging/msm/mdp_ppp_v20.c
@@ -0,0 +1,2486 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include "linux/proc_fs.h"
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <asm/div64.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+static MDP_SCALE_MODE mdp_curr_up_scale_xy;
+static MDP_SCALE_MODE mdp_curr_down_scale_x;
+static MDP_SCALE_MODE mdp_curr_down_scale_y;
+
+static long long mdp_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+struct mdp_table_entry mdp_gaussian_blur_table[] = {
+ /* max variance */
+ { 0x5fffc, 0x20000080 },
+ { 0x50280, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50284, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50288, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5028c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50290, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50294, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50298, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5029c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502a8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ac, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502b8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502bc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502c8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502cc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502d8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502dc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502e8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502ec, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f0, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f4, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502f8, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x502fc, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50300, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50304, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50308, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5030c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50310, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50314, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50318, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5031c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50320, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50324, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50328, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5032c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50330, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50334, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50338, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5033c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50340, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50344, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50348, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5034c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50350, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50354, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50358, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5035c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50360, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50364, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50368, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5036c, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50370, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50374, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x50378, 0x20000080 },
+ { 0x5fffc, 0x20000080 },
+ { 0x5037c, 0x20000080 },
+};
+
+static void load_scale_table(
+ struct mdp_table_entry *table, int len)
+{
+ int i;
+ for (i = 0; i < len; i++)
+ MDP_OUTP(MDP_BASE + table[i].reg, table[i].val);
+}
+
+static void mdp_load_pr_upscale_table(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50204, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50208, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5020c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50210, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50214, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50218, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5021c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50220, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50224, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50228, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5022c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50230, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50234, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50238, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5023c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50240, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50244, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50248, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5024c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50250, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50254, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50258, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5025c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50260, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50264, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50268, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5026c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50270, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50274, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50278, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5027c, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_x_point2TOpoint4(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_y_point2TOpoint4(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_x_point4TOpoint6(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_y_point4TOpoint6(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_x_point6TOpoint8(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_y_point6TOpoint8(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_x_point8TO1(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x0);
+}
+
+static void mdp_load_pr_downscale_table_y_point8TO1(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ff);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x0);
+}
+
+static void mdp_load_bc_upscale_table(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50200, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d);
+ MDP_OUTP(MDP_BASE + 0x50204, 0x7ec003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c);
+ MDP_OUTP(MDP_BASE + 0x50208, 0x7d4003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b);
+ MDP_OUTP(MDP_BASE + 0x5020c, 0x7b8003ed);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c);
+ MDP_OUTP(MDP_BASE + 0x50210, 0x794003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d);
+ MDP_OUTP(MDP_BASE + 0x50214, 0x76c003e4);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f);
+ MDP_OUTP(MDP_BASE + 0x50218, 0x73c003e0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071);
+ MDP_OUTP(MDP_BASE + 0x5021c, 0x708003de);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085);
+ MDP_OUTP(MDP_BASE + 0x50220, 0x6d0003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098);
+ MDP_OUTP(MDP_BASE + 0x50224, 0x698003d9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac);
+ MDP_OUTP(MDP_BASE + 0x50228, 0x654003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1);
+ MDP_OUTP(MDP_BASE + 0x5022c, 0x610003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5);
+ MDP_OUTP(MDP_BASE + 0x50230, 0x5c8003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9);
+ MDP_OUTP(MDP_BASE + 0x50234, 0x580003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd);
+ MDP_OUTP(MDP_BASE + 0x50238, 0x534003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112);
+ MDP_OUTP(MDP_BASE + 0x5023c, 0x4e8003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126);
+ MDP_OUTP(MDP_BASE + 0x50240, 0x494003da);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a);
+ MDP_OUTP(MDP_BASE + 0x50244, 0x448003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d);
+ MDP_OUTP(MDP_BASE + 0x50248, 0x3f4003dd);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160);
+ MDP_OUTP(MDP_BASE + 0x5024c, 0x3a4003df);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172);
+ MDP_OUTP(MDP_BASE + 0x50250, 0x354003e1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184);
+ MDP_OUTP(MDP_BASE + 0x50254, 0x304003e3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195);
+ MDP_OUTP(MDP_BASE + 0x50258, 0x2b0003e6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6);
+ MDP_OUTP(MDP_BASE + 0x5025c, 0x260003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4);
+ MDP_OUTP(MDP_BASE + 0x50260, 0x214003eb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2);
+ MDP_OUTP(MDP_BASE + 0x50264, 0x1c4003ee);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf);
+ MDP_OUTP(MDP_BASE + 0x50268, 0x17c003f1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db);
+ MDP_OUTP(MDP_BASE + 0x5026c, 0x134003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5);
+ MDP_OUTP(MDP_BASE + 0x50270, 0xf0003f6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee);
+ MDP_OUTP(MDP_BASE + 0x50274, 0xac003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5);
+ MDP_OUTP(MDP_BASE + 0x50278, 0x70003fb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb);
+ MDP_OUTP(MDP_BASE + 0x5027c, 0x34003fe);
+}
+
+static void mdp_load_bc_downscale_table_x_point2TOpoint4(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x23400083);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x23000083);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x23000082);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x23000081);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x23000080);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x22c0007f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x2280007f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x2280007e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x2280007d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x2240007d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x2240007c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x2240007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x2200007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x22400079);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x22400078);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x22400077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x22000077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x22000076);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x22000075);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x21c00075);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x21c00074);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x21c00073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x21800073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x21800072);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x21800071);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x21800070);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x2180006f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x2140006e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x2140006d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x2100006d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x2100006c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x2100006b);
+}
+
+static void mdp_load_bc_downscale_table_y_point2TOpoint4(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac00084);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x23400083);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b000084);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x23000083);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400084);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x23000082);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b400085);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x23000081);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1b800085);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x23000080);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc00086);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x22c0007f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c000086);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x2280007f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c400086);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x2280007e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1c800086);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x2280007d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00086);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x2240007d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc00087);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x2240007c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d000087);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x2240007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400087);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x2200007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d400088);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x22400079);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1d800088);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x22400078);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00088);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x22400077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc00089);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x22000077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e000089);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x22000076);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1e400089);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x22000075);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00088);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x21c00075);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec00089);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x21c00074);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f000089);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x21c00073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f400089);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x21800073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f40008a);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x21800072);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1f80008a);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x21800071);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008a);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x21800070);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1fc0008b);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x2180006f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2000008c);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x2140006e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2040008c);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x2140006d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x2080008c);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x2100006d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008c);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x2100006c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x20c0008d);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x2100006b);
+}
+
+static void mdp_load_bc_downscale_table_x_point4TOpoint6(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x33800088);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x33400084);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x33000080);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x3300007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x32400077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x32000073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x31c0006f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x3140006b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x31000067);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x30800062);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x2fc0005f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x2fc0005b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x2f400057);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x2e400054);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x2e000050);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x2d80004c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x2d000049);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x2c800045);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x2c000042);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x2b40003e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x2a80003b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x2a000039);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x29400036);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x28800032);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x2800002f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x2740002c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x26c00029);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x26000027);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x25000024);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x24800021);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x23800020);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x2300001d);
+}
+
+static void mdp_load_bc_downscale_table_y_point4TOpoint6(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x740008c);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x33800088);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x800008e);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x33400084);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x8400092);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x33000080);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9000094);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x3300007b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9c00098);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x32400077);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xa40009b);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x32000073);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xb00009d);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x31c0006f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xbc000a0);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x3140006b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc8000a2);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x31000067);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xd8000a5);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x30800062);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xe4000a8);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x2fc0005f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xec000aa);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x2fc0005b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8000ad);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x2f400057);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x108000b0);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x2e400054);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x114000b2);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x2e000050);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x124000b4);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x2d80004c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x130000b6);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x2d000049);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x140000b8);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x2c800045);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x150000b9);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x2c000042);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x15c000bd);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x2b40003e);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x16c000bf);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x2a80003b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x17c000bf);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x2a000039);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x188000c2);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x29400036);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x19c000c4);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x28800032);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ac000c5);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x2800002f);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1bc000c7);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x2740002c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1cc000c8);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x26c00029);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1dc000c9);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x26000027);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1ec000cc);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x25000024);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x200000cc);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x24800021);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x210000cd);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x23800020);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x220000ce);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x2300001d);
+}
+
+static void mdp_load_bc_downscale_table_x_point6TOpoint8(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x4bc00068);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x4bc00060);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x4b800059);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x4b000052);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x4a80004b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x4a000044);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x4940003d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x48400037);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x47800031);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x4640002b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x45000026);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x43800021);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x4240001c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x40800018);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x3f000014);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x3d400010);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x3b80000c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x39800009);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x37c00006);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x35800004);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x33800002);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x31400000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x2f4003fe);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x2d0003fc);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x2b0003fb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x28c003fa);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x268003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x244003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0x224003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0x200003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x1e0003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x1c0003f8);
+}
+
+static void mdp_load_bc_downscale_table_y_point6TOpoint8(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000070);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x4bc00068);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000078);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x4bc00060);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000080);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x4b800059);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe000089);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x4b000052);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe400091);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x4a80004b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40009a);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x4a000044);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe8000a3);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x4940003d);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec000ac);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x48400037);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff0000b4);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x47800031);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff8000bd);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x4640002b);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc5);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x45000026);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x8000ce);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x43800021);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x10000d6);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x4240001c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x18000df);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x40800018);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x24000e6);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x3f000014);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x30000ee);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x3d400010);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x40000f5);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x3b80000c);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x50000fc);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x39800009);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x6000102);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x37c00006);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x7000109);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x35800004);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x840010e);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x33800002);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x9800114);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x31400000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xac00119);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x2f4003fe);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xc40011e);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x2d0003fc);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xdc00121);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x2b0003fb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf400125);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x28c003fa);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x11000128);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x268003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x12c0012a);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x244003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1480012c);
+ MDP_OUTP(MDP_BASE + 0x50370, 0x224003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1640012e);
+ MDP_OUTP(MDP_BASE + 0x50374, 0x200003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1800012f);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x1e0003f8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x1a00012f);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x1c0003f8);
+}
+
+static void mdp_load_bc_downscale_table_x_point8TO1(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50280, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d);
+ MDP_OUTP(MDP_BASE + 0x50284, 0x7ec003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c);
+ MDP_OUTP(MDP_BASE + 0x50288, 0x7d4003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b);
+ MDP_OUTP(MDP_BASE + 0x5028c, 0x7b8003ed);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c);
+ MDP_OUTP(MDP_BASE + 0x50290, 0x794003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d);
+ MDP_OUTP(MDP_BASE + 0x50294, 0x76c003e4);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f);
+ MDP_OUTP(MDP_BASE + 0x50298, 0x73c003e0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071);
+ MDP_OUTP(MDP_BASE + 0x5029c, 0x708003de);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085);
+ MDP_OUTP(MDP_BASE + 0x502a0, 0x6d0003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098);
+ MDP_OUTP(MDP_BASE + 0x502a4, 0x698003d9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac);
+ MDP_OUTP(MDP_BASE + 0x502a8, 0x654003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1);
+ MDP_OUTP(MDP_BASE + 0x502ac, 0x610003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5);
+ MDP_OUTP(MDP_BASE + 0x502b0, 0x5c8003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9);
+ MDP_OUTP(MDP_BASE + 0x502b4, 0x580003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd);
+ MDP_OUTP(MDP_BASE + 0x502b8, 0x534003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112);
+ MDP_OUTP(MDP_BASE + 0x502bc, 0x4e8003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126);
+ MDP_OUTP(MDP_BASE + 0x502c0, 0x494003da);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a);
+ MDP_OUTP(MDP_BASE + 0x502c4, 0x448003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d);
+ MDP_OUTP(MDP_BASE + 0x502c8, 0x3f4003dd);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160);
+ MDP_OUTP(MDP_BASE + 0x502cc, 0x3a4003df);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172);
+ MDP_OUTP(MDP_BASE + 0x502d0, 0x354003e1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184);
+ MDP_OUTP(MDP_BASE + 0x502d4, 0x304003e3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195);
+ MDP_OUTP(MDP_BASE + 0x502d8, 0x2b0003e6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6);
+ MDP_OUTP(MDP_BASE + 0x502dc, 0x260003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4);
+ MDP_OUTP(MDP_BASE + 0x502e0, 0x214003eb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2);
+ MDP_OUTP(MDP_BASE + 0x502e4, 0x1c4003ee);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf);
+ MDP_OUTP(MDP_BASE + 0x502e8, 0x17c003f1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db);
+ MDP_OUTP(MDP_BASE + 0x502ec, 0x134003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5);
+ MDP_OUTP(MDP_BASE + 0x502f0, 0xf0003f6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee);
+ MDP_OUTP(MDP_BASE + 0x502f4, 0xac003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5);
+ MDP_OUTP(MDP_BASE + 0x502f8, 0x70003fb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb);
+ MDP_OUTP(MDP_BASE + 0x502fc, 0x34003fe);
+}
+
+static void mdp_load_bc_downscale_table_y_point8TO1(void)
+{
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0x0);
+ MDP_OUTP(MDP_BASE + 0x50300, 0x7fc00000);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xff80000d);
+ MDP_OUTP(MDP_BASE + 0x50304, 0x7ec003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfec0001c);
+ MDP_OUTP(MDP_BASE + 0x50308, 0x7d4003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe40002b);
+ MDP_OUTP(MDP_BASE + 0x5030c, 0x7b8003ed);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfd80003c);
+ MDP_OUTP(MDP_BASE + 0x50310, 0x794003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc0004d);
+ MDP_OUTP(MDP_BASE + 0x50314, 0x76c003e4);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfc40005f);
+ MDP_OUTP(MDP_BASE + 0x50318, 0x73c003e0);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb800071);
+ MDP_OUTP(MDP_BASE + 0x5031c, 0x708003de);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfac00085);
+ MDP_OUTP(MDP_BASE + 0x50320, 0x6d0003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa000098);
+ MDP_OUTP(MDP_BASE + 0x50324, 0x698003d9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf98000ac);
+ MDP_OUTP(MDP_BASE + 0x50328, 0x654003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf8c000c1);
+ MDP_OUTP(MDP_BASE + 0x5032c, 0x610003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf84000d5);
+ MDP_OUTP(MDP_BASE + 0x50330, 0x5c8003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf7c000e9);
+ MDP_OUTP(MDP_BASE + 0x50334, 0x580003d7);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf74000fd);
+ MDP_OUTP(MDP_BASE + 0x50338, 0x534003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c00112);
+ MDP_OUTP(MDP_BASE + 0x5033c, 0x4e8003d8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6800126);
+ MDP_OUTP(MDP_BASE + 0x50340, 0x494003da);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600013a);
+ MDP_OUTP(MDP_BASE + 0x50344, 0x448003db);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf600014d);
+ MDP_OUTP(MDP_BASE + 0x50348, 0x3f4003dd);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00160);
+ MDP_OUTP(MDP_BASE + 0x5034c, 0x3a4003df);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00172);
+ MDP_OUTP(MDP_BASE + 0x50350, 0x354003e1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf5c00184);
+ MDP_OUTP(MDP_BASE + 0x50354, 0x304003e3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6000195);
+ MDP_OUTP(MDP_BASE + 0x50358, 0x2b0003e6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf64001a6);
+ MDP_OUTP(MDP_BASE + 0x5035c, 0x260003e8);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf6c001b4);
+ MDP_OUTP(MDP_BASE + 0x50360, 0x214003eb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf78001c2);
+ MDP_OUTP(MDP_BASE + 0x50364, 0x1c4003ee);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf80001cf);
+ MDP_OUTP(MDP_BASE + 0x50368, 0x17c003f1);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xf90001db);
+ MDP_OUTP(MDP_BASE + 0x5036c, 0x134003f3);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfa0001e5);
+ MDP_OUTP(MDP_BASE + 0x50370, 0xf0003f6);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfb4001ee);
+ MDP_OUTP(MDP_BASE + 0x50374, 0xac003f9);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfcc001f5);
+ MDP_OUTP(MDP_BASE + 0x50378, 0x70003fb);
+ MDP_OUTP(MDP_BASE + 0x5fffc, 0xfe4001fb);
+ MDP_OUTP(MDP_BASE + 0x5037c, 0x34003fe);
+}
+
+static int mdp_get_edge_cond(MDPIBUF *iBuf, uint32 *dup, uint32 *dup2)
+{
+ uint32 reg;
+ uint32 dst_roi_width; /* Dimensions of DST ROI. */
+ uint32 dst_roi_height; /* Used to calculate scaling ratios. */
+
+ /*
+ * positions of the luma pixel(relative to the image ) required for
+ * scaling the ROI
+ */
+ int32 luma_interp_point_left = 0; /* left-most luma pixel needed */
+ int32 luma_interp_point_right = 0; /* right-most luma pixel needed */
+ int32 luma_interp_point_top = 0; /* top-most luma pixel needed */
+ int32 luma_interp_point_bottom = 0; /* bottom-most luma pixel needed */
+
+ /*
+ * positions of the chroma pixel(relative to the image ) required for
+ * interpolating a chroma value at all required luma positions
+ */
+ /* left-most chroma pixel needed */
+ int32 chroma_interp_point_left = 0;
+ /* right-most chroma pixel needed */
+ int32 chroma_interp_point_right = 0;
+ /* top-most chroma pixel needed */
+ int32 chroma_interp_point_top = 0;
+ /* bottom-most chroma pixel needed */
+ int32 chroma_interp_point_bottom = 0;
+
+ /*
+ * a rectangular region within the chroma plane of the "image".
+ * Chroma pixels falling inside of this rectangle belongs to the ROI
+ */
+ int32 chroma_bound_left = 0;
+ int32 chroma_bound_right = 0;
+ int32 chroma_bound_top = 0;
+ int32 chroma_bound_bottom = 0;
+
+ /*
+ * number of chroma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32 chroma_repeat_left = 0;
+ int32 chroma_repeat_right = 0;
+ int32 chroma_repeat_top = 0;
+ int32 chroma_repeat_bottom = 0;
+
+ /*
+ * number of luma pixels to replicate on the left, right,
+ * top and bottom edge of the ROI.
+ */
+ int32 luma_repeat_left = 0;
+ int32 luma_repeat_right = 0;
+ int32 luma_repeat_top = 0;
+ int32 luma_repeat_bottom = 0;
+
+ boolean chroma_edge_enable;
+
+ uint32 _is_scale_enabled = 0;
+ uint32 _is_yuv_offsite_vertical = 0;
+
+ /* fg edge duplicate */
+ reg = 0x0;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) { /* if scaling enabled */
+
+ _is_scale_enabled = 1;
+
+ /*
+ * if rotation mode involves a 90 deg rotation, flip
+ * dst_roi_width with dst_roi_height.
+ * Scaling ratios is based on source ROI dimensions, and
+ * dst ROI dimensions before rotation.
+ */
+ if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
+ dst_roi_width = iBuf->roi.dst_height;
+ dst_roi_height = iBuf->roi.dst_width;
+ } else {
+ dst_roi_width = iBuf->roi.dst_width;
+ dst_roi_height = iBuf->roi.dst_height;
+ }
+
+ /*
+ * Find out the luma pixels needed for scaling in the
+ * x direction (LEFT and RIGHT). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (iBuf->roi.width > 3 * dst_roi_width) {
+ /* scale factor < 1/3 */
+ luma_interp_point_left = 0;
+ luma_interp_point_right = (iBuf->roi.width - 1);
+ luma_repeat_left = 0;
+ luma_repeat_right = 0;
+ } else if (iBuf->roi.width == 3 * dst_roi_width) {
+ /* scale factor == 1/3 */
+ luma_interp_point_left = 0;
+ luma_interp_point_right = (iBuf->roi.width - 1) + 1;
+ luma_repeat_left = 0;
+ luma_repeat_right = 1;
+ } else if ((iBuf->roi.width > dst_roi_width) &&
+ (iBuf->roi.width < 3 * dst_roi_width)) {
+ /* 1/3 < scale factor < 1 */
+ luma_interp_point_left = -1;
+ luma_interp_point_right = (iBuf->roi.width - 1) + 1;
+ luma_repeat_left = 1;
+ luma_repeat_right = 1;
+ }
+
+ else if (iBuf->roi.width == dst_roi_width) {
+ /* scale factor == 1 */
+ luma_interp_point_left = -1;
+ luma_interp_point_right = (iBuf->roi.width - 1) + 2;
+ luma_repeat_left = 1;
+ luma_repeat_right = 2;
+ } else { /* (iBuf->roi.width < dst_roi_width) */
+ /* scale factor > 1 */
+ luma_interp_point_left = -2;
+ luma_interp_point_right = (iBuf->roi.width - 1) + 2;
+ luma_repeat_left = 2;
+ luma_repeat_right = 2;
+ }
+
+ /*
+ * Find out the number of pixels needed for scaling in the
+ * y direction (TOP and BOTTOM). Locations of pixels are
+ * relative to the ROI. Upper-left corner of ROI corresponds
+ * to coordinates (0,0). Also set the number of luma pixel
+ * to repeat.
+ */
+ if (iBuf->roi.height > 3 * dst_roi_height) {
+ /* scale factor < 1/3 */
+ luma_interp_point_top = 0;
+ luma_interp_point_bottom = (iBuf->roi.height - 1);
+ luma_repeat_top = 0;
+ luma_repeat_bottom = 0;
+ } else if (iBuf->roi.height == 3 * dst_roi_height) {
+ /* scale factor == 1/3 */
+ luma_interp_point_top = 0;
+ luma_interp_point_bottom = (iBuf->roi.height - 1) + 1;
+ luma_repeat_top = 0;
+ luma_repeat_bottom = 1;
+ } else if ((iBuf->roi.height > dst_roi_height) &&
+ (iBuf->roi.height < 3 * dst_roi_height)) {
+ /* 1/3 < scale factor < 1 */
+ luma_interp_point_top = -1;
+ luma_interp_point_bottom = (iBuf->roi.height - 1) + 1;
+ luma_repeat_top = 1;
+ luma_repeat_bottom = 1;
+ } else if (iBuf->roi.height == dst_roi_height) {
+ /* scale factor == 1 */
+ luma_interp_point_top = -1;
+ luma_interp_point_bottom = (iBuf->roi.height - 1) + 2;
+ luma_repeat_top = 1;
+ luma_repeat_bottom = 2;
+ } else { /* (iBuf->roi.height < dst_roi_height) */
+ /* scale factor > 1 */
+ luma_interp_point_top = -2;
+ luma_interp_point_bottom = (iBuf->roi.height - 1) + 2;
+ luma_repeat_top = 2;
+ luma_repeat_bottom = 2;
+ }
+ } /* if (iBuf->scale.scale_flag) */
+ else { /* scaling disabled */
+ /*
+ * Since no scaling needed, Tile Fetch does not require any
+ * more luma pixel than what the ROI contains.
+ */
+ luma_interp_point_left = (int32) 0;
+ luma_interp_point_right = (int32) (iBuf->roi.width - 1);
+ luma_interp_point_top = (int32) 0;
+ luma_interp_point_bottom = (int32) (iBuf->roi.height - 1);
+
+ luma_repeat_left = 0;
+ luma_repeat_right = 0;
+ luma_repeat_top = 0;
+ luma_repeat_bottom = 0;
+ }
+
+ /* After adding the ROI offsets, we have locations of
+ * luma_interp_points relative to the image.
+ */
+ luma_interp_point_left += (int32) (iBuf->roi.x);
+ luma_interp_point_right += (int32) (iBuf->roi.x);
+ luma_interp_point_top += (int32) (iBuf->roi.y);
+ luma_interp_point_bottom += (int32) (iBuf->roi.y);
+
+ /*
+ * After adding the ROI offsets, we have locations of
+ * chroma_interp_points relative to the image.
+ */
+ chroma_interp_point_left = luma_interp_point_left;
+ chroma_interp_point_right = luma_interp_point_right;
+ chroma_interp_point_top = luma_interp_point_top;
+ chroma_interp_point_bottom = luma_interp_point_bottom;
+
+ chroma_edge_enable = TRUE;
+ /* find out which chroma pixels are needed for chroma upsampling. */
+ switch (iBuf->mdpImg.imgType) {
+ /*
+ * cosite in horizontal axis
+ * fully sampled in vertical axis
+ */
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ /* floor( luma_interp_point_left / 2 ); */
+ chroma_interp_point_left = luma_interp_point_left >> 1;
+ /* floor( ( luma_interp_point_right + 1 ) / 2 ); */
+ chroma_interp_point_right = (luma_interp_point_right + 1) >> 1;
+
+ chroma_interp_point_top = luma_interp_point_top;
+ chroma_interp_point_bottom = luma_interp_point_bottom;
+ break;
+
+ /*
+ * cosite in horizontal axis
+ * offsite in vertical axis
+ */
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ /* floor( luma_interp_point_left / 2) */
+ chroma_interp_point_left = luma_interp_point_left >> 1;
+
+ /* floor( ( luma_interp_point_right + 1 )/ 2 ) */
+ chroma_interp_point_right = (luma_interp_point_right + 1) >> 1;
+
+ /* floor( (luma_interp_point_top - 1 ) / 2 ) */
+ chroma_interp_point_top = (luma_interp_point_top - 1) >> 1;
+
+ /* floor( ( luma_interp_point_bottom + 1 ) / 2 ) */
+ chroma_interp_point_bottom =
+ (luma_interp_point_bottom + 1) >> 1;
+
+ _is_yuv_offsite_vertical = 1;
+ break;
+
+ default:
+ chroma_edge_enable = FALSE;
+ chroma_interp_point_left = luma_interp_point_left;
+ chroma_interp_point_right = luma_interp_point_right;
+ chroma_interp_point_top = luma_interp_point_top;
+ chroma_interp_point_bottom = luma_interp_point_bottom;
+
+ break;
+ }
+
+ /* only if the image type is in YUV domain, we calculate chroma edge */
+ if (chroma_edge_enable) {
+ /* Defines which chroma pixels belongs to the roi */
+ switch (iBuf->mdpImg.imgType) {
+ /*
+ * Cosite in horizontal direction, and fully sampled
+ * in vertical direction.
+ */
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ /*
+ * width of chroma ROI is 1/2 of size of luma ROI
+ * height of chroma ROI same as size of luma ROI
+ */
+ chroma_bound_left = iBuf->roi.x / 2;
+
+ /* there are half as many chroma pixel as luma pixels */
+ chroma_bound_right =
+ (iBuf->roi.width + iBuf->roi.x - 1) / 2;
+ chroma_bound_top = iBuf->roi.y;
+ chroma_bound_bottom =
+ (iBuf->roi.height + iBuf->roi.y - 1);
+ break;
+
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ /*
+ * cosite in horizontal dir, and offsite in vertical dir
+ * width of chroma ROI is 1/2 of size of luma ROI
+ * height of chroma ROI is 1/2 of size of luma ROI
+ */
+
+ chroma_bound_left = iBuf->roi.x / 2;
+ chroma_bound_right =
+ (iBuf->roi.width + iBuf->roi.x - 1) / 2;
+ chroma_bound_top = iBuf->roi.y / 2;
+ chroma_bound_bottom =
+ (iBuf->roi.height + iBuf->roi.y - 1) / 2;
+ break;
+
+ default:
+ /*
+ * If no valid chroma sub-sampling format specified,
+ * assume 4:4:4 ( i.e. fully sampled). Set ROI
+ * boundaries for chroma same as ROI boundaries for
+ * luma.
+ */
+ chroma_bound_left = iBuf->roi.x;
+ chroma_bound_right = iBuf->roi.width + iBuf->roi.x - 1;
+ chroma_bound_top = iBuf->roi.y;
+ chroma_bound_bottom =
+ (iBuf->roi.height + iBuf->roi.y - 1);
+ break;
+ }
+
+ /*
+ * Knowing which chroma pixels are needed, and which chroma
+ * pixels belong to the ROI (i.e. available for fetching ),
+ * calculate how many chroma pixels Tile Fetch needs to
+ * duplicate. If any required chroma pixels falls outside
+ * of the ROI, Tile Fetch must obtain them by replicating
+ * pixels.
+ */
+ if (chroma_bound_left > chroma_interp_point_left)
+ chroma_repeat_left =
+ chroma_bound_left - chroma_interp_point_left;
+ else
+ chroma_repeat_left = 0;
+
+ if (chroma_interp_point_right > chroma_bound_right)
+ chroma_repeat_right =
+ chroma_interp_point_right - chroma_bound_right;
+ else
+ chroma_repeat_right = 0;
+
+ if (chroma_bound_top > chroma_interp_point_top)
+ chroma_repeat_top =
+ chroma_bound_top - chroma_interp_point_top;
+ else
+ chroma_repeat_top = 0;
+
+ if (chroma_interp_point_bottom > chroma_bound_bottom)
+ chroma_repeat_bottom =
+ chroma_interp_point_bottom - chroma_bound_bottom;
+ else
+ chroma_repeat_bottom = 0;
+
+ if (_is_scale_enabled && (iBuf->roi.height == 1)
+ && _is_yuv_offsite_vertical) {
+ chroma_repeat_bottom = 3;
+ chroma_repeat_top = 0;
+ }
+ }
+ /* make sure chroma repeats are non-negative */
+ if ((chroma_repeat_left < 0) || (chroma_repeat_right < 0) ||
+ (chroma_repeat_top < 0) || (chroma_repeat_bottom < 0))
+ return -1;
+
+ /* make sure chroma repeats are no larger than 3 pixels */
+ if ((chroma_repeat_left > 3) || (chroma_repeat_right > 3) ||
+ (chroma_repeat_top > 3) || (chroma_repeat_bottom > 3))
+ return -1;
+
+ /* make sure luma repeats are non-negative */
+ if ((luma_repeat_left < 0) || (luma_repeat_right < 0) ||
+ (luma_repeat_top < 0) || (luma_repeat_bottom < 0))
+ return -1;
+
+ /* make sure luma repeats are no larger than 3 pixels */
+ if ((luma_repeat_left > 3) || (luma_repeat_right > 3) ||
+ (luma_repeat_top > 3) || (luma_repeat_bottom > 3))
+ return -1;
+
+ /* write chroma_repeat_left to register */
+ reg |= (chroma_repeat_left & 3) << MDP_LEFT_CHROMA;
+
+ /* write chroma_repeat_right to register */
+ reg |= (chroma_repeat_right & 3) << MDP_RIGHT_CHROMA;
+
+ /* write chroma_repeat_top to register */
+ reg |= (chroma_repeat_top & 3) << MDP_TOP_CHROMA;
+
+ /* write chroma_repeat_bottom to register */
+ reg |= (chroma_repeat_bottom & 3) << MDP_BOTTOM_CHROMA;
+
+ /* write luma_repeat_left to register */
+ reg |= (luma_repeat_left & 3) << MDP_LEFT_LUMA;
+
+ /* write luma_repeat_right to register */
+ reg |= (luma_repeat_right & 3) << MDP_RIGHT_LUMA;
+
+ /* write luma_repeat_top to register */
+ reg |= (luma_repeat_top & 3) << MDP_TOP_LUMA;
+
+ /* write luma_repeat_bottom to register */
+ reg |= (luma_repeat_bottom & 3) << MDP_BOTTOM_LUMA;
+
+ /* done with reg */
+ *dup = reg;
+
+ /* bg edge duplicate */
+ reg = 0x0;
+
+ switch (iBuf->ibuf_type) {
+ case MDP_Y_CBCR_H2V2:
+ case MDP_Y_CRCB_H2V2:
+ /*
+ * Edge condition for MDP_Y_CRCB/CBCR_H2V2 cosite only.
+ * For 420 cosite, 1 chroma replicated on all sides except
+ * left, so reg 101b8 should be 0x0209. For 420 offsite,
+ * 1 chroma replicated all sides.
+ */
+ if (iBuf->roi.lcd_y == 0) {
+ reg |= BIT(MDP_TOP_CHROMA);
+ }
+
+ if ((iBuf->roi.lcd_y + iBuf->roi.dst_height) ==
+ iBuf->ibuf_height) {
+ reg |= BIT(MDP_BOTTOM_CHROMA);
+ }
+
+ if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) ==
+ iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) {
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ }
+
+ break;
+
+ case MDP_Y_CBCR_H2V1:
+ case MDP_Y_CRCB_H2V1:
+ case MDP_YCRYCB_H2V1:
+ if (((iBuf->roi.lcd_x + iBuf->roi.dst_width) ==
+ iBuf->ibuf_width) && ((iBuf->roi.dst_width % 2) == 0)) {
+ reg |= BIT(MDP_RIGHT_CHROMA);
+ }
+ break;
+ default:
+ break;
+ }
+
+ *dup2 = reg;
+
+ return 0;
+}
+
+#define ADJUST_IP /* for 1/3 scale factor fix */
+
+static int mdp_calc_scale_params(
+/* ROI origin coordinate for the dimension */
+ uint32 org,
+/* src ROI dimension */
+ uint32 dim_in,
+/* scaled ROI dimension*/
+ uint32 dim_out,
+/* is this ROI width dimension? */
+ boolean is_W,
+/* initial phase location address */
+ int32 *phase_init_ptr,
+/* phase increment location address */
+ uint32 *phase_step_ptr,
+/* ROI start over-fetch location address */
+ uint32 *num_repl_beg_ptr,
+/* ROI end over-fetch location address */
+ uint32 *num_repl_end_ptr)
+{
+ boolean rpa_on = FALSE;
+ int init_phase = 0;
+ uint32 beg_of = 0;
+ uint32 end_of = 0;
+ uint64 numer = 0;
+ uint64 denom = 0;
+ /*uint64 inverter = 1; */
+ int64 point5 = 1;
+ int64 one = 1;
+ int64 k1, k2, k3, k4; /* linear equation coefficients */
+ uint64 int_mask;
+ uint64 fract_mask;
+ uint64 Os;
+ int64 Osprime;
+ int64 Od;
+ int64 Odprime;
+ int64 Oreq;
+ uint64 Es;
+ uint64 Ed;
+ uint64 Ereq;
+#ifdef ADJUST_IP
+ int64 IP64;
+ int64 delta;
+#endif
+ uint32 mult;
+
+ /*
+ * The phase accumulator should really be rational for all cases in a
+ * general purpose polyphase scaler for a tiled architecture with
+ * non-zero * origin capability because there is no way to represent
+ * certain scale factors in fixed point regardless of precision.
+ * The error incurred in attempting to use fixed point is most
+ * eggregious for SF where 1/SF is an integral multiple of 1/3.
+ *
+ * However, since the MDP2 has already been committed to HW, we
+ * only use the rational phase accumulator (RPA) when 1/SF is an
+ * integral multiple of 1/3. This will help minimize regressions in
+ * matching the HW to the C-Sim.
+ */
+ /*
+ * Set the RPA flag for this dimension.
+ *
+ * In order for 1/SF (dim_in/dim_out) to be an integral multiple of
+ * 1/3, dim_out must be an integral multiple of 3.
+ */
+ if (!(dim_out % 3)) {
+ mult = dim_out / 3;
+ rpa_on = (!(dim_in % mult));
+ }
+
+ numer = dim_out;
+ denom = dim_in;
+
+ /*
+ * convert to U30.34 before division
+ *
+ * The K vectors carry 4 extra bits of precision
+ * and are rounded.
+ *
+ * We initially go 5 bits over then round by adding
+ * 1 and right shifting by 1
+ * so final result is U31.33
+ */
+ numer <<= PQF_PLUS_5;
+
+ /* now calculate the scale factor (aka k3) */
+ k3 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /* check scale factor for legal range [0.25 - 4.0] */
+ if (((k3 >> 4) < (1LL << PQF_MINUS_2)) ||
+ ((k3 >> 4) > (1LL << PQF_PLUS_2))) {
+ return -1;
+ }
+
+ /* calculate inverse scale factor (aka k1) for phase init */
+ numer = dim_in;
+ denom = dim_out;
+ numer <<= PQF_PLUS_5;
+ k1 = ((mdp_do_div(numer, denom) + 1) >> 1);
+
+ /*
+ * calculate initial phase and ROI overfetch
+ */
+ /* convert point5 & one to S39.24 (will always be positive) */
+ point5 <<= (PQF_PLUS_4 - 1);
+ one <<= PQF_PLUS_4;
+ k2 = ((k1 - one) >> 1);
+ init_phase = (int)(k2 >> 4);
+ k4 = ((k3 - one) >> 1);
+ if (k3 == one) {
+ /* the simple case; SF = 1.0 */
+ beg_of = 1;
+ end_of = 2;
+ } else {
+ /* calculate the masks */
+ fract_mask = one - 1;
+ int_mask = ~fract_mask;
+
+ if (!rpa_on) {
+ /*
+ * FIXED POINT IMPLEMENTATION
+ */
+ if (!org) {
+ /* A fairly simple case; ROI origin = 0 */
+ if (k1 < one) {
+ /* upscaling */
+ beg_of = end_of = 2;
+ }
+ /* 0.33 <= SF < 1.0 */
+ else if (k1 < (3LL << PQF_PLUS_4))
+ beg_of = end_of = 1;
+ /* 0.33 == SF */
+ else if (k1 == (3LL << PQF_PLUS_4)) {
+ beg_of = 0;
+ end_of = 1;
+ }
+ /* 0.25 <= SF < 0.33 */
+ else
+ beg_of = end_of = 0;
+ } else {
+ /*
+ * The complicated case; ROI origin != 0
+ * init_phase needs to be adjusted
+ * OF is also position dependent
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64) org << 1) - 1;
+ Od = ((k3 * Os) >> 1) + k4;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime = (k1 * (Odprime >> PQF_PLUS_4)) + k2;
+
+ /* then floor & decrement to calculate the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate end coord in destination space then map to
+ source space */
+ Ed = Odprime +
+ ((uint64) dim_out << PQF_PLUS_4) - one;
+ Es = (k1 * (Ed >> PQF_PLUS_4)) + k2;
+
+ /* now floor & increment by 2 to calculate the required
+ ending coordinate */
+ Ereq = (Es & int_mask) + (one << 1);
+
+ /* calculate initial phase */
+#ifdef ADJUST_IP
+
+ IP64 = Osprime - Oreq;
+ delta = ((int64) (org) << PQF_PLUS_4) - Oreq;
+ IP64 -= delta;
+
+ /* limit to valid range before the left shift */
+ delta = (IP64 & (1LL << 63)) ? 4 : -4;
+ delta <<= PQF_PLUS_4;
+ while (abs((int)(IP64 >> PQF_PLUS_4)) > 4)
+ IP64 += delta;
+
+ /* right shift to account for extra bits of precision */
+ init_phase = (int)(IP64 >> 4);
+
+#else /* ADJUST_IP */
+
+ /* just calculate the real initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+
+#endif /* ADJUST_IP */
+
+ /* calculate the overfetch */
+ beg_of = org - (uint32) (Oreq >> PQF_PLUS_4);
+ end_of =
+ (uint32) (Ereq >> PQF_PLUS_4) - (org +
+ dim_in -
+ 1);
+ }
+ } else {
+ /*
+ * RPA IMPLEMENTATION
+ *
+ * init_phase needs to be calculated in all RPA_on cases
+ * because it's a numerator, not a fixed point value.
+ */
+
+ /* map (org - .5) into destination space */
+ Os = ((uint64) org << PQF_PLUS_4) - point5;
+ Od = mdp_do_div((dim_out * (Os + point5)),
+ dim_in) - point5;
+
+ /* take the ceiling */
+ Odprime = (Od & int_mask);
+ if (Odprime != Od)
+ Odprime += one;
+
+ /* now map that back to source space */
+ Osprime =
+ mdp_do_div((dim_in * (Odprime + point5)),
+ dim_out) - point5;
+
+ /* then floor & decrement to calculate the required
+ starting coordinate */
+ Oreq = (Osprime & int_mask) - one;
+
+ /* calculate end coord in destination space then map to
+ source space */
+ Ed = Odprime + ((uint64) dim_out << PQF_PLUS_4) - one;
+ Es = mdp_do_div((dim_in * (Ed + point5)),
+ dim_out) - point5;
+
+ /* now floor & increment by 2 to calculate the required
+ ending coordinate */
+ Ereq = (Es & int_mask) + (one << 1);
+
+ /* calculate initial phase */
+
+#ifdef ADJUST_IP
+
+ IP64 = Osprime - Oreq;
+ delta = ((int64) (org) << PQF_PLUS_4) - Oreq;
+ IP64 -= delta;
+
+ /* limit to valid range before the left shift */
+ delta = (IP64 & (1LL << 63)) ? 4 : -4;
+ delta <<= PQF_PLUS_4;
+ while (abs((int)(IP64 >> PQF_PLUS_4)) > 4)
+ IP64 += delta;
+
+ /* right shift to account for extra bits of precision */
+ init_phase = (int)(IP64 >> 4);
+
+#else /* ADJUST_IP */
+
+ /* just calculate the real initial phase */
+ init_phase = (int)((Osprime - Oreq) >> 4);
+
+#endif /* ADJUST_IP */
+
+ /* calculate the overfetch */
+ beg_of = org - (uint32) (Oreq >> PQF_PLUS_4);
+ end_of =
+ (uint32) (Ereq >> PQF_PLUS_4) - (org + dim_in - 1);
+ }
+ }
+
+ /* return the scale parameters */
+ *phase_init_ptr = init_phase;
+ *phase_step_ptr = (uint32) (k1 >> 4);
+ *num_repl_beg_ptr = beg_of;
+ *num_repl_end_ptr = end_of;
+
+ return 0;
+}
+
+static uint8 *mdp_adjust_rot_addr(MDPIBUF *iBuf, uint8 *addr, uint32 uv)
+{
+ uint32 dest_ystride = iBuf->ibuf_width * iBuf->bpp;
+ uint32 h_slice = 1;
+
+ if (uv && ((iBuf->ibuf_type == MDP_Y_CBCR_H2V2) ||
+ (iBuf->ibuf_type == MDP_Y_CRCB_H2V2)))
+ h_slice = 2;
+
+ if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_ROT90) ^
+ MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_LR)) {
+ addr =
+ addr + (iBuf->roi.dst_width -
+ MIN(16, iBuf->roi.dst_width)) * iBuf->bpp;
+ }
+ if (MDP_CHKBIT(iBuf->mdpImg.mdpOp, MDPOP_UD)) {
+ addr =
+ addr + ((iBuf->roi.dst_height -
+ MIN(16, iBuf->roi.dst_height))/h_slice) * dest_ystride;
+ }
+
+ return addr;
+}
+
+void mdp_set_scale(MDPIBUF *iBuf,
+ uint32 dst_roi_width,
+ uint32 dst_roi_height,
+ boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr)
+{
+ uint32 dst_roi_width_scale;
+ uint32 dst_roi_height_scale;
+ boolean use_pr;
+ uint32 phasex_step = 0;
+ uint32 phasey_step = 0;
+ int32 phasex_init = 0;
+ int32 phasey_init = 0;
+ uint32 lines_dup = 0;
+ uint32 lines_dup_bg = 0;
+ uint32 dummy;
+ uint32 mdp_blur = 0;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) {
+ if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
+ dst_roi_width_scale = dst_roi_height;
+ dst_roi_height_scale = dst_roi_width;
+ } else {
+ dst_roi_width_scale = dst_roi_width;
+ dst_roi_height_scale = dst_roi_height;
+ }
+
+ mdp_blur = iBuf->mdpImg.mdpOp & MDPOP_BLUR;
+
+ if ((dst_roi_width_scale != iBuf->roi.width) ||
+ (dst_roi_height_scale != iBuf->roi.height) ||
+ mdp_blur) {
+ *pppop_reg_ptr |=
+ (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
+
+ /* let's use SHIM logic to calculate the partial ROI scaling */
+#if 0
+ phasex_step =
+ (uint32) mdp_do_div(0x20000000 * iBuf->roi.width,
+ dst_roi_width_scale);
+ phasey_step =
+ (uint32) mdp_do_div(0x20000000 * iBuf->roi.height,
+ dst_roi_height_scale);
+
+/*
+ phasex_step= ((long long) iBuf->roi.width * 0x20000000)/dst_roi_width_scale;
+ phasey_step= ((long long)iBuf->roi.height * 0x20000000)/dst_roi_height_scale;
+*/
+
+ phasex_init =
+ (((long long)phasex_step - 0x20000000) >> 1);
+ phasey_init =
+ (((long long)phasey_step - 0x20000000) >> 1);
+
+#else
+ mdp_calc_scale_params(iBuf->roi.x, iBuf->roi.width,
+ dst_roi_width_scale, 1,
+ &phasex_init, &phasex_step,
+ &dummy, &dummy);
+ mdp_calc_scale_params(iBuf->roi.y, iBuf->roi.height,
+ dst_roi_height_scale, 0,
+ &phasey_init, &phasey_step,
+ &dummy, &dummy);
+#endif
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
+ phasex_init);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
+ phasey_init);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144,
+ phasex_step);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148,
+ phasey_step);
+
+ use_pr = (inputRGB) && (outputRGB);
+
+ if ((dst_roi_width_scale > iBuf->roi.width) ||
+ (dst_roi_height_scale > iBuf->roi.height)) {
+ if ((use_pr)
+ && (mdp_curr_up_scale_xy !=
+ MDP_PR_SCALE_UP)) {
+ mdp_load_pr_upscale_table();
+ mdp_curr_up_scale_xy = MDP_PR_SCALE_UP;
+ } else if ((!use_pr)
+ && (mdp_curr_up_scale_xy !=
+ MDP_BC_SCALE_UP)) {
+ mdp_load_bc_upscale_table();
+ mdp_curr_up_scale_xy = MDP_BC_SCALE_UP;
+ }
+ }
+
+ if (mdp_blur) {
+ load_scale_table(mdp_gaussian_blur_table,
+ ARRAY_SIZE(mdp_gaussian_blur_table));
+ mdp_curr_down_scale_x = MDP_SCALE_BLUR;
+ mdp_curr_down_scale_y = MDP_SCALE_BLUR;
+ }
+
+ /* 0.2 < x <= 1 scaling factor */
+ if ((dst_roi_width_scale <= iBuf->roi.width) &&
+ !mdp_blur) {
+ if (((dst_roi_width_scale * 10) /
+ iBuf->roi.width) > 8) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_PR_SCALE_POINT8_1)) {
+ mdp_load_pr_downscale_table_x_point8TO1
+ ();
+ mdp_curr_down_scale_x =
+ MDP_PR_SCALE_POINT8_1;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_BC_SCALE_POINT8_1)) {
+ mdp_load_bc_downscale_table_x_point8TO1
+ ();
+ mdp_curr_down_scale_x =
+ MDP_BC_SCALE_POINT8_1;
+ }
+ } else
+ if (((dst_roi_width_scale * 10) /
+ iBuf->roi.width) > 6) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_PR_SCALE_POINT6_POINT8)) {
+ mdp_load_pr_downscale_table_x_point6TOpoint8
+ ();
+ mdp_curr_down_scale_x =
+ MDP_PR_SCALE_POINT6_POINT8;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_BC_SCALE_POINT6_POINT8))
+ {
+ mdp_load_bc_downscale_table_x_point6TOpoint8
+ ();
+ mdp_curr_down_scale_x =
+ MDP_BC_SCALE_POINT6_POINT8;
+ }
+ } else
+ if (((dst_roi_width_scale * 10) /
+ iBuf->roi.width) > 4) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_PR_SCALE_POINT4_POINT6)) {
+ mdp_load_pr_downscale_table_x_point4TOpoint6
+ ();
+ mdp_curr_down_scale_x =
+ MDP_PR_SCALE_POINT4_POINT6;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_BC_SCALE_POINT4_POINT6))
+ {
+ mdp_load_bc_downscale_table_x_point4TOpoint6
+ ();
+ mdp_curr_down_scale_x =
+ MDP_BC_SCALE_POINT4_POINT6;
+ }
+ } else {
+ if ((use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_PR_SCALE_POINT2_POINT4)) {
+ mdp_load_pr_downscale_table_x_point2TOpoint4
+ ();
+ mdp_curr_down_scale_x =
+ MDP_PR_SCALE_POINT2_POINT4;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_x !=
+ MDP_BC_SCALE_POINT2_POINT4))
+ {
+ mdp_load_bc_downscale_table_x_point2TOpoint4
+ ();
+ mdp_curr_down_scale_x =
+ MDP_BC_SCALE_POINT2_POINT4;
+ }
+ }
+ }
+ /* 0.2 < y <= 1 scaling factor */
+ if ((dst_roi_height_scale <= iBuf->roi.height) &&
+ !mdp_blur) {
+ if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 8) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_PR_SCALE_POINT8_1)) {
+ mdp_load_pr_downscale_table_y_point8TO1
+ ();
+ mdp_curr_down_scale_y =
+ MDP_PR_SCALE_POINT8_1;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_BC_SCALE_POINT8_1)) {
+ mdp_load_bc_downscale_table_y_point8TO1
+ ();
+ mdp_curr_down_scale_y =
+ MDP_BC_SCALE_POINT8_1;
+ }
+ } else
+ if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 6) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_PR_SCALE_POINT6_POINT8)) {
+ mdp_load_pr_downscale_table_y_point6TOpoint8
+ ();
+ mdp_curr_down_scale_y =
+ MDP_PR_SCALE_POINT6_POINT8;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_BC_SCALE_POINT6_POINT8))
+ {
+ mdp_load_bc_downscale_table_y_point6TOpoint8
+ ();
+ mdp_curr_down_scale_y =
+ MDP_BC_SCALE_POINT6_POINT8;
+ }
+ } else
+ if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 4) {
+ if ((use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_PR_SCALE_POINT4_POINT6)) {
+ mdp_load_pr_downscale_table_y_point4TOpoint6
+ ();
+ mdp_curr_down_scale_y =
+ MDP_PR_SCALE_POINT4_POINT6;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_BC_SCALE_POINT4_POINT6))
+ {
+ mdp_load_bc_downscale_table_y_point4TOpoint6
+ ();
+ mdp_curr_down_scale_y =
+ MDP_BC_SCALE_POINT4_POINT6;
+ }
+ } else {
+ if ((use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_PR_SCALE_POINT2_POINT4)) {
+ mdp_load_pr_downscale_table_y_point2TOpoint4
+ ();
+ mdp_curr_down_scale_y =
+ MDP_PR_SCALE_POINT2_POINT4;
+ } else if ((!use_pr)
+ && (mdp_curr_down_scale_y !=
+ MDP_BC_SCALE_POINT2_POINT4))
+ {
+ mdp_load_bc_downscale_table_y_point2TOpoint4
+ ();
+ mdp_curr_down_scale_y =
+ MDP_BC_SCALE_POINT2_POINT4;
+ }
+ }
+ }
+ } else {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE);
+ }
+ }
+ /* setting edge condition here after scaling check */
+ if (mdp_get_edge_cond(iBuf, &lines_dup, &lines_dup_bg))
+ printk(KERN_ERR "msm_fb: mdp_get_edge_cond() error!\n");
+
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01b8, lines_dup);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x01bc, lines_dup_bg);
+}
+
+void mdp_init_scale_table(void)
+{
+ mdp_curr_up_scale_xy = MDP_INIT_SCALE;
+ mdp_curr_down_scale_x = MDP_INIT_SCALE;
+ mdp_curr_down_scale_y = MDP_INIT_SCALE;
+}
+
+void mdp_adjust_start_addr(uint8 **src0,
+ uint8 **src1,
+ int v_slice,
+ int h_slice,
+ int x,
+ int y,
+ uint32 width,
+ uint32 height, int bpp, MDPIBUF *iBuf, int layer)
+{
+ *src0 += (x + y * width) * bpp;
+
+ /* if it's dest/bg buffer, we need to adjust it for rotation */
+ if (layer != 0)
+ *src0 = mdp_adjust_rot_addr(iBuf, *src0, 0);
+
+ if (*src1) {
+ /*
+ * MDP_Y_CBCR_H2V2/MDP_Y_CRCB_H2V2 cosite for now
+ * we need to shift x direction same as y dir for offsite
+ */
+ *src1 +=
+ ((x / h_slice) * h_slice +
+ ((y == 0) ? 0 : ((y + 1) / v_slice - 1) * width)) * bpp;
+
+ /* if it's dest/bg buffer, we need to adjust it for rotation */
+ if (layer != 0)
+ *src1 = mdp_adjust_rot_addr(iBuf, *src1, 1);
+ }
+}
+
+void mdp_set_blend_attr(MDPIBUF *iBuf,
+ uint32 *alpha,
+ uint32 *tpVal,
+ uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
+{
+ if (perPixelAlpha) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ } else {
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.alpha == 0xff)) {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |=
+ PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
+ PPP_BLEND_CALPHA_TRNASP;
+
+ *alpha = iBuf->mdpImg.alpha;
+ *tpVal = iBuf->mdpImg.tpVal;
+ } else {
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_SRCPIXEL_TRANSP;
+ *tpVal = iBuf->mdpImg.tpVal;
+ } else if (iBuf->mdpImg.mdpOp & MDPOP_ALPHAB) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
+ PPP_OP_BLEND_CONSTANT_ALPHA;
+ *alpha = iBuf->mdpImg.alpha;
+ }
+ }
+ }
+}
diff --git a/drivers/staging/msm/mdp_ppp_v31.c b/drivers/staging/msm/mdp_ppp_v31.c
new file mode 100644
index 000000000000..76495dbe4e64
--- /dev/null
+++ b/drivers/staging/msm/mdp_ppp_v31.c
@@ -0,0 +1,828 @@
+/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include "linux/proc_fs.h"
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <asm/div64.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+
+#define MDP_SCALE_COEFF_NUM 32
+#define MDP_SCALE_0P2_TO_0P4_INDEX 0
+#define MDP_SCALE_0P4_TO_0P6_INDEX 32
+#define MDP_SCALE_0P6_TO_0P8_INDEX 64
+#define MDP_SCALE_0P8_TO_8P0_INDEX 96
+#define MDP_SCALE_COEFF_MASK 0x3ff
+
+#define MDP_SCALE_PR 0
+#define MDP_SCALE_FIR 1
+
+static uint32 mdp_scale_0p8_to_8p0_mode;
+static uint32 mdp_scale_0p6_to_0p8_mode;
+static uint32 mdp_scale_0p4_to_0p6_mode;
+static uint32 mdp_scale_0p2_to_0p4_mode;
+
+/* -------- All scaling range, "pixel repeat" -------- */
+static int16 mdp_scale_pixel_repeat_C0[MDP_SCALE_COEFF_NUM] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int16 mdp_scale_pixel_repeat_C1[MDP_SCALE_COEFF_NUM] = {
+ 511, 511, 511, 511, 511, 511, 511, 511,
+ 511, 511, 511, 511, 511, 511, 511, 511,
+ 511, 511, 511, 511, 511, 511, 511, 511,
+ 511, 511, 511, 511, 511, 511, 511, 511
+};
+
+static int16 mdp_scale_pixel_repeat_C2[MDP_SCALE_COEFF_NUM] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int16 mdp_scale_pixel_repeat_C3[MDP_SCALE_COEFF_NUM] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* --------------------------- FIR ------------------------------------- */
+/* -------- Downscale, ranging from 0.8x to 8.0x of original size -------- */
+
+static int16 mdp_scale_0p8_to_8p0_C0[MDP_SCALE_COEFF_NUM] = {
+ 0, -7, -13, -19, -24, -28, -32, -34, -37, -39,
+ -40, -41, -41, -41, -40, -40, -38, -37, -35, -33,
+ -31, -29, -26, -24, -21, -18, -15, -13, -10, -7,
+ -5, -2
+};
+
+static int16 mdp_scale_0p8_to_8p0_C1[MDP_SCALE_COEFF_NUM] = {
+ 511, 507, 501, 494, 485, 475, 463, 450, 436, 422,
+ 405, 388, 370, 352, 333, 314, 293, 274, 253, 233,
+ 213, 193, 172, 152, 133, 113, 95, 77, 60, 43,
+ 28, 13
+};
+
+static int16 mdp_scale_0p8_to_8p0_C2[MDP_SCALE_COEFF_NUM] = {
+ 0, 13, 28, 43, 60, 77, 95, 113, 133, 152,
+ 172, 193, 213, 233, 253, 274, 294, 314, 333, 352,
+ 370, 388, 405, 422, 436, 450, 463, 475, 485, 494,
+ 501, 507,
+};
+
+static int16 mdp_scale_0p8_to_8p0_C3[MDP_SCALE_COEFF_NUM] = {
+ 0, -2, -5, -7, -10, -13, -15, -18, -21, -24,
+ -26, -29, -31, -33, -35, -37, -38, -40, -40, -41,
+ -41, -41, -40, -39, -37, -34, -32, -28, -24, -19,
+ -13, -7
+};
+
+/* -------- Downscale, ranging from 0.6x to 0.8x of original size -------- */
+
+static int16 mdp_scale_0p6_to_0p8_C0[MDP_SCALE_COEFF_NUM] = {
+ 104, 96, 89, 82, 75, 68, 61, 55, 49, 43,
+ 38, 33, 28, 24, 20, 16, 12, 9, 6, 4,
+ 2, 0, -2, -4, -5, -6, -7, -7, -8, -8,
+ -8, -8
+};
+
+static int16 mdp_scale_0p6_to_0p8_C1[MDP_SCALE_COEFF_NUM] = {
+ 303, 303, 302, 300, 298, 296, 293, 289, 286, 281,
+ 276, 270, 265, 258, 252, 245, 238, 230, 223, 214,
+ 206, 197, 189, 180, 172, 163, 154, 145, 137, 128,
+ 120, 112
+};
+
+static int16 mdp_scale_0p6_to_0p8_C2[MDP_SCALE_COEFF_NUM] = {
+ 112, 120, 128, 137, 145, 154, 163, 172, 180, 189,
+ 197, 206, 214, 223, 230, 238, 245, 252, 258, 265,
+ 270, 276, 281, 286, 289, 293, 296, 298, 300, 302,
+ 303, 303
+};
+
+static int16 mdp_scale_0p6_to_0p8_C3[MDP_SCALE_COEFF_NUM] = {
+ -8, -8, -8, -8, -7, -7, -6, -5, -4, -2,
+ 0, 2, 4, 6, 9, 12, 16, 20, 24, 28,
+ 33, 38, 43, 49, 55, 61, 68, 75, 82, 89,
+ 96, 104
+};
+
+/* -------- Downscale, ranging from 0.4x to 0.6x of original size -------- */
+
+static int16 mdp_scale_0p4_to_0p6_C0[MDP_SCALE_COEFF_NUM] = {
+ 136, 132, 128, 123, 119, 115, 111, 107, 103, 98,
+ 95, 91, 87, 84, 80, 76, 73, 69, 66, 62,
+ 59, 57, 54, 50, 47, 44, 41, 39, 36, 33,
+ 32, 29
+};
+
+static int16 mdp_scale_0p4_to_0p6_C1[MDP_SCALE_COEFF_NUM] = {
+ 206, 205, 204, 204, 201, 200, 199, 197, 196, 194,
+ 191, 191, 189, 185, 184, 182, 180, 178, 176, 173,
+ 170, 168, 165, 162, 160, 157, 155, 152, 148, 146,
+ 142, 140
+};
+
+static int16 mdp_scale_0p4_to_0p6_C2[MDP_SCALE_COEFF_NUM] = {
+ 140, 142, 146, 148, 152, 155, 157, 160, 162, 165,
+ 168, 170, 173, 176, 178, 180, 182, 184, 185, 189,
+ 191, 191, 194, 196, 197, 199, 200, 201, 204, 204,
+ 205, 206
+};
+
+static int16 mdp_scale_0p4_to_0p6_C3[MDP_SCALE_COEFF_NUM] = {
+ 29, 32, 33, 36, 39, 41, 44, 47, 50, 54,
+ 57, 59, 62, 66, 69, 73, 76, 80, 84, 87,
+ 91, 95, 98, 103, 107, 111, 115, 119, 123, 128,
+ 132, 136
+};
+
+/* -------- Downscale, ranging from 0.2x to 0.4x of original size -------- */
+
+static int16 mdp_scale_0p2_to_0p4_C0[MDP_SCALE_COEFF_NUM] = {
+ 131, 131, 130, 129, 128, 127, 127, 126, 125, 125,
+ 124, 123, 123, 121, 120, 119, 119, 118, 117, 117,
+ 116, 115, 115, 114, 113, 112, 111, 110, 109, 109,
+ 108, 107
+};
+
+static int16 mdp_scale_0p2_to_0p4_C1[MDP_SCALE_COEFF_NUM] = {
+ 141, 140, 140, 140, 140, 139, 138, 138, 138, 137,
+ 137, 137, 136, 137, 137, 137, 136, 136, 136, 135,
+ 135, 135, 134, 134, 134, 134, 134, 133, 133, 132,
+ 132, 132
+};
+
+static int16 mdp_scale_0p2_to_0p4_C2[MDP_SCALE_COEFF_NUM] = {
+ 132, 132, 132, 133, 133, 134, 134, 134, 134, 134,
+ 135, 135, 135, 136, 136, 136, 137, 137, 137, 136,
+ 137, 137, 137, 138, 138, 138, 139, 140, 140, 140,
+ 140, 141
+};
+
+static int16 mdp_scale_0p2_to_0p4_C3[MDP_SCALE_COEFF_NUM] = {
+ 107, 108, 109, 109, 110, 111, 112, 113, 114, 115,
+ 115, 116, 117, 117, 118, 119, 119, 120, 121, 123,
+ 123, 124, 125, 125, 126, 127, 127, 128, 129, 130,
+ 131, 131
+};
+
+static void mdp_update_scale_table(int index, int16 *c0, int16 *c1,
+ int16 *c2, int16 *c3)
+{
+ int i, val;
+
+ for (i = 0; i < MDP_SCALE_COEFF_NUM; i++) {
+ val =
+ ((MDP_SCALE_COEFF_MASK & c1[i]) << 16) |
+ (MDP_SCALE_COEFF_MASK & c0[i]);
+ MDP_OUTP(MDP_PPP_SCALE_COEFF_LSBn(index), val);
+ val =
+ ((MDP_SCALE_COEFF_MASK & c3[i]) << 16) |
+ (MDP_SCALE_COEFF_MASK & c2[i]);
+ MDP_OUTP(MDP_PPP_SCALE_COEFF_MSBn(index), val);
+ index++;
+ }
+}
+
+void mdp_init_scale_table(void)
+{
+ mdp_scale_0p2_to_0p4_mode = MDP_SCALE_FIR;
+ mdp_update_scale_table(MDP_SCALE_0P2_TO_0P4_INDEX,
+ mdp_scale_0p2_to_0p4_C0,
+ mdp_scale_0p2_to_0p4_C1,
+ mdp_scale_0p2_to_0p4_C2,
+ mdp_scale_0p2_to_0p4_C3);
+
+ mdp_scale_0p4_to_0p6_mode = MDP_SCALE_FIR;
+ mdp_update_scale_table(MDP_SCALE_0P4_TO_0P6_INDEX,
+ mdp_scale_0p4_to_0p6_C0,
+ mdp_scale_0p4_to_0p6_C1,
+ mdp_scale_0p4_to_0p6_C2,
+ mdp_scale_0p4_to_0p6_C3);
+
+ mdp_scale_0p6_to_0p8_mode = MDP_SCALE_FIR;
+ mdp_update_scale_table(MDP_SCALE_0P6_TO_0P8_INDEX,
+ mdp_scale_0p6_to_0p8_C0,
+ mdp_scale_0p6_to_0p8_C1,
+ mdp_scale_0p6_to_0p8_C2,
+ mdp_scale_0p6_to_0p8_C3);
+
+ mdp_scale_0p8_to_8p0_mode = MDP_SCALE_FIR;
+ mdp_update_scale_table(MDP_SCALE_0P8_TO_8P0_INDEX,
+ mdp_scale_0p8_to_8p0_C0,
+ mdp_scale_0p8_to_8p0_C1,
+ mdp_scale_0p8_to_8p0_C2,
+ mdp_scale_0p8_to_8p0_C3);
+}
+
+static long long mdp_do_div(long long num, long long den)
+{
+ do_div(num, den);
+ return num;
+}
+
+#define SCALER_PHASE_BITS 29
+#define HAL_MDP_PHASE_STEP_2P50 0x50000000
+#define HAL_MDP_PHASE_STEP_1P66 0x35555555
+#define HAL_MDP_PHASE_STEP_1P25 0x28000000
+
+struct phase_val {
+ int phase_init_x;
+ int phase_init_y;
+ int phase_step_x;
+ int phase_step_y;
+};
+
+static void mdp_calc_scaleInitPhase_3p1(uint32 in_w,
+ uint32 in_h,
+ uint32 out_w,
+ uint32 out_h,
+ boolean is_rotate,
+ boolean is_pp_x,
+ boolean is_pp_y, struct phase_val *pval)
+{
+ uint64 dst_ROI_width;
+ uint64 dst_ROI_height;
+ uint64 src_ROI_width;
+ uint64 src_ROI_height;
+
+ /*
+ * phase_step_x, phase_step_y, phase_init_x and phase_init_y
+ * are represented in fixed-point, unsigned 3.29 format
+ */
+ uint32 phase_step_x = 0;
+ uint32 phase_step_y = 0;
+ uint32 phase_init_x = 0;
+ uint32 phase_init_y = 0;
+ uint32 yscale_filter_sel, xscale_filter_sel;
+ uint32 scale_unit_sel_x, scale_unit_sel_y;
+
+ uint64 numerator, denominator;
+ uint64 temp_dim;
+
+ src_ROI_width = in_w;
+ src_ROI_height = in_h;
+ dst_ROI_width = out_w;
+ dst_ROI_height = out_h;
+
+ /* if there is a 90 degree rotation */
+ if (is_rotate) {
+ /* decide whether to use FIR or M/N for scaling */
+
+ /* if down-scaling by a factor smaller than 1/4 */
+ if (src_ROI_width > (4 * dst_ROI_height))
+ scale_unit_sel_x = 1; /* use M/N scalar */
+ else
+ scale_unit_sel_x = 0; /* use FIR scalar */
+
+ /* if down-scaling by a factor smaller than 1/4 */
+ if (src_ROI_height > (4 * dst_ROI_width))
+ scale_unit_sel_y = 1; /* use M/N scalar */
+ else
+ scale_unit_sel_y = 0; /* use FIR scalar */
+ } else {
+ /* decide whether to use FIR or M/N for scaling */
+
+ if (src_ROI_width > (4 * dst_ROI_width))
+ scale_unit_sel_x = 1; /* use M/N scalar */
+ else
+ scale_unit_sel_x = 0; /* use FIR scalar */
+
+ if (src_ROI_height > (4 * dst_ROI_height))
+ scale_unit_sel_y = 1; /* use M/N scalar */
+ else
+ scale_unit_sel_y = 0; /* use FIR scalar */
+
+ }
+
+ /* if there is a 90 degree rotation */
+ if (is_rotate) {
+ /* swap the width and height of dst ROI */
+ temp_dim = dst_ROI_width;
+ dst_ROI_width = dst_ROI_height;
+ dst_ROI_height = temp_dim;
+ }
+
+ /* calculate phase step for the x direction */
+
+ /* if destination is only 1 pixel wide, the value of phase_step_x
+ is unimportant. Assigning phase_step_x to src ROI width
+ as an arbitrary value. */
+ if (dst_ROI_width == 1)
+ phase_step_x = (uint32) ((src_ROI_width) << SCALER_PHASE_BITS);
+
+ /* if using FIR scalar */
+ else if (scale_unit_sel_x == 0) {
+
+ /* Calculate the quotient ( src_ROI_width - 1 ) / ( dst_ROI_width - 1)
+ with u3.29 precision. Quotient is rounded up to the larger
+ 29th decimal point. */
+ numerator = (src_ROI_width - 1) << SCALER_PHASE_BITS;
+ denominator = (dst_ROI_width - 1); /* never equals to 0 because of the "( dst_ROI_width == 1 ) case" */
+ phase_step_x = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* divide and round up to the larger 29th decimal point. */
+
+ }
+
+ /* if M/N scalar */
+ else if (scale_unit_sel_x == 1) {
+ /* Calculate the quotient ( src_ROI_width ) / ( dst_ROI_width)
+ with u3.29 precision. Quotient is rounded down to the
+ smaller 29th decimal point. */
+ numerator = (src_ROI_width) << SCALER_PHASE_BITS;
+ denominator = (dst_ROI_width);
+ phase_step_x = (uint32) mdp_do_div(numerator, denominator);
+ }
+ /* calculate phase step for the y direction */
+
+ /* if destination is only 1 pixel wide, the value of
+ phase_step_x is unimportant. Assigning phase_step_x
+ to src ROI width as an arbitrary value. */
+ if (dst_ROI_height == 1)
+ phase_step_y = (uint32) ((src_ROI_height) << SCALER_PHASE_BITS);
+
+ /* if FIR scalar */
+ else if (scale_unit_sel_y == 0) {
+ /* Calculate the quotient ( src_ROI_height - 1 ) / ( dst_ROI_height - 1)
+ with u3.29 precision. Quotient is rounded up to the larger
+ 29th decimal point. */
+ numerator = (src_ROI_height - 1) << SCALER_PHASE_BITS;
+ denominator = (dst_ROI_height - 1); /* never equals to 0 because of the "( dst_ROI_height == 1 )" case */
+ phase_step_y = (uint32) mdp_do_div((numerator + denominator - 1), denominator); /* Quotient is rounded up to the larger 29th decimal point. */
+
+ }
+
+ /* if M/N scalar */
+ else if (scale_unit_sel_y == 1) {
+ /* Calculate the quotient ( src_ROI_height ) / ( dst_ROI_height)
+ with u3.29 precision. Quotient is rounded down to the smaller
+ 29th decimal point. */
+ numerator = (src_ROI_height) << SCALER_PHASE_BITS;
+ denominator = (dst_ROI_height);
+ phase_step_y = (uint32) mdp_do_div(numerator, denominator);
+ }
+
+ /* decide which set of FIR coefficients to use */
+ if (phase_step_x > HAL_MDP_PHASE_STEP_2P50)
+ xscale_filter_sel = 0;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P66)
+ xscale_filter_sel = 1;
+ else if (phase_step_x > HAL_MDP_PHASE_STEP_1P25)
+ xscale_filter_sel = 2;
+ else
+ xscale_filter_sel = 3;
+
+ if (phase_step_y > HAL_MDP_PHASE_STEP_2P50)
+ yscale_filter_sel = 0;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P66)
+ yscale_filter_sel = 1;
+ else if (phase_step_y > HAL_MDP_PHASE_STEP_1P25)
+ yscale_filter_sel = 2;
+ else
+ yscale_filter_sel = 3;
+
+ /* calculate phase init for the x direction */
+
+ /* if using FIR scalar */
+ if (scale_unit_sel_x == 0) {
+ if (dst_ROI_width == 1)
+ phase_init_x =
+ (uint32) ((src_ROI_width - 1) << SCALER_PHASE_BITS);
+ else
+ phase_init_x = 0;
+
+ }
+ /* M over N scalar */
+ else if (scale_unit_sel_x == 1)
+ phase_init_x = 0;
+
+ /* calculate phase init for the y direction
+ if using FIR scalar */
+ if (scale_unit_sel_y == 0) {
+ if (dst_ROI_height == 1)
+ phase_init_y =
+ (uint32) ((src_ROI_height -
+ 1) << SCALER_PHASE_BITS);
+ else
+ phase_init_y = 0;
+
+ }
+ /* M over N scalar */
+ else if (scale_unit_sel_y == 1)
+ phase_init_y = 0;
+
+ /* write registers */
+ pval->phase_step_x = (uint32) phase_step_x;
+ pval->phase_step_y = (uint32) phase_step_y;
+ pval->phase_init_x = (uint32) phase_init_x;
+ pval->phase_init_y = (uint32) phase_init_y;
+
+ return;
+}
+
+void mdp_set_scale(MDPIBUF *iBuf,
+ uint32 dst_roi_width,
+ uint32 dst_roi_height,
+ boolean inputRGB, boolean outputRGB, uint32 *pppop_reg_ptr)
+{
+ uint32 dst_roi_width_scale;
+ uint32 dst_roi_height_scale;
+ struct phase_val pval;
+ boolean use_pr;
+ uint32 ppp_scale_config = 0;
+
+ if (!inputRGB)
+ ppp_scale_config |= BIT(6);
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_ASCALE) {
+ if (iBuf->mdpImg.mdpOp & MDPOP_ROT90) {
+ dst_roi_width_scale = dst_roi_height;
+ dst_roi_height_scale = dst_roi_width;
+ } else {
+ dst_roi_width_scale = dst_roi_width;
+ dst_roi_height_scale = dst_roi_height;
+ }
+
+ if ((dst_roi_width_scale != iBuf->roi.width) ||
+ (dst_roi_height_scale != iBuf->roi.height) ||
+ (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
+ *pppop_reg_ptr |=
+ (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
+
+ mdp_calc_scaleInitPhase_3p1(iBuf->roi.width,
+ iBuf->roi.height,
+ dst_roi_width,
+ dst_roi_height,
+ iBuf->mdpImg.
+ mdpOp & MDPOP_ROT90, 1, 1,
+ &pval);
+
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x013c,
+ pval.phase_init_x);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0140,
+ pval.phase_init_y);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0144,
+ pval.phase_step_x);
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0148,
+ pval.phase_step_y);
+
+ use_pr = (inputRGB) && (outputRGB);
+
+ /* x-direction */
+ if ((dst_roi_width_scale == iBuf->roi.width) &&
+ !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
+ *pppop_reg_ptr &= ~PPP_OP_SCALE_X_ON;
+ } else
+ if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
+ 8) {
+ if ((use_pr)
+ && (mdp_scale_0p8_to_8p0_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p8_to_8p0_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P8_TO_8P0_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p8_to_8p0_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p8_to_8p0_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P8_TO_8P0_INDEX,
+ mdp_scale_0p8_to_8p0_C0,
+ mdp_scale_0p8_to_8p0_C1,
+ mdp_scale_0p8_to_8p0_C2,
+ mdp_scale_0p8_to_8p0_C3);
+ }
+ ppp_scale_config |= (SCALE_U1_SET << 2);
+ } else
+ if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
+ 6) {
+ if ((use_pr)
+ && (mdp_scale_0p6_to_0p8_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p6_to_0p8_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P6_TO_0P8_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p6_to_0p8_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p6_to_0p8_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P6_TO_0P8_INDEX,
+ mdp_scale_0p6_to_0p8_C0,
+ mdp_scale_0p6_to_0p8_C1,
+ mdp_scale_0p6_to_0p8_C2,
+ mdp_scale_0p6_to_0p8_C3);
+ }
+ ppp_scale_config |= (SCALE_D2_SET << 2);
+ } else
+ if (((dst_roi_width_scale * 10) / iBuf->roi.width) >
+ 4) {
+ if ((use_pr)
+ && (mdp_scale_0p4_to_0p6_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p4_to_0p6_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P4_TO_0P6_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p4_to_0p6_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p4_to_0p6_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P4_TO_0P6_INDEX,
+ mdp_scale_0p4_to_0p6_C0,
+ mdp_scale_0p4_to_0p6_C1,
+ mdp_scale_0p4_to_0p6_C2,
+ mdp_scale_0p4_to_0p6_C3);
+ }
+ ppp_scale_config |= (SCALE_D1_SET << 2);
+ } else
+ if (((dst_roi_width_scale * 4) / iBuf->roi.width) >=
+ 1) {
+ if ((use_pr)
+ && (mdp_scale_0p2_to_0p4_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p2_to_0p4_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P2_TO_0P4_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p2_to_0p4_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p2_to_0p4_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P2_TO_0P4_INDEX,
+ mdp_scale_0p2_to_0p4_C0,
+ mdp_scale_0p2_to_0p4_C1,
+ mdp_scale_0p2_to_0p4_C2,
+ mdp_scale_0p2_to_0p4_C3);
+ }
+ ppp_scale_config |= (SCALE_D0_SET << 2);
+ } else
+ ppp_scale_config |= BIT(0);
+
+ /* y-direction */
+ if ((dst_roi_height_scale == iBuf->roi.height) &&
+ !(iBuf->mdpImg.mdpOp & MDPOP_SHARPENING)) {
+ *pppop_reg_ptr &= ~PPP_OP_SCALE_Y_ON;
+ } else if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 8) {
+ if ((use_pr)
+ && (mdp_scale_0p8_to_8p0_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p8_to_8p0_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P8_TO_8P0_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p8_to_8p0_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p8_to_8p0_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P8_TO_8P0_INDEX,
+ mdp_scale_0p8_to_8p0_C0,
+ mdp_scale_0p8_to_8p0_C1,
+ mdp_scale_0p8_to_8p0_C2,
+ mdp_scale_0p8_to_8p0_C3);
+ }
+ ppp_scale_config |= (SCALE_U1_SET << 4);
+ } else
+ if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 6) {
+ if ((use_pr)
+ && (mdp_scale_0p6_to_0p8_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p6_to_0p8_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P6_TO_0P8_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p6_to_0p8_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p6_to_0p8_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P6_TO_0P8_INDEX,
+ mdp_scale_0p6_to_0p8_C0,
+ mdp_scale_0p6_to_0p8_C1,
+ mdp_scale_0p6_to_0p8_C2,
+ mdp_scale_0p6_to_0p8_C3);
+ }
+ ppp_scale_config |= (SCALE_D2_SET << 4);
+ } else
+ if (((dst_roi_height_scale * 10) /
+ iBuf->roi.height) > 4) {
+ if ((use_pr)
+ && (mdp_scale_0p4_to_0p6_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p4_to_0p6_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P4_TO_0P6_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p4_to_0p6_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p4_to_0p6_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P4_TO_0P6_INDEX,
+ mdp_scale_0p4_to_0p6_C0,
+ mdp_scale_0p4_to_0p6_C1,
+ mdp_scale_0p4_to_0p6_C2,
+ mdp_scale_0p4_to_0p6_C3);
+ }
+ ppp_scale_config |= (SCALE_D1_SET << 4);
+ } else
+ if (((dst_roi_height_scale * 4) /
+ iBuf->roi.height) >= 1) {
+ if ((use_pr)
+ && (mdp_scale_0p2_to_0p4_mode !=
+ MDP_SCALE_PR)) {
+ mdp_scale_0p2_to_0p4_mode =
+ MDP_SCALE_PR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P2_TO_0P4_INDEX,
+ mdp_scale_pixel_repeat_C0,
+ mdp_scale_pixel_repeat_C1,
+ mdp_scale_pixel_repeat_C2,
+ mdp_scale_pixel_repeat_C3);
+ } else if ((!use_pr)
+ && (mdp_scale_0p2_to_0p4_mode !=
+ MDP_SCALE_FIR)) {
+ mdp_scale_0p2_to_0p4_mode =
+ MDP_SCALE_FIR;
+ mdp_update_scale_table
+ (MDP_SCALE_0P2_TO_0P4_INDEX,
+ mdp_scale_0p2_to_0p4_C0,
+ mdp_scale_0p2_to_0p4_C1,
+ mdp_scale_0p2_to_0p4_C2,
+ mdp_scale_0p2_to_0p4_C3);
+ }
+ ppp_scale_config |= (SCALE_D0_SET << 4);
+ } else
+ ppp_scale_config |= BIT(1);
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_SHARPENING) {
+ ppp_scale_config |= BIT(7);
+ MDP_OUTP(MDP_BASE + 0x50020,
+ iBuf->mdpImg.sp_value);
+ }
+
+ MDP_OUTP(MDP_BASE + 0x10230, ppp_scale_config);
+ } else {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ASCALE);
+ }
+ }
+}
+
+void mdp_adjust_start_addr(uint8 **src0,
+ uint8 **src1,
+ int v_slice,
+ int h_slice,
+ int x,
+ int y,
+ uint32 width,
+ uint32 height, int bpp, MDPIBUF *iBuf, int layer)
+{
+ switch (layer) {
+ case 0:
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0200, (y << 16) | (x));
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0208,
+ (height << 16) | (width));
+ break;
+
+ case 1:
+ /* MDP 3.1 HW bug workaround */
+ if (iBuf->ibuf_type == MDP_YCRYCB_H2V1) {
+ *src0 += (x + y * width) * bpp;
+ x = y = 0;
+ width = iBuf->roi.dst_width;
+ height = iBuf->roi.dst_height;
+ }
+
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x0204, (y << 16) | (x));
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x020c,
+ (height << 16) | (width));
+ break;
+
+ case 2:
+ MDP_OUTP(MDP_CMD_DEBUG_ACCESS_BASE + 0x019c, (y << 16) | (x));
+ break;
+ }
+}
+
+void mdp_set_blend_attr(MDPIBUF *iBuf,
+ uint32 *alpha,
+ uint32 *tpVal,
+ uint32 perPixelAlpha, uint32 *pppop_reg_ptr)
+{
+ int bg_alpha;
+
+ *alpha = iBuf->mdpImg.alpha;
+ *tpVal = iBuf->mdpImg.tpVal;
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_FG_PM_ALPHA) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON | PPP_OP_BLEND_CONSTANT_ALPHA;
+
+ bg_alpha = PPP_BLEND_BG_USE_ALPHA_SEL |
+ PPP_BLEND_BG_ALPHA_REVERSE;
+
+ if (perPixelAlpha)
+ bg_alpha |= PPP_BLEND_BG_SRCPIXEL_ALPHA;
+ else
+ bg_alpha |= PPP_BLEND_BG_CONSTANT_ALPHA;
+
+ outpdw(MDP_BASE + 0x70010, bg_alpha);
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+ *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+ } else if (perPixelAlpha) {
+ *pppop_reg_ptr |= PPP_OP_ROT_ON |
+ PPP_OP_BLEND_ON | PPP_OP_BLEND_SRCPIXEL_ALPHA;
+ } else {
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ && (iBuf->mdpImg.alpha == 0xff)) {
+ iBuf->mdpImg.mdpOp &= ~(MDPOP_ALPHAB);
+ }
+
+ if ((iBuf->mdpImg.mdpOp & MDPOP_ALPHAB)
+ || (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)) {
+ *pppop_reg_ptr |=
+ PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
+ PPP_OP_BLEND_CONSTANT_ALPHA |
+ PPP_OP_BLEND_ALPHA_BLEND_NORMAL;
+ }
+
+ if (iBuf->mdpImg.mdpOp & MDPOP_TRANSP)
+ *pppop_reg_ptr |= PPP_BLEND_CALPHA_TRNASP;
+ }
+}
diff --git a/drivers/staging/msm/mdp_vsync.c b/drivers/staging/msm/mdp_vsync.c
new file mode 100644
index 000000000000..bbd456044356
--- /dev/null
+++ b/drivers/staging/msm/mdp_vsync.c
@@ -0,0 +1,389 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/hrtimer.h>
+#include <linux/vmalloc.h>
+#include <linux/clk.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <mach/gpio.h>
+
+#include "mdp.h"
+#include "msm_fb.h"
+#include "mddihost.h"
+
+#ifdef CONFIG_FB_MSM_MDP40
+#define MDP_SYNC_CFG_0 0x100
+#define MDP_SYNC_STATUS_0 0x10c
+#define MDP_PRIM_VSYNC_OUT_CTRL 0x118
+#define MDP_PRIM_VSYNC_INIT_VAL 0x128
+#else
+#define MDP_SYNC_CFG_0 0x300
+#define MDP_SYNC_STATUS_0 0x30c
+#define MDP_PRIM_VSYNC_OUT_CTRL 0x318
+#define MDP_PRIM_VSYNC_INIT_VAL 0x328
+#endif
+
+extern mddi_lcd_type mddi_lcd_idx;
+extern spinlock_t mdp_spin_lock;
+extern struct workqueue_struct *mdp_vsync_wq;
+extern int lcdc_mode;
+extern int vsync_mode;
+
+#ifdef MDP_HW_VSYNC
+int vsync_above_th = 4;
+int vsync_start_th = 1;
+int vsync_load_cnt;
+
+struct clk *mdp_vsync_clk;
+
+void mdp_hw_vsync_clk_enable(struct msm_fb_data_type *mfd)
+{
+ if (mfd->use_mdp_vsync)
+ clk_enable(mdp_vsync_clk);
+}
+
+void mdp_hw_vsync_clk_disable(struct msm_fb_data_type *mfd)
+{
+ if (mfd->use_mdp_vsync)
+ clk_disable(mdp_vsync_clk);
+}
+#endif
+
+static void mdp_set_vsync(unsigned long data)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+ struct msm_fb_panel_data *pdata = NULL;
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+
+ if ((pdata) && (pdata->set_vsync_notifier == NULL))
+ return;
+
+ init_timer(&mfd->vsync_resync_timer);
+ mfd->vsync_resync_timer.function = mdp_set_vsync;
+ mfd->vsync_resync_timer.data = data;
+ mfd->vsync_resync_timer.expires =
+ jiffies + mfd->panel_info.lcd.vsync_notifier_period;
+ add_timer(&mfd->vsync_resync_timer);
+
+ if ((mfd->panel_info.lcd.vsync_enable) && (mfd->panel_power_on)
+ && (!mfd->vsync_handler_pending)) {
+ mfd->vsync_handler_pending = TRUE;
+ if (!queue_work(mdp_vsync_wq, &mfd->vsync_resync_worker)) {
+ MSM_FB_INFO
+ ("mdp_set_vsync: can't queue_work! -> needs to increase vsync_resync_timer_duration\n");
+ }
+ } else {
+ MSM_FB_DEBUG
+ ("mdp_set_vsync failed! EN:%d PWR:%d PENDING:%d\n",
+ mfd->panel_info.lcd.vsync_enable, mfd->panel_power_on,
+ mfd->vsync_handler_pending);
+ }
+}
+
+static void mdp_vsync_handler(void *data)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
+
+ if (mfd->use_mdp_vsync) {
+#ifdef MDP_HW_VSYNC
+ if (mfd->panel_power_on)
+ MDP_OUTP(MDP_BASE + MDP_SYNC_STATUS_0, vsync_load_cnt);
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, TRUE);
+#endif
+ } else {
+ mfd->last_vsync_timetick = ktime_get_real();
+ }
+
+ mfd->vsync_handler_pending = FALSE;
+}
+
+irqreturn_t mdp_hw_vsync_handler_proxy(int irq, void *data)
+{
+ /*
+ * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
+ * but getting inaccurate timing in mdp_vsync_handler()
+ * disable_irq(MDP_HW_VSYNC_IRQ);
+ */
+ mdp_vsync_handler(data);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef MDP_HW_VSYNC
+static void mdp_set_sync_cfg_0(struct msm_fb_data_type *mfd, int vsync_cnt)
+{
+ unsigned long cfg;
+
+ cfg = mfd->total_lcd_lines - 1;
+ cfg <<= MDP_SYNCFG_HGT_LOC;
+ if (mfd->panel_info.lcd.hw_vsync_mode)
+ cfg |= MDP_SYNCFG_VSYNC_EXT_EN;
+ cfg |= (MDP_SYNCFG_VSYNC_INT_EN | vsync_cnt);
+
+ MDP_OUTP(MDP_BASE + MDP_SYNC_CFG_0, cfg);
+}
+#endif
+
+void mdp_config_vsync(struct msm_fb_data_type *mfd)
+{
+
+ /* vsync on primary lcd only for now */
+ if ((mfd->dest != DISPLAY_LCD) || (mfd->panel_info.pdest != DISPLAY_1)
+ || (!vsync_mode)) {
+ goto err_handle;
+ }
+
+ if (mfd->panel_info.lcd.vsync_enable) {
+ mfd->total_porch_lines = mfd->panel_info.lcd.v_back_porch +
+ mfd->panel_info.lcd.v_front_porch +
+ mfd->panel_info.lcd.v_pulse_width;
+ mfd->total_lcd_lines =
+ mfd->panel_info.yres + mfd->total_porch_lines;
+ mfd->lcd_ref_usec_time =
+ 100000000 / mfd->panel_info.lcd.refx100;
+ mfd->vsync_handler_pending = FALSE;
+ mfd->last_vsync_timetick.tv.sec = 0;
+ mfd->last_vsync_timetick.tv.nsec = 0;
+
+#ifdef MDP_HW_VSYNC
+ if (mdp_vsync_clk == NULL)
+ mdp_vsync_clk = clk_get(NULL, "mdp_vsync_clk");
+
+ if (IS_ERR(mdp_vsync_clk)) {
+ printk(KERN_ERR "error: can't get mdp_vsync_clk!\n");
+ mfd->use_mdp_vsync = 0;
+ } else
+ mfd->use_mdp_vsync = 1;
+
+ if (mfd->use_mdp_vsync) {
+ uint32 vsync_cnt_cfg, vsync_cnt_cfg_dem;
+ uint32 mdp_vsync_clk_speed_hz;
+
+ mdp_vsync_clk_speed_hz = clk_get_rate(mdp_vsync_clk);
+
+ if (mdp_vsync_clk_speed_hz == 0) {
+ mfd->use_mdp_vsync = 0;
+ } else {
+ /*
+ * Do this calculation in 2 steps for
+ * rounding uint32 properly.
+ */
+ vsync_cnt_cfg_dem =
+ (mfd->panel_info.lcd.refx100 *
+ mfd->total_lcd_lines) / 100;
+ vsync_cnt_cfg =
+ (mdp_vsync_clk_speed_hz) /
+ vsync_cnt_cfg_dem;
+
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
+ FALSE);
+ mdp_hw_vsync_clk_enable(mfd);
+
+ mdp_set_sync_cfg_0(mfd, vsync_cnt_cfg);
+
+ /*
+ * load the last line + 1 to be in the
+ * safety zone
+ */
+ vsync_load_cnt = mfd->panel_info.yres;
+
+ /* line counter init value at the next pulse */
+ MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_INIT_VAL,
+ vsync_load_cnt);
+
+ /*
+ * external vsync source pulse width and
+ * polarity flip
+ */
+ MDP_OUTP(MDP_BASE + MDP_PRIM_VSYNC_OUT_CTRL,
+ BIT(30) | BIT(0));
+
+
+ /* threshold */
+ MDP_OUTP(MDP_BASE + 0x200,
+ (vsync_above_th << 16) |
+ (vsync_start_th));
+
+ mdp_hw_vsync_clk_disable(mfd);
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK,
+ MDP_BLOCK_POWER_OFF, FALSE);
+ }
+ }
+#else
+ mfd->use_mdp_vsync = 0;
+ hrtimer_init(&mfd->dma_hrtimer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ mfd->dma_hrtimer.function = mdp_dma2_vsync_hrtimer_handler;
+ mfd->vsync_width_boundary = vmalloc(mfd->panel_info.xres * 4);
+#endif
+
+ mfd->channel_irq = 0;
+ if (mfd->panel_info.lcd.hw_vsync_mode) {
+ u32 vsync_gpio = mfd->vsync_gpio;
+ u32 ret;
+
+ if (vsync_gpio == -1) {
+ MSM_FB_INFO("vsync_gpio not defined!\n");
+ goto err_handle;
+ }
+
+ ret = gpio_tlmm_config(GPIO_CFG
+ (vsync_gpio,
+ (mfd->use_mdp_vsync) ? 1 : 0,
+ GPIO_INPUT,
+ GPIO_PULL_DOWN,
+ GPIO_2MA),
+ GPIO_ENABLE);
+ if (ret)
+ goto err_handle;
+
+ if (!mfd->use_mdp_vsync) {
+ mfd->channel_irq = MSM_GPIO_TO_INT(vsync_gpio);
+ if (request_irq
+ (mfd->channel_irq,
+ &mdp_hw_vsync_handler_proxy,
+ IRQF_TRIGGER_FALLING, "VSYNC_GPIO",
+ (void *)mfd)) {
+ MSM_FB_INFO
+ ("irq=%d failed! vsync_gpio=%d\n",
+ mfd->channel_irq,
+ vsync_gpio);
+ goto err_handle;
+ }
+ }
+ }
+
+ mdp_set_vsync((unsigned long)mfd);
+ }
+
+ return;
+
+err_handle:
+ if (mfd->vsync_width_boundary)
+ vfree(mfd->vsync_width_boundary);
+ mfd->panel_info.lcd.vsync_enable = FALSE;
+ printk(KERN_ERR "%s: failed!\n", __func__);
+}
+
+void mdp_vsync_resync_workqueue_handler(struct work_struct *work)
+{
+ struct msm_fb_data_type *mfd = NULL;
+ int vsync_fnc_enabled = FALSE;
+ struct msm_fb_panel_data *pdata = NULL;
+
+ mfd = container_of(work, struct msm_fb_data_type, vsync_resync_worker);
+
+ if (mfd) {
+ if (mfd->panel_power_on) {
+ pdata =
+ (struct msm_fb_panel_data *)mfd->pdev->dev.
+ platform_data;
+
+ /*
+ * we need to turn on MDP power if it uses MDP vsync
+ * HW block in SW mode
+ */
+ if ((!mfd->panel_info.lcd.hw_vsync_mode) &&
+ (mfd->use_mdp_vsync) &&
+ (pdata) && (pdata->set_vsync_notifier != NULL)) {
+ /*
+ * enable pwr here since we can't enable it in
+ * vsync callback in isr mode
+ */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON,
+ FALSE);
+ }
+
+ if (pdata->set_vsync_notifier != NULL) {
+ vsync_fnc_enabled = TRUE;
+ pdata->set_vsync_notifier(mdp_vsync_handler,
+ (void *)mfd);
+ }
+ }
+ }
+
+ if ((mfd) && (!vsync_fnc_enabled))
+ mfd->vsync_handler_pending = FALSE;
+}
+
+boolean mdp_hw_vsync_set_handler(msm_fb_vsync_handler_type handler, void *data)
+{
+ /*
+ * ToDo: tried enabling/disabling GPIO MDP HW VSYNC interrupt
+ * but getting inaccurate timing in mdp_vsync_handler()
+ * enable_irq(MDP_HW_VSYNC_IRQ);
+ */
+
+ return TRUE;
+}
+
+uint32 mdp_get_lcd_line_counter(struct msm_fb_data_type *mfd)
+{
+ uint32 elapsed_usec_time;
+ uint32 lcd_line;
+ ktime_t last_vsync_timetick_local;
+ ktime_t curr_time;
+ unsigned long flag;
+
+ if ((!mfd->panel_info.lcd.vsync_enable) || (!vsync_mode))
+ return 0;
+
+ spin_lock_irqsave(&mdp_spin_lock, flag);
+ last_vsync_timetick_local = mfd->last_vsync_timetick;
+ spin_unlock_irqrestore(&mdp_spin_lock, flag);
+
+ curr_time = ktime_get_real();
+ elapsed_usec_time =
+ ((curr_time.tv.sec - last_vsync_timetick_local.tv.sec) * 1000000) +
+ ((curr_time.tv.nsec - last_vsync_timetick_local.tv.nsec) / 1000);
+
+ elapsed_usec_time = elapsed_usec_time % mfd->lcd_ref_usec_time;
+
+ /* lcd line calculation referencing to line counter = 0 */
+ lcd_line =
+ (elapsed_usec_time * mfd->total_lcd_lines) / mfd->lcd_ref_usec_time;
+
+ /* lcd line adjusment referencing to the actual line counter at vsync */
+ lcd_line =
+ (mfd->total_lcd_lines - mfd->panel_info.lcd.v_back_porch +
+ lcd_line) % (mfd->total_lcd_lines + 1);
+
+ if (lcd_line > mfd->total_lcd_lines) {
+ MSM_FB_INFO
+ ("mdp_get_lcd_line_counter: mdp_lcd_rd_cnt >= mfd->total_lcd_lines error!\n");
+ }
+
+ return lcd_line;
+}
diff --git a/drivers/staging/msm/memory.c b/drivers/staging/msm/memory.c
new file mode 100644
index 000000000000..cc80fdf17d61
--- /dev/null
+++ b/drivers/staging/msm/memory.c
@@ -0,0 +1,214 @@
+/* arch/arm/mach-msm/memory.c
+ *
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/mach/map.h>
+#include "memory_ll.h"
+#include <asm/cacheflush.h>
+#if defined(CONFIG_MSM_NPA_REMOTE)
+#include "npa_remote.h"
+#include <linux/completion.h>
+#include <linux/err.h>
+#endif
+
+int arch_io_remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ unsigned long pfn_addr = pfn << PAGE_SHIFT;
+/*
+ if ((pfn_addr >= 0x88000000) && (pfn_addr < 0xD0000000)) {
+ prot = pgprot_device(prot);
+ printk("remapping device %lx\n", prot);
+ }
+*/
+ panic("Memory remap PFN stuff not done\n");
+ return remap_pfn_range(vma, addr, pfn, size, prot);
+}
+
+void *zero_page_strongly_ordered;
+
+static void map_zero_page_strongly_ordered(void)
+{
+ if (zero_page_strongly_ordered)
+ return;
+/*
+ zero_page_strongly_ordered =
+ ioremap_strongly_ordered(page_to_pfn(empty_zero_page)
+ << PAGE_SHIFT, PAGE_SIZE);
+*/
+ panic("Strongly ordered memory functions not implemented\n");
+}
+
+void write_to_strongly_ordered_memory(void)
+{
+ map_zero_page_strongly_ordered();
+ *(int *)zero_page_strongly_ordered = 0;
+}
+EXPORT_SYMBOL(write_to_strongly_ordered_memory);
+
+void flush_axi_bus_buffer(void)
+{
+ __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" \
+ : : "r" (0) : "memory");
+ write_to_strongly_ordered_memory();
+}
+
+#define CACHE_LINE_SIZE 32
+
+/* These cache related routines make the assumption that the associated
+ * physical memory is contiguous. They will operate on all (L1
+ * and L2 if present) caches.
+ */
+void clean_and_invalidate_caches(unsigned long vstart,
+ unsigned long length, unsigned long pstart)
+{
+ unsigned long vaddr;
+
+ for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
+ asm ("mcr p15, 0, %0, c7, c14, 1" : : "r" (vaddr));
+#ifdef CONFIG_OUTER_CACHE
+ outer_flush_range(pstart, pstart + length);
+#endif
+ asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
+ asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+
+ flush_axi_bus_buffer();
+}
+
+void clean_caches(unsigned long vstart,
+ unsigned long length, unsigned long pstart)
+{
+ unsigned long vaddr;
+
+ for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
+ asm ("mcr p15, 0, %0, c7, c10, 1" : : "r" (vaddr));
+#ifdef CONFIG_OUTER_CACHE
+ outer_clean_range(pstart, pstart + length);
+#endif
+ asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
+ asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+
+ flush_axi_bus_buffer();
+}
+
+void invalidate_caches(unsigned long vstart,
+ unsigned long length, unsigned long pstart)
+{
+ unsigned long vaddr;
+
+ for (vaddr = vstart; vaddr < vstart + length; vaddr += CACHE_LINE_SIZE)
+ asm ("mcr p15, 0, %0, c7, c6, 1" : : "r" (vaddr));
+#ifdef CONFIG_OUTER_CACHE
+ outer_inv_range(pstart, pstart + length);
+#endif
+ asm ("mcr p15, 0, %0, c7, c10, 4" : : "r" (0));
+ asm ("mcr p15, 0, %0, c7, c5, 0" : : "r" (0));
+
+ flush_axi_bus_buffer();
+}
+
+void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment)
+{
+ void *unused_addr = NULL;
+ unsigned long addr, tmp_size, unused_size;
+
+ /* Allocate maximum size needed, see where it ends up.
+ * Then free it -- in this path there are no other allocators
+ * so we can depend on getting the same address back
+ * when we allocate a smaller piece that is aligned
+ * at the end (if necessary) and the piece we really want,
+ * then free the unused first piece.
+ */
+
+ tmp_size = size + alignment - PAGE_SIZE;
+ addr = (unsigned long)alloc_bootmem(tmp_size);
+ free_bootmem(__pa(addr), tmp_size);
+
+ unused_size = alignment - (addr % alignment);
+ if (unused_size)
+ unused_addr = alloc_bootmem(unused_size);
+
+ addr = (unsigned long)alloc_bootmem(size);
+ if (unused_size)
+ free_bootmem(__pa(unused_addr), unused_size);
+
+ return (void *)addr;
+}
+
+#if defined(CONFIG_MSM_NPA_REMOTE)
+struct npa_client *npa_memory_client;
+#endif
+
+static int change_memory_power_state(unsigned long start_pfn,
+ unsigned long nr_pages, int state)
+{
+#if defined(CONFIG_MSM_NPA_REMOTE)
+ static atomic_t node_created_flag = ATOMIC_INIT(1);
+#else
+ unsigned long start;
+ unsigned long size;
+ unsigned long virtual;
+#endif
+ int rc = 0;
+
+#if defined(CONFIG_MSM_NPA_REMOTE)
+ if (atomic_dec_and_test(&node_created_flag)) {
+ /* Create NPA 'required' client. */
+ npa_memory_client = npa_create_sync_client(NPA_MEMORY_NODE_NAME,
+ "memory node", NPA_CLIENT_REQUIRED);
+ if (IS_ERR(npa_memory_client)) {
+ rc = PTR_ERR(npa_memory_client);
+ return rc;
+ }
+ }
+
+ rc = npa_issue_required_request(npa_memory_client, state);
+#else
+ if (state == MEMORY_DEEP_POWERDOWN) {
+ /* simulate turning off memory by writing bit pattern into it */
+ start = start_pfn << PAGE_SHIFT;
+ size = nr_pages << PAGE_SHIFT;
+ virtual = __phys_to_virt(start);
+ memset((void *)virtual, 0x27, size);
+ }
+#endif
+ return rc;
+}
+
+int platform_physical_remove_pages(unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ return change_memory_power_state(start_pfn, nr_pages,
+ MEMORY_DEEP_POWERDOWN);
+}
+
+int platform_physical_add_pages(unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ return change_memory_power_state(start_pfn, nr_pages, MEMORY_ACTIVE);
+}
+
+int platform_physical_low_power_pages(unsigned long start_pfn,
+ unsigned long nr_pages)
+{
+ return change_memory_power_state(start_pfn, nr_pages,
+ MEMORY_SELF_REFRESH);
+}
diff --git a/drivers/staging/msm/memory_ll.h b/drivers/staging/msm/memory_ll.h
new file mode 100644
index 000000000000..18a239a89a78
--- /dev/null
+++ b/drivers/staging/msm/memory_ll.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __ASM_ARCH_MEMORY_LL_H
+#define __ASM_ARCH_MEMORY_LL_H
+
+#define MAX_PHYSMEM_BITS 32
+#define SECTION_SIZE_BITS 25
+
+#define HAS_ARCH_IO_REMAP_PFN_RANGE
+
+#ifndef __ASSEMBLY__
+void *alloc_bootmem_aligned(unsigned long size, unsigned long alignment);
+void clean_and_invalidate_caches(unsigned long, unsigned long, unsigned long);
+void clean_caches(unsigned long, unsigned long, unsigned long);
+void invalidate_caches(unsigned long, unsigned long, unsigned long);
+int platform_physical_remove_pages(unsigned long, unsigned long);
+int platform_physical_add_pages(unsigned long, unsigned long);
+int platform_physical_low_power_pages(unsigned long, unsigned long);
+
+#ifdef CONFIG_ARCH_MSM_ARM11
+void write_to_strongly_ordered_memory(void);
+
+#include <asm/mach-types.h>
+
+#define arch_barrier_extra() do \
+ { if (machine_is_msm7x27_surf() || machine_is_msm7x27_ffa()) \
+ write_to_strongly_ordered_memory(); \
+ } while (0)
+#endif
+
+#ifdef CONFIG_CACHE_L2X0
+extern void l2x0_cache_sync(void);
+#define finish_arch_switch(prev) do { l2x0_cache_sync(); } while (0)
+#endif
+
+#endif
+
+#ifdef CONFIG_ARCH_MSM_SCORPION
+#define arch_has_speculative_dfetch() 1
+#endif
+
+#endif
+
+/* these correspond to values known by the modem */
+#define MEMORY_DEEP_POWERDOWN 0
+#define MEMORY_SELF_REFRESH 1
+#define MEMORY_ACTIVE 2
+
+#define NPA_MEMORY_NODE_NAME "/mem/ebi1/cs1"
diff --git a/drivers/staging/msm/msm_fb.c b/drivers/staging/msm/msm_fb.c
new file mode 100644
index 000000000000..af5620e4eee1
--- /dev/null
+++ b/drivers/staging/msm/msm_fb.c
@@ -0,0 +1,2354 @@
+/*
+ *
+ * Core MSM framebuffer driver.
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include "msm_mdp.h"
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <mach/board.h>
+#include <linux/uaccess.h>
+
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+#include <linux/console.h>
+#include <linux/leds.h>
+#include <asm/dma-mapping.h>
+
+
+#define MSM_FB_C
+#include "msm_fb.h"
+#include "mddihosti.h"
+#include "tvenc.h"
+#include "mdp.h"
+#include "mdp4.h"
+
+#ifdef CONFIG_FB_MSM_LOGO
+#define INIT_IMAGE_FILE "/logo.rle"
+extern int load_565rle_image(char *filename);
+#endif
+
+
+#define pgprot_noncached(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
+#define pgprot_writecombine(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+#define pgprot_device(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK|L_PTE_EXEC, L_PTE_MT_DEV_NONSHARED)
+#define pgprot_writethroughcache(prot) \
+ __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITETHROUGH)
+#define pgprot_writebackcache(prot) \
+ __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEBACK)
+#define pgprot_writebackwacache(prot) \
+ __pgprot((pgprot_val(prot) & ~L_PTE_MT_MASK) | L_PTE_MT_WRITEALLOC)
+
+static unsigned char *fbram;
+static unsigned char *fbram_phys;
+static int fbram_size;
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+int vsync_mode = 1;
+
+#define MAX_FBI_LIST 32
+static struct fb_info *fbi_list[MAX_FBI_LIST];
+static int fbi_list_index;
+
+static struct msm_fb_data_type *mfd_list[MAX_FBI_LIST];
+static int mfd_list_index;
+
+static u32 msm_fb_pseudo_palette[16] = {
+ 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
+};
+
+u32 msm_fb_debug_enabled;
+/* Setting msm_fb_msg_level to 8 prints out ALL messages */
+u32 msm_fb_msg_level = 7;
+
+/* Setting mddi_msg_level to 8 prints out ALL messages */
+u32 mddi_msg_level = 5;
+
+extern int32 mdp_block_power_cnt[MDP_MAX_BLOCK];
+extern unsigned long mdp_timer_duration;
+
+static int msm_fb_register(struct msm_fb_data_type *mfd);
+static int msm_fb_open(struct fb_info *info, int user);
+static int msm_fb_release(struct fb_info *info, int user);
+static int msm_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd);
+int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd);
+static int msm_fb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int msm_fb_set_par(struct fb_info *info);
+static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
+ boolean op_enable);
+static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd);
+static int msm_fb_resume_sub(struct msm_fb_data_type *mfd);
+static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma);
+
+#ifdef MSM_FB_ENABLE_DBGFS
+
+#define MSM_FB_MAX_DBGFS 1024
+#define MAX_BACKLIGHT_BRIGHTNESS 255
+
+int msm_fb_debugfs_file_index;
+struct dentry *msm_fb_debugfs_root;
+struct dentry *msm_fb_debugfs_file[MSM_FB_MAX_DBGFS];
+
+struct dentry *msm_fb_get_debugfs_root(void)
+{
+ if (msm_fb_debugfs_root == NULL)
+ msm_fb_debugfs_root = debugfs_create_dir("msm_fb", NULL);
+
+ return msm_fb_debugfs_root;
+}
+
+void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
+ u32 *var)
+{
+ if (msm_fb_debugfs_file_index >= MSM_FB_MAX_DBGFS)
+ return;
+
+ msm_fb_debugfs_file[msm_fb_debugfs_file_index++] =
+ debugfs_create_u32(name, S_IRUGO | S_IWUSR, root, var);
+}
+#endif
+
+int msm_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (!mfd->cursor_update)
+ return -ENODEV;
+
+ return mfd->cursor_update(info, cursor);
+}
+
+static int msm_fb_resource_initialized;
+
+#ifndef CONFIG_FB_BACKLIGHT
+static int lcd_backlight_registered;
+
+static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);
+ int bl_lvl;
+
+ if (value > MAX_BACKLIGHT_BRIGHTNESS)
+ value = MAX_BACKLIGHT_BRIGHTNESS;
+
+ /* This maps android backlight level 0 to 255 into
+ driver backlight level 0 to bl_max with rounding */
+ bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)
+ /(2 * MAX_BACKLIGHT_BRIGHTNESS);
+
+ if (!bl_lvl && value)
+ bl_lvl = 1;
+
+ msm_fb_set_backlight(mfd, bl_lvl, 1);
+}
+
+static struct led_classdev backlight_led = {
+ .name = "lcd-backlight",
+ .brightness = MAX_BACKLIGHT_BRIGHTNESS,
+ .brightness_set = msm_fb_set_bl_brightness,
+};
+#endif
+
+static struct msm_fb_platform_data *msm_fb_pdata;
+
+int msm_fb_detect_client(const char *name)
+{
+ int ret = -EPERM;
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ u32 id;
+#endif
+
+ if (msm_fb_pdata && msm_fb_pdata->detect_client) {
+ ret = msm_fb_pdata->detect_client(name);
+
+ /* if it's non mddi panel, we need to pre-scan
+ mddi client to see if we can disable mddi host */
+
+#ifdef CONFIG_FB_MSM_MDDI_AUTO_DETECT
+ if (!ret && msm_fb_pdata->mddi_prescan)
+ id = mddi_get_client_id();
+#endif
+ }
+
+ return ret;
+}
+
+static int msm_fb_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ int rc;
+
+ MSM_FB_DEBUG("msm_fb_probe\n");
+
+ if ((pdev->id == 0) && (pdev->num_resources > 0)) {
+ msm_fb_pdata = pdev->dev.platform_data;
+ fbram_size =
+ pdev->resource[0].end - pdev->resource[0].start + 1;
+ fbram_phys = (char *)pdev->resource[0].start;
+ fbram = ioremap((unsigned long)fbram_phys, fbram_size);
+
+ if (!fbram) {
+ printk(KERN_ERR "fbram ioremap failed!\n");
+ return -ENOMEM;
+ }
+ MSM_FB_INFO("msm_fb_probe: phy_Addr = 0x%x virt = 0x%x\n",
+ (int)fbram_phys, (int)fbram);
+
+ msm_fb_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!msm_fb_resource_initialized)
+ return -EPERM;
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ mfd->panel_info.frame_count = 0;
+ mfd->bl_level = mfd->panel_info.bl_max;
+
+ if (mfd->panel_info.type == LCDC_PANEL)
+ mfd->allow_set_offset =
+ msm_fb_pdata->allow_set_offset != NULL ?
+ msm_fb_pdata->allow_set_offset() : 0;
+ else
+ mfd->allow_set_offset = 0;
+
+ rc = msm_fb_register(mfd);
+ if (rc)
+ return rc;
+
+#ifdef CONFIG_FB_BACKLIGHT
+ msm_fb_config_backlight(mfd);
+#else
+ /* android supports only one lcd-backlight/lcd for now */
+ if (!lcd_backlight_registered) {
+ if (led_classdev_register(&pdev->dev, &backlight_led))
+ printk(KERN_ERR "led_classdev_register failed\n");
+ else
+ lcd_backlight_registered = 1;
+ }
+#endif
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+}
+
+static int msm_fb_remove(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+
+ MSM_FB_DEBUG("msm_fb_remove\n");
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (msm_fb_suspend_sub(mfd))
+ printk(KERN_ERR "msm_fb_remove: can't stop the device %d\n", mfd->index);
+
+ if (mfd->channel_irq != 0)
+ free_irq(mfd->channel_irq, (void *)mfd);
+
+ if (mfd->vsync_width_boundary)
+ vfree(mfd->vsync_width_boundary);
+
+ if (mfd->vsync_resync_timer.function)
+ del_timer(&mfd->vsync_resync_timer);
+
+ if (mfd->refresh_timer.function)
+ del_timer(&mfd->refresh_timer);
+
+ if (mfd->dma_hrtimer.function)
+ hrtimer_cancel(&mfd->dma_hrtimer);
+
+ /* remove /dev/fb* */
+ unregister_framebuffer(mfd->fbi);
+
+#ifdef CONFIG_FB_BACKLIGHT
+ /* remove /sys/class/backlight */
+ backlight_device_unregister(mfd->fbi->bl_dev);
+#else
+ if (lcd_backlight_registered) {
+ lcd_backlight_registered = 0;
+ led_classdev_unregister(&backlight_led);
+ }
+#endif
+
+#ifdef MSM_FB_ENABLE_DBGFS
+ if (mfd->sub_dir)
+ debugfs_remove(mfd->sub_dir);
+#endif
+
+ return 0;
+}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int msm_fb_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct msm_fb_data_type *mfd;
+ int ret = 0;
+
+ MSM_FB_DEBUG("msm_fb_suspend\n");
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ acquire_console_sem();
+ fb_set_suspend(mfd->fbi, 1);
+
+ ret = msm_fb_suspend_sub(mfd);
+ if (ret != 0) {
+ printk(KERN_ERR "msm_fb: failed to suspend! %d\n", ret);
+ fb_set_suspend(mfd->fbi, 0);
+ } else {
+ pdev->dev.power.power_state = state;
+ }
+
+ release_console_sem();
+ return ret;
+}
+#else
+#define msm_fb_suspend NULL
+#endif
+
+static int msm_fb_suspend_sub(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ /*
+ * suspend this channel
+ */
+ mfd->suspend.sw_refreshing_enable = mfd->sw_refreshing_enable;
+ mfd->suspend.op_enable = mfd->op_enable;
+ mfd->suspend.panel_power_on = mfd->panel_power_on;
+
+ if (mfd->op_enable) {
+ ret =
+ msm_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi,
+ mfd->suspend.op_enable);
+ if (ret) {
+ MSM_FB_INFO
+ ("msm_fb_suspend: can't turn off display!\n");
+ return ret;
+ }
+ mfd->op_enable = FALSE;
+ }
+ /*
+ * try to power down
+ */
+ mdp_pipe_ctrl(MDP_MASTER_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+
+ /*
+ * detach display channel irq if there's any
+ * or wait until vsync-resync completes
+ */
+ if ((mfd->dest == DISPLAY_LCD)) {
+ if (mfd->panel_info.lcd.vsync_enable) {
+ if (mfd->panel_info.lcd.hw_vsync_mode) {
+ if (mfd->channel_irq != 0)
+ disable_irq(mfd->channel_irq);
+ } else {
+ volatile boolean vh_pending;
+ do {
+ vh_pending = mfd->vsync_handler_pending;
+ } while (vh_pending);
+ }
+ }
+ }
+
+ return 0;
+}
+
+#if defined(CONFIG_PM) && !defined(CONFIG_HAS_EARLYSUSPEND)
+static int msm_fb_resume(struct platform_device *pdev)
+{
+ /* This resume function is called when interrupt is enabled.
+ */
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ MSM_FB_DEBUG("msm_fb_resume\n");
+
+ mfd = (struct msm_fb_data_type *)platform_get_drvdata(pdev);
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ acquire_console_sem();
+ ret = msm_fb_resume_sub(mfd);
+ pdev->dev.power.power_state = PMSG_ON;
+ fb_set_suspend(mfd->fbi, 1);
+ release_console_sem();
+
+ return ret;
+}
+#else
+#define msm_fb_resume NULL
+#endif
+
+static int msm_fb_resume_sub(struct msm_fb_data_type *mfd)
+{
+ int ret = 0;
+
+ if ((!mfd) || (mfd->key != MFD_KEY))
+ return 0;
+
+ /* attach display channel irq if there's any */
+ if (mfd->channel_irq != 0)
+ enable_irq(mfd->channel_irq);
+
+ /* resume state var recover */
+ mfd->sw_refreshing_enable = mfd->suspend.sw_refreshing_enable;
+ mfd->op_enable = mfd->suspend.op_enable;
+
+ if (mfd->suspend.panel_power_on) {
+ ret =
+ msm_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi,
+ mfd->op_enable);
+ if (ret)
+ MSM_FB_INFO("msm_fb_resume: can't turn on display!\n");
+ }
+
+ return ret;
+}
+
+static struct platform_driver msm_fb_driver = {
+ .probe = msm_fb_probe,
+ .remove = msm_fb_remove,
+#ifndef CONFIG_HAS_EARLYSUSPEND
+ .suspend = msm_fb_suspend,
+ .resume = msm_fb_resume,
+#endif
+ .shutdown = NULL,
+ .driver = {
+ /* Driver name must match the device name added in platform.c. */
+ .name = "msm_fb",
+ },
+};
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+static void msmfb_early_suspend(struct early_suspend *h)
+{
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ early_suspend);
+ msm_fb_suspend_sub(mfd);
+}
+
+static void msmfb_early_resume(struct early_suspend *h)
+{
+ struct msm_fb_data_type *mfd = container_of(h, struct msm_fb_data_type,
+ early_suspend);
+ msm_fb_resume_sub(mfd);
+}
+#endif
+
+void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save)
+{
+ struct msm_fb_panel_data *pdata;
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+
+ if ((pdata) && (pdata->set_backlight)) {
+ down(&mfd->sem);
+ if ((bkl_lvl != mfd->bl_level) || (!save)) {
+ u32 old_lvl;
+
+ old_lvl = mfd->bl_level;
+ mfd->bl_level = bkl_lvl;
+ pdata->set_backlight(mfd);
+
+ if (!save)
+ mfd->bl_level = old_lvl;
+ }
+ up(&mfd->sem);
+ }
+}
+
+static int msm_fb_blank_sub(int blank_mode, struct fb_info *info,
+ boolean op_enable)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct msm_fb_panel_data *pdata = NULL;
+ int ret = 0;
+
+ if (!op_enable)
+ return -EPERM;
+
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+ if ((!pdata) || (!pdata->on) || (!pdata->off)) {
+ printk(KERN_ERR "msm_fb_blank_sub: no panel operation detected!\n");
+ return -ENODEV;
+ }
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ if (!mfd->panel_power_on) {
+ mdelay(100);
+ ret = pdata->on(mfd->pdev);
+ if (ret == 0) {
+ mfd->panel_power_on = TRUE;
+
+ msm_fb_set_backlight(mfd,
+ mfd->bl_level, 0);
+
+/* ToDo: possible conflict with android which doesn't expect sw refresher */
+/*
+ if (!mfd->hw_refresh)
+ {
+ if ((ret = msm_fb_resume_sw_refresher(mfd)) != 0)
+ {
+ MSM_FB_INFO("msm_fb_blank_sub: msm_fb_resume_sw_refresher failed = %d!\n",ret);
+ }
+ }
+*/
+ }
+ }
+ break;
+
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ case FB_BLANK_POWERDOWN:
+ default:
+ if (mfd->panel_power_on) {
+ int curr_pwr_state;
+
+ mfd->op_enable = FALSE;
+ curr_pwr_state = mfd->panel_power_on;
+ mfd->panel_power_on = FALSE;
+
+ mdelay(100);
+ ret = pdata->off(mfd->pdev);
+ if (ret)
+ mfd->panel_power_on = curr_pwr_state;
+
+ msm_fb_set_backlight(mfd, 0, 0);
+ mfd->op_enable = TRUE;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static void msm_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ cfb_fillrect(info, rect);
+ if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
+ !mfd->sw_currently_refreshing) {
+ struct fb_var_screeninfo var;
+
+ var = info->var;
+ var.reserved[0] = 0x54445055;
+ var.reserved[1] = (rect->dy << 16) | (rect->dx);
+ var.reserved[2] = ((rect->dy + rect->height) << 16) |
+ (rect->dx + rect->width);
+
+ msm_fb_pan_display(&var, info);
+ }
+}
+
+static void msm_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ cfb_copyarea(info, area);
+ if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
+ !mfd->sw_currently_refreshing) {
+ struct fb_var_screeninfo var;
+
+ var = info->var;
+ var.reserved[0] = 0x54445055;
+ var.reserved[1] = (area->dy << 16) | (area->dx);
+ var.reserved[2] = ((area->dy + area->height) << 16) |
+ (area->dx + area->width);
+
+ msm_fb_pan_display(&var, info);
+ }
+}
+
+static void msm_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ cfb_imageblit(info, image);
+ if (!mfd->hw_refresh && (info->var.yoffset == 0) &&
+ !mfd->sw_currently_refreshing) {
+ struct fb_var_screeninfo var;
+
+ var = info->var;
+ var.reserved[0] = 0x54445055;
+ var.reserved[1] = (image->dy << 16) | (image->dx);
+ var.reserved[2] = ((image->dy + image->height) << 16) |
+ (image->dx + image->width);
+
+ msm_fb_pan_display(&var, info);
+ }
+}
+
+static int msm_fb_blank(int blank_mode, struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ return msm_fb_blank_sub(blank_mode, info, mfd->op_enable);
+}
+
+static int msm_fb_set_lut(struct fb_cmap *cmap, struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (!mfd->lut_update)
+ return -ENODEV;
+
+ mfd->lut_update(info, cmap);
+ return 0;
+}
+
+/*
+ * Custom Framebuffer mmap() function for MSM driver.
+ * Differs from standard mmap() function by allowing for customized
+ * page-protection.
+ */
+static int msm_fb_mmap(struct fb_info *info, struct vm_area_struct * vma)
+{
+ /* Get frame buffer memory range. */
+ unsigned long start = info->fix.smem_start;
+ u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ if (off >= len) {
+ /* memory mapped io */
+ off -= len;
+ if (info->var.accel_flags) {
+ mutex_unlock(&info->lock);
+ return -EINVAL;
+ }
+ start = info->fix.mmio_start;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
+ }
+
+ /* Set VM flags. */
+ start &= PAGE_MASK;
+ if ((vma->vm_end - vma->vm_start + off) > len)
+ return -EINVAL;
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ /* This is an IO map - tell maydump to skip this VMA */
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ /* Set VM page protection */
+ if (mfd->mdp_fb_page_protection == MDP_FB_PAGE_PROTECTION_WRITECOMBINE)
+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE)
+ vma->vm_page_prot = pgprot_writethroughcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE)
+ vma->vm_page_prot = pgprot_writebackcache(vma->vm_page_prot);
+ else if (mfd->mdp_fb_page_protection ==
+ MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE)
+ vma->vm_page_prot = pgprot_writebackwacache(vma->vm_page_prot);
+ else
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ /* Remap the frame buffer I/O range */
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static struct fb_ops msm_fb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = msm_fb_open,
+ .fb_release = msm_fb_release,
+ .fb_read = NULL,
+ .fb_write = NULL,
+ .fb_cursor = NULL,
+ .fb_check_var = msm_fb_check_var, /* vinfo check */
+ .fb_set_par = msm_fb_set_par, /* set the video mode according to info->var */
+ .fb_setcolreg = NULL, /* set color register */
+ .fb_blank = msm_fb_blank, /* blank display */
+ .fb_pan_display = msm_fb_pan_display, /* pan display */
+ .fb_fillrect = msm_fb_fillrect, /* Draws a rectangle */
+ .fb_copyarea = msm_fb_copyarea, /* Copy data from area to another */
+ .fb_imageblit = msm_fb_imageblit, /* Draws a image to the display */
+ .fb_rotate = NULL,
+ .fb_sync = NULL, /* wait for blit idle, optional */
+ .fb_ioctl = msm_fb_ioctl, /* perform fb specific ioctl (optional) */
+ .fb_mmap = msm_fb_mmap,
+};
+
+static int msm_fb_register(struct msm_fb_data_type *mfd)
+{
+ int ret = -ENODEV;
+ int bpp;
+ struct msm_panel_info *panel_info = &mfd->panel_info;
+ struct fb_info *fbi = mfd->fbi;
+ struct fb_fix_screeninfo *fix;
+ struct fb_var_screeninfo *var;
+ int *id;
+ int fbram_offset;
+
+ /*
+ * fb info initialization
+ */
+ fix = &fbi->fix;
+ var = &fbi->var;
+
+ fix->type_aux = 0; /* if type == FB_TYPE_INTERLEAVED_PLANES */
+ fix->visual = FB_VISUAL_TRUECOLOR; /* True Color */
+ fix->ywrapstep = 0; /* No support */
+ fix->mmio_start = 0; /* No MMIO Address */
+ fix->mmio_len = 0; /* No MMIO Address */
+ fix->accel = FB_ACCEL_NONE;/* FB_ACCEL_MSM needes to be added in fb.h */
+
+ var->xoffset = 0, /* Offset from virtual to visible */
+ var->yoffset = 0, /* resolution */
+ var->grayscale = 0, /* No graylevels */
+ var->nonstd = 0, /* standard pixel format */
+ var->activate = FB_ACTIVATE_VBL, /* activate it at vsync */
+ var->height = -1, /* height of picture in mm */
+ var->width = -1, /* width of picture in mm */
+ var->accel_flags = 0, /* acceleration flags */
+ var->sync = 0, /* see FB_SYNC_* */
+ var->rotate = 0, /* angle we rotate counter clockwise */
+ mfd->op_enable = FALSE;
+
+ switch (mfd->fb_imgType) {
+ case MDP_RGB_565:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 11;
+ var->blue.length = 5;
+ var->green.length = 6;
+ var->red.length = 5;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 2;
+ break;
+
+ case MDP_RGB_888:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 8;
+ var->red.offset = 16;
+ var->blue.length = 8;
+ var->green.length = 8;
+ var->red.length = 8;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 3;
+ break;
+
+ case MDP_ARGB_8888:
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->xpanstep = 1;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+ var->blue.offset = 0;
+ var->green.offset = 8;
+ var->red.offset = 16;
+ var->blue.length = 8;
+ var->green.length = 8;
+ var->red.length = 8;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ bpp = 3;
+ break;
+
+ case MDP_YCRYCB_H2V1:
+ /* ToDo: need to check TV-Out YUV422i framebuffer format */
+ /* we might need to create new type define */
+ fix->type = FB_TYPE_INTERLEAVED_PLANES;
+ fix->xpanstep = 2;
+ fix->ypanstep = 1;
+ var->vmode = FB_VMODE_NONINTERLACED;
+
+ /* how about R/G/B offset? */
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 11;
+ var->blue.length = 5;
+ var->green.length = 6;
+ var->red.length = 5;
+ var->blue.msb_right = 0;
+ var->green.msb_right = 0;
+ var->red.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ bpp = 2;
+ break;
+
+ default:
+ MSM_FB_ERR("msm_fb_init: fb %d unkown image type!\n",
+ mfd->index);
+ return ret;
+ }
+
+ /* The adreno GPU hardware requires that the pitch be aligned to
+ 32 pixels for color buffers, so for the cases where the GPU
+ is writing directly to fb0, the framebuffer pitch
+ also needs to be 32 pixel aligned */
+
+ if (mfd->index == 0)
+ fix->line_length = ALIGN(panel_info->xres * bpp, 32);
+ else
+ fix->line_length = panel_info->xres * bpp;
+
+ fix->smem_len = fix->line_length * panel_info->yres * mfd->fb_page;
+
+ mfd->var_xres = panel_info->xres;
+ mfd->var_yres = panel_info->yres;
+
+ var->pixclock = mfd->panel_info.clk_rate;
+ mfd->var_pixclock = var->pixclock;
+
+ var->xres = panel_info->xres;
+ var->yres = panel_info->yres;
+ var->xres_virtual = panel_info->xres;
+ var->yres_virtual = panel_info->yres * mfd->fb_page;
+ var->bits_per_pixel = bpp * 8, /* FrameBuffer color depth */
+ /*
+ * id field for fb app
+ */
+ id = (int *)&mfd->panel;
+
+#if defined(CONFIG_FB_MSM_MDP22)
+ snprintf(fix->id, sizeof(fix->id), "msmfb22_%x", (__u32) *id);
+#elif defined(CONFIG_FB_MSM_MDP30)
+ snprintf(fix->id, sizeof(fix->id), "msmfb30_%x", (__u32) *id);
+#elif defined(CONFIG_FB_MSM_MDP31)
+ snprintf(fix->id, sizeof(fix->id), "msmfb31_%x", (__u32) *id);
+#elif defined(CONFIG_FB_MSM_MDP40)
+ snprintf(fix->id, sizeof(fix->id), "msmfb40_%x", (__u32) *id);
+#else
+ error CONFIG_FB_MSM_MDP undefined !
+#endif
+ fbi->fbops = &msm_fb_ops;
+ fbi->flags = FBINFO_FLAG_DEFAULT;
+ fbi->pseudo_palette = msm_fb_pseudo_palette;
+
+ mfd->ref_cnt = 0;
+ mfd->sw_currently_refreshing = FALSE;
+ mfd->sw_refreshing_enable = TRUE;
+ mfd->panel_power_on = FALSE;
+
+ mfd->pan_waiting = FALSE;
+ init_completion(&mfd->pan_comp);
+ init_completion(&mfd->refresher_comp);
+ init_MUTEX(&mfd->sem);
+
+ fbram_offset = PAGE_ALIGN((int)fbram)-(int)fbram;
+ fbram += fbram_offset;
+ fbram_phys += fbram_offset;
+ fbram_size -= fbram_offset;
+
+ if (fbram_size < fix->smem_len) {
+ printk(KERN_ERR "error: no more framebuffer memory!\n");
+ return -ENOMEM;
+ }
+
+ fbi->screen_base = fbram;
+ fbi->fix.smem_start = (unsigned long)fbram_phys;
+
+ memset(fbi->screen_base, 0x0, fix->smem_len);
+
+ mfd->op_enable = TRUE;
+ mfd->panel_power_on = FALSE;
+
+ /* cursor memory allocation */
+ if (mfd->cursor_update) {
+ mfd->cursor_buf = dma_alloc_coherent(NULL,
+ MDP_CURSOR_SIZE,
+ (dma_addr_t *) &mfd->cursor_buf_phys,
+ GFP_KERNEL);
+ if (!mfd->cursor_buf)
+ mfd->cursor_update = 0;
+ }
+
+ if (mfd->lut_update) {
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret)
+ printk(KERN_ERR "%s: fb_alloc_cmap() failed!\n",
+ __func__);
+ }
+
+ if (register_framebuffer(fbi) < 0) {
+ if (mfd->lut_update)
+ fb_dealloc_cmap(&fbi->cmap);
+
+ if (mfd->cursor_buf)
+ dma_free_coherent(NULL,
+ MDP_CURSOR_SIZE,
+ mfd->cursor_buf,
+ (dma_addr_t) mfd->cursor_buf_phys);
+
+ mfd->op_enable = FALSE;
+ return -EPERM;
+ }
+
+ fbram += fix->smem_len;
+ fbram_phys += fix->smem_len;
+ fbram_size -= fix->smem_len;
+
+ MSM_FB_INFO
+ ("FrameBuffer[%d] %dx%d size=%d bytes is registered successfully!\n",
+ mfd->index, fbi->var.xres, fbi->var.yres, fbi->fix.smem_len);
+
+#ifdef CONFIG_FB_MSM_LOGO
+ if (!load_565rle_image(INIT_IMAGE_FILE)) ; /* Flip buffer */
+#endif
+ ret = 0;
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ mfd->early_suspend.suspend = msmfb_early_suspend;
+ mfd->early_suspend.resume = msmfb_early_resume;
+ mfd->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB - 2;
+ register_early_suspend(&mfd->early_suspend);
+#endif
+
+#ifdef MSM_FB_ENABLE_DBGFS
+ {
+ struct dentry *root;
+ struct dentry *sub_dir;
+ char sub_name[2];
+
+ root = msm_fb_get_debugfs_root();
+ if (root != NULL) {
+ sub_name[0] = (char)(mfd->index + 0x30);
+ sub_name[1] = '\0';
+ sub_dir = debugfs_create_dir(sub_name, root);
+ } else {
+ sub_dir = NULL;
+ }
+
+ mfd->sub_dir = sub_dir;
+
+ if (sub_dir) {
+ msm_fb_debugfs_file_create(sub_dir, "op_enable",
+ (u32 *) &mfd->op_enable);
+ msm_fb_debugfs_file_create(sub_dir, "panel_power_on",
+ (u32 *) &mfd->
+ panel_power_on);
+ msm_fb_debugfs_file_create(sub_dir, "ref_cnt",
+ (u32 *) &mfd->ref_cnt);
+ msm_fb_debugfs_file_create(sub_dir, "fb_imgType",
+ (u32 *) &mfd->fb_imgType);
+ msm_fb_debugfs_file_create(sub_dir,
+ "sw_currently_refreshing",
+ (u32 *) &mfd->
+ sw_currently_refreshing);
+ msm_fb_debugfs_file_create(sub_dir,
+ "sw_refreshing_enable",
+ (u32 *) &mfd->
+ sw_refreshing_enable);
+
+ msm_fb_debugfs_file_create(sub_dir, "xres",
+ (u32 *) &mfd->panel_info.
+ xres);
+ msm_fb_debugfs_file_create(sub_dir, "yres",
+ (u32 *) &mfd->panel_info.
+ yres);
+ msm_fb_debugfs_file_create(sub_dir, "bpp",
+ (u32 *) &mfd->panel_info.
+ bpp);
+ msm_fb_debugfs_file_create(sub_dir, "type",
+ (u32 *) &mfd->panel_info.
+ type);
+ msm_fb_debugfs_file_create(sub_dir, "wait_cycle",
+ (u32 *) &mfd->panel_info.
+ wait_cycle);
+ msm_fb_debugfs_file_create(sub_dir, "pdest",
+ (u32 *) &mfd->panel_info.
+ pdest);
+ msm_fb_debugfs_file_create(sub_dir, "backbuff",
+ (u32 *) &mfd->panel_info.
+ fb_num);
+ msm_fb_debugfs_file_create(sub_dir, "clk_rate",
+ (u32 *) &mfd->panel_info.
+ clk_rate);
+ msm_fb_debugfs_file_create(sub_dir, "frame_count",
+ (u32 *) &mfd->panel_info.
+ frame_count);
+
+
+ switch (mfd->dest) {
+ case DISPLAY_LCD:
+ msm_fb_debugfs_file_create(sub_dir,
+ "vsync_enable",
+ (u32 *)&mfd->panel_info.lcd.vsync_enable);
+ msm_fb_debugfs_file_create(sub_dir,
+ "refx100",
+ (u32 *) &mfd->panel_info.lcd. refx100);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_back_porch",
+ (u32 *) &mfd->panel_info.lcd.v_back_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_front_porch",
+ (u32 *) &mfd->panel_info.lcd.v_front_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_pulse_width",
+ (u32 *) &mfd->panel_info.lcd.v_pulse_width);
+ msm_fb_debugfs_file_create(sub_dir,
+ "hw_vsync_mode",
+ (u32 *) &mfd->panel_info.lcd.hw_vsync_mode);
+ msm_fb_debugfs_file_create(sub_dir,
+ "vsync_notifier_period", (u32 *)
+ &mfd->panel_info.lcd.vsync_notifier_period);
+ break;
+
+ case DISPLAY_LCDC:
+ msm_fb_debugfs_file_create(sub_dir,
+ "h_back_porch",
+ (u32 *) &mfd->panel_info.lcdc.h_back_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "h_front_porch",
+ (u32 *) &mfd->panel_info.lcdc.h_front_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "h_pulse_width",
+ (u32 *) &mfd->panel_info.lcdc.h_pulse_width);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_back_porch",
+ (u32 *) &mfd->panel_info.lcdc.v_back_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_front_porch",
+ (u32 *) &mfd->panel_info.lcdc.v_front_porch);
+ msm_fb_debugfs_file_create(sub_dir,
+ "v_pulse_width",
+ (u32 *) &mfd->panel_info.lcdc.v_pulse_width);
+ msm_fb_debugfs_file_create(sub_dir,
+ "border_clr",
+ (u32 *) &mfd->panel_info.lcdc.border_clr);
+ msm_fb_debugfs_file_create(sub_dir,
+ "underflow_clr",
+ (u32 *) &mfd->panel_info.lcdc.underflow_clr);
+ msm_fb_debugfs_file_create(sub_dir,
+ "hsync_skew",
+ (u32 *) &mfd->panel_info.lcdc.hsync_skew);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+#endif /* MSM_FB_ENABLE_DBGFS */
+
+ return ret;
+}
+
+static int msm_fb_open(struct fb_info *info, int user)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (!mfd->ref_cnt) {
+ mdp_set_dma_pan_info(info, NULL, TRUE);
+
+ if (msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable)) {
+ printk(KERN_ERR "msm_fb_open: can't turn on display!\n");
+ return -1;
+ }
+ }
+
+ mfd->ref_cnt++;
+ return 0;
+}
+
+static int msm_fb_release(struct fb_info *info, int user)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ int ret = 0;
+
+ if (!mfd->ref_cnt) {
+ MSM_FB_INFO("msm_fb_release: try to close unopened fb %d!\n",
+ mfd->index);
+ return -EINVAL;
+ }
+
+ mfd->ref_cnt--;
+
+ if (!mfd->ref_cnt) {
+ if ((ret =
+ msm_fb_blank_sub(FB_BLANK_POWERDOWN, info,
+ mfd->op_enable)) != 0) {
+ printk(KERN_ERR "msm_fb_release: can't turn off display!\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+DECLARE_MUTEX(msm_fb_pan_sem);
+
+static int msm_fb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ struct mdp_dirty_region dirty;
+ struct mdp_dirty_region *dirtyPtr = NULL;
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if ((!mfd->op_enable) || (!mfd->panel_power_on))
+ return -EPERM;
+
+ if (var->xoffset > (info->var.xres_virtual - info->var.xres))
+ return -EINVAL;
+
+ if (var->yoffset > (info->var.yres_virtual - info->var.yres))
+ return -EINVAL;
+
+ if (info->fix.xpanstep)
+ info->var.xoffset =
+ (var->xoffset / info->fix.xpanstep) * info->fix.xpanstep;
+
+ if (info->fix.ypanstep)
+ info->var.yoffset =
+ (var->yoffset / info->fix.ypanstep) * info->fix.ypanstep;
+
+ /* "UPDT" */
+ if (var->reserved[0] == 0x54445055) {
+ dirty.xoffset = var->reserved[1] & 0xffff;
+ dirty.yoffset = (var->reserved[1] >> 16) & 0xffff;
+
+ if ((var->reserved[2] & 0xffff) <= dirty.xoffset)
+ return -EINVAL;
+ if (((var->reserved[2] >> 16) & 0xffff) <= dirty.yoffset)
+ return -EINVAL;
+
+ dirty.width = (var->reserved[2] & 0xffff) - dirty.xoffset;
+ dirty.height =
+ ((var->reserved[2] >> 16) & 0xffff) - dirty.yoffset;
+ info->var.yoffset = var->yoffset;
+
+ if (dirty.xoffset < 0)
+ return -EINVAL;
+
+ if (dirty.yoffset < 0)
+ return -EINVAL;
+
+ if ((dirty.xoffset + dirty.width) > info->var.xres)
+ return -EINVAL;
+
+ if ((dirty.yoffset + dirty.height) > info->var.yres)
+ return -EINVAL;
+
+ if ((dirty.width <= 0) || (dirty.height <= 0))
+ return -EINVAL;
+
+ dirtyPtr = &dirty;
+ }
+
+ /* Flip */
+ /* A constant value is used to indicate that we should change the DMA
+ output buffer instead of just panning */
+
+ if (var->reserved[0] == 0x466c6970) {
+ unsigned long length, address;
+ struct file *p_src_file;
+ struct mdp_img imgdata;
+ int bpp;
+
+ if (mfd->allow_set_offset) {
+ imgdata.memory_id = var->reserved[1];
+ imgdata.priv = var->reserved[2];
+
+ /* If there is no memory ID then we want to reset back
+ to the original fb visibility */
+ if (var->reserved[1]) {
+ if (var->reserved[4] == MDP_BLIT_SRC_GEM) {
+ panic("waaaaaaaaaaaaaah");
+ if ( /*get_gem_img(&imgdata,
+ (unsigned long *) &address,
+ &length)*/ -1 < 0) {
+ return -1;
+ }
+ } else {
+ /*get_img(&imgdata, info, &address,
+ &length, &p_src_file);*/
+ panic("waaaaaah");
+ }
+ mfd->ibuf.visible_swapped = TRUE;
+ } else {
+ /* Flip back to the original address
+ adjusted for xoffset and yoffset */
+
+ bpp = info->var.bits_per_pixel / 8;
+ address = (unsigned long) info->fix.smem_start;
+ address += info->var.xoffset * bpp +
+ info->var.yoffset * info->fix.line_length;
+
+ mfd->ibuf.visible_swapped = FALSE;
+ }
+
+ mdp_set_offset_info(info, address,
+ (var->activate == FB_ACTIVATE_VBL));
+
+ mfd->dma_fnc(mfd);
+ return 0;
+ } else
+ return -EINVAL;
+ }
+
+ down(&msm_fb_pan_sem);
+ mdp_set_dma_pan_info(info, dirtyPtr,
+ (var->activate == FB_ACTIVATE_VBL));
+ mdp_dma_pan_update(info);
+ up(&msm_fb_pan_sem);
+
+ ++mfd->panel_info.frame_count;
+ return 0;
+}
+
+static int msm_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+
+ if (var->rotate != FB_ROTATE_UR)
+ return -EINVAL;
+ if (var->grayscale != info->var.grayscale)
+ return -EINVAL;
+
+ switch (var->bits_per_pixel) {
+ case 16:
+ if ((var->green.offset != 5) ||
+ !((var->blue.offset == 11)
+ || (var->blue.offset == 0)) ||
+ !((var->red.offset == 11)
+ || (var->red.offset == 0)) ||
+ (var->blue.length != 5) ||
+ (var->green.length != 6) ||
+ (var->red.length != 5) ||
+ (var->blue.msb_right != 0) ||
+ (var->green.msb_right != 0) ||
+ (var->red.msb_right != 0) ||
+ (var->transp.offset != 0) ||
+ (var->transp.length != 0))
+ return -EINVAL;
+ break;
+
+ case 24:
+ if ((var->blue.offset != 0) ||
+ (var->green.offset != 8) ||
+ (var->red.offset != 16) ||
+ (var->blue.length != 8) ||
+ (var->green.length != 8) ||
+ (var->red.length != 8) ||
+ (var->blue.msb_right != 0) ||
+ (var->green.msb_right != 0) ||
+ (var->red.msb_right != 0) ||
+ !(((var->transp.offset == 0) &&
+ (var->transp.length == 0)) ||
+ ((var->transp.offset == 24) &&
+ (var->transp.length == 8))))
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((var->xres_virtual <= 0) || (var->yres_virtual <= 0))
+ return -EINVAL;
+
+ if (info->fix.smem_len <
+ (var->xres_virtual*var->yres_virtual*(var->bits_per_pixel/8)))
+ return -EINVAL;
+
+ if ((var->xres == 0) || (var->yres == 0))
+ return -EINVAL;
+
+ if ((var->xres > mfd->panel_info.xres) ||
+ (var->yres > mfd->panel_info.yres))
+ return -EINVAL;
+
+ if (var->xoffset > (var->xres_virtual - var->xres))
+ return -EINVAL;
+
+ if (var->yoffset > (var->yres_virtual - var->yres))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int msm_fb_set_par(struct fb_info *info)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ struct fb_var_screeninfo *var = &info->var;
+ int old_imgType;
+ int blank = 0;
+
+ old_imgType = mfd->fb_imgType;
+ switch (var->bits_per_pixel) {
+ case 16:
+ if (var->red.offset == 0)
+ mfd->fb_imgType = MDP_BGR_565;
+ else
+ mfd->fb_imgType = MDP_RGB_565;
+ break;
+
+ case 24:
+ if ((var->transp.offset == 0) && (var->transp.length == 0))
+ mfd->fb_imgType = MDP_RGB_888;
+ else if ((var->transp.offset == 24) &&
+ (var->transp.length == 8)) {
+ mfd->fb_imgType = MDP_ARGB_8888;
+ info->var.bits_per_pixel = 32;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if ((mfd->var_pixclock != var->pixclock) ||
+ (mfd->hw_refresh && ((mfd->fb_imgType != old_imgType) ||
+ (mfd->var_pixclock != var->pixclock) ||
+ (mfd->var_xres != var->xres) ||
+ (mfd->var_yres != var->yres)))) {
+ mfd->var_xres = var->xres;
+ mfd->var_yres = var->yres;
+ mfd->var_pixclock = var->pixclock;
+ blank = 1;
+ }
+
+ if (blank) {
+ msm_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable);
+ msm_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable);
+ }
+
+ return 0;
+}
+
+static int msm_fb_stop_sw_refresher(struct msm_fb_data_type *mfd)
+{
+ if (mfd->hw_refresh)
+ return -EPERM;
+
+ if (mfd->sw_currently_refreshing) {
+ down(&mfd->sem);
+ mfd->sw_currently_refreshing = FALSE;
+ up(&mfd->sem);
+
+ /* wait until the refresher finishes the last job */
+ wait_for_completion_killable(&mfd->refresher_comp);
+ }
+
+ return 0;
+}
+
+int msm_fb_resume_sw_refresher(struct msm_fb_data_type *mfd)
+{
+ boolean do_refresh;
+
+ if (mfd->hw_refresh)
+ return -EPERM;
+
+ down(&mfd->sem);
+ if ((!mfd->sw_currently_refreshing) && (mfd->sw_refreshing_enable)) {
+ do_refresh = TRUE;
+ mfd->sw_currently_refreshing = TRUE;
+ } else {
+ do_refresh = FALSE;
+ }
+ up(&mfd->sem);
+
+ if (do_refresh)
+ mdp_refresh_screen((unsigned long)mfd);
+
+ return 0;
+}
+
+void mdp_ppp_put_img(struct file *p_src_file, struct file *p_dst_file)
+{
+#ifdef CONFIG_ANDROID_PMEM
+ if (p_src_file)
+ put_pmem_file(p_src_file);
+ if (p_dst_file)
+ put_pmem_file(p_dst_file);
+#endif
+}
+
+int mdp_blit(struct fb_info *info, struct mdp_blit_req *req)
+{
+ int ret;
+ struct file *p_src_file = 0, *p_dst_file = 0;
+ if (unlikely(req->src_rect.h == 0 || req->src_rect.w == 0)) {
+ printk(KERN_ERR "mpd_ppp: src img of zero size!\n");
+ return -EINVAL;
+ }
+ if (unlikely(req->dst_rect.h == 0 || req->dst_rect.w == 0))
+ return 0;
+
+ ret = mdp_ppp_blit(info, req, &p_src_file, &p_dst_file);
+ mdp_ppp_put_img(p_src_file, p_dst_file);
+ return ret;
+}
+
+typedef void (*msm_dma_barrier_function_pointer) (void *, size_t);
+
+static inline void msm_fb_dma_barrier_for_rect(struct fb_info *info,
+ struct mdp_img *img, struct mdp_rect *rect,
+ msm_dma_barrier_function_pointer dma_barrier_fp
+ )
+{
+ /*
+ * Compute the start and end addresses of the rectangles.
+ * NOTE: As currently implemented, the data between
+ * the end of one row and the start of the next is
+ * included in the address range rather than
+ * doing multiple calls for each row.
+ */
+
+ char * const pmem_start = info->screen_base;
+/* int bytes_per_pixel = mdp_get_bytes_per_pixel(img->format);
+ unsigned long start = (unsigned long)pmem_start + img->offset +
+ (img->width * rect->y + rect->x) * bytes_per_pixel;
+ size_t size = ((rect->h - 1) * img->width + rect->w) * bytes_per_pixel;
+ (*dma_barrier_fp) ((void *) start, size);
+*/
+ panic("waaaaah");
+}
+
+static inline void msm_dma_nc_pre(void)
+{
+ dmb();
+}
+static inline void msm_dma_wt_pre(void)
+{
+ dmb();
+}
+static inline void msm_dma_todevice_wb_pre(void *start, size_t size)
+{
+ #warning this
+// dma_cache_pre_ops(start, size, DMA_TO_DEVICE);
+}
+
+static inline void msm_dma_fromdevice_wb_pre(void *start, size_t size)
+{
+ #warning this
+// dma_cache_pre_ops(start, size, DMA_FROM_DEVICE);
+}
+
+static inline void msm_dma_nc_post(void)
+{
+ dmb();
+}
+
+static inline void msm_dma_fromdevice_wt_post(void *start, size_t size)
+{
+ #warning this
+// dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
+}
+
+static inline void msm_dma_todevice_wb_post(void *start, size_t size)
+{
+ #warning this
+// dma_cache_post_ops(start, size, DMA_TO_DEVICE);
+}
+
+static inline void msm_dma_fromdevice_wb_post(void *start, size_t size)
+{
+ #warning this
+// dma_cache_post_ops(start, size, DMA_FROM_DEVICE);
+}
+
+/*
+ * Do the write barriers required to guarantee data is committed to RAM
+ * (from CPU cache or internal buffers) before a DMA operation starts.
+ * NOTE: As currently implemented, the data between
+ * the end of one row and the start of the next is
+ * included in the address range rather than
+ * doing multiple calls for each row.
+*/
+static void msm_fb_ensure_memory_coherency_before_dma(struct fb_info *info,
+ struct mdp_blit_req *req_list,
+ int req_list_count)
+{
+#ifdef CONFIG_ARCH_QSD8X50
+ int i;
+
+ /*
+ * Normally, do the requested barriers for each address
+ * range that corresponds to a rectangle.
+ *
+ * But if at least one write barrier is requested for data
+ * going to or from the device but no address range is
+ * needed for that barrier, then do the barrier, but do it
+ * only once, no matter how many requests there are.
+ */
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ switch (mfd->mdp_fb_page_protection) {
+ default:
+ case MDP_FB_PAGE_PROTECTION_NONCACHED:
+ case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
+ /*
+ * The following barrier is only done at most once,
+ * since further calls would be redundant.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags
+ & MDP_NO_DMA_BARRIER_START)) {
+ msm_dma_nc_pre();
+ break;
+ }
+ }
+ break;
+
+ case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
+ /*
+ * The following barrier is only done at most once,
+ * since further calls would be redundant.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags
+ & MDP_NO_DMA_BARRIER_START)) {
+ msm_dma_wt_pre();
+ break;
+ }
+ }
+ break;
+
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags &
+ MDP_NO_DMA_BARRIER_START)) {
+
+ msm_fb_dma_barrier_for_rect(info,
+ &(req_list[i].src),
+ &(req_list[i].src_rect),
+ msm_dma_todevice_wb_pre
+ );
+
+ msm_fb_dma_barrier_for_rect(info,
+ &(req_list[i].dst),
+ &(req_list[i].dst_rect),
+ msm_dma_todevice_wb_pre
+ );
+ }
+ }
+ break;
+ }
+#else
+ dmb();
+#endif
+}
+
+
+/*
+ * Do the write barriers required to guarantee data will be re-read from RAM by
+ * the CPU after a DMA operation ends.
+ * NOTE: As currently implemented, the data between
+ * the end of one row and the start of the next is
+ * included in the address range rather than
+ * doing multiple calls for each row.
+*/
+static void msm_fb_ensure_memory_coherency_after_dma(struct fb_info *info,
+ struct mdp_blit_req *req_list,
+ int req_list_count)
+{
+#ifdef CONFIG_ARCH_QSD8X50
+ int i;
+
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ switch (mfd->mdp_fb_page_protection) {
+ default:
+ case MDP_FB_PAGE_PROTECTION_NONCACHED:
+ case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
+ /*
+ * The following barrier is only done at most once,
+ * since further calls would be redundant.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags
+ & MDP_NO_DMA_BARRIER_END)) {
+ msm_dma_nc_post();
+ break;
+ }
+ }
+ break;
+
+ case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags &
+ MDP_NO_DMA_BARRIER_END)) {
+
+ msm_fb_dma_barrier_for_rect(info,
+ &(req_list[i].dst),
+ &(req_list[i].dst_rect),
+ msm_dma_fromdevice_wt_post
+ );
+ }
+ }
+ break;
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags &
+ MDP_NO_DMA_BARRIER_END)) {
+
+ msm_fb_dma_barrier_for_rect(info,
+ &(req_list[i].dst),
+ &(req_list[i].dst_rect),
+ msm_dma_fromdevice_wb_post
+ );
+ }
+ }
+ break;
+ }
+#else
+ dmb();
+#endif
+}
+
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+void msm_fb_ensure_mem_coherency_after_dma(struct fb_info *info,
+ struct mdp_blit_req *req_list, int req_list_count)
+{
+ BUG_ON(!info);
+
+ /*
+ * Ensure that CPU cache and other internal CPU state is
+ * updated to reflect any change in memory modified by MDP blit
+ * DMA.
+ */
+ msm_fb_ensure_memory_coherency_after_dma(info,
+ req_list, req_list_count);
+}
+
+static int msmfb_async_blit(struct fb_info *info, void __user *p)
+{
+ /*
+ * CAUTION: The names of the struct types intentionally *DON'T* match
+ * the names of the variables declared -- they appear to be swapped.
+ * Read the code carefully and you should see that the variable names
+ * make sense.
+ */
+ const int MAX_LIST_WINDOW = 16;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp_blit_req_list req_list_header;
+
+ int count, i, req_list_count;
+
+ /* Get the count size for the total BLIT request. */
+ if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
+ return -EFAULT;
+ p += sizeof(req_list_header);
+ count = req_list_header.count;
+ while (count > 0) {
+ /*
+ * Access the requests through a narrow window to decrease copy
+ * overhead and make larger requests accessible to the
+ * coherency management code.
+ * NOTE: The window size is intended to be larger than the
+ * typical request size, but not require more than 2
+ * kbytes of stack storage.
+ */
+ req_list_count = count;
+ if (req_list_count > MAX_LIST_WINDOW)
+ req_list_count = MAX_LIST_WINDOW;
+ if (copy_from_user(&req_list, p,
+ sizeof(struct mdp_blit_req)*req_list_count))
+ return -EFAULT;
+
+ /*
+ * Ensure that any data CPU may have previously written to
+ * internal state (but not yet committed to memory) is
+ * guaranteed to be committed to memory now.
+ */
+ msm_fb_ensure_memory_coherency_before_dma(info,
+ req_list, req_list_count);
+
+ /*
+ * Do the blit DMA, if required -- returning early only if
+ * there is a failure.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags & MDP_NO_BLIT)) {
+ int ret = 0;
+ struct mdp_ppp_djob *job = NULL;
+
+ if (unlikely(req_list[i].src_rect.h == 0 ||
+ req_list[i].src_rect.w == 0)) {
+ MSM_FB_ERR("mpd_ppp: "
+ "src img of zero size!\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(req_list[i].dst_rect.h == 0 ||
+ req_list[i].dst_rect.w == 0))
+ continue;
+
+ /* create a new display job */
+ job = mdp_ppp_new_djob();
+ if (unlikely(!job))
+ return -ENOMEM;
+
+ job->info = info;
+ memcpy(&job->req, &req_list[i],
+ sizeof(struct mdp_blit_req));
+
+ /* Do the actual blit. */
+ ret = mdp_ppp_blit(info, &job->req,
+ &job->p_src_file, &job->p_dst_file);
+
+ /*
+ * Note that early returns don't guarantee
+ * memory coherency.
+ */
+ if (ret || mdp_ppp_get_ret_code()) {
+ mdp_ppp_clear_curr_djob();
+ return ret;
+ }
+ }
+ }
+
+ /* Go to next window of requests. */
+ count -= req_list_count;
+ p += sizeof(struct mdp_blit_req)*req_list_count;
+ }
+ return 0;
+}
+#else
+
+/*
+ * NOTE: The userspace issues blit operations in a sequence, the sequence
+ * start with a operation marked START and ends in an operation marked
+ * END. It is guranteed by the userspace that all the blit operations
+ * between START and END are only within the regions of areas designated
+ * by the START and END operations and that the userspace doesnt modify
+ * those areas. Hence it would be enough to perform barrier/cache operations
+ * only on the START and END operations.
+ */
+static int msmfb_blit(struct fb_info *info, void __user *p)
+{
+ /*
+ * CAUTION: The names of the struct types intentionally *DON'T* match
+ * the names of the variables declared -- they appear to be swapped.
+ * Read the code carefully and you should see that the variable names
+ * make sense.
+ */
+ const int MAX_LIST_WINDOW = 16;
+ struct mdp_blit_req req_list[MAX_LIST_WINDOW];
+ struct mdp_blit_req_list req_list_header;
+
+ int count, i, req_list_count;
+
+ /* Get the count size for the total BLIT request. */
+ if (copy_from_user(&req_list_header, p, sizeof(req_list_header)))
+ return -EFAULT;
+ p += sizeof(req_list_header);
+ count = req_list_header.count;
+ while (count > 0) {
+ /*
+ * Access the requests through a narrow window to decrease copy
+ * overhead and make larger requests accessible to the
+ * coherency management code.
+ * NOTE: The window size is intended to be larger than the
+ * typical request size, but not require more than 2
+ * kbytes of stack storage.
+ */
+ req_list_count = count;
+ if (req_list_count > MAX_LIST_WINDOW)
+ req_list_count = MAX_LIST_WINDOW;
+ if (copy_from_user(&req_list, p,
+ sizeof(struct mdp_blit_req)*req_list_count))
+ return -EFAULT;
+
+ /*
+ * Ensure that any data CPU may have previously written to
+ * internal state (but not yet committed to memory) is
+ * guaranteed to be committed to memory now.
+ */
+ msm_fb_ensure_memory_coherency_before_dma(info,
+ req_list, req_list_count);
+
+ /*
+ * Do the blit DMA, if required -- returning early only if
+ * there is a failure.
+ */
+ for (i = 0; i < req_list_count; i++) {
+ if (!(req_list[i].flags & MDP_NO_BLIT)) {
+ /* Do the actual blit. */
+ int ret = mdp_blit(info, &(req_list[i]));
+
+ /*
+ * Note that early returns don't guarantee
+ * memory coherency.
+ */
+ if (ret)
+ return ret;
+ }
+ }
+
+ /*
+ * Ensure that CPU cache and other internal CPU state is
+ * updated to reflect any change in memory modified by MDP blit
+ * DMA.
+ */
+ msm_fb_ensure_memory_coherency_after_dma(info,
+ req_list,
+ req_list_count);
+
+ /* Go to next window of requests. */
+ count -= req_list_count;
+ p += sizeof(struct mdp_blit_req)*req_list_count;
+ }
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_MSM_OVERLAY
+static int msmfb_overlay_get(struct fb_info *info, void __user *p)
+{
+ struct mdp_overlay req;
+ int ret;
+
+ if (copy_from_user(&req, p, sizeof(req)))
+ return -EFAULT;
+
+ ret = mdp4_overlay_get(info, &req);
+ if (ret) {
+ printk(KERN_ERR "%s: ioctl failed \n",
+ __func__);
+ return ret;
+ }
+ if (copy_to_user(p, &req, sizeof(req))) {
+ printk(KERN_ERR "%s: copy2user failed \n",
+ __func__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int msmfb_overlay_set(struct fb_info *info, void __user *p)
+{
+ struct mdp_overlay req;
+ int ret;
+
+ if (copy_from_user(&req, p, sizeof(req)))
+ return -EFAULT;
+
+ ret = mdp4_overlay_set(info, &req);
+ if (ret) {
+ printk(KERN_ERR "%s:ioctl failed \n",
+ __func__);
+ return ret;
+ }
+
+ if (copy_to_user(p, &req, sizeof(req))) {
+ printk(KERN_ERR "%s: copy2user failed \n",
+ __func__);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int msmfb_overlay_unset(struct fb_info *info, unsigned long *argp)
+{
+ int ret, ndx;
+
+ ret = copy_from_user(&ndx, argp, sizeof(ndx));
+ if (ret) {
+ printk(KERN_ERR "%s:msmfb_overlay_unset ioctl failed \n",
+ __func__);
+ return ret;
+ }
+
+ return mdp4_overlay_unset(info, ndx);
+}
+
+static int msmfb_overlay_play(struct fb_info *info, unsigned long *argp)
+{
+ int ret;
+ struct msmfb_overlay_data req;
+ struct file *p_src_file = 0;
+
+ ret = copy_from_user(&req, argp, sizeof(req));
+ if (ret) {
+ printk(KERN_ERR "%s:msmfb_overlay_play ioctl failed \n",
+ __func__);
+ return ret;
+ }
+
+ ret = mdp4_overlay_play(info, &req, &p_src_file);
+
+ if (p_src_file)
+ put_pmem_file(p_src_file);
+
+ return ret;
+}
+
+#endif
+
+DECLARE_MUTEX(msm_fb_ioctl_ppp_sem);
+DEFINE_MUTEX(msm_fb_ioctl_lut_sem);
+DEFINE_MUTEX(msm_fb_ioctl_hist_sem);
+
+/* Set color conversion matrix from user space */
+
+#ifndef CONFIG_FB_MSM_MDP40
+static void msmfb_set_color_conv(struct mdp_ccs *p)
+{
+ int i;
+
+ if (p->direction == MDP_CCS_RGB2YUV) {
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ /* RGB->YUV primary forward matrix */
+ for (i = 0; i < MDP_CCS_SIZE; i++)
+ writel(p->ccs[i], MDP_CSC_PFMVn(i));
+
+ #ifdef CONFIG_FB_MSM_MDP31
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ writel(p->bv[i], MDP_CSC_POST_BV2n(i));
+ #endif
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ } else {
+ /* MDP cmd block enable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+
+ /* YUV->RGB primary reverse matrix */
+ for (i = 0; i < MDP_CCS_SIZE; i++)
+ writel(p->ccs[i], MDP_CSC_PRMVn(i));
+ for (i = 0; i < MDP_BV_SIZE; i++)
+ writel(p->bv[i], MDP_CSC_PRE_BV1n(i));
+
+ /* MDP cmd block disable */
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF, FALSE);
+ }
+}
+#endif
+
+
+static int msm_fb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+{
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
+ void __user *argp = (void __user *)arg;
+ struct fb_cursor cursor;
+ struct fb_cmap cmap;
+ struct mdp_histogram hist;
+#ifndef CONFIG_FB_MSM_MDP40
+ struct mdp_ccs ccs_matrix;
+#endif
+ struct mdp_page_protection fb_page_protection;
+ int ret = 0;
+
+ if (!mfd->op_enable)
+ return -EPERM;
+
+ switch (cmd) {
+#ifdef CONFIG_FB_MSM_OVERLAY
+ case MSMFB_OVERLAY_GET:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_overlay_get(info, argp);
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+ case MSMFB_OVERLAY_SET:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_overlay_set(info, argp);
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+ case MSMFB_OVERLAY_UNSET:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_overlay_unset(info, argp);
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+ case MSMFB_OVERLAY_PLAY:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_overlay_play(info, argp);
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+#endif
+ case MSMFB_BLIT:
+ down(&msm_fb_ioctl_ppp_sem);
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+ ret = msmfb_async_blit(info, argp);
+ mdp_ppp_wait(); /* Wait for all blits to be finished. */
+#else
+ ret = msmfb_blit(info, argp);
+#endif
+ up(&msm_fb_ioctl_ppp_sem);
+
+ break;
+
+ /* Ioctl for setting ccs matrix from user space */
+ case MSMFB_SET_CCS_MATRIX:
+#ifndef CONFIG_FB_MSM_MDP40
+ ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix));
+ if (ret) {
+ printk(KERN_ERR
+ "%s:MSMFB_SET_CCS_MATRIX ioctl failed \n",
+ __func__);
+ return ret;
+ }
+
+ down(&msm_fb_ioctl_ppp_sem);
+ if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
+ mdp_ccs_rgb2yuv = ccs_matrix;
+ else
+ mdp_ccs_yuv2rgb = ccs_matrix;
+
+ msmfb_set_color_conv(&ccs_matrix) ;
+ up(&msm_fb_ioctl_ppp_sem);
+#else
+ ret = -EINVAL;
+#endif
+
+ break;
+
+ /* Ioctl for getting ccs matrix to user space */
+ case MSMFB_GET_CCS_MATRIX:
+#ifndef CONFIG_FB_MSM_MDP40
+ ret = copy_from_user(&ccs_matrix, argp, sizeof(ccs_matrix)) ;
+ if (ret) {
+ printk(KERN_ERR
+ "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
+ __func__);
+ return ret;
+ }
+
+ down(&msm_fb_ioctl_ppp_sem);
+ if (ccs_matrix.direction == MDP_CCS_RGB2YUV)
+ ccs_matrix = mdp_ccs_rgb2yuv;
+ else
+ ccs_matrix = mdp_ccs_yuv2rgb;
+
+ ret = copy_to_user(argp, &ccs_matrix, sizeof(ccs_matrix));
+
+ if (ret) {
+ printk(KERN_ERR
+ "%s:MSMFB_GET_CCS_MATRIX ioctl failed \n",
+ __func__);
+ return ret ;
+ }
+ up(&msm_fb_ioctl_ppp_sem);
+#else
+ ret = -EINVAL;
+#endif
+
+ break;
+
+#ifdef CONFIG_MDP_PPP_ASYNC_OP
+ case MSMFB_ASYNC_BLIT:
+ down(&msm_fb_ioctl_ppp_sem);
+ ret = msmfb_async_blit(info, argp);
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+
+ case MSMFB_BLIT_FLUSH:
+ down(&msm_fb_ioctl_ppp_sem);
+ mdp_ppp_wait();
+ up(&msm_fb_ioctl_ppp_sem);
+ break;
+#endif
+
+ case MSMFB_GRP_DISP:
+#ifdef CONFIG_FB_MSM_MDP22
+ {
+ unsigned long grp_id;
+
+ ret = copy_from_user(&grp_id, argp, sizeof(grp_id));
+ if (ret)
+ return ret;
+
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_ON, FALSE);
+ writel(grp_id, MDP_FULL_BYPASS_WORD43);
+ mdp_pipe_ctrl(MDP_CMD_BLOCK, MDP_BLOCK_POWER_OFF,
+ FALSE);
+ break;
+ }
+#else
+ return -EFAULT;
+#endif
+ case MSMFB_SUSPEND_SW_REFRESHER:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ mfd->sw_refreshing_enable = FALSE;
+ ret = msm_fb_stop_sw_refresher(mfd);
+ break;
+
+ case MSMFB_RESUME_SW_REFRESHER:
+ if (!mfd->panel_power_on)
+ return -EPERM;
+
+ mfd->sw_refreshing_enable = TRUE;
+ ret = msm_fb_resume_sw_refresher(mfd);
+ break;
+
+ case MSMFB_CURSOR:
+ ret = copy_from_user(&cursor, argp, sizeof(cursor));
+ if (ret)
+ return ret;
+
+ ret = msm_fb_cursor(info, &cursor);
+ break;
+
+ case MSMFB_SET_LUT:
+ ret = copy_from_user(&cmap, argp, sizeof(cmap));
+ if (ret)
+ return ret;
+
+ mutex_lock(&msm_fb_ioctl_lut_sem);
+ ret = msm_fb_set_lut(&cmap, info);
+ mutex_unlock(&msm_fb_ioctl_lut_sem);
+ break;
+
+ case MSMFB_HISTOGRAM:
+ if (!mfd->do_histogram)
+ return -ENODEV;
+
+ ret = copy_from_user(&hist, argp, sizeof(hist));
+ if (ret)
+ return ret;
+
+ mutex_lock(&msm_fb_ioctl_hist_sem);
+ ret = mfd->do_histogram(info, &hist);
+ mutex_unlock(&msm_fb_ioctl_hist_sem);
+ break;
+
+ case MSMFB_GET_PAGE_PROTECTION:
+ fb_page_protection.page_protection
+ = mfd->mdp_fb_page_protection;
+ ret = copy_to_user(argp, &fb_page_protection,
+ sizeof(fb_page_protection));
+ if (ret)
+ return ret;
+ break;
+
+ case MSMFB_SET_PAGE_PROTECTION:
+#ifdef CONFIG_ARCH_QSD8X50
+ ret = copy_from_user(&fb_page_protection, argp,
+ sizeof(fb_page_protection));
+ if (ret)
+ return ret;
+
+ /* Validate the proposed page protection settings. */
+ switch (fb_page_protection.page_protection) {
+ case MDP_FB_PAGE_PROTECTION_NONCACHED:
+ case MDP_FB_PAGE_PROTECTION_WRITECOMBINE:
+ case MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE:
+ /* Write-back cache (read allocate) */
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE:
+ /* Write-back cache (write allocate) */
+ case MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE:
+ mfd->mdp_fb_page_protection =
+ fb_page_protection.page_protection;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+#else
+ /*
+ * Don't allow caching until 7k DMA cache operations are
+ * available.
+ */
+ ret = -EINVAL;
+#endif
+ break;
+
+ default:
+ MSM_FB_INFO("MDP: unknown ioctl (cmd=%d) received!\n", cmd);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int msm_fb_register_driver(void)
+{
+ return platform_driver_register(&msm_fb_driver);
+}
+
+void msm_fb_add_device(struct platform_device *pdev)
+{
+ struct msm_fb_panel_data *pdata;
+ struct platform_device *this_dev = NULL;
+ struct fb_info *fbi;
+ struct msm_fb_data_type *mfd = NULL;
+ u32 type, id, fb_num;
+
+ if (!pdev)
+ return;
+ id = pdev->id;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return;
+ type = pdata->panel_info.type;
+ fb_num = pdata->panel_info.fb_num;
+
+ if (fb_num <= 0)
+ return;
+
+ if (fbi_list_index >= MAX_FBI_LIST) {
+ printk(KERN_ERR "msm_fb: no more framebuffer info list!\n");
+ return;
+ }
+ /*
+ * alloc panel device data
+ */
+ this_dev = msm_fb_device_alloc(pdata, type, id);
+
+ if (!this_dev) {
+ printk(KERN_ERR
+ "%s: msm_fb_device_alloc failed!\n", __func__);
+ return;
+ }
+
+ /*
+ * alloc framebuffer info + par data
+ */
+ fbi = framebuffer_alloc(sizeof(struct msm_fb_data_type), NULL);
+ if (fbi == NULL) {
+ platform_device_put(this_dev);
+ printk(KERN_ERR "msm_fb: can't alloca framebuffer info data!\n");
+ return;
+ }
+
+ mfd = (struct msm_fb_data_type *)fbi->par;
+ mfd->key = MFD_KEY;
+ mfd->fbi = fbi;
+ mfd->panel.type = type;
+ mfd->panel.id = id;
+ mfd->fb_page = fb_num;
+ mfd->index = fbi_list_index;
+ mfd->mdp_fb_page_protection = MDP_FB_PAGE_PROTECTION_WRITECOMBINE;
+
+ /* link to the latest pdev */
+ mfd->pdev = this_dev;
+
+ mfd_list[mfd_list_index++] = mfd;
+ fbi_list[fbi_list_index++] = fbi;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(this_dev, mfd);
+
+ if (platform_device_add(this_dev)) {
+ printk(KERN_ERR "msm_fb: platform_device_add failed!\n");
+ platform_device_put(this_dev);
+ framebuffer_release(fbi);
+ fbi_list_index--;
+ return;
+ }
+}
+EXPORT_SYMBOL(msm_fb_add_device);
+
+int __init msm_fb_init(void)
+{
+ int rc = -ENODEV;
+
+ if (msm_fb_register_driver())
+ return rc;
+
+#ifdef MSM_FB_ENABLE_DBGFS
+ {
+ struct dentry *root;
+
+ if ((root = msm_fb_get_debugfs_root()) != NULL) {
+ msm_fb_debugfs_file_create(root,
+ "msm_fb_msg_printing_level",
+ (u32 *) &msm_fb_msg_level);
+ msm_fb_debugfs_file_create(root,
+ "mddi_msg_printing_level",
+ (u32 *) &mddi_msg_level);
+ msm_fb_debugfs_file_create(root, "msm_fb_debug_enabled",
+ (u32 *) &msm_fb_debug_enabled);
+ }
+ }
+#endif
+
+ return 0;
+}
+
+module_init(msm_fb_init);
diff --git a/drivers/staging/msm/msm_fb.h b/drivers/staging/msm/msm_fb.h
new file mode 100644
index 000000000000..f93913800475
--- /dev/null
+++ b/drivers/staging/msm/msm_fb.h
@@ -0,0 +1,174 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MSM_FB_H
+#define MSM_FB_H
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <mach/board.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <mach/memory.h>
+#include <linux/semaphore.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/hrtimer.h>
+
+#include <linux/fb.h>
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
+#include "msm_fb_panel.h"
+#include "mdp.h"
+
+#define MSM_FB_DEFAULT_PAGE_SIZE 2
+#define MFD_KEY 0x11161126
+#define MSM_FB_MAX_DEV_LIST 32
+
+struct disp_info_type_suspend {
+ boolean op_enable;
+ boolean sw_refreshing_enable;
+ boolean panel_power_on;
+};
+
+struct msm_fb_data_type {
+ __u32 key;
+ __u32 index;
+ __u32 ref_cnt;
+ __u32 fb_page;
+
+ panel_id_type panel;
+ struct msm_panel_info panel_info;
+
+ DISP_TARGET dest;
+ struct fb_info *fbi;
+
+ boolean op_enable;
+ uint32 fb_imgType;
+ boolean sw_currently_refreshing;
+ boolean sw_refreshing_enable;
+ boolean hw_refresh;
+
+ MDPIBUF ibuf;
+ boolean ibuf_flushed;
+ struct timer_list refresh_timer;
+ struct completion refresher_comp;
+
+ boolean pan_waiting;
+ struct completion pan_comp;
+
+ /* vsync */
+ boolean use_mdp_vsync;
+ __u32 vsync_gpio;
+ __u32 total_lcd_lines;
+ __u32 total_porch_lines;
+ __u32 lcd_ref_usec_time;
+ __u32 refresh_timer_duration;
+
+ struct hrtimer dma_hrtimer;
+
+ boolean panel_power_on;
+ struct work_struct dma_update_worker;
+ struct semaphore sem;
+
+ struct timer_list vsync_resync_timer;
+ boolean vsync_handler_pending;
+ struct work_struct vsync_resync_worker;
+
+ ktime_t last_vsync_timetick;
+
+ __u32 *vsync_width_boundary;
+
+ unsigned int pmem_id;
+ struct disp_info_type_suspend suspend;
+
+ __u32 channel_irq;
+
+ struct mdp_dma_data *dma;
+ void (*dma_fnc) (struct msm_fb_data_type *mfd);
+ int (*cursor_update) (struct fb_info *info,
+ struct fb_cursor *cursor);
+ int (*lut_update) (struct fb_info *info,
+ struct fb_cmap *cmap);
+ int (*do_histogram) (struct fb_info *info,
+ struct mdp_histogram *hist);
+ void *cursor_buf;
+ void *cursor_buf_phys;
+
+ void *cmd_port;
+ void *data_port;
+ void *data_port_phys;
+
+ __u32 bl_level;
+
+ struct platform_device *pdev;
+
+ __u32 var_xres;
+ __u32 var_yres;
+ __u32 var_pixclock;
+
+#ifdef MSM_FB_ENABLE_DBGFS
+ struct dentry *sub_dir;
+#endif
+
+#ifdef CONFIG_HAS_EARLYSUSPEND
+ struct early_suspend early_suspend;
+ struct early_suspend mddi_early_suspend;
+ struct early_suspend mddi_ext_early_suspend;
+#endif
+ u32 mdp_fb_page_protection;
+ int allow_set_offset;
+};
+
+struct dentry *msm_fb_get_debugfs_root(void);
+void msm_fb_debugfs_file_create(struct dentry *root, const char *name,
+ u32 *var);
+void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl,
+ u32 save);
+
+void msm_fb_add_device(struct platform_device *pdev);
+
+int msm_fb_detect_client(const char *name);
+
+#ifdef CONFIG_FB_BACKLIGHT
+void msm_fb_config_backlight(struct msm_fb_data_type *mfd);
+#endif
+
+#endif /* MSM_FB_H */
diff --git a/drivers/staging/msm/msm_fb_bl.c b/drivers/staging/msm/msm_fb_bl.c
new file mode 100644
index 000000000000..033fc9486e01
--- /dev/null
+++ b/drivers/staging/msm/msm_fb_bl.c
@@ -0,0 +1,79 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/backlight.h>
+
+#include "msm_fb.h"
+
+static int msm_fb_bl_get_brightness(struct backlight_device *pbd)
+{
+ return pbd->props.brightness;
+}
+
+static int msm_fb_bl_update_status(struct backlight_device *pbd)
+{
+ struct msm_fb_data_type *mfd = bl_get_data(pbd);
+ __u32 bl_lvl;
+
+ bl_lvl = pbd->props.brightness;
+ bl_lvl = mfd->fbi->bl_curve[bl_lvl];
+ msm_fb_set_backlight(mfd, bl_lvl, 1);
+ return 0;
+}
+
+static struct backlight_ops msm_fb_bl_ops = {
+ .get_brightness = msm_fb_bl_get_brightness,
+ .update_status = msm_fb_bl_update_status,
+};
+
+void msm_fb_config_backlight(struct msm_fb_data_type *mfd)
+{
+ struct msm_fb_panel_data *pdata;
+ struct backlight_device *pbd;
+ struct fb_info *fbi;
+ char name[16];
+
+ fbi = mfd->fbi;
+ pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;
+
+ if ((pdata) && (pdata->set_backlight)) {
+ snprintf(name, sizeof(name), "msmfb_bl%d", mfd->index);
+ pbd =
+ backlight_device_register(name, fbi->dev, mfd,
+ &msm_fb_bl_ops);
+ if (!IS_ERR(pbd)) {
+ fbi->bl_dev = pbd;
+ fb_bl_default_curve(fbi,
+ 0,
+ mfd->panel_info.bl_min,
+ mfd->panel_info.bl_max);
+ pbd->props.max_brightness = FB_BACKLIGHT_LEVELS - 1;
+ pbd->props.brightness = FB_BACKLIGHT_LEVELS - 1;
+ backlight_update_status(pbd);
+ } else {
+ fbi->bl_dev = NULL;
+ printk(KERN_ERR "msm_fb: backlight_device_register failed!\n");
+ }
+ }
+}
diff --git a/drivers/staging/msm/msm_fb_def.h b/drivers/staging/msm/msm_fb_def.h
new file mode 100644
index 000000000000..6de440937422
--- /dev/null
+++ b/drivers/staging/msm/msm_fb_def.h
@@ -0,0 +1,201 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MSM_FB_DEF_H
+#define MSM_FB_DEF_H
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include "msm_mdp.h"
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+#include <linux/console.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include "linux/proc_fs.h"
+#include <mach/hardware.h>
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/platform_device.h>
+
+typedef s64 int64;
+typedef s32 int32;
+typedef s16 int16;
+typedef s8 int8;
+
+typedef u64 uint64;
+typedef u32 uint32;
+typedef u16 uint16;
+typedef u8 uint8;
+
+typedef s32 int4;
+typedef s16 int2;
+typedef s8 int1;
+
+typedef u32 uint4;
+typedef u16 uint2;
+typedef u8 uint1;
+
+typedef u32 dword;
+typedef u16 word;
+typedef u8 byte;
+
+typedef unsigned int boolean;
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define MSM_FB_ENABLE_DBGFS
+#define FEATURE_MDDI
+
+#define outp32(addr, val) writel(val, addr)
+#define outp16(addr, val) writew(val, addr)
+#define outp8(addr, val) writeb(val, addr)
+#define outp(addr, val) outp32(addr, val)
+
+#ifndef MAX
+#define MAX( x, y ) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef MIN
+#define MIN( x, y ) (((x) < (y)) ? (x) : (y))
+#endif
+
+/*--------------------------------------------------------------------------*/
+
+#define inp32(addr) readl(addr)
+#define inp16(addr) readw(addr)
+#define inp8(addr) readb(addr)
+#define inp(addr) inp32(addr)
+
+#define inpw(port) readw(port)
+#define outpw(port, val) writew(val, port)
+#define inpdw(port) readl(port)
+#define outpdw(port, val) writel(val, port)
+
+
+#define clk_busy_wait(x) msleep_interruptible((x)/1000)
+
+#define memory_barrier()
+
+#define assert(expr) \
+ if(!(expr)) { \
+ printk(KERN_ERR "msm_fb: assertion failed! %s,%s,%s,line=%d\n",\
+ #expr, __FILE__, __func__, __LINE__); \
+ }
+
+#define ASSERT(x) assert(x)
+
+#define DISP_EBI2_LOCAL_DEFINE
+#ifdef DISP_EBI2_LOCAL_DEFINE
+#define LCD_PRIM_BASE_PHYS 0x98000000
+#define LCD_SECD_BASE_PHYS 0x9c000000
+#define EBI2_PRIM_LCD_RS_PIN 0x20000
+#define EBI2_SECD_LCD_RS_PIN 0x20000
+
+#define EBI2_PRIM_LCD_CLR 0xC0
+#define EBI2_PRIM_LCD_SEL 0x40
+
+#define EBI2_SECD_LCD_CLR 0x300
+#define EBI2_SECD_LCD_SEL 0x100
+#endif
+
+extern u32 msm_fb_msg_level;
+
+/*
+ * Message printing priorities:
+ * LEVEL 0 KERN_EMERG (highest priority)
+ * LEVEL 1 KERN_ALERT
+ * LEVEL 2 KERN_CRIT
+ * LEVEL 3 KERN_ERR
+ * LEVEL 4 KERN_WARNING
+ * LEVEL 5 KERN_NOTICE
+ * LEVEL 6 KERN_INFO
+ * LEVEL 7 KERN_DEBUG (Lowest priority)
+ */
+#define MSM_FB_EMERG(msg, ...) \
+ if (msm_fb_msg_level > 0) \
+ printk(KERN_EMERG msg, ## __VA_ARGS__);
+#define MSM_FB_ALERT(msg, ...) \
+ if (msm_fb_msg_level > 1) \
+ printk(KERN_ALERT msg, ## __VA_ARGS__);
+#define MSM_FB_CRIT(msg, ...) \
+ if (msm_fb_msg_level > 2) \
+ printk(KERN_CRIT msg, ## __VA_ARGS__);
+#define MSM_FB_ERR(msg, ...) \
+ if (msm_fb_msg_level > 3) \
+ printk(KERN_ERR msg, ## __VA_ARGS__);
+#define MSM_FB_WARNING(msg, ...) \
+ if (msm_fb_msg_level > 4) \
+ printk(KERN_WARNING msg, ## __VA_ARGS__);
+#define MSM_FB_NOTICE(msg, ...) \
+ if (msm_fb_msg_level > 5) \
+ printk(KERN_NOTICE msg, ## __VA_ARGS__);
+#define MSM_FB_INFO(msg, ...) \
+ if (msm_fb_msg_level > 6) \
+ printk(KERN_INFO msg, ## __VA_ARGS__);
+#define MSM_FB_DEBUG(msg, ...) \
+ if (msm_fb_msg_level > 7) \
+ printk(KERN_DEBUG msg, ## __VA_ARGS__);
+
+#ifdef MSM_FB_C
+unsigned char *msm_mdp_base;
+unsigned char *msm_pmdh_base;
+unsigned char *msm_emdh_base;
+#else
+extern unsigned char *msm_mdp_base;
+extern unsigned char *msm_pmdh_base;
+extern unsigned char *msm_emdh_base;
+#endif
+
+#endif /* MSM_FB_DEF_H */
diff --git a/drivers/staging/msm/msm_fb_panel.c b/drivers/staging/msm/msm_fb_panel.c
new file mode 100644
index 000000000000..b17a239a1bc7
--- /dev/null
+++ b/drivers/staging/msm/msm_fb_panel.c
@@ -0,0 +1,136 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/version.h>
+#include <linux/proc_fs.h>
+#include <linux/vmalloc.h>
+#include <linux/debugfs.h>
+
+#include "msm_fb_panel.h"
+
+int panel_next_on(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_panel_data *pdata;
+ struct msm_fb_panel_data *next_pdata;
+ struct platform_device *next_pdev;
+
+ pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
+
+ if (pdata) {
+ next_pdev = pdata->next;
+ if (next_pdev) {
+ next_pdata =
+ (struct msm_fb_panel_data *)next_pdev->dev.
+ platform_data;
+ if ((next_pdata) && (next_pdata->on))
+ ret = next_pdata->on(next_pdev);
+ }
+ }
+
+ return ret;
+}
+
+int panel_next_off(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct msm_fb_panel_data *pdata;
+ struct msm_fb_panel_data *next_pdata;
+ struct platform_device *next_pdev;
+
+ pdata = (struct msm_fb_panel_data *)pdev->dev.platform_data;
+
+ if (pdata) {
+ next_pdev = pdata->next;
+ if (next_pdev) {
+ next_pdata =
+ (struct msm_fb_panel_data *)next_pdev->dev.
+ platform_data;
+ if ((next_pdata) && (next_pdata->on))
+ ret = next_pdata->off(next_pdev);
+ }
+ }
+
+ return ret;
+}
+
+struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
+ u32 type, u32 id)
+{
+ struct platform_device *this_dev = NULL;
+ char dev_name[16];
+
+ switch (type) {
+ case EBI2_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "ebi2_lcd");
+ break;
+
+ case MDDI_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "mddi");
+ break;
+
+ case EXT_MDDI_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "mddi_ext");
+ break;
+
+ case TV_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "tvenc");
+ break;
+
+ case HDMI_PANEL:
+ case LCDC_PANEL:
+ snprintf(dev_name, sizeof(dev_name), "lcdc");
+ break;
+
+ default:
+ return NULL;
+ }
+
+ if (pdata != NULL)
+ pdata->next = NULL;
+ else
+ return NULL;
+
+ this_dev =
+ platform_device_alloc(dev_name, ((u32) type << 16) | (u32) id);
+
+ if (this_dev) {
+ if (platform_device_add_data
+ (this_dev, pdata, sizeof(struct msm_fb_panel_data))) {
+ printk
+ ("msm_fb_device_alloc: platform_device_add_data failed!\n");
+ platform_device_put(this_dev);
+ return NULL;
+ }
+ }
+
+ return this_dev;
+}
diff --git a/drivers/staging/msm/msm_fb_panel.h b/drivers/staging/msm/msm_fb_panel.h
new file mode 100644
index 000000000000..ab458310c3a2
--- /dev/null
+++ b/drivers/staging/msm/msm_fb_panel.h
@@ -0,0 +1,145 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef MSM_FB_PANEL_H
+#define MSM_FB_PANEL_H
+
+#include "msm_fb_def.h"
+
+struct msm_fb_data_type;
+
+typedef void (*msm_fb_vsync_handler_type) (void *arg);
+
+/* panel id type */
+typedef struct panel_id_s {
+ uint16 id;
+ uint16 type;
+} panel_id_type;
+
+/* panel type list */
+#define NO_PANEL 0xffff /* No Panel */
+#define MDDI_PANEL 1 /* MDDI */
+#define EBI2_PANEL 2 /* EBI2 */
+#define LCDC_PANEL 3 /* internal LCDC type */
+#define EXT_MDDI_PANEL 4 /* Ext.MDDI */
+#define TV_PANEL 5 /* TV */
+#define HDMI_PANEL 6 /* HDMI TV */
+
+/* panel class */
+typedef enum {
+ DISPLAY_LCD = 0, /* lcd = ebi2/mddi */
+ DISPLAY_LCDC, /* lcdc */
+ DISPLAY_TV, /* TV Out */
+ DISPLAY_EXT_MDDI, /* External MDDI */
+} DISP_TARGET;
+
+/* panel device locaiton */
+typedef enum {
+ DISPLAY_1 = 0, /* attached as first device */
+ DISPLAY_2, /* attached on second device */
+ MAX_PHYS_TARGET_NUM,
+} DISP_TARGET_PHYS;
+
+/* panel info type */
+struct lcd_panel_info {
+ __u32 vsync_enable;
+ __u32 refx100;
+ __u32 v_back_porch;
+ __u32 v_front_porch;
+ __u32 v_pulse_width;
+ __u32 hw_vsync_mode;
+ __u32 vsync_notifier_period;
+};
+
+struct lcdc_panel_info {
+ __u32 h_back_porch;
+ __u32 h_front_porch;
+ __u32 h_pulse_width;
+ __u32 v_back_porch;
+ __u32 v_front_porch;
+ __u32 v_pulse_width;
+ __u32 border_clr;
+ __u32 underflow_clr;
+ __u32 hsync_skew;
+};
+
+struct mddi_panel_info {
+ __u32 vdopkt;
+};
+
+struct msm_panel_info {
+ __u32 xres;
+ __u32 yres;
+ __u32 bpp;
+ __u32 type;
+ __u32 wait_cycle;
+ DISP_TARGET_PHYS pdest;
+ __u32 bl_max;
+ __u32 bl_min;
+ __u32 fb_num;
+ __u32 clk_rate;
+ __u32 clk_min;
+ __u32 clk_max;
+ __u32 frame_count;
+
+ union {
+ struct mddi_panel_info mddi;
+ };
+
+ union {
+ struct lcd_panel_info lcd;
+ struct lcdc_panel_info lcdc;
+ };
+};
+
+struct msm_fb_panel_data {
+ struct msm_panel_info panel_info;
+ void (*set_rect) (int x, int y, int xres, int yres);
+ void (*set_vsync_notifier) (msm_fb_vsync_handler_type, void *arg);
+ void (*set_backlight) (struct msm_fb_data_type *);
+
+ /* function entry chain */
+ int (*on) (struct platform_device *pdev);
+ int (*off) (struct platform_device *pdev);
+ struct platform_device *next;
+};
+
+/*===========================================================================
+ FUNCTIONS PROTOTYPES
+============================================================================*/
+struct platform_device *msm_fb_device_alloc(struct msm_fb_panel_data *pdata,
+ u32 type, u32 id);
+int panel_next_on(struct platform_device *pdev);
+int panel_next_off(struct platform_device *pdev);
+
+int lcdc_device_register(struct msm_panel_info *pinfo);
+
+int mddi_toshiba_device_register(struct msm_panel_info *pinfo,
+ u32 channel, u32 panel);
+
+#endif /* MSM_FB_PANEL_H */
diff --git a/drivers/staging/msm/msm_mdp.h b/drivers/staging/msm/msm_mdp.h
new file mode 100644
index 000000000000..2d5323f5b62d
--- /dev/null
+++ b/drivers/staging/msm/msm_mdp.h
@@ -0,0 +1,245 @@
+/* include/linux/msm_mdp.h
+ *
+ * Copyright (C) 2007 Google Incorporated
+ * Copyright (c) 2009-2010, Code Aurora Forum. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _MSM_MDP_H_
+#define _MSM_MDP_H_
+
+#include <linux/types.h>
+#include <linux/fb.h>
+
+#define MSMFB_IOCTL_MAGIC 'm'
+#define MSMFB_GRP_DISP _IOW(MSMFB_IOCTL_MAGIC, 1, unsigned int)
+#define MSMFB_BLIT _IOW(MSMFB_IOCTL_MAGIC, 2, unsigned int)
+#define MSMFB_SUSPEND_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 128, unsigned int)
+#define MSMFB_RESUME_SW_REFRESHER _IOW(MSMFB_IOCTL_MAGIC, 129, unsigned int)
+#define MSMFB_CURSOR _IOW(MSMFB_IOCTL_MAGIC, 130, struct fb_cursor)
+#define MSMFB_SET_LUT _IOW(MSMFB_IOCTL_MAGIC, 131, struct fb_cmap)
+#define MSMFB_HISTOGRAM _IOWR(MSMFB_IOCTL_MAGIC, 132, struct mdp_histogram)
+/* new ioctls's for set/get ccs matrix */
+#define MSMFB_GET_CCS_MATRIX _IOWR(MSMFB_IOCTL_MAGIC, 133, struct mdp_ccs)
+#define MSMFB_SET_CCS_MATRIX _IOW(MSMFB_IOCTL_MAGIC, 134, struct mdp_ccs)
+#define MSMFB_OVERLAY_SET _IOWR(MSMFB_IOCTL_MAGIC, 135, \
+ struct mdp_overlay)
+#define MSMFB_OVERLAY_UNSET _IOW(MSMFB_IOCTL_MAGIC, 136, unsigned int)
+#define MSMFB_OVERLAY_PLAY _IOW(MSMFB_IOCTL_MAGIC, 137, \
+ struct msmfb_overlay_data)
+#define MSMFB_GET_PAGE_PROTECTION _IOR(MSMFB_IOCTL_MAGIC, 138, \
+ struct mdp_page_protection)
+#define MSMFB_SET_PAGE_PROTECTION _IOW(MSMFB_IOCTL_MAGIC, 139, \
+ struct mdp_page_protection)
+#define MSMFB_OVERLAY_GET _IOR(MSMFB_IOCTL_MAGIC, 140, \
+ struct mdp_overlay)
+
+/* new ioctls for async MDP ops */
+#define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 141, unsigned int)
+#define MSMFB_BLIT_FLUSH _IOR(MSMFB_IOCTL_MAGIC, 142, unsigned int)
+
+#define MDP_IMGTYPE2_START 0x10000
+
+enum {
+ MDP_RGB_565, /* RGB 565 planer */
+ MDP_XRGB_8888, /* RGB 888 padded */
+ MDP_Y_CBCR_H2V2, /* Y and CbCr, pseudo planer w/ Cb is in MSB */
+ MDP_ARGB_8888, /* ARGB 888 */
+ MDP_RGB_888, /* RGB 888 planer */
+ MDP_Y_CRCB_H2V2, /* Y and CrCb, pseudo planer w/ Cr is in MSB */
+ MDP_YCRYCB_H2V1, /* YCrYCb interleave */
+ MDP_Y_CRCB_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
+ MDP_Y_CBCR_H2V1, /* Y and CrCb, pseduo planer w/ Cr is in MSB */
+ MDP_RGBA_8888, /* ARGB 888 */
+ MDP_BGRA_8888, /* ABGR 888 */
+ MDP_Y_CRCB_H2V2_TILE, /* Y and CrCb, pseudo planer tile */
+ MDP_Y_CBCR_H2V2_TILE, /* Y and CbCr, pseudo planer tile */
+ MDP_IMGTYPE_LIMIT,
+ MDP_BGR_565 = MDP_IMGTYPE2_START, /* BGR 565 planer */
+ MDP_FB_FORMAT, /* framebuffer format */
+ MDP_IMGTYPE_LIMIT2 /* Non valid image type after this enum */
+};
+
+enum {
+ PMEM_IMG,
+ FB_IMG,
+};
+
+/* mdp_blit_req flag values */
+#define MDP_ROT_NOP 0
+#define MDP_FLIP_LR 0x1
+#define MDP_FLIP_UD 0x2
+#define MDP_ROT_90 0x4
+#define MDP_ROT_180 (MDP_FLIP_UD|MDP_FLIP_LR)
+#define MDP_ROT_270 (MDP_ROT_90|MDP_FLIP_UD|MDP_FLIP_LR)
+#define MDP_DITHER 0x8
+#define MDP_BLUR 0x10
+#define MDP_BLEND_FG_PREMULT 0x20000
+
+#define MDP_DEINTERLACE 0x80000000
+#define MDP_SHARPENING 0x40000000
+
+#define MDP_NO_DMA_BARRIER_START 0x20000000
+#define MDP_NO_DMA_BARRIER_END 0x10000000
+#define MDP_NO_BLIT 0x08000000
+#define MDP_BLIT_WITH_DMA_BARRIERS 0x000
+#define MDP_BLIT_WITH_NO_DMA_BARRIERS \
+ (MDP_NO_DMA_BARRIER_START | MDP_NO_DMA_BARRIER_END)
+#define MDP_TRANSP_NOP 0xffffffff
+#define MDP_ALPHA_NOP 0xff
+
+#define MDP_BLIT_SRC_GEM 0x02000000 /* set for GEM, clear for PMEM */
+#define MDP_BLIT_DST_GEM 0x01000000 /* set for GEM, clear for PMEM */
+
+#define MDP_FB_PAGE_PROTECTION_NONCACHED (0)
+#define MDP_FB_PAGE_PROTECTION_WRITECOMBINE (1)
+#define MDP_FB_PAGE_PROTECTION_WRITETHROUGHCACHE (2)
+#define MDP_FB_PAGE_PROTECTION_WRITEBACKCACHE (3)
+#define MDP_FB_PAGE_PROTECTION_WRITEBACKWACACHE (4)
+/* Sentinel: Don't use! */
+#define MDP_FB_PAGE_PROTECTION_INVALID (5)
+/* Count of the number of MDP_FB_PAGE_PROTECTION_... values. */
+#define MDP_NUM_FB_PAGE_PROTECTION_VALUES (5)
+
+struct mdp_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct mdp_img {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+ uint32_t offset;
+ int memory_id; /* the file descriptor */
+ uint32_t priv;
+};
+
+/*
+ * {3x3} + {3} ccs matrix
+ */
+
+#define MDP_CCS_RGB2YUV 0
+#define MDP_CCS_YUV2RGB 1
+
+#define MDP_CCS_SIZE 9
+#define MDP_BV_SIZE 3
+
+struct mdp_ccs {
+ int direction; /* MDP_CCS_RGB2YUV or YUV2RGB */
+ uint16_t ccs[MDP_CCS_SIZE]; /* 3x3 color coefficients */
+ uint16_t bv[MDP_BV_SIZE]; /* 1x3 bias vector */
+};
+
+/* The version of the mdp_blit_req structure so that
+ * user applications can selectively decide which functionality
+ * to include
+ */
+
+#define MDP_BLIT_REQ_VERSION 2
+
+struct mdp_blit_req {
+ struct mdp_img src;
+ struct mdp_img dst;
+ struct mdp_rect src_rect;
+ struct mdp_rect dst_rect;
+ uint32_t alpha;
+ uint32_t transp_mask;
+ uint32_t flags;
+ int sharpening_strength; /* -127 <--> 127, default 64 */
+};
+
+struct mdp_blit_req_list {
+ uint32_t count;
+ struct mdp_blit_req req[];
+};
+
+struct msmfb_data {
+ uint32_t offset;
+ int memory_id;
+ int id;
+};
+
+#define MSMFB_NEW_REQUEST -1
+
+struct msmfb_overlay_data {
+ uint32_t id;
+ struct msmfb_data data;
+};
+
+struct msmfb_img {
+ uint32_t width;
+ uint32_t height;
+ uint32_t format;
+};
+
+struct mdp_overlay {
+ struct msmfb_img src;
+ struct mdp_rect src_rect;
+ struct mdp_rect dst_rect;
+ uint32_t z_order; /* stage number */
+ uint32_t is_fg; /* control alpha & transp */
+ uint32_t alpha;
+ uint32_t transp_mask;
+ uint32_t flags;
+ uint32_t id;
+ uint32_t user_data[8];
+};
+
+struct mdp_histogram {
+ uint32_t frame_cnt;
+ uint32_t bin_cnt;
+ uint32_t *r;
+ uint32_t *g;
+ uint32_t *b;
+};
+
+struct mdp_page_protection {
+ uint32_t page_protection;
+};
+
+
+struct msm_panel_common_pdata {
+ int gpio;
+ int (*backlight_level)(int level, int max, int min);
+ int (*pmic_backlight)(int level);
+ int (*panel_num)(void);
+ void (*panel_config_gpio)(int);
+ int *gpio_num;
+};
+
+struct lcdc_platform_data {
+ int (*lcdc_gpio_config)(int on);
+ void (*lcdc_power_save)(int);
+};
+
+struct tvenc_platform_data {
+ int (*pm_vid_en)(int on);
+};
+
+struct mddi_platform_data {
+ void (*mddi_power_save)(int on);
+ int (*mddi_sel_clk)(u32 *clk_rate);
+};
+
+struct msm_fb_platform_data {
+ int (*detect_client)(const char *name);
+ int mddi_prescan;
+ int (*allow_set_offset)(void);
+};
+
+struct msm_hdmi_platform_data {
+ int irq;
+ int (*cable_detect)(int insert);
+};
+
+#endif /*_MSM_MDP_H_*/
diff --git a/drivers/staging/msm/staging-devices.c b/drivers/staging/msm/staging-devices.c
new file mode 100644
index 000000000000..0f8ec3e26013
--- /dev/null
+++ b/drivers/staging/msm/staging-devices.c
@@ -0,0 +1,323 @@
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/bootmem.h>
+#include <linux/delay.h>
+
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+
+#include <mach/board.h>
+#include <mach/irqs.h>
+#include <mach/sirc.h>
+#include <mach/gpio.h>
+
+#include "msm_mdp.h"
+#include "memory_ll.h"
+//#include "android_pmem.h"
+#include <mach/board.h>
+
+#ifdef CONFIG_MSM_SOC_REV_A
+#define MSM_SMI_BASE 0xE0000000
+#else
+#define MSM_SMI_BASE 0x00000000
+#endif
+
+
+#define TOUCHPAD_SUSPEND 34
+#define TOUCHPAD_IRQ 38
+
+#define MSM_PMEM_MDP_SIZE 0x1591000
+
+#ifdef CONFIG_MSM_SOC_REV_A
+#define SMEM_SPINLOCK_I2C "D:I2C02000021"
+#else
+#define SMEM_SPINLOCK_I2C "S:6"
+#endif
+
+#define MSM_PMEM_ADSP_SIZE 0x1C00000
+
+#define MSM_FB_SIZE 0x500000
+#define MSM_FB_SIZE_ST15 0x800000
+#define MSM_AUDIO_SIZE 0x80000
+#define MSM_GPU_PHYS_SIZE SZ_2M
+
+#ifdef CONFIG_MSM_SOC_REV_A
+#define MSM_SMI_BASE 0xE0000000
+#else
+#define MSM_SMI_BASE 0x00000000
+#endif
+
+#define MSM_SHARED_RAM_PHYS (MSM_SMI_BASE + 0x00100000)
+
+#define MSM_PMEM_SMI_BASE (MSM_SMI_BASE + 0x02B00000)
+#define MSM_PMEM_SMI_SIZE 0x01500000
+
+#define MSM_FB_BASE MSM_PMEM_SMI_BASE
+#define MSM_GPU_PHYS_BASE (MSM_FB_BASE + MSM_FB_SIZE)
+#define MSM_PMEM_SMIPOOL_BASE (MSM_GPU_PHYS_BASE + MSM_GPU_PHYS_SIZE)
+#define MSM_PMEM_SMIPOOL_SIZE (MSM_PMEM_SMI_SIZE - MSM_FB_SIZE \
+ - MSM_GPU_PHYS_SIZE)
+
+#if defined(CONFIG_FB_MSM_MDP40)
+#define MDP_BASE 0xA3F00000
+#define PMDH_BASE 0xAD600000
+#define EMDH_BASE 0xAD700000
+#define TVENC_BASE 0xAD400000
+#else
+#define MDP_BASE 0xAA200000
+#define PMDH_BASE 0xAA600000
+#define EMDH_BASE 0xAA700000
+#define TVENC_BASE 0xAA400000
+#endif
+
+#define PMEM_KERNEL_EBI1_SIZE (CONFIG_PMEM_KERNEL_SIZE * 1024 * 1024)
+
+static struct resource msm_fb_resources[] = {
+ {
+ .flags = IORESOURCE_DMA,
+ }
+};
+
+static struct resource msm_mdp_resources[] = {
+ {
+ .name = "mdp",
+ .start = MDP_BASE,
+ .end = MDP_BASE + 0x000F0000 - 1,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device msm_mdp_device = {
+ .name = "mdp",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_mdp_resources),
+ .resource = msm_mdp_resources,
+};
+
+static struct platform_device msm_lcdc_device = {
+ .name = "lcdc",
+ .id = 0,
+};
+
+static int msm_fb_detect_panel(const char *name)
+{
+ int ret = -EPERM;
+
+ if (machine_is_qsd8x50_ffa() || machine_is_qsd8x50a_ffa()) {
+ if (!strncmp(name, "mddi_toshiba_wvga_pt", 20))
+ ret = 0;
+ else
+ ret = -ENODEV;
+ } else if ((machine_is_qsd8x50_surf() || machine_is_qsd8x50a_surf())
+ && !strcmp(name, "lcdc_external"))
+ ret = 0;
+ else if (0 /*machine_is_qsd8x50_grapefruit() */) {
+ if (!strcmp(name, "lcdc_grapefruit_vga"))
+ ret = 0;
+ else
+ ret = -ENODEV;
+ } else if (machine_is_qsd8x50_st1()) {
+ if (!strcmp(name, "lcdc_st1_wxga"))
+ ret = 0;
+ else
+ ret = -ENODEV;
+ } else if (machine_is_qsd8x50a_st1_5()) {
+ if (!strcmp(name, "lcdc_st15") ||
+ !strcmp(name, "hdmi_sii9022"))
+ ret = 0;
+ else
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+/* Only allow a small subset of machines to set the offset via
+ FB PAN_DISPLAY */
+
+static int msm_fb_allow_set_offset(void)
+{
+ return (machine_is_qsd8x50_st1() ||
+ machine_is_qsd8x50a_st1_5()) ? 1 : 0;
+}
+
+
+static struct msm_fb_platform_data msm_fb_pdata = {
+ .detect_client = msm_fb_detect_panel,
+ .allow_set_offset = msm_fb_allow_set_offset,
+};
+
+static struct platform_device msm_fb_device = {
+ .name = "msm_fb",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(msm_fb_resources),
+ .resource = msm_fb_resources,
+ .dev = {
+ .platform_data = &msm_fb_pdata,
+ }
+};
+
+static void __init qsd8x50_allocate_memory_regions(void)
+{
+ void *addr;
+ unsigned long size;
+ if (machine_is_qsd8x50a_st1_5())
+ size = MSM_FB_SIZE_ST15;
+ else
+ size = MSM_FB_SIZE;
+
+ addr = alloc_bootmem(size); // (void *)MSM_FB_BASE;
+ if (!addr)
+ printk("Failed to allocate bootmem for framebuffer\n");
+
+
+ msm_fb_resources[0].start = __pa(addr);
+ msm_fb_resources[0].end = msm_fb_resources[0].start + size - 1;
+ pr_info(KERN_ERR "using %lu bytes of SMI at %lx physical for fb\n",
+ size, (unsigned long)addr);
+}
+
+static int msm_fb_lcdc_gpio_config(int on)
+{
+// return 0;
+ if (machine_is_qsd8x50_st1()) {
+ if (on) {
+ gpio_set_value(32, 1);
+ mdelay(100);
+ gpio_set_value(20, 1);
+ gpio_set_value(17, 1);
+ gpio_set_value(19, 1);
+ } else {
+ gpio_set_value(17, 0);
+ gpio_set_value(19, 0);
+ gpio_set_value(20, 0);
+ mdelay(100);
+ gpio_set_value(32, 0);
+ }
+ } else if (machine_is_qsd8x50a_st1_5()) {
+ if (on) {
+ gpio_set_value(17, 1);
+ gpio_set_value(19, 1);
+ gpio_set_value(20, 1);
+ gpio_set_value(22, 0);
+ gpio_set_value(32, 1);
+ gpio_set_value(155, 1);
+ //st15_hdmi_power(1);
+ gpio_set_value(22, 1);
+
+ } else {
+ gpio_set_value(17, 0);
+ gpio_set_value(19, 0);
+ gpio_set_value(22, 0);
+ gpio_set_value(32, 0);
+ gpio_set_value(155, 0);
+ // st15_hdmi_power(0);
+ }
+ }
+ return 0;
+}
+
+
+static struct lcdc_platform_data lcdc_pdata = {
+ .lcdc_gpio_config = msm_fb_lcdc_gpio_config,
+};
+
+static struct msm_gpio msm_fb_st15_gpio_config_data[] = {
+ { GPIO_CFG(17, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en0" },
+ { GPIO_CFG(19, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "dat_pwr_sv" },
+ { GPIO_CFG(20, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lvds_pwr_dn" },
+ { GPIO_CFG(22, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en1" },
+ { GPIO_CFG(32, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "lcdc_en2" },
+ { GPIO_CFG(103, 0, GPIO_INPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_irq" },
+ { GPIO_CFG(155, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA), "hdmi_3v3" },
+};
+
+static struct msm_panel_common_pdata mdp_pdata = {
+ .gpio = 98,
+};
+
+static struct platform_device *devices[] __initdata = {
+ &msm_fb_device,
+};
+
+
+static void __init msm_register_device(struct platform_device *pdev, void *data)
+{
+ int ret;
+
+ pdev->dev.platform_data = data;
+
+ ret = platform_device_register(pdev);
+ if (ret)
+ dev_err(&pdev->dev,
+ "%s: platform_device_register() failed = %d\n",
+ __func__, ret);
+}
+
+void __init msm_fb_register_device(char *name, void *data)
+{
+ if (!strncmp(name, "mdp", 3))
+ msm_register_device(&msm_mdp_device, data);
+/*
+ else if (!strncmp(name, "pmdh", 4))
+ msm_register_device(&msm_mddi_device, data);
+ else if (!strncmp(name, "emdh", 4))
+ msm_register_device(&msm_mddi_ext_device, data);
+ else if (!strncmp(name, "ebi2", 4))
+ msm_register_device(&msm_ebi2_lcd_device, data);
+ else if (!strncmp(name, "tvenc", 5))
+ msm_register_device(&msm_tvenc_device, data);
+ else */
+
+ if (!strncmp(name, "lcdc", 4))
+ msm_register_device(&msm_lcdc_device, data);
+ /*else
+ printk(KERN_ERR "%s: unknown device! %s\n", __func__, name);
+*/
+}
+
+static void __init msm_fb_add_devices(void)
+{
+ int rc;
+ msm_fb_register_device("mdp", &mdp_pdata);
+// msm_fb_register_device("pmdh", &mddi_pdata);
+// msm_fb_register_device("emdh", &mddi_pdata);
+// msm_fb_register_device("tvenc", 0);
+
+ if (machine_is_qsd8x50a_st1_5()) {
+/* rc = st15_hdmi_vreg_init();
+ if (rc)
+ return;
+*/
+ rc = msm_gpios_request_enable(
+ msm_fb_st15_gpio_config_data,
+ ARRAY_SIZE(msm_fb_st15_gpio_config_data));
+ if (rc) {
+ printk(KERN_ERR "%s: unable to init lcdc gpios\n",
+ __func__);
+ return;
+ }
+ msm_fb_register_device("lcdc", &lcdc_pdata);
+ } else
+ msm_fb_register_device("lcdc", 0);
+}
+
+int __init staging_init_pmem(void)
+{
+ qsd8x50_allocate_memory_regions();
+ return 0;
+}
+
+int __init staging_init_devices(void)
+{
+ platform_add_devices(devices, ARRAY_SIZE(devices));
+ msm_fb_add_devices();
+ return 0;
+}
+
+arch_initcall(staging_init_pmem);
+arch_initcall(staging_init_devices);
diff --git a/drivers/staging/msm/tv_ntsc.c b/drivers/staging/msm/tv_ntsc.c
new file mode 100644
index 000000000000..5eb67611661a
--- /dev/null
+++ b/drivers/staging/msm/tv_ntsc.c
@@ -0,0 +1,163 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#include "msm_fb.h"
+#include "tvenc.h"
+
+#define NTSC_TV_DIMENSION_WIDTH 720
+#define NTSC_TV_DIMENSION_HEIGHT 480
+
+static int ntsc_off(struct platform_device *pdev);
+static int ntsc_on(struct platform_device *pdev);
+
+static int ntsc_on(struct platform_device *pdev)
+{
+ uint32 reg = 0;
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
+
+ if (mfd->panel.id == NTSC_M) {
+ /* Cr gain 11, Cb gain C6, y_gain 97 */
+ TV_OUT(TV_GAIN, 0x0081B697);
+ } else {
+ /* Cr gain 11, Cb gain C6, y_gain 97 */
+ TV_OUT(TV_GAIN, 0x008bc4a3);
+ reg |= TVENC_CTL_NTSCJ_MODE;
+ }
+
+ TV_OUT(TV_CGMS, 0x0);
+ /* NTSC Timing */
+ TV_OUT(TV_SYNC_1, 0x0020009e);
+ TV_OUT(TV_SYNC_2, 0x011306B4);
+ TV_OUT(TV_SYNC_3, 0x0006000C);
+ TV_OUT(TV_SYNC_4, 0x0028020D);
+ TV_OUT(TV_SYNC_5, 0x005E02FB);
+ TV_OUT(TV_SYNC_6, 0x0006000C);
+ TV_OUT(TV_SYNC_7, 0x00000012);
+ TV_OUT(TV_BURST_V1, 0x0013020D);
+ TV_OUT(TV_BURST_V2, 0x0014020C);
+ TV_OUT(TV_BURST_V3, 0x0013020D);
+ TV_OUT(TV_BURST_V4, 0x0014020C);
+ TV_OUT(TV_BURST_H, 0x00AE00F2);
+ TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
+ TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);
+
+ reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60;
+
+ reg |= TVENC_CTL_Y_FILTER_EN |
+ TVENC_CTL_CR_FILTER_EN |
+ TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;
+#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
+ reg |= TVENC_CTL_S_VIDEO_EN;
+#endif
+
+ TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */
+ TV_OUT(TV_OFFSET, 0x008080f0);
+
+#ifdef CONFIG_FB_MSM_MDP31
+ TV_OUT(TV_DAC_INTF, 0x29);
+#endif
+ TV_OUT(TV_ENC_CTL, reg);
+
+ reg |= TVENC_CTL_ENC_EN;
+ TV_OUT(TV_ENC_CTL, reg);
+
+ return ret;
+}
+
+static int ntsc_off(struct platform_device *pdev)
+{
+ TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
+ return 0;
+}
+
+static int __init ntsc_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = ntsc_probe,
+ .driver = {
+ .name = "tv_ntsc",
+ },
+};
+
+static struct msm_fb_panel_data ntsc_panel_data = {
+ .panel_info.xres = NTSC_TV_DIMENSION_WIDTH,
+ .panel_info.yres = NTSC_TV_DIMENSION_HEIGHT,
+ .panel_info.type = TV_PANEL,
+ .panel_info.pdest = DISPLAY_1,
+ .panel_info.wait_cycle = 0,
+ .panel_info.bpp = 16,
+ .panel_info.fb_num = 2,
+ .on = ntsc_on,
+ .off = ntsc_off,
+};
+
+static struct platform_device this_device = {
+ .name = "tv_ntsc",
+ .id = 0,
+ .dev = {
+ .platform_data = &ntsc_panel_data,
+ }
+};
+
+static int __init ntsc_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(ntsc_init); \ No newline at end of file
diff --git a/drivers/staging/msm/tv_pal.c b/drivers/staging/msm/tv_pal.c
new file mode 100644
index 000000000000..204da514660e
--- /dev/null
+++ b/drivers/staging/msm/tv_pal.c
@@ -0,0 +1,213 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#include "msm_fb.h"
+#include "tvenc.h"
+
+#ifdef CONFIG_FB_MSM_TVOUT_PAL_M
+#define PAL_TV_DIMENSION_WIDTH 720
+#define PAL_TV_DIMENSION_HEIGHT 480
+#else
+#define PAL_TV_DIMENSION_WIDTH 720
+#define PAL_TV_DIMENSION_HEIGHT 576
+#endif
+
+static int pal_on(struct platform_device *pdev)
+{
+ uint32 reg = 0;
+ int ret = 0;
+ struct msm_fb_data_type *mfd;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
+
+ switch (mfd->panel.id) {
+ case PAL_BDGHIN:
+ /* Cr gain 11, Cb gain C6, y_gain 97 */
+ TV_OUT(TV_GAIN, 0x0088c1a0);
+ TV_OUT(TV_CGMS, 0x00012345);
+ TV_OUT(TV_TEST_MUX, 0x0);
+ /* PAL Timing */
+ TV_OUT(TV_SYNC_1, 0x00180097);
+ TV_OUT(TV_SYNC_2, 0x011f06c0);
+ TV_OUT(TV_SYNC_3, 0x0005000a);
+ TV_OUT(TV_SYNC_4, 0x00320271);
+ TV_OUT(TV_SYNC_5, 0x005602f9);
+ TV_OUT(TV_SYNC_6, 0x0005000a);
+ TV_OUT(TV_SYNC_7, 0x0000000f);
+ TV_OUT(TV_BURST_V1, 0x0012026e);
+ TV_OUT(TV_BURST_V2, 0x0011026d);
+ TV_OUT(TV_BURST_V3, 0x00100270);
+ TV_OUT(TV_BURST_V4, 0x0013026f);
+ TV_OUT(TV_BURST_H, 0x00af00ea);
+ TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
+ TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);
+
+ reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN;
+ break;
+ case PAL_M:
+ /* Cr gain 11, Cb gain C6, y_gain 97 */
+ TV_OUT(TV_GAIN, 0x0081b697);
+ TV_OUT(TV_CGMS, 0x000af317);
+ TV_OUT(TV_TEST_MUX, 0x000001c3);
+ TV_OUT(TV_TEST_MODE, 0x00000002);
+ /* PAL Timing */
+ TV_OUT(TV_SYNC_1, 0x0020009e);
+ TV_OUT(TV_SYNC_2, 0x011306b4);
+ TV_OUT(TV_SYNC_3, 0x0006000c);
+ TV_OUT(TV_SYNC_4, 0x0028020D);
+ TV_OUT(TV_SYNC_5, 0x005e02fb);
+ TV_OUT(TV_SYNC_6, 0x0006000c);
+ TV_OUT(TV_SYNC_7, 0x00000012);
+ TV_OUT(TV_BURST_V1, 0x0012020b);
+ TV_OUT(TV_BURST_V2, 0x0016020c);
+ TV_OUT(TV_BURST_V3, 0x00150209);
+ TV_OUT(TV_BURST_V4, 0x0013020c);
+ TV_OUT(TV_BURST_H, 0x00bf010b);
+ TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
+ TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);
+
+ reg |= TVENC_CTL_TV_MODE_PAL_M;
+ break;
+ case PAL_N:
+ /* Cr gain 11, Cb gain C6, y_gain 97 */
+ TV_OUT(TV_GAIN, 0x0081b697);
+ TV_OUT(TV_CGMS, 0x000af317);
+ TV_OUT(TV_TEST_MUX, 0x000001c3);
+ TV_OUT(TV_TEST_MODE, 0x00000002);
+ /* PAL Timing */
+ TV_OUT(TV_SYNC_1, 0x00180097);
+ TV_OUT(TV_SYNC_2, 0x12006c0);
+ TV_OUT(TV_SYNC_3, 0x0005000a);
+ TV_OUT(TV_SYNC_4, 0x00320271);
+ TV_OUT(TV_SYNC_5, 0x005602f9);
+ TV_OUT(TV_SYNC_6, 0x0005000a);
+ TV_OUT(TV_SYNC_7, 0x0000000f);
+ TV_OUT(TV_BURST_V1, 0x0012026e);
+ TV_OUT(TV_BURST_V2, 0x0011026d);
+ TV_OUT(TV_BURST_V3, 0x00100270);
+ TV_OUT(TV_BURST_V4, 0x0013026f);
+ TV_OUT(TV_BURST_H, 0x00af00fa);
+ TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
+ TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);
+
+ reg |= TVENC_CTL_TV_MODE_PAL_N;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ reg |= TVENC_CTL_Y_FILTER_EN |
+ TVENC_CTL_CR_FILTER_EN |
+ TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;
+#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
+ reg |= TVENC_CTL_S_VIDEO_EN;
+#endif
+
+ TV_OUT(TV_LEVEL, 0x00000000); /* DC offset to 0. */
+ TV_OUT(TV_OFFSET, 0x008080f0);
+
+#ifdef CONFIG_FB_MSM_MDP31
+ TV_OUT(TV_DAC_INTF, 0x29);
+#endif
+ TV_OUT(TV_ENC_CTL, reg);
+
+ reg |= TVENC_CTL_ENC_EN;
+ TV_OUT(TV_ENC_CTL, reg);
+
+ return ret;
+}
+
+static int pal_off(struct platform_device *pdev)
+{
+ TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
+ return 0;
+}
+
+static int __init pal_probe(struct platform_device *pdev)
+{
+ msm_fb_add_device(pdev);
+
+ return 0;
+}
+
+static struct platform_driver this_driver = {
+ .probe = pal_probe,
+ .driver = {
+ .name = "tv_pal",
+ },
+};
+
+static struct msm_fb_panel_data pal_panel_data = {
+ .panel_info.xres = PAL_TV_DIMENSION_WIDTH,
+ .panel_info.yres = PAL_TV_DIMENSION_HEIGHT,
+ .panel_info.type = TV_PANEL,
+ .panel_info.pdest = DISPLAY_1,
+ .panel_info.wait_cycle = 0,
+ .panel_info.bpp = 16,
+ .panel_info.fb_num = 2,
+ .on = pal_on,
+ .off = pal_off,
+};
+
+static struct platform_device this_device = {
+ .name = "tv_pal",
+ .id = 0,
+ .dev = {
+ .platform_data = &pal_panel_data,
+ }
+};
+
+static int __init pal_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&this_driver);
+ if (!ret) {
+ ret = platform_device_register(&this_device);
+ if (ret)
+ platform_driver_unregister(&this_driver);
+ }
+
+ return ret;
+}
+
+module_init(pal_init);
diff --git a/drivers/staging/msm/tvenc.c b/drivers/staging/msm/tvenc.c
new file mode 100644
index 000000000000..f41c5ac22f25
--- /dev/null
+++ b/drivers/staging/msm/tvenc.c
@@ -0,0 +1,295 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+#include <linux/semaphore.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/pm_qos_params.h>
+
+#define TVENC_C
+#include "tvenc.h"
+#include "msm_fb.h"
+
+static int tvenc_probe(struct platform_device *pdev);
+static int tvenc_remove(struct platform_device *pdev);
+
+static int tvenc_off(struct platform_device *pdev);
+static int tvenc_on(struct platform_device *pdev);
+
+static struct platform_device *pdev_list[MSM_FB_MAX_DEV_LIST];
+static int pdev_list_cnt;
+
+static struct clk *tvenc_clk;
+static struct clk *tvdac_clk;
+
+static struct platform_driver tvenc_driver = {
+ .probe = tvenc_probe,
+ .remove = tvenc_remove,
+ .suspend = NULL,
+// .suspend_late = NULL,
+// .resume_early = NULL,
+ .resume = NULL,
+ .shutdown = NULL,
+ .driver = {
+ .name = "tvenc",
+ },
+};
+
+static struct tvenc_platform_data *tvenc_pdata;
+
+static int tvenc_off(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ ret = panel_next_off(pdev);
+
+ clk_disable(tvenc_clk);
+ clk_disable(tvdac_clk);
+
+ if (tvenc_pdata && tvenc_pdata->pm_vid_en)
+ ret = tvenc_pdata->pm_vid_en(0);
+
+ //pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
+ // PM_QOS_DEFAULT_VALUE);
+
+ if (ret)
+ printk(KERN_ERR "%s: pm_vid_en(off) failed! %d\n",
+ __func__, ret);
+
+ return ret;
+}
+
+static int tvenc_on(struct platform_device *pdev)
+{
+ int ret = 0;
+
+// pm_qos_update_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
+// 128000);
+ if (tvenc_pdata && tvenc_pdata->pm_vid_en)
+ ret = tvenc_pdata->pm_vid_en(1);
+
+ if (ret) {
+ printk(KERN_ERR "%s: pm_vid_en(on) failed! %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ clk_enable(tvenc_clk);
+ clk_enable(tvdac_clk);
+
+ ret = panel_next_on(pdev);
+
+ return ret;
+}
+
+void tvenc_gen_test_pattern(struct msm_fb_data_type *mfd)
+{
+ uint32 reg = 0, i;
+
+ reg = readl(MSM_TV_ENC_CTL);
+ reg |= TVENC_CTL_TEST_PATT_EN;
+
+ for (i = 0; i < 3; i++) {
+ TV_OUT(TV_ENC_CTL, 0); /* disable TV encoder */
+
+ switch (i) {
+ /*
+ * TV Encoder - Color Bar Test Pattern
+ */
+ case 0:
+ reg |= TVENC_CTL_TPG_CLRBAR;
+ break;
+ /*
+ * TV Encoder - Red Frame Test Pattern
+ */
+ case 1:
+ reg |= TVENC_CTL_TPG_REDCLR;
+ break;
+ /*
+ * TV Encoder - Modulated Ramp Test Pattern
+ */
+ default:
+ reg |= TVENC_CTL_TPG_MODRAMP;
+ break;
+ }
+
+ TV_OUT(TV_ENC_CTL, reg);
+ mdelay(5000);
+
+ switch (i) {
+ /*
+ * TV Encoder - Color Bar Test Pattern
+ */
+ case 0:
+ reg &= ~TVENC_CTL_TPG_CLRBAR;
+ break;
+ /*
+ * TV Encoder - Red Frame Test Pattern
+ */
+ case 1:
+ reg &= ~TVENC_CTL_TPG_REDCLR;
+ break;
+ /*
+ * TV Encoder - Modulated Ramp Test Pattern
+ */
+ default:
+ reg &= ~TVENC_CTL_TPG_MODRAMP;
+ break;
+ }
+ }
+}
+
+static int tvenc_resource_initialized;
+
+static int tvenc_probe(struct platform_device *pdev)
+{
+ struct msm_fb_data_type *mfd;
+ struct platform_device *mdp_dev = NULL;
+ struct msm_fb_panel_data *pdata = NULL;
+ int rc;
+
+ if (pdev->id == 0) {
+ tvenc_base = ioremap(pdev->resource[0].start,
+ pdev->resource[0].end -
+ pdev->resource[0].start + 1);
+ if (!tvenc_base) {
+ printk(KERN_ERR
+ "tvenc_base ioremap failed!\n");
+ return -ENOMEM;
+ }
+ tvenc_pdata = pdev->dev.platform_data;
+ tvenc_resource_initialized = 1;
+ return 0;
+ }
+
+ if (!tvenc_resource_initialized)
+ return -EPERM;
+
+ mfd = platform_get_drvdata(pdev);
+
+ if (!mfd)
+ return -ENODEV;
+
+ if (mfd->key != MFD_KEY)
+ return -EINVAL;
+
+ if (pdev_list_cnt >= MSM_FB_MAX_DEV_LIST)
+ return -ENOMEM;
+
+ if (tvenc_base == NULL)
+ return -ENOMEM;
+
+ mdp_dev = platform_device_alloc("mdp", pdev->id);
+ if (!mdp_dev)
+ return -ENOMEM;
+
+ /*
+ * link to the latest pdev
+ */
+ mfd->pdev = mdp_dev;
+ mfd->dest = DISPLAY_TV;
+
+ /*
+ * alloc panel device data
+ */
+ if (platform_device_add_data
+ (mdp_dev, pdev->dev.platform_data,
+ sizeof(struct msm_fb_panel_data))) {
+ printk(KERN_ERR "tvenc_probe: platform_device_add_data failed!\n");
+ platform_device_put(mdp_dev);
+ return -ENOMEM;
+ }
+ /*
+ * data chain
+ */
+ pdata = mdp_dev->dev.platform_data;
+ pdata->on = tvenc_on;
+ pdata->off = tvenc_off;
+ pdata->next = pdev;
+
+ /*
+ * get/set panel specific fb info
+ */
+ mfd->panel_info = pdata->panel_info;
+ mfd->fb_imgType = MDP_YCRYCB_H2V1;
+
+ /*
+ * set driver data
+ */
+ platform_set_drvdata(mdp_dev, mfd);
+
+ /*
+ * register in mdp driver
+ */
+ rc = platform_device_add(mdp_dev);
+ if (rc)
+ goto tvenc_probe_err;
+
+ pdev_list[pdev_list_cnt++] = pdev;
+ return 0;
+
+tvenc_probe_err:
+ platform_device_put(mdp_dev);
+ return rc;
+}
+
+static int tvenc_remove(struct platform_device *pdev)
+{
+// pm_qos_remove_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc");
+ return 0;
+}
+
+static int tvenc_register_driver(void)
+{
+ return platform_driver_register(&tvenc_driver);
+}
+
+static int __init tvenc_driver_init(void)
+{
+ tvenc_clk = clk_get(NULL, "tv_enc_clk");
+ tvdac_clk = clk_get(NULL, "tv_dac_clk");
+
+ if (IS_ERR(tvenc_clk)) {
+ printk(KERN_ERR "error: can't get tvenc_clk!\n");
+ return IS_ERR(tvenc_clk);
+ }
+
+ if (IS_ERR(tvdac_clk)) {
+ printk(KERN_ERR "error: can't get tvdac_clk!\n");
+ return IS_ERR(tvdac_clk);
+ }
+
+// pm_qos_add_requirement(PM_QOS_SYSTEM_BUS_FREQ , "tvenc",
+// PM_QOS_DEFAULT_VALUE);
+ return tvenc_register_driver();
+}
+
+module_init(tvenc_driver_init);
diff --git a/drivers/staging/msm/tvenc.h b/drivers/staging/msm/tvenc.h
new file mode 100644
index 000000000000..a682dbebcf7d
--- /dev/null
+++ b/drivers/staging/msm/tvenc.h
@@ -0,0 +1,117 @@
+/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef TVENC_H
+#define TVENC_H
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+
+#include <mach/hardware.h>
+#include <linux/io.h>
+
+#include <asm/system.h>
+#include <asm/mach-types.h>
+
+#include "msm_fb_panel.h"
+
+#define NTSC_M 0 /* North America, Korea */
+#define NTSC_J 1 /* Japan */
+#define PAL_BDGHIN 2 /* Non-argentina PAL-N */
+#define PAL_M 3 /* PAL-M */
+#define PAL_N 4 /* Argentina PAL-N */
+
+/* 3.57954545 Mhz */
+#define TVENC_CTL_TV_MODE_NTSC_M_PAL60 0
+/* 3.57961149 Mhz */
+#define TVENC_CTL_TV_MODE_PAL_M BIT(0)
+/*non-Argintina = 4.3361875 Mhz */
+#define TVENC_CTL_TV_MODE_PAL_BDGHIN BIT(1)
+/*Argentina = 3.582055625 Mhz */
+#define TVENC_CTL_TV_MODE_PAL_N (BIT(1)|BIT(0))
+
+#define TVENC_CTL_ENC_EN BIT(2)
+#define TVENC_CTL_CC_EN BIT(3)
+#define TVENC_CTL_CGMS_EN BIT(4)
+#define TVENC_CTL_MACRO_EN BIT(5)
+#define TVENC_CTL_Y_FILTER_W_NOTCH BIT(6)
+#define TVENC_CTL_Y_FILTER_WO_NOTCH 0
+#define TVENC_CTL_Y_FILTER_EN BIT(7)
+#define TVENC_CTL_CR_FILTER_EN BIT(8)
+#define TVENC_CTL_CB_FILTER_EN BIT(9)
+#define TVENC_CTL_SINX_FILTER_EN BIT(10)
+#define TVENC_CTL_TEST_PATT_EN BIT(11)
+#define TVENC_CTL_OUTPUT_INV BIT(12)
+#define TVENC_CTL_PAL60_MODE BIT(13)
+#define TVENC_CTL_NTSCJ_MODE BIT(14)
+#define TVENC_CTL_TPG_CLRBAR 0
+#define TVENC_CTL_TPG_MODRAMP BIT(15)
+#define TVENC_CTL_TPG_REDCLR BIT(16)
+#define TVENC_CTL_S_VIDEO_EN BIT(19)
+
+#ifdef TVENC_C
+void *tvenc_base;
+#else
+extern void *tvenc_base;
+#endif
+
+#define TV_OUT(reg, v) writel(v, tvenc_base + MSM_##reg)
+
+#define MSM_TV_ENC_CTL 0x00
+#define MSM_TV_LEVEL 0x04
+#define MSM_TV_GAIN 0x08
+#define MSM_TV_OFFSET 0x0c
+#define MSM_TV_CGMS 0x10
+#define MSM_TV_SYNC_1 0x14
+#define MSM_TV_SYNC_2 0x18
+#define MSM_TV_SYNC_3 0x1c
+#define MSM_TV_SYNC_4 0x20
+#define MSM_TV_SYNC_5 0x24
+#define MSM_TV_SYNC_6 0x28
+#define MSM_TV_SYNC_7 0x2c
+#define MSM_TV_BURST_V1 0x30
+#define MSM_TV_BURST_V2 0x34
+#define MSM_TV_BURST_V3 0x38
+#define MSM_TV_BURST_V4 0x3c
+#define MSM_TV_BURST_H 0x40
+#define MSM_TV_SOL_REQ_ODD 0x44
+#define MSM_TV_SOL_REQ_EVEN 0x48
+#define MSM_TV_DAC_CTL 0x4c
+#define MSM_TV_TEST_MUX 0x50
+#define MSM_TV_TEST_MODE 0x54
+#define MSM_TV_TEST_MISR_RESET 0x58
+#define MSM_TV_TEST_EXPORT_MISR 0x5c
+#define MSM_TV_TEST_MISR_CURR_VAL 0x60
+#define MSM_TV_TEST_SOF_CFG 0x64
+#define MSM_TV_DAC_INTF 0x100
+
+#endif /* TVENC_H */
diff --git a/drivers/staging/phison/Kconfig b/drivers/staging/phison/Kconfig
index d3c65d315a2e..1b56119a7657 100644
--- a/drivers/staging/phison/Kconfig
+++ b/drivers/staging/phison/Kconfig
@@ -1,5 +1,5 @@
config IDE_PHISON
tristate "PCIE ATA PS5000 IDE support"
- depends on PCI && ATA && ATA_SFF
+ depends on PCI && ATA && ATA_SFF && ATA_BMDMA
---help---
This is an experimental driver for PS5000 IDE driver.
diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c
index 643b413d9f0f..e818f53ccfd7 100644
--- a/drivers/staging/pohmelfs/inode.c
+++ b/drivers/staging/pohmelfs/inode.c
@@ -968,12 +968,18 @@ int pohmelfs_setattr_raw(struct inode *inode, struct iattr *attr)
goto err_out_exit;
}
- err = inode_setattr(inode, attr);
- if (err) {
- dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
- goto err_out_exit;
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ err = vmtruncate(inode, attr->ia_size);
+ if (err) {
+ dprintk("%s: ino: %llu, failed to set the attributes.\n", __func__, POHMELFS_I(inode)->ino);
+ goto err_out_exit;
+ }
}
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
dprintk("%s: ino: %llu, mode: %o -> %o, uid: %u -> %u, gid: %u -> %u, size: %llu -> %llu.\n",
__func__, POHMELFS_I(inode)->ino, inode->i_mode, attr->ia_mode,
inode->i_uid, attr->ia_uid, inode->i_gid, attr->ia_gid, inode->i_size, attr->ia_size);
diff --git a/drivers/staging/rt2860/sta_ioctl.c b/drivers/staging/rt2860/sta_ioctl.c
index 112da7a6c417..6b8268d3dc75 100644
--- a/drivers/staging/rt2860/sta_ioctl.c
+++ b/drivers/staging/rt2860/sta_ioctl.c
@@ -2522,6 +2522,8 @@ int rt28xx_sta_ioctl(IN struct net_device *net_dev,
Status =
copy_to_user(erq->pointer, pAd->nickname,
erq->length);
+ if (Status)
+ Status = -EFAULT;
break;
}
case SIOCGIWRATE: /*get default bit rate (bps) */
diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c
index dacefea78113..ce796c9d64bf 100644
--- a/drivers/staging/rtl8187se/r8180_core.c
+++ b/drivers/staging/rtl8187se/r8180_core.c
@@ -61,7 +61,7 @@ static struct pci_device_id rtl8180_pci_id_tbl[] __devinitdata = {
};
-static char *ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
static int hwseqnum = 0;
static int hwwep = 0;
static int channels = 0x3fff;
@@ -74,7 +74,7 @@ MODULE_AUTHOR("Andrea Merello <andreamrl@tiscali.it>");
MODULE_DESCRIPTION("Linux driver for Realtek RTL8180 / RTL8185 WiFi cards");
-module_param(ifname, charp, S_IRUGO|S_IWUSR);
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
module_param(hwseqnum, int, S_IRUGO|S_IWUSR);
module_param(hwwep, int, S_IRUGO|S_IWUSR);
module_param(channels, int, S_IRUGO|S_IWUSR);
@@ -3611,7 +3611,7 @@ static int __devinit rtl8180_pci_probe(struct pci_dev *pdev,
if (dev_alloc_name(dev, ifname) < 0) {
DMESG("Oops: devname already taken! Trying wlan%%d...\n");
- ifname = "wlan%d";
+ strcpy(ifname, "wlan%d");
dev_alloc_name(dev, ifname);
}
diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index eb41402d1d37..e311eedf48df 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -116,7 +116,7 @@ static struct pci_device_id rtl8192_pci_id_tbl[] __devinitdata = {
{}
};
-static char* ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
static int hwwep = 1; //default use hw. set 0 to use software security
static int channels = 0x3fff;
@@ -127,7 +127,7 @@ MODULE_DEVICE_TABLE(pci, rtl8192_pci_id_tbl);
MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards");
-module_param(ifname, charp, S_IRUGO|S_IWUSR );
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
//module_param(hwseqnum,int, S_IRUGO|S_IWUSR);
module_param(hwwep,int, S_IRUGO|S_IWUSR);
module_param(channels,int, S_IRUGO|S_IWUSR);
@@ -6455,7 +6455,7 @@ static int __devinit rtl8192_pci_probe(struct pci_dev *pdev,
if (dev_alloc_name(dev, ifname) < 0){
RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n");
- ifname = "wlan%d";
+ strcpy(ifname, "wlan%d");
dev_alloc_name(dev, ifname);
}
diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c
index 447d6474a70c..03f1cf192346 100644
--- a/drivers/staging/rtl8192su/r8192U_core.c
+++ b/drivers/staging/rtl8192su/r8192U_core.c
@@ -142,13 +142,13 @@ MODULE_VERSION("V 1.1");
MODULE_DEVICE_TABLE(usb, rtl8192_usb_id_tbl);
MODULE_DESCRIPTION("Linux driver for Realtek RTL8192 USB WiFi cards");
-static char* ifname = "wlan%d";
+static char ifname[IFNAMSIZ] = "wlan%d";
static int hwwep = 1; //default use hw. set 0 to use software security
static int channels = 0x3fff;
-module_param(ifname, charp, S_IRUGO|S_IWUSR );
+module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR);
//module_param(hwseqnum,int, S_IRUGO|S_IWUSR);
module_param(hwwep,int, S_IRUGO|S_IWUSR);
module_param(channels,int, S_IRUGO|S_IWUSR);
@@ -7377,7 +7377,7 @@ static int __devinit rtl8192_usb_probe(struct usb_interface *intf,
if (dev_alloc_name(dev, ifname) < 0){
RT_TRACE(COMP_INIT, "Oops: devname already taken! Trying wlan%%d...\n");
- ifname = "wlan%d";
+ strcpy(ifname, "wlan%d");
dev_alloc_name(dev, ifname);
}
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
index 0332c370fd82..ecbde3467b1b 100644
--- a/drivers/staging/sep/sep_driver.c
+++ b/drivers/staging/sep/sep_driver.c
@@ -594,8 +594,10 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep,
dbg("SEP Driver:--------> sep_allocate_data_pool_memory_handler start\n");
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_alloc_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
/* allocate memory */
if ((sep->data_pool_bytes_allocated + command_args.num_bytes) > SEP_DRIVER_DATA_POOL_SHARED_AREA_SIZE_IN_BYTES) {
@@ -609,8 +611,10 @@ static int sep_allocate_data_pool_memory_handler(struct sep_device *sep,
/* write the memory back to the user space */
error = copy_to_user((void *) arg, (void *) &command_args, sizeof(struct sep_driver_alloc_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
/* set the allocation */
sep->data_pool_bytes_allocated += command_args.num_bytes;
@@ -661,6 +665,8 @@ static int sep_write_into_data_pool_handler(struct sep_device *sep, unsigned lon
}
/* copy the application data */
error = copy_from_user(virt_address, (void *) app_in_address, num_bytes);
+ if (error)
+ error = -EFAULT;
end_function:
dbg("SEP Driver:<-------- sep_write_into_data_pool_handler end\n");
return error;
@@ -711,6 +717,8 @@ static int sep_read_from_data_pool_handler(struct sep_device *sep, unsigned long
/* copy the application data */
error = copy_to_user((void *) app_out_address, virt_address, num_bytes);
+ if (error)
+ error = -EFAULT;
end_function:
dbg("SEP Driver:<-------- sep_read_from_data_pool_handler end\n");
return error;
@@ -1448,8 +1456,10 @@ static int sep_create_sync_dma_tables_handler(struct sep_device *sep,
dbg("SEP Driver:--------> sep_create_sync_dma_tables_handler start\n");
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_sync_table_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
edbg("app_in_address is %08lx\n", command_args.app_in_address);
edbg("app_out_address is %08lx\n", command_args.app_out_address);
@@ -1799,8 +1809,10 @@ static int sep_create_flow_dma_tables_handler(struct sep_device *sep,
goto end_function;
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_build_flow_table_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
/* create flow tables */
error = sep_prepare_flow_dma_tables(sep, command_args.num_virtual_buffers, command_args.virt_buff_data_addr, flow_context_ptr, &first_table_data, &last_table_data, command_args.isKernelVirtualAddress);
@@ -1819,8 +1831,10 @@ static int sep_create_flow_dma_tables_handler(struct sep_device *sep,
/* send the parameters to user application */
error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_build_flow_table_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function_with_error;
+ }
/* all the flow created - update the flow entry with temp id */
flow_context_ptr->flow_id = SEP_TEMP_FLOW_ID;
@@ -1861,8 +1875,10 @@ static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg
/* get input parameters */
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_flow_table_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
/* find the flow structure for the flow id */
flow_context_ptr = sep_find_flow_context(sep, command_args.flow_id);
@@ -1933,6 +1949,8 @@ static int sep_add_flow_tables_handler(struct sep_device *sep, unsigned long arg
/* send the parameters to user application */
error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_add_flow_table_t));
+ if (error)
+ error = -EFAULT;
end_function_with_error:
/* free the allocated tables */
sep_deallocated_flow_tables(&first_table_data);
@@ -1953,8 +1971,10 @@ static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned
dbg("SEP Driver:--------> sep_add_flow_tables_message_handler start\n");
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_add_message_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
/* check input */
if (command_args.message_size_in_bytes > SEP_MAX_ADD_MESSAGE_LENGTH_IN_BYTES) {
@@ -1970,6 +1990,8 @@ static int sep_add_flow_tables_message_handler(struct sep_device *sep, unsigned
/* copy the message into context */
flow_context_ptr->message_size_in_bytes = command_args.message_size_in_bytes;
error = copy_from_user(flow_context_ptr->message, (void *) command_args.message_address, command_args.message_size_in_bytes);
+ if (error)
+ error = -EFAULT;
end_function:
dbg("SEP Driver:<-------- sep_add_flow_tables_message_handler end\n");
return error;
@@ -1994,6 +2016,8 @@ static int sep_get_static_pool_addr_handler(struct sep_device *sep, unsigned lon
/* send the parameters to user application */
error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_static_pool_addr_t));
+ if (error)
+ error = -EFAULT;
dbg("SEP Driver:<-------- sep_get_static_pool_addr_handler end\n");
return error;
}
@@ -2010,8 +2034,10 @@ static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsign
dbg("SEP Driver:--------> sep_get_physical_mapped_offset_handler start\n");
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_get_mapped_offset_t));
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
if (command_args.physical_address < sep->shared_bus) {
error = -EINVAL;
@@ -2025,6 +2051,8 @@ static int sep_get_physical_mapped_offset_handler(struct sep_device *sep, unsign
/* send the parameters to user application */
error = copy_to_user((void *) arg, &command_args, sizeof(struct sep_driver_get_mapped_offset_t));
+ if (error)
+ error = -EFAULT;
end_function:
dbg("SEP Driver:<-------- sep_get_physical_mapped_offset_handler end\n");
return error;
@@ -2070,11 +2098,11 @@ static int sep_init_handler(struct sep_device *sep, unsigned long arg)
error = 0;
error = copy_from_user(&command_args, (void *) arg, sizeof(struct sep_driver_init_t));
-
- dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user \n");
-
- if (error)
+ if (error) {
+ error = -EFAULT;
goto end_function;
+ }
+ dbg("SEP Driver:--------> sep_init_handler - finished copy_from_user\n");
/* PATCH - configure the DMA to single -burst instead of multi-burst */
/*sep_configure_dma_burst(); */
diff --git a/drivers/staging/tm6000/Kconfig b/drivers/staging/tm6000/Kconfig
index 5fe759cc2ee9..3657e33e8817 100644
--- a/drivers/staging/tm6000/Kconfig
+++ b/drivers/staging/tm6000/Kconfig
@@ -2,7 +2,8 @@ config VIDEO_TM6000
tristate "TV Master TM5600/6000/6010 driver"
depends on VIDEO_DEV && I2C && INPUT && USB && EXPERIMENTAL
select VIDEO_TUNER
- select TUNER_XC2028
+ select MEDIA_TUNER_XC2028
+ select MEDIA_TUNER_XC5000
select VIDEOBUF_VMALLOC
help
Support for TM5600/TM6000/TM6010 USB Device
diff --git a/drivers/staging/tm6000/tm6000-alsa.c b/drivers/staging/tm6000/tm6000-alsa.c
index bc89f9d28002..273e26ede650 100644
--- a/drivers/staging/tm6000/tm6000-alsa.c
+++ b/drivers/staging/tm6000/tm6000-alsa.c
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/usb.h>
+#include <linux/slab.h>
#include <asm/delay.h>
#include <sound/core.h>
@@ -410,5 +411,28 @@ error:
snd_card_free(card);
return rc;
}
-EXPORT_SYMBOL_GPL(tm6000_audio_init);
+static int tm6000_audio_fini(struct tm6000_core *dev)
+{
+ return 0;
+}
+
+struct tm6000_ops audio_ops = {
+ .id = TM6000_AUDIO,
+ .name = "TM6000 Audio Extension",
+ .init = tm6000_audio_init,
+ .fini = tm6000_audio_fini,
+};
+
+static int __init tm6000_alsa_register(void)
+{
+ return tm6000_register_extension(&audio_ops);
+}
+
+static void __exit tm6000_alsa_unregister(void)
+{
+ tm6000_unregister_extension(&audio_ops);
+}
+
+module_init(tm6000_alsa_register);
+module_exit(tm6000_alsa_unregister);
diff --git a/drivers/staging/tm6000/tm6000-cards.c b/drivers/staging/tm6000/tm6000-cards.c
index 6143e20d139d..6a9ae40c7c6d 100644
--- a/drivers/staging/tm6000/tm6000-cards.c
+++ b/drivers/staging/tm6000/tm6000-cards.c
@@ -24,6 +24,7 @@
#include <linux/i2c.h>
#include <linux/usb.h>
#include <linux/version.h>
+#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tvaudio.h>
@@ -363,13 +364,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
0x02, arg);
msleep(10);
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- TM6000_GPIO_CLK, 0);
- if (rc < 0)
- return rc;
- msleep(10);
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- TM6000_GPIO_CLK, 1);
+ rc = tm6000_i2c_reset(dev, 10);
break;
case XC2028_TUNER_RESET:
/* Reset codes during load firmware */
@@ -423,14 +418,7 @@ int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
break;
case 2:
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- TM6000_GPIO_CLK, 0);
- if (rc < 0)
- return rc;
- msleep(100);
- rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
- TM6000_GPIO_CLK, 1);
- msleep(100);
+ rc = tm6000_i2c_reset(dev, 100);
break;
}
}
@@ -563,7 +551,7 @@ static void tm6000_config_tuner(struct tm6000_core *dev)
switch (dev->tuner_type) {
case TUNER_XC2028:
- tun_setup.tuner_callback = tm6000_tuner_callback;;
+ tun_setup.tuner_callback = tm6000_tuner_callback;
break;
case TUNER_XC5000:
tun_setup.tuner_callback = tm6000_xc5000_callback;
@@ -692,6 +680,10 @@ static int tm6000_init_dev(struct tm6000_core *dev)
if (rc < 0)
goto err;
+ tm6000_add_into_devlist(dev);
+
+ tm6000_init_extension(dev);
+
if (dev->caps.has_dvb) {
dev->dvb = kzalloc(sizeof(*(dev->dvb)), GFP_KERNEL);
if (!dev->dvb) {
@@ -921,6 +913,25 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
}
#endif
+ if (dev->gpio.power_led) {
+ switch (dev->model) {
+ case TM6010_BOARD_HAUPPAUGE_900H:
+ case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
+ case TM6010_BOARD_TWINHAN_TU501:
+ /* Power led off */
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x01);
+ msleep(15);
+ break;
+ case TM6010_BOARD_BEHOLD_WANDER:
+ case TM6010_BOARD_BEHOLD_VOYAGER:
+ /* Power led off */
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.power_led, 0x00);
+ msleep(15);
+ break;
+ }
+ }
tm6000_v4l2_unregister(dev);
tm6000_i2c_unregister(dev);
@@ -931,6 +942,9 @@ static void tm6000_usb_disconnect(struct usb_interface *interface)
usb_put_dev(dev->udev);
+ tm6000_remove_from_devlist(dev);
+ tm6000_close_extension(dev);
+
mutex_unlock(&dev->lock);
kfree(dev);
}
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index bfbc53bd2912..c3690e3580da 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include "tm6000.h"
@@ -153,6 +154,22 @@ int tm6000_get_reg32 (struct tm6000_core *dev, u8 req, u16 value, u16 index)
return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24;
}
+int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep)
+{
+ int rc;
+
+ rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0);
+ if (rc < 0)
+ return rc;
+
+ msleep(tsleep);
+
+ rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1);
+ msleep(tsleep);
+
+ return rc;
+}
+
void tm6000_set_fourcc_format(struct tm6000_core *dev)
{
if (dev->dev_type == TM6010) {
@@ -323,6 +340,12 @@ int tm6000_init_analog_mode (struct tm6000_core *dev)
tm6000_set_standard (dev, &dev->norm);
tm6000_set_audio_bitrate (dev,48000);
+ /* switch dvb led off */
+ if (dev->gpio.dvb_led) {
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.dvb_led, 0x01);
+ }
+
return 0;
}
@@ -375,6 +398,13 @@ int tm6000_init_digital_mode (struct tm6000_core *dev)
tm6000_set_reg (dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
msleep(100);
}
+
+ /* switch dvb led on */
+ if (dev->gpio.dvb_led) {
+ tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
+ dev->gpio.dvb_led, 0x00);
+ }
+
return 0;
}
@@ -600,3 +630,95 @@ printk("Original value=%d\n",val);
return val;
}
EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
+
+static LIST_HEAD(tm6000_devlist);
+static DEFINE_MUTEX(tm6000_devlist_mutex);
+
+/*
+ * tm6000_realease_resource()
+ */
+
+void tm6000_remove_from_devlist(struct tm6000_core *dev)
+{
+ mutex_lock(&tm6000_devlist_mutex);
+ list_del(&dev->devlist);
+ mutex_unlock(&tm6000_devlist_mutex);
+};
+
+void tm6000_add_into_devlist(struct tm6000_core *dev)
+{
+ mutex_lock(&tm6000_devlist_mutex);
+ list_add_tail(&dev->devlist, &tm6000_devlist);
+ mutex_unlock(&tm6000_devlist_mutex);
+};
+
+/*
+ * Extension interface
+ */
+
+static LIST_HEAD(tm6000_extension_devlist);
+static DEFINE_MUTEX(tm6000_extension_devlist_lock);
+
+int tm6000_register_extension(struct tm6000_ops *ops)
+{
+ struct tm6000_core *dev = NULL;
+
+ mutex_lock(&tm6000_devlist_mutex);
+ mutex_lock(&tm6000_extension_devlist_lock);
+ list_add_tail(&ops->next, &tm6000_extension_devlist);
+ list_for_each_entry(dev, &tm6000_devlist, devlist) {
+ if (dev)
+ ops->init(dev);
+ }
+ printk(KERN_INFO "tm6000: Initialized (%s) extension\n", ops->name);
+ mutex_unlock(&tm6000_extension_devlist_lock);
+ mutex_unlock(&tm6000_devlist_mutex);
+ return 0;
+}
+EXPORT_SYMBOL(tm6000_register_extension);
+
+void tm6000_unregister_extension(struct tm6000_ops *ops)
+{
+ struct tm6000_core *dev = NULL;
+
+ mutex_lock(&tm6000_devlist_mutex);
+ list_for_each_entry(dev, &tm6000_devlist, devlist) {
+ if (dev)
+ ops->fini(dev);
+ }
+
+ mutex_lock(&tm6000_extension_devlist_lock);
+ printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name);
+ list_del(&ops->next);
+ mutex_unlock(&tm6000_extension_devlist_lock);
+ mutex_unlock(&tm6000_devlist_mutex);
+}
+EXPORT_SYMBOL(tm6000_unregister_extension);
+
+void tm6000_init_extension(struct tm6000_core *dev)
+{
+ struct tm6000_ops *ops = NULL;
+
+ mutex_lock(&tm6000_extension_devlist_lock);
+ if (!list_empty(&tm6000_extension_devlist)) {
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
+ }
+ }
+ mutex_unlock(&tm6000_extension_devlist_lock);
+}
+
+void tm6000_close_extension(struct tm6000_core *dev)
+{
+ struct tm6000_ops *ops = NULL;
+
+ mutex_lock(&tm6000_extension_devlist_lock);
+ if (!list_empty(&tm6000_extension_devlist)) {
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
+ }
+ }
+ mutex_unlock(&tm6000_extension_devlist_lock);
+}
diff --git a/drivers/staging/tm6000/tm6000-dvb.c b/drivers/staging/tm6000/tm6000-dvb.c
index eafc89c22b6b..86c1c8b5f25a 100644
--- a/drivers/staging/tm6000/tm6000-dvb.c
+++ b/drivers/staging/tm6000/tm6000-dvb.c
@@ -18,6 +18,7 @@
*/
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/usb.h>
#include "tm6000.h"
@@ -28,6 +29,7 @@
#include <media/tuner.h>
#include "tuner-xc2028.h"
+#include "xc5000.h"
static void inline print_err_status (struct tm6000_core *dev,
int packet, int status)
@@ -100,7 +102,10 @@ int tm6000_start_stream(struct tm6000_core *dev)
printk(KERN_INFO "tm6000: got start stream request %s\n",__FUNCTION__);
- tm6000_init_digital_mode(dev);
+ if (dev->mode != TM6000_MODE_DIGITAL) {
+ tm6000_init_digital_mode(dev);
+ dev->mode = TM6000_MODE_DIGITAL;
+ }
dvb->bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
if(dvb->bulk_urb == NULL) {
@@ -254,27 +259,55 @@ int tm6000_dvb_register(struct tm6000_core *dev)
dvb->adapter.priv = dev;
if (dvb->frontend) {
- struct xc2028_config cfg = {
- .i2c_adap = &dev->i2c_adap,
- .i2c_addr = dev->tuner_addr,
- };
-
- dvb->frontend->callback = tm6000_tuner_callback;
- ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
- if (ret < 0) {
- printk(KERN_ERR
- "tm6000: couldn't register frontend\n");
- goto adapter_err;
- }
-
- if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
- printk(KERN_ERR "tm6000: couldn't register "
- "frontend (xc3028)\n");
- ret = -EINVAL;
- goto frontend_err;
+ switch (dev->tuner_type) {
+ case TUNER_XC2028: {
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_adap,
+ .i2c_addr = dev->tuner_addr,
+ };
+
+ dvb->frontend->callback = tm6000_tuner_callback;
+ ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "tm6000: couldn't register frontend\n");
+ goto adapter_err;
+ }
+
+ if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) {
+ printk(KERN_ERR "tm6000: couldn't register "
+ "frontend (xc3028)\n");
+ ret = -EINVAL;
+ goto frontend_err;
+ }
+ printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
+ "attached to frontend!\n");
+ break;
+ }
+ case TUNER_XC5000: {
+ struct xc5000_config cfg = {
+ .i2c_address = dev->tuner_addr,
+ };
+
+ dvb->frontend->callback = tm6000_xc5000_callback;
+ ret = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (ret < 0) {
+ printk(KERN_ERR
+ "tm6000: couldn't register frontend\n");
+ goto adapter_err;
+ }
+
+ if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) {
+ printk(KERN_ERR "tm6000: couldn't register "
+ "frontend (xc5000)\n");
+ ret = -EINVAL;
+ goto frontend_err;
+ }
+ printk(KERN_INFO "tm6000: XC5000 asked to be "
+ "attached to frontend!\n");
+ break;
+ }
}
- printk(KERN_INFO "tm6000: XC2028/3028 asked to be "
- "attached to frontend!\n");
} else {
printk(KERN_ERR "tm6000: no frontend found\n");
}
diff --git a/drivers/staging/tm6000/tm6000-video.c b/drivers/staging/tm6000/tm6000-video.c
index f2b7fe4a3581..56fa371e08c8 100644
--- a/drivers/staging/tm6000/tm6000-video.c
+++ b/drivers/staging/tm6000/tm6000-video.c
@@ -48,7 +48,7 @@
#define TM6000_MIN_BUF 4
#define TM6000_DEF_BUF 8
-#define TM6000_MAX_ISO_PACKETS 40 /* Max number of ISO packets */
+#define TM6000_MAX_ISO_PACKETS 46 /* Max number of ISO packets */
/* Declare static vars that will be used as parameters */
static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
@@ -205,7 +205,11 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
c = (header >> 24) & 0xff;
/* split the header fields */
- size = (((header & 0x7e) << 1) -1) *4;
+ size = ((header & 0x7e) << 1);
+
+ if (size > 0)
+ size -= 4;
+
block = (header >> 7) & 0xf;
field = (header >> 11) & 0x1;
line = (header >> 12) & 0x1ff;
@@ -307,10 +311,12 @@ static int copy_packet(struct urb *urb, u32 header, u8 **ptr, u8 *endp,
case TM6000_URB_MSG_PTS:
break;
case TM6000_URB_MSG_AUDIO:
-/* Need some code to process audio */
-printk ("%ld: cmd=%s, size=%d\n", jiffies,
+ /* Need some code to process audio */
+ printk ("%ld: cmd=%s, size=%d\n", jiffies,
tm6000_msg_type[cmd],size);
break;
+ case TM6000_URB_MSG_VBI:
+ break;
default:
dprintk (dev, V4L2_DEBUG_ISOC, "cmd=%s, size=%d\n",
tm6000_msg_type[cmd],size);
@@ -333,14 +339,23 @@ printk ("%ld: cmd=%s, size=%d\n", jiffies,
return rc;
}
-static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
- struct urb *urb, struct tm6000_buffer **buf)
+static int copy_streams(u8 *data, unsigned long len,
+ struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
u8 *ptr=data, *endp=data+len;
unsigned long header=0;
int rc=0;
+ struct tm6000_buffer *buf;
+ char *outp = NULL;
+
+ get_next_buf(dma_q, &buf);
+ if (buf)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ if (!outp)
+ return 0;
for (ptr=data; ptr<endp;) {
if (!dev->isoc_ctl.cmd) {
@@ -388,14 +403,14 @@ static int copy_streams(u8 *data, u8 *out_p, unsigned long len,
}
HEADER:
/* Copy or continue last copy */
- rc=copy_packet(urb,header,&ptr,endp,out_p,buf);
+ rc=copy_packet(urb,header,&ptr,endp,outp,&buf);
if (rc<0) {
buf=NULL;
printk(KERN_ERR "tm6000: buffer underrun at %ld\n",
jiffies);
return rc;
}
- if (!*buf)
+ if (!buf)
return 0;
}
@@ -404,31 +419,40 @@ HEADER:
/*
* Identify the tm5600/6000 buffer header type and properly handles
*/
-static int copy_multiplexed(u8 *ptr, u8 *out_p, unsigned long len,
- struct urb *urb, struct tm6000_buffer **buf)
+static int copy_multiplexed(u8 *ptr, unsigned long len,
+ struct urb *urb)
{
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
unsigned int pos=dev->isoc_ctl.pos,cpysize;
int rc=1;
+ struct tm6000_buffer *buf;
+ char *outp = NULL;
+
+ get_next_buf(dma_q, &buf);
+ if (buf)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ if (!outp)
+ return 0;
while (len>0) {
- cpysize=min(len,(*buf)->vb.size-pos);
-//printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
- memcpy(&out_p[pos], ptr, cpysize);
+ cpysize=min(len,buf->vb.size-pos);
+ //printk("Copying %d bytes (max=%lu) from %p to %p[%u]\n",cpysize,(*buf)->vb.size,ptr,out_p,pos);
+ memcpy(&outp[pos], ptr, cpysize);
pos+=cpysize;
ptr+=cpysize;
len-=cpysize;
- if (pos >= (*buf)->vb.size) {
+ if (pos >= buf->vb.size) {
pos=0;
/* Announces that a new buffer were filled */
- buffer_filled (dev, dma_q, *buf);
+ buffer_filled (dev, dma_q, buf);
dprintk(dev, V4L2_DEBUG_ISOC, "new buffer filled\n");
- get_next_buf (dma_q, buf);
- if (!*buf)
+ get_next_buf (dma_q, &buf);
+ if (!buf)
break;
- out_p = videobuf_to_vmalloc(&((*buf)->vb));
- if (!out_p)
+ outp = videobuf_to_vmalloc(&(buf->vb));
+ if (!outp)
return rc;
pos = 0;
}
@@ -487,52 +511,36 @@ static inline int tm6000_isoc_copy(struct urb *urb)
struct tm6000_dmaqueue *dma_q = urb->context;
struct tm6000_core *dev= container_of(dma_q,struct tm6000_core,vidq);
struct tm6000_buffer *buf;
- int i, len=0, rc=1;
- int size;
- char *outp = NULL, *p;
- unsigned long copied;
-
- get_next_buf(dma_q, &buf);
- if (buf)
- outp = videobuf_to_vmalloc(&buf->vb);
+ int i, len=0, rc=1, status;
+ char *p;
- if (!outp)
- return 0;
-
- size = buf->vb.size;
-
- copied=0;
-
- if (urb->status<0) {
- print_err_status (dev,-1,urb->status);
+ if (urb->status < 0) {
+ print_err_status (dev, -1, urb->status);
return 0;
}
for (i = 0; i < urb->number_of_packets; i++) {
- int status = urb->iso_frame_desc[i].status;
+ status = urb->iso_frame_desc[i].status;
if (status<0) {
print_err_status (dev,i,status);
continue;
}
- len=urb->iso_frame_desc[i].actual_length;
+ len = urb->iso_frame_desc[i].actual_length;
-// if (len>=TM6000_URB_MSG_LEN) {
- p=urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+ if (len > 0) {
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
if (!urb->iso_frame_desc[i].status) {
- if ((buf->fmt->fourcc)==V4L2_PIX_FMT_TM6000) {
- rc=copy_multiplexed(p, outp, len, urb, &buf);
+ if ((dev->fourcc)==V4L2_PIX_FMT_TM6000) {
+ rc=copy_multiplexed(p, len, urb);
if (rc<=0)
return rc;
} else {
- copy_streams(p, outp, len, urb, &buf);
+ copy_streams(p, len, urb);
}
}
- copied += len;
- if (copied >= size || !buf)
- break;
-// }
+ }
}
return rc;
}
@@ -612,7 +620,7 @@ static void tm6000_uninit_isoc(struct tm6000_core *dev)
static int tm6000_prepare_isoc(struct tm6000_core *dev, unsigned int framesize)
{
struct tm6000_dmaqueue *dma_q = &dev->vidq;
- int i, j, sb_size, pipe, size, max_packets, num_bufs = 5;
+ int i, j, sb_size, pipe, size, max_packets, num_bufs = 8;
struct urb *urb;
/* De-allocates all pending stuff */
diff --git a/drivers/staging/tm6000/tm6000.h b/drivers/staging/tm6000/tm6000.h
index 6812d6867d57..7bbaf26dea14 100644
--- a/drivers/staging/tm6000/tm6000.h
+++ b/drivers/staging/tm6000/tm6000.h
@@ -168,6 +168,10 @@ struct tm6000_core {
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
+
+ /* extension */
+ struct list_head devlist;
+
/* video for linux */
int users;
@@ -203,6 +207,16 @@ struct tm6000_core {
spinlock_t slock;
};
+#define TM6000_AUDIO 0x10
+
+struct tm6000_ops {
+ struct list_head next;
+ char *name;
+ int id;
+ int (*init)(struct tm6000_core *);
+ int (*fini)(struct tm6000_core *);
+};
+
struct tm6000_fh {
struct tm6000_core *dev;
@@ -232,6 +246,8 @@ int tm6000_get_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index);
int tm6000_set_reg (struct tm6000_core *dev, u8 req, u16 value, u16 index);
+int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep);
+
int tm6000_init (struct tm6000_core *dev);
int tm6000_init_analog_mode (struct tm6000_core *dev);
@@ -246,6 +262,13 @@ int tm6000_v4l2_unregister(struct tm6000_core *dev);
int tm6000_v4l2_exit(void);
void tm6000_set_fourcc_format(struct tm6000_core *dev);
+void tm6000_remove_from_devlist(struct tm6000_core *dev);
+void tm6000_add_into_devlist(struct tm6000_core *dev);
+int tm6000_register_extension(struct tm6000_ops *ops);
+void tm6000_unregister_extension(struct tm6000_ops *ops);
+void tm6000_init_extension(struct tm6000_core *dev);
+void tm6000_close_extension(struct tm6000_core *dev);
+
/* In tm6000-stds.c */
void tm6000_get_std_res(struct tm6000_core *dev);
int tm6000_set_standard (struct tm6000_core *dev, v4l2_std_id *norm);
@@ -275,7 +298,7 @@ unsigned int tm6000_v4l2_poll(struct file *file,
int tm6000_queue_init(struct tm6000_core *dev);
/* In tm6000-alsa.c */
-int tm6000_audio_init(struct tm6000_core *dev, int idx);
+/*int tm6000_audio_init(struct tm6000_core *dev, int idx);*/
/* Debug stuff */
diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c
index 52408164036f..6a499f0eb594 100644
--- a/drivers/staging/usbip/usbip_common.c
+++ b/drivers/staging/usbip/usbip_common.c
@@ -378,47 +378,67 @@ int usbip_thread(void *param)
complete_and_exit(&ut->thread_done, 0);
}
+static void stop_rx_thread(struct usbip_device *ud)
+{
+ if (ud->tcp_rx.thread != NULL) {
+ send_sig(SIGKILL, ud->tcp_rx.thread, 1);
+ wait_for_completion(&ud->tcp_rx.thread_done);
+ usbip_udbg("rx_thread for ud %p has finished\n", ud);
+ }
+}
+
+static void stop_tx_thread(struct usbip_device *ud)
+{
+ if (ud->tcp_tx.thread != NULL) {
+ send_sig(SIGKILL, ud->tcp_tx.thread, 1);
+ wait_for_completion(&ud->tcp_tx.thread_done);
+ usbip_udbg("tx_thread for ud %p has finished\n", ud);
+ }
+}
+
int usbip_start_threads(struct usbip_device *ud)
{
/*
* threads are invoked per one device (per one connection).
*/
struct task_struct *th;
+ int err = 0;
th = kthread_run(usbip_thread, (void *)&ud->tcp_rx, "usbip");
if (IS_ERR(th)) {
printk(KERN_WARNING
"Unable to start control thread\n");
- return PTR_ERR(th);
+ err = PTR_ERR(th);
+ goto ust_exit;
}
+
th = kthread_run(usbip_thread, (void *)&ud->tcp_tx, "usbip");
if (IS_ERR(th)) {
printk(KERN_WARNING
"Unable to start control thread\n");
- return PTR_ERR(th);
+ err = PTR_ERR(th);
+ goto tx_thread_err;
}
/* confirm threads are starting */
wait_for_completion(&ud->tcp_rx.thread_done);
wait_for_completion(&ud->tcp_tx.thread_done);
+
return 0;
+
+tx_thread_err:
+ stop_rx_thread(ud);
+
+ust_exit:
+ return err;
}
EXPORT_SYMBOL_GPL(usbip_start_threads);
void usbip_stop_threads(struct usbip_device *ud)
{
/* kill threads related to this sdev, if v.c. exists */
- if (ud->tcp_rx.thread != NULL) {
- send_sig(SIGKILL, ud->tcp_rx.thread, 1);
- wait_for_completion(&ud->tcp_rx.thread_done);
- usbip_udbg("rx_thread for ud %p has finished\n", ud);
- }
-
- if (ud->tcp_tx.thread != NULL) {
- send_sig(SIGKILL, ud->tcp_tx.thread, 1);
- wait_for_completion(&ud->tcp_tx.thread_done);
- usbip_udbg("tx_thread for ud %p has finished\n", ud);
- }
+ stop_rx_thread(ud);
+ stop_tx_thread(ud);
}
EXPORT_SYMBOL_GPL(usbip_stop_threads);
diff --git a/drivers/staging/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index 0c82eb47a28d..0f9ea58ff717 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -523,7 +523,7 @@ static int ca91cx42_alloc_resource(struct vme_master_resource *image,
}
if (image->bus_resource.name == NULL) {
- image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
if (image->bus_resource.name == NULL) {
dev_err(ca91cx42_bridge->parent, "Unable to allocate "
"memory for resource name\n");
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index abe88a380b72..f09cac163139 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -828,7 +828,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image,
return 0;
if (image->bus_resource.name == NULL) {
- image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_KERNEL);
+ image->bus_resource.name = kmalloc(VMENAMSIZ+3, GFP_ATOMIC);
if (image->bus_resource.name == NULL) {
dev_err(tsi148_bridge->parent, "Unable to allocate "
"memory for resource name\n");
diff --git a/drivers/staging/wlags49_h2/Kconfig b/drivers/staging/wlags49_h2/Kconfig
index b6fc2ca7d85c..3efcbf8afedf 100644
--- a/drivers/staging/wlags49_h2/Kconfig
+++ b/drivers/staging/wlags49_h2/Kconfig
@@ -1,9 +1,11 @@
config WLAGS49_H2
tristate "Agere Systems HERMES II Wireless PC Card Model 0110"
- depends on WLAN && WIRELESS_EXT && PCMCIA
+ depends on WLAN && PCMCIA
+ select WIRELESS_EXT
select WEXT_SPY
+ select WEXT_PRIV
---help---
- Driver for wireless cards using Agere's HERMES II chipset
- which are identified with Manufacture ID: 0156,0003
- The software is a modified version of wl_lkm_722_abg.tar.gz
- from the Agere Systems website, addapted for Ubuntu 9.04.
+ Driver for wireless cards using Agere's HERMES II chipset
+ which are identified with Manufacture ID: 0156,0003
+ The software is a modified version of wl_lkm_722_abg.tar.gz
+ from the Agere Systems website, addapted for Ubuntu 9.04.
diff --git a/drivers/staging/wlags49_h25/Kconfig b/drivers/staging/wlags49_h25/Kconfig
index dcc170929c13..bf5664a51cd4 100644
--- a/drivers/staging/wlags49_h25/Kconfig
+++ b/drivers/staging/wlags49_h25/Kconfig
@@ -1,9 +1,11 @@
config WLAGS49_H25
tristate "Linksys HERMES II.5 WCF54G_Wireless-G_CompactFlash_Card"
- depends on WLAN && WIRELESS_EXT && PCMCIA
+ depends on WLAN && PCMCIA
+ select WIRELESS_EXT
select WEXT_SPY
+ select WEXT_PRIV
---help---
- Driver for wireless cards using Agere's HERMES II.5 chipset
- which are identified with Manufacture ID: 0156,0004
- The software is a modified version of wl_lkm_722_abg.tar.gz
- from the Agere Systems website, addapted for Ubuntu 9.04.
+ Driver for wireless cards using Agere's HERMES II.5 chipset
+ which are identified with Manufacture ID: 0156,0004
+ The software is a modified version of wl_lkm_722_abg.tar.gz
+ from the Agere Systems website, addapted for Ubuntu 9.04.
diff --git a/drivers/staging/xgifb/Kconfig b/drivers/staging/xgifb/Kconfig
new file mode 100644
index 000000000000..bb0ca5974ea0
--- /dev/null
+++ b/drivers/staging/xgifb/Kconfig
@@ -0,0 +1,11 @@
+config FB_XGI
+ tristate "XGI display support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This driver supports notebooks with XGI Z7,Z9,Z11 PCI chips.
+ Say Y if you have such a graphics card.
+ To compile this driver as a module, choose M here: the
+ module will be called xgifb.ko
diff --git a/drivers/staging/xgifb/Makefile b/drivers/staging/xgifb/Makefile
new file mode 100644
index 000000000000..2a317707de0f
--- /dev/null
+++ b/drivers/staging/xgifb/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_FB_XGI) += xgifb.o
+
+xgifb-objs := XGI_main_26.o XGI_accel.o vb_init.o vb_setmode.o vb_util.o vb_ext.o
+
diff --git a/drivers/staging/xgifb/TODO b/drivers/staging/xgifb/TODO
new file mode 100644
index 000000000000..7d71019b84c2
--- /dev/null
+++ b/drivers/staging/xgifb/TODO
@@ -0,0 +1,15 @@
+This drivers still need a lot of work. I can list all cleanups to do but it's
+going to be long. So, I'm writing "cleanups" and not the list.
+
+Arnaud
+
+TODO:
+- clean ups
+- fix build warnings when module
+- sort out dup ids with SiS driver
+- remove useless/wrong/unused #ifdef/code/...
+- fix printk usages
+- get rid of non-linux related stuff
+
+Please send patches to:
+Arnaud Patard <apatard@mandriva.com>
diff --git a/drivers/staging/xgifb/XGI.h b/drivers/staging/xgifb/XGI.h
new file mode 100644
index 000000000000..87803dd032de
--- /dev/null
+++ b/drivers/staging/xgifb/XGI.h
@@ -0,0 +1,10 @@
+#ifndef _XGI_H
+#define _XGI_H
+
+#if 1
+#define TWDEBUG(x)
+#else
+#define TWDEBUG(x) printk(KERN_INFO x "\n");
+#endif
+
+#endif
diff --git a/drivers/staging/xgifb/XGI_accel.c b/drivers/staging/xgifb/XGI_accel.c
new file mode 100644
index 000000000000..86ec3421942f
--- /dev/null
+++ b/drivers/staging/xgifb/XGI_accel.c
@@ -0,0 +1,596 @@
+/*
+ * XGI 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's XGI300_accel.c which is
+ * Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ * Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and XGI310_accel.c which is
+ * Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>
+ * (see http://www.winischhofer.net/
+ * for more information and updates)
+ */
+
+//#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/agp_backend.h>
+
+#include <linux/types.h>
+/*
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <linux/XGIfb.h>
+#else
+#include <video/XGIfb.h>
+#endif
+*/
+#include <asm/io.h>
+
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include <video/fbcon.h>
+#include <video/fbcon-cfb8.h>
+#include <video/fbcon-cfb16.h>
+#include <video/fbcon-cfb24.h>
+#include <video/fbcon-cfb32.h>
+#endif
+
+#include "osdef.h"
+#include "vgatypes.h"
+#include "vb_struct.h"
+#include "XGIfb.h"
+#include "XGI_accel.h"
+
+
+extern struct video_info xgi_video_info;
+extern int XGIfb_accel;
+
+static const int XGIALUConv[] =
+{
+ 0x00, /* dest = 0; 0, GXclear, 0 */
+ 0x88, /* dest &= src; DSa, GXand, 0x1 */
+ 0x44, /* dest = src & ~dest; SDna, GXandReverse, 0x2 */
+ 0xCC, /* dest = src; S, GXcopy, 0x3 */
+ 0x22, /* dest &= ~src; DSna, GXandInverted, 0x4 */
+ 0xAA, /* dest = dest; D, GXnoop, 0x5 */
+ 0x66, /* dest = ^src; DSx, GXxor, 0x6 */
+ 0xEE, /* dest |= src; DSo, GXor, 0x7 */
+ 0x11, /* dest = ~src & ~dest; DSon, GXnor, 0x8 */
+ 0x99, /* dest ^= ~src ; DSxn, GXequiv, 0x9 */
+ 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
+ 0xDD, /* dest = src|~dest ; SDno, GXorReverse, 0xB */
+ 0x33, /* dest = ~src; Sn, GXcopyInverted, 0xC */
+ 0xBB, /* dest |= ~src; DSno, GXorInverted, 0xD */
+ 0x77, /* dest = ~src|~dest; DSan, GXnand, 0xE */
+ 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
+};
+/* same ROP but with Pattern as Source */
+static const int XGIPatALUConv[] =
+{
+ 0x00, /* dest = 0; 0, GXclear, 0 */
+ 0xA0, /* dest &= src; DPa, GXand, 0x1 */
+ 0x50, /* dest = src & ~dest; PDna, GXandReverse, 0x2 */
+ 0xF0, /* dest = src; P, GXcopy, 0x3 */
+ 0x0A, /* dest &= ~src; DPna, GXandInverted, 0x4 */
+ 0xAA, /* dest = dest; D, GXnoop, 0x5 */
+ 0x5A, /* dest = ^src; DPx, GXxor, 0x6 */
+ 0xFA, /* dest |= src; DPo, GXor, 0x7 */
+ 0x05, /* dest = ~src & ~dest; DPon, GXnor, 0x8 */
+ 0xA5, /* dest ^= ~src ; DPxn, GXequiv, 0x9 */
+ 0x55, /* dest = ~dest; Dn, GXInvert, 0xA */
+ 0xF5, /* dest = src|~dest ; PDno, GXorReverse, 0xB */
+ 0x0F, /* dest = ~src; Pn, GXcopyInverted, 0xC */
+ 0xAF, /* dest |= ~src; DPno, GXorInverted, 0xD */
+ 0x5F, /* dest = ~src|~dest; DPan, GXnand, 0xE */
+ 0xFF, /* dest = 0xFF; 1, GXset, 0xF */
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+static const unsigned char myrops[] = {
+ 3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+ };
+#endif
+
+/* 300 series */
+#if 0
+static void
+XGI300Sync(void)
+{
+ XGI300Idle
+}
+#endif
+static void
+XGI310Sync(void)
+{
+ XGI310Idle
+}
+#if 0
+static void
+XGI300SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+ unsigned int planemask, int trans_color)
+{
+ XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
+ XGI300SetupSRCPitch(xgi_video_info.video_linelength)
+ XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
+
+ if(trans_color != -1) {
+ XGI300SetupROP(0x0A)
+ XGI300SetupSRCTrans(trans_color)
+ XGI300SetupCMDFlag(TRANSPARENT_BITBLT)
+ } else {
+ XGI300SetupROP(XGIALUConv[rop])
+ }
+ if(xdir > 0) {
+ XGI300SetupCMDFlag(X_INC)
+ }
+ if(ydir > 0) {
+ XGI300SetupCMDFlag(Y_INC)
+ }
+}
+
+static void
+XGI300SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+ int width, int height)
+{
+ long srcbase, dstbase;
+
+ srcbase = dstbase = 0;
+ if (src_y >= 2048) {
+ srcbase = xgi_video_info.video_linelength * src_y;
+ src_y = 0;
+ }
+ if (dst_y >= 2048) {
+ dstbase = xgi_video_info.video_linelength * dst_y;
+ dst_y = 0;
+ }
+
+ XGI300SetupSRCBase(srcbase);
+ XGI300SetupDSTBase(dstbase);
+
+ if(!(xgi_video_info.CommandReg & X_INC)) {
+ src_x += width-1;
+ dst_x += width-1;
+ }
+ if(!(xgi_video_info.CommandReg & Y_INC)) {
+ src_y += height-1;
+ dst_y += height-1;
+ }
+ XGI300SetupRect(width, height)
+ XGI300SetupSRCXY(src_x, src_y)
+ XGI300SetupDSTXY(dst_x, dst_y)
+ XGI300DoCMD
+}
+
+static void
+XGI300SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+ XGI300SetupPATFG(color)
+ XGI300SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
+ XGI300SetupDSTColorDepth(xgi_video_info.DstColor);
+ XGI300SetupROP(XGIPatALUConv[rop])
+ XGI300SetupCMDFlag(PATFG)
+}
+
+static void
+XGI300SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+ long dstbase;
+
+ dstbase = 0;
+ if(y >= 2048) {
+ dstbase = xgi_video_info.video_linelength * y;
+ y = 0;
+ }
+ XGI300SetupDSTBase(dstbase)
+ XGI300SetupDSTXY(x,y)
+ XGI300SetupRect(w,h)
+ XGI300SetupCMDFlag(X_INC | Y_INC | BITBLT)
+ XGI300DoCMD
+}
+#endif
+/* 310/325 series ------------------------------------------------ */
+
+static void
+XGI310SetupForScreenToScreenCopy(int xdir, int ydir, int rop,
+ unsigned int planemask, int trans_color)
+{
+ XGI310SetupDSTColorDepth(xgi_video_info.DstColor);
+ XGI310SetupSRCPitch(xgi_video_info.video_linelength)
+ XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
+ if (trans_color != -1) {
+ XGI310SetupROP(0x0A)
+ XGI310SetupSRCTrans(trans_color)
+ XGI310SetupCMDFlag(TRANSPARENT_BITBLT)
+ } else {
+ XGI310SetupROP(XGIALUConv[rop])
+ /* Set command - not needed, both 0 */
+ /* XGISetupCMDFlag(BITBLT | SRCVIDEO) */
+ }
+ XGI310SetupCMDFlag(xgi_video_info.XGI310_AccelDepth)
+ /* TW: The 310/325 series is smart enough to know the direction */
+}
+
+static void
+XGI310SubsequentScreenToScreenCopy(int src_x, int src_y, int dst_x, int dst_y,
+ int width, int height)
+{
+ long srcbase, dstbase;
+ int mymin, mymax;
+
+ srcbase = dstbase = 0;
+ mymin = min(src_y, dst_y);
+ mymax = max(src_y, dst_y);
+
+ /* Although the chip knows the direction to use
+ * if the source and destination areas overlap,
+ * that logic fails if we fiddle with the bitmap
+ * addresses. Therefore, we check if the source
+ * and destination blitting areas overlap and
+ * adapt the bitmap addresses synchronously
+ * if the coordinates exceed the valid range.
+ * The the areas do not overlap, we do our
+ * normal check.
+ */
+ if((mymax - mymin) < height) {
+ if((src_y >= 2048) || (dst_y >= 2048)) {
+ srcbase = xgi_video_info.video_linelength * mymin;
+ dstbase = xgi_video_info.video_linelength * mymin;
+ src_y -= mymin;
+ dst_y -= mymin;
+ }
+ } else {
+ if(src_y >= 2048) {
+ srcbase = xgi_video_info.video_linelength * src_y;
+ src_y = 0;
+ }
+ if(dst_y >= 2048) {
+ dstbase = xgi_video_info.video_linelength * dst_y;
+ dst_y = 0;
+ }
+ }
+
+ XGI310SetupSRCBase(srcbase);
+ XGI310SetupDSTBase(dstbase);
+ XGI310SetupRect(width, height)
+ XGI310SetupSRCXY(src_x, src_y)
+ XGI310SetupDSTXY(dst_x, dst_y)
+ XGI310DoCMD
+}
+
+static void
+XGI310SetupForSolidFill(int color, int rop, unsigned int planemask)
+{
+ XGI310SetupPATFG(color)
+ XGI310SetupDSTRect(xgi_video_info.video_linelength, 0xFFF)
+ XGI310SetupDSTColorDepth(xgi_video_info.DstColor);
+ XGI310SetupROP(XGIPatALUConv[rop])
+ XGI310SetupCMDFlag(PATFG | xgi_video_info.XGI310_AccelDepth)
+}
+
+static void
+XGI310SubsequentSolidFillRect(int x, int y, int w, int h)
+{
+ long dstbase;
+
+ dstbase = 0;
+ if(y >= 2048) {
+ dstbase = xgi_video_info.video_linelength * y;
+ y = 0;
+ }
+ XGI310SetupDSTBase(dstbase)
+ XGI310SetupDSTXY(x,y)
+ XGI310SetupRect(w,h)
+ XGI310SetupCMDFlag(BITBLT)
+ XGI310DoCMD
+}
+
+/* --------------------------------------------------------------------- */
+
+/* The exported routines */
+
+int XGIfb_initaccel(void)
+{
+#ifdef XGIFB_USE_SPINLOCKS
+ spin_lock_init(&xgi_video_info.lockaccel);
+#endif
+ return(0);
+}
+
+void XGIfb_syncaccel(void)
+{
+
+ XGI310Sync();
+
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34) /* --- KERNEL 2.5.34 and later --- */
+
+int fbcon_XGI_sync(struct fb_info *info)
+{
+ if(!XGIfb_accel) return 0;
+ CRITFLAGS
+
+ XGI310Sync();
+
+ CRITEND
+ return 0;
+}
+
+void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
+{
+ int col=0;
+ CRITFLAGS
+
+
+ if(!rect->width || !rect->height)
+ return;
+
+ if(!XGIfb_accel) {
+ cfb_fillrect(info, rect);
+ return;
+ }
+
+ switch(info->var.bits_per_pixel) {
+ case 8: col = rect->color;
+ break;
+ case 16: col = ((u32 *)(info->pseudo_palette))[rect->color];
+ break;
+ case 32: col = ((u32 *)(info->pseudo_palette))[rect->color];
+ break;
+ }
+
+
+ CRITBEGIN
+ XGI310SetupForSolidFill(col, myrops[rect->rop], 0);
+ XGI310SubsequentSolidFillRect(rect->dx, rect->dy, rect->width, rect->height);
+ CRITEND
+ XGI310Sync();
+
+
+}
+
+void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area)
+{
+ int xdir, ydir;
+ CRITFLAGS
+
+
+ if(!XGIfb_accel) {
+ cfb_copyarea(info, area);
+ return;
+ }
+
+ if(!area->width || !area->height)
+ return;
+
+ if(area->sx < area->dx) xdir = 0;
+ else xdir = 1;
+ if(area->sy < area->dy) ydir = 0;
+ else ydir = 1;
+
+ CRITBEGIN
+ XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+ XGI310SubsequentScreenToScreenCopy(area->sx, area->sy, area->dx, area->dy, area->width, area->height);
+ CRITEND
+ XGI310Sync();
+
+}
+
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33) /* ------ KERNEL <2.5.34 ------ */
+
+void fbcon_XGI_bmove(struct display *p, int srcy, int srcx,
+ int dsty, int dstx, int height, int width)
+{
+ int xdir, ydir;
+ CRITFLAGS
+
+ if(!xgi_video_info.accel) {
+ switch(xgi_video_info.video_bpp) {
+ case 8:
+#ifdef FBCON_HAS_CFB8
+ fbcon_cfb8_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+ break;
+ case 16:
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+ break;
+ case 32:
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_bmove(p, srcy, srcx, dsty, dstx, height, width);
+#endif
+ break;
+ }
+ return;
+ }
+
+ srcx *= fontwidth(p);
+ srcy *= fontheight(p);
+ dstx *= fontwidth(p);
+ dsty *= fontheight(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+
+ if(srcx < dstx) xdir = 0;
+ else xdir = 1;
+ if(srcy < dsty) ydir = 0;
+ else ydir = 1;
+
+
+ CRITBEGIN
+ XGI310SetupForScreenToScreenCopy(xdir, ydir, 3, 0, -1);
+ XGI310SubsequentScreenToScreenCopy(srcx, srcy, dstx, dsty, width, height);
+ CRITEND
+ XGI310Sync();
+#if 0
+ printk(KERN_INFO "XGI_bmove sx %d sy %d dx %d dy %d w %d h %d\n",
+ srcx, srcy, dstx, dsty, width, height);
+#endif
+
+}
+
+
+static void fbcon_XGI_clear(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width, int color)
+{
+ CRITFLAGS
+
+ srcx *= fontwidth(p);
+ srcy *= fontheight(p);
+ width *= fontwidth(p);
+ height *= fontheight(p);
+
+
+ CRITBEGIN
+ XGI310SetupForSolidFill(color, 3, 0);
+ XGI310SubsequentSolidFillRect(srcx, srcy, width, height);
+ CRITEND
+ XGI310Sync();
+
+}
+
+void fbcon_XGI_clear8(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width)
+{
+ u32 bgx;
+
+ if(!xgi_video_info.accel) {
+#ifdef FBCON_HAS_CFB8
+ fbcon_cfb8_clear(conp, p, srcy, srcx, height, width);
+#endif
+ return;
+ }
+
+ bgx = attr_bgcol_ec(p, conp);
+ fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_XGI_clear16(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width)
+{
+ u32 bgx;
+ if(!xgi_video_info.accel) {
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_clear(conp, p, srcy, srcx, height, width);
+#endif
+ return;
+ }
+
+ bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_XGI_clear32(struct vc_data *conp, struct display *p,
+ int srcy, int srcx, int height, int width)
+{
+ u32 bgx;
+
+ if(!xgi_video_info.accel) {
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_clear(conp, p, srcy, srcx, height, width);
+#endif
+ return;
+ }
+
+ bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)];
+ fbcon_XGI_clear(conp, p, srcy, srcx, height, width, bgx);
+}
+
+void fbcon_XGI_revc(struct display *p, int srcx, int srcy)
+{
+ CRITFLAGS
+
+ if(!xgi_video_info.accel) {
+ switch(xgi_video_info.video_bpp) {
+ case 16:
+#ifdef FBCON_HAS_CFB16
+ fbcon_cfb16_revc(p, srcx, srcy);
+#endif
+ break;
+ case 32:
+#ifdef FBCON_HAS_CFB32
+ fbcon_cfb32_revc(p, srcx, srcy);
+#endif
+ break;
+ }
+ return;
+ }
+
+ srcx *= fontwidth(p);
+ srcy *= fontheight(p);
+
+
+ CRITBEGIN
+ XGI310SetupForSolidFill(0, 0x0a, 0);
+ XGI310SubsequentSolidFillRect(srcx, srcy, fontwidth(p), fontheight(p));
+ CRITEND
+ XGI310Sync();
+
+}
+
+#ifdef FBCON_HAS_CFB8
+struct display_switch fbcon_XGI8 = {
+ setup: fbcon_cfb8_setup,
+ bmove: fbcon_XGI_bmove,
+ clear: fbcon_XGI_clear8,
+ putc: fbcon_cfb8_putc,
+ putcs: fbcon_cfb8_putcs,
+ revc: fbcon_cfb8_revc,
+ clear_margins: fbcon_cfb8_clear_margins,
+ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB16
+struct display_switch fbcon_XGI16 = {
+ setup: fbcon_cfb16_setup,
+ bmove: fbcon_XGI_bmove,
+ clear: fbcon_XGI_clear16,
+ putc: fbcon_cfb16_putc,
+ putcs: fbcon_cfb16_putcs,
+ revc: fbcon_XGI_revc,
+ clear_margins: fbcon_cfb16_clear_margins,
+ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+#ifdef FBCON_HAS_CFB32
+struct display_switch fbcon_XGI32 = {
+ setup: fbcon_cfb32_setup,
+ bmove: fbcon_XGI_bmove,
+ clear: fbcon_XGI_clear32,
+ putc: fbcon_cfb32_putc,
+ putcs: fbcon_cfb32_putcs,
+ revc: fbcon_XGI_revc,
+ clear_margins: fbcon_cfb32_clear_margins,
+ fontwidthmask: FONTWIDTH(4)|FONTWIDTH(8)|FONTWIDTH(12)|FONTWIDTH(16)
+};
+#endif
+
+#endif /* KERNEL VERSION */
+
+
diff --git a/drivers/staging/xgifb/XGI_accel.h b/drivers/staging/xgifb/XGI_accel.h
new file mode 100644
index 000000000000..04e126772bb8
--- /dev/null
+++ b/drivers/staging/xgifb/XGI_accel.h
@@ -0,0 +1,511 @@
+/*
+ * XGI 300/630/730/540/315/550/650/740 frame buffer driver
+ * for Linux kernels 2.4.x and 2.5.x
+ *
+ * 2D acceleration part
+ *
+ * Based on the X driver's XGI300_accel.h which is
+ * Copyright Xavier Ducoin <x.ducoin@lectra.com>
+ * Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ * and XGI310_accel.h which is
+ * Copyright 2002 by Thomas Winischhofer, Vienna, Austria
+ *
+ * Author: Thomas Winischhofer <thomas@winischhofer.net>:
+ * (see http://www.winischhofer.net/
+ * for more information and updates)
+ */
+
+#ifndef _XGIFB_ACCEL_H
+#define _XGIFB_ACCEL_H
+
+/* Guard accelerator accesses with spin_lock_irqsave? Works well without. */
+#undef XGIFB_USE_SPINLOCKS
+
+#ifdef XGIFB_USE_SPINLOCKS
+#include <linux/spinlock.h>
+#define CRITBEGIN spin_lock_irqsave(&xgi_video_info.lockaccel), critflags);
+#define CRITEND spin_unlock_irqrestore(&xgi_video_info.lockaccel), critflags);
+#define CRITFLAGS unsigned long critflags;
+#else
+#define CRITBEGIN
+#define CRITEND
+#define CRITFLAGS
+#endif
+
+/* Definitions for the XGI engine communication. */
+
+#define PATREGSIZE 384 /* Pattern register size. 384 bytes @ 0x8300 */
+#define BR(x) (0x8200 | (x) << 2)
+#define PBR(x) (0x8300 | (x) << 2)
+
+/* XGI300 engine commands */
+#define BITBLT 0x00000000 /* Blit */
+#define COLOREXP 0x00000001 /* Color expand */
+#define ENCOLOREXP 0x00000002 /* Enhanced color expand */
+#define MULTIPLE_SCANLINE 0x00000003 /* ? */
+#define LINE 0x00000004 /* Draw line */
+#define TRAPAZOID_FILL 0x00000005 /* Fill trapezoid */
+#define TRANSPARENT_BITBLT 0x00000006 /* Transparent Blit */
+
+/* Additional engine commands for 310/325 */
+#define ALPHA_BLEND 0x00000007 /* Alpha blend ? */
+#define A3D_FUNCTION 0x00000008 /* 3D command ? */
+#define CLEAR_Z_BUFFER 0x00000009 /* ? */
+#define GRADIENT_FILL 0x0000000A /* Gradient fill */
+#define STRETCH_BITBLT 0x0000000B /* Stretched Blit */
+
+/* source select */
+#define SRCVIDEO 0x00000000 /* source is video RAM */
+#define SRCSYSTEM 0x00000010 /* source is system memory */
+#define SRCCPUBLITBUF SRCSYSTEM /* source is CPU-driven BitBuffer (for color expand) */
+#define SRCAGP 0x00000020 /* source is AGP memory (?) */
+
+/* Pattern flags */
+#define PATFG 0x00000000 /* foreground color */
+#define PATPATREG 0x00000040 /* pattern in pattern buffer (0x8300) */
+#define PATMONO 0x00000080 /* mono pattern */
+
+/* blitting direction (300 series only) */
+#define X_INC 0x00010000
+#define X_DEC 0x00000000
+#define Y_INC 0x00020000
+#define Y_DEC 0x00000000
+
+/* Clipping flags */
+#define NOCLIP 0x00000000
+#define NOMERGECLIP 0x04000000
+#define CLIPENABLE 0x00040000
+#define CLIPWITHOUTMERGE 0x04040000
+
+/* Transparency */
+#define OPAQUE 0x00000000
+#define TRANSPARENT 0x00100000
+
+/* ? */
+#define DSTAGP 0x02000000
+#define DSTVIDEO 0x02000000
+
+/* Line */
+#define LINE_STYLE 0x00800000
+#define NO_RESET_COUNTER 0x00400000
+#define NO_LAST_PIXEL 0x00200000
+
+/* Subfunctions for Color/Enhanced Color Expansion (310/325 only) */
+#define COLOR_TO_MONO 0x00100000
+#define AA_TEXT 0x00200000
+
+/* Some general registers for 310/325 series */
+#define SRC_ADDR 0x8200
+#define SRC_PITCH 0x8204
+#define AGP_BASE 0x8206 /* color-depth dependent value */
+#define SRC_Y 0x8208
+#define SRC_X 0x820A
+#define DST_Y 0x820C
+#define DST_X 0x820E
+#define DST_ADDR 0x8210
+#define DST_PITCH 0x8214
+#define DST_HEIGHT 0x8216
+#define RECT_WIDTH 0x8218
+#define RECT_HEIGHT 0x821A
+#define PAT_FGCOLOR 0x821C
+#define PAT_BGCOLOR 0x8220
+#define SRC_FGCOLOR 0x8224
+#define SRC_BGCOLOR 0x8228
+#define MONO_MASK 0x822C
+#define LEFT_CLIP 0x8234
+#define TOP_CLIP 0x8236
+#define RIGHT_CLIP 0x8238
+#define BOTTOM_CLIP 0x823A
+#define COMMAND_READY 0x823C
+#define FIRE_TRIGGER 0x8240
+
+#define PATTERN_REG 0x8300 /* 384 bytes pattern buffer */
+
+/* Line registers */
+#define LINE_X0 SRC_Y
+#define LINE_X1 DST_Y
+#define LINE_Y0 SRC_X
+#define LINE_Y1 DST_X
+#define LINE_COUNT RECT_WIDTH
+#define LINE_STYLE_PERIOD RECT_HEIGHT
+#define LINE_STYLE_0 MONO_MASK
+#define LINE_STYLE_1 0x8230
+#define LINE_XN PATTERN_REG
+#define LINE_YN PATTERN_REG+2
+
+/* Transparent bitblit registers */
+#define TRANS_DST_KEY_HIGH PAT_FGCOLOR
+#define TRANS_DST_KEY_LOW PAT_BGCOLOR
+#define TRANS_SRC_KEY_HIGH SRC_FGCOLOR
+#define TRANS_SRC_KEY_LOW SRC_BGCOLOR
+
+/* Queue */
+#define Q_BASE_ADDR 0x85C0 /* Base address of software queue (?) */
+#define Q_WRITE_PTR 0x85C4 /* Current write pointer (?) */
+#define Q_READ_PTR 0x85C8 /* Current read pointer (?) */
+#define Q_STATUS 0x85CC /* queue status */
+
+
+#define MMIO_IN8(base, offset) \
+ *(volatile u8 *)(((u8*)(base)) + (offset))
+#define MMIO_IN16(base, offset) \
+ *(volatile u16 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_IN32(base, offset) \
+ *(volatile u32 *)(void *)(((u8*)(base)) + (offset))
+#define MMIO_OUT8(base, offset, val) \
+ *(volatile u8 *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT16(base, offset, val) \
+ *(volatile u16 *)(void *)(((u8*)(base)) + (offset)) = (val)
+#define MMIO_OUT32(base, offset, val) \
+ *(volatile u32 *)(void *)(((u8*)(base)) + (offset)) = (val)
+
+
+
+/* ------------- XGI 300 series -------------- */
+
+/* Macros to do useful things with the XGI BitBLT engine */
+
+/* BR(16) (0x8420):
+
+ bit 31 2D engine: 1 is idle,
+ bit 30 3D engine: 1 is idle,
+ bit 29 Command queue: 1 is empty
+
+ bits 28:24: Current CPU driven BitBlt buffer stage bit[4:0]
+
+ bits 15:0: Current command queue length
+
+*/
+
+/* TW: BR(16)+2 = 0x8242 */
+
+int xgiCmdQueLen;
+
+#define XGI300Idle \
+ { \
+ while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+ while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+ while( (MMIO_IN16(xgi_video_info.mmio_vbase, BR(16)+2) & 0xE000) != 0xE000){}; \
+ xgiCmdQueLen=MMIO_IN16(xgi_video_info.mmio_vbase, 0x8240); \
+ }
+/* TW: (do three times, because 2D engine seems quite unsure about whether or not it's idle) */
+
+#define XGI300SetupSRCBase(base) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(0), base);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupSRCPitch(pitch) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, BR(1), pitch);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupSRCXY(x,y) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(2), (x)<<16 | (y) );\
+ xgiCmdQueLen --;
+
+#define XGI300SetupDSTBase(base) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(4), base);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupDSTXY(x,y) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(3), (x)<<16 | (y) );\
+ xgiCmdQueLen --;
+
+#define XGI300SetupDSTRect(x,y) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(5), (y)<<16 | (x) );\
+ xgiCmdQueLen --;
+
+#define XGI300SetupDSTColorDepth(bpp) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, BR(1)+2, bpp);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupRect(w,h) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(6), (h)<<16 | (w) );\
+ xgiCmdQueLen --;
+
+#define XGI300SetupPATFG(color) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(7), color);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupPATBG(color) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(8), color);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupSRCFG(color) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(9), color);\
+ xgiCmdQueLen --;
+
+#define XGI300SetupSRCBG(color) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(10), color);\
+ xgiCmdQueLen --;
+
+/* 0x8224 src colorkey high */
+/* 0x8228 src colorkey low */
+/* 0x821c dest colorkey high */
+/* 0x8220 dest colorkey low */
+#define XGI300SetupSRCTrans(color) \
+ if (xgiCmdQueLen <= 1) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8224, color);\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8228, color);\
+ xgiCmdQueLen -= 2;
+
+#define XGI300SetupDSTTrans(color) \
+ if (xgiCmdQueLen <= 1) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, 0x821C, color); \
+ MMIO_OUT32(xgi_video_info.mmio_vbase, 0x8220, color); \
+ xgiCmdQueLen -= 2;
+
+#define XGI300SetupMONOPAT(p0,p1) \
+ if (xgiCmdQueLen <= 1) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(11), p0);\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(12), p1);\
+ xgiCmdQueLen -= 2;
+
+#define XGI300SetupClipLT(left,top) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(13), ((left) & 0xFFFF) | (top)<<16 );\
+ xgiCmdQueLen--;
+
+#define XGI300SetupClipRB(right,bottom) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(14), ((right) & 0xFFFF) | (bottom)<<16 );\
+ xgiCmdQueLen--;
+
+/* General */
+#define XGI300SetupROP(rop) \
+ xgi_video_info.CommandReg = (rop) << 8;
+
+#define XGI300SetupCMDFlag(flags) \
+ xgi_video_info.CommandReg |= (flags);
+
+#define XGI300DoCMD \
+ if (xgiCmdQueLen <= 1) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(15), xgi_video_info.CommandReg); \
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(16), 0);\
+ xgiCmdQueLen -= 2;
+
+/* Line */
+#define XGI300SetupX0Y0(x,y) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(2), (y)<<16 | (x) );\
+ xgiCmdQueLen--;
+
+#define XGI300SetupX1Y1(x,y) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(3), (y)<<16 | (x) );\
+ xgiCmdQueLen--;
+
+#define XGI300SetupLineCount(c) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, BR(6), c);\
+ xgiCmdQueLen--;
+
+#define XGI300SetupStylePeriod(p) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, BR(6)+2, p);\
+ xgiCmdQueLen--;
+
+#define XGI300SetupStyleLow(ls) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(11), ls);\
+ xgiCmdQueLen--;
+
+#define XGI300SetupStyleHigh(ls) \
+ if (xgiCmdQueLen <= 0) XGI300Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, BR(12), ls);\
+ xgiCmdQueLen--;
+
+
+
+/* ----------- XGI 310/325 series --------------- */
+
+/* Q_STATUS:
+ bit 31 = 1: All engines idle and all queues empty
+ bit 30 = 1: Hardware Queue (=HW CQ, 2D queue, 3D queue) empty
+ bit 29 = 1: 2D engine is idle
+ bit 28 = 1: 3D engine is idle
+ bit 27 = 1: HW command queue empty
+ bit 26 = 1: 2D queue empty
+ bit 25 = 1: 3D queue empty
+ bit 24 = 1: SW command queue empty
+ bits 23:16: 2D counter 3
+ bits 15:8: 2D counter 2
+ bits 7:0: 2D counter 1
+
+ Where is the command queue length (current amount of commands the queue
+ can accept) on the 310/325 series? (The current implementation is taken
+ from 300 series and certainly wrong...)
+*/
+
+/* TW: FIXME: xgiCmdQueLen is... where....? */
+#define XGI310Idle \
+ { \
+ while( (MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+ while( (MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS+2) & 0x8000) != 0x8000){}; \
+ xgiCmdQueLen=MMIO_IN16(xgi_video_info.mmio_vbase, Q_STATUS); \
+ }
+
+#define XGI310SetupSRCBase(base) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_ADDR, base);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupSRCPitch(pitch) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, SRC_PITCH, pitch);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupSRCXY(x,y) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_Y, (x)<<16 | (y) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupDSTBase(base) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, DST_ADDR, base);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupDSTXY(x,y) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, DST_Y, (x)<<16 | (y) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupDSTRect(x,y) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, DST_PITCH, (y)<<16 | (x) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupDSTColorDepth(bpp) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, AGP_BASE, bpp);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupRect(w,h) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, RECT_WIDTH, (h)<<16 | (w) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupPATFG(color) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, PAT_FGCOLOR, color);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupPATBG(color) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, PAT_BGCOLOR, color);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupSRCFG(color) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_FGCOLOR, color);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupSRCBG(color) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, SRC_BGCOLOR, color);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupSRCTrans(color) \
+ if (xgiCmdQueLen <= 1) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_SRC_KEY_HIGH, color);\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_SRC_KEY_LOW, color);\
+ xgiCmdQueLen -= 2;
+
+#define XGI310SetupDSTTrans(color) \
+ if (xgiCmdQueLen <= 1) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_DST_KEY_HIGH, color); \
+ MMIO_OUT32(xgi_video_info.mmio_vbase, TRANS_DST_KEY_LOW, color); \
+ xgiCmdQueLen -= 2;
+
+#define XGI310SetupMONOPAT(p0,p1) \
+ if (xgiCmdQueLen <= 1) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, MONO_MASK, p0);\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, MONO_MASK+4, p1);\
+ xgiCmdQueLen -= 2;
+
+#define XGI310SetupClipLT(left,top) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, LEFT_CLIP, ((left) & 0xFFFF) | (top)<<16 );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupClipRB(right,bottom) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, RIGHT_CLIP, ((right) & 0xFFFF) | (bottom)<<16 );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupROP(rop) \
+ xgi_video_info.CommandReg = (rop) << 8;
+
+#define XGI310SetupCMDFlag(flags) \
+ xgi_video_info.CommandReg |= (flags);
+
+#define XGI310DoCMD \
+ if (xgiCmdQueLen <= 1) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, COMMAND_READY, xgi_video_info.CommandReg); \
+ MMIO_OUT32(xgi_video_info.mmio_vbase, FIRE_TRIGGER, 0); \
+ xgiCmdQueLen -= 2;
+
+#define XGI310SetupX0Y0(x,y) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_X0, (y)<<16 | (x) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupX1Y1(x,y) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_X1, (y)<<16 | (x) );\
+ xgiCmdQueLen--;
+
+#define XGI310SetupLineCount(c) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, LINE_COUNT, c);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupStylePeriod(p) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT16(xgi_video_info.mmio_vbase, LINE_STYLE_PERIOD, p);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupStyleLow(ls) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_STYLE_0, ls);\
+ xgiCmdQueLen--;
+
+#define XGI310SetupStyleHigh(ls) \
+ if (xgiCmdQueLen <= 0) XGI310Idle;\
+ MMIO_OUT32(xgi_video_info.mmio_vbase, LINE_STYLE_1, ls);\
+ xgiCmdQueLen--;
+
+int XGIfb_initaccel(void);
+void XGIfb_syncaccel(void);
+
+extern struct video_info xgi_video_info;
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
+void fbcon_XGI_bmove(struct display *p, int srcy, int srcx, int dsty,
+ int dstx, int height, int width);
+void fbcon_XGI_revc(struct display *p, int srcy, int srcx);
+void fbcon_XGI_clear8(struct vc_data *conp, struct display *p, int srcy,
+ int srcx, int height, int width);
+void fbcon_XGI_clear16(struct vc_data *conp, struct display *p, int srcy,
+ int srcx, int height, int width);
+void fbcon_XGI_clear32(struct vc_data *conp, struct display *p, int srcy,
+ int srcx, int height, int width);
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
+extern int XGIfb_accel;
+void fbcon_XGI_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+void fbcon_XGI_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+#endif
+
+#endif
diff --git a/drivers/staging/xgifb/XGI_main.h b/drivers/staging/xgifb/XGI_main.h
new file mode 100644
index 000000000000..4f4171e8a68a
--- /dev/null
+++ b/drivers/staging/xgifb/XGI_main.h
@@ -0,0 +1,1023 @@
+#ifndef _XGIFB_MAIN
+#define _XGIFB_MAIN
+
+
+/* ------------------- Constant Definitions ------------------------- */
+
+
+#include "XGIfb.h"
+#include "vb_struct.h"
+#include "vb_def.h"
+
+//#define LINUXBIOS /* turn this on when compiling for LINUXBIOS */
+#define AGPOFF /* default is turn off AGP */
+
+#define XGIFAIL(x) do { printk(x "\n"); return -EINVAL; } while(0)
+
+#define VER_MAJOR 0
+#define VER_MINOR 8
+#define VER_LEVEL 1
+
+#define DRIVER_DESC "XGI Volari Frame Buffer Module Version 0.8.1"
+
+#ifndef PCI_VENDOR_ID_XG
+#define PCI_VENDOR_ID_XG 0x18CA
+#endif
+
+#ifndef PCI_DEVICE_ID_XG_40
+#define PCI_DEVICE_ID_XG_40 0x040
+#endif
+#ifndef PCI_DEVICE_ID_XG_41
+#define PCI_DEVICE_ID_XG_41 0x041
+#endif
+#ifndef PCI_DEVICE_ID_XG_42
+#define PCI_DEVICE_ID_XG_42 0x042
+#endif
+#ifndef PCI_DEVICE_ID_XG_20
+#define PCI_DEVICE_ID_XG_20 0x020
+#endif
+#ifndef PCI_DEVICE_ID_XG_27
+#define PCI_DEVICE_ID_XG_27 0x027
+#endif
+
+
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#define XGI_IOTYPE1 void __iomem
+#define XGI_IOTYPE2 __iomem
+#define XGIINITSTATIC static
+#else
+#define XGI_IOTYPE1 unsigned char
+#define XGI_IOTYPE2
+#define XGIINITSTATIC
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static struct pci_device_id __devinitdata xgifb_pci_table[] = {
+
+ { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_27, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_40, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_XG, PCI_DEVICE_ID_XG_42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, xgifb_pci_table);
+#endif
+/* To be included in fb.h */
+#ifndef FB_ACCEL_XGI_GLAMOUR_2
+#define FB_ACCEL_XGI_GLAMOUR_2 40 /* XGI 315, 650, 740 */
+#endif
+#ifndef FB_ACCEL_XGI_XABRE
+#define FB_ACCEL_XGI_XABRE 41 /* XGI 330 ("Xabre") */
+#endif
+
+#define MAX_ROM_SCAN 0x10000
+
+#define HW_CURSOR_CAP 0x80
+#define TURBO_QUEUE_CAP 0x40
+#define AGP_CMD_QUEUE_CAP 0x20
+#define VM_CMD_QUEUE_CAP 0x10
+#define MMIO_CMD_QUEUE_CAP 0x08
+
+
+
+/* For 315 series */
+
+#define COMMAND_QUEUE_AREA_SIZE 0x80000 /* 512K */
+#define COMMAND_QUEUE_THRESHOLD 0x1F
+
+
+/* TW */
+#define HW_CURSOR_AREA_SIZE_315 0x4000 /* 16K */
+#define HW_CURSOR_AREA_SIZE_300 0x1000 /* 4K */
+
+#define OH_ALLOC_SIZE 4000
+#define SENTINEL 0x7fffffff
+
+#define SEQ_ADR 0x14
+#define SEQ_DATA 0x15
+#define DAC_ADR 0x18
+#define DAC_DATA 0x19
+#define CRTC_ADR 0x24
+#define CRTC_DATA 0x25
+#define DAC2_ADR (0x16-0x30)
+#define DAC2_DATA (0x17-0x30)
+#define VB_PART1_ADR (0x04-0x30)
+#define VB_PART1_DATA (0x05-0x30)
+#define VB_PART2_ADR (0x10-0x30)
+#define VB_PART2_DATA (0x11-0x30)
+#define VB_PART3_ADR (0x12-0x30)
+#define VB_PART3_DATA (0x13-0x30)
+#define VB_PART4_ADR (0x14-0x30)
+#define VB_PART4_DATA (0x15-0x30)
+
+#define XGISR XGI_Pr.P3c4
+#define XGICR XGI_Pr.P3d4
+#define XGIDACA XGI_Pr.P3c8
+#define XGIDACD XGI_Pr.P3c9
+#define XGIPART1 XGI_Pr.Part1Port
+#define XGIPART2 XGI_Pr.Part2Port
+#define XGIPART3 XGI_Pr.Part3Port
+#define XGIPART4 XGI_Pr.Part4Port
+#define XGIPART5 XGI_Pr.Part5Port
+#define XGIDAC2A XGIPART5
+#define XGIDAC2D (XGIPART5 + 1)
+#define XGIMISCR (XGI_Pr.RelIO + 0x1c)
+#define XGIINPSTAT (XGI_Pr.RelIO + 0x2a)
+
+#define IND_XGI_PASSWORD 0x05 /* SRs */
+#define IND_XGI_COLOR_MODE 0x06
+#define IND_XGI_RAMDAC_CONTROL 0x07
+#define IND_XGI_DRAM_SIZE 0x14
+#define IND_XGI_SCRATCH_REG_16 0x16
+#define IND_XGI_SCRATCH_REG_17 0x17
+#define IND_XGI_SCRATCH_REG_1A 0x1A
+#define IND_XGI_MODULE_ENABLE 0x1E
+#define IND_XGI_PCI_ADDRESS_SET 0x20
+#define IND_XGI_TURBOQUEUE_ADR 0x26
+#define IND_XGI_TURBOQUEUE_SET 0x27
+#define IND_XGI_POWER_ON_TRAP 0x38
+#define IND_XGI_POWER_ON_TRAP2 0x39
+#define IND_XGI_CMDQUEUE_SET 0x26
+#define IND_XGI_CMDQUEUE_THRESHOLD 0x27
+
+#define IND_XGI_SCRATCH_REG_CR30 0x30 /* CRs */
+#define IND_XGI_SCRATCH_REG_CR31 0x31
+#define IND_XGI_SCRATCH_REG_CR32 0x32
+#define IND_XGI_SCRATCH_REG_CR33 0x33
+#define IND_XGI_LCD_PANEL 0x36
+#define IND_XGI_SCRATCH_REG_CR37 0x37
+#define IND_XGI_AGP_IO_PAD 0x48
+
+#define IND_BRI_DRAM_STATUS 0x63 /* PCI config memory size offset */
+
+#define MMIO_QUEUE_PHYBASE 0x85C0
+#define MMIO_QUEUE_WRITEPORT 0x85C4
+#define MMIO_QUEUE_READPORT 0x85C8
+
+#define IND_XGI_CRT2_WRITE_ENABLE_300 0x24
+#define IND_XGI_CRT2_WRITE_ENABLE_315 0x2F
+
+#define XGI_PASSWORD 0x86 /* SR05 */
+#define XGI_INTERLACED_MODE 0x20 /* SR06 */
+#define XGI_8BPP_COLOR_MODE 0x0
+#define XGI_15BPP_COLOR_MODE 0x1
+#define XGI_16BPP_COLOR_MODE 0x2
+#define XGI_32BPP_COLOR_MODE 0x4
+
+#define XGI_DRAM_SIZE_MASK 0xF0 /*SR14 */
+#define XGI_DRAM_SIZE_1MB 0x00
+#define XGI_DRAM_SIZE_2MB 0x01
+#define XGI_DRAM_SIZE_4MB 0x02
+#define XGI_DRAM_SIZE_8MB 0x03
+#define XGI_DRAM_SIZE_16MB 0x04
+#define XGI_DRAM_SIZE_32MB 0x05
+#define XGI_DRAM_SIZE_64MB 0x06
+#define XGI_DRAM_SIZE_128MB 0x07
+#define XGI_DRAM_SIZE_256MB 0x08
+#define XGI_DATA_BUS_MASK 0x02
+#define XGI_DATA_BUS_64 0x00
+#define XGI_DATA_BUS_128 0x01
+#define XGI_DUAL_CHANNEL_MASK 0x0C
+#define XGI_SINGLE_CHANNEL_1_RANK 0x0
+#define XGI_SINGLE_CHANNEL_2_RANK 0x1
+#define XGI_ASYM_DDR 0x02
+#define XGI_DUAL_CHANNEL_1_RANK 0x3
+
+#define XGI550_DRAM_SIZE_MASK 0x3F /* 550/650/740 SR14 */
+#define XGI550_DRAM_SIZE_4MB 0x00
+#define XGI550_DRAM_SIZE_8MB 0x01
+#define XGI550_DRAM_SIZE_16MB 0x03
+#define XGI550_DRAM_SIZE_24MB 0x05
+#define XGI550_DRAM_SIZE_32MB 0x07
+#define XGI550_DRAM_SIZE_64MB 0x0F
+#define XGI550_DRAM_SIZE_96MB 0x17
+#define XGI550_DRAM_SIZE_128MB 0x1F
+#define XGI550_DRAM_SIZE_256MB 0x3F
+
+#define XGI_SCRATCH_REG_1A_MASK 0x10
+
+#define XGI_ENABLE_2D 0x40 /* SR1E */
+
+#define XGI_MEM_MAP_IO_ENABLE 0x01 /* SR20 */
+#define XGI_PCI_ADDR_ENABLE 0x80
+
+#define XGI_AGP_CMDQUEUE_ENABLE 0x80 /* 315/650/740 SR26 */
+#define XGI_VRAM_CMDQUEUE_ENABLE 0x40
+#define XGI_MMIO_CMD_ENABLE 0x20
+#define XGI_CMD_QUEUE_SIZE_512k 0x00
+#define XGI_CMD_QUEUE_SIZE_1M 0x04
+#define XGI_CMD_QUEUE_SIZE_2M 0x08
+#define XGI_CMD_QUEUE_SIZE_4M 0x0C
+#define XGI_CMD_QUEUE_RESET 0x01
+#define XGI_CMD_AUTO_CORR 0x02
+
+#define XGI_SIMULTANEOUS_VIEW_ENABLE 0x01 /* CR30 */
+#define XGI_MODE_SELECT_CRT2 0x02
+#define XGI_VB_OUTPUT_COMPOSITE 0x04
+#define XGI_VB_OUTPUT_SVIDEO 0x08
+#define XGI_VB_OUTPUT_SCART 0x10
+#define XGI_VB_OUTPUT_LCD 0x20
+#define XGI_VB_OUTPUT_CRT2 0x40
+#define XGI_VB_OUTPUT_HIVISION 0x80
+
+#define XGI_VB_OUTPUT_DISABLE 0x20 /* CR31 */
+#define XGI_DRIVER_MODE 0x40
+
+#define XGI_VB_COMPOSITE 0x01 /* CR32 */
+#define XGI_VB_SVIDEO 0x02
+#define XGI_VB_SCART 0x04
+#define XGI_VB_LCD 0x08
+#define XGI_VB_CRT2 0x10
+#define XGI_CRT1 0x20
+#define XGI_VB_HIVISION 0x40
+#define XGI_VB_YPBPR 0x80
+#define XGI_VB_TV (XGI_VB_COMPOSITE | XGI_VB_SVIDEO | \
+ XGI_VB_SCART | XGI_VB_HIVISION|XGI_VB_YPBPR)
+
+#define XGI_EXTERNAL_CHIP_MASK 0x0E /* CR37 */
+#define XGI_EXTERNAL_CHIP_XGI301 0x01 /* in CR37 << 1 ! */
+#define XGI_EXTERNAL_CHIP_LVDS 0x02 /* in CR37 << 1 ! */
+#define XGI_EXTERNAL_CHIP_TRUMPION 0x03 /* in CR37 << 1 ! */
+#define XGI_EXTERNAL_CHIP_LVDS_CHRONTEL 0x04 /* in CR37 << 1 ! */
+#define XGI_EXTERNAL_CHIP_CHRONTEL 0x05 /* in CR37 << 1 ! */
+#define XGI310_EXTERNAL_CHIP_LVDS 0x02 /* in CR37 << 1 ! */
+#define XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL 0x03 /* in CR37 << 1 ! */
+
+#define XGI_AGP_2X 0x20 /* CR48 */
+
+#define BRI_DRAM_SIZE_MASK 0x70 /* PCI bridge config data */
+#define BRI_DRAM_SIZE_2MB 0x00
+#define BRI_DRAM_SIZE_4MB 0x01
+#define BRI_DRAM_SIZE_8MB 0x02
+#define BRI_DRAM_SIZE_16MB 0x03
+#define BRI_DRAM_SIZE_32MB 0x04
+#define BRI_DRAM_SIZE_64MB 0x05
+
+#define HW_DEVICE_EXTENSION XGI_HW_DEVICE_INFO
+#define PHW_DEVICE_EXTENSION PXGI_HW_DEVICE_INFO
+
+#define SR_BUFFER_SIZE 5
+#define CR_BUFFER_SIZE 5
+
+/* Useful macros */
+#define inXGIREG(base) inb(base)
+#define outXGIREG(base,val) outb(val,base)
+#define orXGIREG(base,val) do { \
+ unsigned char __Temp = inb(base); \
+ outXGIREG(base, __Temp | (val)); \
+ } while (0)
+#define andXGIREG(base,val) do { \
+ unsigned char __Temp = inb(base); \
+ outXGIREG(base, __Temp & (val)); \
+ } while (0)
+#define inXGIIDXREG(base,idx,var) do { \
+ outb(idx,base); var=inb((base)+1); \
+ } while (0)
+#define outXGIIDXREG(base,idx,val) do { \
+ outb(idx,base); outb((val),(base)+1); \
+ } while (0)
+#define orXGIIDXREG(base,idx,val) do { \
+ unsigned char __Temp; \
+ outb(idx,base); \
+ __Temp = inb((base)+1)|(val); \
+ outXGIIDXREG(base,idx,__Temp); \
+ } while (0)
+#define andXGIIDXREG(base,idx,and) do { \
+ unsigned char __Temp; \
+ outb(idx,base); \
+ __Temp = inb((base)+1)&(and); \
+ outXGIIDXREG(base,idx,__Temp); \
+ } while (0)
+#define setXGIIDXREG(base,idx,and,or) do { \
+ unsigned char __Temp; \
+ outb(idx,base); \
+ __Temp = (inb((base)+1)&(and))|(or); \
+ outXGIIDXREG(base,idx,__Temp); \
+ } while (0)
+
+/* ------------------- Global Variables ----------------------------- */
+
+/* Fbcon variables */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static struct fb_info* fb_info;
+#else
+static struct fb_info XGI_fb_info;
+#endif
+
+
+static int video_type = FB_TYPE_PACKED_PIXELS;
+
+static struct fb_var_screeninfo default_var = {
+ .xres = 0,
+ .yres = 0,
+ .xres_virtual = 0,
+ .yres_virtual = 0,
+ .xoffset = 0,
+ .yoffset = 0,
+ .bits_per_pixel = 0,
+ .grayscale = 0,
+ .red = {0, 8, 0},
+ .green = {0, 8, 0},
+ .blue = {0, 8, 0},
+ .transp = {0, 0, 0},
+ .nonstd = 0,
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .accel_flags = 0,
+ .pixclock = 0,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .hsync_len = 0,
+ .vsync_len = 0,
+ .sync = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ .reserved = {0, 0, 0, 0, 0, 0}
+#endif
+};
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static struct fb_fix_screeninfo XGIfb_fix = {
+ .id = "XGI",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .xpanstep = 1,
+ .ypanstep = 1,
+};
+static char myid[20];
+static u32 pseudo_palette[17];
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static struct display XGI_disp;
+
+static struct display_switch XGIfb_sw;
+
+static struct {
+ u16 blue, green, red, pad;
+} XGI_palette[256];
+
+static union {
+#ifdef FBCON_HAS_CFB16
+ u16 cfb16[16];
+#endif
+#ifdef FBCON_HAS_CFB32
+ u32 cfb32[16];
+#endif
+} XGI_fbcon_cmap;
+
+static int XGIfb_inverse = 0;
+#endif
+
+/* display status */
+static int XGIfb_off = 0;
+static int XGIfb_crt1off = 0;
+static int XGIfb_forcecrt1 = -1;
+static int XGIvga_enabled = 0;
+static int XGIfb_userom = 0;
+//static int XGIfb_useoem = -1;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static int currcon = 0;
+#endif
+
+/* global flags */
+static int XGIfb_registered;
+static int XGIfb_tvmode = 0;
+static int XGIfb_mem = 0;
+static int XGIfb_pdc = 0;
+static int enable_dstn = 0;
+static int XGIfb_ypan = -1;
+
+
+int XGIfb_accel = 0;
+
+
+static int XGIfb_hwcursor_size = 0;
+static int XGIfb_CRT2_write_enable = 0;
+
+int XGIfb_crt2type = -1; /* TW: CRT2 type (for overriding autodetection) */
+int XGIfb_tvplug = -1; /* PR: Tv plug type (for overriding autodetection) */
+
+int XGIfb_queuemode = -1; /* TW: Use MMIO queue mode by default (310/325 series only) */
+
+unsigned char XGIfb_detectedpdc = 0;
+
+unsigned char XGIfb_detectedlcda = 0xff;
+
+
+
+
+/* TW: For ioctl XGIFB_GET_INFO */
+/* XGIfb_info XGIfbinfo; */
+
+/* TW: Hardware extension; contains data on hardware */
+HW_DEVICE_EXTENSION XGIhw_ext;
+
+/* TW: XGI private structure */
+VB_DEVICE_INFO XGI_Pr;
+
+/* card parameters */
+static unsigned long XGIfb_mmio_size = 0;
+static u8 XGIfb_caps = 0;
+
+typedef enum _XGI_CMDTYPE {
+ MMIO_CMD = 0,
+ AGP_CMD_QUEUE,
+ VM_CMD_QUEUE,
+} XGI_CMDTYPE;
+
+#define MD_XGI300 1
+#define MD_XGI315 2
+
+/* mode table */
+/* NOT const - will be patched for 1280x960 mode number chaos reasons */
+struct _XGIbios_mode {
+ char name[15];
+ u8 mode_no;
+ u16 vesa_mode_no_1; /* "XGI defined" VESA mode number */
+ u16 vesa_mode_no_2; /* Real VESA mode numbers */
+ u16 xres;
+ u16 yres;
+ u16 bpp;
+ u16 rate_idx;
+ u16 cols;
+ u16 rows;
+ u8 chipset;
+} XGIbios_mode[] = {
+#define MODE_INDEX_NONE 0 /* TW: index for mode=none */
+ {"none", 0xFF, 0x0000, 0x0000, 0, 0, 0, 0, 0, 0, MD_XGI300|MD_XGI315}, /* TW: for mode "none" */
+ {"320x240x16", 0x56, 0x0000, 0x0000, 320, 240, 16, 1, 40, 15, MD_XGI315},
+ {"320x480x8", 0x5A, 0x0000, 0x0000, 320, 480, 8, 1, 40, 30, MD_XGI315}, /* TW: FSTN */
+ {"320x480x16", 0x5B, 0x0000, 0x0000, 320, 480, 16, 1, 40, 30, MD_XGI315}, /* TW: FSTN */
+ {"640x480x8", 0x2E, 0x0101, 0x0101, 640, 480, 8, 1, 80, 30, MD_XGI300|MD_XGI315},
+ {"640x480x16", 0x44, 0x0111, 0x0111, 640, 480, 16, 1, 80, 30, MD_XGI300|MD_XGI315},
+ {"640x480x24", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_XGI300|MD_XGI315}, /* TW: That's for people who mix up color- and fb depth */
+ {"640x480x32", 0x62, 0x013a, 0x0112, 640, 480, 32, 1, 80, 30, MD_XGI300|MD_XGI315},
+ {"720x480x8", 0x31, 0x0000, 0x0000, 720, 480, 8, 1, 90, 30, MD_XGI300|MD_XGI315},
+ {"720x480x16", 0x33, 0x0000, 0x0000, 720, 480, 16, 1, 90, 30, MD_XGI300|MD_XGI315},
+ {"720x480x24", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_XGI300|MD_XGI315},
+ {"720x480x32", 0x35, 0x0000, 0x0000, 720, 480, 32, 1, 90, 30, MD_XGI300|MD_XGI315},
+ {"720x576x8", 0x32, 0x0000, 0x0000, 720, 576, 8, 1, 90, 36, MD_XGI300|MD_XGI315},
+ {"720x576x16", 0x34, 0x0000, 0x0000, 720, 576, 16, 1, 90, 36, MD_XGI300|MD_XGI315},
+ {"720x576x24", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_XGI300|MD_XGI315},
+ {"720x576x32", 0x36, 0x0000, 0x0000, 720, 576, 32, 1, 90, 36, MD_XGI300|MD_XGI315},
+ {"800x480x8", 0x70, 0x0000, 0x0000, 800, 480, 8, 1, 100, 30, MD_XGI300|MD_XGI315},
+ {"800x480x16", 0x7a, 0x0000, 0x0000, 800, 480, 16, 1, 100, 30, MD_XGI300|MD_XGI315},
+ {"800x480x24", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_XGI300|MD_XGI315},
+ {"800x480x32", 0x76, 0x0000, 0x0000, 800, 480, 32, 1, 100, 30, MD_XGI300|MD_XGI315},
+#define DEFAULT_MODE 21 /* TW: index for 800x600x8 */
+#define DEFAULT_LCDMODE 21 /* TW: index for 800x600x8 */
+#define DEFAULT_TVMODE 21 /* TW: index for 800x600x8 */
+ {"800x600x8", 0x30, 0x0103, 0x0103, 800, 600, 8, 1, 100, 37, MD_XGI300|MD_XGI315},
+ {"800x600x16", 0x47, 0x0114, 0x0114, 800, 600, 16, 1, 100, 37, MD_XGI300|MD_XGI315},
+ {"800x600x24", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, MD_XGI300|MD_XGI315},
+ {"800x600x32", 0x63, 0x013b, 0x0115, 800, 600, 32, 1, 100, 37, MD_XGI300|MD_XGI315},
+ {"1024x576x8", 0x71, 0x0000, 0x0000, 1024, 576, 8, 1, 128, 36, MD_XGI300|MD_XGI315},
+ {"1024x576x16", 0x74, 0x0000, 0x0000, 1024, 576, 16, 1, 128, 36, MD_XGI300|MD_XGI315},
+ {"1024x576x24", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_XGI300|MD_XGI315},
+ {"1024x576x32", 0x77, 0x0000, 0x0000, 1024, 576, 32, 1, 128, 36, MD_XGI300|MD_XGI315},
+ {"1024x600x8", 0x20, 0x0000, 0x0000, 1024, 600, 8, 1, 128, 37, MD_XGI300 }, /* TW: 300 series only */
+ {"1024x600x16", 0x21, 0x0000, 0x0000, 1024, 600, 16, 1, 128, 37, MD_XGI300 },
+ {"1024x600x24", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_XGI300 },
+ {"1024x600x32", 0x22, 0x0000, 0x0000, 1024, 600, 32, 1, 128, 37, MD_XGI300 },
+ {"1024x768x8", 0x38, 0x0105, 0x0105, 1024, 768, 8, 1, 128, 48, MD_XGI300|MD_XGI315},
+ {"1024x768x16", 0x4A, 0x0117, 0x0117, 1024, 768, 16, 1, 128, 48, MD_XGI300|MD_XGI315},
+ {"1024x768x24", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, MD_XGI300|MD_XGI315},
+ {"1024x768x32", 0x64, 0x013c, 0x0118, 1024, 768, 32, 1, 128, 48, MD_XGI300|MD_XGI315},
+ {"1152x768x8", 0x23, 0x0000, 0x0000, 1152, 768, 8, 1, 144, 48, MD_XGI300 }, /* TW: 300 series only */
+ {"1152x768x16", 0x24, 0x0000, 0x0000, 1152, 768, 16, 1, 144, 48, MD_XGI300 },
+ {"1152x768x24", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_XGI300 },
+ {"1152x768x32", 0x25, 0x0000, 0x0000, 1152, 768, 32, 1, 144, 48, MD_XGI300 },
+ {"1280x720x8", 0x79, 0x0000, 0x0000, 1280, 720, 8, 1, 160, 45, MD_XGI300|MD_XGI315},
+ {"1280x720x16", 0x75, 0x0000, 0x0000, 1280, 720, 16, 1, 160, 45, MD_XGI300|MD_XGI315},
+ {"1280x720x24", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_XGI300|MD_XGI315},
+ {"1280x720x32", 0x78, 0x0000, 0x0000, 1280, 720, 32, 1, 160, 45, MD_XGI300|MD_XGI315},
+ {"1280x768x8", 0x23, 0x0000, 0x0000, 1280, 768, 8, 1, 160, 48, MD_XGI315}, /* TW: 310/325 series only */
+ {"1280x768x16", 0x24, 0x0000, 0x0000, 1280, 768, 16, 1, 160, 48, MD_XGI315},
+ {"1280x768x24", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_XGI315},
+ {"1280x768x32", 0x25, 0x0000, 0x0000, 1280, 768, 32, 1, 160, 48, MD_XGI315},
+#define MODEINDEX_1280x960 48
+ {"1280x960x8", 0x7C, 0x0000, 0x0000, 1280, 960, 8, 1, 160, 60, MD_XGI300|MD_XGI315}, /* TW: Modenumbers being patched */
+ {"1280x960x16", 0x7D, 0x0000, 0x0000, 1280, 960, 16, 1, 160, 60, MD_XGI300|MD_XGI315},
+ {"1280x960x24", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_XGI300|MD_XGI315},
+ {"1280x960x32", 0x7E, 0x0000, 0x0000, 1280, 960, 32, 1, 160, 60, MD_XGI300|MD_XGI315},
+ {"1280x1024x8", 0x3A, 0x0107, 0x0107, 1280, 1024, 8, 1, 160, 64, MD_XGI300|MD_XGI315},
+ {"1280x1024x16", 0x4D, 0x011a, 0x011a, 1280, 1024, 16, 1, 160, 64, MD_XGI300|MD_XGI315},
+ {"1280x1024x24", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, MD_XGI300|MD_XGI315},
+ {"1280x1024x32", 0x65, 0x013d, 0x011b, 1280, 1024, 32, 1, 160, 64, MD_XGI300|MD_XGI315},
+ {"1400x1050x8", 0x26, 0x0000, 0x0000, 1400, 1050, 8, 1, 175, 65, MD_XGI315}, /* TW: 310/325 series only */
+ {"1400x1050x16", 0x27, 0x0000, 0x0000, 1400, 1050, 16, 1, 175, 65, MD_XGI315},
+ {"1400x1050x24", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_XGI315},
+ {"1400x1050x32", 0x28, 0x0000, 0x0000, 1400, 1050, 32, 1, 175, 65, MD_XGI315},
+ {"1600x1200x8", 0x3C, 0x0130, 0x011c, 1600, 1200, 8, 1, 200, 75, MD_XGI300|MD_XGI315},
+ {"1600x1200x16", 0x3D, 0x0131, 0x011e, 1600, 1200, 16, 1, 200, 75, MD_XGI300|MD_XGI315},
+ {"1600x1200x24", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_XGI300|MD_XGI315},
+ {"1600x1200x32", 0x66, 0x013e, 0x011f, 1600, 1200, 32, 1, 200, 75, MD_XGI300|MD_XGI315},
+ {"1920x1440x8", 0x68, 0x013f, 0x0000, 1920, 1440, 8, 1, 240, 75, MD_XGI300|MD_XGI315},
+ {"1920x1440x16", 0x69, 0x0140, 0x0000, 1920, 1440, 16, 1, 240, 75, MD_XGI300|MD_XGI315},
+ {"1920x1440x24", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_XGI300|MD_XGI315},
+ {"1920x1440x32", 0x6B, 0x0141, 0x0000, 1920, 1440, 32, 1, 240, 75, MD_XGI300|MD_XGI315},
+ {"2048x1536x8", 0x6c, 0x0000, 0x0000, 2048, 1536, 8, 1, 256, 96, MD_XGI315}, /* TW: 310/325 series only */
+ {"2048x1536x16", 0x6d, 0x0000, 0x0000, 2048, 1536, 16, 1, 256, 96, MD_XGI315},
+ {"2048x1536x24", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_XGI315},
+ {"2048x1536x32", 0x6e, 0x0000, 0x0000, 2048, 1536, 32, 1, 256, 96, MD_XGI315},
+ {"\0", 0x00, 0, 0, 0, 0, 0, 0, 0}
+};
+
+/* mode-related variables */
+#ifdef MODULE
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int xgifb_mode_idx = 1;
+#else
+static int XGIfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */
+#endif
+#else
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int xgifb_mode_idx = -1; /* Use a default mode if we are inside the kernel */
+#else
+static int XGIfb_mode_idx = -1;
+#endif
+#endif
+u8 XGIfb_mode_no = 0;
+u8 XGIfb_rate_idx = 0;
+
+/* TW: CR36 evaluation */
+const USHORT XGI300paneltype[] =
+ { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
+ LCD_1280x960, LCD_640x480, LCD_1024x600, LCD_1152x768,
+ LCD_1024x768, LCD_1024x768, LCD_1024x768,
+ LCD_1024x768, LCD_1024x768, LCD_1024x768, LCD_1024x768 };
+
+const USHORT XGI310paneltype[] =
+ { LCD_UNKNOWN, LCD_800x600, LCD_1024x768, LCD_1280x1024,
+ LCD_640x480, LCD_1024x600, LCD_1152x864, LCD_1280x960,
+ LCD_1152x768, LCD_1400x1050,LCD_1280x768, LCD_1600x1200,
+ LCD_1024x768, LCD_1024x768, LCD_1024x768 };
+
+static const struct _XGI_crt2type {
+ char name[10];
+ int type_no;
+ int tvplug_no;
+} XGI_crt2type[] = {
+ {"NONE", 0, -1},
+ {"LCD", DISPTYPE_LCD, -1},
+ {"TV", DISPTYPE_TV, -1},
+ {"VGA", DISPTYPE_CRT2, -1},
+ {"SVIDEO", DISPTYPE_TV, TVPLUG_SVIDEO},
+ {"COMPOSITE", DISPTYPE_TV, TVPLUG_COMPOSITE},
+ {"SCART", DISPTYPE_TV, TVPLUG_SCART},
+ {"none", 0, -1},
+ {"lcd", DISPTYPE_LCD, -1},
+ {"tv", DISPTYPE_TV, -1},
+ {"vga", DISPTYPE_CRT2, -1},
+ {"svideo", DISPTYPE_TV, TVPLUG_SVIDEO},
+ {"composite", DISPTYPE_TV, TVPLUG_COMPOSITE},
+ {"scart", DISPTYPE_TV, TVPLUG_SCART},
+ {"\0", -1, -1}
+};
+
+/* Queue mode selection for 310 series */
+static const struct _XGI_queuemode {
+ char name[6];
+ int type_no;
+} XGI_queuemode[] = {
+ {"AGP", AGP_CMD_QUEUE},
+ {"VRAM", VM_CMD_QUEUE},
+ {"MMIO", MMIO_CMD},
+ {"agp", AGP_CMD_QUEUE},
+ {"vram", VM_CMD_QUEUE},
+ {"mmio", MMIO_CMD},
+ {"\0", -1}
+};
+
+/* TV standard */
+static const struct _XGI_tvtype {
+ char name[6];
+ int type_no;
+} XGI_tvtype[] = {
+ {"PAL", 1},
+ {"NTSC", 2},
+ {"pal", 1},
+ {"ntsc", 2},
+ {"\0", -1}
+};
+
+static const struct _XGI_vrate {
+ u16 idx;
+ u16 xres;
+ u16 yres;
+ u16 refresh;
+} XGIfb_vrate[] = {
+ {1, 640, 480, 60}, {2, 640, 480, 72}, {3, 640, 480, 75}, {4, 640, 480, 85},
+ {5, 640, 480,100}, {6, 640, 480, 120}, {7, 640, 480, 160}, {8, 640, 480, 200},
+ {1, 720, 480, 60},
+ {1, 720, 576, 58},
+ {1, 800, 480, 60}, {2, 800, 480, 75}, {3, 800, 480, 85},
+ {1, 800, 600, 60}, {2, 800, 600, 72}, {3, 800, 600, 75},
+ {4, 800, 600, 85}, {5, 800, 600, 100}, {6, 800, 600, 120}, {7, 800, 600, 160},
+ {1, 1024, 768, 60}, {2, 1024, 768, 70}, {3, 1024, 768, 75},
+ {4, 1024, 768, 85}, {5, 1024, 768, 100}, {6, 1024, 768, 120},
+ {1, 1024, 576, 60}, {2, 1024, 576, 75}, {3, 1024, 576, 85},
+ {1, 1024, 600, 60},
+ {1, 1152, 768, 60},
+ {1, 1280, 720, 60}, {2, 1280, 720, 75}, {3, 1280, 720, 85},
+ {1, 1280, 768, 60},
+ {1, 1280, 1024, 60}, {2, 1280, 1024, 75}, {3, 1280, 1024, 85},
+ {1, 1280, 960, 70},
+ {1, 1400, 1050, 60},
+ {1, 1600, 1200, 60}, {2, 1600, 1200, 65}, {3, 1600, 1200, 70}, {4, 1600, 1200, 75},
+ {5, 1600, 1200, 85}, {6, 1600, 1200, 100}, {7, 1600, 1200, 120},
+ {1, 1920, 1440, 60}, {2, 1920, 1440, 65}, {3, 1920, 1440, 70}, {4, 1920, 1440, 75},
+ {5, 1920, 1440, 85}, {6, 1920, 1440, 100},
+ {1, 2048, 1536, 60}, {2, 2048, 1536, 65}, {3, 2048, 1536, 70}, {4, 2048, 1536, 75},
+ {5, 2048, 1536, 85},
+ {0, 0, 0, 0}
+};
+
+static const struct _chswtable {
+ int subsysVendor;
+ int subsysCard;
+ char *vendorName;
+ char *cardName;
+} mychswtable[] = {
+ { 0x1631, 0x1002, "Mitachi", "0x1002" },
+ { 0, 0, "" , "" }
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/* Offscreen layout */
+typedef struct _XGI_GLYINFO {
+ unsigned char ch;
+ int fontwidth;
+ int fontheight;
+ u8 gmask[72];
+ int ngmask;
+} XGI_GLYINFO;
+#endif
+
+typedef struct _XGI_OH {
+ struct _XGI_OH *poh_next;
+ struct _XGI_OH *poh_prev;
+ unsigned long offset;
+ unsigned long size;
+} XGI_OH;
+
+typedef struct _XGI_OHALLOC {
+ struct _XGI_OHALLOC *poha_next;
+ XGI_OH aoh[1];
+} XGI_OHALLOC;
+
+typedef struct _XGI_HEAP {
+ XGI_OH oh_free;
+ XGI_OH oh_used;
+ XGI_OH *poh_freelist;
+ XGI_OHALLOC *poha_chain;
+ unsigned long max_freesize;
+} XGI_HEAP;
+
+static unsigned long XGIfb_hwcursor_vbase;
+
+static unsigned long XGIfb_heap_start;
+static unsigned long XGIfb_heap_end;
+static unsigned long XGIfb_heap_size;
+static XGI_HEAP XGIfb_heap;
+
+// Eden Chen
+static const struct _XGI_TV_filter {
+ u8 filter[9][4];
+} XGI_TV_filter[] = {
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_0 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_1 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_2 */
+ {0xF5,0xEE,0x1B,0x44},
+ {0xF8,0xF4,0x18,0x38},
+ {0xEB,0x04,0x25,0x18},
+ {0xF1,0x05,0x1F,0x16},
+ {0xF6,0x06,0x1A,0x14},
+ {0xFA,0x06,0x16,0x14},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_3 */
+ {0xF1,0x04,0x1F,0x18},
+ {0xEE,0x0D,0x22,0x06},
+ {0xF7,0x06,0x19,0x14},
+ {0xF4,0x0B,0x1C,0x0A},
+ {0xFA,0x07,0x16,0x12},
+ {0xF9,0x0A,0x17,0x0C},
+ {0x00,0x07,0x10,0x12},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_4 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_5 */
+ {0xF5,0xEE,0x1B,0x44},
+ {0xF8,0xF4,0x18,0x38},
+ {0xEB,0x04,0x25,0x18},
+ {0xF1,0x05,0x1F,0x16},
+ {0xF6,0x06,0x1A,0x14},
+ {0xFA,0x06,0x16,0x14},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_6 */
+ {0xEB,0x04,0x25,0x18},
+ {0xE7,0x0E,0x29,0x04},
+ {0xEE,0x0C,0x22,0x08},
+ {0xF6,0x0B,0x1A,0x0A},
+ {0xF9,0x0A,0x17,0x0C},
+ {0xFC,0x0A,0x14,0x0C},
+ {0x00,0x08,0x10,0x10},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* NTSCFilter_7 */
+ {0xEC,0x02,0x24,0x1C},
+ {0xF2,0x04,0x1E,0x18},
+ {0xEB,0x15,0x25,0xF6},
+ {0xF4,0x10,0x1C,0x00},
+ {0xF8,0x0F,0x18,0x02},
+ {0x00,0x04,0x10,0x18},
+ {0x01,0x06,0x0F,0x14},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_0 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_1 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_2 */
+ {0xF5,0xEE,0x1B,0x44},
+ {0xF8,0xF4,0x18,0x38},
+ {0xF1,0xF7,0x01,0x32},
+ {0xF5,0xFB,0x1B,0x2A},
+ {0xF9,0xFF,0x17,0x22},
+ {0xFB,0x01,0x15,0x1E},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_3 */
+ {0xF5,0xFB,0x1B,0x2A},
+ {0xEE,0xFE,0x22,0x24},
+ {0xF3,0x00,0x1D,0x20},
+ {0xF9,0x03,0x17,0x1A},
+ {0xFB,0x02,0x14,0x1E},
+ {0xFB,0x04,0x15,0x18},
+ {0x00,0x06,0x10,0x14},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_4 */
+ {0x00,0xE0,0x10,0x60},
+ {0x00,0xEE,0x10,0x44},
+ {0x00,0xF4,0x10,0x38},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0x00,0x00,0x10,0x20},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_5 */
+ {0xF5,0xEE,0x1B,0x44},
+ {0xF8,0xF4,0x18,0x38},
+ {0xF1,0xF7,0x1F,0x32},
+ {0xF5,0xFB,0x1B,0x2A},
+ {0xF9,0xFF,0x17,0x22},
+ {0xFB,0x01,0x15,0x1E},
+ {0x00,0x04,0x10,0x18},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_6 */
+ {0xF5,0xEE,0x1B,0x2A},
+ {0xEE,0xFE,0x22,0x24},
+ {0xF3,0x00,0x1D,0x20},
+ {0xF9,0x03,0x17,0x1A},
+ {0xFB,0x02,0x14,0x1E},
+ {0xFB,0x04,0x15,0x18},
+ {0x00,0x06,0x10,0x14},
+ {0xFF,0xFF,0xFF,0xFF} }},
+ { {{0x00,0x00,0x00,0x40}, /* PALFilter_7 */
+ {0xF5,0xEE,0x1B,0x44},
+ {0xF8,0xF4,0x18,0x38},
+ {0xFC,0xFB,0x14,0x2A},
+ {0xEB,0x05,0x25,0x16},
+ {0xF1,0x05,0x1F,0x16},
+ {0xFA,0x07,0x16,0x12},
+ {0x00,0x07,0x10,0x12},
+ {0xFF,0xFF,0xFF,0xFF} }}
+};
+
+static int filter = -1;
+static unsigned char filter_tb;
+
+
+/* ---------------------- Routine prototypes ------------------------- */
+
+/* Interface used by the world */
+#ifndef MODULE
+XGIINITSTATIC int __init XGIfb_setup(char *options);
+#endif
+
+/* Interface to the low level console driver */
+
+
+
+/* fbdev routines */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ int XGIfb_init(void);
+static int XGIfb_get_fix(struct fb_fix_screeninfo *fix,
+ int con,
+ struct fb_info *info);
+static int XGIfb_get_var(struct fb_var_screeninfo *var,
+ int con,
+ struct fb_info *info);
+static int XGIfb_set_var(struct fb_var_screeninfo *var,
+ int con,
+ struct fb_info *info);
+static void XGIfb_crtc_to_var(struct fb_var_screeninfo *var);
+static int XGIfb_get_cmap(struct fb_cmap *cmap,
+ int kspc,
+ int con,
+ struct fb_info *info);
+static int XGIfb_set_cmap(struct fb_cmap *cmap,
+ int kspc,
+ int con,
+ struct fb_info *info);
+static int XGIfb_update_var(int con,
+ struct fb_info *info);
+static int XGIfb_switch(int con,
+ struct fb_info *info);
+static void XGIfb_blank(int blank,
+ struct fb_info *info);
+static void XGIfb_set_disp(int con,
+ struct fb_var_screeninfo *var,
+ struct fb_info *info);
+static int XGI_getcolreg(unsigned regno, unsigned *red, unsigned *green,
+ unsigned *blue, unsigned *transp,
+ struct fb_info *fb_info);
+static void XGIfb_do_install_cmap(int con,
+ struct fb_info *info);
+static void XGI_get_glyph(struct fb_info *info,
+ XGI_GLYINFO *gly);
+static int XGIfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma);
+static int XGIfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg, int con,
+ struct fb_info *info);
+#endif
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+XGIINITSTATIC int __init xgifb_init(void);
+static int XGIfb_set_par(struct fb_info *info);
+static int XGIfb_blank(int blank,
+ struct fb_info *info);
+/*static int XGIfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma);
+*/
+extern void fbcon_XGI_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect);
+extern void fbcon_XGI_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area);
+#if 0
+extern void cfb_imageblit(struct fb_info *info,
+ const struct fb_image *image);
+#endif
+extern int fbcon_XGI_sync(struct fb_info *info);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg);
+#else
+static int XGIfb_ioctl(struct inode *inode,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg,
+ struct fb_info *info);
+#endif
+
+/*
+extern int XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr,
+ PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ unsigned char modeno, unsigned char rateindex);
+extern int XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ unsigned char modeno, unsigned char rateindex,
+ unsigned int *left_margin, unsigned int *right_margin,
+ unsigned int *upper_margin, unsigned int *lower_margin,
+ unsigned int *hsync_len, unsigned int *vsync_len,
+ unsigned int *sync, unsigned int *vmode);
+*/
+#endif
+ extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO );
+static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info);
+
+/* Internal 2D accelerator functions */
+extern int XGIfb_initaccel(void);
+extern void XGIfb_syncaccel(void);
+
+/* Internal general routines */
+static void XGIfb_search_mode(const char *name);
+static int XGIfb_validate_mode(int modeindex);
+static u8 XGIfb_search_refresh_rate(unsigned int rate);
+static int XGIfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *fb_info);
+static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info);
+static void XGIfb_pre_setmode(void);
+static void XGIfb_post_setmode(void);
+
+static BOOLEAN XGIfb_CheckVBRetrace(void);
+static BOOLEAN XGIfbcheckvretracecrt2(void);
+static BOOLEAN XGIfbcheckvretracecrt1(void);
+static BOOLEAN XGIfb_bridgeisslave(void);
+
+struct XGI_memreq {
+ unsigned long offset;
+ unsigned long size;
+};
+
+/* XGI-specific Export functions */
+void XGI_dispinfo(struct ap_data *rec);
+void XGI_malloc(struct XGI_memreq *req);
+void XGI_free(unsigned long base);
+
+/* Internal hardware access routines */
+void XGIfb_set_reg4(u16 port, unsigned long data);
+u32 XGIfb_get_reg3(u16 port);
+
+/* Chipset-dependent internal routines */
+
+
+static int XGIfb_get_dram_size(void);
+static void XGIfb_detect_VB(void);
+static void XGIfb_get_VB_type(void);
+static int XGIfb_has_VB(void);
+
+
+/* Internal heap routines */
+static int XGIfb_heap_init(void);
+static XGI_OH *XGIfb_poh_new_node(void);
+static XGI_OH *XGIfb_poh_allocate(unsigned long size);
+static void XGIfb_delete_node(XGI_OH *poh);
+static void XGIfb_insert_node(XGI_OH *pohList, XGI_OH *poh);
+static XGI_OH *XGIfb_poh_free(unsigned long base);
+static void XGIfb_free_node(XGI_OH *poh);
+
+/* Internal routines to access PCI configuration space */
+BOOLEAN XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+ unsigned long offset, unsigned long set, unsigned long *value);
+//BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+// unsigned long offset, unsigned long set, unsigned long *value);
+
+
+/* Routines from init.c/init301.c */
+extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo);
+extern BOOLEAN XGIInitNew(PXGI_HW_DEVICE_INFO HwDeviceExtension);
+extern BOOLEAN XGISetModeNew(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo);
+//extern void XGI_SetEnableDstn(VB_DEVICE_INFO *XGI_Pr);
+extern void XGI_LongWait(VB_DEVICE_INFO *XGI_Pr);
+extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
+/* TW: Chrontel TV functions */
+extern USHORT XGI_GetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
+extern void XGI_SetCH700x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
+extern USHORT XGI_GetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
+extern void XGI_SetCH701x(VB_DEVICE_INFO *XGI_Pr, USHORT tempbx);
+extern void XGI_SetCH70xxANDOR(VB_DEVICE_INFO *XGI_Pr, USHORT tempax,USHORT tempbh);
+extern void XGI_DDC2Delay(VB_DEVICE_INFO *XGI_Pr, USHORT delaytime);
+
+/* TW: Sensing routines */
+void XGI_Sense30x(void);
+int XGIDoSense(int tempbl, int tempbh, int tempcl, int tempch);
+
+extern XGI21_LVDSCapStruct XGI21_LCDCapList[13];
+#endif
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
new file mode 100644
index 000000000000..867012b48a01
--- /dev/null
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -0,0 +1,3773 @@
+/*
+ * XG20, XG21, XG40, XG42 frame buffer device
+ * for Linux kernels 2.5.x, 2.6.x
+ * Base on TW's sis fbdev code.
+ */
+
+//#include <linux/config.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/console.h>
+#include <linux/selection.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+#include <linux/vt_kern.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/kernel.h>
+
+#include "osdef.h"
+
+
+#ifndef XGIFB_PAN
+#define XGIFB_PAN
+#endif
+
+#include <asm/io.h>
+#ifdef CONFIG_MTRR
+#include <asm/mtrr.h>
+#endif
+
+#include "XGIfb.h"
+#include "vgatypes.h"
+#include "XGI_main.h"
+#include "vb_util.h"
+
+
+#define Index_CR_GPIO_Reg1 0x48
+#define Index_CR_GPIO_Reg2 0x49
+#define Index_CR_GPIO_Reg3 0x4a
+
+#define GPIOG_EN (1<<6)
+#define GPIOG_WRITE (1<<6)
+#define GPIOG_READ (1<<1)
+int XGIfb_GetXG21DefaultLVDSModeIdx(void);
+
+/* -------------------- Macro definitions ---------------------------- */
+
+#undef XGIFBDEBUG
+
+#ifdef XGIFBDEBUG
+#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#ifdef XGIFBDEBUG
+static void dumpVGAReg(void)
+{
+ u8 i,reg;
+
+outXGIIDXREG(XGISR, 0x05, 0x86);
+/*
+outXGIIDXREG(XGISR, 0x08, 0x4f);
+outXGIIDXREG(XGISR, 0x0f, 0x20);
+outXGIIDXREG(XGISR, 0x11, 0x4f);
+outXGIIDXREG(XGISR, 0x13, 0x45);
+outXGIIDXREG(XGISR, 0x14, 0x51);
+outXGIIDXREG(XGISR, 0x1e, 0x41);
+outXGIIDXREG(XGISR, 0x1f, 0x0);
+outXGIIDXREG(XGISR, 0x20, 0xa1);
+outXGIIDXREG(XGISR, 0x22, 0xfb);
+outXGIIDXREG(XGISR, 0x26, 0x22);
+outXGIIDXREG(XGISR, 0x3e, 0x07);
+*/
+
+//outXGIIDXREG(XGICR, 0x19, 0x00);
+//outXGIIDXREG(XGICR, 0x1a, 0x3C);
+//outXGIIDXREG(XGICR, 0x22, 0xff);
+//outXGIIDXREG(XGICR, 0x3D, 0x10);
+
+//outXGIIDXREG(XGICR, 0x4a, 0xf3);
+
+//outXGIIDXREG(XGICR, 0x57, 0x0);
+//outXGIIDXREG(XGICR, 0x7a, 0x2c);
+
+//outXGIIDXREG(XGICR, 0x82, 0xcc);
+//outXGIIDXREG(XGICR, 0x8c, 0x0);
+/*
+outXGIIDXREG(XGICR, 0x99, 0x1);
+outXGIIDXREG(XGICR, 0x41, 0x40);
+*/
+
+ for(i=0; i < 0x4f; i++)
+ {
+ inXGIIDXREG(XGISR, i, reg);
+ printk("\no 3c4 %x",i);
+ printk("\ni 3c5 => %x",reg);
+ }
+
+ for(i=0; i < 0xF0; i++)
+ {
+ inXGIIDXREG(XGICR, i, reg);
+ printk("\no 3d4 %x",i);
+ printk("\ni 3d5 => %x",reg);
+ }
+/*
+
+ outXGIIDXREG(XGIPART1,0x2F,1);
+ for(i=1; i < 0x50; i++)
+ {
+ inXGIIDXREG(XGIPART1, i, reg);
+ printk("\no d004 %x",i);
+ printk("\ni d005 => %x",reg);
+ }
+
+ for(i=0; i < 0x50; i++)
+ {
+ inXGIIDXREG(XGIPART2, i, reg);
+ printk("\no d010 %x",i);
+ printk("\ni d011 => %x",reg);
+ }
+ for(i=0; i < 0x50; i++)
+ {
+ inXGIIDXREG(XGIPART3, i, reg);
+ printk("\no d012 %x",i);
+ printk("\ni d013 => %x",reg);
+ }
+ for(i=0; i < 0x50; i++)
+ {
+ inXGIIDXREG(XGIPART4, i, reg);
+ printk("\no d014 %x",i);
+ printk("\ni d015 => %x",reg);
+ }
+*/
+}
+#else
+static inline void dumpVGAReg(void) {}
+#endif
+
+/* data for XGI components */
+struct video_info xgi_video_info;
+
+
+#if 1
+#define DEBUGPRN(x)
+#else
+#define DEBUGPRN(x) printk(KERN_INFO x "\n");
+#endif
+
+
+/* --------------- Hardware Access Routines -------------------------- */
+
+#ifdef LINUX_KERNEL
+int
+XGIfb_mode_rate_to_dclock(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ unsigned char modeno, unsigned char rateindex)
+{
+ USHORT ModeNo = modeno;
+ USHORT ModeIdIndex = 0, ClockIndex = 0;
+ USHORT RefreshRateTableIndex = 0;
+
+ /*ULONG temp = 0;*/
+ int Clock;
+ XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase;
+ InitTo330Pointer( HwDeviceExtension->jChipType, XGI_Pr ) ;
+
+ RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, XGI_Pr ) ;
+
+/*
+ temp = XGI_SearchModeID( ModeNo , &ModeIdIndex, XGI_Pr ) ;
+ if(!temp) {
+ printk(KERN_ERR "Could not find mode %x\n", ModeNo);
+ return 65000;
+ }
+
+ RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
+ RefreshRateTableIndex += (rateindex - 1);
+
+*/
+ ClockIndex = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRTVCLK;
+ if(HwDeviceExtension->jChipType < XGI_315H) {
+ ClockIndex &= 0x3F;
+ }
+ Clock = XGI_Pr->VCLKData[ClockIndex].CLOCK * 1000 ;
+
+ return(Clock);
+}
+
+int
+XGIfb_mode_rate_to_ddata(VB_DEVICE_INFO *XGI_Pr, PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ unsigned char modeno, unsigned char rateindex,
+ u32 *left_margin, u32 *right_margin,
+ u32 *upper_margin, u32 *lower_margin,
+ u32 *hsync_len, u32 *vsync_len,
+ u32 *sync, u32 *vmode)
+{
+ USHORT ModeNo = modeno;
+ USHORT ModeIdIndex = 0, index = 0;
+ USHORT RefreshRateTableIndex = 0;
+
+ unsigned short VRE, VBE, VRS, VBS, VDE, VT;
+ unsigned short HRE, HBE, HRS, HBS, HDE, HT;
+ unsigned char sr_data, cr_data, cr_data2;
+ unsigned long cr_data3;
+ int A, B, C, D, E, F, temp, j;
+ XGI_Pr->ROMAddr = HwDeviceExtension->pjVirtualRomBase;
+ InitTo330Pointer( HwDeviceExtension->jChipType, XGI_Pr ) ;
+ RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, XGI_Pr ) ;
+/*
+ temp = XGI_SearchModeID( ModeNo, &ModeIdIndex, XGI_Pr);
+ if(!temp) return 0;
+
+ RefreshRateTableIndex = XGI_Pr->EModeIDTable[ModeIdIndex].REFindex;
+ RefreshRateTableIndex += (rateindex - 1);
+*/
+ index = XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_CRT1CRTC;
+
+ sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[5];
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[0];
+
+ /* Horizontal total */
+ HT = (cr_data & 0xff) |
+ ((unsigned short) (sr_data & 0x03) << 8);
+ A = HT + 5;
+
+ /*cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
+
+ Horizontal display enable end
+ HDE = (cr_data & 0xff) |
+ ((unsigned short) (sr_data & 0x0C) << 6);*/
+ HDE = (XGI_Pr->RefIndex[RefreshRateTableIndex].XRes >> 3) -1;
+ E = HDE + 1;
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[3];
+
+ /* Horizontal retrace (=sync) start */
+ HRS = (cr_data & 0xff) |
+ ((unsigned short) (sr_data & 0xC0) << 2);
+ F = HRS - E - 3;
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[1];
+
+ /* Horizontal blank start */
+ HBS = (cr_data & 0xff) |
+ ((unsigned short) (sr_data & 0x30) << 4);
+
+ sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[6];
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[2];
+
+ cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[4];
+
+ /* Horizontal blank end */
+ HBE = (cr_data & 0x1f) |
+ ((unsigned short) (cr_data2 & 0x80) >> 2) |
+ ((unsigned short) (sr_data & 0x03) << 6);
+
+ /* Horizontal retrace (=sync) end */
+ HRE = (cr_data2 & 0x1f) | ((sr_data & 0x04) << 3);
+
+ temp = HBE - ((E - 1) & 255);
+ B = (temp > 0) ? temp : (temp + 256);
+
+ temp = HRE - ((E + F + 3) & 63);
+ C = (temp > 0) ? temp : (temp + 64);
+
+ D = B - F - C;
+
+ *left_margin = D * 8;
+ *right_margin = F * 8;
+ *hsync_len = C * 8;
+
+ sr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[14];
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[8];
+
+ cr_data2 = XGI_Pr->XGINEWUB_CRT1Table[index].CR[9];
+
+ /* Vertical total */
+ VT = (cr_data & 0xFF) |
+ ((unsigned short) (cr_data2 & 0x01) << 8) |
+ ((unsigned short)(cr_data2 & 0x20) << 4) |
+ ((unsigned short) (sr_data & 0x01) << 10);
+ A = VT + 2;
+
+ //cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10];
+
+ /* Vertical display enable end */
+/* VDE = (cr_data & 0xff) |
+ ((unsigned short) (cr_data2 & 0x02) << 7) |
+ ((unsigned short) (cr_data2 & 0x40) << 3) |
+ ((unsigned short) (sr_data & 0x02) << 9); */
+ VDE = XGI_Pr->RefIndex[RefreshRateTableIndex].YRes -1;
+ E = VDE + 1;
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[10];
+
+ /* Vertical retrace (=sync) start */
+ VRS = (cr_data & 0xff) |
+ ((unsigned short) (cr_data2 & 0x04) << 6) |
+ ((unsigned short) (cr_data2 & 0x80) << 2) |
+ ((unsigned short) (sr_data & 0x08) << 7);
+ F = VRS + 1 - E;
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[12];
+
+ cr_data3 = (XGI_Pr->XGINEWUB_CRT1Table[index].CR[14] & 0x80) << 5;
+
+ /* Vertical blank start */
+ VBS = (cr_data & 0xff) |
+ ((unsigned short) (cr_data2 & 0x08) << 5) |
+ ((unsigned short) (cr_data3 & 0x20) << 4) |
+ ((unsigned short) (sr_data & 0x04) << 8);
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[13];
+
+ /* Vertical blank end */
+ VBE = (cr_data & 0xff) |
+ ((unsigned short) (sr_data & 0x10) << 4);
+ temp = VBE - ((E - 1) & 511);
+ B = (temp > 0) ? temp : (temp + 512);
+
+ cr_data = XGI_Pr->XGINEWUB_CRT1Table[index].CR[11];
+
+ /* Vertical retrace (=sync) end */
+ VRE = (cr_data & 0x0f) | ((sr_data & 0x20) >> 1);
+ temp = VRE - ((E + F - 1) & 31);
+ C = (temp > 0) ? temp : (temp + 32);
+
+ D = B - F - C;
+
+ *upper_margin = D;
+ *lower_margin = F;
+ *vsync_len = C;
+
+ if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x8000)
+ *sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ else
+ *sync |= FB_SYNC_VERT_HIGH_ACT;
+
+ if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x4000)
+ *sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ else
+ *sync |= FB_SYNC_HOR_HIGH_ACT;
+
+ *vmode = FB_VMODE_NONINTERLACED;
+ if(XGI_Pr->RefIndex[RefreshRateTableIndex].Ext_InfoFlag & 0x0080)
+ *vmode = FB_VMODE_INTERLACED;
+ else {
+ j = 0;
+ while(XGI_Pr->EModeIDTable[j].Ext_ModeID != 0xff) {
+ if(XGI_Pr->EModeIDTable[j].Ext_ModeID ==
+ XGI_Pr->RefIndex[RefreshRateTableIndex].ModeID) {
+ if(XGI_Pr->EModeIDTable[j].Ext_ModeFlag & DoubleScanMode) {
+ *vmode = FB_VMODE_DOUBLE;
+ }
+ break;
+ }
+ j++;
+ }
+ }
+
+#if 0 /* That's bullshit, only the resolution needs to be shifted */
+ if((*vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ *upper_margin <<= 1;
+ *lower_margin <<= 1;
+ *vsync_len <<= 1;
+ } else if((*vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ *upper_margin >>= 1;
+ *lower_margin >>= 1;
+ *vsync_len >>= 1;
+ }
+#endif
+
+ return 1;
+}
+
+#endif
+
+
+
+void XGIRegInit(VB_DEVICE_INFO *XGI_Pr, ULONG BaseAddr)
+{
+ XGI_Pr->RelIO = BaseAddr;
+ XGI_Pr->P3c4 = BaseAddr + 0x14;
+ XGI_Pr->P3d4 = BaseAddr + 0x24;
+ XGI_Pr->P3c0 = BaseAddr + 0x10;
+ XGI_Pr->P3ce = BaseAddr + 0x1e;
+ XGI_Pr->P3c2 = BaseAddr + 0x12;
+ XGI_Pr->P3ca = BaseAddr + 0x1a;
+ XGI_Pr->P3c6 = BaseAddr + 0x16;
+ XGI_Pr->P3c7 = BaseAddr + 0x17;
+ XGI_Pr->P3c8 = BaseAddr + 0x18;
+ XGI_Pr->P3c9 = BaseAddr + 0x19;
+ XGI_Pr->P3da = BaseAddr + 0x2A;
+ XGI_Pr->Part1Port = BaseAddr + XGI_CRT2_PORT_04; /* Digital video interface registers (LCD) */
+ XGI_Pr->Part2Port = BaseAddr + XGI_CRT2_PORT_10; /* 301 TV Encoder registers */
+ XGI_Pr->Part3Port = BaseAddr + XGI_CRT2_PORT_12; /* 301 Macrovision registers */
+ XGI_Pr->Part4Port = BaseAddr + XGI_CRT2_PORT_14; /* 301 VGA2 (and LCD) registers */
+ XGI_Pr->Part5Port = BaseAddr + XGI_CRT2_PORT_14+2; /* 301 palette address port registers */
+
+}
+
+
+void XGIfb_set_reg4(u16 port, unsigned long data)
+{
+ outl((u32) (data & 0xffffffff), port);
+}
+
+u32 XGIfb_get_reg3(u16 port)
+{
+ u32 data;
+
+ data = inl(port);
+ return (data);
+}
+
+/* ------------ Interface for init & mode switching code ------------- */
+
+BOOLEAN
+XGIfb_query_VGA_config_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+ unsigned long offset, unsigned long set, unsigned long *value)
+{
+ static struct pci_dev *pdev = NULL;
+ static unsigned char init = 0, valid_pdev = 0;
+
+ if (!set)
+ DPRINTK("XGIfb: Get VGA offset 0x%lx\n", offset);
+ else
+ DPRINTK("XGIfb: Set offset 0x%lx to 0x%lx\n", offset, *value);
+
+ if (!init) {
+ init = TRUE;
+ pdev = pci_get_device(PCI_VENDOR_ID_XG, xgi_video_info.chip_id, pdev);
+ if (pdev) {
+ valid_pdev = TRUE;
+ pci_dev_put(pdev);
+ }
+ }
+
+ if (!valid_pdev) {
+ printk(KERN_DEBUG "XGIfb: Can't find XGI %d VGA device.\n",
+ xgi_video_info.chip_id);
+ return FALSE;
+ }
+
+ if (set == 0)
+ pci_read_config_dword(pdev, offset, (u32 *)value);
+ else
+ pci_write_config_dword(pdev, offset, (u32)(*value));
+
+ return TRUE;
+}
+
+/*BOOLEAN XGIfb_query_north_bridge_space(PXGI_HW_DEVICE_INFO pXGIhw_ext,
+ unsigned long offset, unsigned long set, unsigned long *value)
+{
+ static struct pci_dev *pdev = NULL;
+ static unsigned char init = 0, valid_pdev = 0;
+ u16 nbridge_id = 0;
+
+ if (!init) {
+ init = TRUE;
+ switch (xgi_video_info.chip) {
+ case XGI_540:
+ nbridge_id = PCI_DEVICE_ID_XG_540;
+ break;
+ case XGI_630:
+ nbridge_id = PCI_DEVICE_ID_XG_630;
+ break;
+ case XGI_730:
+ nbridge_id = PCI_DEVICE_ID_XG_730;
+ break;
+ case XGI_550:
+ nbridge_id = PCI_DEVICE_ID_XG_550;
+ break;
+ case XGI_650:
+ nbridge_id = PCI_DEVICE_ID_XG_650;
+ break;
+ case XGI_740:
+ nbridge_id = PCI_DEVICE_ID_XG_740;
+ break;
+ default:
+ nbridge_id = 0;
+ break;
+ }
+
+ pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev);
+ if (pdev)
+ valid_pdev = TRUE;
+ }
+
+ if (!valid_pdev) {
+ printk(KERN_DEBUG "XGIfb: Can't find XGI %d North Bridge device.\n",
+ nbridge_id);
+ return FALSE;
+ }
+
+ if (set == 0)
+ pci_read_config_dword(pdev, offset, (u32 *)value);
+ else
+ pci_write_config_dword(pdev, offset, (u32)(*value));
+
+ return TRUE;
+}
+*/
+/* ------------------ Internal helper routines ----------------- */
+
+static void XGIfb_search_mode(const char *name)
+{
+ int i = 0, j = 0, l;
+
+ if(name == NULL) {
+ printk(KERN_ERR "XGIfb: Internal error, using default mode.\n");
+ xgifb_mode_idx = DEFAULT_MODE;
+ if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD))
+ {
+ xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx();
+ }
+ return;
+ }
+
+
+ if (!strcmp(name, XGIbios_mode[MODE_INDEX_NONE].name)) {
+ printk(KERN_ERR "XGIfb: Mode 'none' not supported anymore. Using default.\n");
+ xgifb_mode_idx = DEFAULT_MODE;
+ if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD))
+ {
+ xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx();
+ }
+ return;
+ }
+
+ while(XGIbios_mode[i].mode_no != 0) {
+ l = min(strlen(name), strlen(XGIbios_mode[i].name));
+ if (!strncmp(name, XGIbios_mode[i].name, l)) {
+ xgifb_mode_idx = i;
+ j = 1;
+ break;
+ }
+ i++;
+ }
+ if(!j) printk(KERN_INFO "XGIfb: Invalid mode '%s'\n", name);
+}
+
+static void XGIfb_search_vesamode(unsigned int vesamode)
+{
+ int i = 0, j = 0;
+
+ if(vesamode == 0) {
+
+ printk(KERN_ERR "XGIfb: Mode 'none' not supported anymore. Using default.\n");
+ xgifb_mode_idx = DEFAULT_MODE;
+ if ((xgi_video_info.chip == XG21) && ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD))
+ {
+ xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx();
+ }
+ return;
+ }
+
+ vesamode &= 0x1dff; /* Clean VESA mode number from other flags */
+
+ while(XGIbios_mode[i].mode_no != 0) {
+ if( (XGIbios_mode[i].vesa_mode_no_1 == vesamode) ||
+ (XGIbios_mode[i].vesa_mode_no_2 == vesamode) ) {
+ xgifb_mode_idx = i;
+ j = 1;
+ break;
+ }
+ i++;
+ }
+ if(!j) printk(KERN_INFO "XGIfb: Invalid VESA mode 0x%x'\n", vesamode);
+}
+
+int XGIfb_GetXG21LVDSData(void)
+{
+ u8 tmp;
+ unsigned char *pData;
+ int i,j,k;
+
+ inXGIIDXREG(XGISR,0x1e,tmp);
+ outXGIIDXREG(XGISR, 0x1e, tmp|4);
+
+ pData = xgi_video_info.mmio_vbase+0x20000;
+ if ((pData[0x0]==0x55) && (pData[0x1]==0xAA) && (pData[0x65] & 0x1))
+ {
+ i = pData[ 0x316 ] | ( pData[ 0x317 ] << 8 );
+ j = pData[ i-1 ] ;
+ if ( j == 0xff )
+ {
+ j = 1;
+ }
+ k = 0;
+ do
+ {
+ XGI21_LCDCapList[k].LVDS_Capability = pData[ i ] | ( pData[ i + 1 ] << 8 );
+ XGI21_LCDCapList[k].LVDSHT = pData[ i + 2 ] | ( pData[ i + 3 ] << 8 ) ;
+ XGI21_LCDCapList[k].LVDSVT = pData[ i + 4 ] | ( pData[ i + 5 ] << 8 );
+ XGI21_LCDCapList[k].LVDSHDE = pData[ i + 6 ] | ( pData[ i + 7 ] << 8 );
+ XGI21_LCDCapList[k].LVDSVDE = pData[ i + 8 ] | ( pData[ i + 9 ] << 8 );
+ XGI21_LCDCapList[k].LVDSHFP = pData[ i + 10 ] | ( pData[ i + 11 ] << 8 );
+ XGI21_LCDCapList[k].LVDSVFP = pData[ i + 12 ] | ( pData[ i + 13 ] << 8 );
+ XGI21_LCDCapList[k].LVDSHSYNC = pData[ i + 14 ] | ( pData[ i + 15 ] << 8 );
+ XGI21_LCDCapList[k].LVDSVSYNC = pData[ i + 16 ] | ( pData[ i + 17 ] << 8 );
+ XGI21_LCDCapList[k].VCLKData1 = pData[ i + 18 ] ;
+ XGI21_LCDCapList[k].VCLKData2 = pData[ i + 19 ] ;
+ XGI21_LCDCapList[k].PSC_S1 = pData[ i + 20 ] ;
+ XGI21_LCDCapList[k].PSC_S2 = pData[ i + 21 ] ;
+ XGI21_LCDCapList[k].PSC_S3 = pData[ i + 22 ] ;
+ XGI21_LCDCapList[k].PSC_S4 = pData[ i + 23 ] ;
+ XGI21_LCDCapList[k].PSC_S5 = pData[ i + 24 ] ;
+ i += 25;
+ j--;
+ k++;
+ } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) );
+ return 1;
+ }
+ return 0;
+}
+
+int XGIfb_GetXG21DefaultLVDSModeIdx(void)
+{
+
+ int found_mode = 0;
+ int XGIfb_mode_idx = 0;
+
+ found_mode = 0;
+ while( (XGIbios_mode[XGIfb_mode_idx].mode_no != 0) &&
+ (XGIbios_mode[XGIfb_mode_idx].xres <= XGI21_LCDCapList[0].LVDSHDE) )
+ {
+ if( (XGIbios_mode[XGIfb_mode_idx].xres == XGI21_LCDCapList[0].LVDSHDE) &&
+ (XGIbios_mode[XGIfb_mode_idx].yres == XGI21_LCDCapList[0].LVDSVDE) &&
+ (XGIbios_mode[XGIfb_mode_idx].bpp == 8))
+ {
+ XGIfb_mode_no = XGIbios_mode[XGIfb_mode_idx].mode_no;
+ found_mode = 1;
+ break;
+ }
+ XGIfb_mode_idx++;
+ }
+ if (!found_mode)
+ XGIfb_mode_idx = 0;
+
+ return (XGIfb_mode_idx);
+}
+
+
+static int XGIfb_validate_mode(int myindex)
+{
+ u16 xres, yres;
+
+ if (xgi_video_info.chip == XG21)
+ {
+ if ((xgi_video_info.disp_state & DISPTYPE_DISP2) == DISPTYPE_LCD)
+ {
+ xres = XGI21_LCDCapList[0].LVDSHDE;
+ yres = XGI21_LCDCapList[0].LVDSVDE;
+ if(XGIbios_mode[myindex].xres > xres)
+ return(-1);
+ if(XGIbios_mode[myindex].yres > yres)
+ return(-1);
+ if ((XGIbios_mode[myindex].xres < xres) && (XGIbios_mode[myindex].yres < yres) )
+ {
+ if (XGIbios_mode[myindex].bpp > 8)
+ return(-1);
+ }
+
+ }
+ return(myindex);
+
+ }
+
+ /* FIXME: for now, all is valid on XG27 */
+ if (xgi_video_info.chip == XG27)
+ return(myindex);
+
+ if(!(XGIbios_mode[myindex].chipset & MD_XGI315))
+ return(-1);
+
+ switch (xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ case DISPTYPE_LCD:
+ switch (XGIhw_ext.ulCRT2LCDType) {
+ case LCD_640x480:
+ xres = 640; yres = 480; break;
+ case LCD_800x600:
+ xres = 800; yres = 600; break;
+ case LCD_1024x600:
+ xres = 1024; yres = 600; break;
+ case LCD_1024x768:
+ xres = 1024; yres = 768; break;
+ case LCD_1152x768:
+ xres = 1152; yres = 768; break;
+ case LCD_1280x960:
+ xres = 1280; yres = 960; break;
+ case LCD_1280x768:
+ xres = 1280; yres = 768; break;
+ case LCD_1280x1024:
+ xres = 1280; yres = 1024; break;
+ case LCD_1400x1050:
+ xres = 1400; yres = 1050; break;
+ case LCD_1600x1200:
+ xres = 1600; yres = 1200; break;
+// case LCD_320x480: // TW: FSTN
+// xres = 320; yres = 480; break;
+ default:
+ xres = 0; yres = 0; break;
+ }
+ if(XGIbios_mode[myindex].xres > xres) {
+ return(-1);
+ }
+ if(XGIbios_mode[myindex].yres > yres) {
+ return(-1);
+ }
+ if((XGIhw_ext.ulExternalChip == 0x01) || // LVDS
+ (XGIhw_ext.ulExternalChip == 0x05)) // LVDS+Chrontel
+ {
+ switch (XGIbios_mode[myindex].xres) {
+ case 512:
+ if(XGIbios_mode[myindex].yres != 512) return -1;
+ if(XGIhw_ext.ulCRT2LCDType == LCD_1024x600) return -1;
+ break;
+ case 640:
+ if((XGIbios_mode[myindex].yres != 400) &&
+ (XGIbios_mode[myindex].yres != 480))
+ return -1;
+ break;
+ case 800:
+ if(XGIbios_mode[myindex].yres != 600) return -1;
+ break;
+ case 1024:
+ if((XGIbios_mode[myindex].yres != 600) &&
+ (XGIbios_mode[myindex].yres != 768))
+ return -1;
+ if((XGIbios_mode[myindex].yres == 600) &&
+ (XGIhw_ext.ulCRT2LCDType != LCD_1024x600))
+ return -1;
+ break;
+ case 1152:
+ if((XGIbios_mode[myindex].yres) != 768) return -1;
+ if(XGIhw_ext.ulCRT2LCDType != LCD_1152x768) return -1;
+ break;
+ case 1280:
+ if((XGIbios_mode[myindex].yres != 768) &&
+ (XGIbios_mode[myindex].yres != 1024))
+ return -1;
+ if((XGIbios_mode[myindex].yres == 768) &&
+ (XGIhw_ext.ulCRT2LCDType != LCD_1280x768))
+ return -1;
+ break;
+ case 1400:
+ if(XGIbios_mode[myindex].yres != 1050) return -1;
+ break;
+ case 1600:
+ if(XGIbios_mode[myindex].yres != 1200) return -1;
+ break;
+ default:
+ return -1;
+ }
+ } else {
+ switch (XGIbios_mode[myindex].xres) {
+ case 512:
+ if(XGIbios_mode[myindex].yres != 512) return -1;
+ break;
+ case 640:
+ if((XGIbios_mode[myindex].yres != 400) &&
+ (XGIbios_mode[myindex].yres != 480))
+ return -1;
+ break;
+ case 800:
+ if(XGIbios_mode[myindex].yres != 600) return -1;
+ break;
+ case 1024:
+ if(XGIbios_mode[myindex].yres != 768) return -1;
+ break;
+ case 1280:
+ if((XGIbios_mode[myindex].yres != 960) &&
+ (XGIbios_mode[myindex].yres != 1024))
+ return -1;
+ if(XGIbios_mode[myindex].yres == 960) {
+ if(XGIhw_ext.ulCRT2LCDType == LCD_1400x1050)
+ return -1;
+ }
+ break;
+ case 1400:
+ if(XGIbios_mode[myindex].yres != 1050) return -1;
+ break;
+ case 1600:
+ if(XGIbios_mode[myindex].yres != 1200) return -1;
+ break;
+ default:
+ return -1;
+ }
+ }
+ break;
+ case DISPTYPE_TV:
+ switch (XGIbios_mode[myindex].xres) {
+ case 512:
+ case 640:
+ case 800:
+ break;
+ case 720:
+ if (xgi_video_info.TV_type == TVMODE_NTSC) {
+ if (XGIbios_mode[myindex].yres != 480) {
+ return(-1);
+ }
+ } else if (xgi_video_info.TV_type == TVMODE_PAL) {
+ if (XGIbios_mode[myindex].yres != 576) {
+ return(-1);
+ }
+ }
+ // TW: LVDS/CHRONTEL does not support 720
+ if (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL ||
+ xgi_video_info.hasVB == HASVB_CHRONTEL) {
+ return(-1);
+ }
+ break;
+ case 1024:
+ if (xgi_video_info.TV_type == TVMODE_NTSC) {
+ if(XGIbios_mode[myindex].bpp == 32) {
+ return(-1);
+ }
+ }
+ // TW: LVDS/CHRONTEL only supports < 800 (1024 on 650/Ch7019)
+ if (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL ||
+ xgi_video_info.hasVB == HASVB_CHRONTEL) {
+ if(xgi_video_info.chip < XGI_315H) {
+ return(-1);
+ }
+ }
+ break;
+ default:
+ return(-1);
+ }
+ break;
+ case DISPTYPE_CRT2:
+ if(XGIbios_mode[myindex].xres > 1280) return -1;
+ break;
+ }
+ return(myindex);
+
+}
+
+static void XGIfb_search_crt2type(const char *name)
+{
+ int i = 0;
+
+ if(name == NULL)
+ return;
+
+ while(XGI_crt2type[i].type_no != -1) {
+ if (!strcmp(name, XGI_crt2type[i].name)) {
+ XGIfb_crt2type = XGI_crt2type[i].type_no;
+ XGIfb_tvplug = XGI_crt2type[i].tvplug_no;
+ break;
+ }
+ i++;
+ }
+ if(XGIfb_crt2type < 0)
+ printk(KERN_INFO "XGIfb: Invalid CRT2 type: %s\n", name);
+}
+
+static void XGIfb_search_queuemode(const char *name)
+{
+ int i = 0;
+
+ if(name == NULL)
+ return;
+
+ while (XGI_queuemode[i].type_no != -1) {
+ if (!strcmp(name, XGI_queuemode[i].name)) {
+ XGIfb_queuemode = XGI_queuemode[i].type_no;
+ break;
+ }
+ i++;
+ }
+ if (XGIfb_queuemode < 0)
+ printk(KERN_INFO "XGIfb: Invalid queuemode type: %s\n", name);
+}
+
+static u8 XGIfb_search_refresh_rate(unsigned int rate)
+{
+ u16 xres, yres;
+ int i = 0;
+
+ xres = XGIbios_mode[xgifb_mode_idx].xres;
+ yres = XGIbios_mode[xgifb_mode_idx].yres;
+
+ XGIfb_rate_idx = 0;
+ while ((XGIfb_vrate[i].idx != 0) && (XGIfb_vrate[i].xres <= xres)) {
+ if ((XGIfb_vrate[i].xres == xres) && (XGIfb_vrate[i].yres == yres)) {
+ if (XGIfb_vrate[i].refresh == rate) {
+ XGIfb_rate_idx = XGIfb_vrate[i].idx;
+ break;
+ } else if (XGIfb_vrate[i].refresh > rate) {
+ if ((XGIfb_vrate[i].refresh - rate) <= 3) {
+ DPRINTK("XGIfb: Adjusting rate from %d up to %d\n",
+ rate, XGIfb_vrate[i].refresh);
+ XGIfb_rate_idx = XGIfb_vrate[i].idx;
+ xgi_video_info.refresh_rate = XGIfb_vrate[i].refresh;
+ } else if (((rate - XGIfb_vrate[i-1].refresh) <= 2)
+ && (XGIfb_vrate[i].idx != 1)) {
+ DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
+ rate, XGIfb_vrate[i-1].refresh);
+ XGIfb_rate_idx = XGIfb_vrate[i-1].idx;
+ xgi_video_info.refresh_rate = XGIfb_vrate[i-1].refresh;
+ }
+ break;
+ } else if((rate - XGIfb_vrate[i].refresh) <= 2) {
+ DPRINTK("XGIfb: Adjusting rate from %d down to %d\n",
+ rate, XGIfb_vrate[i].refresh);
+ XGIfb_rate_idx = XGIfb_vrate[i].idx;
+ break;
+ }
+ }
+ i++;
+ }
+ if (XGIfb_rate_idx > 0) {
+ return XGIfb_rate_idx;
+ } else {
+ printk(KERN_INFO
+ "XGIfb: Unsupported rate %d for %dx%d\n", rate, xres, yres);
+ return 0;
+ }
+}
+
+static void XGIfb_search_tvstd(const char *name)
+{
+ int i = 0;
+
+ if(name == NULL)
+ return;
+
+ while (XGI_tvtype[i].type_no != -1) {
+ if (!strcmp(name, XGI_tvtype[i].name)) {
+ XGIfb_tvmode = XGI_tvtype[i].type_no;
+ break;
+ }
+ i++;
+ }
+}
+
+static BOOLEAN XGIfb_bridgeisslave(void)
+{
+ unsigned char usScratchP1_00;
+
+ if(xgi_video_info.hasVB == HASVB_NONE) return FALSE;
+
+ inXGIIDXREG(XGIPART1,0x00,usScratchP1_00);
+ if( (usScratchP1_00 & 0x50) == 0x10) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+static BOOLEAN XGIfbcheckvretracecrt1(void)
+{
+ unsigned char temp;
+
+ inXGIIDXREG(XGICR,0x17,temp);
+ if(!(temp & 0x80)) return FALSE;
+
+
+ inXGIIDXREG(XGISR,0x1f,temp);
+ if(temp & 0xc0) return FALSE;
+
+
+ if(inXGIREG(XGIINPSTAT) & 0x08) return TRUE;
+ else return FALSE;
+}
+
+static BOOLEAN XGIfbcheckvretracecrt2(void)
+{
+ unsigned char temp;
+ if(xgi_video_info.hasVB == HASVB_NONE) return FALSE;
+ inXGIIDXREG(XGIPART1, 0x30, temp);
+ if(temp & 0x02) return FALSE;
+ else return TRUE;
+}
+
+static BOOLEAN XGIfb_CheckVBRetrace(void)
+{
+ if(xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ if(XGIfb_bridgeisslave()) {
+ return(XGIfbcheckvretracecrt1());
+ } else {
+ return(XGIfbcheckvretracecrt2());
+ }
+ }
+ return(XGIfbcheckvretracecrt1());
+}
+
+/* ----------- FBDev related routines for all series ----------- */
+
+
+static void XGIfb_bpp_to_var(struct fb_var_screeninfo *var)
+{
+ switch(var->bits_per_pixel) {
+ case 8:
+ var->red.offset = var->green.offset = var->blue.offset = 0;
+ var->red.length = var->green.length = var->blue.length = 6;
+ xgi_video_info.video_cmap_len = 256;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 8;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ }
+}
+
+
+
+static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ struct fb_info *info)
+{
+
+ unsigned int htotal = var->left_margin + var->xres +
+ var->right_margin + var->hsync_len;
+ unsigned int vtotal = var->upper_margin + var->yres +
+ var->lower_margin + var->vsync_len;
+#if defined(__powerpc__)
+ u8 sr_data, cr_data;
+#endif
+ unsigned int drate = 0, hrate = 0;
+ int found_mode = 0;
+ int old_mode;
+// unsigned char reg,reg1;
+
+ DEBUGPRN("Inside do_set_var");
+// printk(KERN_DEBUG "XGIfb:var->yres=%d, var->upper_margin=%d, var->lower_margin=%d, var->vsync_len=%d\n", var->yres,var->upper_margin,var->lower_margin,var->vsync_len);
+
+ info->var.xres_virtual = var->xres_virtual;
+ info->var.yres_virtual = var->yres_virtual;
+ info->var.bits_per_pixel = var->bits_per_pixel;
+
+ if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
+ vtotal <<= 1;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
+ vtotal <<= 2;
+ else if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED)
+ {
+// vtotal <<= 1;
+// var->yres <<= 1;
+ }
+
+ if(!htotal || !vtotal) {
+ DPRINTK("XGIfb: Invalid 'var' information\n");
+ return -EINVAL;
+ }
+ printk(KERN_DEBUG "XGIfb: var->pixclock=%d, htotal=%d, vtotal=%d\n",
+ var->pixclock,htotal,vtotal);
+
+
+
+ if(var->pixclock && htotal && vtotal) {
+ drate = 1000000000 / var->pixclock;
+ hrate = (drate * 1000) / htotal;
+ xgi_video_info.refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+ } else {
+ xgi_video_info.refresh_rate = 60;
+ }
+
+ printk(KERN_DEBUG "XGIfb: Change mode to %dx%dx%d-%dHz\n",
+ var->xres,var->yres,var->bits_per_pixel,xgi_video_info.refresh_rate);
+
+ old_mode = xgifb_mode_idx;
+ xgifb_mode_idx = 0;
+
+ while( (XGIbios_mode[xgifb_mode_idx].mode_no != 0) &&
+ (XGIbios_mode[xgifb_mode_idx].xres <= var->xres) ) {
+ if( (XGIbios_mode[xgifb_mode_idx].xres == var->xres) &&
+ (XGIbios_mode[xgifb_mode_idx].yres == var->yres) &&
+ (XGIbios_mode[xgifb_mode_idx].bpp == var->bits_per_pixel)) {
+ XGIfb_mode_no = XGIbios_mode[xgifb_mode_idx].mode_no;
+ found_mode = 1;
+ break;
+ }
+ xgifb_mode_idx++;
+ }
+
+ if(found_mode)
+ xgifb_mode_idx = XGIfb_validate_mode(xgifb_mode_idx);
+ else
+ xgifb_mode_idx = -1;
+
+ if(xgifb_mode_idx < 0) {
+ printk(KERN_ERR "XGIfb: Mode %dx%dx%d not supported\n", var->xres,
+ var->yres, var->bits_per_pixel);
+ xgifb_mode_idx = old_mode;
+ return -EINVAL;
+ }
+
+ if(XGIfb_search_refresh_rate(xgi_video_info.refresh_rate) == 0) {
+ XGIfb_rate_idx = XGIbios_mode[xgifb_mode_idx].rate_idx;
+ xgi_video_info.refresh_rate = 60;
+ }
+
+ if(isactive) {
+
+
+ XGIfb_pre_setmode();
+ if(XGISetModeNew( &XGIhw_ext, XGIfb_mode_no) == 0) {
+ printk(KERN_ERR "XGIfb: Setting mode[0x%x] failed\n", XGIfb_mode_no);
+ return -EINVAL;
+ }
+ info->fix.line_length = ((info->var.xres_virtual * info->var.bits_per_pixel)>>6);
+
+ outXGIIDXREG(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD);
+
+ outXGIIDXREG(XGICR,0x13,(info->fix.line_length & 0x00ff));
+ outXGIIDXREG(XGISR,0x0E,(info->fix.line_length & 0xff00)>>8);
+
+ XGIfb_post_setmode();
+
+ DPRINTK("XGIfb: Set new mode: %dx%dx%d-%d \n",
+ XGIbios_mode[xgifb_mode_idx].xres,
+ XGIbios_mode[xgifb_mode_idx].yres,
+ XGIbios_mode[xgifb_mode_idx].bpp,
+ xgi_video_info.refresh_rate);
+
+ xgi_video_info.video_bpp = XGIbios_mode[xgifb_mode_idx].bpp;
+ xgi_video_info.video_vwidth = info->var.xres_virtual;
+ xgi_video_info.video_width = XGIbios_mode[xgifb_mode_idx].xres;
+ xgi_video_info.video_vheight = info->var.yres_virtual;
+ xgi_video_info.video_height = XGIbios_mode[xgifb_mode_idx].yres;
+ xgi_video_info.org_x = xgi_video_info.org_y = 0;
+ xgi_video_info.video_linelength = info->var.xres_virtual * (xgi_video_info.video_bpp >> 3);
+ xgi_video_info.accel = 0;
+ if(XGIfb_accel) {
+ xgi_video_info.accel = (var->accel_flags & FB_ACCELF_TEXT) ? -1 : 0;
+ }
+ switch(xgi_video_info.video_bpp)
+ {
+ case 8:
+ xgi_video_info.DstColor = 0x0000;
+ xgi_video_info.XGI310_AccelDepth = 0x00000000;
+ xgi_video_info.video_cmap_len = 256;
+#if defined(__powerpc__)
+ inXGIIDXREG (XGICR, 0x4D, cr_data);
+ outXGIIDXREG(XGICR, 0x4D, (cr_data & 0xE0));
+#endif
+ break;
+ case 16:
+ xgi_video_info.DstColor = 0x8000;
+ xgi_video_info.XGI310_AccelDepth = 0x00010000;
+#if defined(__powerpc__)
+ inXGIIDXREG (XGICR, 0x4D, cr_data);
+ outXGIIDXREG(XGICR, 0x4D, ((cr_data & 0xE0) | 0x0B));
+#endif
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ case 32:
+ xgi_video_info.DstColor = 0xC000;
+ xgi_video_info.XGI310_AccelDepth = 0x00020000;
+ xgi_video_info.video_cmap_len = 16;
+#if defined(__powerpc__)
+ inXGIIDXREG (XGICR, 0x4D, cr_data);
+ outXGIIDXREG(XGICR, 0x4D, ((cr_data & 0xE0) | 0x15));
+#endif
+ break;
+ default:
+ xgi_video_info.video_cmap_len = 16;
+ printk(KERN_ERR "XGIfb: Unsupported depth %d", xgi_video_info.video_bpp);
+ xgi_video_info.accel = 0;
+ break;
+ }
+ }
+ XGIfb_bpp_to_var(var); /*update ARGB info*/
+ DEBUGPRN("End of do_set_var");
+
+ dumpVGAReg();
+ return 0;
+}
+
+#ifdef XGIFB_PAN
+static int XGIfb_pan_var(struct fb_var_screeninfo *var)
+{
+ unsigned int base;
+
+// printk("Inside pan_var");
+
+ if (var->xoffset > (var->xres_virtual - var->xres)) {
+// printk( "Pan: xo: %d xv %d xr %d\n",
+// var->xoffset, var->xres_virtual, var->xres);
+ return -EINVAL;
+ }
+ if(var->yoffset > (var->yres_virtual - var->yres)) {
+// printk( "Pan: yo: %d yv %d yr %d\n",
+// var->yoffset, var->yres_virtual, var->yres);
+ return -EINVAL;
+ }
+ base = var->yoffset * var->xres_virtual + var->xoffset;
+
+ /* calculate base bpp dep. */
+ switch(var->bits_per_pixel) {
+ case 16:
+ base >>= 1;
+ break;
+ case 32:
+ break;
+ case 8:
+ default:
+ base >>= 2;
+ break;
+ }
+
+ outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+
+ outXGIIDXREG(XGICR, 0x0D, base & 0xFF);
+ outXGIIDXREG(XGICR, 0x0C, (base >> 8) & 0xFF);
+ outXGIIDXREG(XGISR, 0x0D, (base >> 16) & 0xFF);
+ outXGIIDXREG(XGISR, 0x37, (base >> 24) & 0x03);
+ setXGIIDXREG(XGISR, 0x37, 0xDF, (base >> 21) & 0x04);
+
+ if(xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ orXGIIDXREG(XGIPART1, XGIfb_CRT2_write_enable, 0x01);
+ outXGIIDXREG(XGIPART1, 0x06, (base & 0xFF));
+ outXGIIDXREG(XGIPART1, 0x05, ((base >> 8) & 0xFF));
+ outXGIIDXREG(XGIPART1, 0x04, ((base >> 16) & 0xFF));
+ setXGIIDXREG(XGIPART1, 0x02, 0x7F, ((base >> 24) & 0x01) << 7);
+ }
+// printk("End of pan_var");
+ return 0;
+}
+#endif
+
+
+void XGI_dispinfo(struct ap_data *rec)
+{
+ rec->minfo.bpp = xgi_video_info.video_bpp;
+ rec->minfo.xres = xgi_video_info.video_width;
+ rec->minfo.yres = xgi_video_info.video_height;
+ rec->minfo.v_xres = xgi_video_info.video_vwidth;
+ rec->minfo.v_yres = xgi_video_info.video_vheight;
+ rec->minfo.org_x = xgi_video_info.org_x;
+ rec->minfo.org_y = xgi_video_info.org_y;
+ rec->minfo.vrate = xgi_video_info.refresh_rate;
+ rec->iobase = xgi_video_info.vga_base - 0x30;
+ rec->mem_size = xgi_video_info.video_size;
+ rec->disp_state = xgi_video_info.disp_state;
+ rec->version = (VER_MAJOR << 24) | (VER_MINOR << 16) | VER_LEVEL;
+ rec->hasVB = xgi_video_info.hasVB;
+ rec->TV_type = xgi_video_info.TV_type;
+ rec->TV_plug = xgi_video_info.TV_plug;
+ rec->chip = xgi_video_info.chip;
+}
+
+
+
+
+static int XGIfb_open(struct fb_info *info, int user)
+{
+ return 0;
+}
+
+static int XGIfb_release(struct fb_info *info, int user)
+{
+ return 0;
+}
+
+static int XGIfb_get_cmap_len(const struct fb_var_screeninfo *var)
+{
+ int rc = 16;
+
+ switch(var->bits_per_pixel) {
+ case 8:
+ rc = 256;
+ break;
+ case 16:
+ rc = 16;
+ break;
+ case 32:
+ rc = 16;
+ break;
+ }
+ return rc;
+}
+
+static int XGIfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
+ unsigned transp, struct fb_info *info)
+{
+ if (regno >= XGIfb_get_cmap_len(&info->var))
+ return 1;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ outXGIREG(XGIDACA, regno);
+ outXGIREG(XGIDACD, (red >> 10));
+ outXGIREG(XGIDACD, (green >> 10));
+ outXGIREG(XGIDACD, (blue >> 10));
+ if (xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ outXGIREG(XGIDAC2A, regno);
+ outXGIREG(XGIDAC2D, (red >> 8));
+ outXGIREG(XGIDAC2D, (green >> 8));
+ outXGIREG(XGIDAC2D, (blue >> 8));
+ }
+ break;
+ case 16:
+ ((u32 *)(info->pseudo_palette))[regno] =
+ ((red & 0xf800)) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+ break;
+ case 32:
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *) (info->pseudo_palette))[regno] =
+ (red << 16) | (green << 8) | (blue);
+ break;
+ }
+ return 0;
+}
+
+static int XGIfb_set_par(struct fb_info *info)
+{
+ int err;
+
+// printk("XGIfb: inside set_par\n");
+ if((err = XGIfb_do_set_var(&info->var, 1, info)))
+ return err;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+ XGIfb_get_fix(&info->fix, info->currcon, info);
+#else
+ XGIfb_get_fix(&info->fix, -1, info);
+#endif
+// printk("XGIfb:end of set_par\n");
+ return 0;
+}
+
+static int XGIfb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned int htotal =
+ var->left_margin + var->xres + var->right_margin +
+ var->hsync_len;
+ unsigned int vtotal = 0;
+ unsigned int drate = 0, hrate = 0;
+ int found_mode = 0;
+ int refresh_rate, search_idx;
+
+ DEBUGPRN("Inside check_var");
+
+ if((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED) {
+ vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+ vtotal <<= 1;
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+ vtotal <<= 2;
+ } else if((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ vtotal = var->upper_margin + (var->yres/2) + var->lower_margin +
+ var->vsync_len;
+ } else vtotal = var->upper_margin + var->yres + var->lower_margin +
+ var->vsync_len;
+
+ if(!(htotal) || !(vtotal)) {
+ XGIFAIL("XGIfb: no valid timing data");
+ }
+
+
+ if(var->pixclock && htotal && vtotal) {
+ drate = 1000000000 / var->pixclock;
+ hrate = (drate * 1000) / htotal;
+ xgi_video_info.refresh_rate = (unsigned int) (hrate * 2 / vtotal);
+ printk(KERN_DEBUG \
+ "%s: pixclock = %d ,htotal=%d, vtotal=%d\n" \
+ "%s: drate=%d, hrate=%d, refresh_rate=%d\n",
+ __func__,var->pixclock, htotal, vtotal,
+ __func__, drate, hrate, xgi_video_info.refresh_rate);
+ } else {
+ xgi_video_info.refresh_rate = 60;
+ }
+
+/*
+ if((var->pixclock) && (htotal)) {
+ drate = 1E12 / var->pixclock;
+ hrate = drate / htotal;
+ refresh_rate = (unsigned int) (hrate / vtotal * 2 + 0.5);
+ } else refresh_rate = 60;
+*/
+ /* TW: Calculation wrong for 1024x600 - force it to 60Hz */
+ if((var->xres == 1024) && (var->yres == 600)) refresh_rate = 60;
+
+ search_idx = 0;
+ while((XGIbios_mode[search_idx].mode_no != 0) &&
+ (XGIbios_mode[search_idx].xres <= var->xres) ) {
+ if((XGIbios_mode[search_idx].xres == var->xres) &&
+ (XGIbios_mode[search_idx].yres == var->yres) &&
+ (XGIbios_mode[search_idx].bpp == var->bits_per_pixel)) {
+ if(XGIfb_validate_mode(search_idx) > 0) {
+ found_mode = 1;
+ break;
+ }
+ }
+ search_idx++;
+ }
+
+ if(!found_mode) {
+
+ printk(KERN_ERR "XGIfb: %dx%dx%d is no valid mode\n",
+ var->xres, var->yres, var->bits_per_pixel);
+
+ search_idx = 0;
+ while(XGIbios_mode[search_idx].mode_no != 0) {
+
+ if( (var->xres <= XGIbios_mode[search_idx].xres) &&
+ (var->yres <= XGIbios_mode[search_idx].yres) &&
+ (var->bits_per_pixel == XGIbios_mode[search_idx].bpp) ) {
+ if(XGIfb_validate_mode(search_idx) > 0) {
+ found_mode = 1;
+ break;
+ }
+ }
+ search_idx++;
+ }
+ if(found_mode) {
+ var->xres = XGIbios_mode[search_idx].xres;
+ var->yres = XGIbios_mode[search_idx].yres;
+ printk(KERN_DEBUG "XGIfb: Adapted to mode %dx%dx%d\n",
+ var->xres, var->yres, var->bits_per_pixel);
+
+ } else {
+ printk(KERN_ERR "XGIfb: Failed to find similar mode to %dx%dx%d\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+ }
+
+ /* TW: TODO: Check the refresh rate */
+
+ /* Adapt RGB settings */
+ XGIfb_bpp_to_var(var);
+
+ /* Sanity check for offsets */
+ if (var->xoffset < 0)
+ var->xoffset = 0;
+ if (var->yoffset < 0)
+ var->yoffset = 0;
+
+
+ if(!XGIfb_ypan) {
+ if(var->xres != var->xres_virtual)
+ var->xres_virtual = var->xres;
+ if(var->yres != var->yres_virtual)
+ var->yres_virtual = var->yres;
+ }/* else {
+ // TW: Now patch yres_virtual if we use panning
+ // May I do this?
+ var->yres_virtual = xgi_video_info.heapstart / (var->xres * (var->bits_per_pixel >> 3));
+ if(var->yres_virtual <= var->yres) {
+ // TW: Paranoia check
+ var->yres_virtual = var->yres;
+ }
+ }*/
+
+ /* Truncate offsets to maximum if too high */
+ if (var->xoffset > var->xres_virtual - var->xres)
+ var->xoffset = var->xres_virtual - var->xres - 1;
+
+ if (var->yoffset > var->yres_virtual - var->yres)
+ var->yoffset = var->yres_virtual - var->yres - 1;
+
+ /* Set everything else to 0 */
+ var->red.msb_right =
+ var->green.msb_right =
+ var->blue.msb_right =
+ var->transp.offset = var->transp.length = var->transp.msb_right = 0;
+
+ DEBUGPRN("end of check_var");
+ return 0;
+}
+
+#ifdef XGIFB_PAN
+static int XGIfb_pan_display( struct fb_var_screeninfo *var,
+ struct fb_info* info)
+{
+ int err;
+
+// printk("\nInside pan_display:");
+
+ if (var->xoffset > (var->xres_virtual - var->xres))
+ return -EINVAL;
+ if (var->yoffset > (var->yres_virtual - var->yres))
+ return -EINVAL;
+
+ if (var->vmode & FB_VMODE_YWRAP) {
+ if (var->yoffset < 0
+ || var->yoffset >= info->var.yres_virtual
+ || var->xoffset) return -EINVAL;
+ } else {
+ if (var->xoffset + info->var.xres > info->var.xres_virtual ||
+ var->yoffset + info->var.yres > info->var.yres_virtual)
+ return -EINVAL;
+ }
+
+ if((err = XGIfb_pan_var(var)) < 0) return err;
+
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
+ if (var->vmode & FB_VMODE_YWRAP)
+ info->var.vmode |= FB_VMODE_YWRAP;
+ else
+ info->var.vmode &= ~FB_VMODE_YWRAP;
+
+// printk(" End of pan_display");
+ return 0;
+}
+#endif
+
+#if 0
+static int XGIfb_mmap(struct fb_info *info, struct file *file,
+ struct vm_area_struct *vma)
+{
+ unsigned long start;
+ unsigned long off;
+ u32 len, mmio_off;
+
+ DEBUGPRN("inside mmap");
+ if(vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) return -EINVAL;
+
+ off = vma->vm_pgoff << PAGE_SHIFT;
+
+ start = (unsigned long) xgi_video_info.video_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.video_size);
+ start &= PAGE_MASK;
+#if 0
+ if (off >= len) {
+ off -= len;
+#endif
+ /* By Jake Page: Treat mmap request with offset beyond heapstart
+ * as request for mapping the mmio area
+ */
+ #if 1
+ mmio_off = PAGE_ALIGN((start & ~PAGE_MASK) + xgi_video_info.heapstart);
+ if(off >= mmio_off) {
+ off -= mmio_off;
+ if(info->var.accel_flags) return -EINVAL;
+
+ start = (unsigned long) xgi_video_info.mmio_base;
+ len = PAGE_ALIGN((start & ~PAGE_MASK) + XGIfb_mmio_size);
+ }
+ start &= PAGE_MASK;
+ #endif
+ if((vma->vm_end - vma->vm_start + off) > len) return -EINVAL;
+
+ off += start;
+ vma->vm_pgoff = off >> PAGE_SHIFT;
+ vma->vm_flags |= VM_IO; /* by Jake Page; is that really needed? */
+
+#if defined(__i386__) || defined(__x86_64__)
+ if (boot_cpu_data.x86 > 3)
+ pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+#endif
+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start,
+ vma->vm_page_prot))
+ return -EAGAIN;
+
+ DEBUGPRN("end of mmap");
+ return 0;
+}
+#endif
+static int XGIfb_blank(int blank, struct fb_info *info)
+{
+ u8 reg;
+
+ inXGIIDXREG(XGICR, 0x17, reg);
+
+ if(blank > 0)
+ reg &= 0x7f;
+ else
+ reg |= 0x80;
+
+ outXGIIDXREG(XGICR, 0x17, reg);
+ outXGIIDXREG(XGISR, 0x00, 0x01); /* Synchronous Reset */
+ outXGIIDXREG(XGISR, 0x00, 0x03); /* End Reset */
+ return(0);
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
+static int XGIfb_ioctl(struct fb_info *info, unsigned int cmd,
+ unsigned long arg)
+#else
+static int XGIfb_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ struct fb_info *info)
+#endif
+
+{
+ DEBUGPRN("inside ioctl");
+ switch (cmd) {
+ case FBIO_ALLOC:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ XGI_malloc((struct XGI_memreq *) arg);
+ break;
+ case FBIO_FREE:
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ XGI_free(*(unsigned long *) arg);
+ break;
+ case FBIOGET_HWCINFO:
+ {
+ unsigned long *hwc_offset = (unsigned long *) arg;
+
+ if (XGIfb_caps & HW_CURSOR_CAP)
+ *hwc_offset = XGIfb_hwcursor_vbase -
+ (unsigned long) xgi_video_info.video_vbase;
+ else
+ *hwc_offset = 0;
+
+ break;
+ }
+ case FBIOPUT_MODEINFO:
+ {
+ struct mode_info *x = (struct mode_info *)arg;
+
+ xgi_video_info.video_bpp = x->bpp;
+ xgi_video_info.video_width = x->xres;
+ xgi_video_info.video_height = x->yres;
+ xgi_video_info.video_vwidth = x->v_xres;
+ xgi_video_info.video_vheight = x->v_yres;
+ xgi_video_info.org_x = x->org_x;
+ xgi_video_info.org_y = x->org_y;
+ xgi_video_info.refresh_rate = x->vrate;
+ xgi_video_info.video_linelength = xgi_video_info.video_vwidth * (xgi_video_info.video_bpp >> 3);
+ switch(xgi_video_info.video_bpp) {
+ case 8:
+ xgi_video_info.DstColor = 0x0000;
+ xgi_video_info.XGI310_AccelDepth = 0x00000000;
+ xgi_video_info.video_cmap_len = 256;
+ break;
+ case 16:
+ xgi_video_info.DstColor = 0x8000;
+ xgi_video_info.XGI310_AccelDepth = 0x00010000;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ case 32:
+ xgi_video_info.DstColor = 0xC000;
+ xgi_video_info.XGI310_AccelDepth = 0x00020000;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ default:
+ xgi_video_info.video_cmap_len = 16;
+ printk(KERN_ERR "XGIfb: Unsupported accel depth %d", xgi_video_info.video_bpp);
+ xgi_video_info.accel = 0;
+ break;
+ }
+
+ break;
+ }
+ case FBIOGET_DISPINFO:
+ XGI_dispinfo((struct ap_data *)arg);
+ break;
+ case XGIFB_GET_INFO: /* TW: New for communication with X driver */
+ {
+ XGIfb_info *x = (XGIfb_info *)arg;
+
+ //x->XGIfb_id = XGIFB_ID;
+ x->XGIfb_version = VER_MAJOR;
+ x->XGIfb_revision = VER_MINOR;
+ x->XGIfb_patchlevel = VER_LEVEL;
+ x->chip_id = xgi_video_info.chip_id;
+ x->memory = xgi_video_info.video_size / 1024;
+ x->heapstart = xgi_video_info.heapstart / 1024;
+ x->fbvidmode = XGIfb_mode_no;
+ x->XGIfb_caps = XGIfb_caps;
+ x->XGIfb_tqlen = 512; /* yet unused */
+ x->XGIfb_pcibus = xgi_video_info.pcibus;
+ x->XGIfb_pcislot = xgi_video_info.pcislot;
+ x->XGIfb_pcifunc = xgi_video_info.pcifunc;
+ x->XGIfb_lcdpdc = XGIfb_detectedpdc;
+ x->XGIfb_lcda = XGIfb_detectedlcda;
+ break;
+ }
+ case XGIFB_GET_VBRSTATUS:
+ {
+ unsigned long *vbrstatus = (unsigned long *) arg;
+ if(XGIfb_CheckVBRetrace()) *vbrstatus = 1;
+ else *vbrstatus = 0;
+ }
+ default:
+ return -EINVAL;
+ }
+ DEBUGPRN("end of ioctl");
+ return 0;
+
+}
+
+
+
+/* ----------- FBDev related routines for all series ---------- */
+
+static int XGIfb_get_fix(struct fb_fix_screeninfo *fix, int con,
+ struct fb_info *info)
+{
+ DEBUGPRN("inside get_fix");
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+
+ strcpy(fix->id, myid);
+
+ fix->smem_start = xgi_video_info.video_base;
+
+ fix->smem_len = xgi_video_info.video_size;
+
+
+/* if((!XGIfb_mem) || (XGIfb_mem > (xgi_video_info.video_size/1024))) {
+ if (xgi_video_info.video_size > 0x1000000) {
+ fix->smem_len = 0xD00000;
+ } else if (xgi_video_info.video_size > 0x800000)
+ fix->smem_len = 0x800000;
+ else
+ fix->smem_len = 0x400000;
+ } else
+ fix->smem_len = XGIfb_mem * 1024;
+*/
+ fix->type = video_type;
+ fix->type_aux = 0;
+ if(xgi_video_info.video_bpp == 8)
+ fix->visual = FB_VISUAL_PSEUDOCOLOR;
+ else
+ fix->visual = FB_VISUAL_DIRECTCOLOR;
+ fix->xpanstep = 0;
+#ifdef XGIFB_PAN
+ if(XGIfb_ypan) fix->ypanstep = 1;
+#endif
+ fix->ywrapstep = 0;
+ fix->line_length = xgi_video_info.video_linelength;
+ fix->mmio_start = xgi_video_info.mmio_base;
+ fix->mmio_len = XGIfb_mmio_size;
+ if(xgi_video_info.chip >= XG40)
+ fix->accel = FB_ACCEL_XGI_XABRE;
+ else
+ fix->accel = FB_ACCEL_XGI_GLAMOUR_2;
+
+
+ DEBUGPRN("end of get_fix");
+ return 0;
+}
+
+
+static struct fb_ops XGIfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = XGIfb_open,
+ .fb_release = XGIfb_release,
+ .fb_check_var = XGIfb_check_var,
+ .fb_set_par = XGIfb_set_par,
+ .fb_setcolreg = XGIfb_setcolreg,
+#ifdef XGIFB_PAN
+ .fb_pan_display = XGIfb_pan_display,
+#endif
+ .fb_blank = XGIfb_blank,
+ .fb_fillrect = fbcon_XGI_fillrect,
+ .fb_copyarea = fbcon_XGI_copyarea,
+ .fb_imageblit = cfb_imageblit,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
+ .fb_cursor = soft_cursor,
+#endif
+ .fb_sync = fbcon_XGI_sync,
+ .fb_ioctl = XGIfb_ioctl,
+// .fb_mmap = XGIfb_mmap,
+};
+
+/* ---------------- Chip generation dependent routines ---------------- */
+
+
+/* for XGI 315/550/650/740/330 */
+
+static int XGIfb_get_dram_size(void)
+{
+
+ u8 ChannelNum,tmp;
+ u8 reg = 0;
+
+ /* xorg driver sets 32MB * 1 channel */
+ if (xgi_video_info.chip == XG27)
+ outXGIIDXREG(XGISR, IND_XGI_DRAM_SIZE, 0x51);
+
+ inXGIIDXREG(XGISR, IND_XGI_DRAM_SIZE, reg);
+ switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) {
+ case XGI_DRAM_SIZE_1MB:
+ xgi_video_info.video_size = 0x100000;
+ break;
+ case XGI_DRAM_SIZE_2MB:
+ xgi_video_info.video_size = 0x200000;
+ break;
+ case XGI_DRAM_SIZE_4MB:
+ xgi_video_info.video_size = 0x400000;
+ break;
+ case XGI_DRAM_SIZE_8MB:
+ xgi_video_info.video_size = 0x800000;
+ break;
+ case XGI_DRAM_SIZE_16MB:
+ xgi_video_info.video_size = 0x1000000;
+ break;
+ case XGI_DRAM_SIZE_32MB:
+ xgi_video_info.video_size = 0x2000000;
+ break;
+ case XGI_DRAM_SIZE_64MB:
+ xgi_video_info.video_size = 0x4000000;
+ break;
+ case XGI_DRAM_SIZE_128MB:
+ xgi_video_info.video_size = 0x8000000;
+ break;
+ case XGI_DRAM_SIZE_256MB:
+ xgi_video_info.video_size = 0x10000000;
+ break;
+ default:
+ return -1;
+ }
+
+ tmp = (reg & 0x0c) >> 2;
+ switch(xgi_video_info.chip)
+ {
+ case XG20:
+ case XG21:
+ case XG27:
+ ChannelNum = 1;
+ break;
+
+ case XG42:
+ if(reg & 0x04)
+ ChannelNum = 2;
+ else
+ ChannelNum = 1;
+ break;
+
+ case XG45:
+ if(tmp == 1)
+ ChannelNum = 2;
+ else
+ if(tmp == 2)
+ ChannelNum = 3;
+ else
+ if(tmp == 3)
+ ChannelNum = 4;
+ else
+ ChannelNum = 1;
+ break;
+
+ case XG40:
+ default:
+ if(tmp == 2)
+ ChannelNum = 2;
+ else
+ if(tmp == 3)
+ ChannelNum = 3;
+ else
+ ChannelNum = 1;
+ break;
+ }
+
+
+ xgi_video_info.video_size = xgi_video_info.video_size * ChannelNum;
+ //PLiad fixed for benchmarking and fb set
+ //xgi_video_info.video_size = 0x200000;//1024x768x16
+ //xgi_video_info.video_size = 0x1000000;//benchmark
+
+ printk("XGIfb: SR14=%x DramSzie %x ChannelNum %x\n",reg,xgi_video_info.video_size ,ChannelNum );
+ return 0;
+
+}
+
+static void XGIfb_detect_VB(void)
+{
+ u8 cr32, temp=0;
+
+ xgi_video_info.TV_plug = xgi_video_info.TV_type = 0;
+
+ switch(xgi_video_info.hasVB) {
+ case HASVB_LVDS_CHRONTEL:
+ case HASVB_CHRONTEL:
+ break;
+ case HASVB_301:
+ case HASVB_302:
+// XGI_Sense30x(); //Yi-Lin TV Sense?
+ break;
+ }
+
+ inXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR32, cr32);
+
+ if ((cr32 & XGI_CRT1) && !XGIfb_crt1off)
+ XGIfb_crt1off = 0;
+ else {
+ if (cr32 & 0x5F)
+ XGIfb_crt1off = 1;
+ else
+ XGIfb_crt1off = 0;
+ }
+
+ if (XGIfb_crt2type != -1)
+ /* TW: Override with option */
+ xgi_video_info.disp_state = XGIfb_crt2type;
+ else if (cr32 & XGI_VB_TV)
+ xgi_video_info.disp_state = DISPTYPE_TV;
+ else if (cr32 & XGI_VB_LCD)
+ xgi_video_info.disp_state = DISPTYPE_LCD;
+ else if (cr32 & XGI_VB_CRT2)
+ xgi_video_info.disp_state = DISPTYPE_CRT2;
+ else
+ xgi_video_info.disp_state = 0;
+
+ if(XGIfb_tvplug != -1)
+ /* PR/TW: Override with option */
+ xgi_video_info.TV_plug = XGIfb_tvplug;
+ else if (cr32 & XGI_VB_HIVISION) {
+ xgi_video_info.TV_type = TVMODE_HIVISION;
+ xgi_video_info.TV_plug = TVPLUG_SVIDEO;
+ }
+ else if (cr32 & XGI_VB_SVIDEO)
+ xgi_video_info.TV_plug = TVPLUG_SVIDEO;
+ else if (cr32 & XGI_VB_COMPOSITE)
+ xgi_video_info.TV_plug = TVPLUG_COMPOSITE;
+ else if (cr32 & XGI_VB_SCART)
+ xgi_video_info.TV_plug = TVPLUG_SCART;
+
+ if(xgi_video_info.TV_type == 0) {
+ /* TW: PAL/NTSC changed for 650 */
+ if((xgi_video_info.chip <= XGI_315PRO) || (xgi_video_info.chip >= XGI_330)) {
+
+ inXGIIDXREG(XGICR, 0x38, temp);
+ if(temp & 0x10)
+ xgi_video_info.TV_type = TVMODE_PAL;
+ else
+ xgi_video_info.TV_type = TVMODE_NTSC;
+
+ } else {
+
+ inXGIIDXREG(XGICR, 0x79, temp);
+ if(temp & 0x20)
+ xgi_video_info.TV_type = TVMODE_PAL;
+ else
+ xgi_video_info.TV_type = TVMODE_NTSC;
+ }
+ }
+
+ /* TW: Copy forceCRT1 option to CRT1off if option is given */
+ if (XGIfb_forcecrt1 != -1) {
+ if (XGIfb_forcecrt1) XGIfb_crt1off = 0;
+ else XGIfb_crt1off = 1;
+ }
+}
+
+static void XGIfb_get_VB_type(void)
+{
+ u8 reg;
+
+ if (!XGIfb_has_VB()) {
+ inXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR37, reg);
+ switch ((reg & XGI_EXTERNAL_CHIP_MASK) >> 1) {
+ case XGI310_EXTERNAL_CHIP_LVDS:
+ xgi_video_info.hasVB = HASVB_LVDS;
+ break;
+ case XGI310_EXTERNAL_CHIP_LVDS_CHRONTEL:
+ xgi_video_info.hasVB = HASVB_LVDS_CHRONTEL;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+static int XGIfb_has_VB(void)
+{
+ u8 vb_chipid;
+
+ inXGIIDXREG(XGIPART4, 0x00, vb_chipid);
+ switch (vb_chipid) {
+ case 0x01:
+ xgi_video_info.hasVB = HASVB_301;
+ break;
+ case 0x02:
+ xgi_video_info.hasVB = HASVB_302;
+ break;
+ default:
+ xgi_video_info.hasVB = HASVB_NONE;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+/* ------------------ Sensing routines ------------------ */
+
+/* TW: Determine and detect attached devices on XGI30x */
+int
+XGIDoSense(int tempbl, int tempbh, int tempcl, int tempch)
+{
+ int temp,i;
+
+ outXGIIDXREG(XGIPART4,0x11,tempbl);
+ temp = tempbh | tempcl;
+ setXGIIDXREG(XGIPART4,0x10,0xe0,temp);
+ for(i=0; i<10; i++) XGI_LongWait(&XGI_Pr);
+ tempch &= 0x7f;
+ inXGIIDXREG(XGIPART4,0x03,temp);
+ temp ^= 0x0e;
+ temp &= tempch;
+ return(temp);
+}
+
+void
+XGI_Sense30x(void)
+{
+ u8 backupP4_0d;
+ u8 testsvhs_tempbl, testsvhs_tempbh;
+ u8 testsvhs_tempcl, testsvhs_tempch;
+ u8 testcvbs_tempbl, testcvbs_tempbh;
+ u8 testcvbs_tempcl, testcvbs_tempch;
+ u8 testvga2_tempbl, testvga2_tempbh;
+ u8 testvga2_tempcl, testvga2_tempch;
+ int myflag, result;
+
+ inXGIIDXREG(XGIPART4,0x0d,backupP4_0d);
+ outXGIIDXREG(XGIPART4,0x0d,(backupP4_0d | 0x04));
+
+
+
+ testvga2_tempbh = 0x00; testvga2_tempbl = 0xd1;
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xb9;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xb3;
+ if((XGIhw_ext.ujVBChipID != VB_CHIP_301) &&
+ (XGIhw_ext.ujVBChipID != VB_CHIP_302)) {
+ testvga2_tempbh = 0x01; testvga2_tempbl = 0x90;
+ testsvhs_tempbh = 0x01; testsvhs_tempbl = 0x6b;
+ testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x74;
+ if(XGIhw_ext.ujVBChipID == VB_CHIP_301LV ||
+ XGIhw_ext.ujVBChipID == VB_CHIP_302LV) {
+ testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
+ testsvhs_tempbh = 0x02; testsvhs_tempbl = 0x00;
+ testcvbs_tempbh = 0x01; testcvbs_tempbl = 0x00;
+ }
+ }
+ if(XGIhw_ext.ujVBChipID != VB_CHIP_301LV &&
+ XGIhw_ext.ujVBChipID != VB_CHIP_302LV) {
+ inXGIIDXREG(XGIPART4,0x01,myflag);
+ if(myflag & 0x04) {
+ testvga2_tempbh = 0x00; testvga2_tempbl = 0xfd;
+ testsvhs_tempbh = 0x00; testsvhs_tempbl = 0xdd;
+ testcvbs_tempbh = 0x00; testcvbs_tempbl = 0xee;
+ }
+ }
+ if((XGIhw_ext.ujVBChipID == VB_CHIP_301LV) ||
+ (XGIhw_ext.ujVBChipID == VB_CHIP_302LV) ) {
+ testvga2_tempbh = 0x00; testvga2_tempbl = 0x00;
+ testvga2_tempch = 0x00; testvga2_tempcl = 0x00;
+ testsvhs_tempch = 0x04; testsvhs_tempcl = 0x08;
+ testcvbs_tempch = 0x08; testcvbs_tempcl = 0x08;
+ } else {
+ testvga2_tempch = 0x0e; testvga2_tempcl = 0x08;
+ testsvhs_tempch = 0x06; testsvhs_tempcl = 0x04;
+ testcvbs_tempch = 0x08; testcvbs_tempcl = 0x04;
+ }
+
+
+ if(testvga2_tempch || testvga2_tempcl || testvga2_tempbh || testvga2_tempbl) {
+ result = XGIDoSense(testvga2_tempbl, testvga2_tempbh,
+ testvga2_tempcl, testvga2_tempch);
+ if(result) {
+ printk(KERN_INFO "XGIfb: Detected secondary VGA connection\n");
+ orXGIIDXREG(XGICR, 0x32, 0x10);
+ }
+ }
+
+ result = XGIDoSense(testsvhs_tempbl, testsvhs_tempbh,
+ testsvhs_tempcl, testsvhs_tempch);
+ if(result) {
+ printk(KERN_INFO "XGIfb: Detected TV connected to SVHS output\n");
+ /* TW: So we can be sure that there IS a SVHS output */
+ xgi_video_info.TV_plug = TVPLUG_SVIDEO;
+ orXGIIDXREG(XGICR, 0x32, 0x02);
+ }
+
+ if(!result) {
+ result = XGIDoSense(testcvbs_tempbl, testcvbs_tempbh,
+ testcvbs_tempcl, testcvbs_tempch);
+ if(result) {
+ printk(KERN_INFO "XGIfb: Detected TV connected to CVBS output\n");
+ /* TW: So we can be sure that there IS a CVBS output */
+ xgi_video_info.TV_plug = TVPLUG_COMPOSITE;
+ orXGIIDXREG(XGICR, 0x32, 0x01);
+ }
+ }
+ XGIDoSense(0, 0, 0, 0);
+
+ outXGIIDXREG(XGIPART4,0x0d,backupP4_0d);
+}
+
+
+
+/* ------------------------ Heap routines -------------------------- */
+
+static int XGIfb_heap_init(void)
+{
+ XGI_OH *poh;
+ u8 temp=0;
+
+ int agp_enabled = 1;
+ u32 agp_size;
+ unsigned long *cmdq_baseport = 0;
+ unsigned long *read_port = 0;
+ unsigned long *write_port = 0;
+ XGI_CMDTYPE cmd_type;
+#ifndef AGPOFF
+ struct agp_kern_info *agp_info;
+ struct agp_memory *agp;
+ u32 agp_phys;
+#endif
+
+/* TW: The heap start is either set manually using the "mem" parameter, or
+ * defaults as follows:
+ * -) If more than 16MB videoRAM available, let our heap start at 12MB.
+ * -) If more than 8MB videoRAM available, let our heap start at 8MB.
+ * -) If 4MB or less is available, let it start at 4MB.
+ * This is for avoiding a clash with X driver which uses the beginning
+ * of the videoRAM. To limit size of X framebuffer, use Option MaxXFBMem
+ * in XF86Config-4.
+ * The heap start can also be specified by parameter "mem" when starting the XGIfb
+ * driver. XGIfb mem=1024 lets heap starts at 1MB, etc.
+ */
+ if ((!XGIfb_mem) || (XGIfb_mem > (xgi_video_info.video_size/1024))) {
+ if (xgi_video_info.video_size > 0x1000000) {
+ xgi_video_info.heapstart = 0xD00000;
+ } else if (xgi_video_info.video_size > 0x800000) {
+ xgi_video_info.heapstart = 0x800000;
+ } else {
+ xgi_video_info.heapstart = 0x400000;
+ }
+ } else {
+ xgi_video_info.heapstart = XGIfb_mem * 1024;
+ }
+ XGIfb_heap_start =
+ (unsigned long) (xgi_video_info.video_vbase + xgi_video_info.heapstart);
+ printk(KERN_INFO "XGIfb: Memory heap starting at %dK\n",
+ (int)(xgi_video_info.heapstart / 1024));
+
+ XGIfb_heap_end = (unsigned long) xgi_video_info.video_vbase + xgi_video_info.video_size;
+ XGIfb_heap_size = XGIfb_heap_end - XGIfb_heap_start;
+
+
+
+ /* TW: Now initialize the 310 series' command queue mode.
+ * On 310/325, there are three queue modes available which
+ * are chosen by setting bits 7:5 in SR26:
+ * 1. MMIO queue mode (bit 5, 0x20). The hardware will keep
+ * track of the queue, the FIFO, command parsing and so
+ * on. This is the one comparable to the 300 series.
+ * 2. VRAM queue mode (bit 6, 0x40). In this case, one will
+ * have to do queue management himself. Register 0x85c4 will
+ * hold the location of the next free queue slot, 0x85c8
+ * is the "queue read pointer" whose way of working is
+ * unknown to me. Anyway, this mode would require a
+ * translation of the MMIO commands to some kind of
+ * accelerator assembly and writing these commands
+ * to the memory location pointed to by 0x85c4.
+ * We will not use this, as nobody knows how this
+ * "assembly" works, and as it would require a complete
+ * re-write of the accelerator code.
+ * 3. AGP queue mode (bit 7, 0x80). Works as 2., but keeps the
+ * queue in AGP memory space.
+ *
+ * SR26 bit 4 is called "Bypass H/W queue".
+ * SR26 bit 1 is called "Enable Command Queue Auto Correction"
+ * SR26 bit 0 resets the queue
+ * Size of queue memory is encoded in bits 3:2 like this:
+ * 00 (0x00) 512K
+ * 01 (0x04) 1M
+ * 10 (0x08) 2M
+ * 11 (0x0C) 4M
+ * The queue location is to be written to 0x85C0.
+ *
+ */
+ cmdq_baseport = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_PHYBASE);
+ write_port = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_WRITEPORT);
+ read_port = (unsigned long *)(xgi_video_info.mmio_vbase + MMIO_QUEUE_READPORT);
+
+ DPRINTK("AGP base: 0x%p, read: 0x%p, write: 0x%p\n", cmdq_baseport, read_port, write_port);
+
+ agp_size = COMMAND_QUEUE_AREA_SIZE;
+
+#ifndef AGPOFF
+ if (XGIfb_queuemode == AGP_CMD_QUEUE) {
+ agp_info = vmalloc(sizeof(*agp_info));
+ memset((void*)agp_info, 0x00, sizeof(*agp_info));
+ agp_copy_info(agp_info);
+
+ agp_backend_acquire();
+
+ agp = agp_allocate_memory(COMMAND_QUEUE_AREA_SIZE/PAGE_SIZE,
+ AGP_NORMAL_MEMORY);
+ if (agp == NULL) {
+ DPRINTK("XGIfb: Allocating AGP buffer failed.\n");
+ agp_enabled = 0;
+ } else {
+ if (agp_bind_memory(agp, agp->pg_start) != 0) {
+ DPRINTK("XGIfb: AGP: Failed to bind memory\n");
+ /* TODO: Free AGP memory here */
+ agp_enabled = 0;
+ } else {
+ agp_enable(0);
+ }
+ }
+ }
+#else
+ agp_enabled = 0;
+#endif
+
+ /* TW: Now select the queue mode */
+
+ if ((agp_enabled) && (XGIfb_queuemode == AGP_CMD_QUEUE)) {
+ cmd_type = AGP_CMD_QUEUE;
+ printk(KERN_INFO "XGIfb: Using AGP queue mode\n");
+/* } else if (XGIfb_heap_size >= COMMAND_QUEUE_AREA_SIZE) */
+ } else if (XGIfb_queuemode == VM_CMD_QUEUE) {
+ cmd_type = VM_CMD_QUEUE;
+ printk(KERN_INFO "XGIfb: Using VRAM queue mode\n");
+ } else {
+ printk(KERN_INFO "XGIfb: Using MMIO queue mode\n");
+ cmd_type = MMIO_CMD;
+ }
+
+ switch (agp_size) {
+ case 0x80000:
+ temp = XGI_CMD_QUEUE_SIZE_512k;
+ break;
+ case 0x100000:
+ temp = XGI_CMD_QUEUE_SIZE_1M;
+ break;
+ case 0x200000:
+ temp = XGI_CMD_QUEUE_SIZE_2M;
+ break;
+ case 0x400000:
+ temp = XGI_CMD_QUEUE_SIZE_4M;
+ break;
+ }
+
+ switch (cmd_type) {
+ case AGP_CMD_QUEUE:
+#ifndef AGPOFF
+ DPRINTK("XGIfb: AGP buffer base = 0x%lx, offset = 0x%x, size = %dK\n",
+ agp_info->aper_base, agp->physical, agp_size/1024);
+
+ agp_phys = agp_info->aper_base + agp->physical;
+
+ outXGIIDXREG(XGICR, IND_XGI_AGP_IO_PAD, 0);
+ outXGIIDXREG(XGICR, IND_XGI_AGP_IO_PAD, XGI_AGP_2X);
+
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET);
+
+ *write_port = *read_port;
+
+ temp |= XGI_AGP_CMDQUEUE_ENABLE;
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp);
+
+ *cmdq_baseport = agp_phys;
+
+ XGIfb_caps |= AGP_CMD_QUEUE_CAP;
+#endif
+ break;
+
+ case VM_CMD_QUEUE:
+ XGIfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+ XGIfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET);
+
+ *write_port = *read_port;
+
+ temp |= XGI_VRAM_CMDQUEUE_ENABLE;
+ outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp);
+
+ *cmdq_baseport = xgi_video_info.video_size - COMMAND_QUEUE_AREA_SIZE;
+
+ XGIfb_caps |= VM_CMD_QUEUE_CAP;
+
+ DPRINTK("XGIfb: VM Cmd Queue offset = 0x%lx, size is %dK\n",
+ *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
+ break;
+
+ default: /* MMIO */
+
+// printk("%s:%d - I'm here\n", __FUNCTION__, __LINE__);
+ /* TW: This previously only wrote XGI_MMIO_CMD_ENABLE
+ * to IND_XGI_CMDQUEUE_SET. I doubt that this is
+ * enough. Reserve memory in any way.
+ */
+// FIXME XGIfb_heap_end -= COMMAND_QUEUE_AREA_SIZE;
+// FIXME XGIfb_heap_size -= COMMAND_QUEUE_AREA_SIZE;
+// FIXME
+// FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_THRESHOLD, COMMAND_QUEUE_THRESHOLD);
+// FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, XGI_CMD_QUEUE_RESET);
+// FIXME
+// FIXME *write_port = *read_port;
+// FIXME
+// FIXME /* TW: Set Auto_Correction bit */
+// FIXME temp |= (XGI_MMIO_CMD_ENABLE | XGI_CMD_AUTO_CORR);
+// FIXME // FIXME outXGIIDXREG(XGISR, IND_XGI_CMDQUEUE_SET, temp);
+// FIXME
+// FIXME *cmdq_baseport = xgi_video_info.video_size - COMMAND_QUEUE_AREA_SIZE;
+// FIXME
+// FIXME XGIfb_caps |= MMIO_CMD_QUEUE_CAP;
+// FIXME
+// FIXME DPRINTK("XGIfb: MMIO Cmd Queue offset = 0x%lx, size is %dK\n",
+// FIXME *cmdq_baseport, COMMAND_QUEUE_AREA_SIZE/1024);
+ break;
+ }
+
+
+
+
+ /* TW: Now reserve memory for the HWCursor. It is always located at the very
+ top of the videoRAM, right below the TB memory area (if used). */
+ if (XGIfb_heap_size >= XGIfb_hwcursor_size) {
+ XGIfb_heap_end -= XGIfb_hwcursor_size;
+ XGIfb_heap_size -= XGIfb_hwcursor_size;
+ XGIfb_hwcursor_vbase = XGIfb_heap_end;
+
+ XGIfb_caps |= HW_CURSOR_CAP;
+
+ DPRINTK("XGIfb: Hardware Cursor start at 0x%lx, size is %dK\n",
+ XGIfb_heap_end, XGIfb_hwcursor_size/1024);
+ }
+
+ XGIfb_heap.poha_chain = NULL;
+ XGIfb_heap.poh_freelist = NULL;
+
+ poh = XGIfb_poh_new_node();
+
+ if(poh == NULL) return 1;
+
+ poh->poh_next = &XGIfb_heap.oh_free;
+ poh->poh_prev = &XGIfb_heap.oh_free;
+ poh->size = XGIfb_heap_end - XGIfb_heap_start + 1;
+ poh->offset = XGIfb_heap_start - (unsigned long) xgi_video_info.video_vbase;
+
+ DPRINTK("XGIfb: Heap start:0x%p, end:0x%p, len=%dk\n",
+ (char *) XGIfb_heap_start, (char *) XGIfb_heap_end,
+ (unsigned int) poh->size / 1024);
+
+ DPRINTK("XGIfb: First Node offset:0x%x, size:%dk\n",
+ (unsigned int) poh->offset, (unsigned int) poh->size / 1024);
+
+ XGIfb_heap.oh_free.poh_next = poh;
+ XGIfb_heap.oh_free.poh_prev = poh;
+ XGIfb_heap.oh_free.size = 0;
+ XGIfb_heap.max_freesize = poh->size;
+
+ XGIfb_heap.oh_used.poh_next = &XGIfb_heap.oh_used;
+ XGIfb_heap.oh_used.poh_prev = &XGIfb_heap.oh_used;
+ XGIfb_heap.oh_used.size = SENTINEL;
+
+ return 0;
+}
+
+static XGI_OH *XGIfb_poh_new_node(void)
+{
+ int i;
+ unsigned long cOhs;
+ XGI_OHALLOC *poha;
+ XGI_OH *poh;
+
+ if (XGIfb_heap.poh_freelist == NULL) {
+ poha = kmalloc(OH_ALLOC_SIZE, GFP_KERNEL);
+ if(!poha) return NULL;
+
+ poha->poha_next = XGIfb_heap.poha_chain;
+ XGIfb_heap.poha_chain = poha;
+
+ cOhs = (OH_ALLOC_SIZE - sizeof(XGI_OHALLOC)) / sizeof(XGI_OH) + 1;
+
+ poh = &poha->aoh[0];
+ for (i = cOhs - 1; i != 0; i--) {
+ poh->poh_next = poh + 1;
+ poh = poh + 1;
+ }
+
+ poh->poh_next = NULL;
+ XGIfb_heap.poh_freelist = &poha->aoh[0];
+ }
+
+ poh = XGIfb_heap.poh_freelist;
+ XGIfb_heap.poh_freelist = poh->poh_next;
+
+ return (poh);
+}
+
+static XGI_OH *XGIfb_poh_allocate(unsigned long size)
+{
+ XGI_OH *pohThis;
+ XGI_OH *pohRoot;
+ int bAllocated = 0;
+
+ if (size > XGIfb_heap.max_freesize) {
+ DPRINTK("XGIfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ pohThis = XGIfb_heap.oh_free.poh_next;
+
+ while (pohThis != &XGIfb_heap.oh_free) {
+ if (size <= pohThis->size) {
+ bAllocated = 1;
+ break;
+ }
+ pohThis = pohThis->poh_next;
+ }
+
+ if (!bAllocated) {
+ DPRINTK("XGIfb: Can't allocate %dk size on offscreen\n",
+ (unsigned int) size / 1024);
+ return (NULL);
+ }
+
+ if (size == pohThis->size) {
+ pohRoot = pohThis;
+ XGIfb_delete_node(pohThis);
+ } else {
+ pohRoot = XGIfb_poh_new_node();
+
+ if (pohRoot == NULL) {
+ return (NULL);
+ }
+
+ pohRoot->offset = pohThis->offset;
+ pohRoot->size = size;
+
+ pohThis->offset += size;
+ pohThis->size -= size;
+ }
+
+ XGIfb_heap.max_freesize -= size;
+
+ pohThis = &XGIfb_heap.oh_used;
+ XGIfb_insert_node(pohThis, pohRoot);
+
+ return (pohRoot);
+}
+
+static void XGIfb_delete_node(XGI_OH *poh)
+{
+ XGI_OH *poh_prev;
+ XGI_OH *poh_next;
+
+ poh_prev = poh->poh_prev;
+ poh_next = poh->poh_next;
+
+ poh_prev->poh_next = poh_next;
+ poh_next->poh_prev = poh_prev;
+
+}
+
+static void XGIfb_insert_node(XGI_OH *pohList, XGI_OH *poh)
+{
+ XGI_OH *pohTemp;
+
+ pohTemp = pohList->poh_next;
+
+ pohList->poh_next = poh;
+ pohTemp->poh_prev = poh;
+
+ poh->poh_prev = pohList;
+ poh->poh_next = pohTemp;
+}
+
+static XGI_OH *XGIfb_poh_free(unsigned long base)
+{
+ XGI_OH *pohThis;
+ XGI_OH *poh_freed;
+ XGI_OH *poh_prev;
+ XGI_OH *poh_next;
+ unsigned long ulUpper;
+ unsigned long ulLower;
+ int foundNode = 0;
+
+ poh_freed = XGIfb_heap.oh_used.poh_next;
+
+ while(poh_freed != &XGIfb_heap.oh_used) {
+ if(poh_freed->offset == base) {
+ foundNode = 1;
+ break;
+ }
+
+ poh_freed = poh_freed->poh_next;
+ }
+
+ if (!foundNode) return (NULL);
+
+ XGIfb_heap.max_freesize += poh_freed->size;
+
+ poh_prev = poh_next = NULL;
+ ulUpper = poh_freed->offset + poh_freed->size;
+ ulLower = poh_freed->offset;
+
+ pohThis = XGIfb_heap.oh_free.poh_next;
+
+ while (pohThis != &XGIfb_heap.oh_free) {
+ if (pohThis->offset == ulUpper) {
+ poh_next = pohThis;
+ }
+ else if ((pohThis->offset + pohThis->size) ==
+ ulLower) {
+ poh_prev = pohThis;
+ }
+ pohThis = pohThis->poh_next;
+ }
+
+ XGIfb_delete_node(poh_freed);
+
+ if (poh_prev && poh_next) {
+ poh_prev->size += (poh_freed->size + poh_next->size);
+ XGIfb_delete_node(poh_next);
+ XGIfb_free_node(poh_freed);
+ XGIfb_free_node(poh_next);
+ return (poh_prev);
+ }
+
+ if (poh_prev) {
+ poh_prev->size += poh_freed->size;
+ XGIfb_free_node(poh_freed);
+ return (poh_prev);
+ }
+
+ if (poh_next) {
+ poh_next->size += poh_freed->size;
+ poh_next->offset = poh_freed->offset;
+ XGIfb_free_node(poh_freed);
+ return (poh_next);
+ }
+
+ XGIfb_insert_node(&XGIfb_heap.oh_free, poh_freed);
+
+ return (poh_freed);
+}
+
+static void XGIfb_free_node(XGI_OH *poh)
+{
+ if(poh == NULL) return;
+
+ poh->poh_next = XGIfb_heap.poh_freelist;
+ XGIfb_heap.poh_freelist = poh;
+
+}
+
+void XGI_malloc(struct XGI_memreq *req)
+{
+ XGI_OH *poh;
+
+ poh = XGIfb_poh_allocate(req->size);
+
+ if(poh == NULL) {
+ req->offset = 0;
+ req->size = 0;
+ DPRINTK("XGIfb: Video RAM allocation failed\n");
+ } else {
+ DPRINTK("XGIfb: Video RAM allocation succeeded: 0x%p\n",
+ (char *) (poh->offset + (unsigned long) xgi_video_info.video_vbase));
+
+ req->offset = poh->offset;
+ req->size = poh->size;
+ }
+
+}
+
+void XGI_free(unsigned long base)
+{
+ XGI_OH *poh;
+
+ poh = XGIfb_poh_free(base);
+
+ if(poh == NULL) {
+ DPRINTK("XGIfb: XGIfb_poh_free() failed at base 0x%x\n",
+ (unsigned int) base);
+ }
+}
+
+/* --------------------- SetMode routines ------------------------- */
+
+static void XGIfb_pre_setmode(void)
+{
+ u8 cr30 = 0, cr31 = 0;
+
+ inXGIIDXREG(XGICR, 0x31, cr31);
+ cr31 &= ~0x60;
+
+ switch (xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ case DISPTYPE_CRT2:
+ cr30 = (XGI_VB_OUTPUT_CRT2 | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= XGI_DRIVER_MODE;
+ break;
+ case DISPTYPE_LCD:
+ cr30 = (XGI_VB_OUTPUT_LCD | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= XGI_DRIVER_MODE;
+ break;
+ case DISPTYPE_TV:
+ if (xgi_video_info.TV_type == TVMODE_HIVISION)
+ cr30 = (XGI_VB_OUTPUT_HIVISION | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ else if (xgi_video_info.TV_plug == TVPLUG_SVIDEO)
+ cr30 = (XGI_VB_OUTPUT_SVIDEO | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE)
+ cr30 = (XGI_VB_OUTPUT_COMPOSITE | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ else if (xgi_video_info.TV_plug == TVPLUG_SCART)
+ cr30 = (XGI_VB_OUTPUT_SCART | XGI_SIMULTANEOUS_VIEW_ENABLE);
+ cr31 |= XGI_DRIVER_MODE;
+
+ if (XGIfb_tvmode == 1 || xgi_video_info.TV_type == TVMODE_PAL)
+ cr31 |= 0x01;
+ else
+ cr31 &= ~0x01;
+ break;
+ default: /* disable CRT2 */
+ cr30 = 0x00;
+ cr31 |= (XGI_DRIVER_MODE | XGI_VB_OUTPUT_DISABLE);
+ }
+
+ outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR30, cr30);
+ outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR31, cr31);
+ outXGIIDXREG(XGICR, IND_XGI_SCRATCH_REG_CR33, (XGIfb_rate_idx & 0x0F));
+
+ if(xgi_video_info.accel) XGIfb_syncaccel();
+
+
+}
+
+static void XGIfb_post_setmode(void)
+{
+ u8 reg;
+ BOOLEAN doit = TRUE;
+#if 0 /* TW: Wrong: Is not in MMIO space, but in RAM */
+ /* Backup mode number to MMIO space */
+ if(xgi_video_info.mmio_vbase) {
+ *(volatile u8 *)(((u8*)xgi_video_info.mmio_vbase) + 0x449) = (unsigned char)XGIfb_mode_no;
+ }
+#endif
+/* outXGIIDXREG(XGISR,IND_XGI_PASSWORD,XGI_PASSWORD);
+ outXGIIDXREG(XGICR,0x13,0x00);
+ setXGIIDXREG(XGISR,0x0E,0xF0,0x01);
+*test**/
+ if (xgi_video_info.video_bpp == 8) {
+ /* TW: We can't switch off CRT1 on LVDS/Chrontel in 8bpp Modes */
+ if ((xgi_video_info.hasVB == HASVB_LVDS) || (xgi_video_info.hasVB == HASVB_LVDS_CHRONTEL)) {
+ doit = FALSE;
+ }
+ /* TW: We can't switch off CRT1 on 301B-DH in 8bpp Modes if using LCD */
+ if (xgi_video_info.disp_state & DISPTYPE_LCD) {
+ doit = FALSE;
+ }
+ }
+
+ /* TW: We can't switch off CRT1 if bridge is in slave mode */
+ if(xgi_video_info.hasVB != HASVB_NONE) {
+ inXGIIDXREG(XGIPART1, 0x00, reg);
+
+
+ if((reg & 0x50) == 0x10) {
+ doit = FALSE;
+ }
+
+ } else XGIfb_crt1off = 0;
+
+ inXGIIDXREG(XGICR, 0x17, reg);
+ if((XGIfb_crt1off) && (doit))
+ reg &= ~0x80;
+ else
+ reg |= 0x80;
+ outXGIIDXREG(XGICR, 0x17, reg);
+
+ andXGIIDXREG(XGISR, IND_XGI_RAMDAC_CONTROL, ~0x04);
+
+ if((xgi_video_info.disp_state & DISPTYPE_TV) && (xgi_video_info.hasVB == HASVB_301)) {
+
+ inXGIIDXREG(XGIPART4, 0x01, reg);
+
+ if(reg < 0xB0) { /* Set filter for XGI301 */
+
+ switch (xgi_video_info.video_width) {
+ case 320:
+ filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 4 : 12;
+ break;
+ case 640:
+ filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 5 : 13;
+ break;
+ case 720:
+ filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 6 : 14;
+ break;
+ case 800:
+ filter_tb = (xgi_video_info.TV_type == TVMODE_NTSC) ? 7 : 15;
+ break;
+ default:
+ filter = -1;
+ break;
+ }
+
+ orXGIIDXREG(XGIPART1, XGIfb_CRT2_write_enable, 0x01);
+
+ if(xgi_video_info.TV_type == TVMODE_NTSC) {
+
+ andXGIIDXREG(XGIPART2, 0x3a, 0x1f);
+
+ if (xgi_video_info.TV_plug == TVPLUG_SVIDEO) {
+
+ andXGIIDXREG(XGIPART2, 0x30, 0xdf);
+
+ } else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE) {
+
+ orXGIIDXREG(XGIPART2, 0x30, 0x20);
+
+ switch (xgi_video_info.video_width) {
+ case 640:
+ outXGIIDXREG(XGIPART2, 0x35, 0xEB);
+ outXGIIDXREG(XGIPART2, 0x36, 0x04);
+ outXGIIDXREG(XGIPART2, 0x37, 0x25);
+ outXGIIDXREG(XGIPART2, 0x38, 0x18);
+ break;
+ case 720:
+ outXGIIDXREG(XGIPART2, 0x35, 0xEE);
+ outXGIIDXREG(XGIPART2, 0x36, 0x0C);
+ outXGIIDXREG(XGIPART2, 0x37, 0x22);
+ outXGIIDXREG(XGIPART2, 0x38, 0x08);
+ break;
+ case 800:
+ outXGIIDXREG(XGIPART2, 0x35, 0xEB);
+ outXGIIDXREG(XGIPART2, 0x36, 0x15);
+ outXGIIDXREG(XGIPART2, 0x37, 0x25);
+ outXGIIDXREG(XGIPART2, 0x38, 0xF6);
+ break;
+ }
+ }
+
+ } else if(xgi_video_info.TV_type == TVMODE_PAL) {
+
+ andXGIIDXREG(XGIPART2, 0x3A, 0x1F);
+
+ if (xgi_video_info.TV_plug == TVPLUG_SVIDEO) {
+
+ andXGIIDXREG(XGIPART2, 0x30, 0xDF);
+
+ } else if (xgi_video_info.TV_plug == TVPLUG_COMPOSITE) {
+
+ orXGIIDXREG(XGIPART2, 0x30, 0x20);
+
+ switch (xgi_video_info.video_width) {
+ case 640:
+ outXGIIDXREG(XGIPART2, 0x35, 0xF1);
+ outXGIIDXREG(XGIPART2, 0x36, 0xF7);
+ outXGIIDXREG(XGIPART2, 0x37, 0x1F);
+ outXGIIDXREG(XGIPART2, 0x38, 0x32);
+ break;
+ case 720:
+ outXGIIDXREG(XGIPART2, 0x35, 0xF3);
+ outXGIIDXREG(XGIPART2, 0x36, 0x00);
+ outXGIIDXREG(XGIPART2, 0x37, 0x1D);
+ outXGIIDXREG(XGIPART2, 0x38, 0x20);
+ break;
+ case 800:
+ outXGIIDXREG(XGIPART2, 0x35, 0xFC);
+ outXGIIDXREG(XGIPART2, 0x36, 0xFB);
+ outXGIIDXREG(XGIPART2, 0x37, 0x14);
+ outXGIIDXREG(XGIPART2, 0x38, 0x2A);
+ break;
+ }
+ }
+ }
+
+ if ((filter >= 0) && (filter <=7)) {
+ DPRINTK("FilterTable[%d]-%d: %02x %02x %02x %02x\n", filter_tb, filter,
+ XGI_TV_filter[filter_tb].filter[filter][0],
+ XGI_TV_filter[filter_tb].filter[filter][1],
+ XGI_TV_filter[filter_tb].filter[filter][2],
+ XGI_TV_filter[filter_tb].filter[filter][3]
+ );
+ outXGIIDXREG(XGIPART2, 0x35, (XGI_TV_filter[filter_tb].filter[filter][0]));
+ outXGIIDXREG(XGIPART2, 0x36, (XGI_TV_filter[filter_tb].filter[filter][1]));
+ outXGIIDXREG(XGIPART2, 0x37, (XGI_TV_filter[filter_tb].filter[filter][2]));
+ outXGIIDXREG(XGIPART2, 0x38, (XGI_TV_filter[filter_tb].filter[filter][3]));
+ }
+
+ }
+
+ }
+
+}
+
+#ifndef MODULE
+XGIINITSTATIC int __init XGIfb_setup(char *options)
+{
+ char *this_opt;
+
+
+
+ xgi_video_info.refresh_rate = 0;
+
+ printk(KERN_INFO "XGIfb: Options %s\n", options);
+
+ if (!options || !*options)
+ return 0;
+
+ while((this_opt = strsep(&options, ",")) != NULL) {
+
+ if (!*this_opt) continue;
+
+ if (!strncmp(this_opt, "mode:", 5)) {
+ XGIfb_search_mode(this_opt + 5);
+ } else if (!strncmp(this_opt, "vesa:", 5)) {
+ XGIfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
+ } else if (!strncmp(this_opt, "mode:", 5)) {
+ XGIfb_search_mode(this_opt + 5);
+ } else if (!strncmp(this_opt, "vesa:", 5)) {
+ XGIfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0));
+ } else if (!strncmp(this_opt, "vrate:", 6)) {
+ xgi_video_info.refresh_rate = simple_strtoul(this_opt + 6, NULL, 0);
+ } else if (!strncmp(this_opt, "rate:", 5)) {
+ xgi_video_info.refresh_rate = simple_strtoul(this_opt + 5, NULL, 0);
+ } else if (!strncmp(this_opt, "off", 3)) {
+ XGIfb_off = 1;
+ } else if (!strncmp(this_opt, "crt1off", 7)) {
+ XGIfb_crt1off = 1;
+ } else if (!strncmp(this_opt, "filter:", 7)) {
+ filter = (int)simple_strtoul(this_opt + 7, NULL, 0);
+ } else if (!strncmp(this_opt, "forcecrt2type:", 14)) {
+ XGIfb_search_crt2type(this_opt + 14);
+ } else if (!strncmp(this_opt, "forcecrt1:", 10)) {
+ XGIfb_forcecrt1 = (int)simple_strtoul(this_opt + 10, NULL, 0);
+ } else if (!strncmp(this_opt, "tvmode:",7)) {
+ XGIfb_search_tvstd(this_opt + 7);
+ } else if (!strncmp(this_opt, "tvstandard:",11)) {
+ XGIfb_search_tvstd(this_opt + 7);
+ } else if (!strncmp(this_opt, "mem:",4)) {
+ XGIfb_mem = simple_strtoul(this_opt + 4, NULL, 0);
+ } else if (!strncmp(this_opt, "dstn", 4)) {
+ enable_dstn = 1;
+ /* TW: DSTN overrules forcecrt2type */
+ XGIfb_crt2type = DISPTYPE_LCD;
+ } else if (!strncmp(this_opt, "queuemode:", 10)) {
+ XGIfb_search_queuemode(this_opt + 10);
+ } else if (!strncmp(this_opt, "pdc:", 4)) {
+ XGIfb_pdc = simple_strtoul(this_opt + 4, NULL, 0);
+ if(XGIfb_pdc & ~0x3c) {
+ printk(KERN_INFO "XGIfb: Illegal pdc parameter\n");
+ XGIfb_pdc = 0;
+ }
+ } else if (!strncmp(this_opt, "noaccel", 7)) {
+ XGIfb_accel = 0;
+ } else if (!strncmp(this_opt, "noypan", 6)) {
+ XGIfb_ypan = 0;
+ } else if (!strncmp(this_opt, "userom:", 7)) {
+ XGIfb_userom = (int)simple_strtoul(this_opt + 7, NULL, 0);
+// } else if (!strncmp(this_opt, "useoem:", 7)) {
+// XGIfb_useoem = (int)simple_strtoul(this_opt + 7, NULL, 0);
+ } else {
+ XGIfb_search_mode(this_opt);
+// printk(KERN_INFO "XGIfb: Invalid option %s\n", this_opt);
+ }
+
+ /* TW: Acceleration only with MMIO mode */
+ if((XGIfb_queuemode != -1) && (XGIfb_queuemode != MMIO_CMD)) {
+ XGIfb_ypan = 0;
+ XGIfb_accel = 0;
+ }
+ /* TW: Panning only with acceleration */
+ if(XGIfb_accel == 0) XGIfb_ypan = 0;
+
+ }
+ printk("\nxgifb: outa xgifb_setup 3450");
+ return 0;
+}
+#endif
+
+static unsigned char VBIOS_BUF[65535];
+
+unsigned char* attempt_map_rom(struct pci_dev *dev,void *copy_address)
+{
+ u32 rom_size = 0;
+ u32 rom_address = 0;
+ int j;
+
+ /* Get the size of the expansion rom */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0xFFFFFFFF);
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &rom_size);
+ if ((rom_size & 0x01) == 0)
+ {
+ printk("No ROM\n");
+ return NULL;
+ }
+
+ rom_size &= 0xFFFFF800;
+ rom_size = (~rom_size)+1;
+
+ rom_address = pci_resource_start(dev, 0);
+ if (rom_address == 0 || rom_address == 0xFFFFFFF0)
+ {
+ printk("No suitable rom address found\n"); return NULL;
+ }
+
+ printk("ROM Size is %dK, Address is %x\n", rom_size/1024, rom_address);
+
+ /* Map ROM */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, rom_address | PCI_ROM_ADDRESS_ENABLE);
+
+ /* memcpy(copy_address, rom_address, rom_size); */
+ {
+ unsigned char *virt_addr = ioremap(rom_address, 0x8000000);
+
+ unsigned char *from = (unsigned char *)virt_addr;
+ unsigned char *to = (unsigned char *)copy_address;
+ for (j=0; j<65536 /*rom_size*/; j++) *to++ = *from++;
+ }
+
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+
+ printk("Copy is done\n");
+
+ return copy_address;
+}
+
+int __devinit xgifb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ u16 reg16;
+ u8 reg, reg1;
+ u8 CR48,CR38;
+ if (XGIfb_off)
+ return -ENXIO;
+
+ XGIfb_registered = 0;
+
+ memset(&XGIhw_ext, 0, sizeof(HW_DEVICE_EXTENSION));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+ fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);
+ if(!fb_info) return -ENOMEM;
+#else
+ XGI_fb_info = kmalloc( sizeof(struct fb_info), GFP_KERNEL);
+ if(!XGI_fb_info) return -ENOMEM;
+ memset(XGI_fb_info, 0, sizeof(struct fb_info));
+#endif
+
+ xgi_video_info.chip_id = pdev->device;
+ pci_read_config_byte(pdev, PCI_REVISION_ID,&xgi_video_info.revision_id);
+ pci_read_config_word(pdev, PCI_COMMAND, &reg16);
+ XGIhw_ext.jChipRevision = xgi_video_info.revision_id;
+ XGIvga_enabled = reg16 & 0x01;
+
+ xgi_video_info.pcibus = pdev->bus->number;
+ xgi_video_info.pcislot = PCI_SLOT(pdev->devfn);
+ xgi_video_info.pcifunc = PCI_FUNC(pdev->devfn);
+ xgi_video_info.subsysvendor = pdev->subsystem_vendor;
+ xgi_video_info.subsysdevice = pdev->subsystem_device;
+
+ xgi_video_info.video_base = pci_resource_start(pdev, 0);
+ xgi_video_info.mmio_base = pci_resource_start(pdev, 1);
+ XGIfb_mmio_size = pci_resource_len(pdev, 1);
+ xgi_video_info.vga_base = pci_resource_start(pdev, 2) + 0x30;
+ XGIhw_ext.pjIOAddress = (PUCHAR)xgi_video_info.vga_base;
+ //XGI_Pr.RelIO = ioremap(pci_resource_start(pdev, 2), 128) + 0x30;
+ printk("XGIfb: Relocate IO address: %lx [%08lx] \n", (unsigned long)pci_resource_start(pdev, 2), XGI_Pr.RelIO);
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ XGIRegInit(&XGI_Pr, (ULONG)XGIhw_ext.pjIOAddress);
+
+ outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+ inXGIIDXREG(XGISR, IND_XGI_PASSWORD, reg1);
+
+ if(reg1 != 0xa1) /*I/O error */
+ {
+ printk("\nXGIfb: I/O error!!!");
+ return -EIO;
+ }
+
+ switch (xgi_video_info.chip_id) {
+ case PCI_DEVICE_ID_XG_20:
+ orXGIIDXREG(XGICR, Index_CR_GPIO_Reg3, GPIOG_EN);
+ inXGIIDXREG(XGICR, Index_CR_GPIO_Reg1, CR48);
+ if (CR48&GPIOG_READ)
+ xgi_video_info.chip = XG21;
+ else
+ xgi_video_info.chip = XG20;
+ XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+ XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315;
+ break;
+ case PCI_DEVICE_ID_XG_40:
+ xgi_video_info.chip = XG40;
+ XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+ XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315;
+ break;
+ case PCI_DEVICE_ID_XG_41:
+ xgi_video_info.chip = XG41;
+ XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+ XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315;
+ break;
+ case PCI_DEVICE_ID_XG_42:
+ xgi_video_info.chip = XG42;
+ XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+ XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315;
+ break;
+ case PCI_DEVICE_ID_XG_27:
+ xgi_video_info.chip = XG27;
+ XGIfb_hwcursor_size = HW_CURSOR_AREA_SIZE_315 * 2;
+ XGIfb_CRT2_write_enable = IND_XGI_CRT2_WRITE_ENABLE_315;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ printk("XGIfb:chipid = %x\n",xgi_video_info.chip);
+ XGIhw_ext.jChipType = xgi_video_info.chip;
+
+ switch (xgi_video_info.chip) {
+ case XG40:
+ case XG41:
+ case XG42:
+ case XG45:
+ case XG20:
+ case XG21:
+ case XG27:
+ XGIhw_ext.bIntegratedMMEnabled = TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+
+ XGIhw_ext.pDevice = NULL;
+ if ((xgi_video_info.chip == XG21) || (XGIfb_userom))
+ {
+ XGIhw_ext.pjVirtualRomBase = attempt_map_rom(pdev, VBIOS_BUF);
+
+ if(XGIhw_ext.pjVirtualRomBase)
+ printk(KERN_INFO "XGIfb: Video ROM found and mapped to %p\n",XGIhw_ext.pjVirtualRomBase);
+ else
+ printk(KERN_INFO "XGIfb: Video ROM not found\n");
+ } else {
+ XGIhw_ext.pjVirtualRomBase = NULL;
+ printk(KERN_INFO "XGIfb: Video ROM usage disabled\n");
+ }
+ XGIhw_ext.pjCustomizedROMImage = NULL;
+ XGIhw_ext.bSkipDramSizing = 0;
+ XGIhw_ext.pQueryVGAConfigSpace = &XGIfb_query_VGA_config_space;
+// XGIhw_ext.pQueryNorthBridgeSpace = &XGIfb_query_north_bridge_space;
+ strcpy(XGIhw_ext.szVBIOSVer, "0.84");
+
+
+ XGIhw_ext.pSR = vmalloc(sizeof(XGI_DSReg) * SR_BUFFER_SIZE);
+ if (XGIhw_ext.pSR == NULL)
+ {
+ printk(KERN_ERR "XGIfb: Fatal error: Allocating SRReg space failed.\n");
+ return -ENODEV;
+ }
+ XGIhw_ext.pSR[0].jIdx = XGIhw_ext.pSR[0].jVal = 0xFF;
+
+ XGIhw_ext.pCR = vmalloc(sizeof(XGI_DSReg) * CR_BUFFER_SIZE);
+ if (XGIhw_ext.pCR == NULL)
+ {
+ vfree(XGIhw_ext.pSR);
+ printk(KERN_ERR "XGIfb: Fatal error: Allocating CRReg space failed.\n");
+ return -ENODEV;
+ }
+ XGIhw_ext.pCR[0].jIdx = XGIhw_ext.pCR[0].jVal = 0xFF;
+
+
+
+
+ if (!XGIvga_enabled)
+ {
+ /* Mapping Max FB Size for 315 Init */
+ XGIhw_ext.pjVideoMemoryAddress = ioremap(xgi_video_info.video_base, 0x10000000);
+ if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF))
+ {
+#ifdef LINUXBIOS
+ printk("XGIfb: XGIInit() ...");
+ /* XGIInitNewt for LINUXBIOS only */
+ if(XGIInitNew(&XGIhw_ext))
+ {
+ printk("OK\n");
+ }
+ else
+ {
+ printk("Fail\n");
+ }
+#endif
+
+ outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+
+
+ }
+ }
+#ifdef LINUXBIOS
+ else
+ {
+ XGIhw_ext.pjVideoMemoryAddress = ioremap(xgi_video_info.video_base, 0x10000000);
+ if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF))
+ {
+
+ outXGIIDXREG(XGISR, IND_XGI_PASSWORD, XGI_PASSWORD);
+
+ // yilin Because no VBIOS DRAM Sizing, Dram size will error.
+ // Set SR13 ,14 temporarily for UDtech
+ outXGIIDXREG(XGISR, 0x13, 0x45);
+ outXGIIDXREG(XGISR, 0x14, 0x51);
+
+
+ }
+ }
+#endif
+ if (XGIfb_get_dram_size())
+ {
+ vfree(XGIhw_ext.pSR);
+ vfree(XGIhw_ext.pCR);
+ printk(KERN_INFO "XGIfb: Fatal error: Unable to determine RAM size.\n");
+ return -ENODEV;
+ }
+
+
+
+ if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF))
+ {
+ /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */
+ orXGIIDXREG(XGISR, IND_XGI_PCI_ADDRESS_SET, (XGI_PCI_ADDR_ENABLE | XGI_MEM_MAP_IO_ENABLE));
+ /* Enable 2D accelerator engine */
+ orXGIIDXREG(XGISR, IND_XGI_MODULE_ENABLE, XGI_ENABLE_2D);
+ }
+
+ XGIhw_ext.ulVideoMemorySize = xgi_video_info.video_size;
+
+ if (!request_mem_region(xgi_video_info.video_base, xgi_video_info.video_size, "XGIfb FB"))
+ { printk("unable request memory size %x",xgi_video_info.video_size);
+ printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve frame buffer memory\n");
+ printk(KERN_ERR "XGIfb: Is there another framebuffer driver active?\n");
+ vfree(XGIhw_ext.pSR);
+ vfree(XGIhw_ext.pCR);
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(xgi_video_info.mmio_base, XGIfb_mmio_size, "XGIfb MMIO"))
+ {
+ printk(KERN_ERR "XGIfb: Fatal error: Unable to reserve MMIO region\n");
+ release_mem_region(xgi_video_info.video_base, xgi_video_info.video_size);
+ vfree(XGIhw_ext.pSR);
+ vfree(XGIhw_ext.pCR);
+ return -ENODEV;
+ }
+
+ xgi_video_info.video_vbase = XGIhw_ext.pjVideoMemoryAddress =
+ ioremap(xgi_video_info.video_base, xgi_video_info.video_size);
+ xgi_video_info.mmio_vbase = ioremap(xgi_video_info.mmio_base, XGIfb_mmio_size);
+
+ printk(KERN_INFO "XGIfb: Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n",
+ xgi_video_info.video_base, xgi_video_info.video_vbase,xgi_video_info.video_size / 1024);
+
+ printk(KERN_INFO "XGIfb: MMIO at 0x%lx, mapped to 0x%p, size %ldk\n",
+ xgi_video_info.mmio_base, xgi_video_info.mmio_vbase,XGIfb_mmio_size / 1024);
+ printk("XGIfb: XGIInitNew() ...");
+ if(XGIInitNew(&XGIhw_ext))
+ {
+ printk("OK\n");
+ }
+ else
+ {
+ printk("Fail\n");
+ }
+
+ if(XGIfb_heap_init())
+ {
+ printk(KERN_WARNING "XGIfb: Failed to initialize offscreen memory heap\n");
+ }
+
+
+ xgi_video_info.mtrr = (unsigned int) 0;
+
+ if((xgifb_mode_idx < 0) || ((XGIbios_mode[xgifb_mode_idx].mode_no) != 0xFF))
+ {
+ xgi_video_info.hasVB = HASVB_NONE;
+ if((xgi_video_info.chip == XG20)||(xgi_video_info.chip == XG27))
+ xgi_video_info.hasVB = HASVB_NONE;
+ else if(xgi_video_info.chip == XG21) {
+ inXGIIDXREG(XGICR,0x38,CR38);
+ if ((CR38&0xE0) == 0xC0) {
+ xgi_video_info.disp_state = DISPTYPE_LCD;
+ if (!XGIfb_GetXG21LVDSData()) {
+ int m;
+ for (m=0; m < sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct); m++) {
+ if ((XGI21_LCDCapList[m].LVDSHDE == XGIbios_mode[xgifb_mode_idx].xres) &&
+ (XGI21_LCDCapList[m].LVDSVDE == XGIbios_mode[xgifb_mode_idx].yres)) {
+ XGINew_SetReg1( XGI_Pr.P3d4 , 0x36, m) ;
+ }
+ }
+ }
+ }
+ else if ((CR38&0xE0) == 0x60)
+ xgi_video_info.hasVB = HASVB_CHRONTEL ;
+ else
+ xgi_video_info.hasVB = HASVB_NONE;
+ }
+ else
+ XGIfb_get_VB_type();
+
+ XGIhw_ext.ujVBChipID = VB_CHIP_UNKNOWN;
+
+ XGIhw_ext.ulExternalChip = 0;
+
+ switch (xgi_video_info.hasVB) {
+ case HASVB_301:
+ inXGIIDXREG(XGIPART4, 0x01, reg);
+ if (reg >= 0xE0) {
+ XGIhw_ext.ujVBChipID = VB_CHIP_302LV;
+ printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg);
+ } else if (reg >= 0xD0) {
+ XGIhw_ext.ujVBChipID = VB_CHIP_301LV;
+ printk(KERN_INFO "XGIfb: XGI301LV bridge detected (revision 0x%02x)\n",reg);
+ }
+ /* else if (reg >= 0xB0) {
+ XGIhw_ext.ujVBChipID = VB_CHIP_301B;
+ inXGIIDXREG(XGIPART4,0x23,reg1);
+ printk("XGIfb: XGI301B bridge detected\n");
+ }*/
+ else {
+ XGIhw_ext.ujVBChipID = VB_CHIP_301;
+ printk("XGIfb: XGI301 bridge detected\n");
+ }
+ break;
+ case HASVB_302:
+ inXGIIDXREG(XGIPART4, 0x01, reg);
+ if (reg >= 0xE0) {
+ XGIhw_ext.ujVBChipID = VB_CHIP_302LV;
+ printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg);
+ } else if (reg >= 0xD0) {
+ XGIhw_ext.ujVBChipID = VB_CHIP_301LV;
+ printk(KERN_INFO "XGIfb: XGI302LV bridge detected (revision 0x%02x)\n",reg);
+ } else if (reg >= 0xB0) {
+ inXGIIDXREG(XGIPART4,0x23,reg1);
+
+ XGIhw_ext.ujVBChipID = VB_CHIP_302B;
+
+ } else {
+ XGIhw_ext.ujVBChipID = VB_CHIP_302;
+ printk(KERN_INFO "XGIfb: XGI302 bridge detected\n");
+ }
+ break;
+ case HASVB_LVDS:
+ XGIhw_ext.ulExternalChip = 0x1;
+ printk(KERN_INFO "XGIfb: LVDS transmitter detected\n");
+ break;
+ case HASVB_TRUMPION:
+ XGIhw_ext.ulExternalChip = 0x2;
+ printk(KERN_INFO "XGIfb: Trumpion Zurac LVDS scaler detected\n");
+ break;
+ case HASVB_CHRONTEL:
+ XGIhw_ext.ulExternalChip = 0x4;
+ printk(KERN_INFO "XGIfb: Chrontel TV encoder detected\n");
+ break;
+ case HASVB_LVDS_CHRONTEL:
+ XGIhw_ext.ulExternalChip = 0x5;
+ printk(KERN_INFO "XGIfb: LVDS transmitter and Chrontel TV encoder detected\n");
+ break;
+ default:
+ printk(KERN_INFO "XGIfb: No or unknown bridge type detected\n");
+ break;
+ }
+
+ if (xgi_video_info.hasVB != HASVB_NONE) {
+ XGIfb_detect_VB();
+ }
+
+ if (xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ if (XGIfb_crt1off)
+ xgi_video_info.disp_state |= DISPMODE_SINGLE;
+ else
+ xgi_video_info.disp_state |= (DISPMODE_MIRROR | DISPTYPE_CRT1);
+ } else {
+ xgi_video_info.disp_state = DISPMODE_SINGLE | DISPTYPE_CRT1;
+ }
+
+ if (xgi_video_info.disp_state & DISPTYPE_LCD) {
+ if (!enable_dstn) {
+ inXGIIDXREG(XGICR, IND_XGI_LCD_PANEL, reg);
+ reg &= 0x0f;
+ XGIhw_ext.ulCRT2LCDType = XGI310paneltype[reg];
+
+ } else {
+ // TW: FSTN/DSTN
+ XGIhw_ext.ulCRT2LCDType = LCD_320x480;
+ }
+ }
+
+ XGIfb_detectedpdc = 0;
+
+ XGIfb_detectedlcda = 0xff;
+#ifndef LINUXBIOS
+
+ /* TW: Try to find about LCDA */
+
+ if((XGIhw_ext.ujVBChipID == VB_CHIP_302B) ||
+ (XGIhw_ext.ujVBChipID == VB_CHIP_301LV) ||
+ (XGIhw_ext.ujVBChipID == VB_CHIP_302LV))
+ {
+ int tmp;
+ inXGIIDXREG(XGICR,0x34,tmp);
+ if(tmp <= 0x13)
+ {
+ // Currently on LCDA? (Some BIOSes leave CR38)
+ inXGIIDXREG(XGICR,0x38,tmp);
+ if((tmp & 0x03) == 0x03)
+ {
+// XGI_Pr.XGI_UseLCDA = TRUE;
+ }else
+ {
+ // Currently on LCDA? (Some newer BIOSes set D0 in CR35)
+ inXGIIDXREG(XGICR,0x35,tmp);
+ if(tmp & 0x01)
+ {
+// XGI_Pr.XGI_UseLCDA = TRUE;
+ }else
+ {
+ inXGIIDXREG(XGICR,0x30,tmp);
+ if(tmp & 0x20)
+ {
+ inXGIIDXREG(XGIPART1,0x13,tmp);
+ if(tmp & 0x04)
+ {
+// XGI_Pr.XGI_UseLCDA = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+
+#endif
+
+ if (xgifb_mode_idx >= 0)
+ xgifb_mode_idx = XGIfb_validate_mode(xgifb_mode_idx);
+
+ if (xgifb_mode_idx < 0) {
+ switch (xgi_video_info.disp_state & DISPTYPE_DISP2) {
+ case DISPTYPE_LCD:
+ xgifb_mode_idx = DEFAULT_LCDMODE;
+ if (xgi_video_info.chip == XG21)
+ {
+ xgifb_mode_idx = XGIfb_GetXG21DefaultLVDSModeIdx();
+ }
+ break;
+ case DISPTYPE_TV:
+ xgifb_mode_idx = DEFAULT_TVMODE;
+ break;
+ default:
+ xgifb_mode_idx = DEFAULT_MODE;
+ break;
+ }
+ }
+
+ XGIfb_mode_no = XGIbios_mode[xgifb_mode_idx].mode_no;
+
+
+ if( xgi_video_info.refresh_rate == 0)
+ xgi_video_info.refresh_rate = 60; /*yilin set default refresh rate */
+ if(XGIfb_search_refresh_rate(xgi_video_info.refresh_rate) == 0)
+ {
+ XGIfb_rate_idx = XGIbios_mode[xgifb_mode_idx].rate_idx;
+ xgi_video_info.refresh_rate = 60;
+ }
+
+ xgi_video_info.video_bpp = XGIbios_mode[xgifb_mode_idx].bpp;
+ xgi_video_info.video_vwidth = xgi_video_info.video_width = XGIbios_mode[xgifb_mode_idx].xres;
+ xgi_video_info.video_vheight = xgi_video_info.video_height = XGIbios_mode[xgifb_mode_idx].yres;
+ xgi_video_info.org_x = xgi_video_info.org_y = 0;
+ xgi_video_info.video_linelength = xgi_video_info.video_width * (xgi_video_info.video_bpp >> 3);
+ switch(xgi_video_info.video_bpp) {
+ case 8:
+ xgi_video_info.DstColor = 0x0000;
+ xgi_video_info.XGI310_AccelDepth = 0x00000000;
+ xgi_video_info.video_cmap_len = 256;
+ break;
+ case 16:
+ xgi_video_info.DstColor = 0x8000;
+ xgi_video_info.XGI310_AccelDepth = 0x00010000;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ case 32:
+ xgi_video_info.DstColor = 0xC000;
+ xgi_video_info.XGI310_AccelDepth = 0x00020000;
+ xgi_video_info.video_cmap_len = 16;
+ break;
+ default:
+ xgi_video_info.video_cmap_len = 16;
+ printk(KERN_INFO "XGIfb: Unsupported depth %d", xgi_video_info.video_bpp);
+ break;
+ }
+
+
+
+ printk(KERN_INFO "XGIfb: Default mode is %dx%dx%d (%dHz)\n",
+ xgi_video_info.video_width, xgi_video_info.video_height, xgi_video_info.video_bpp,
+ xgi_video_info.refresh_rate);
+
+ default_var.xres = default_var.xres_virtual = xgi_video_info.video_width;
+ default_var.yres = default_var.yres_virtual = xgi_video_info.video_height;
+ default_var.bits_per_pixel = xgi_video_info.video_bpp;
+
+ XGIfb_bpp_to_var(&default_var);
+
+ default_var.pixclock = (u32) (1000000000 /
+ XGIfb_mode_rate_to_dclock(&XGI_Pr, &XGIhw_ext,
+ XGIfb_mode_no, XGIfb_rate_idx));
+
+ if(XGIfb_mode_rate_to_ddata(&XGI_Pr, &XGIhw_ext,
+ XGIfb_mode_no, XGIfb_rate_idx,
+ &default_var.left_margin, &default_var.right_margin,
+ &default_var.upper_margin, &default_var.lower_margin,
+ &default_var.hsync_len, &default_var.vsync_len,
+ &default_var.sync, &default_var.vmode)) {
+
+ if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
+ default_var.yres <<= 1;
+ default_var.yres_virtual <<= 1;
+ } else if((default_var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE) {
+ default_var.pixclock >>= 1;
+ default_var.yres >>= 1;
+ default_var.yres_virtual >>= 1;
+ }
+
+ }
+
+
+#if 0
+#ifdef XGIFB_PAN
+ if(XGIfb_ypan) {
+ default_var.yres_virtual =
+ xgi_video_info.heapstart / (default_var.xres * (default_var.bits_per_pixel >> 3));
+ if(default_var.yres_virtual <= default_var.yres) {
+ default_var.yres_virtual = default_var.yres;
+ }
+ }
+#endif
+#endif
+
+
+ xgi_video_info.accel = 0;
+ if(XGIfb_accel) {
+ xgi_video_info.accel = -1;
+ default_var.accel_flags |= FB_ACCELF_TEXT;
+ XGIfb_initaccel();
+ }
+
+ fb_info->flags = FBINFO_FLAG_DEFAULT;
+ fb_info->var = default_var;
+ fb_info->fix = XGIfb_fix;
+ fb_info->par = &xgi_video_info;
+ fb_info->screen_base = xgi_video_info.video_vbase;
+ fb_info->fbops = &XGIfb_ops;
+ XGIfb_get_fix(&fb_info->fix, -1, fb_info);
+ fb_info->pseudo_palette = pseudo_palette;
+
+ fb_alloc_cmap(&fb_info->cmap, 256 , 0);
+
+
+#ifdef CONFIG_MTRR
+ xgi_video_info.mtrr = mtrr_add((unsigned int) xgi_video_info.video_base,
+ (unsigned int) xgi_video_info.video_size,
+ MTRR_TYPE_WRCOMB, 1);
+ if(xgi_video_info.mtrr) {
+ printk(KERN_INFO "XGIfb: Added MTRRs\n");
+ }
+#endif
+
+ if(register_framebuffer(fb_info) < 0)
+ {
+ return -EINVAL;
+ }
+
+ XGIfb_registered = 1;
+
+ printk(KERN_INFO "XGIfb: Installed XGIFB_GET_INFO ioctl (%x)\n", XGIFB_GET_INFO);
+
+/* printk(KERN_INFO "XGIfb: 2D acceleration is %s, scrolling mode %s\n",
+ XGIfb_accel ? "enabled" : "disabled",
+ XGIfb_ypan ? "ypan" : "redraw");
+*/
+ printk(KERN_INFO "fb%d: %s frame buffer device, Version %d.%d.%02d\n",
+ fb_info->node, myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+
+
+ }
+
+ dumpVGAReg();
+
+ return 0;
+}
+
+
+/*****************************************************/
+/* PCI DEVICE HANDLING */
+/*****************************************************/
+
+static void __devexit xgifb_remove(struct pci_dev *pdev)
+{
+ /* Unregister the framebuffer */
+// if(xgi_video_info.registered) {
+ unregister_framebuffer(fb_info);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
+ framebuffer_release(fb_info);
+#else
+ kfree(fb_info);
+#endif
+// }
+
+ pci_set_drvdata(pdev, NULL);
+
+};
+
+static struct pci_driver xgifb_driver = {
+ .name = "xgifb",
+ .id_table = xgifb_pci_table,
+ .probe = xgifb_probe,
+ .remove = __devexit_p(xgifb_remove)
+};
+
+XGIINITSTATIC int __init xgifb_init(void)
+{
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("xgifb", &option))
+ return -ENODEV;
+ XGIfb_setup(option);
+#endif
+#endif
+ return(pci_register_driver(&xgifb_driver));
+}
+
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
+#ifndef MODULE
+module_init(xgifb_init);
+#endif
+#endif
+
+/*****************************************************/
+/* MODULE */
+/*****************************************************/
+
+#ifdef MODULE
+
+static char *mode = NULL;
+static int vesa = 0;
+static unsigned int rate = 0;
+static unsigned int crt1off = 1;
+static unsigned int mem = 0;
+static char *forcecrt2type = NULL;
+static int forcecrt1 = -1;
+static int pdc = -1;
+static int pdc1 = -1;
+static int noaccel = -1;
+static int noypan = -1;
+static int nomax = -1;
+static int userom = -1;
+static int useoem = -1;
+static char *tvstandard = NULL;
+static int nocrt2rate = 0;
+static int scalelcd = -1;
+static char *specialtiming = NULL;
+static int lvdshl = -1;
+static int tvxposoffset = 0, tvyposoffset = 0;
+#if !defined(__i386__) && !defined(__x86_64__)
+static int resetcard = 0;
+static int videoram = 0;
+#endif
+
+MODULE_DESCRIPTION("Z7 Z9 Z9S Z11 framebuffer device driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("XGITECH , Others");
+
+
+
+module_param(mem, int, 0);
+module_param(noaccel, int, 0);
+module_param(noypan, int, 0);
+module_param(nomax, int, 0);
+module_param(userom, int, 0);
+module_param(useoem, int, 0);
+module_param(mode, charp, 0);
+module_param(vesa, int, 0);
+module_param(rate, int, 0);
+module_param(forcecrt1, int, 0);
+module_param(forcecrt2type, charp, 0);
+module_param(scalelcd, int, 0);
+module_param(pdc, int, 0);
+module_param(pdc1, int, 0);
+module_param(specialtiming, charp, 0);
+module_param(lvdshl, int, 0);
+module_param(tvstandard, charp, 0);
+module_param(tvxposoffset, int, 0);
+module_param(tvyposoffset, int, 0);
+module_param(filter, int, 0);
+module_param(nocrt2rate, int, 0);
+#if !defined(__i386__) && !defined(__x86_64__)
+module_param(resetcard, int, 0);
+module_param(videoram, int, 0);
+#endif
+
+
+MODULE_PARM_DESC(mem,
+ "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
+ "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
+ "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
+ "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
+ "otherwise at 12288KB. On 315 and Xabre series, the heap size is 32KB by default.\n"
+ "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
+ "for XFree86 4.x/X.org 6.7 and later.\n");
+
+MODULE_PARM_DESC(noaccel,
+ "\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
+ "(default: 0)\n");
+
+MODULE_PARM_DESC(noypan,
+ "\nIf set to anything other than 0, y-panning will be disabled and scrolling\n"
+ "will be performed by redrawing the screen. (default: 0)\n");
+
+MODULE_PARM_DESC(nomax,
+ "\nIf y-panning is enabled, xgifb will by default use the entire available video\n"
+ "memory for the virtual screen in order to optimize scrolling performance. If\n"
+ "this is set to anything other than 0, xgifb will not do this and thereby \n"
+ "enable the user to positively specify a virtual Y size of the screen using\n"
+ "fbset. (default: 0)\n");
+
+
+
+MODULE_PARM_DESC(mode,
+ "\nSelects the desired default display mode in the format XxYxDepth,\n"
+ "eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
+ "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
+ "number, it will be interpreted as a VESA mode number. (default: 800x600x8)\n");
+
+MODULE_PARM_DESC(vesa,
+ "\nSelects the desired default display mode by VESA defined mode number, eg.\n"
+ "0x117 (default: 0x0103)\n");
+
+
+MODULE_PARM_DESC(rate,
+ "\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
+ "If the mode is specified in the format XxY-Depth@Rate, this parameter\n"
+ "will be ignored (default: 60)\n");
+
+MODULE_PARM_DESC(forcecrt1,
+ "\nNormally, the driver autodetects whether or not CRT1 (external VGA) is \n"
+ "connected. With this option, the detection can be overridden (1=CRT1 ON,\n"
+ "0=CRT1 OFF) (default: [autodetected])\n");
+
+MODULE_PARM_DESC(forcecrt2type,
+ "\nIf this option is omitted, the driver autodetects CRT2 output devices, such as\n"
+ "LCD, TV or secondary VGA. With this option, this autodetection can be\n"
+ "overridden. Possible parameters are LCD, TV, VGA or NONE. NONE disables CRT2.\n"
+ "On systems with a SiS video bridge, parameters SVIDEO, COMPOSITE or SCART can\n"
+ "be used instead of TV to override the TV detection. Furthermore, on systems\n"
+ "with a SiS video bridge, SVIDEO+COMPOSITE, HIVISION, YPBPR480I, YPBPR480P,\n"
+ "YPBPR720P and YPBPR1080I are understood. However, whether or not these work\n"
+ "depends on the very hardware in use. (default: [autodetected])\n");
+
+MODULE_PARM_DESC(scalelcd,
+ "\nSetting this to 1 will force the driver to scale the LCD image to the panel's\n"
+ "native resolution. Setting it to 0 will disable scaling; LVDS panels will\n"
+ "show black bars around the image, TMDS panels will probably do the scaling\n"
+ "themselves. Default: 1 on LVDS panels, 0 on TMDS panels\n");
+
+MODULE_PARM_DESC(pdc,
+ "\nThis is for manually selecting the LCD panel delay compensation. The driver\n"
+ "should detect this correctly in most cases; however, sometimes this is not\n"
+ "possible. If you see 'small waves' on the LCD, try setting this to 4, 32 or 24\n"
+ "on a 300 series chipset; 6 on a 315 series chipset. If the problem persists,\n"
+ "try other values (on 300 series: between 4 and 60 in steps of 4; on 315 series:\n"
+ "any value from 0 to 31). (default: autodetected, if LCD is active during start)\n");
+
+MODULE_PARM_DESC(pdc1,
+ "\nThis is same as pdc, but for LCD-via CRT1. Hence, this is for the 315/330\n"
+ "series only. (default: autodetected if LCD is in LCD-via-CRT1 mode during\n"
+ "startup) - Note: currently, this has no effect because LCD-via-CRT1 is not\n"
+ "implemented yet.\n");
+
+MODULE_PARM_DESC(specialtiming,
+ "\nPlease refer to documentation for more information on this option.\n");
+
+MODULE_PARM_DESC(lvdshl,
+ "\nPlease refer to documentation for more information on this option.\n");
+
+MODULE_PARM_DESC(tvstandard,
+ "\nThis allows overriding the BIOS default for the TV standard. Valid choices are\n"
+ "pal, ntsc, palm and paln. (default: [auto; pal or ntsc only])\n");
+
+MODULE_PARM_DESC(tvxposoffset,
+ "\nRelocate TV output horizontally. Possible parameters: -32 through 32.\n"
+ "Default: 0\n");
+
+MODULE_PARM_DESC(tvyposoffset,
+ "\nRelocate TV output vertically. Possible parameters: -32 through 32.\n"
+ "Default: 0\n");
+
+MODULE_PARM_DESC(filter,
+ "\nSelects TV flicker filter type (only for systems with a SiS301 video bridge).\n"
+ "(Possible values 0-7, default: [no filter])\n");
+
+MODULE_PARM_DESC(nocrt2rate,
+ "\nSetting this to 1 will force the driver to use the default refresh rate for\n"
+ "CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
+
+
+
+
+int __init xgifb_init_module(void)
+{
+ printk("\nXGIfb_init_module");
+ if(mode)
+ XGIfb_search_mode(mode);
+ else if (vesa != -1)
+ XGIfb_search_vesamode(vesa);
+
+ return(xgifb_init());
+}
+
+static void __exit xgifb_remove_module(void)
+{
+ pci_unregister_driver(&xgifb_driver);
+ printk(KERN_DEBUG "xgifb: Module unloaded\n");
+}
+
+module_init(xgifb_init_module);
+module_exit(xgifb_remove_module);
+
+#endif /* /MODULE */
+
+EXPORT_SYMBOL(XGI_malloc);
+EXPORT_SYMBOL(XGI_free);
+
diff --git a/drivers/staging/xgifb/XGIfb.h b/drivers/staging/xgifb/XGIfb.h
new file mode 100644
index 000000000000..41bf163d4e6b
--- /dev/null
+++ b/drivers/staging/xgifb/XGIfb.h
@@ -0,0 +1,215 @@
+#ifndef _LINUX_XGIFB
+#define _LINUX_XGIFB
+#include <linux/spinlock.h>
+#include <asm/ioctl.h>
+#include <asm/types.h>
+
+#define DISPTYPE_CRT1 0x00000008L
+#define DISPTYPE_CRT2 0x00000004L
+#define DISPTYPE_LCD 0x00000002L
+#define DISPTYPE_TV 0x00000001L
+#define DISPTYPE_DISP1 DISPTYPE_CRT1
+#define DISPTYPE_DISP2 (DISPTYPE_CRT2 | DISPTYPE_LCD | DISPTYPE_TV)
+#define DISPMODE_SINGLE 0x00000020L
+#define DISPMODE_MIRROR 0x00000010L
+#define DISPMODE_DUALVIEW 0x00000040L
+
+#define HASVB_NONE 0x00
+#define HASVB_301 0x01
+#define HASVB_LVDS 0x02
+#define HASVB_TRUMPION 0x04
+#define HASVB_LVDS_CHRONTEL 0x10
+#define HASVB_302 0x20
+#define HASVB_303 0x40
+#define HASVB_CHRONTEL 0x80
+
+#ifndef XGIFB_ID
+#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */
+#endif
+
+typedef enum _XGI_CHIP_TYPE {
+ XGI_VGALegacy = 0,
+ XGI_300,
+ XGI_630,
+ XGI_730,
+ XGI_540,
+ XGI_315H,
+ XGI_315,
+ XGI_315PRO,
+ XGI_550,
+ XGI_640,
+ XGI_740,
+ XGI_650,
+ XGI_650M,
+ XGI_330 = 16,
+ XGI_660,
+ XGI_661,
+ XGI_760,
+ XG40 = 32,
+ XG41,
+ XG42,
+ XG45,
+ XG20 = 48,
+ XG21,
+ XG27,
+ MAX_XGI_CHIP
+} XGI_CHIP_TYPE;
+
+typedef enum _TVTYPE {
+ TVMODE_NTSC = 0,
+ TVMODE_PAL,
+ TVMODE_HIVISION,
+ TVTYPE_PALM, // vicki@030226
+ TVTYPE_PALN, // vicki@030226
+ TVTYPE_NTSCJ, // vicki@030226
+ TVMODE_TOTAL
+} XGI_TV_TYPE;
+
+
+typedef struct _XGIFB_INFO XGIfb_info;
+struct _XGIFB_INFO {
+
+unsigned long XGIfb_id;
+ int chip_id; /* PCI ID of detected chip */
+ int memory; /* video memory in KB which XGIfb manages */
+ int heapstart; /* heap start (= XGIfb "mem" argument) in KB */
+ unsigned char fbvidmode; /* current XGIfb mode */
+
+ unsigned char XGIfb_version;
+ unsigned char XGIfb_revision;
+ unsigned char XGIfb_patchlevel;
+
+ unsigned char XGIfb_caps; /* XGIfb capabilities */
+
+ int XGIfb_tqlen; /* turbo queue length (in KB) */
+
+ unsigned int XGIfb_pcibus; /* The card's PCI ID */
+ unsigned int XGIfb_pcislot;
+ unsigned int XGIfb_pcifunc;
+
+ unsigned char XGIfb_lcdpdc; /* PanelDelayCompensation */
+
+ unsigned char XGIfb_lcda; /* Detected status of LCDA for low res/text modes */
+
+ char reserved[235]; /* for future use */
+};
+
+
+
+
+typedef enum _TVPLUGTYPE { // vicki@030226
+// TVPLUG_Legacy = 0,
+// TVPLUG_COMPOSITE,
+// TVPLUG_SVIDEO,
+// TVPLUG_SCART,
+// TVPLUG_TOTAL
+ TVPLUG_UNKNOWN = 0,
+ TVPLUG_COMPOSITE = 1,
+ TVPLUG_SVIDEO = 2,
+ TVPLUG_COMPOSITE_AND_SVIDEO = 3,
+ TVPLUG_SCART = 4,
+ TVPLUG_YPBPR_525i = 5,
+ TVPLUG_YPBPR_525P = 6,
+ TVPLUG_YPBPR_750P = 7,
+ TVPLUG_YPBPR_1080i = 8,
+ TVPLUG_TOTAL
+} XGI_TV_PLUG;
+
+
+struct mode_info {
+ int bpp;
+ int xres;
+ int yres;
+ int v_xres;
+ int v_yres;
+ int org_x;
+ int org_y;
+ unsigned int vrate;
+};
+
+struct ap_data {
+ struct mode_info minfo;
+ unsigned long iobase;
+ unsigned int mem_size;
+ unsigned long disp_state;
+ XGI_CHIP_TYPE chip;
+ unsigned char hasVB;
+ XGI_TV_TYPE TV_type;
+ XGI_TV_PLUG TV_plug;
+ unsigned long version;
+ char reserved[256];
+};
+
+
+
+/* If changing this, vgatypes.h must also be changed (for X driver) */
+
+
+/*
+ * NOTE! The ioctl types used to be "size_t" by mistake, but were
+ * really meant to be __u32. Changed to "__u32" even though that
+ * changes the value on 64-bit architectures, because the value
+ * (with a 4-byte size) is also hardwired in vgatypes.h for user
+ * space exports. So "__u32" is actually more compatible, duh!
+ */
+#define XGIFB_GET_INFO _IOR('n',0xF8,__u32)
+#define XGIFB_GET_VBRSTATUS _IOR('n',0xF9,__u32)
+
+
+
+struct video_info{
+ int chip_id;
+ unsigned int video_size;
+ unsigned long video_base;
+ char * video_vbase;
+ unsigned long mmio_base;
+ char * mmio_vbase;
+ unsigned long vga_base;
+ unsigned long mtrr;
+ unsigned long heapstart;
+
+ int video_bpp;
+ int video_cmap_len;
+ int video_width;
+ int video_height;
+ int video_vwidth;
+ int video_vheight;
+ int org_x;
+ int org_y;
+ int video_linelength;
+ unsigned int refresh_rate;
+
+ unsigned long disp_state;
+ unsigned char hasVB;
+ unsigned char TV_type;
+ unsigned char TV_plug;
+
+ XGI_CHIP_TYPE chip;
+ unsigned char revision_id;
+
+ unsigned short DstColor;
+ unsigned long XGI310_AccelDepth;
+ unsigned long CommandReg;
+
+ spinlock_t lockaccel;
+
+ unsigned int pcibus;
+ unsigned int pcislot;
+ unsigned int pcifunc;
+
+ int accel;
+ unsigned short subsysvendor;
+ unsigned short subsysdevice;
+
+ char reserved[236];
+};
+
+
+extern struct video_info xgi_video_info;
+
+#ifdef __KERNEL__
+//extern void xgi_malloc(struct xgi_memreq *req);
+extern void xgi_free(unsigned long base);
+extern void xgi_dispinfo(struct ap_data *rec);
+#endif
+#endif
diff --git a/drivers/staging/xgifb/osdef.h b/drivers/staging/xgifb/osdef.h
new file mode 100644
index 000000000000..4bc7d3a7440c
--- /dev/null
+++ b/drivers/staging/xgifb/osdef.h
@@ -0,0 +1,153 @@
+#ifndef _OSDEF_H_
+#define _OSDEF_H_
+
+/* #define WINCE_HEADER*/
+/*#define WIN2000*/
+/* #define TC */
+#define LINUX_KERNEL
+/* #define LINUX_XF86 */
+
+/**********************************************************************/
+#ifdef LINUX_KERNEL
+//#include <linux/config.h>
+#endif
+
+
+/**********************************************************************/
+#ifdef TC
+#endif
+#ifdef WIN2000
+#endif
+#ifdef WINCE_HEADER
+#endif
+#ifdef LINUX_XF86
+#define LINUX
+#endif
+#ifdef LINUX_KERNEL
+#define LINUX
+#endif
+
+/**********************************************************************/
+#ifdef TC
+#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
+#endif
+#ifdef WIN2000
+#define XGI_SetMemory(MemoryAddress,MemorySize,value) MemFill((PVOID) MemoryAddress,(ULONG) MemorySize,(UCHAR) value);
+#endif
+#ifdef WINCE_HEADER
+#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize);
+#endif
+#ifdef LINUX_XF86
+#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
+#endif
+#ifdef LINUX_KERNEL
+#define XGI_SetMemory(MemoryAddress,MemorySize,value) memset(MemoryAddress, value, MemorySize)
+#endif
+/**********************************************************************/
+
+/**********************************************************************/
+
+#ifdef TC
+#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
+#endif
+#ifdef WIN2000
+#define XGI_MemoryCopy(Destination,Soruce,Length) /*VideoPortMoveMemory((PUCHAR)Destination , Soruce,length);*/
+#endif
+#ifdef WINCE_HEADER
+#define XGI_MemoryCopy(Destination,Soruce,Length) memmove(Destination, Soruce, Length);
+#endif
+#ifdef LINUX_XF86
+#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
+#endif
+#ifdef LINUX_KERNEL
+#define XGI_MemoryCopy(Destination,Soruce,Length) memcpy(Destination,Soruce,Length)
+#endif
+
+/**********************************************************************/
+
+#ifdef OutPortByte
+#undef OutPortByte
+#endif /* OutPortByte */
+
+#ifdef OutPortWord
+#undef OutPortWord
+#endif /* OutPortWord */
+
+#ifdef OutPortLong
+#undef OutPortLong
+#endif /* OutPortLong */
+
+#ifdef InPortByte
+#undef InPortByte
+#endif /* InPortByte */
+
+#ifdef InPortWord
+#undef InPortWord
+#endif /* InPortWord */
+
+#ifdef InPortLong
+#undef InPortLong
+#endif /* InPortLong */
+
+/**********************************************************************/
+/* TC */
+/**********************************************************************/
+
+#ifdef TC
+#define OutPortByte(p,v) outp((unsigned short)(p),(unsigned char)(v))
+#define OutPortWord(p,v) outp((unsigned short)(p),(unsigned short)(v))
+#define OutPortLong(p,v) outp((unsigned short)(p),(unsigned long)(v))
+#define InPortByte(p) inp((unsigned short)(p))
+#define InPortWord(p) inp((unsigned short)(p))
+#define InPortLong(p) ((inp((unsigned short)(p+2))<<16) | inp((unsigned short)(p)))
+#endif
+
+/**********************************************************************/
+/* LINUX XF86 */
+/**********************************************************************/
+
+#ifdef LINUX_XF86
+#define OutPortByte(p,v) outb((CARD16)(p),(CARD8)(v))
+#define OutPortWord(p,v) outw((CARD16)(p),(CARD16)(v))
+#define OutPortLong(p,v) outl((CARD16)(p),(CARD32)(v))
+#define InPortByte(p) inb((CARD16)(p))
+#define InPortWord(p) inw((CARD16)(p))
+#define InPortLong(p) inl((CARD16)(p))
+#endif
+
+#ifdef LINUX_KERNEL
+#define OutPortByte(p,v) outb((u8)(v),(p))
+#define OutPortWord(p,v) outw((u16)(v),(p))
+#define OutPortLong(p,v) outl((u32)(v),(p))
+#define InPortByte(p) inb(p)
+#define InPortWord(p) inw(p)
+#define InPortLong(p) inl(p)
+#endif
+
+/**********************************************************************/
+/* WIN 2000 */
+/**********************************************************************/
+
+#ifdef WIN2000
+#define OutPortByte(p,v) VideoPortWritePortUchar ((PUCHAR) (p), (UCHAR) (v))
+#define OutPortWord(p,v) VideoPortWritePortUshort((PUSHORT) (p), (USHORT) (v))
+#define OutPortLong(p,v) VideoPortWritePortUlong ((PULONG) (p), (ULONG) (v))
+#define InPortByte(p) VideoPortReadPortUchar ((PUCHAR) (p))
+#define InPortWord(p) VideoPortReadPortUshort ((PUSHORT) (p))
+#define InPortLong(p) VideoPortReadPortUlong ((PULONG) (p))
+#endif
+
+
+/**********************************************************************/
+/* WIN CE */
+/**********************************************************************/
+
+#ifdef WINCE_HEADER
+#define OutPortByte(p,v) WRITE_PORT_UCHAR ((PUCHAR) (p), (UCHAR) (v))
+#define OutPortWord(p,v) WRITE_PORT_USHORT((PUSHORT) (p), (USHORT) (v))
+#define OutPortLong(p,v) WRITE_PORT_ULONG ((PULONG) (p), (ULONG) (v))
+#define InPortByte(p) READ_PORT_UCHAR ((PUCHAR) (p))
+#define InPortWord(p) READ_PORT_USHORT ((PUSHORT) (p))
+#define InPortLong(p) READ_PORT_ULONG ((PULONG) (p))
+#endif
+#endif // _OSDEF_H_
diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h
new file mode 100644
index 000000000000..17a7ada4926e
--- /dev/null
+++ b/drivers/staging/xgifb/vb_def.h
@@ -0,0 +1,1017 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/xgi/initdef.h,v 1.4 2000/12/02 01:16:17 dawes Exp $ */
+#ifndef _INITDEF_
+#define _INITDEF_
+
+#ifndef NewScratch
+#define NewScratch
+#endif
+/* shampoo */
+#ifdef LINUX_KERNEL
+#define SEQ_ADDRESS_PORT 0x0014
+#define SEQ_DATA_PORT 0x0015
+#define MISC_OUTPUT_REG_READ_PORT 0x001C
+#define MISC_OUTPUT_REG_WRITE_PORT 0x0012
+#define GRAPH_DATA_PORT 0x1F
+#define GRAPH_ADDRESS_PORT 0x1E
+#define XGI_MASK_DUAL_CHIP 0x04 /* SR3A */
+#define CRTC_ADDRESS_PORT_COLOR 0x0024
+#define VIDEO_SUBSYSTEM_ENABLE_PORT 0x0013
+#define PCI_COMMAND 0x04
+#endif
+/* ~shampoo */
+
+
+#define VB_XGI301 0x0001 /*301b*/
+#define VB_XGI301B 0x0002
+#define VB_XGI302B 0x0004
+#define VB_XGI301LV 0x0008 /*301lv*/
+#define VB_XGI302LV 0x0010
+#define VB_XGI301C 0x0020 /* for 301C */
+#define VB_NoLCD 0x8000
+/*end 301b*/
+
+#define VB_YPbPrInfo 0x07 /*301lv*/
+#define VB_YPbPr525i 0x00
+#define VB_YPbPr525p 0x01
+#define VB_YPbPr750p 0x02
+#define VB_YPbPr1080i 0x03
+
+/* #define CRT1Len 17 */
+#define LVDSCRT1Len 15
+#define CHTVRegDataLen 5
+
+/* #define ModeInfoFlag 0x07 */
+/* #define IsTextMode 0x07 */
+/* #define ModeText 0x00 */
+/* #define ModeCGA 0x01 */
+/* #define ModeEGA 0x02 */
+/* #define ModeVGA 0x03 */
+/* #define Mode15Bpp 0x04 */
+/* #define Mode16Bpp 0x05 */
+/* #define Mode24Bpp 0x06 */
+/* #define Mode32Bpp 0x07 */
+
+/* #define DACInfoFlag 0x18 */
+/* #define MemoryInfoFlag 0x1E0 */
+/* #define MemorySizeShift 0x05 */
+
+#define Charx8Dot 0x0200
+#define LineCompareOff 0x0400
+#define CRT2Mode 0x0800
+#define HalfDCLK 0x1000
+#define NoSupportSimuTV 0x2000
+#define DoubleScanMode 0x8000
+
+#define SupportAllCRT2 0x0078
+#define SupportTV 0x0008
+#define SupportHiVisionTV 0x0010
+#define SupportLCD 0x0020
+#define SupportRAMDAC2 0x0040
+#define NoSupportTV 0x0070
+#define NoSupportHiVisionTV 0x0060
+#define NoSupportLCD 0x0058
+#define SupportCHTV 0x0800
+#define SupportCRT2in301C 0x0100 /* for 301C */
+#define SupportTV1024 0x0800 /*301b*/
+#define SupportYPbPr 0x1000 /*301lv*/
+#define InterlaceMode 0x0080
+#define SyncPP 0x0000
+#define SyncPN 0x4000
+#define SyncNP 0x8000
+/* #define SyncNN 0xc000 */
+#define ECLKindex0 0x0000
+#define ECLKindex1 0x0100
+#define ECLKindex2 0x0200
+#define ECLKindex3 0x0300
+#define ECLKindex4 0x0400
+
+#define SetSimuScanMode 0x0001
+#define SwitchToCRT2 0x0002
+/* #define SetCRT2ToTV 0x009C */
+#define SetCRT2ToAVIDEO 0x0004
+#define SetCRT2ToSVIDEO 0x0008
+#define SetCRT2ToSCART 0x0010
+#define SetCRT2ToLCD 0x0020
+#define SetCRT2ToRAMDAC 0x0040
+#define SetCRT2ToHiVisionTV 0x0080
+#define SetNTSCTV 0x0000
+/* #define SetPALTV 0x0100 */
+#define SetInSlaveMode 0x0200
+#define SetNotSimuMode 0x0400
+#define SetNotSimuTVMode 0x0400
+#define SetDispDevSwitch 0x0800
+#define LoadDACFlag 0x1000
+#define DisableCRT2Display 0x2000
+#define DriverMode 0x4000
+#define HotKeySwitch 0x8000
+#define SetCHTVOverScan 0x8000
+/* #define SetCRT2ToLCDA 0x8000 301b */
+#define PanelRGB18Bit 0x0100
+#define PanelRGB24Bit 0x0000
+
+#define TVOverScan 0x10
+#define TVOverScanShift 4
+#define ClearBufferFlag 0x20
+#define EnableDualEdge 0x01 /*301b*/
+#define SetToLCDA 0x02
+
+#define YPbPrModeInfo 0x38
+/* #define YPbPrMode525i 0x00 */
+/* #define YPbPrMode525p 0x08 */
+/* #define YPbPrMode750p 0x10 */
+/* #define YPbPrMode1080i 0x18 */
+
+#define SetSCARTOutput 0x01
+#define BoardTVType 0x02
+#define EnablePALMN 0x40
+/* #define ProgrammingCRT2 0x01 */
+/* #define TVSimuMode 0x02 */
+/* #define RPLLDIV2XO 0x04 */
+/* #define LCDVESATiming 0x08 */
+/* #define EnableLVDSDDA 0x10 */
+#define SetDispDevSwitchFlag 0x20
+#define CheckWinDos 0x40
+#define SetJDOSMode 0x80
+
+#define Panel320x480 0x07/*fstn*/
+/* [ycchen] 02/12/03 Modify for Multi-Sync. LCD Support */
+#define PanelResInfo 0x1F /* CR36 Panel Type/LCDResInfo */
+#define PanelRefInfo 0x60
+#define Panel800x600 0x01
+#define Panel1024x768 0x02
+#define Panel1024x768x75 0x22
+#define Panel1280x1024 0x03
+#define Panel1280x1024x75 0x23
+#define Panel640x480 0x04
+#define Panel1024x600 0x05
+#define Panel1152x864 0x06
+#define Panel1280x960 0x07
+#define Panel1152x768 0x08
+#define Panel1400x1050 0x09
+#define Panel1280x768 0x0A
+#define Panel1600x1200 0x0B
+
+#define PanelRef60Hz 0x00
+#define PanelRef75Hz 0x20
+#define LCDRGB18Bit 0x01
+
+#define ExtChipTrumpion 0x06
+#define ExtChipCH7005 0x08
+#define ExtChipMitacTV 0x0a
+#define LCDNonExpanding 0x10
+#define LCDNonExpandingShift 4
+#define LCDSync 0x20
+#define LCDSyncBit 0xe0
+#define LCDSyncShift 6
+
+/* #define DDC2DelayTime 300 */
+
+#define CRT2DisplayFlag 0x2000
+/* #define LCDDataLen 8 */
+/* #define HiTVDataLen 12 */
+/* #define TVDataLen 16 */
+/* #define SetPALTV 0x0100 */
+#define HalfDCLK 0x1000
+#define NTSCHT 1716
+#define NTSCVT 525
+#define PALHT 1728
+#define PALVT 625
+#define StHiTVHT 892
+#define StHiTVVT 1126
+#define StHiTextTVHT 1000
+#define StHiTextTVVT 1126
+#define ExtHiTVHT 2100
+#define ExtHiTVVT 1125
+
+#define St750pTVHT 1716
+#define St750pTVVT 525
+#define Ext750pTVHT 1716
+#define Ext750pTVVT 525
+#define St525pTVHT 1716
+#define St525pTVVT 525
+#define Ext525pTVHT 1716
+#define Ext525pTVVT 525
+#define St525iTVHT 1716
+#define St525iTVVT 525
+#define Ext525iTVHT 1716
+#define Ext525iTVVT 525
+
+#define VCLKStartFreq 25
+#define SoftDramType 0x80
+#define VCLK40 0x04
+
+#define VCLK162 0x21
+
+#define LCDRGB18Bit 0x01
+#define LoadDACFlag 0x1000
+#define AfterLockCRT2 0x4000
+#define SetCRT2ToAVIDEO 0x0004
+#define SetCRT2ToSCART 0x0010
+#define Ext2StructSize 5
+
+
+#define YPbPr525iVCLK 0x03B
+#define YPbPr525iVCLK_2 0x03A
+
+#define SwitchToCRT2 0x0002
+/* #define LCDVESATiming 0x08 */
+#define SetSCARTOutput 0x01
+#define AVIDEOSense 0x01
+#define SVIDEOSense 0x02
+#define SCARTSense 0x04
+#define LCDSense 0x08
+#define Monitor1Sense 0x20
+#define Monitor2Sense 0x10
+#define HiTVSense 0x40
+#define BoardTVType 0x02
+#define HotPlugFunction 0x08
+#define StStructSize 0x06
+
+
+#define XGI_CRT2_PORT_00 0x00 - 0x030
+#define XGI_CRT2_PORT_04 0x04 - 0x030
+#define XGI_CRT2_PORT_10 0x10 - 0x30
+#define XGI_CRT2_PORT_12 0x12 - 0x30
+#define XGI_CRT2_PORT_14 0x14 - 0x30
+
+
+#define LCDNonExpanding 0x10
+#define ADR_CRT2PtrData 0x20E
+#define offset_Zurac 0x210
+#define ADR_LVDSDesPtrData 0x212
+#define ADR_LVDSCRT1DataPtr 0x214
+#define ADR_CHTVVCLKPtr 0x216
+#define ADR_CHTVRegDataPtr 0x218
+
+#define LVDSDataLen 6
+/* #define EnableLVDSDDA 0x10 */
+/* #define LVDSDesDataLen 3 */
+#define ActiveNonExpanding 0x40
+#define ActiveNonExpandingShift 6
+/* #define ActivePAL 0x20 */
+#define ActivePALShift 5
+/* #define ModeSwitchStatus 0x0F */
+#define SoftTVType 0x40
+#define SoftSettingAddr 0x52
+#define ModeSettingAddr 0x53
+
+/* #define SelectCRT1Rate 0x4 */
+
+#define _PanelType00 0x00
+#define _PanelType01 0x08
+#define _PanelType02 0x10
+#define _PanelType03 0x18
+#define _PanelType04 0x20
+#define _PanelType05 0x28
+#define _PanelType06 0x30
+#define _PanelType07 0x38
+#define _PanelType08 0x40
+#define _PanelType09 0x48
+#define _PanelType0A 0x50
+#define _PanelType0B 0x58
+#define _PanelType0C 0x60
+#define _PanelType0D 0x68
+#define _PanelType0E 0x70
+#define _PanelType0F 0x78
+
+
+#define PRIMARY_VGA 0 /* 1: XGI is primary vga 0:XGI is secondary vga */
+#define BIOSIDCodeAddr 0x235
+#define OEMUtilIDCodeAddr 0x237
+#define VBModeIDTableAddr 0x239
+#define OEMTVPtrAddr 0x241
+#define PhaseTableAddr 0x243
+#define NTSCFilterTableAddr 0x245
+#define PALFilterTableAddr 0x247
+#define OEMLCDPtr_1Addr 0x249
+#define OEMLCDPtr_2Addr 0x24B
+#define LCDHPosTable_1Addr 0x24D
+#define LCDHPosTable_2Addr 0x24F
+#define LCDVPosTable_1Addr 0x251
+#define LCDVPosTable_2Addr 0x253
+#define OEMLCDPIDTableAddr 0x255
+
+#define VBModeStructSize 5
+#define PhaseTableSize 4
+#define FilterTableSize 4
+#define LCDHPosTableSize 7
+#define LCDVPosTableSize 5
+#define OEMLVDSPIDTableSize 4
+#define LVDSHPosTableSize 4
+#define LVDSVPosTableSize 6
+
+#define VB_ModeID 0
+#define VB_TVTableIndex 1
+#define VB_LCDTableIndex 2
+#define VB_LCDHIndex 3
+#define VB_LCDVIndex 4
+
+#define OEMLCDEnable 0x0001
+#define OEMLCDDelayEnable 0x0002
+#define OEMLCDPOSEnable 0x0004
+#define OEMTVEnable 0x0100
+#define OEMTVDelayEnable 0x0200
+#define OEMTVFlickerEnable 0x0400
+#define OEMTVPhaseEnable 0x0800
+#define OEMTVFilterEnable 0x1000
+
+#define OEMLCDPanelIDSupport 0x0080
+
+/* #define LCDVESATiming 0x0001 //LCD Info CR37 */
+/* #define EnableLVDSDDA 0x0002 */
+#define EnableScalingLCD 0x0008
+#define SetPWDEnable 0x0004
+#define SetLCDtoNonExpanding 0x0010
+/* #define SetLCDPolarity 0x00E0 */
+#define SetLCDDualLink 0x0100
+#define SetLCDLowResolution 0x0200
+#define SetLCDStdMode 0x0400
+#define SetTVStdMode 0x0200
+#define SetTVLowResolution 0x0400
+/* =============================================================
+ for 310
+============================================================== */
+#define SoftDRAMType 0x80
+#define SoftSetting_OFFSET 0x52
+#define SR07_OFFSET 0x7C
+#define SR15_OFFSET 0x7D
+#define SR16_OFFSET 0x81
+#define SR17_OFFSET 0x85
+#define SR19_OFFSET 0x8D
+#define SR1F_OFFSET 0x99
+#define SR21_OFFSET 0x9A
+#define SR22_OFFSET 0x9B
+#define SR23_OFFSET 0x9C
+#define SR24_OFFSET 0x9D
+#define SR25_OFFSET 0x9E
+#define SR31_OFFSET 0x9F
+#define SR32_OFFSET 0xA0
+#define SR33_OFFSET 0xA1
+
+#define CR40_OFFSET 0xA2
+#define SR25_1_OFFSET 0xF6
+#define CR49_OFFSET 0xF7
+
+#define VB310Data_1_2_Offset 0xB6
+#define VB310Data_4_D_Offset 0xB7
+#define VB310Data_4_E_Offset 0xB8
+#define VB310Data_4_10_Offset 0xBB
+
+#define RGBSenseDataOffset 0xBD
+#define YCSenseDataOffset 0xBF
+#define VideoSenseDataOffset 0xC1
+#define OutputSelectOffset 0xF3
+
+#define ECLK_MCLK_DISTANCE 0x14
+#define VBIOSTablePointerStart 0x200
+#define StandTablePtrOffset VBIOSTablePointerStart+0x02
+#define EModeIDTablePtrOffset VBIOSTablePointerStart+0x04
+#define CRT1TablePtrOffset VBIOSTablePointerStart+0x06
+#define ScreenOffsetPtrOffset VBIOSTablePointerStart+0x08
+#define VCLKDataPtrOffset VBIOSTablePointerStart+0x0A
+#define MCLKDataPtrOffset VBIOSTablePointerStart+0x0E
+#define CRT2PtrDataPtrOffset VBIOSTablePointerStart+0x10
+#define TVAntiFlickPtrOffset VBIOSTablePointerStart+0x12
+#define TVDelayPtr1Offset VBIOSTablePointerStart+0x14
+#define TVPhaseIncrPtr1Offset VBIOSTablePointerStart+0x16
+#define TVYFilterPtr1Offset VBIOSTablePointerStart+0x18
+#define LCDDelayPtr1Offset VBIOSTablePointerStart+0x20
+#define TVEdgePtr1Offset VBIOSTablePointerStart+0x24
+#define CRT2Delay1Offset VBIOSTablePointerStart+0x28
+#define LCDDataDesOffset VBIOSTablePointerStart-0x02
+#define LCDDataPtrOffset VBIOSTablePointerStart+0x2A
+#define LCDDesDataPtrOffset VBIOSTablePointerStart+0x2C
+#define LCDDataList VBIOSTablePointerStart+0x22 /* add for GetLCDPtr */
+#define TVDataList VBIOSTablePointerStart+0x36 /* add for GetTVPtr */
+/* */
+/* Modify from 310.inc */
+/* */
+/* */
+
+
+#define ShowMsgFlag 0x20 /* SoftSetting */
+#define ShowVESAFlag 0x10
+#define HotPlugFunction 0x08
+#define ModeSoftSetting 0x04
+#define TVSoftSetting 0x02
+#define LCDSoftSetting 0x01
+
+#define GatingCRTinLCDA 0x10
+#define SetHiTVOutput 0x08
+#define SetYPbPrOutput 0x04
+#define BoardTVType 0x02
+#define SetSCARTOutput 0x01
+
+#define ModeSettingYPbPr 0x02 /* TVModeSetting, Others as same as CR30 */
+
+/* TVModeSetting same as CR35 */
+
+/* LCDModeSetting same as CR37 */
+
+#define EnableNewTVFont 0x10 /* MiscCapability */
+
+#define EnableLCDOutput 0x80 /* LCDCfgSetting */
+
+#define SoftDRAMType 0x80 /* DRAMSetting */
+#define SoftDRAMConfig 0x40
+#define MosSelDRAMType 0x20
+#define SDRAM 000h
+#define SGRAM 0x01
+#define ESDRAM 0x02
+
+#define EnableAGPCfgSetting 0x01 /* AGPCfgSetting */
+
+/* ---------------- SetMode Stack */
+#define CRT1Len 15
+#define VCLKLen 4
+#define DefThreshold 0x0100
+#define ExtRegsSize (57+8+37+70+63+28+768+1)/64+1
+
+#define VGA_XGI315 0x0001 /* VGA Type Info */
+#define VGA_SNewis315e 0x0002 /* 315 series */
+#define VGA_XGI550 0x0004
+#define VGA_XGI640 0x0008
+#define VGA_XGI740 0x0010
+#define VGA_XGI650 0x0020
+#define VGA_XGI650M 0x0040
+#define VGA_XGI651 0x0080
+#define VGA_XGI340 0x0001 /* 340 series */
+#define VGA_XGI330 0x0001 /* 330 series */
+#define VGA_XGI660 0x0001 /* 660 series */
+
+#define VB_XGI301 0x0001 /* VB Type Info */
+#define VB_XGI301B 0x0002 /* 301 series */
+#define VB_XGI302B 0x0004
+#define VB_NoLCD 0x8000
+#define VB_XGI301LV 0x0008
+#define VB_XGI302LV 0x0010
+#define VB_LVDS_NS 0x0001 /* 3rd party chip */
+#define VB_CH7017 0x0002
+#define VB_CH7007 0x0080 /* [Billy] 07/05/03 */
+/* #define VB_LVDS_SI 0x0004 */
+
+#define ModeInfoFlag 0x0007
+#define IsTextMode 0x0007
+#define ModeText 0x0000
+#define ModeCGA 0x0001
+#define ModeEGA 0x0002 /* 16 colors mode */
+#define ModeVGA 0x0003 /* 256 colors mode */
+#define Mode15Bpp 0x0004 /* 15 Bpp Color Mode */
+#define Mode16Bpp 0x0005 /* 16 Bpp Color Mode */
+#define Mode24Bpp 0x0006 /* 24 Bpp Color Mode */
+#define Mode32Bpp 0x0007 /* 32 Bpp Color Mode */
+
+#define DACInfoFlag 0x0018
+#define MONODAC 0x0000
+#define CGADAC 0x0008
+#define EGADAC 0x0010
+#define VGADAC 0x0018
+
+#define MemoryInfoFlag 0x01e0
+#define MemorySizeShift 5
+#define Need1MSize 0x0000
+#define Need2MSize 0x0020
+#define Need4MSize 0x0060
+#define Need8MSize 0x00e0
+#define Need16MSize 0x01e0
+
+#define Charx8Dot 0x0200
+#define LineCompareOff 0x0400
+#define CRT2Mode 0x0800
+#define HalfDCLK 0x1000
+#define NoSupportSimuTV 0x2000
+#define DoubleScanMode 0x8000
+
+/* -------------- Ext_InfoFlag */
+#define SupportModeInfo 0x0007
+#define Support256 0x0003
+#define Support15Bpp 0x0004
+#define Support16Bpp 0x0005
+#define Support24Bpp 0x0006
+#define Support32Bpp 0x0007
+
+#define SupportAllCRT2 0x0078
+#define SupportTV 0x0008
+#define SupportHiVisionTV 0x0010
+#define SupportLCD 0x0020
+#define SupportRAMDAC2 0x0040
+#define NoSupportTV 0x0070
+#define NoSupportHiVisionTV 0x0060
+#define NoSupportLCD 0x0058
+#define SupportTV1024 0x0800 /* 301btest */
+#define SupportYPbPr 0x1000 /* 301lv */
+#define InterlaceMode 0x0080
+#define SyncPP 0x0000
+#define SyncPN 0x4000
+#define SyncNP 0x8000
+#define SyncNN 0xC000
+
+/* -------------- SetMode Stack/Scratch */
+#define SetSimuScanMode 0x0001 /* VBInfo/CR30 & CR31 */
+#define SwitchToCRT2 0x0002
+#define SetCRT2ToTV1 0x009C
+#define SetCRT2ToTV 0x089C
+#define SetCRT2ToAVIDEO 0x0004
+#define SetCRT2ToSVIDEO 0x0008
+#define SetCRT2ToSCART 0x0010
+#define SetCRT2ToLCD 0x0020
+#define SetCRT2ToRAMDAC 0x0040
+#define SetCRT2ToHiVisionTV 0x0080
+#define SetCRT2ToLCDA 0x0100
+#define SetInSlaveMode 0x0200
+#define SetNotSimuMode 0x0400
+#define HKEventMode 0x0800
+#define SetCRT2ToYPbPr 0x0800
+#define LoadDACFlag 0x1000
+#define DisableCRT2Display 0x2000
+#define DriverMode 0x4000
+#define SetCRT2ToDualEdge 0x8000
+#define HotKeySwitch 0x8000
+
+#define ProgrammingCRT2 0x0001 /* Set Flag */
+#define EnableVCMode 0x0002
+#define SetHKEventMode 0x0004
+#define ReserveTVOption 0x0008
+#define DisableRelocateIO 0x0010
+#define Win9xDOSMode 0x0020
+#define JDOSMode 0x0040
+/* #define SetWin9xforJap 0x0080 // not used now */
+/* #define SetWin9xforKorea 0x0100 // not used now */
+#define GatingCRT 0x0800
+#define DisableChB 0x1000
+#define EnableChB 0x2000
+#define DisableChA 0x4000
+#define EnableChA 0x8000
+
+#define SetNTSCTV 0x0000 /* TV Info */
+#define SetPALTV 0x0001
+#define SetNTSCJ 0x0002
+#define SetPALMTV 0x0004
+#define SetPALNTV 0x0008
+#define SetCHTVUnderScan 0x0000
+/* #define SetCHTVOverScan 0x0010 */
+#define SetYPbPrMode525i 0x0020
+#define SetYPbPrMode525p 0x0040
+#define SetYPbPrMode750p 0x0080
+#define SetYPbPrMode1080i 0x0100
+#define SetTVStdMode 0x0200
+#define SetTVLowResolution 0x0400
+#define SetTVSimuMode 0x0800
+#define TVSimuMode 0x0800
+#define RPLLDIV2XO 0x1000
+#define NTSC1024x768 0x2000
+#define SetTVLockMode 0x4000
+
+#define LCDVESATiming 0x0001 /* LCD Info/CR37 */
+#define EnableLVDSDDA 0x0002
+#define EnableScalingLCD 0x0008
+#define SetPWDEnable 0x0004
+#define SetLCDtoNonExpanding 0x0010
+#define SetLCDPolarity 0x00e0
+#define SetLCDDualLink 0x0100
+#define SetLCDLowResolution 0x0200
+#define SetLCDStdMode 0x0400
+
+#define DefaultLCDCap 0x80ea /* LCD Capability shampoo */
+#define RLVDSDHL00 0x0000
+#define RLVDSDHL01 0x0001
+#define RLVDSDHL10 0x0002 /* default */
+#define RLVDSDHL11 0x0003
+#define EnableLCD24bpp 0x0004 /* default */
+#define DisableLCD24bpp 0x0000
+#define RLVDSClkSFT0 0x0000
+#define RLVDSClkSFT1 0x0008 /* default */
+#define EnableLVDSDCBal 0x0010
+#define DisableLVDSDCBal 0x0000 /* default */
+#define SinglePolarity 0x0020 /* default */
+#define MultiPolarity 0x0000
+#define LCDPolarity 0x00c0 /* default: SyncNN */
+#define LCDSingleLink 0x0000 /* default */
+#define LCDDualLink 0x0100
+#define EnableSpectrum 0x0200
+#define DisableSpectrum 0x0000 /* default */
+#define PWDEnable 0x0400
+#define PWDDisable 0x0000 /* default */
+#define PWMEnable 0x0800
+#define PWMDisable 0x0000 /* default */
+#define EnableVBCLKDRVLOW 0x4000
+#define EnableVBCLKDRVHigh 0x0000 /* default */
+#define EnablePLLSPLOW 0x8000
+#define EnablePLLSPHigh 0x0000 /* default */
+
+#define LCDBToA 0x20 /* LCD SetFlag */
+#define StLCDBToA 0x40
+#define LockLCDBToA 0x80
+#define LCDToFull 0x10
+#define AVIDEOSense 0x01 /* CR32 */
+#define SVIDEOSense 0x02
+#define SCARTSense 0x04
+#define LCDSense 0x08
+#define Monitor2Sense 0x10
+#define Monitor1Sense 0x20
+#define HiTVSense 0x40
+
+#ifdef NewScratch
+#define YPbPrSense 0x80 /* NEW SCRATCH */
+#endif
+
+#define TVSense 0xc7
+
+#define TVOverScan 0x10 /* CR35 */
+#define TVOverScanShift 4
+
+#ifdef NewScratch
+#define NTSCMode 0x00
+#define PALMode 0x00
+#define NTSCJMode 0x02
+#define PALMNMode 0x0c
+#define YPbPrMode 0xe0
+#define YPbPrMode525i 0x00
+#define YPbPrMode525p 0x20
+#define YPbPrMode750p 0x40
+#define YPbPrMode1080i 0x60
+#else /* Old Scratch */
+#define ClearBufferFlag 0x20
+#endif
+
+
+#define LCDRGB18Bit 0x01 /* CR37 */
+#define LCDNonExpanding 0x10
+#define LCDNonExpandingShift 4
+#define LCDSync 0x20
+#define LCDSyncBit 0xe0 /* H/V polarity & sync ID */
+#define LCDSyncShift 6
+
+#ifdef NewScratch
+#define ScalingLCD 0x08
+#else /* Old Scratch */
+#define ExtChipType 0x0e
+#define ExtChip301 0x02
+#define ExtChipLVDS 0x04
+#define ExtChipCH7019 0x06
+#define ScalingLCD 0x10
+#endif
+
+#define EnableDualEdge 0x01 /* CR38 */
+#define SetToLCDA 0x02
+#ifdef NewScratch
+#define SetYPbPr 0x04
+#define DisableChannelA 0x08
+#define DisableChannelB 0x10
+#define ExtChipType 0xe0
+#define ExtChip301 0x20
+#define ExtChipLVDS 0x40
+#define ExtChipCH7019 0x60
+#else /* Old Scratch */
+#define YPbPrSense 0x04
+#define SetYPbPr 0x08
+#define YPbPrMode 0x30
+#define YPbPrMode525i 0x00
+#define YPbPrMode525p 0x10
+#define YPbPrMode750p 0x20
+#define YPbPrMode1080i 0x30
+#define PALMNMode 0xc0
+#endif
+
+#define BacklightControlBit 0x01 /* CR3A */
+#define Win9xforJap 0x40
+#define Win9xforKorea 0x80
+
+#define ForceMDBits 0x07 /* CR3B */
+#define ForceMD_JDOS 0x00
+#define ForceMD_640x400T 0x01
+#define ForceMD_640x350T 0x02
+#define ForceMD_720x400T 0x03
+#define ForceMD_640x480E 0x04
+#define ForceMD_640x400E 0x05
+#define ForceP1Bit 0x10
+#define ForceP2Bit 0x20
+#define EnableForceMDinBIOS 0x40
+#define EnableForceMDinDrv 0x80
+
+#ifdef NewScratch /* New Scratch */
+/* ---------------------- VUMA Information */
+#define LCDSettingFromCMOS 0x04 /* CR3C */
+#define TVSettingFromCMOS 0x08
+#define DisplayDeviceFromCMOS 0x10
+#define HKSupportInSBIOS 0x20
+#define OSDSupportInSBIOS 0x40
+#define DisableLogo 0x80
+
+/* ---------------------- HK Evnet Definition */
+#define HKEvent 0x0f /* CR3D */
+#define HK_ModeSwitch 0x01
+#define HK_Expanding 0x02
+#define HK_OverScan 0x03
+#define HK_Brightness 0x04
+#define HK_Contrast 0x05
+#define HK_Mute 0x06
+#define HK_Volume 0x07
+#define ModeSwitchStatus 0xf0
+#define ActiveCRT1 0x10
+#define ActiveLCD 0x0020
+#define ActiveTV 0x40
+#define ActiveCRT2 0x80
+
+#define TVSwitchStatus 0x1f /* CR3E */
+#define ActiveAVideo 0x01
+#define ActiveSVideo 0x02
+#define ActiveSCART 0x04
+#define ActiveHiTV 0x08
+#define ActiveYPbPr 0x10
+
+#define EnableHKEvent 0x01 /* CR3F */
+#define EnableOSDEvent 0x02
+#define StartOSDEvent 0x04
+#define IgnoreHKEvent 0x08
+#define IgnoreOSDEvent 0x10
+#else /* Old Scratch */
+#define OSD_SBIOS 0x02 /* SR17 */
+#define DisableLogo 0x04
+#define SelectKDOS 0x08
+#define KorWinMode 0x10
+#define KorMode3Bit 0x0020
+#define PSCCtrlBit 0x40
+#define NPSCCtrlBitShift 6
+#define BlueScreenBit 0x80
+
+#define HKEvent 0x0f /* CR79 */
+#define HK_ModeSwitch 0x01
+#define HK_Expanding 0x02
+#define HK_OverScan 0x03
+#define HK_Brightness 0x04
+#define HK_Contrast 0x05
+#define HK_Mute 0x06
+#define HK_Volume 0x07
+#define ActivePAL 0x0020
+#define ActivePALShift 5
+#define ActiveNonExpanding 0x40
+#define ActiveNonExpandingShift 6
+#define ActiveOverScan 0x80
+#define ActiveOverScanShift 7
+
+#define ModeSwitchStatus 0x0b /* SR15 */
+#define ActiveCRT1 0x01
+#define ActiveLCD 0x02
+#define ActiveCRT2 0x08
+
+#define TVSwitchStatus 0xf0 /* SR16 */
+#define TVConfigShift 3
+#define ActiveTV 0x01
+#define ActiveYPbPr 0x04
+#define ActiveAVideo 0x10
+#define ActiveSVideo 0x0020
+#define ActiveSCART 0x40
+#define ActiveHiTV 0x80
+
+#define EnableHKEvent 0x01 /* CR7A */
+#define EnableOSDEvent 0x02
+#define StartOSDEvent 0x04
+#define CMOSSupport 0x08
+#define HotKeySupport 0x10
+#define IngoreHKOSDEvent 0x20
+#endif
+
+/* //------------- Misc. Definition */
+#define SelectCRT1Rate 00h
+/* #define SelectCRT2Rate 04h */
+
+#define DDC1DelayTime 1000
+#ifdef TRUMPION
+#define DDC2DelayTime 15
+#else
+#define DDC2DelayTime 150
+#endif
+
+#define R_FACTOR 04Dh
+#define G_FACTOR 097h
+#define B_FACTOR 01Ch
+/* --------------------------------------------------------- */
+/* translated from asm code 301def.h */
+/* */
+/* --------------------------------------------------------- */
+#define LCDDataLen 8
+#define HiTVDataLen 12
+#define TVDataLen 12
+#define LVDSCRT1Len_H 8
+#define LVDSCRT1Len_V 7
+#define LVDSDataLen 6
+#define LVDSDesDataLen 6
+#define LCDDesDataLen 6
+#define LVDSDesDataLen2 8
+#define LCDDesDataLen2 8
+#define CHTVRegLen 16
+#define CHLVRegLen 12
+
+#define StHiTVHT 892
+#define StHiTVVT 1126
+#define StHiTextTVHT 1000
+#define StHiTextTVVT 1126
+#define ExtHiTVHT 2100
+#define ExtHiTVVT 1125
+#define NTSCHT 1716
+#define NTSCVT 525
+#define NTSC1024x768HT 1908
+#define NTSC1024x768VT 525
+#define PALHT 1728
+#define PALVT 625
+
+#define YPbPrTV525iHT 1716 /* YPbPr */
+#define YPbPrTV525iVT 525
+#define YPbPrTV525pHT 1716
+#define YPbPrTV525pVT 525
+#define YPbPrTV750pHT 1650
+#define YPbPrTV750pVT 750
+
+#define CRT2VCLKSel 0xc0
+
+#define CRT2Delay1 0x04 /* XGI301 */
+#define CRT2Delay2 0x0A /* 301B,302 */
+
+
+#define VCLK25_175 0x00
+#define VCLK28_322 0x01
+#define VCLK31_5 0x02
+#define VCLK36 0x03
+#define VCLK40 0x04
+#define VCLK43_163 0x05
+#define VCLK44_9 0x06
+#define VCLK49_5 0x07
+#define VCLK50 0x08
+#define VCLK52_406 0x09
+#define VCLK56_25 0x0A
+#define VCLK65 0x0B
+#define VCLK67_765 0x0C
+#define VCLK68_179 0x0D
+#define VCLK72_852 0x0E
+#define VCLK75 0x0F
+#define VCLK75_8 0x10
+#define VCLK78_75 0x11
+#define VCLK79_411 0x12
+#define VCLK83_95 0x13
+#define VCLK84_8 0x14
+#define VCLK86_6 0x15
+#define VCLK94_5 0x16
+#define VCLK104_998 0x17
+#define VCLK105_882 0x18
+#define VCLK108_2 0x19
+#define VCLK109_175 0x1A
+#define VCLK113_309 0x1B
+#define VCLK116_406 0x1C
+#define VCLK132_258 0x1D
+#define VCLK135_5 0x1E
+#define VCLK139_054 0x1F
+#define VCLK157_5 0x20
+#define VCLK162 0x21
+#define VCLK175 0x22
+#define VCLK189 0x23
+#define VCLK194_4 0x24
+#define VCLK202_5 0x25
+#define VCLK229_5 0x26
+#define VCLK234 0x27
+#define VCLK252_699 0x28
+#define VCLK254_817 0x29
+#define VCLK265_728 0x2A
+#define VCLK266_952 0x2B
+#define VCLK269_655 0x2C
+#define VCLK272_042 0x2D
+#define VCLK277_015 0x2E
+#define VCLK286_359 0x2F
+#define VCLK291_132 0x30
+#define VCLK291_766 0x31
+#define VCLK309_789 0x32
+#define VCLK315_195 0x33
+#define VCLK323_586 0x34
+#define VCLK330_615 0x35
+#define VCLK332_177 0x36
+#define VCLK340_477 0x37
+#define VCLK375_847 0x38
+#define VCLK388_631 0x39
+#define VCLK125_999 0x51
+#define VCLK148_5 0x52
+#define VCLK178_992 0x54
+#define VCLK217_325 0x55
+#define VCLK299_505 0x56
+#define YPbPr750pVCLK 0x57
+
+#define TVVCLKDIV2 0x3A
+#define TVVCLK 0x3B
+#define HiTVVCLKDIV2 0x3C
+#define HiTVVCLK 0x3D
+#define HiTVSimuVCLK 0x3E
+#define HiTVTextVCLK 0x3F
+#define VCLK39_77 0x40
+/* #define YPbPr750pVCLK 0x0F */
+#define YPbPr525pVCLK 0x3A
+/* #define ;;YPbPr525iVCLK 0x3B */
+/* #define ;;YPbPr525iVCLK_2 0x3A */
+#define NTSC1024VCLK 0x41
+#define VCLK25_175_41 0x42 /* ; ScaleLCD */
+#define VCLK25_175_42 0x43
+#define VCLK28_322_43 0x44
+#define VCLK40_44 0x45
+#define VCLKQVGA_1 0x46 /* ; QVGA */
+#define VCLKQVGA_2 0x47
+#define VCLKQVGA_3 0x48
+#define VCLK35_2 0x49 /* ; 800x480 */
+#define VCLK122_61 0x4A
+#define VCLK80_350 0x4B
+#define VCLK107_385 0x4C
+
+#define CHTVVCLK30_2 0x50 /* ;;CHTV */
+#define CHTVVCLK28_1 0x51
+#define CHTVVCLK43_6 0x52
+#define CHTVVCLK26_4 0x53
+#define CHTVVCLK24_6 0x54
+#define CHTVVCLK47_8 0x55
+#define CHTVVCLK31_5 0x56
+#define CHTVVCLK26_2 0x57
+#define CHTVVCLK39 0x58
+#define CHTVVCLK36 0x59
+
+#define CH7007TVVCLK30_2 0x00 /* [Billy] 2007/05/18 For CH7007 */
+#define CH7007TVVCLK28_1 0x01
+#define CH7007TVVCLK43_6 0x02
+#define CH7007TVVCLK26_4 0x03
+#define CH7007TVVCLK24_6 0x04
+#define CH7007TVVCLK47_8 0x05
+#define CH7007TVVCLK31_5 0x06
+#define CH7007TVVCLK26_2 0x07
+#define CH7007TVVCLK39 0x08
+#define CH7007TVVCLK36 0x09
+
+#define RES320x200 0x00
+#define RES320x240 0x01
+#define RES400x300 0x02
+#define RES512x384 0x03
+#define RES640x400 0x04
+#define RES640x480x60 0x05
+#define RES640x480x72 0x06
+#define RES640x480x75 0x07
+#define RES640x480x85 0x08
+#define RES640x480x100 0x09
+#define RES640x480x120 0x0A
+#define RES640x480x160 0x0B
+#define RES640x480x200 0x0C
+#define RES800x600x56 0x0D
+#define RES800x600x60 0x0E
+#define RES800x600x72 0x0F
+#define RES800x600x75 0x10
+#define RES800x600x85 0x11
+#define RES800x600x100 0x12
+#define RES800x600x120 0x13
+#define RES800x600x160 0x14
+#define RES1024x768x43 0x15
+#define RES1024x768x60 0x16
+#define RES1024x768x70 0x17
+#define RES1024x768x75 0x18
+#define RES1024x768x85 0x19
+#define RES1024x768x100 0x1A
+#define RES1024x768x120 0x1B
+#define RES1280x1024x43 0x1C
+#define RES1280x1024x60 0x1D
+#define RES1280x1024x75 0x1E
+#define RES1280x1024x85 0x1F
+#define RES1600x1200x60 0x20
+#define RES1600x1200x65 0x21
+#define RES1600x1200x70 0x22
+#define RES1600x1200x75 0x23
+#define RES1600x1200x85 0x24
+#define RES1600x1200x100 0x25
+#define RES1600x1200x120 0x26
+#define RES1920x1440x60 0x27
+#define RES1920x1440x65 0x28
+#define RES1920x1440x70 0x29
+#define RES1920x1440x75 0x2A
+#define RES1920x1440x85 0x2B
+#define RES1920x1440x100 0x2C
+#define RES2048x1536x60 0x2D
+#define RES2048x1536x65 0x2E
+#define RES2048x1536x70 0x2F
+#define RES2048x1536x75 0x30
+#define RES2048x1536x85 0x31
+#define RES800x480x60 0x32
+#define RES800x480x75 0x33
+#define RES800x480x85 0x34
+#define RES1024x576x60 0x35
+#define RES1024x576x75 0x36
+#define RES1024x576x85 0x37
+#define RES1280x720x60 0x38
+#define RES1280x720x75 0x39
+#define RES1280x720x85 0x3A
+#define RES1280x960x60 0x3B
+#define RES720x480x60 0x3C
+#define RES720x576x56 0x3D
+#define RES856x480x79I 0x3E
+#define RES856x480x60 0x3F
+#define RES1280x768x60 0x40
+#define RES1400x1050x60 0x41
+#define RES1152x864x60 0x42
+#define RES1152x864x75 0x43
+#define RES1024x768x160 0x44
+#define RES1280x960x75 0x45
+#define RES1280x960x85 0x46
+#define RES1280x960x120 0x47
+
+#define LFBDRAMTrap 0x30
+#endif
diff --git a/drivers/staging/xgifb/vb_ext.c b/drivers/staging/xgifb/vb_ext.c
new file mode 100644
index 000000000000..49b39ee93a89
--- /dev/null
+++ b/drivers/staging/xgifb/vb_ext.c
@@ -0,0 +1,1370 @@
+#include "osdef.h"
+
+
+
+
+#ifdef WIN2000
+
+#include <dderror.h>
+#include <devioctl.h>
+#include <miniport.h>
+#include <ntddvdeo.h>
+#include <video.h>
+#include "xgiv.h"
+#include "dd_i2c.h"
+#include "tools.h"
+#endif /* WIN2000 */
+
+#ifdef LINUX_XF86
+#include "xf86.h"
+#include "xf86PciInfo.h"
+#include "xgi.h"
+#include "xgi_regs.h"
+#endif
+
+#ifdef LINUX_KERNEL
+#include <linux/version.h>
+#include <asm/io.h>
+#include <linux/types.h>
+#include "XGIfb.h"
+/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <video/XGIfb.h>
+#else
+#include <linux/XGIfb.h>
+#endif*/
+#endif
+
+
+
+#include "vb_def.h"
+#include "vgatypes.h"
+#include "vb_struct.h"
+#include "vb_util.h"
+#include "vb_setmode.h"
+#include "vb_ext.h"
+extern UCHAR XGI330_SoftSetting;
+extern UCHAR XGI330_OutputSelect;
+extern USHORT XGI330_RGBSenseData2;
+extern USHORT XGI330_YCSenseData2;
+extern USHORT XGI330_VideoSenseData2;
+#ifdef WIN2000
+extern UCHAR SenseCHTV(PHW_DEVICE_EXTENSION pHWDE); /* 2007/05/17 Billy */
+#endif
+void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo );
+BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo);
+USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGINew_GetLCDDDCInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ;
+BOOLEAN XGINew_BridgeIsEnable(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo );
+BOOLEAN XGINew_Sense(USHORT tempbx,USHORT tempcx, PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
+
+/**************************************************************
+ Dynamic Sense
+*************************************************************/
+
+void XGI_WaitDisplay(void);
+BOOLEAN XGI_Is301C(PVB_DEVICE_INFO);
+BOOLEAN XGI_Is301LV(PVB_DEVICE_INFO);
+
+#ifdef WIN2000
+UCHAR XGI_SenseLCD(PHW_DEVICE_EXTENSION, PVB_DEVICE_INFO);
+UCHAR XGI_GetLCDDDCInfo(PHW_DEVICE_EXTENSION,PVB_DEVICE_INFO);
+
+extern BOOL bGetDdcInfo(
+PHW_DEVICE_EXTENSION pHWDE,
+ULONG ulWhichOne,
+PUCHAR pjQueryBuffer,
+ULONG ulBufferSize
+ );
+
+#endif
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_Is301B */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_Is301B( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT flag ;
+
+ flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) ;
+
+ if ( flag > 0x0B0 )
+ return( 0 ) ; /* 301b */
+ else
+ return( 1 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_Is301C */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_Is301C( PVB_DEVICE_INFO pVBInfo )
+{
+ if ( ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) & 0xF0 ) == 0xC0 )
+ return( 1 ) ;
+
+ if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) >= 0xD0 )
+ {
+ if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) == 0xE0 )
+ return( 1 ) ;
+ }
+
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_Is301LV */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_Is301LV( PVB_DEVICE_INFO pVBInfo )
+{
+ if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) >= 0xD0 )
+ {
+ if ( XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) == 0xFF )
+ {
+ return( 1 ) ;
+ }
+ }
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_Sense */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_Sense( USHORT tempbx , USHORT tempcx, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp , i , tempch ;
+
+ temp = tempbx & 0xFF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp |= ( tempcx & 0x00FF ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ;
+
+ for( i = 0 ; i < 10 ; i++ )
+ XGI_LongWait( pVBInfo) ;
+
+ tempch = ( tempcx & 0x7F00 ) >> 8 ;
+ temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ;
+ temp = temp ^ ( 0x0E ) ;
+ temp &= tempch ;
+
+ if ( temp > 0 )
+ return( 1 ) ;
+ else
+ return( 0 ) ;
+}
+
+#ifdef WIN2000
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SenseLCD */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGI_SenseLCD( PHW_DEVICE_EXTENSION pHWDE, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax , tempbx , tempcx ;
+ UCHAR SoftSetting = XGI330_SoftSetting ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV ) )
+ return( 1 ) ;
+
+
+ if ( SoftSetting & HotPlugFunction ) /* Hot Plug Detection */
+ {
+ XGINew_SetRegAND( pVBInfo->Part4Port , 0x0F , 0x3F ) ;
+ tempbx = 0 ;
+ tempcx = 0x9010 ;
+ if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) )
+ return( 1 ) ;
+
+ return( 0 ) ;
+ }
+ else /* Get LCD Info from EDID */
+ return(XGI_GetLCDDDCInfo(pHWDE, pVBInfo));
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLCDDDCInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGI_GetLCDDDCInfo( PHW_DEVICE_EXTENSION pHWDE , PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR tempah , tempbl , tempbh ;
+ USHORT tempbx , temp ;
+ UCHAR pjEDIDBuf[ 256 ] ;
+ ULONG ulBufferSize = 256 ;
+ UCHAR bMASK_OUTPUTSTATE_CRT2LCD = 2 ; /* 0423 shampoo */
+
+ bGetDdcInfo( pHWDE , MASK_OUTPUTSTATE_CRT2LCD , pjEDIDBuf , ulBufferSize ) ;
+ if ( ( *( ( PULONG )pjEDIDBuf ) == 0xFFFFFF00 ) && ( *( ( PULONG )( pjEDIDBuf + 4 ) ) == 0x00FFFFFF ) )
+ {
+ tempah = Panel1024x768 ;
+ tempbl=( *( pjEDIDBuf + 0x3A ) ) & 0xf0 ;
+
+ if ( tempbl != 0x40 )
+ {
+ tempah = Panel1600x1200 ;
+ if ( tempbl != 0x60 )
+ {
+ tempah = Panel1280x1024 ;
+ tempbh = ( *( pjEDIDBuf + 0x3B ) ) ;
+ if ( tempbh != 0x00 )
+ {
+ tempah = Panel1280x960 ;
+ if ( tempbh != 0x0C0 )
+ {
+ tempbx = ( ( *( pjEDIDBuf + 0x24 ) ) << 8 ) | ( *( pjEDIDBuf + 0x23 ) ) ;
+ tempah = Panel1280x1024 ;
+ if ( !( tempbx & 0x0100 ) )
+ {
+ tempah = Panel1024x768 ;
+ if ( !( tempbx & 0x0E00 ) )
+ {
+ tempah = Panel1280x1024 ;
+ }
+ }
+ }
+
+ if ( tempbx & 0x00FF )
+ {
+ temp = ScalingLCD ;
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x37 , temp ) ;
+ }
+ }
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ;
+ tempah = ( ( *( pjEDIDBuf + 0x47 ) ) & 0x06 ) ; /* Polarity */
+ tempah = ( tempah ^ 0x06 ) << 4 ;
+ tempah |= LCDSync ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ( ~LCDSyncBit ) , tempah ) ;
+ tempbh= XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ;
+ tempbh &= 0x07 ;
+ if ( tempbh == Panel1280x960 )
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x37 , 0x0E ) ;
+ }
+ else if ( *pjEDIDBuf == 0x20 )
+ {
+ tempah = Panel1024x768 ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , ( ~0x07 ) , tempah ) ;
+ }
+ else
+ {
+ return( 0 ) ;
+ }
+
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DySense */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus)
+{
+ UCHAR pre_CRD,pre_SR1E , pre_Part2_0 , pre_Part4_D ;
+ USHORT tempax , tempbx , tempcx , pushax , temp ;
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ UCHAR OutputSelect = XGI330_OutputSelect ;
+ PXGI_HW_DEVICE_INFO HwDeviceExtension= pHWDE->pXGIHWDE ;
+ UCHAR bConnectStatus = 0 ;
+ pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ROMAddr = pHWDE->pjVirtualRomBase ;
+
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pushax = XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ; /* 0512 Fix Dysense hanged */
+ temp = ( pushax & 0x00FF ) | 0x80 ;
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x17 , temp ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
+ /* beginning of dynamic sense CRT1 */
+
+ pVBInfo->IF_DEF_CH7007 = 0;
+ if (pHWDE->bCH7007)
+ {
+ InitTo330Pointer( pHWDE->pXGIHWDE->jChipType, pVBInfo ) ;
+ HwDeviceExtension->pDevice = (PVOID)pHWDE;
+ pVBInfo->IF_DEF_CH7007 = 1;
+ /* [Billy] 2007/05/14 For CH7007 */
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ bConnectStatus = SenseCHTV(HwDeviceExtension->pDevice) ; /* 07/05/28 */
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~0x03 , (UCHAR)bConnectStatus ) ;
+ }
+ }
+ if(( pHWDE->jChipID >= XG40 ) || ( pHWDE->jChipID >= XG20 ))
+ {
+
+ if ( pHWDE->jChipID >= XG40 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ; /* write sense pattern 30->4a */
+ else
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x5F ) ; /* write sense pattern */
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x53 , 0xFF , 0x02 ) ; /* enable sense DAC */
+ XGI_WaitDisply(pVBInfo) ;
+
+ if(XGINew_GetReg2( pVBInfo->P3c2 ) & 0x10 )
+ bConnectStatus |= Monitor1Sense ;
+
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x53 , 0xFD ) ; /* disable sense DAC */
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x57 , 0x00 ) ; /* clear sense pattern */
+
+
+ /* ---------- End of dynamic sense CRT1 ----------- */
+
+ /* ---------- beginning of dynamic sense VB ------------ */
+ pre_SR1E = XGINew_GetReg1( pVBInfo->P3c4 , 0x1E ) ;
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ; /* Enable CRT2,work-a-round for 301B/301LV/302LV */
+ pre_Part2_0 = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
+ pre_Part4_D = XGINew_GetReg1( pVBInfo->Part4Port , 0x0D ) ;
+
+ if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~0x07 , 0x01 ) ; /* Set Part4 0x0D D[2:0] to 001b */
+
+ /* tempax = 0 ; */
+ if ( !XGI_Is301LV( pVBInfo ) )
+ {
+ tempbx = XGI330_RGBSenseData2 ;
+ tempcx = 0x0E08 ;
+ if(XGINew_Sense( tempbx , tempcx, pVBInfo ) )
+ {
+ bConnectStatus |= Monitor2Sense ;
+ if ( OutputSelect & SetSCARTOutput )
+ {
+ bConnectStatus ^= ( Monitor2Sense | SCARTSense ) ;
+ }
+ }
+ }
+ if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x0D , 0x04 ) ; /* Set Part4 0x0D D[2]=1 for dynamic sense */
+
+ if ( ( XGINew_Is301B( pVBInfo ) ) )
+ XGINew_SetRegOR( pVBInfo->Part2Port , 0x00 , 0x0C ) ; /* ????????? */
+
+ if ( XGINew_SenseHiTV( HwDeviceExtension , pVBInfo) ) /* add by kuku for Dysense HiTV //start */
+ {
+ bConnectStatus|= YPbPrSense ;
+ }
+ else
+ {
+ tempbx = XGI330_YCSenseData2 ; /* Y/C Sense Data Ptr */
+ tempcx = 0x0604 ;
+ if ( XGINew_Sense( tempbx , tempcx , pVBInfo) )
+ bConnectStatus |= SVIDEOSense ;
+
+ if ( OutputSelect & BoardTVType )
+ {
+ tempbx = XGI330_VideoSenseData2 ;
+ tempcx = 0x0804 ;
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo) )
+ bConnectStatus|= AVIDEOSense ;
+ }
+ else
+ {
+ if ( !( bConnectStatus & SVIDEOSense ) )
+ {
+ tempbx = XGI330_VideoSenseData2 ;
+ tempcx = 0x0804 ;
+ if ( XGINew_Sense( tempbx , tempcx, pVBInfo ) )
+ bConnectStatus |= AVIDEOSense ;
+ }
+ }
+ } /* end */
+ /* DySenseVBCnt */
+
+ tempbx = 0 ;
+ tempcx = 0 ;
+ XGINew_Sense(tempbx , tempcx, pVBInfo ) ;
+
+ if ( !( bConnectStatus & Monitor2Sense ) )
+ {
+ if ( XGI_SenseLCD( pHWDE , pVBInfo ) )
+ bConnectStatus |= LCDSense ;
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~( AVIDEOSense | SVIDEOSense | LCDSense | Monitor2Sense | Monitor1Sense ) , bConnectStatus ) ;
+
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0D , pre_Part4_D ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , pre_Part2_0 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1E , pre_SR1E ) ;
+
+ if ( XGI_Is301C( pVBInfo ) ) /* 301C only */
+ {
+ tempax = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
+ if ( tempax & 0x20 )
+ {
+ /* Reset VBPro */
+ for( tempcx = 2 ; tempcx > 0 ; tempcx-- )
+ {
+ tempax ^= 0x20 ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , tempax ) ;
+ }
+ }
+ }
+ /* End of dynamic sense VB */
+ }
+ else
+ {
+ XGI_SenseCRT1(pVBInfo) ;
+ XGI_GetSenseStatus( HwDeviceExtension, pVBInfo ) ; /* sense CRT2 */
+ bConnectStatus = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ;
+ }
+ temp = pushax & 0x00FF ; /* 0512 Fix Dysense hanged */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , temp ) ;
+ if ( bConnectStatus )
+ {
+ *ujConnectStatus = bConnectStatus ;
+ return( 1 ) ;
+ }
+ else
+ return( 0 ) ;
+}
+
+#endif /* WIN2000 */
+
+/* --------------------------------------------------------------------- */
+/* Function : XGISetDPMS */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+VOID XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE )
+{
+ USHORT ModeNo, ModeIdIndex ;
+ UCHAR temp ;
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->BaseAddr = (ULONG)pXGIHWDE->pjIOAddress ;
+ pVBInfo->ROMAddr = pXGIHWDE->pjVirtualRomBase ;
+
+
+ pVBInfo->IF_DEF_LVDS = 0 ;
+ pVBInfo->IF_DEF_CH7005 = 0 ;
+ pVBInfo->IF_DEF_HiVision = 1 ;
+ pVBInfo->IF_DEF_LCDA = 1 ;
+ pVBInfo->IF_DEF_CH7017 = 0 ;
+ pVBInfo->IF_DEF_YPbPr = 1 ;
+ pVBInfo->IF_DEF_CRT2Monitor = 0 ;
+ pVBInfo->IF_DEF_VideoCapture = 0 ;
+ pVBInfo->IF_DEF_ScaleLCD = 0 ;
+ pVBInfo->IF_DEF_OEMUtil = 0 ;
+ pVBInfo->IF_DEF_PWD = 0 ;
+
+ InitTo330Pointer( pXGIHWDE->jChipType, pVBInfo ) ;
+ ReadVBIOSTablData( pXGIHWDE->jChipType , pVBInfo) ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 )
+ {
+ if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) & 0x20 )
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ }
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_CH7007 == 0 )
+ {
+ XGINew_SetModeScratch ( pXGIHWDE , pVBInfo ) ;
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ; /* 1.Openkey */
+ XGI_UnLockCRT2( pXGIHWDE , pVBInfo) ;
+ ModeNo = XGINew_GetReg1( pVBInfo->P3d4 , 0x34 ) ;
+ XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ;
+ XGI_GetVGAType( pXGIHWDE , pVBInfo ) ;
+
+ if ( ( pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) || ( pVBInfo->IF_DEF_CH7007 == 1 ))
+ {
+ XGI_GetVBType( pVBInfo ) ;
+ XGI_GetVBInfo( ModeNo , ModeIdIndex , pXGIHWDE, pVBInfo ) ;
+ XGI_GetTVInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetLCDInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ }
+
+ if ( VESA_POWER_STATE == 0x00000400 )
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) & 0xFE ) ) ;
+ else
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , ( UCHAR )( XGINew_GetReg1( pVBInfo->Part4Port , 0x31 ) | 0x01 ) ) ;
+
+ temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1f ) ;
+ temp &= 0x3f ;
+ switch ( VESA_POWER_STATE )
+ {
+ case 0x00000000: /* on */
+ if ( ( pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x00 ) ) ;
+ XGI_EnableBridge( pXGIHWDE, pVBInfo ) ;
+ }
+ else
+ {
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ XGI_XG21BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */
+ XGI_XG21SetPanelDelay( 2,pVBInfo ) ;
+ }
+ }
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ XGI_XG27BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */
+ XGI_XG21SetPanelDelay( 2,pVBInfo ) ;
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , ~0xC0 , 0x00 ) ;
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x01 , ~0x20 ) ; /* CRT on */
+
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ if ( temp & 0xE0 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ; /* DVO ON */
+ XGI_SetXG21FPBits( pVBInfo );
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */
+ /*XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~0x20 , 0x20 ) ;*/ /* LCD Display ON */
+ }
+ XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */
+ XGI_DisplayOn( pXGIHWDE, pVBInfo );
+ }
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ if ( temp & 0xE0 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ; /* DVO ON */
+ XGI_SetXG27FPBits( pVBInfo );
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */
+ /*XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~0x20 , 0x20 ) ;*/ /* LCD Display ON */
+ }
+ XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */
+ XGI_DisplayOn( pXGIHWDE, pVBInfo );
+ }
+ }
+ break ;
+ case 0x00000100: /* standby */
+ if ( pXGIHWDE->jChipType >= XG21 )
+ {
+ XGI_DisplayOff( pXGIHWDE, pVBInfo );
+ }
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x40 ) ) ;
+ break ;
+ case 0x00000200: /* suspend */
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ XGI_DisplayOff( pXGIHWDE, pVBInfo );
+ XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */
+ }
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ XGI_DisplayOff( pXGIHWDE, pVBInfo );
+ XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0x80 ) ) ;
+ break ;
+ case 0x00000400: /* off */
+ if ( (pXGIHWDE->ujVBChipID == VB_CHIP_301 ) || ( pXGIHWDE->ujVBChipID == VB_CHIP_302 ) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1f , ( UCHAR )( temp | 0xc0 ) ) ;
+ XGI_DisableBridge( pXGIHWDE, pVBInfo ) ;
+ }
+ else
+ {
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ XGI_DisplayOff( pXGIHWDE, pVBInfo );
+
+ XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ if ( temp & 0xE0 )
+ {
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x09 , ~0x80 ) ; /* DVO Off */
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Enable write GPIOF */
+ /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x48 , ~0x20 ) ;*/ /* LCD Display OFF */
+ }
+ }
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ XGI_DisplayOff( pXGIHWDE, pVBInfo );
+
+ XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* LVDS signal off */
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ if ( temp & 0xE0 )
+ {
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x09 , ~0x80 ) ; /* DVO Off */
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , ~0xC0 , 0xC0 ) ;
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x01 , 0x20 ) ; /* CRT Off */
+
+ if ( ( pXGIHWDE->jChipType == XG21 ) && ( pVBInfo->IF_DEF_LVDS == 1 ) )
+ {
+ XGI_XG21SetPanelDelay( 4,pVBInfo ) ;
+ XGI_XG21BLSignalVDD( 0x01 , 0x00, pVBInfo ) ; /* LVDS VDD off */
+ XGI_XG21SetPanelDelay( 5,pVBInfo ) ;
+ }
+ if ( ( pXGIHWDE->jChipType == XG27 ) && ( pVBInfo->IF_DEF_LVDS == 1 ) )
+ {
+ XGI_XG21SetPanelDelay( 4,pVBInfo ) ;
+ XGI_XG27BLSignalVDD( 0x01 , 0x00, pVBInfo ) ; /* LVDS VDD off */
+ XGI_XG21SetPanelDelay( 5,pVBInfo ) ;
+ }
+ }
+ break ;
+
+ default:
+ break ;
+ }
+ XGI_LockCRT2( pXGIHWDE , pVBInfo ) ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetSenseStatus */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax = 0 , tempbx , tempcx , temp ,
+ P2reg0 = 0 , SenseModeNo = 0 , OutputSelect = *pVBInfo->pOutputSelect ,
+ ModeIdIndex , i ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; /* ynlai 02/27/2002 */
+ tempbx = XGINew_GetReg1( pVBInfo->P3c4 , 0x1B ) ;
+ tempax = ( ( tempax & 0xFE ) >> 1 ) | ( tempbx << 8 ) ;
+ if ( tempax == 0x00 )
+ { /* Get Panel id from DDC */
+ temp = XGINew_GetLCDDDCInfo( HwDeviceExtension, pVBInfo ) ;
+ if ( temp == 1 )
+ { /* LCD connect */
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x39 , 0xFF , 0x01 ) ; /* set CR39 bit0="1" */
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , 0xEF , 0x00 ) ; /* clean CR37 bit4="0" */
+ temp = LCDSense ;
+ }
+ else
+ { /* LCD don't connect */
+ temp = 0 ;
+ }
+ }
+ else
+ {
+ XGINew_GetPanelID(pVBInfo) ;
+ temp = LCDSense ;
+ }
+
+ tempbx = ~( LCDSense | AVIDEOSense | SVIDEOSense ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , tempbx , temp ) ;
+ }
+ else
+ { /* for 301 */
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ { /* for HiVision */
+ tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x38 ) ;
+ temp = tempax & 0x01 ;
+ tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) ;
+ temp = temp | ( tempax & 0x02 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xA0 , temp ) ;
+ }
+ else
+ {
+ if ( XGI_BridgeIsOn( pVBInfo ) )
+ {
+ P2reg0 = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
+ if ( !XGINew_BridgeIsEnable( HwDeviceExtension, pVBInfo ) )
+ {
+ SenseModeNo = 0x2e ;
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x41 ) ; */
+ /* XGISetModeNew( HwDeviceExtension , 0x2e ) ; // ynlai InitMode */
+
+ temp = XGI_SearchModeID( SenseModeNo , &ModeIdIndex, pVBInfo ) ;
+ XGI_GetVGAType( HwDeviceExtension , pVBInfo) ;
+ XGI_GetVBType( pVBInfo ) ;
+ pVBInfo->SetFlag = 0x00 ;
+ pVBInfo->ModeType = ModeVGA ;
+ pVBInfo->VBInfo = SetCRT2ToRAMDAC | LoadDACFlag | SetInSlaveMode ;
+ XGI_GetLCDInfo( 0x2e , ModeIdIndex, pVBInfo ) ;
+ XGI_GetTVInfo( 0x2e , ModeIdIndex, pVBInfo ) ;
+ XGI_EnableBridge( HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT2Group301( SenseModeNo , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT2ModeRegs( 0x2e , HwDeviceExtension, pVBInfo ) ;
+ /* XGI_DisableBridge( HwDeviceExtension, pVBInfo ) ; */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xDF , 0x20 ) ; /* Display Off 0212 */
+ for( i = 0 ; i < 20 ; i++ )
+ {
+ XGI_LongWait(pVBInfo) ;
+ }
+ }
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , 0x1c ) ;
+ tempax = 0 ;
+ tempbx = *pVBInfo->pRGBSenseData ;
+
+ if ( !( XGINew_Is301B( pVBInfo ) ) )
+ {
+ tempbx = *pVBInfo->pRGBSenseData2 ;
+ }
+
+ tempcx = 0x0E08 ;
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ tempax |= Monitor2Sense ;
+ }
+ }
+
+ if ( pVBInfo->VBType & VB_XGI301C)
+ {
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x0d , 0x04 ) ;
+ }
+
+ if ( XGINew_SenseHiTV( HwDeviceExtension , pVBInfo) ) /* add by kuku for Multi-adapter sense HiTV */
+ {
+ tempax |= HiTVSense ;
+ if ( ( pVBInfo->VBType & VB_XGI301C ) )
+ {
+ tempax ^= ( HiTVSense | YPbPrSense ) ;
+ }
+ }
+
+ if ( !( tempax & ( HiTVSense | YPbPrSense ) ) ) /* start */
+ {
+
+ tempbx = *pVBInfo->pYCSenseData ;
+
+ if ( !( XGINew_Is301B( pVBInfo ) ) )
+ {
+ tempbx=*pVBInfo->pYCSenseData2;
+ }
+
+ tempcx = 0x0604 ;
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ tempax |= SVIDEOSense ;
+ }
+ }
+
+ if ( OutputSelect & BoardTVType )
+ {
+ tempbx = *pVBInfo->pVideoSenseData ;
+
+ if ( !( XGINew_Is301B( pVBInfo ) ) )
+ {
+ tempbx = *pVBInfo->pVideoSenseData2 ;
+ }
+
+ tempcx = 0x0804 ;
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ tempax |= AVIDEOSense ;
+ }
+ }
+ }
+ else
+ {
+ if ( !( tempax & SVIDEOSense ) )
+ {
+ tempbx = *pVBInfo->pVideoSenseData ;
+
+ if ( !( XGINew_Is301B( pVBInfo ) ) )
+ {
+ tempbx=*pVBInfo->pVideoSenseData2;
+ }
+
+ tempcx = 0x0804 ;
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ if ( XGINew_Sense(tempbx , tempcx, pVBInfo ) )
+ {
+ tempax |= AVIDEOSense ;
+ }
+ }
+ }
+ }
+ }
+ } /* end */
+ if ( !( tempax & Monitor2Sense ) )
+ {
+ if ( XGINew_SenseLCD( HwDeviceExtension, pVBInfo ) )
+ {
+ tempax |= LCDSense ;
+ }
+ }
+ tempbx = 0 ;
+ tempcx = 0 ;
+ XGINew_Sense(tempbx , tempcx, pVBInfo ) ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~0xDF , tempax ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , P2reg0 ) ;
+
+ if ( !( P2reg0 & 0x20 ) )
+ {
+ pVBInfo->VBInfo = DisableCRT2Display ;
+ /* XGI_SetCRT2Group301( SenseModeNo , HwDeviceExtension, pVBInfo ) ; */
+ }
+ }
+ }
+ XGI_DisableBridge( HwDeviceExtension, pVBInfo ) ; /* shampoo 0226 */
+
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SenseLCD */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGINew_SenseLCD( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+{
+ /* USHORT SoftSetting ; */
+ USHORT temp ;
+
+ if ( ( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40 ) )
+ temp = 0 ;
+ else
+ temp=XGINew_GetPanelID(pVBInfo) ;
+
+ if( !temp )
+ temp = XGINew_GetLCDDDCInfo( HwDeviceExtension, pVBInfo ) ;
+
+ return( temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_GetLCDDDCInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_GetLCDDDCInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT temp ;
+
+ /* add lcd sense */
+ if ( HwDeviceExtension->ulCRT2LCDType == LCD_UNKNOWN )
+ {
+ return( 0 ) ;
+ }
+ else
+ {
+ temp = ( USHORT )HwDeviceExtension->ulCRT2LCDType ;
+ switch( HwDeviceExtension->ulCRT2LCDType )
+ {
+ case LCD_INVALID:
+ case LCD_800x600:
+ case LCD_1024x768:
+ case LCD_1280x1024:
+ break ;
+
+ case LCD_640x480:
+ case LCD_1024x600:
+ case LCD_1152x864:
+ case LCD_1280x960:
+ case LCD_1152x768:
+ temp = 0 ;
+ break ;
+
+ case LCD_1400x1050:
+ case LCD_1280x768:
+ case LCD_1600x1200:
+ break ;
+
+ case LCD_1920x1440:
+ case LCD_2048x1536:
+ temp = 0 ;
+ break ;
+
+ default:
+ break ;
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x36 , 0xF0 , temp ) ;
+ return( 1 ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_GetPanelID(PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT PanelTypeTable[ 16 ] = { SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType00 ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType01 ,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType02 ,
+ SyncNN | PanelRGB18Bit | Panel640x480 | _PanelType03 ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType04 ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType05 ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType06 ,
+ SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType07 ,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType08 ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType09 ,
+ SyncNN | PanelRGB18Bit | Panel800x600 | _PanelType0A ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0B ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0C ,
+ SyncNN | PanelRGB24Bit | Panel1024x768 | _PanelType0D ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0E ,
+ SyncNN | PanelRGB18Bit | Panel1024x768 | _PanelType0F } ;
+ USHORT tempax , tempbx , temp ;
+ /* USHORT return_flag ; */
+
+ tempax = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ;
+ tempbx = tempax & 0x1E ;
+
+ if ( tempax == 0 )
+ return( 0 ) ;
+ else
+ {
+/*
+ if ( !( tempax & 0x10 ) )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ tempbx = 0 ;
+ temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x38 ) ;
+ if ( temp & 0x40 )
+ tempbx |= 0x08 ;
+ if ( temp & 0x20 )
+ tempbx |= 0x02 ;
+ if ( temp & 0x01 )
+ tempbx |= 0x01 ;
+
+ temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) ;
+ if ( temp & 0x80 )
+ tempbx |= 0x04 ;
+ }
+ else
+ {
+ return( 0 ) ;
+ }
+ }
+*/
+
+ tempbx = tempbx >> 1 ;
+ temp = tempbx & 0x00F ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x36 , temp ) ;
+ tempbx-- ;
+ tempbx = PanelTypeTable[ tempbx ] ;
+
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~( LCDSyncBit | LCDRGB18Bit ) , temp ) ;
+ return( 1 ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_BridgeIsEnable */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_BridgeIsEnable( PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT flag ;
+
+ if ( XGI_BridgeIsOn( pVBInfo ) == 0 )
+ {
+ flag = XGINew_GetReg1( pVBInfo->Part1Port , 0x0 ) ;
+
+ if ( flag & 0x050 )
+ {
+ return( 1 ) ;
+ }
+ else
+ {
+ return( 0 ) ;
+ }
+
+ }
+ return( 0 ) ;
+}
+
+/* ------------------------------------------------------ */
+/* Function : XGINew_SenseHiTV */
+/* Input : */
+/* Output : */
+/* Description : */
+/* ------------------------------------------------------ */
+BOOLEAN XGINew_SenseHiTV( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx , tempcx , temp , i , tempch;
+
+ tempbx = *pVBInfo->pYCSenseData2 ;
+
+ tempcx = 0x0604 ;
+
+ temp = tempbx & 0xFF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp |= ( tempcx & 0x00FF ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ;
+
+ for( i = 0 ; i < 10 ; i++ )
+ XGI_LongWait(pVBInfo) ;
+
+ tempch = ( tempcx & 0xFF00 ) >> 8;
+ temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ;
+ temp = temp ^ ( 0x0E ) ;
+ temp &= tempch ;
+
+ if ( temp != tempch )
+ return( 0 ) ;
+
+ tempbx = *pVBInfo->pVideoSenseData2 ;
+
+ tempcx = 0x0804 ;
+ temp = tempbx & 0xFF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp |= ( tempcx & 0x00FF ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ;
+
+ for( i = 0 ; i < 10 ; i++ )
+ XGI_LongWait(pVBInfo) ;
+
+ tempch = ( tempcx & 0xFF00 ) >> 8;
+ temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ;
+ temp = temp ^ ( 0x0E ) ;
+ temp &= tempch ;
+
+ if ( temp != tempch )
+ return( 0 ) ;
+ else
+ {
+ tempbx = 0x3FF ;
+ tempcx = 0x0804 ;
+ temp = tempbx & 0xFF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x11 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp |= ( tempcx & 0x00FF ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x10 , ~0x1F , temp ) ;
+
+ for( i = 0 ; i < 10 ; i++ )
+ XGI_LongWait(pVBInfo) ;
+
+ tempch = ( tempcx & 0xFF00 ) >> 8;
+ temp = XGINew_GetReg1( pVBInfo->Part4Port , 0x03 ) ;
+ temp = temp ^ ( 0x0E ) ;
+ temp &= tempch ;
+
+ if ( temp != tempch )
+ return( 1 ) ;
+ else
+ return( 0 ) ;
+ }
+}
+
+
+
+/*
+;-----------------------------------------------------------------------------
+; Description: Get Panel support
+; O/P :
+; BL: Panel ID=81h for no scaler LVDS
+; BH: Panel enhanced Mode Count
+; CX: Panel H. resolution
+; DX: PAnel V. resolution
+;-----------------------------------------------------------------------------
+*/
+void XGI_XG21Fun14Sub70( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+{
+
+ USHORT ModeIdIndex;
+ USHORT ModeNo;
+
+ USHORT EModeCount;
+ USHORT lvdstableindex;
+
+ lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
+ pBiosArguments->h.bl = 0x81;
+ pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE;
+ pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE;
+ EModeCount = 0;
+
+ pBiosArguments->x.ax = 0x0014;
+ for( ModeIdIndex = 0 ; ; ModeIdIndex ++ )
+ {
+ ModeNo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID;
+ if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID == 0xFF )
+ {
+ pBiosArguments->h.bh = (UCHAR) EModeCount;
+ return;
+ }
+ if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) )
+ {
+ continue;
+ }
+ EModeCount++ ;
+ }
+}
+/*(
+;-----------------------------------------------------------------------------
+;
+; Description: Get Panel mode ID for enhanced mode
+; I/P : BH: EModeIndex ( which < Panel enhanced Mode Count )
+; O/P :
+; BL: Mode ID
+; CX: H. resolution of the assigned by the index
+; DX: V. resolution of the assigned by the index
+;
+;-----------------------------------------------------------------------------
+*/
+void XGI_XG21Fun14Sub71( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+{
+
+ USHORT EModeCount;
+ USHORT ModeIdIndex,resindex;
+ USHORT ModeNo;
+ USHORT EModeIndex = pBiosArguments->h.bh;
+
+ EModeCount = 0;
+ for( ModeIdIndex = 0 ; ; ModeIdIndex ++ )
+ {
+ ModeNo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID;
+ if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeID == 0xFF )
+ {
+ pBiosArguments->x.ax = 0x0114;
+ return;
+ }
+ if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) )
+ {
+ continue;
+ }
+ if (EModeCount == EModeIndex)
+ {
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ pBiosArguments->h.bl = (UCHAR) ModeNo;
+ pBiosArguments->x.cx = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ pBiosArguments->x.dx = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ pBiosArguments->x.ax = 0x0014;
+ }
+ EModeCount++ ;
+
+ }
+
+}
+/*
+;-----------------------------------------------------------------------------
+;
+; Description: Validate Panel modes ID support
+; I/P :
+; BL: ModeID
+; O/P :
+; CX: H. resolution of the assigned by the index
+; DX: V. resolution of the assigned by the index
+;
+;-----------------------------------------------------------------------------
+*/
+void XGI_XG21Fun14Sub72( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+{
+ USHORT ModeIdIndex,resindex;
+ USHORT ModeNo;
+
+
+ ModeNo = pBiosArguments->h.bl ;
+ XGI_SearchModeID( ModeNo, &ModeIdIndex, pVBInfo);
+ if ( !XGI_XG21CheckLVDSMode( ModeNo , ModeIdIndex, pVBInfo) )
+ {
+ pBiosArguments->x.cx = 0;
+ pBiosArguments->x.dx = 0;
+ pBiosArguments->x.ax = 0x0114;
+ return;
+ }
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( ModeNo <= 0x13 )
+ {
+ pBiosArguments->x.cx = pVBInfo->StResInfo[ resindex ].HTotal ;
+ pBiosArguments->x.dx = pVBInfo->StResInfo[ resindex ].VTotal ;
+ }
+ else
+ {
+ pBiosArguments->x.cx = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ pBiosArguments->x.dx = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ }
+
+ pBiosArguments->x.ax = 0x0014;
+
+}
+
+/*
+;-----------------------------------------------------------------------------
+; Description: Get Customized Panel misc. information support
+; I/P : Select
+; to get panel horizontal timing
+; to get panel vertical timing
+; to get channel clock parameter
+; to get panel misc information
+;
+; O/P :
+; BL: for input Select = 0 ;
+; BX: *Value1 = Horizontal total
+; CX: *Value2 = Horizontal front porch
+; DX: *Value2 = Horizontal sync width
+; BL: for input Select = 1 ;
+; BX: *Value1 = Vertical total
+; CX: *Value2 = Vertical front porch
+; DX: *Value2 = Vertical sync width
+; BL: for input Select = 2 ;
+; BX: Value1 = The first CLK parameter
+; CX: Value2 = The second CLK parameter
+; BL: for input Select = 4 ;
+; BX[15]: *Value1 D[15] VESA V. Polarity
+; BX[14]: *Value1 D[14] VESA H. Polarity
+; BX[7]: *Value1 D[7] Panel V. Polarity
+; BX[6]: *Value1 D[6] Panel H. Polarity
+;-----------------------------------------------------------------------------
+*/
+void XGI_XG21Fun14Sub73( PVB_DEVICE_INFO pVBInfo , PX86_REGS pBiosArguments )
+{
+ UCHAR Select;
+
+ USHORT lvdstableindex;
+
+ lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
+ Select = pBiosArguments->h.bl;
+
+ switch (Select)
+ {
+ case 0:
+ pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT;
+ pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP;
+ pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC;
+ break;
+ case 1:
+ pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT;
+ pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP;
+ pBiosArguments->x.dx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC;
+ break;
+ case 2:
+ pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1;
+ pBiosArguments->x.cx = pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2;
+ break;
+ case 4:
+ pBiosArguments->x.bx = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability;
+ break;
+ }
+
+ pBiosArguments->x.ax = 0x0014;
+}
+
+
+void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments)
+{
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+
+ pVBInfo->IF_DEF_LVDS = 0 ;
+ pVBInfo->IF_DEF_CH7005 = 0 ;
+ pVBInfo->IF_DEF_HiVision = 1 ;
+ pVBInfo->IF_DEF_LCDA = 1 ;
+ pVBInfo->IF_DEF_CH7017 = 0 ;
+ pVBInfo->IF_DEF_YPbPr = 1 ;
+ pVBInfo->IF_DEF_CRT2Monitor = 0 ;
+ pVBInfo->IF_DEF_VideoCapture = 0 ;
+ pVBInfo->IF_DEF_ScaleLCD = 0 ;
+ pVBInfo->IF_DEF_OEMUtil = 0 ;
+ pVBInfo->IF_DEF_PWD = 0 ;
+
+ InitTo330Pointer( pXGIHWDE->jChipType, pVBInfo ) ;
+ ReadVBIOSTablData( pXGIHWDE->jChipType , pVBInfo) ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ switch(pBiosArguments->x.ax)
+ {
+ case 0x1470:
+ XGI_XG21Fun14Sub70( pVBInfo , pBiosArguments ) ;
+ break;
+ case 0x1471:
+ XGI_XG21Fun14Sub71( pVBInfo , pBiosArguments ) ;
+ break;
+ case 0x1472:
+ XGI_XG21Fun14Sub72( pVBInfo , pBiosArguments ) ;
+ break;
+ case 0x1473:
+ XGI_XG21Fun14Sub73( pVBInfo , pBiosArguments ) ;
+ break;
+ }
+}
diff --git a/drivers/staging/xgifb/vb_ext.h b/drivers/staging/xgifb/vb_ext.h
new file mode 100644
index 000000000000..9a72f5ecb713
--- /dev/null
+++ b/drivers/staging/xgifb/vb_ext.h
@@ -0,0 +1,32 @@
+#ifndef _VBEXT_
+#define _VBEXT_
+
+struct DWORDREGS {
+ ULONG Eax, Ebx, Ecx, Edx, Esi, Edi, Ebp;
+};
+
+struct WORDREGS {
+ USHORT ax, hi_ax, bx, hi_bx, cx, hi_cx, dx, hi_dx, si, hi_si, di ,hi_di, bp, hi_bp;
+};
+
+struct BYTEREGS {
+ UCHAR al, ah, hi_al, hi_ah, bl, bh, hi_bl, hi_bh, cl, ch, hi_cl, hi_ch, dl, dh, hi_dl, hi_dh;
+};
+
+typedef union _X86_REGS {
+ struct DWORDREGS e;
+ struct WORDREGS x;
+ struct BYTEREGS h;
+} X86_REGS, *PX86_REGS;
+
+extern void XGI_XG21Fun14( PXGI_HW_DEVICE_INFO pXGIHWDE, PX86_REGS pBiosArguments);
+extern void XGISetDPMS( PXGI_HW_DEVICE_INFO pXGIHWDE , ULONG VESA_POWER_STATE ) ;
+extern void XGI_GetSenseStatus( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo );
+extern void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
+extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
+extern USHORT XGINew_SenseLCD(PXGI_HW_DEVICE_INFO,PVB_DEVICE_INFO pVBInfo);
+#ifdef WIN2000
+extern BOOLEAN XGI_DySense( PHW_DEVICE_EXTENSION pHWDE , PUCHAR ujConnectStatus );
+#endif /* WIN2000 */
+
+#endif
diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c
new file mode 100644
index 000000000000..b85ca9ba8076
--- /dev/null
+++ b/drivers/staging/xgifb/vb_init.c
@@ -0,0 +1,3444 @@
+#include "osdef.h"
+#include "vgatypes.h"
+
+
+#ifdef LINUX_KERNEL
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/delay.h> /* udelay */
+#include "XGIfb.h"
+/*#if LINUX_VERSxION_CODE >= KERNEL_VERSION(2,5,0)
+#include <video/XGIfb.h>
+#else
+#include <linux/XGIfb.h>
+#endif */
+#endif
+
+#ifdef WIN2000
+#include <dderror.h>
+#include <devioctl.h>
+#include <miniport.h>
+#include <ntddvdeo.h>
+#include <video.h>
+#include "xgiv.h"
+#include "dd_i2c.h"
+#include "tools.h"
+#endif
+
+#include "vb_def.h"
+#include "vb_struct.h"
+#include "vb_util.h"
+#include "vb_setmode.h"
+#include "vb_init.h"
+#include "vb_ext.h"
+
+#ifdef LINUX_XF86
+#include "xf86.h"
+#include "xf86PciInfo.h"
+#include "xgi.h"
+#include "xgi_regs.h"
+#endif
+
+#ifdef LINUX_KERNEL
+#include <asm/io.h>
+#include <linux/types.h>
+#endif
+
+
+
+
+UCHAR XGINew_ChannelAB,XGINew_DataBusWidth;
+
+USHORT XGINew_DRAMType[17][5]={{0x0C,0x0A,0x02,0x40,0x39},{0x0D,0x0A,0x01,0x40,0x48},
+ {0x0C,0x09,0x02,0x20,0x35},{0x0D,0x09,0x01,0x20,0x44},
+ {0x0C,0x08,0x02,0x10,0x31},{0x0D,0x08,0x01,0x10,0x40},
+ {0x0C,0x0A,0x01,0x20,0x34},{0x0C,0x09,0x01,0x08,0x32},
+ {0x0B,0x08,0x02,0x08,0x21},{0x0C,0x08,0x01,0x08,0x30},
+ {0x0A,0x08,0x02,0x04,0x11},{0x0B,0x0A,0x01,0x10,0x28},
+ {0x09,0x08,0x02,0x02,0x01},{0x0B,0x09,0x01,0x08,0x24},
+ {0x0B,0x08,0x01,0x04,0x20},{0x0A,0x08,0x01,0x02,0x10},
+ {0x09,0x08,0x01,0x01,0x00}};
+
+USHORT XGINew_SDRDRAM_TYPE[13][5]=
+{
+{ 2,12, 9,64,0x35},
+{ 1,13, 9,64,0x44},
+{ 2,12, 8,32,0x31},
+{ 2,11, 9,32,0x25},
+{ 1,12, 9,32,0x34},
+{ 1,13, 8,32,0x40},
+{ 2,11, 8,16,0x21},
+{ 1,12, 8,16,0x30},
+{ 1,11, 9,16,0x24},
+{ 1,11, 8, 8,0x20},
+{ 2, 9, 8, 4,0x01},
+{ 1,10, 8, 4,0x10},
+{ 1, 9, 8, 2,0x00}
+};
+
+USHORT XGINew_DDRDRAM_TYPE[4][5]=
+{
+{ 2,12, 9,64,0x35},
+{ 2,12, 8,32,0x31},
+{ 2,11, 8,16,0x21},
+{ 2, 9, 8, 4,0x01}
+};
+USHORT XGINew_DDRDRAM_TYPE340[4][5]=
+{
+{ 2,13, 9,64,0x45},
+{ 2,12, 9,32,0x35},
+{ 2,12, 8,16,0x31},
+{ 2,11, 8, 8,0x21}
+};
+USHORT XGINew_DDRDRAM_TYPE20[12][5]=
+{
+{ 2,14,11,128,0x5D},
+{ 2,14,10,64,0x59},
+{ 2,13,11,64,0x4D},
+{ 2,14, 9,32,0x55},
+{ 2,13,10,32,0x49},
+{ 2,12,11,32,0x3D},
+{ 2,14, 8,16,0x51},
+{ 2,13, 9,16,0x45},
+{ 2,12,10,16,0x39},
+{ 2,13, 8, 8,0x41},
+{ 2,12, 9, 8,0x35},
+{ 2,12, 8, 4,0x31}
+};
+
+void XGINew_SetDRAMSize_340(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
+void XGINew_SetDRAMSize_310(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
+void XGINew_SetMemoryClock(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+void XGINew_SetDRAMModeRegister(PVB_DEVICE_INFO );
+void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension );
+void XGINew_SetDRAMDefaultRegister340(PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG, PVB_DEVICE_INFO );
+UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension) ;
+
+int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
+void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO ,PVB_DEVICE_INFO) ;
+void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO) ;
+int XGINew_SDRSizing(PVB_DEVICE_INFO);
+int XGINew_DDRSizing( PVB_DEVICE_INFO );
+void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO);
+int XGINew_RAMType; /*int ModeIDOffset,StandTable,CRT1Table,ScreenOffset,REFIndex;*/
+ULONG UNIROM; /* UNIROM */
+BOOLEAN ChkLFB( PVB_DEVICE_INFO );
+void XGINew_Delay15us(ULONG);
+void SetPowerConsume (PXGI_HW_DEVICE_INFO HwDeviceExtension,ULONG XGI_P3d4Port);
+void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
+void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo);
+void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension );
+void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension );
+void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
+void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo ) ;
+void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ;
+UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
+void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo) ;
+UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
+
+#ifdef WIN2000
+/* [Billy] 2007/05/20 For CH7007 */
+extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8];
+extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[];
+#endif
+
+#ifdef LINUX_KERNEL
+void DelayUS(ULONG MicroSeconds)
+{
+ udelay(MicroSeconds);
+}
+#endif
+
+/* --------------------------------------------------------------------- */
+/* Function : XGIInitNew */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ UCHAR i , temp = 0 , temp1 ;
+ // VBIOSVersion[ 5 ] ;
+ PUCHAR volatile pVideoMemory;
+
+ /* ULONG j, k ; */
+
+ PXGI_DSReg pSR ;
+
+ ULONG Temp ;
+
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+
+ pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr;
+
+
+// Newdebugcode( 0x99 ) ;
+
+
+ /* if ( pVBInfo->ROMAddr == 0 ) */
+ /* return( FALSE ) ; */
+
+ if ( pVBInfo->FBAddr == 0 )
+{
+ printk("\n pVBInfo->FBAddr == 0 ");
+ return( FALSE ) ;
+}
+printk("1");
+ if ( pVBInfo->BaseAddr == 0 )
+{
+ printk("\npVBInfo->BaseAddr == 0 ");
+ return( FALSE ) ;
+}
+printk("2");
+
+ XGINew_SetReg3( ( pVBInfo->BaseAddr + 0x12 ) , 0x67 ) ; /* 3c2 <- 67 ,ynlai */
+
+ pVBInfo->ISXPDOS = 0 ;
+printk("3");
+
+if ( !HwDeviceExtension->bIntegratedMMEnabled )
+{
+ return( FALSE ) ; /* alan */
+}
+printk("4");
+
+// XGI_MemoryCopy( VBIOSVersion , HwDeviceExtension->szVBIOSVer , 4 ) ;
+
+ // VBIOSVersion[ 4 ] = 0x0 ;
+
+ /* 09/07/99 modify by domao */
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+printk("5");
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */
+
+ InitTo330Pointer( HwDeviceExtension->jChipType, pVBInfo ) ;
+
+ /* ReadVBIOSData */
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+
+ /* 1.Openkey */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
+printk("6");
+
+ /* GetXG21Sense (GPIO) */
+ if ( HwDeviceExtension->jChipType == XG21 )
+ {
+ XGINew_GetXG21Sense(HwDeviceExtension, pVBInfo) ;
+ }
+ if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ XGINew_GetXG27Sense(HwDeviceExtension, pVBInfo) ;
+ }
+printk("7");
+
+ /* 2.Reset Extended register */
+
+ for( i = 0x06 ; i < 0x20 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ;
+
+ for( i = 0x21 ; i <= 0x27 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ;
+
+ /* for( i = 0x06 ; i <= 0x27 ; i++ ) */
+ /* XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ; */
+
+printk("8");
+
+ if(( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40))
+ {
+ for( i = 0x31 ; i <= 0x3B ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ;
+ }
+ else
+ {
+ for( i = 0x31 ; i <= 0x3D ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , i , 0 ) ;
+ }
+printk("9");
+
+ if ( HwDeviceExtension->jChipType == XG42 ) /* [Hsuan] 2004/08/20 Auto over driver for XG42 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3B , 0xC0 ) ;
+
+ /* for( i = 0x30 ; i <= 0x3F ; i++ ) */
+ /* XGINew_SetReg1( pVBInfo->P3d4 , i , 0 ) ; */
+
+ for( i = 0x79 ; i <= 0x7C ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , i , 0 ) ; /* shampoo 0208 */
+
+printk("10");
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x97 , *pVBInfo->pXGINew_CR97 ) ;
+
+ /* 3.SetMemoryClock
+
+ if ( HwDeviceExtension->jChipType >= XG40 )
+ XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo) ;
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ; */
+
+printk("11");
+
+ /* 4.SetDefExt1Regs begin */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x07 , *pVBInfo->pSR07 ) ;
+ if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x40 , *pVBInfo->pSR40 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x41 , *pVBInfo->pSR41 ) ;
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x11 , 0x0F ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , *pVBInfo->pSR1F ) ;
+ /* XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0x20 ) ; */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0xA0 ) ; /* alan, 2001/6/26 Frame buffer can read/write SR20 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x36 , 0x70 ) ; /* Hsuan, 2006/01/01 H/W request for slow corner chip */
+ if ( HwDeviceExtension->jChipType == XG27 ) /* Alan 12/07/2006 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x36 , *pVBInfo->pSR36 ) ;
+
+ /* SR11 = 0x0F ; */
+ /* XGINew_SetReg1( pVBInfo->P3c4 , 0x11 , SR11 ) ; */
+
+printk("12");
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ {
+// /* Set AGP Rate */
+// temp1 = XGINew_GetReg1( pVBInfo->P3c4 , 0x3B ) ;
+// temp1 &= 0x02 ;
+// if ( temp1 == 0x02 )
+// {
+// XGINew_SetReg4( 0xcf8 , 0x80000000 ) ;
+// ChipsetID = XGINew_GetReg3( 0x0cfc ) ;
+// XGINew_SetReg4( 0xcf8 , 0x8000002C ) ;
+// VendorID = XGINew_GetReg3( 0x0cfc ) ;
+// VendorID &= 0x0000FFFF ;
+// XGINew_SetReg4( 0xcf8 , 0x8001002C ) ;
+// GraphicVendorID = XGINew_GetReg3( 0x0cfc ) ;
+// GraphicVendorID &= 0x0000FFFF;
+//
+// if ( ChipsetID == 0x7301039 )
+/// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x09 ) ;
+//
+// ChipsetID &= 0x0000FFFF ;
+///
+// if ( ( ChipsetID == 0x700E ) || ( ChipsetID == 0x1022 ) || ( ChipsetID == 0x1106 ) || ( ChipsetID == 0x10DE ) )
+// {
+// if ( ChipsetID == 0x1106 )
+// {
+// if ( ( VendorID == 0x1019 ) && ( GraphicVendorID == 0x1019 ) )
+// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0D ) ;
+// else
+// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0B ) ;
+// }
+// else
+// XGINew_SetReg1( pVBInfo->P3d4 , 0x5F , 0x0B ) ;
+// }
+// }
+
+printk("13");
+
+ if ( HwDeviceExtension->jChipType >= XG40 )
+ {
+ /* Set AGP customize registers (in SetDefAGPRegs) Start */
+ for( i = 0x47 ; i <= 0x4C ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ i - 0x47 ] ) ;
+
+ for( i = 0x70 ; i <= 0x71 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ 6 + i - 0x70 ] ) ;
+
+ for( i = 0x74 ; i <= 0x77 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , i , pVBInfo->AGPReg[ 8 + i - 0x74 ] ) ;
+ /* Set AGP customize registers (in SetDefAGPRegs) End */
+ /*[Hsuan]2004/12/14 AGP Input Delay Adjustment on 850 */
+// XGINew_SetReg4( 0xcf8 , 0x80000000 ) ;
+// ChipsetID = XGINew_GetReg3( 0x0cfc ) ;
+// if ( ChipsetID == 0x25308086 )
+// XGINew_SetReg1( pVBInfo->P3d4 , 0x77 , 0xF0 ) ;
+
+ HwDeviceExtension->pQueryVGAConfigSpace( HwDeviceExtension , 0x50 , 0 , &Temp ) ; /* Get */
+ Temp >>= 20 ;
+ Temp &= 0xF ;
+
+ if ( Temp == 1 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x48 , 0x20 ) ; /* CR48 */
+ }
+printk("14");
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x49 , pVBInfo->CR49[ 0 ] ) ;
+ } /* != XG20 */
+
+ /* Set PCI */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x23 , *pVBInfo->pSR23 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x24 , *pVBInfo->pSR24 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x25 , pVBInfo->SR25[ 0 ] ) ;
+printk("15");
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ {
+ /* Set VB */
+ XGI_UnLockCRT2( HwDeviceExtension, pVBInfo) ;
+ XGINew_SetRegANDOR( pVBInfo->Part0Port , 0x3F , 0xEF , 0x00 ) ; /* alan, disable VideoCapture */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , 0x00 ) ;
+ temp1 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x7B ) ; /* chk if BCLK>=100MHz */
+ temp = ( UCHAR )( ( temp1 >> 4 ) & 0x0F ) ;
+
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x02 , ( *pVBInfo->pCRT2Data_1_2 ) ) ;
+
+printk("16");
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x2E , 0x08 ) ; /* use VB */
+ } /* != XG20 */
+
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x27 , 0x1F ) ;
+
+ if ( ( HwDeviceExtension->jChipType == XG42 ) && XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo) != 0 ) /* Not DDR */
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , ( *pVBInfo->pSR31 & 0x3F ) | 0x40 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , ( *pVBInfo->pSR32 & 0xFC ) | 0x01 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , *pVBInfo->pSR31 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , *pVBInfo->pSR32 ) ;
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x33 , *pVBInfo->pSR33 ) ;
+printk("17");
+
+/*
+ if ( HwDeviceExtension->jChipType >= XG40 )
+ SetPowerConsume ( HwDeviceExtension , pVBInfo->P3c4); */
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ {
+ if ( XGI_BridgeIsOn( pVBInfo ) == 1 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x00 , 0x1C ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0D , *pVBInfo->pCRT2Data_4_D ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0E , *pVBInfo->pCRT2Data_4_E ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x10 , *pVBInfo->pCRT2Data_4_10 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0F , 0x3F ) ;
+ }
+
+ XGI_LockCRT2( HwDeviceExtension, pVBInfo ) ;
+ }
+ } /* != XG20 */
+printk("18");
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x83 , 0x00 ) ;
+printk("181");
+
+ if ( HwDeviceExtension->bSkipSense == FALSE )
+ {
+printk("182");
+
+ XGI_SenseCRT1(pVBInfo) ;
+
+printk("183");
+ /* XGINew_DetectMonitor( HwDeviceExtension ) ; */
+pVBInfo->IF_DEF_CH7007 = 0;
+ if ( ( HwDeviceExtension->jChipType == XG21 ) && (pVBInfo->IF_DEF_CH7007) )
+ {
+printk("184");
+ XGI_GetSenseStatus( HwDeviceExtension , pVBInfo ) ; /* sense CRT2 */
+printk("185");
+
+ }
+ if ( HwDeviceExtension->jChipType == XG21 )
+ {
+printk("186");
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~Monitor1Sense , Monitor1Sense ) ; /* Z9 default has CRT */
+ temp = GetXG21FPBits( pVBInfo ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~0x01, temp ) ;
+printk("187");
+
+ }
+ if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , ~Monitor1Sense , Monitor1Sense ) ; /* Z9 default has CRT */
+ temp = GetXG27FPBits( pVBInfo ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x37 , ~0x03, temp ) ;
+ }
+ }
+printk("19");
+
+ if ( HwDeviceExtension->jChipType >= XG40 )
+ {
+ if ( HwDeviceExtension->jChipType >= XG40 )
+ {
+ XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
+ }
+
+ XGINew_SetDRAMDefaultRegister340( HwDeviceExtension , pVBInfo->P3d4, pVBInfo ) ;
+
+ if ( HwDeviceExtension->bSkipDramSizing == TRUE )
+ {
+ pSR = HwDeviceExtension->pSR ;
+ if ( pSR!=NULL )
+ {
+ while( pSR->jIdx != 0xFF )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , pSR->jIdx , pSR->jVal ) ;
+ pSR++ ;
+ }
+ }
+ /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */
+ } /* SkipDramSizing */
+ else
+ {
+#if 0
+ if ( HwDeviceExtension->jChipType == XG20 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , pVBInfo->SR15[0][XGINew_RAMType] ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , pVBInfo->SR15[1][XGINew_RAMType] ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x20 , 0x20 ) ;
+ }
+ else
+#endif
+{
+printk("20");
+
+ XGINew_SetDRAMSize_340( HwDeviceExtension , pVBInfo) ;
+}
+printk("21");
+
+ }
+ } /* XG40 */
+
+printk("22");
+
+
+ /* SetDefExt2Regs begin */
+/*
+ AGP = 1 ;
+ temp =( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) ;
+ temp &= 0x30 ;
+ if ( temp == 0x30 )
+ AGP = 0 ;
+
+ if ( AGP == 0 )
+ *pVBInfo->pSR21 &= 0xEF ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , *pVBInfo->pSR21 ) ;
+ if ( AGP == 1 )
+ *pVBInfo->pSR22 &= 0x20 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , *pVBInfo->pSR22 ) ;
+*/
+
+// base = 0x80000000 ;
+// OutPortLong( 0xcf8 , base ) ;
+// Temp = ( InPortLong( 0xcfc ) & 0xFFFF ) ;
+// if ( Temp == 0x1039 )
+// {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , ( UCHAR )( ( *pVBInfo->pSR22 ) & 0xFE ) ) ;
+// }
+// else
+// {
+// XGINew_SetReg1( pVBInfo->P3c4 , 0x22 , *pVBInfo->pSR22 ) ;
+// }
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , *pVBInfo->pSR21 ) ;
+
+printk("23");
+
+
+ XGINew_ChkSenseStatus ( HwDeviceExtension , pVBInfo ) ;
+ XGINew_SetModeScratch ( HwDeviceExtension , pVBInfo ) ;
+
+printk("24");
+
+
+XGINew_SetReg1( pVBInfo->P3d4 , 0x8c , 0x87);
+XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x31);
+printk("25");
+
+ return( TRUE ) ;
+} /* end of init */
+
+
+
+
+
+/* ============== alan ====================== */
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_GetXG20DRAMType */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGINew_GetXG20DRAMType( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR data, temp ;
+
+ if ( HwDeviceExtension->jChipType < XG20 )
+ {
+ if ( *pVBInfo->pSoftSetting & SoftDRAMType )
+ {
+ data = *pVBInfo->pSoftSetting & 0x07 ;
+ return( data ) ;
+ }
+ else
+ {
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) & 0x02 ;
+
+ if ( data == 0 )
+ data = ( XGINew_GetReg1( pVBInfo->P3c4 , 0x3A ) & 0x02 ) >> 1 ;
+
+ return( data ) ;
+ }
+ }
+ else if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ if ( *pVBInfo->pSoftSetting & SoftDRAMType )
+ {
+ data = *pVBInfo->pSoftSetting & 0x07 ;
+ return( data ) ;
+ }
+ temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3B ) ;
+
+ if (( temp & 0x88 )==0x80) /* SR3B[7][3]MAA15 MAA11 (Power on Trapping) */
+ data = 0 ; /*DDR*/
+ else
+ data = 1 ; /*DDRII*/
+ return( data ) ;
+ }
+ else if ( HwDeviceExtension->jChipType == XG21 )
+ {
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0xB4 , ~0x02 ) ; /* Independent GPIO control */
+ DelayUS(800);
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x4A , 0x80 ) ; /* Enable GPIOH read */
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ; /* GPIOF 0:DVI 1:DVO */
+// HOTPLUG_SUPPORT
+// for current XG20 & XG21, GPIOH is floating, driver will fix DDR temporarily
+ if ( temp & 0x01 ) /* DVI read GPIOH */
+ data = 1 ; /*DDRII*/
+ else
+ data = 0 ; /*DDR*/
+//~HOTPLUG_SUPPORT
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0xB4 , 0x02 ) ;
+ return( data ) ;
+ }
+ else
+ {
+ data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) & 0x01 ;
+
+ if ( data == 1 )
+ data ++ ;
+
+ return( data );
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_Get310DRAMType */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGINew_Get310DRAMType(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR data ;
+
+ /* index = XGINew_GetReg1( pVBInfo->P3c4 , 0x1A ) ; */
+ /* index &= 07 ; */
+
+ if ( *pVBInfo->pSoftSetting & SoftDRAMType )
+ data = *pVBInfo->pSoftSetting & 0x03 ;
+ else
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3a ) & 0x03 ;
+
+ return( data ) ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_Delay15us */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+/*
+void XGINew_Delay15us(ULONG ulMicrsoSec)
+{
+}
+*/
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SDR_MRS */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SDR_MRS( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT data ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ;
+ data &= 0x3F ; /* SR16 D7=0,D6=0 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; /* enable mode register set(MRS) low */
+ /* XGINew_Delay15us( 0x100 ) ; */
+ data |= 0x80 ; /* SR16 D7=1,D6=0 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ; /* enable mode register set(MRS) high */
+ /* XGINew_Delay15us( 0x100 ) ; */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR1x_MRS_340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR1x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+ XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ;
+ XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ if ( *pVBInfo->pXGINew_DRAMTypeDefinition != 0x0C ) /* Samsung F Die */
+ {
+ DelayUS( 3000 ) ; /* Delay 67 x 3 Delay15us */
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+ }
+
+ DelayUS( 60 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 0 ] ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 1 ] ) ;
+ DelayUS( 1000 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ;
+ DelayUS( 500 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 2 ] ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , pVBInfo->SR16[ 3 ] ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR2x_MRS_340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR2x_MRS_340( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x19 , 0x20 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+ DelayUS( 60 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+ DelayUS( 1000 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ;
+ DelayUS( 500 ) ;
+ /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDRII_Bootup_XG27 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDRII_Bootup_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = P3c4 + 0x10 ;
+ XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+
+ /* Set Double Frequency */
+ /* XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; */ /* CR97 */
+ XGINew_SetReg1( P3d4 , 0x97 , *pVBInfo->pXGINew_CR97 ) ; /* CR97 */
+
+ DelayUS( 200 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS2
+ XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS3
+ XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */
+ DelayUS( 15) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS1
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* Set SR18 */ //MRS, DLL Enable
+ XGINew_SetReg1( P3c4 , 0x19 , 0x0A ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ; /* Set SR16 */
+ /* DelayUS( 15 ) ; */
+
+ XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* Set SR1B */
+ DelayUS( 60 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* Set SR1B */
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* Set SR18 */ //MRS, DLL Reset
+ XGINew_SetReg1( P3c4 , 0x19 , 0x08 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ; /* Set SR16 */
+
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x80 ) ; /* Set SR18 */ //MRS, ODT
+ XGINew_SetReg1( P3c4 , 0x19 , 0x46 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* Set SR18 */ //EMRS
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ; /* Set SR19 */
+ XGINew_SetReg1( P3c4 , 0x16 , 0x20 ) ; /* Set SR16 */
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0xA0 ) ; /* Set SR16 */
+ DelayUS( 15 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* Set SR1B refresh control 000:close; 010:open */
+ DelayUS( 200 ) ;
+
+
+}
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR2_MRS_XG20 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR2_MRS_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = P3c4 + 0x10 ;
+
+ XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+
+ XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; /* CR97 */
+
+ DelayUS( 200 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS2 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS3 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+
+ // XGINew_SetReg1( P3c4 , 0x18 , 0x52 ) ; /* MRS1 */
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x02 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+
+ DelayUS( 15 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* SR1B */
+ DelayUS( 100 ) ;
+
+ //XGINew_SetReg1( P3c4 , 0x18 , 0x52 ) ; /* MRS2 */
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x05 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x85 ) ;
+
+ DelayUS( 200 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR2_MRS_XG20 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR2_MRS_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = P3c4 + 0x10 ;
+
+ XGINew_RAMType = ( int )XGINew_GetXG20DRAMType( HwDeviceExtension , pVBInfo ) ;
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+
+ XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ; /* CR97 */
+ DelayUS( 200 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS2 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x80 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x10 ) ;
+ DelayUS( 15 ) ; ////06/11/23 XG27 A0 for CKE enable
+ XGINew_SetReg1( P3c4 , 0x16 , 0x90 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS3 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0xC0 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 15 ) ; ////06/11/22 XG27 A0
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ; /* EMRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 15 ) ; ////06/11/22 XG27 A0
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x06 ) ; ////[Billy]06/11/22 DLL Reset for XG27 Hynix DRAM
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 15 ) ; ////06/11/23 XG27 A0
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ DelayUS( 30 ) ; ////06/11/23 XG27 A0 Start Auto-PreCharge
+ XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */
+ DelayUS( 60 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ; /* SR1B */
+
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x42 ) ; /* MRS1 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x04 ) ; //// DLL without Reset for XG27 Hynix DRAM
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x80 ); ////XG27 OCD ON
+ XGINew_SetReg1( P3c4 , 0x19 , 0x46 );
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 );
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 );
+
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ DelayUS( 30 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+
+ DelayUS( 15 ) ; ////Start Auto-PreCharge
+ XGINew_SetReg1( P3c4 , 0x1B , 0x04 ) ; /* SR1B */
+ DelayUS( 200 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ; /* SR1B */
+
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR1x_DefaultRegister */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR1x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = Port ,
+ P3c4 = Port - 0x10 ;
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ {
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */
+
+ XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ;
+ XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ;
+
+ XGINew_DDR1x_MRS_XG20( P3c4 , pVBInfo) ;
+ }
+ else
+ {
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+
+ switch( HwDeviceExtension->jChipType )
+ {
+ case XG41:
+ case XG42:
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */
+ break ;
+ default:
+ XGINew_SetReg1( P3d4 , 0x82 , 0x88 ) ;
+ XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ;
+ XGINew_GetReg1( P3d4 , 0x86 ) ;
+ XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ;
+ XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ;
+ XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ break ;
+ }
+
+ XGINew_SetReg1( P3d4 , 0x97 , 0x00 ) ;
+ XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ;
+ XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ;
+ XGINew_DDR1x_MRS_340( P3c4 , pVBInfo ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR2x_DefaultRegister */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR2x_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port ,PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = Port ,
+ P3c4 = Port - 0x10 ;
+
+ XGINew_SetMemoryClock( HwDeviceExtension , pVBInfo ) ;
+
+ /* 20040906 Hsuan modify CR82, CR85, CR86 for XG42 */
+ switch( HwDeviceExtension->jChipType )
+ {
+ case XG41:
+ case XG42:
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */
+ break ;
+ default:
+ /* keep following setting sequence, each setting in the same reg insert idle */
+ XGINew_SetReg1( P3d4 , 0x82 , 0x88 ) ;
+ XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ;
+ XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ;
+ XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ }
+ XGINew_SetReg1( P3d4 , 0x97 , 0x11 ) ;
+ if ( HwDeviceExtension->jChipType == XG42 )
+ {
+ XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( P3d4 , 0x98 , 0x03 ) ;
+ }
+ XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ;
+
+ XGINew_DDR2x_MRS_340( P3c4 , pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR2_DefaultRegister */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR2_DefaultRegister( PXGI_HW_DEVICE_INFO HwDeviceExtension, ULONG Port , PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG P3d4 = Port ,
+ P3c4 = Port - 0x10 ;
+
+ /* keep following setting sequence, each setting in the same reg insert idle */
+ XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ;
+ XGINew_SetReg1( P3d4 , 0x86 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x86 , 0x88 ) ;
+ XGINew_GetReg1( P3d4 , 0x86 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x86 , pVBInfo->CR40[ 13 ][ XGINew_RAMType ] ) ; /* CR86 */
+ XGINew_SetReg1( P3d4 , 0x82 , 0x77 ) ;
+ XGINew_SetReg1( P3d4 , 0x85 , 0x00 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , 0x88 ) ;
+ XGINew_GetReg1( P3d4 , 0x85 ) ; /* Insert read command for delay */
+ XGINew_SetReg1( P3d4 , 0x85 , pVBInfo->CR40[ 12 ][ XGINew_RAMType ] ) ; /* CR85 */
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGINew_SetReg1( P3d4 , 0x82 , pVBInfo->CR40[ 11 ][ XGINew_RAMType ] ) ; /* CR82 */
+ else
+ XGINew_SetReg1( P3d4 , 0x82 , 0xA8 ) ; /* CR82 */
+
+ XGINew_SetReg1( P3d4 , 0x98 , 0x01 ) ;
+ XGINew_SetReg1( P3d4 , 0x9A , 0x02 ) ;
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGINew_DDRII_Bootup_XG27( HwDeviceExtension , P3c4 , pVBInfo) ;
+ else
+ XGINew_DDR2_MRS_XG20( HwDeviceExtension , P3c4, pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMDefaultRegister340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMDefaultRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG Port , PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR temp , temp1 , temp2 , temp3 ,
+ i , j , k ;
+
+ ULONG P3d4 = Port ,
+ P3c4 = Port - 0x10 ;
+
+ XGINew_SetReg1( P3d4 , 0x6D , pVBInfo->CR40[ 8 ][ XGINew_RAMType ] ) ;
+ XGINew_SetReg1( P3d4 , 0x68 , pVBInfo->CR40[ 5 ][ XGINew_RAMType ] ) ;
+ XGINew_SetReg1( P3d4 , 0x69 , pVBInfo->CR40[ 6 ][ XGINew_RAMType ] ) ;
+ XGINew_SetReg1( P3d4 , 0x6A , pVBInfo->CR40[ 7 ][ XGINew_RAMType ] ) ;
+
+ temp2 = 0 ;
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ temp = pVBInfo->CR6B[ XGINew_RAMType ][ i ] ; /* CR6B DQS fine tune delay */
+ for( j = 0 ; j < 4 ; j++ )
+ {
+ temp1 = ( ( temp >> ( 2 * j ) ) & 0x03 ) << 2 ;
+ temp2 |= temp1 ;
+ XGINew_SetReg1( P3d4 , 0x6B , temp2 ) ;
+ XGINew_GetReg1( P3d4 , 0x6B ) ; /* Insert read command for delay */
+ temp2 &= 0xF0 ;
+ temp2 += 0x10 ;
+ }
+ }
+
+ temp2 = 0 ;
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ temp = pVBInfo->CR6E[ XGINew_RAMType ][ i ] ; /* CR6E DQM fine tune delay */
+ for( j = 0 ; j < 4 ; j++ )
+ {
+ temp1 = ( ( temp >> ( 2 * j ) ) & 0x03 ) << 2 ;
+ temp2 |= temp1 ;
+ XGINew_SetReg1( P3d4 , 0x6E , temp2 ) ;
+ XGINew_GetReg1( P3d4 , 0x6E ) ; /* Insert read command for delay */
+ temp2 &= 0xF0 ;
+ temp2 += 0x10 ;
+ }
+ }
+
+ temp3 = 0 ;
+ for( k = 0 ; k < 4 ; k++ )
+ {
+ XGINew_SetRegANDOR( P3d4 , 0x6E , 0xFC , temp3 ) ; /* CR6E_D[1:0] select channel */
+ temp2 = 0 ;
+ for( i = 0 ; i < 8 ; i++ )
+ {
+ temp = pVBInfo->CR6F[ XGINew_RAMType ][ 8 * k + i ] ; /* CR6F DQ fine tune delay */
+ for( j = 0 ; j < 4 ; j++ )
+ {
+ temp1 = ( temp >> ( 2 * j ) ) & 0x03 ;
+ temp2 |= temp1 ;
+ XGINew_SetReg1( P3d4 , 0x6F , temp2 ) ;
+ XGINew_GetReg1( P3d4 , 0x6F ) ; /* Insert read command for delay */
+ temp2 &= 0xF8 ;
+ temp2 += 0x08 ;
+ }
+ }
+ temp3 += 0x01 ;
+ }
+
+ XGINew_SetReg1( P3d4 , 0x80 , pVBInfo->CR40[ 9 ][ XGINew_RAMType ] ) ; /* CR80 */
+ XGINew_SetReg1( P3d4 , 0x81 , pVBInfo->CR40[ 10 ][ XGINew_RAMType ] ) ; /* CR81 */
+
+ temp2 = 0x80 ;
+ temp = pVBInfo->CR89[ XGINew_RAMType ][ 0 ] ; /* CR89 terminator type select */
+ for( j = 0 ; j < 4 ; j++ )
+ {
+ temp1 = ( temp >> ( 2 * j ) ) & 0x03 ;
+ temp2 |= temp1 ;
+ XGINew_SetReg1( P3d4 , 0x89 , temp2 ) ;
+ XGINew_GetReg1( P3d4 , 0x89 ) ; /* Insert read command for delay */
+ temp2 &= 0xF0 ;
+ temp2 += 0x10 ;
+ }
+
+ temp = pVBInfo->CR89[ XGINew_RAMType ][ 1 ] ;
+ temp1 = temp & 0x03 ;
+ temp2 |= temp1 ;
+ XGINew_SetReg1( P3d4 , 0x89 , temp2 ) ;
+
+ temp = pVBInfo->CR40[ 3 ][ XGINew_RAMType ] ;
+ temp1 = temp & 0x0F ;
+ temp2 = ( temp >> 4 ) & 0x07 ;
+ temp3 = temp & 0x80 ;
+ XGINew_SetReg1( P3d4 , 0x45 , temp1 ) ; /* CR45 */
+ XGINew_SetReg1( P3d4 , 0x99 , temp2 ) ; /* CR99 */
+ XGINew_SetRegOR( P3d4 , 0x40 , temp3 ) ; /* CR40_D[7] */
+ XGINew_SetReg1( P3d4 , 0x41 , pVBInfo->CR40[ 0 ][ XGINew_RAMType ] ) ; /* CR41 */
+
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGINew_SetReg1( P3d4 , 0x8F , *pVBInfo->pCR8F ) ; /* CR8F */
+
+ for( j = 0 ; j <= 6 ; j++ )
+ XGINew_SetReg1( P3d4 , ( 0x90 + j ) , pVBInfo->CR40[ 14 + j ][ XGINew_RAMType ] ) ; /* CR90 - CR96 */
+
+ for( j = 0 ; j <= 2 ; j++ )
+ XGINew_SetReg1( P3d4 , ( 0xC3 + j ) , pVBInfo->CR40[ 21 + j ][ XGINew_RAMType ] ) ; /* CRC3 - CRC5 */
+
+ for( j = 0 ; j < 2 ; j++ )
+ XGINew_SetReg1( P3d4 , ( 0x8A + j ) , pVBInfo->CR40[ 1 + j ][ XGINew_RAMType ] ) ; /* CR8A - CR8B */
+
+ if ( ( HwDeviceExtension->jChipType == XG41 ) || ( HwDeviceExtension->jChipType == XG42 ) )
+ XGINew_SetReg1( P3d4 , 0x8C , 0x87 ) ;
+
+ XGINew_SetReg1( P3d4 , 0x59 , pVBInfo->CR40[ 4 ][ XGINew_RAMType ] ) ; /* CR59 */
+
+ XGINew_SetReg1( P3d4 , 0x83 , 0x09 ) ; /* CR83 */
+ XGINew_SetReg1( P3d4 , 0x87 , 0x00 ) ; /* CR87 */
+ XGINew_SetReg1( P3d4 , 0xCF , *pVBInfo->pCRCF ) ; /* CRCF */
+ if ( XGINew_RAMType )
+ {
+ //XGINew_SetReg1( P3c4 , 0x17 , 0xC0 ) ; /* SR17 DDRII */
+ XGINew_SetReg1( P3c4 , 0x17 , 0x80 ) ; /* SR17 DDRII */
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGINew_SetReg1( P3c4 , 0x17 , 0x02 ) ; /* SR17 DDRII */
+
+ }
+ else
+ XGINew_SetReg1( P3c4 , 0x17 , 0x00 ) ; /* SR17 DDR */
+ XGINew_SetReg1( P3c4 , 0x1A , 0x87 ) ; /* SR1A */
+
+ temp = XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) ;
+ if( temp == 0 )
+ XGINew_DDR1x_DefaultRegister( HwDeviceExtension, P3d4, pVBInfo ) ;
+ else
+ {
+ XGINew_SetReg1( P3d4 , 0xB0 , 0x80 ) ; /* DDRII Dual frequency mode */
+ XGINew_DDR2_DefaultRegister( HwDeviceExtension, P3d4, pVBInfo ) ;
+ }
+ XGINew_SetReg1( P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR_MRS */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR_MRS(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+
+ PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
+
+ /* SR16 <- 1F,DF,2F,AF */
+ /* yriver modified SR16 <- 0F,DF,0F,AF */
+ /* enable DLL of DDR SD/SGRAM , SR16 D4=1 */
+ data = pVideoMemory[ 0xFB ] ;
+ /* data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ; */
+
+ data &= 0x0F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data |= 0xC0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data &= 0x0F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data |= 0x80 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data &= 0x0F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data |= 0xD0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data &= 0x0F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+ data |= 0xA0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , data ) ;
+/*
+ else {
+ data &= 0x0F;
+ data |= 0x10;
+ XGINew_SetReg1(pVBInfo->P3c4,0x16,data);
+
+ if (!(pVBInfo->SR15[1][XGINew_RAMType] & 0x10))
+ {
+ data &= 0x0F;
+ }
+
+ data |= 0xC0;
+ XGINew_SetReg1(pVBInfo->P3c4,0x16,data);
+
+
+ data &= 0x0F;
+ data |= 0x20;
+ XGINew_SetReg1(pVBInfo->P3c4,0x16,data);
+ if (!(pVBInfo->SR15[1][XGINew_RAMType] & 0x10))
+ {
+ data &= 0x0F;
+ }
+
+ data |= 0x80;
+ XGINew_SetReg1(pVBInfo->P3c4,0x16,data);
+ }
+*/
+}
+
+
+/* check if read cache pointer is correct */
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_VerifyMclk */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_VerifyMclk( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ PUCHAR pVideoMemory = pVBInfo->FBAddr ;
+ UCHAR i , j ;
+ USHORT Temp , SR21 ;
+
+ pVideoMemory[ 0 ] = 0xaa ; /* alan */
+ pVideoMemory[ 16 ] = 0x55 ; /* note: PCI read cache is off */
+
+ if ( ( pVideoMemory[ 0 ] != 0xaa ) || ( pVideoMemory[ 16 ] != 0x55 ) )
+ {
+ for( i = 0 , j = 16 ; i < 2 ; i++ , j += 16 )
+ {
+ SR21 = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
+ Temp = SR21 & 0xFB ; /* disable PCI post write buffer empty gating */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , Temp ) ;
+
+ Temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3C ) ;
+ Temp |= 0x01 ; /* MCLK reset */
+
+
+ Temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x3C ) ;
+ Temp &= 0xFE ; /* MCLK normal operation */
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , SR21 ) ;
+
+ pVideoMemory[ 16 + j ] = j ;
+ if ( pVideoMemory[ 16 + j ] == j )
+ {
+ pVideoMemory[ j ] = j ;
+ break ;
+ }
+ }
+ }
+}
+
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMSize_340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMSize_340( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+
+ XGISetModeNew( HwDeviceExtension , 0x2e ) ;
+
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */
+ XGI_DisplayOff( HwDeviceExtension, pVBInfo );
+
+ /*data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ;*/
+ /*data |= 0x20 ;*/
+ /*XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ;*/ /* Turn OFF Display */
+ XGINew_DDRSizing340( HwDeviceExtension, pVBInfo ) ;
+ data=XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMSize_310( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ,
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+#ifdef XGI301
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x40 ) ; */
+#endif
+
+#ifdef XGI302 /* alan,should change value */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x30 , 0x4D ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x31 , 0xc0 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x34 , 0x3F ) ;
+#endif
+
+ XGISetModeNew( HwDeviceExtension , 0x2e ) ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data & 0xDF ) ) ; /* disable read cache */
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1 ) ;
+ data |= 0x20 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ; /* Turn OFF Display */
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x16 ) ;
+
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , ( USHORT )( data | 0x0F ) ) ; /* assume lowest speed DRAM */
+
+ XGINew_SetDRAMModeRegister( pVBInfo ) ;
+ XGINew_DisableRefresh( HwDeviceExtension, pVBInfo ) ;
+ XGINew_CheckBusWidth_310( pVBInfo) ;
+ XGINew_VerifyMclk( HwDeviceExtension, pVBInfo ) ; /* alan 2000/7/3 */
+
+
+
+ if ( XGINew_Get310DRAMType( pVBInfo ) < 2 )
+ {
+ XGINew_SDRSizing( pVBInfo ) ;
+ }
+ else
+ {
+ XGINew_DDRSizing( pVBInfo) ;
+ }
+
+
+
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x16 , pVBInfo->SR15[ 1 ][ XGINew_RAMType ] ) ; /* restore SR16 */
+
+ XGINew_EnableRefresh( HwDeviceExtension, pVBInfo ) ;
+ data=XGINew_GetReg1( pVBInfo->P3c4 ,0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x21 , ( USHORT )( data | 0x20 ) ) ; /* enable read cache */
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMModeRegister340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+
+void XGINew_SetDRAMModeRegister340( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+ UCHAR data ;
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ISXPDOS = 0 ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */
+
+ InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo);
+
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+
+ if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 )
+ {
+ data = ( XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) & 0x02 ) >> 1 ;
+ if ( data == 0x01 )
+ XGINew_DDR2x_MRS_340( pVBInfo->P3c4, pVBInfo ) ;
+ else
+ XGINew_DDR1x_MRS_340( pVBInfo->P3c4, pVBInfo ) ;
+ }
+ else
+ XGINew_DDR2_MRS_XG20( HwDeviceExtension, pVBInfo->P3c4, pVBInfo);
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMModeRegister */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMModeRegister( PVB_DEVICE_INFO pVBInfo)
+{
+ if ( XGINew_Get310DRAMType( pVBInfo ) < 2 )
+ {
+ XGINew_SDR_MRS(pVBInfo ) ;
+ }
+ else
+ {
+ /* SR16 <- 0F,CF,0F,8F */
+ XGINew_DDR_MRS( pVBInfo ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DisableRefresh */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DisableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1B ) ;
+ data &= 0xF8 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , data ) ;
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_EnableRefresh */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_EnableRefresh( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */
+
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DisableChannelInterleaving */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DisableChannelInterleaving( int index , USHORT XGINew_DDRDRAM_TYPE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x15 ) ;
+ data &= 0x1F ;
+
+ switch( XGINew_DDRDRAM_TYPE[ index ][ 3 ] )
+ {
+ case 64:
+ data |= 0 ;
+ break ;
+ case 32:
+ data |= 0x20 ;
+ break ;
+ case 16:
+ data |= 0x40 ;
+ break ;
+ case 4:
+ data |= 0x60 ;
+ break ;
+ default:
+ break ;
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMSizingType */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMSizingType( int index , USHORT DRAMTYPE_TABLE[][ 5 ] ,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+
+ data = DRAMTYPE_TABLE[ index ][ 4 ] ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x13 , 0x80 , data ) ;
+ DelayUS( 15 ) ;
+ /* should delay 50 ns */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckBusWidth_310 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_CheckBusWidth_310( PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+ PULONG volatile pVideoMemory ;
+
+ pVideoMemory = (PULONG) pVBInfo->FBAddr;
+
+ if ( XGINew_Get310DRAMType( pVBInfo ) < 2 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x12 ) ;
+ /* should delay */
+ XGINew_SDR_MRS( pVBInfo ) ;
+
+ XGINew_ChannelAB = 0 ;
+ XGINew_DataBusWidth = 128 ;
+ pVideoMemory[ 0 ] = 0x01234567L ;
+ pVideoMemory[ 1 ] = 0x456789ABL ;
+ pVideoMemory[ 2 ] = 0x89ABCDEFL ;
+ pVideoMemory[ 3 ] = 0xCDEF0123L ;
+ pVideoMemory[ 4 ] = 0x55555555L ;
+ pVideoMemory[ 5 ] = 0x55555555L ;
+ pVideoMemory[ 6 ] = 0xFFFFFFFFL ;
+ pVideoMemory[ 7 ] = 0xFFFFFFFFL ;
+
+ if ( ( pVideoMemory[ 3 ] != 0xCDEF0123L ) || ( pVideoMemory[ 2 ] != 0x89ABCDEFL ) )
+ {
+ /* ChannelA64Bit */
+ XGINew_DataBusWidth = 64 ;
+ XGINew_ChannelAB = 0 ;
+ data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( data & 0xFD ) ) ;
+ }
+
+ if ( ( pVideoMemory[ 1 ] != 0x456789ABL ) || ( pVideoMemory[ 0 ] != 0x01234567L ) )
+ {
+ /* ChannelB64Bit */
+ XGINew_DataBusWidth = 64 ;
+ XGINew_ChannelAB = 1 ;
+ data=XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( USHORT )( ( data & 0xFD ) | 0x01 ) ) ;
+ }
+
+ return ;
+ }
+ else
+ {
+ /* DDR Dual channel */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x02 ) ; /* Channel A, 64bit */
+ /* should delay */
+ XGINew_DDR_MRS( pVBInfo ) ;
+
+ XGINew_ChannelAB = 0 ;
+ XGINew_DataBusWidth = 64 ;
+ pVideoMemory[ 0 ] = 0x01234567L ;
+ pVideoMemory[ 1 ] = 0x456789ABL ;
+ pVideoMemory[ 2 ] = 0x89ABCDEFL ;
+ pVideoMemory[ 3 ] = 0xCDEF0123L ;
+ pVideoMemory[ 4 ] = 0x55555555L ;
+ pVideoMemory[ 5 ] = 0x55555555L ;
+ pVideoMemory[ 6 ] = 0xAAAAAAAAL ;
+ pVideoMemory[ 7 ] = 0xAAAAAAAAL ;
+
+ if ( pVideoMemory[ 1 ] == 0x456789ABL )
+ {
+ if ( pVideoMemory[ 0 ] == 0x01234567L )
+ {
+ /* Channel A 64bit */
+ return ;
+ }
+ }
+ else
+ {
+ if ( pVideoMemory[ 0 ] == 0x01234567L )
+ {
+ /* Channel A 32bit */
+ XGINew_DataBusWidth = 32 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x00 ) ;
+ return ;
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x03 ) ; /* Channel B, 64bit */
+ XGINew_DDR_MRS( pVBInfo);
+
+ XGINew_ChannelAB = 1 ;
+ XGINew_DataBusWidth = 64 ;
+ pVideoMemory[ 0 ] = 0x01234567L ;
+ pVideoMemory[ 1 ] = 0x456789ABL ;
+ pVideoMemory[ 2 ] = 0x89ABCDEFL ;
+ pVideoMemory[ 3 ] = 0xCDEF0123L ;
+ pVideoMemory[ 4 ] = 0x55555555L ;
+ pVideoMemory[ 5 ] = 0x55555555L ;
+ pVideoMemory[ 6 ] = 0xAAAAAAAAL ;
+ pVideoMemory[ 7 ] = 0xAAAAAAAAL ;
+
+ if ( pVideoMemory[ 1 ] == 0x456789ABL )
+ {
+ /* Channel B 64 */
+ if ( pVideoMemory[ 0 ] == 0x01234567L )
+ {
+ /* Channel B 64bit */
+ return ;
+ }
+ else
+ {
+ /* error */
+ }
+ }
+ else
+ {
+ if ( pVideoMemory[ 0 ] == 0x01234567L )
+ {
+ /* Channel B 32 */
+ XGINew_DataBusWidth = 32 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x01 ) ;
+ }
+ else
+ {
+ /* error */
+ }
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetRank */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_SetRank( int index , UCHAR RankNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+ int RankSize ;
+
+ if ( ( RankNo == 2 ) && ( DRAMTYPE_TABLE[ index ][ 0 ] == 2 ) )
+ return 0 ;
+
+ RankSize = DRAMTYPE_TABLE[ index ][ 3 ] / 2 * XGINew_DataBusWidth / 32 ;
+
+ if ( ( RankNo * RankSize ) <= 128 )
+ {
+ data = 0 ;
+
+ while( ( RankSize >>= 1 ) > 0 )
+ {
+ data += 0x10 ;
+ }
+ data |= ( RankNo - 1 ) << 2 ;
+ data |= ( XGINew_DataBusWidth / 64 ) & 2 ;
+ data |= XGINew_ChannelAB ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ;
+ /* should delay */
+ XGINew_SDR_MRS( pVBInfo ) ;
+ return( 1 ) ;
+ }
+ else
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDDRChannel */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_SetDDRChannel( int index , UCHAR ChannelNo , UCHAR XGINew_ChannelAB , USHORT DRAMTYPE_TABLE[][ 5 ] , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+ int RankSize ;
+
+ RankSize = DRAMTYPE_TABLE[index][3]/2 * XGINew_DataBusWidth/32;
+ /* RankSize = DRAMTYPE_TABLE[ index ][ 3 ] ; */
+ if ( ChannelNo * RankSize <= 128 )
+ {
+ data = 0 ;
+ while( ( RankSize >>= 1 ) > 0 )
+ {
+ data += 0x10 ;
+ }
+
+ if ( ChannelNo == 2 )
+ data |= 0x0C ;
+
+ data |= ( XGINew_DataBusWidth / 32 ) & 2 ;
+ data |= XGINew_ChannelAB ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ;
+ /* should delay */
+ XGINew_DDR_MRS( pVBInfo ) ;
+ return( 1 ) ;
+ }
+ else
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckColumn */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckColumn( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ ULONG Increment , Position ;
+
+ /* Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 1 ) ; */
+ Increment = 1 << ( 10 + XGINew_DataBusWidth / 64 ) ;
+
+ for( i = 0 , Position = 0 ; i < 2 ; i++ )
+ {
+ *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ Position += Increment ;
+ }
+
+#ifdef WIN2000 /* chiawen for linux solution */
+ DelayUS( 100 ) ;
+#endif
+
+ for( i = 0 , Position = 0 ; i < 2 ; i++ )
+ {
+ /* if ( pVBInfo->FBAddr[ Position ] != Position ) */
+ if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
+ return( 0 ) ;
+ Position += Increment ;
+ }
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckBanks */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckBanks( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ ULONG Increment , Position ;
+
+ Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + XGINew_DataBusWidth / 64 + 2 ) ;
+
+ for( i = 0 , Position = 0 ; i < 4 ; i++ )
+ {
+ /* pVBInfo->FBAddr[ Position ] = Position ; */
+ *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ Position += Increment ;
+ }
+
+ for( i = 0 , Position = 0 ; i < 4 ; i++ )
+ {
+ /* if (pVBInfo->FBAddr[ Position ] != Position ) */
+ if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
+ return( 0 ) ;
+ Position += Increment ;
+ }
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckRank */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ ULONG Increment , Position ;
+
+ Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] +
+ DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ;
+
+ for( i = 0 , Position = 0 ; i < 2 ; i++ )
+ {
+ /* pVBInfo->FBAddr[ Position ] = Position ; */
+ /* *( ( PULONG )( pVBInfo->FBAddr ) ) = Position ; */
+ *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ Position += Increment ;
+ }
+
+ for( i = 0 , Position = 0 ; i < 2 ; i++ )
+ {
+ /* if ( pVBInfo->FBAddr[ Position ] != Position ) */
+ /* if ( ( *( PULONG )( pVBInfo->FBAddr ) ) != Position ) */
+ if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
+ return( 0 ) ;
+ Position += Increment ;
+ }
+ return( 1 );
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckDDRRank */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckDDRRank( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ ULONG Increment , Position ;
+ USHORT data ;
+
+ Increment = 1 << ( DRAMTYPE_TABLE[ index ][ 2 ] + DRAMTYPE_TABLE[ index ][ 1 ] +
+ DRAMTYPE_TABLE[ index ][ 0 ] + XGINew_DataBusWidth / 64 + RankNo ) ;
+
+ Increment += Increment / 2 ;
+
+ Position = 0;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 0 ) ) = 0x01234567 ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 1 ) ) = 0x456789AB ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 2 ) ) = 0x55555555 ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 3 ) ) = 0x55555555 ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 4 ) ) = 0xAAAAAAAA ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position + 5 ) ) = 0xAAAAAAAA ;
+
+ if ( ( *( PULONG )( pVBInfo->FBAddr + 1 ) ) == 0x456789AB )
+ return( 1 ) ;
+
+ if ( ( *( PULONG )( pVBInfo->FBAddr + 0 ) ) == 0x01234567 )
+ return( 0 ) ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ;
+ data &= 0xF3 ;
+ data |= 0x0E ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x15 ) ;
+ data += 0x20 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , data ) ;
+
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckRanks */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ int r ;
+
+ for( r = RankNo ; r >= 1 ; r-- )
+ {
+ if ( !XGINew_CheckRank( r , index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+ }
+
+ if ( !XGINew_CheckBanks( index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+
+ if ( !XGINew_CheckColumn( index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckDDRRanks */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_CheckDDRRanks( int RankNo , int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ int r ;
+
+ for( r = RankNo ; r >= 1 ; r-- )
+ {
+ if ( !XGINew_CheckDDRRank( r , index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+ }
+
+ if ( !XGINew_CheckBanks( index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+
+ if ( !XGINew_CheckColumn( index , DRAMTYPE_TABLE, pVBInfo ) )
+ return( 0 ) ;
+
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_SDRSizing(PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ UCHAR j ;
+
+ for( i = 0 ; i < 13 ; i++ )
+ {
+ XGINew_SetDRAMSizingType( i , XGINew_SDRDRAM_TYPE , pVBInfo) ;
+
+ for( j = 2 ; j > 0 ; j-- )
+ {
+ if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_SDRDRAM_TYPE , pVBInfo) )
+ continue ;
+ else
+ {
+ if ( XGINew_CheckRanks( j , i , XGINew_SDRDRAM_TYPE, pVBInfo) )
+ return( 1 ) ;
+ }
+ }
+ }
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMSizeReg */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGINew_SetDRAMSizeReg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data = 0 , memsize = 0 ;
+ int RankSize ;
+ UCHAR ChannelNo ;
+
+ RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 32 ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ;
+ data &= 0x80 ;
+
+ if ( data == 0x80 )
+ RankSize *= 2 ;
+
+ data = 0 ;
+
+ if( XGINew_ChannelAB == 3 )
+ ChannelNo = 4 ;
+ else
+ ChannelNo = XGINew_ChannelAB ;
+
+ if ( ChannelNo * RankSize <= 256 )
+ {
+ while( ( RankSize >>= 1 ) > 0 )
+ {
+ data += 0x10 ;
+ }
+
+ memsize = data >> 4 ;
+
+ /* [2004/03/25] Vicent, Fix DRAM Sizing Error */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) & 0x0F ) | ( data & 0xF0 ) ) ;
+
+ /* data |= XGINew_ChannelAB << 2 ; */
+ /* data |= ( XGINew_DataBusWidth / 64 ) << 1 ; */
+ /* XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; */
+
+ /* should delay */
+ /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */
+ }
+ return( memsize ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMSize20Reg */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGINew_SetDRAMSize20Reg( int index , USHORT DRAMTYPE_TABLE[][ 5 ], PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data = 0 , memsize = 0 ;
+ int RankSize ;
+ UCHAR ChannelNo ;
+
+ RankSize = DRAMTYPE_TABLE[ index ][ 3 ] * XGINew_DataBusWidth / 8 ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x13 ) ;
+ data &= 0x80 ;
+
+ if ( data == 0x80 )
+ RankSize *= 2 ;
+
+ data = 0 ;
+
+ if( XGINew_ChannelAB == 3 )
+ ChannelNo = 4 ;
+ else
+ ChannelNo = XGINew_ChannelAB ;
+
+ if ( ChannelNo * RankSize <= 256 )
+ {
+ while( ( RankSize >>= 1 ) > 0 )
+ {
+ data += 0x10 ;
+ }
+
+ memsize = data >> 4 ;
+
+ /* [2004/03/25] Vicent, Fix DRAM Sizing Error */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , ( XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) & 0x0F ) | ( data & 0xF0 ) ) ;
+ DelayUS( 15 ) ;
+
+ /* data |= XGINew_ChannelAB << 2 ; */
+ /* data |= ( XGINew_DataBusWidth / 64 ) << 1 ; */
+ /* XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , data ) ; */
+
+ /* should delay */
+ /* XGINew_SetDRAMModeRegister340( pVBInfo ) ; */
+ }
+ return( memsize ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_ReadWriteRest */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_ReadWriteRest( USHORT StopAddr , USHORT StartAddr, PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ ULONG Position = 0 ;
+
+ *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+
+ for( i = StartAddr ; i <= StopAddr ; i++ )
+ {
+ Position = 1 << i ;
+ *( ( PULONG )( pVBInfo->FBAddr + Position ) ) = Position ;
+ }
+
+ DelayUS( 500 ) ; /* [Vicent] 2004/04/16. Fix #1759 Memory Size error in Multi-Adapter. */
+
+ Position = 0 ;
+
+ if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
+ return( 0 ) ;
+
+ for( i = StartAddr ; i <= StopAddr ; i++ )
+ {
+ Position = 1 << i ;
+ if ( ( *( PULONG )( pVBInfo->FBAddr + Position ) ) != Position )
+ return( 0 ) ;
+ }
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckFrequence */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGINew_CheckFrequence( PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR data ;
+
+ data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) ;
+
+ if ( ( data & 0x10 ) == 0 )
+ {
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x39 ) ;
+ data = ( data & 0x02 ) >> 1 ;
+ return( data ) ;
+ }
+ else
+ return( data & 0x01 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_CheckChannel */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_CheckChannel( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR data;
+
+ switch( HwDeviceExtension->jChipType )
+ {
+ case XG20:
+ case XG21:
+ data = XGINew_GetReg1( pVBInfo->P3d4 , 0x97 ) ;
+ data = data & 0x01;
+ XGINew_ChannelAB = 1 ; /* XG20 "JUST" one channel */
+
+ if ( data == 0 ) /* Single_32_16 */
+ {
+
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x1000000)
+ {
+
+ XGINew_DataBusWidth = 32 ; /* 32 bits */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* 22bit + 2 rank + 32bit */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ;
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000)
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* 22bit + 1 rank + 32bit */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ;
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 23 , 23 , pVBInfo ) == 1 )
+ return ;
+ }
+ }
+
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000)
+ {
+ XGINew_DataBusWidth = 16 ; /* 16 bits */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* 22bit + 2 rank + 16bit */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x41 ) ;
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 )
+ return ;
+ else
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ;
+ DelayUS( 15 ) ;
+ }
+
+ }
+ else /* Dual_16_8 */
+ {
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x800000)
+ {
+
+ XGINew_DataBusWidth = 16 ; /* 16 bits */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* (0x31:12x8x2) 22bit + 2 rank */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x41 ) ; /* 0x41:16Mx16 bit*/
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 )
+ return ;
+
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x400000)
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* (0x31:12x8x2) 22bit + 1 rank */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x31 ) ; /* 0x31:8Mx16 bit*/
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 22 , 22 , pVBInfo ) == 1 )
+ return ;
+ }
+ }
+
+
+ if (( HwDeviceExtension->ulVideoMemorySize - 1 ) > 0x400000)
+ {
+ XGINew_DataBusWidth = 8 ; /* 8 bits */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xB1 ) ; /* (0x31:12x8x2) 22bit + 2 rank */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x30 ) ; /* 0x30:8Mx8 bit*/
+ DelayUS( 15 ) ;
+
+ if ( XGINew_ReadWriteRest( 22 , 21 , pVBInfo ) == 1 )
+ return ;
+ else
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x31 ) ; /* (0x31:12x8x2) 22bit + 1 rank */
+ DelayUS( 15 ) ;
+ }
+ }
+ break ;
+
+ case XG27:
+ XGINew_DataBusWidth = 16 ; /* 16 bits */
+ XGINew_ChannelAB = 1 ; /* Single channel */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x51 ) ; /* 32Mx16 bit*/
+ break ;
+ case XG41:
+ if ( XGINew_CheckFrequence(pVBInfo) == 1 )
+ {
+ XGINew_DataBusWidth = 32 ; /* 32 bits */
+ XGINew_ChannelAB = 3 ; /* Quad Channel */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4C ) ;
+
+ if ( XGINew_ReadWriteRest( 25 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 2 ; /* Dual channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x48 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x49 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 3 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x3C ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x38 ) ;
+
+ if ( XGINew_ReadWriteRest( 8 , 4 , pVBInfo ) == 1 )
+ return ;
+ else
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x39 ) ;
+ }
+ else
+ { /* DDR */
+ XGINew_DataBusWidth = 64 ; /* 64 bits */
+ XGINew_ChannelAB = 2 ; /* Dual channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x5A ) ;
+
+ if ( XGINew_ReadWriteRest( 25 , 24 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 1 ; /* Single channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x53 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 2 ; /* Dual channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4A ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 1 ; /* Single channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ;
+
+ if ( XGINew_ReadWriteRest( 8 , 4 , pVBInfo ) == 1 )
+ return ;
+ else
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x43 ) ;
+ }
+
+ break ;
+
+ case XG42:
+/*
+ XG42 SR14 D[3] Reserve
+ D[2] = 1, Dual Channel
+ = 0, Single Channel
+
+ It's Different from Other XG40 Series.
+*/
+ if ( XGINew_CheckFrequence(pVBInfo) == 1 ) /* DDRII, DDR2x */
+ {
+ XGINew_DataBusWidth = 32 ; /* 32 bits */
+ XGINew_ChannelAB = 2 ; /* 2 Channel */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x44 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x34 ) ;
+ if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 1 ; /* Single Channel */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x40 ) ;
+
+ if ( XGINew_ReadWriteRest( 23 , 22 , pVBInfo ) == 1 )
+ return ;
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x30 ) ;
+ }
+ }
+ else
+ { /* DDR */
+ XGINew_DataBusWidth = 64 ; /* 64 bits */
+ XGINew_ChannelAB = 1 ; /* 1 channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x52 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x42 ) ;
+ }
+ }
+
+ break ;
+
+ default: /* XG40 */
+
+ if ( XGINew_CheckFrequence(pVBInfo) == 1 ) /* DDRII */
+ {
+ XGINew_DataBusWidth = 32 ; /* 32 bits */
+ XGINew_ChannelAB = 3 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4C ) ;
+
+ if ( XGINew_ReadWriteRest( 25 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_ChannelAB = 2 ; /* 2 channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x48 ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ return ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x3C ) ;
+
+ if ( XGINew_ReadWriteRest( 24 , 23 , pVBInfo ) == 1 )
+ XGINew_ChannelAB = 3 ; /* 4 channels */
+ else
+ {
+ XGINew_ChannelAB = 2 ; /* 2 channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x38 ) ;
+ }
+ }
+ else
+ { /* DDR */
+ XGINew_DataBusWidth = 64 ; /* 64 bits */
+ XGINew_ChannelAB = 2 ; /* 2 channels */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0xA1 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x5A ) ;
+
+ if ( XGINew_ReadWriteRest( 25 , 24 , pVBInfo ) == 1 )
+ return ;
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x13 , 0x21 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x14 , 0x4A ) ;
+ }
+ }
+ break ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDRSizing340 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_DDRSizing340( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ USHORT memsize , addr ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x15 , 0x00 ) ; /* noninterleaving */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1C , 0x00 ) ; /* nontiling */
+ XGINew_CheckChannel( HwDeviceExtension, pVBInfo ) ;
+
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ {
+ for( i = 0 ; i < 12 ; i++ )
+ {
+ XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE20, pVBInfo ) ;
+ memsize = XGINew_SetDRAMSize20Reg( i , XGINew_DDRDRAM_TYPE20, pVBInfo ) ;
+ if ( memsize == 0 )
+ continue ;
+
+ addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ;
+ if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) )
+ continue ;
+
+ if ( XGINew_ReadWriteRest( addr , 5, pVBInfo ) == 1 )
+ return( 1 ) ;
+ }
+ }
+ else
+ {
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE340, pVBInfo ) ;
+ memsize = XGINew_SetDRAMSizeReg( i , XGINew_DDRDRAM_TYPE340, pVBInfo ) ;
+
+ if ( memsize == 0 )
+ continue ;
+
+ addr = memsize + ( XGINew_ChannelAB - 2 ) + 20 ;
+ if ( ( HwDeviceExtension->ulVideoMemorySize - 1 ) < ( ULONG )( 1 << addr ) )
+ continue ;
+
+ if ( XGINew_ReadWriteRest( addr , 9, pVBInfo ) == 1 )
+ return( 1 ) ;
+ }
+ }
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDRSizing */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int XGINew_DDRSizing(PVB_DEVICE_INFO pVBInfo)
+{
+ int i ;
+ UCHAR j ;
+
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ XGINew_SetDRAMSizingType( i , XGINew_DDRDRAM_TYPE, pVBInfo ) ;
+ XGINew_DisableChannelInterleaving( i , XGINew_DDRDRAM_TYPE , pVBInfo) ;
+ for( j = 2 ; j > 0 ; j-- )
+ {
+ XGINew_SetDDRChannel( i , j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE , pVBInfo ) ;
+ if ( !XGINew_SetRank( i , ( UCHAR )j , XGINew_ChannelAB , XGINew_DDRDRAM_TYPE, pVBInfo ) )
+ continue ;
+ else
+ {
+ if ( XGINew_CheckDDRRanks( j , i , XGINew_DDRDRAM_TYPE, pVBInfo ) )
+ return( 1 ) ;
+ }
+ }
+ }
+ return( 0 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetMemoryClock */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetMemoryClock( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x28 , pVBInfo->MCLKData[ XGINew_RAMType ].SR28 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x29 , pVBInfo->MCLKData[ XGINew_RAMType ].SR29 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2A , pVBInfo->MCLKData[ XGINew_RAMType ].SR2A ) ;
+
+
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , pVBInfo->ECLKData[ XGINew_RAMType ].SR2E ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , pVBInfo->ECLKData[ XGINew_RAMType ].SR2F ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x30 , pVBInfo->ECLKData[ XGINew_RAMType ].SR30 ) ;
+
+ /* [Vicent] 2004/07/07, When XG42 ECLK = MCLK = 207MHz, Set SR32 D[1:0] = 10b */
+ /* [Hsuan] 2004/08/20, Modify SR32 value, when MCLK=207MHZ, ELCK=250MHz, Set SR32 D[1:0] = 10b */
+ if ( HwDeviceExtension->jChipType == XG42 )
+ {
+ if ( ( pVBInfo->MCLKData[ XGINew_RAMType ].SR28 == 0x1C ) && ( pVBInfo->MCLKData[ XGINew_RAMType ].SR29 == 0x01 )
+ && ( ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x1C ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) )
+ || ( ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2E == 0x22 ) && ( pVBInfo->ECLKData[ XGINew_RAMType ].SR2F == 0x01 ) ) ) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , ( ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) & 0xFC ) | 0x02 ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : ChkLFB */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN ChkLFB( PVB_DEVICE_INFO pVBInfo )
+{
+ if ( LFBDRAMTrap & XGINew_GetReg1( pVBInfo->P3d4 , 0x78 ) )
+ return( TRUE ) ;
+ else
+ return( FALSE );
+}
+
+
+/* --------------------------------------------------------------------- */
+/* input : dx ,valid value : CR or second chip's CR */
+/* */
+/* SetPowerConsume : */
+/* Description: reduce 40/43 power consumption in first chip or */
+/* in second chip, assume CR A1 D[6]="1" in this case */
+/* output : none */
+/* --------------------------------------------------------------------- */
+void SetPowerConsume ( PXGI_HW_DEVICE_INFO HwDeviceExtension , ULONG XGI_P3d4Port )
+{
+ ULONG lTemp ;
+ UCHAR bTemp;
+
+ HwDeviceExtension->pQueryVGAConfigSpace( HwDeviceExtension , 0x08 , 0 , &lTemp ) ; /* Get */
+ if ((lTemp&0xFF)==0)
+ {
+ /* set CR58 D[5]=0 D[3]=0 */
+ XGINew_SetRegAND( XGI_P3d4Port , 0x58 , 0xD7 ) ;
+ bTemp = (UCHAR) XGINew_GetReg1( XGI_P3d4Port , 0xCB ) ;
+ if (bTemp&0x20)
+ {
+ if (!(bTemp&0x10))
+ {
+ XGINew_SetRegANDOR( XGI_P3d4Port , 0x58 , 0xD7 , 0x20 ) ; /* CR58 D[5]=1 D[3]=0 */
+ }
+ else
+ {
+ XGINew_SetRegANDOR( XGI_P3d4Port , 0x58 , 0xD7 , 0x08 ) ; /* CR58 D[5]=0 D[3]=1 */
+ }
+
+ }
+
+ }
+}
+
+
+
+#if defined(LINUX_XF86)||defined(LINUX_KERNEL)
+void XGINew_InitVBIOSData(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+
+ /* ULONG ROMAddr = (ULONG)HwDeviceExtension->pjVirtualRomBase; */
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ISXPDOS = 0 ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ XGI_GetVBType( pVBInfo ) ; /* Run XGI_GetVBType before InitTo330Pointer */
+
+ switch(HwDeviceExtension->jChipType)
+ {
+ case XG40:
+ case XG41:
+ case XG42:
+ case XG20:
+ case XG21:
+ default:
+ InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo);
+ return ;
+ }
+
+}
+#endif /* For Linux */
+
+/* --------------------------------------------------------------------- */
+/* Function : ReadVBIOSTablData */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo)
+{
+ PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
+ ULONG i ;
+ UCHAR j , k ;
+#if 0
+ ULONG ii , jj ;
+ i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ; /* UniROM */
+ if ( i != 0 )
+ UNIROM = 1 ;
+
+ ii = 0x90 ;
+ for( jj = 0x00 ; jj < 0x08 ; jj++ )
+ {
+ pVBInfo->MCLKData[ jj ].SR28 = pVideoMemory[ ii ] ;
+ pVBInfo->MCLKData[ jj ].SR29 = pVideoMemory[ ii + 1] ;
+ pVBInfo->MCLKData[ jj ].SR2A = pVideoMemory[ ii + 2] ;
+ pVBInfo->MCLKData[ jj ].CLOCK = pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ;
+ ii += 0x05 ;
+ }
+
+ ii = 0xB8 ;
+ for( jj = 0x00 ; jj < 0x08 ; jj++ )
+ {
+ pVBInfo->ECLKData[ jj ].SR2E = pVideoMemory[ ii ] ;
+ pVBInfo->ECLKData[ jj ].SR2F=pVideoMemory[ ii + 1 ] ;
+ pVBInfo->ECLKData[ jj ].SR30= pVideoMemory[ ii + 2 ] ;
+ pVBInfo->ECLKData[ jj ].CLOCK= pVideoMemory[ ii + 3 ] | ( pVideoMemory[ ii + 4 ] << 8 ) ;
+ ii += 0x05 ;
+ }
+
+ /* Volari customize data area start */
+ /* if ( ChipType == XG40 ) */
+ if ( ChipType >= XG40 )
+ {
+ ii = 0xE0 ;
+ for( jj = 0x00 ; jj < 0x03 ; jj++ )
+ {
+ pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR13, SR14, and SR18 */
+ pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
+ pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
+ pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
+ pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
+ pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
+ pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
+ pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
+ ii += 0x08 ;
+ }
+ ii = 0x110 ;
+ jj = 0x03 ;
+ pVBInfo->SR15[ jj ][ 0 ] = pVideoMemory[ ii ] ; /* SR1B */
+ pVBInfo->SR15[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
+ pVBInfo->SR15[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
+ pVBInfo->SR15[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
+ pVBInfo->SR15[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
+ pVBInfo->SR15[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
+ pVBInfo->SR15[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
+ pVBInfo->SR15[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
+
+ *pVBInfo->pSR07 = pVideoMemory[ 0x74 ] ;
+ *pVBInfo->pSR1F = pVideoMemory[ 0x75 ] ;
+ *pVBInfo->pSR21 = pVideoMemory[ 0x76 ] ;
+ *pVBInfo->pSR22 = pVideoMemory[ 0x77 ] ;
+ *pVBInfo->pSR23 = pVideoMemory[ 0x78 ] ;
+ *pVBInfo->pSR24 = pVideoMemory[ 0x79 ] ;
+ pVBInfo->SR25[ 0 ] = pVideoMemory[ 0x7A ] ;
+ *pVBInfo->pSR31 = pVideoMemory[ 0x7B ] ;
+ *pVBInfo->pSR32 = pVideoMemory[ 0x7C ] ;
+ *pVBInfo->pSR33 = pVideoMemory[ 0x7D ] ;
+ ii = 0xF8 ;
+
+ for( jj = 0 ; jj < 3 ; jj++ )
+ {
+ pVBInfo->CR40[ jj ][ 0 ] = pVideoMemory[ ii ] ;
+ pVBInfo->CR40[ jj ][ 1 ] = pVideoMemory[ ii + 1 ] ;
+ pVBInfo->CR40[ jj ][ 2 ] = pVideoMemory[ ii + 2 ] ;
+ pVBInfo->CR40[ jj ][ 3 ] = pVideoMemory[ ii + 3 ] ;
+ pVBInfo->CR40[ jj ][ 4 ] = pVideoMemory[ ii + 4 ] ;
+ pVBInfo->CR40[ jj ][ 5 ] = pVideoMemory[ ii + 5 ] ;
+ pVBInfo->CR40[ jj ][ 6 ] = pVideoMemory[ ii + 6 ] ;
+ pVBInfo->CR40[ jj ][ 7 ] = pVideoMemory[ ii + 7 ] ;
+ ii += 0x08 ;
+ }
+
+ ii = 0x118 ;
+ for( j = 3 ; j < 24 ; j++ )
+ {
+ pVBInfo->CR40[ j ][ 0 ] = pVideoMemory[ ii ] ;
+ pVBInfo->CR40[ j ][ 1 ] = pVideoMemory[ ii + 1 ] ;
+ pVBInfo->CR40[ j ][ 2 ] = pVideoMemory[ ii + 2 ] ;
+ pVBInfo->CR40[ j ][ 3 ] = pVideoMemory[ ii + 3 ] ;
+ pVBInfo->CR40[ j ][ 4 ] = pVideoMemory[ ii + 4 ] ;
+ pVBInfo->CR40[ j ][ 5 ] = pVideoMemory[ ii + 5 ] ;
+ pVBInfo->CR40[ j ][ 6 ] = pVideoMemory[ ii + 6 ] ;
+ pVBInfo->CR40[ j ][ 7 ] = pVideoMemory[ ii + 7 ] ;
+ ii += 0x08 ;
+ }
+
+ i = pVideoMemory[ 0x1C0 ] | ( pVideoMemory[ 0x1C1 ] << 8 ) ;
+
+ for( j = 0 ; j < 8 ; j++ )
+ {
+ for( k = 0 ; k < 4 ; k++ )
+ pVBInfo->CR6B[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ;
+ }
+
+ i = pVideoMemory[ 0x1C2 ] | ( pVideoMemory[ 0x1C3 ] << 8 ) ;
+
+ for( j = 0 ; j < 8 ; j++ )
+ {
+ for( k = 0 ; k < 4 ; k++ )
+ pVBInfo->CR6E[ j ][ k ] = pVideoMemory[ i + 4 * j + k ] ;
+ }
+
+ i = pVideoMemory[ 0x1C4 ] | ( pVideoMemory[ 0x1C5 ] << 8 ) ;
+ for( j = 0 ; j < 8 ; j++ )
+ {
+ for( k = 0 ; k < 32 ; k++ )
+ pVBInfo->CR6F[ j ][ k ] = pVideoMemory[ i + 32 * j + k ] ;
+ }
+
+ i = pVideoMemory[ 0x1C6 ] | ( pVideoMemory[ 0x1C7 ] << 8 ) ;
+
+ for( j = 0 ; j < 8 ; j++ )
+ {
+ for( k = 0 ; k < 2 ; k++ )
+ pVBInfo->CR89[ j ][ k ] = pVideoMemory[ i + 2 * j + k ] ;
+ }
+
+ i = pVideoMemory[ 0x1C8 ] | ( pVideoMemory[ 0x1C9 ] << 8 ) ;
+ for( j = 0 ; j < 12 ; j++ )
+ pVBInfo->AGPReg[ j ] = pVideoMemory[ i + j ] ;
+
+ i = pVideoMemory[ 0x1CF ] | ( pVideoMemory[ 0x1D0 ] << 8 ) ;
+ for( j = 0 ; j < 4 ; j++ )
+ pVBInfo->SR16[ j ] = pVideoMemory[ i + j ] ;
+
+ if ( ChipType == XG21 )
+ {
+ if (pVideoMemory[ 0x67 ] & 0x80)
+ {
+ *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ];
+ }
+ if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 )
+ {
+ *pVBInfo->pCR2E = pVideoMemory[ i + 4 ] ;
+ *pVBInfo->pCR2F = pVideoMemory[ i + 5 ] ;
+ *pVBInfo->pCR46 = pVideoMemory[ i + 6 ] ;
+ *pVBInfo->pCR47 = pVideoMemory[ i + 7 ] ;
+ }
+ }
+
+ if ( ChipType == XG27 )
+ {
+ jj = i+j;
+ for( i = 0 ; i <= 0xB ; i++,jj++ )
+ pVBInfo->pCRD0[i] = pVideoMemory[ jj ] ;
+ for( i = 0x0 ; i <= 0x1 ; i++,jj++ )
+ pVBInfo->pCRDE[i] = pVideoMemory[ jj ] ;
+
+ *pVBInfo->pSR40 = pVideoMemory[ jj ] ;
+ jj++;
+ *pVBInfo->pSR41 = pVideoMemory[ jj ] ;
+
+ if (pVideoMemory[ 0x67 ] & 0x80)
+ {
+ *pVBInfo->pDVOSetting = pVideoMemory[ 0x67 ];
+ }
+ if ( (pVideoMemory[ 0x67 ] & 0xC0) == 0xC0 )
+ {
+ jj++;
+ *pVBInfo->pCR2E = pVideoMemory[ jj ] ;
+ *pVBInfo->pCR2F = pVideoMemory[ jj + 1 ] ;
+ *pVBInfo->pCR46 = pVideoMemory[ jj + 2 ] ;
+ *pVBInfo->pCR47 = pVideoMemory[ jj + 3 ] ;
+ }
+
+ }
+
+ *pVBInfo->pCRCF = pVideoMemory[ 0x1CA ] ;
+ *pVBInfo->pXGINew_DRAMTypeDefinition = pVideoMemory[ 0x1CB ] ;
+ *pVBInfo->pXGINew_I2CDefinition = pVideoMemory[ 0x1D1 ] ;
+ if ( ChipType >= XG20 )
+ {
+ *pVBInfo->pXGINew_CR97 = pVideoMemory[ 0x1D2 ] ;
+ if ( ChipType == XG27 )
+ {
+ *pVBInfo->pSR36 = pVideoMemory[ 0x1D3 ] ;
+ *pVBInfo->pCR8F = pVideoMemory[ 0x1D5 ] ;
+ }
+ }
+
+ }
+#endif
+ /* Volari customize data area end */
+
+ if ( ChipType == XG21 )
+ {
+ pVBInfo->IF_DEF_LVDS = 0 ;
+ if (pVideoMemory[ 0x65 ] & 0x1)
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ i = pVideoMemory[ 0x316 ] | ( pVideoMemory[ 0x317 ] << 8 );
+ j = pVideoMemory[ i-1 ] ;
+ if ( j != 0xff )
+ {
+ k = 0;
+ do
+ {
+ pVBInfo->XG21_LVDSCapList[k].LVDS_Capability = pVideoMemory[ i ] | ( pVideoMemory[ i + 1 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSHT = pVideoMemory[ i + 2 ] | ( pVideoMemory[ i + 3 ] << 8 ) ;
+ pVBInfo->XG21_LVDSCapList[k].LVDSVT = pVideoMemory[ i + 4 ] | ( pVideoMemory[ i + 5 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSHDE = pVideoMemory[ i + 6 ] | ( pVideoMemory[ i + 7 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSVDE = pVideoMemory[ i + 8 ] | ( pVideoMemory[ i + 9 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSHFP = pVideoMemory[ i + 10 ] | ( pVideoMemory[ i + 11 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSVFP = pVideoMemory[ i + 12 ] | ( pVideoMemory[ i + 13 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSHSYNC = pVideoMemory[ i + 14 ] | ( pVideoMemory[ i + 15 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].LVDSVSYNC = pVideoMemory[ i + 16 ] | ( pVideoMemory[ i + 17 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[k].VCLKData1 = pVideoMemory[ i + 18 ] ;
+ pVBInfo->XG21_LVDSCapList[k].VCLKData2 = pVideoMemory[ i + 19 ] ;
+ pVBInfo->XG21_LVDSCapList[k].PSC_S1 = pVideoMemory[ i + 20 ] ;
+ pVBInfo->XG21_LVDSCapList[k].PSC_S2 = pVideoMemory[ i + 21 ] ;
+ pVBInfo->XG21_LVDSCapList[k].PSC_S3 = pVideoMemory[ i + 22 ] ;
+ pVBInfo->XG21_LVDSCapList[k].PSC_S4 = pVideoMemory[ i + 23 ] ;
+ pVBInfo->XG21_LVDSCapList[k].PSC_S5 = pVideoMemory[ i + 24 ] ;
+ i += 25;
+ j--;
+ k++;
+ } while ( (j>0) && ( k < (sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct)) ) );
+ }
+ else
+ {
+ pVBInfo->XG21_LVDSCapList[0].LVDS_Capability = pVideoMemory[ i ] | ( pVideoMemory[ i + 1 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSHT = pVideoMemory[ i + 2 ] | ( pVideoMemory[ i + 3 ] << 8 ) ;
+ pVBInfo->XG21_LVDSCapList[0].LVDSVT = pVideoMemory[ i + 4 ] | ( pVideoMemory[ i + 5 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSHDE = pVideoMemory[ i + 6 ] | ( pVideoMemory[ i + 7 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSVDE = pVideoMemory[ i + 8 ] | ( pVideoMemory[ i + 9 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSHFP = pVideoMemory[ i + 10 ] | ( pVideoMemory[ i + 11 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSVFP = pVideoMemory[ i + 12 ] | ( pVideoMemory[ i + 13 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSHSYNC = pVideoMemory[ i + 14 ] | ( pVideoMemory[ i + 15 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].LVDSVSYNC = pVideoMemory[ i + 16 ] | ( pVideoMemory[ i + 17 ] << 8 );
+ pVBInfo->XG21_LVDSCapList[0].VCLKData1 = pVideoMemory[ i + 18 ] ;
+ pVBInfo->XG21_LVDSCapList[0].VCLKData2 = pVideoMemory[ i + 19 ] ;
+ pVBInfo->XG21_LVDSCapList[0].PSC_S1 = pVideoMemory[ i + 20 ] ;
+ pVBInfo->XG21_LVDSCapList[0].PSC_S2 = pVideoMemory[ i + 21 ] ;
+ pVBInfo->XG21_LVDSCapList[0].PSC_S3 = pVideoMemory[ i + 22 ] ;
+ pVBInfo->XG21_LVDSCapList[0].PSC_S4 = pVideoMemory[ i + 23 ] ;
+ pVBInfo->XG21_LVDSCapList[0].PSC_S5 = pVideoMemory[ i + 24 ] ;
+ }
+ }
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_DDR1x_MRS_XG20 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_DDR1x_MRS_XG20( ULONG P3c4 , PVB_DEVICE_INFO pVBInfo)
+{
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x01 ) ;
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+ DelayUS( 60 ) ;
+
+ XGINew_SetReg1( P3c4 , 0x18 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x19 , 0x40 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x80 ) ;
+ DelayUS( 60 ) ;
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x01 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x03 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ;
+ DelayUS( 1000 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x03 ) ;
+ DelayUS( 500 ) ;
+ /* XGINew_SetReg1( P3c4 , 0x18 , 0x31 ) ; */
+ XGINew_SetReg1( P3c4 , 0x18 , pVBInfo->SR15[ 2 ][ XGINew_RAMType ] ) ; /* SR18 */
+ XGINew_SetReg1( P3c4 , 0x19 , 0x00 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x03 ) ;
+ XGINew_SetReg1( P3c4 , 0x16 , 0x83 ) ;
+ XGINew_SetReg1( P3c4 , 0x1B , 0x00 ) ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetDRAMModeRegister_XG20 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetDRAMModeRegister_XG20( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ISXPDOS = 0 ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo);
+
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+
+ if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 )
+ XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ;
+ else
+ XGINew_DDR2_MRS_XG20( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ;
+}
+
+void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ISXPDOS = 0 ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo);
+
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+
+ if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 )
+ XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ;
+ else
+ //XGINew_DDR2_MRS_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ;
+ XGINew_DDRII_Bootup_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo) ;
+
+ //XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , pVBInfo->SR15[ 3 ][ XGINew_RAMType ] ) ; /* SR1B */
+
+}
+/*
+void XGINew_SetDRAMModeRegister_XG27( PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+#ifndef LINUX_XF86
+ UCHAR data ;
+#endif
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ;
+ pVBInfo->BaseAddr = HwDeviceExtension->pjIOAddress ;
+ pVBInfo->ISXPDOS = 0 ;
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ InitTo330Pointer(HwDeviceExtension->jChipType,pVBInfo);
+
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+
+ if ( XGINew_GetXG20DRAMType( HwDeviceExtension, pVBInfo) == 0 )
+ XGINew_DDR1x_MRS_XG20( pVBInfo->P3c4, pVBInfo ) ;
+ else
+ XGINew_DDR2_MRS_XG27( HwDeviceExtension , pVBInfo->P3c4 , pVBInfo ) ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1B , 0x03 ) ;
+}
+*/
+/* -------------------------------------------------------- */
+/* Function : XGINew_ChkSenseStatus */
+/* Input : */
+/* Output : */
+/* Description : */
+/* -------------------------------------------------------- */
+void XGINew_ChkSenseStatus ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx=0 , temp , tempcx , CR3CData;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x32 ) ;
+
+ if ( temp & Monitor1Sense )
+ tempbx |= ActiveCRT1 ;
+ if ( temp & LCDSense )
+ tempbx |= ActiveLCD ;
+ if ( temp & Monitor2Sense )
+ tempbx |= ActiveCRT2 ;
+ if ( temp & TVSense )
+ {
+ tempbx |= ActiveTV ;
+ if ( temp & AVIDEOSense )
+ tempbx |= ( ActiveAVideo << 8 );
+ if ( temp & SVIDEOSense )
+ tempbx |= ( ActiveSVideo << 8 );
+ if ( temp & SCARTSense )
+ tempbx |= ( ActiveSCART << 8 );
+ if ( temp & HiTVSense )
+ tempbx |= ( ActiveHiTV << 8 );
+ if ( temp & YPbPrSense )
+ tempbx |= ( ActiveYPbPr << 8 );
+ }
+
+ tempcx = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ;
+ tempcx |= ( XGINew_GetReg1( pVBInfo->P3d4 , 0x3e ) << 8 ) ;
+
+ if ( tempbx & tempcx )
+ {
+ CR3CData = XGINew_GetReg1( pVBInfo->P3d4 , 0x3c ) ;
+ if ( !( CR3CData & DisplayDeviceFromCMOS ) )
+ {
+ tempcx = 0x1FF0 ;
+ if ( *pVBInfo->pSoftSetting & ModeSoftSetting )
+ {
+ tempbx = 0x1FF0 ;
+ }
+ }
+ }
+ else
+ {
+ tempcx = 0x1FF0 ;
+ if ( *pVBInfo->pSoftSetting & ModeSoftSetting )
+ {
+ tempbx = 0x1FF0 ;
+ }
+ }
+
+ tempbx &= tempcx ;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x3d , ( tempbx & 0x00FF ) ) ;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x3e , ( ( tempbx & 0xFF00 ) >> 8 )) ;
+}
+/* -------------------------------------------------------- */
+/* Function : XGINew_SetModeScratch */
+/* Input : */
+/* Output : */
+/* Description : */
+/* -------------------------------------------------------- */
+void XGINew_SetModeScratch ( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp , tempcl = 0 , tempch = 0 , CR31Data , CR38Data;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ;
+ temp |= XGINew_GetReg1( pVBInfo->P3d4 , 0x3e ) << 8 ;
+ temp |= ( XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) & ( DriverMode >> 8) ) << 8 ;
+
+ if ( pVBInfo->IF_DEF_CRT2Monitor == 1)
+ {
+ if ( temp & ActiveCRT2 )
+ tempcl = SetCRT2ToRAMDAC ;
+ }
+
+ if ( temp & ActiveLCD )
+ {
+ tempcl |= SetCRT2ToLCD ;
+ if ( temp & DriverMode )
+ {
+ if ( temp & ActiveTV )
+ {
+ tempch = SetToLCDA | EnableDualEdge ;
+ temp ^= SetCRT2ToLCD ;
+
+ if ( ( temp >> 8 ) & ActiveAVideo )
+ tempcl |= SetCRT2ToAVIDEO ;
+ if ( ( temp >> 8 ) & ActiveSVideo )
+ tempcl |= SetCRT2ToSVIDEO ;
+ if ( ( temp >> 8 ) & ActiveSCART )
+ tempcl |= SetCRT2ToSCART ;
+
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ {
+ if ( ( temp >> 8 ) & ActiveHiTV )
+ tempcl |= SetCRT2ToHiVisionTV ;
+ }
+
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( ( temp >> 8 ) & ActiveYPbPr )
+ tempch |= SetYPbPr ;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( ( temp >> 8 ) & ActiveAVideo )
+ tempcl |= SetCRT2ToAVIDEO ;
+ if ( ( temp >> 8 ) & ActiveSVideo )
+ tempcl |= SetCRT2ToSVIDEO ;
+ if ( ( temp >> 8 ) & ActiveSCART )
+ tempcl |= SetCRT2ToSCART ;
+
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ {
+ if ( ( temp >> 8 ) & ActiveHiTV )
+ tempcl |= SetCRT2ToHiVisionTV ;
+ }
+
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( ( temp >> 8 ) & ActiveYPbPr )
+ tempch |= SetYPbPr ;
+ }
+ }
+
+
+ tempcl |= SetSimuScanMode ;
+ if ( (!( temp & ActiveCRT1 )) && ( ( temp & ActiveLCD ) || ( temp & ActiveTV ) || ( temp & ActiveCRT2 ) ) )
+ tempcl ^= ( SetSimuScanMode | SwitchToCRT2 ) ;
+ if ( ( temp & ActiveLCD ) && ( temp & ActiveTV ) )
+ tempcl ^= ( SetSimuScanMode | SwitchToCRT2 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x30 , tempcl ) ;
+
+ CR31Data = XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ;
+ CR31Data &= ~( SetNotSimuMode >> 8 ) ;
+ if ( !( temp & ActiveCRT1 ) )
+ CR31Data |= ( SetNotSimuMode >> 8 ) ;
+ CR31Data &= ~( DisableCRT2Display >> 8 ) ;
+ if (!( ( temp & ActiveLCD ) || ( temp & ActiveTV ) || ( temp & ActiveCRT2 ) ) )
+ CR31Data |= ( DisableCRT2Display >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x31 , CR31Data ) ;
+
+ CR38Data = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ CR38Data &= ~SetYPbPr ;
+ CR38Data |= tempch ;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x38 , CR38Data ) ;
+
+}
+
+/* -------------------------------------------------------- */
+/* Function : XGINew_GetXG21Sense */
+/* Input : */
+/* Output : */
+/* Description : */
+/* -------------------------------------------------------- */
+void XGINew_GetXG21Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR Temp;
+ PUCHAR volatile pVideoMemory = ( PUCHAR )pVBInfo->ROMAddr ;
+
+ pVBInfo->IF_DEF_LVDS = 0 ;
+
+#ifdef WIN2000
+ pVBInfo->IF_DEF_CH7007 = 0 ;
+ if ( ( pVideoMemory[ 0x65 ] & 0x02 ) ) /* For XG21 CH7007 */
+ {
+ /* VideoDebugPrint((0, "ReadVBIOSTablData: pVideoMemory[ 0x65 ] =%x\n",pVideoMemory[ 0x65 ])); */
+ pVBInfo->IF_DEF_CH7007 = 1 ; /* [Billy] 07/05/03 */
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0x60 ) ; /* CH7007 on chip */
+ }
+ else
+#endif
+#if 1
+ if (( pVideoMemory[ 0x65 ] & 0x01 ) ) /* For XG21 LVDS */
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xC0 ) ; /* LVDS on chip */
+ }
+ else
+ {
+#endif
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x03 , 0x03 ) ; /* Enable GPIOA/B read */
+ Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0xC0;
+ if ( Temp == 0xC0 )
+ { /* DVI & DVO GPIOA/B pull high */
+ XGINew_SenseLCD( HwDeviceExtension, pVBInfo ) ;
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x20 , 0x20 ) ; /* Enable read GPIOF */
+ Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0x04 ;
+ if ( !Temp )
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0x80 ) ; /* TMDS on chip */
+ else
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xA0 ) ; /* Only DVO on chip */
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ; /* Disable read GPIOF */
+ }
+#if 1
+ }
+#endif
+}
+
+/* -------------------------------------------------------- */
+/* Function : XGINew_GetXG27Sense */
+/* Input : */
+/* Output : */
+/* Description : */
+/* -------------------------------------------------------- */
+void XGINew_GetXG27Sense(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR Temp,bCR4A;
+
+ pVBInfo->IF_DEF_LVDS = 0 ;
+ bCR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x07 , 0x07 ) ; /* Enable GPIOA/B/C read */
+ Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) & 0x07;
+ XGINew_SetReg1( pVBInfo->P3d4, 0x4A , bCR4A ) ;
+
+ if ( Temp <= 0x02 )
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xC0 ) ; /* LVDS setting */
+ XGINew_SetReg1( pVBInfo->P3d4, 0x30 , 0x21 ) ;
+ }
+ else
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x38 , ~0xE0 , 0xA0 ) ; /* TMDS/DVO setting */
+ }
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x32 , LCDSense ) ;
+
+}
+
+UCHAR GetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR38,CR4A,temp;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x10 , 0x10 ) ; /* enable GPIOE read */
+ CR38 = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ temp =0;
+ if ( ( CR38 & 0xE0 ) > 0x80 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ;
+ temp &= 0x08;
+ temp >>= 3;
+ }
+
+ XGINew_SetReg1( pVBInfo->P3d4, 0x4A , CR4A ) ;
+
+ return temp;
+}
+
+UCHAR GetXG27FPBits(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR4A,temp;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x4A , ~0x03 , 0x03 ) ; /* enable GPIOA/B/C read */
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ;
+ if ( temp <= 2 )
+ {
+ temp &= 0x03;
+ }
+ else
+ {
+ temp = ((temp&0x04)>>1) || ((~temp)&0x01);
+ }
+ XGINew_SetReg1( pVBInfo->P3d4, 0x4A , CR4A ) ;
+
+ return temp;
+}
+
diff --git a/drivers/staging/xgifb/vb_init.h b/drivers/staging/xgifb/vb_init.h
new file mode 100644
index 000000000000..1f39d9c74cdd
--- /dev/null
+++ b/drivers/staging/xgifb/vb_init.h
@@ -0,0 +1,7 @@
+#ifndef _VBINIT_
+#define _VBINIT_
+extern BOOLEAN XGIInitNew( PXGI_HW_DEVICE_INFO HwDeviceExtension ) ;
+extern XGI21_LVDSCapStruct XGI21_LCDCapList[13];
+
+#endif
+
diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c
new file mode 100644
index 000000000000..bd7f73898644
--- /dev/null
+++ b/drivers/staging/xgifb/vb_setmode.c
@@ -0,0 +1,10736 @@
+#include "osdef.h"
+
+#ifdef TC
+#include <stdio.h>
+#include <string.h>
+#include <conio.h>
+#include <dos.h>
+#endif
+
+
+#ifdef LINUX_XF86
+#include "xf86.h"
+#include "xf86PciInfo.h"
+#include "xgi.h"
+#include "xgi_regs.h"
+#endif
+
+#ifdef LINUX_KERNEL
+#include <asm/io.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include "XGIfb.h"
+/*#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <video/XGIfb.h>
+#else
+#include <linux/XGIfb.h>
+#endif*/
+#endif
+
+#ifdef WIN2000
+#include <dderror.h>
+#include <devioctl.h>
+#include <miniport.h>
+#include <ntddvdeo.h>
+#include <video.h>
+
+#include "xgiv.h"
+#include "dd_i2c.h"
+#include "tools.h"
+#endif
+
+#include "vb_def.h"
+#include "vgatypes.h"
+#include "vb_struct.h"
+#include "vb_util.h"
+#include "vb_table.h"
+
+
+
+#define IndexMask 0xff
+#ifndef XGI_MASK_DUAL_CHIP
+#define XGI_MASK_DUAL_CHIP 0x04 /* SR3A */
+#endif
+
+
+
+BOOLEAN XGI_IsLCDDualLink(PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_BacklightByDrv(PVB_DEVICE_INFO pVBInfo);
+
+BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_AjustCRT2Rate(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,USHORT *i, PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ;
+BOOLEAN XGI_BridgeIsOn(PVB_DEVICE_INFO pVBInfo);
+UCHAR XGI_GetModePtr( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
+USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetColorDepth(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetVGAHT2(PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetVCLK2Ptr(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_VBLongWait(PVB_DEVICE_INFO pVBInfo);
+void XGI_SaveCRT2Info(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo);
+void XGI_GetCRT2Data(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_GetCRT2ResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_PreSetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetGroup1(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLockRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetGroup2(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetGroup5(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void* XGI_GetLcdPtr(USHORT BX, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void* XGI_GetTVPtr(USHORT BX, USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo);
+void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo);
+void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo);
+void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo);
+void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo);
+
+void XGI_DisplayOn(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
+void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo );
+void XGI_SetCRT1Group(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo);
+void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo);
+void XGI_UpdateXG21CRTC(USHORT ModeNo, PVB_DEVICE_INFO pVBInfo, USHORT RefreshRateTableIndex);
+void XGI_WaitDisply(PVB_DEVICE_INFO pVBInfo);
+void XGI_SenseCRT1(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetSeqRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetMiscRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRTCRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetATTRegs(USHORT ModeNo,USHORT StandTableIndex,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo );
+void XGI_SetGRCRegs(USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo);
+
+void XGI_SetSync(USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1CRTC(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension);
+void XGI_SetCRT1Timing_H(PVB_DEVICE_INFO pVBInfo,PXGI_HW_DEVICE_INFO HwDeviceExtension);
+void XGI_SetCRT1Timing_V(USHORT ModeIdIndex,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1DE(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1VCLK(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1FIFO(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1ModeRegs(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetVCLKState(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+
+void XGI_LoadDAC(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_WriteDAC(USHORT dl, USHORT ah, USHORT al, USHORT dh, PVB_DEVICE_INFO pVBInfo);
+/*void XGI_ClearBuffer(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,PVB_DEVICE_INFO pVBInfo);*/
+void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetLVDSResInfo( USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetLVDSData(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_ModCRT1Regs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLVDSRegs(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_UpdateModeInfo(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo);
+void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT2ECLK( USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo);
+void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO pVBInfo);
+void XGI_GetLCDSync(USHORT* HSyncWidth, USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo);
+void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT2VCLK(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_OEM310Setting(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetDelayComp(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLCDCap(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo);
+void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo);
+void SetSpectrum(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetAntiFlicker(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetEdgeEnhance(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetPhaseIncr(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetYFilter(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo );
+void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo );
+void XGI_CloseCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
+void XGI_OpenCRTC(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
+void XGI_GetRAMDAC2DATA(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
+void XGI_LockCRT2(PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO pVBInfo);
+void XGINew_EnableCRT2(PVB_DEVICE_INFO pVBInfo);
+void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo);
+void XGI_LongWait(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo );
+void XGI_GetLCDVCLKPtr(UCHAR* di_0,UCHAR *di_1, PVB_DEVICE_INFO pVBInfo);
+UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetLCDCapPtr(PVB_DEVICE_INFO pVBInfo);
+USHORT XGI_GetLCDCapPtr1(PVB_DEVICE_INFO pVBInfo);
+XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo);
+void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
+void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
+UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo);
+UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo);
+void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
+void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
+void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
+UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo );
+
+extern void ReadVBIOSTablData( UCHAR ChipType , PVB_DEVICE_INFO pVBInfo);
+#ifdef WIN2000
+/* [Billy] 2007/05/17 For CH7007 */
+extern UCHAR CH7007TVReg_UNTSC[][8],CH7007TVReg_ONTSC[][8],CH7007TVReg_UPAL[][8],CH7007TVReg_OPAL[][8];
+extern UCHAR CH7007TVCRT1UNTSC_H[][10],CH7007TVCRT1ONTSC_H[][10],CH7007TVCRT1UPAL_H[][10],CH7007TVCRT1OPAL_H[][10] ;
+extern UCHAR CH7007TVCRT1UNTSC_V[][10],CH7007TVCRT1ONTSC_V[][10],CH7007TVCRT1UPAL_V[][10],CH7007TVCRT1OPAL_V[][10] ;
+extern UCHAR XGI7007_CHTVVCLKUNTSC[],XGI7007_CHTVVCLKONTSC[],XGI7007_CHTVVCLKUPAL[],XGI7007_CHTVVCLKOPAL[];
+
+extern BOOLEAN XGI_XG21CheckCH7007TVMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo ) ;
+extern void SetCH7007Regs(PXGI_HW_DEVICE_INFO HwDeviceExtension, USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo ) ;
+extern VP_STATUS TurnOnCH7007(PHW_DEVICE_EXTENSION pHWDE) ;
+extern VP_STATUS TurnOffCH7007(PHW_DEVICE_EXTENSION pHWDE) ;
+extern BOOLEAN IsCH7007TVMode(PVB_DEVICE_INFO pVBInfo) ;
+#endif
+
+/* USHORT XGINew_flag_clearbuffer; 0: no clear frame buffer 1:clear frame buffer */
+
+
+
+
+
+USHORT XGINew_MDA_DAC[]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F};
+
+USHORT XGINew_CGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
+
+USHORT XGINew_EGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x05,0x15,
+ 0x20,0x30,0x24,0x34,0x21,0x31,0x25,0x35,
+ 0x08,0x18,0x0C,0x1C,0x09,0x19,0x0D,0x1D,
+ 0x28,0x38,0x2C,0x3C,0x29,0x39,0x2D,0x3D,
+ 0x02,0x12,0x06,0x16,0x03,0x13,0x07,0x17,
+ 0x22,0x32,0x26,0x36,0x23,0x33,0x27,0x37,
+ 0x0A,0x1A,0x0E,0x1E,0x0B,0x1B,0x0F,0x1F,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F};
+
+USHORT XGINew_VGA_DAC[]={0x00,0x10,0x04,0x14,0x01,0x11,0x09,0x15,
+ 0x2A,0x3A,0x2E,0x3E,0x2B,0x3B,0x2F,0x3F,
+ 0x00,0x05,0x08,0x0B,0x0E,0x11,0x14,0x18,
+ 0x1C,0x20,0x24,0x28,0x2D,0x32,0x38,0x3F,
+
+ 0x00,0x10,0x1F,0x2F,0x3F,0x1F,0x27,0x2F,
+ 0x37,0x3F,0x2D,0x31,0x36,0x3A,0x3F,0x00,
+ 0x07,0x0E,0x15,0x1C,0x0E,0x11,0x15,0x18,
+ 0x1C,0x14,0x16,0x18,0x1A,0x1C,0x00,0x04,
+ 0x08,0x0C,0x10,0x08,0x0A,0x0C,0x0E,0x10,
+ 0x0B,0x0C,0x0D,0x0F,0x10};
+
+
+/* --------------------------------------------------------------------- */
+/* Function : InitTo330Pointer */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void InitTo330Pointer( UCHAR ChipType ,PVB_DEVICE_INFO pVBInfo)
+{
+ pVBInfo->SModeIDTable = (XGI_StStruct *) XGI330_SModeIDTable ;
+ pVBInfo->StandTable = (XGI_StandTableStruct *) XGI330_StandTable ;
+ pVBInfo->EModeIDTable = (XGI_ExtStruct *) XGI330_EModeIDTable ;
+ pVBInfo->RefIndex = (XGI_Ext2Struct *) XGI330_RefIndex ;
+ pVBInfo->XGINEWUB_CRT1Table = (XGI_CRT1TableStruct *) XGI_CRT1Table ;
+
+ /* add for new UNIVGABIOS */
+ /* XGINew_UBLCDDataTable = (XGI_LCDDataTablStruct *) XGI_LCDDataTable ; */
+ /* XGINew_UBTVDataTable = (XGI_TVDataTablStruct *) XGI_TVDataTable ; */
+
+
+ if ( ChipType >= XG40 )
+ {
+ pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI340New_MCLKData ;
+ pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI340_ECLKData ;
+ }
+ else
+ {
+ pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI330New_MCLKData ;
+ pVBInfo->ECLKData = (XGI_ECLKDataStruct *) XGI330_ECLKData ;
+ }
+
+ pVBInfo->VCLKData = (XGI_VCLKDataStruct *) XGI_VCLKData ;
+ pVBInfo->VBVCLKData = (XGI_VBVCLKDataStruct *) XGI_VBVCLKData ;
+ pVBInfo->ScreenOffset = XGI330_ScreenOffset ;
+ pVBInfo->StResInfo = (XGI_StResInfoStruct *) XGI330_StResInfo ;
+ pVBInfo->ModeResInfo = (XGI_ModeResInfoStruct *) XGI330_ModeResInfo ;
+
+ pVBInfo->pOutputSelect = &XGI330_OutputSelect ;
+ pVBInfo->pSoftSetting = &XGI330_SoftSetting ;
+ pVBInfo->pSR07 = &XGI330_SR07 ;
+ pVBInfo->LCDResInfo = 0 ;
+ pVBInfo->LCDTypeInfo = 0 ;
+ pVBInfo->LCDInfo = 0 ;
+ pVBInfo->VBInfo = 0 ;
+ pVBInfo->TVInfo = 0;
+
+
+ pVBInfo->SR15 = XGI340_SR13 ;
+ pVBInfo->CR40 = XGI340_cr41 ;
+ pVBInfo->SR25 = XGI330_sr25 ;
+ pVBInfo->pSR31 = &XGI330_sr31 ;
+ pVBInfo->pSR32 = &XGI330_sr32 ;
+ pVBInfo->CR6B = XGI340_CR6B ;
+ pVBInfo->CR6E = XGI340_CR6E ;
+ pVBInfo->CR6F = XGI340_CR6F ;
+ pVBInfo->CR89 = XGI340_CR89 ;
+ pVBInfo->AGPReg = XGI340_AGPReg ;
+ pVBInfo->SR16 = XGI340_SR16 ;
+ pVBInfo->pCRCF = &XG40_CRCF ;
+ pVBInfo->pXGINew_DRAMTypeDefinition = &XG40_DRAMTypeDefinition ;
+
+
+ pVBInfo->CR49 = XGI330_CR49 ;
+ pVBInfo->pSR1F = &XGI330_SR1F ;
+ pVBInfo->pSR21 = &XGI330_SR21 ;
+ pVBInfo->pSR22 = &XGI330_SR22 ;
+ pVBInfo->pSR23 = &XGI330_SR23 ;
+ pVBInfo->pSR24 = &XGI330_SR24 ;
+ pVBInfo->pSR33 = &XGI330_SR33 ;
+
+
+
+ pVBInfo->pCRT2Data_1_2 = &XGI330_CRT2Data_1_2 ;
+ pVBInfo->pCRT2Data_4_D = &XGI330_CRT2Data_4_D ;
+ pVBInfo->pCRT2Data_4_E = &XGI330_CRT2Data_4_E ;
+ pVBInfo->pCRT2Data_4_10 = &XGI330_CRT2Data_4_10 ;
+ pVBInfo->pRGBSenseData = &XGI330_RGBSenseData ;
+ pVBInfo->pVideoSenseData = &XGI330_VideoSenseData ;
+ pVBInfo->pYCSenseData = &XGI330_YCSenseData ;
+ pVBInfo->pRGBSenseData2 = &XGI330_RGBSenseData2 ;
+ pVBInfo->pVideoSenseData2 = &XGI330_VideoSenseData2 ;
+ pVBInfo->pYCSenseData2 = &XGI330_YCSenseData2 ;
+
+ pVBInfo->NTSCTiming = XGI330_NTSCTiming ;
+ pVBInfo->PALTiming = XGI330_PALTiming ;
+ pVBInfo->HiTVExtTiming = XGI330_HiTVExtTiming ;
+ pVBInfo->HiTVSt1Timing = XGI330_HiTVSt1Timing ;
+ pVBInfo->HiTVSt2Timing = XGI330_HiTVSt2Timing ;
+ pVBInfo->HiTVTextTiming = XGI330_HiTVTextTiming ;
+ pVBInfo->YPbPr750pTiming = XGI330_YPbPr750pTiming ;
+ pVBInfo->YPbPr525pTiming = XGI330_YPbPr525pTiming ;
+ pVBInfo->YPbPr525iTiming = XGI330_YPbPr525iTiming ;
+ pVBInfo->HiTVGroup3Data = XGI330_HiTVGroup3Data ;
+ pVBInfo->HiTVGroup3Simu = XGI330_HiTVGroup3Simu ;
+ pVBInfo->HiTVGroup3Text = XGI330_HiTVGroup3Text ;
+ pVBInfo->Ren525pGroup3 = XGI330_Ren525pGroup3 ;
+ pVBInfo->Ren750pGroup3 = XGI330_Ren750pGroup3 ;
+
+
+ pVBInfo->TimingH = (XGI_TimingHStruct *) XGI_TimingH ;
+ pVBInfo->TimingV = (XGI_TimingVStruct *) XGI_TimingV ;
+ pVBInfo->UpdateCRT1 = (XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table ;
+
+ pVBInfo->CHTVVCLKUNTSC = XGI330_CHTVVCLKUNTSC ;
+ pVBInfo->CHTVVCLKONTSC = XGI330_CHTVVCLKONTSC ;
+ pVBInfo->CHTVVCLKUPAL = XGI330_CHTVVCLKUPAL ;
+ pVBInfo->CHTVVCLKOPAL = XGI330_CHTVVCLKOPAL ;
+
+ /* 310 customization related */
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ pVBInfo->LCDCapList = XGI_LCDDLCapList ;
+ else
+ pVBInfo->LCDCapList = XGI_LCDCapList ;
+
+ if ( ( ChipType == XG21 ) || ( ChipType == XG27 ) )
+ pVBInfo->XG21_LVDSCapList = XGI21_LCDCapList ;
+
+ pVBInfo->XGI_TVDelayList = XGI301TVDelayList ;
+ pVBInfo->XGI_TVDelayList2 = XGI301TVDelayList2 ;
+
+
+ pVBInfo->pXGINew_I2CDefinition = &XG40_I2CDefinition ;
+
+ if ( ChipType >= XG20 )
+ pVBInfo->pXGINew_CR97 = &XG20_CR97 ;
+
+ if ( ChipType == XG27 )
+ {
+ pVBInfo->MCLKData = (XGI_MCLKDataStruct *) XGI27New_MCLKData ;
+ pVBInfo->CR40 = XGI27_cr41 ;
+ pVBInfo->pXGINew_CR97 = &XG27_CR97 ;
+ pVBInfo->pSR36 = &XG27_SR36 ;
+ pVBInfo->pCR8F = &XG27_CR8F ;
+ pVBInfo->pCRD0 = XG27_CRD0 ;
+ pVBInfo->pCRDE = XG27_CRDE ;
+ pVBInfo->pSR40 = &XG27_SR40 ;
+ pVBInfo->pSR41 = &XG27_SR41 ;
+
+ }
+
+ if ( ChipType >= XG20 )
+ {
+ pVBInfo->pDVOSetting = &XG21_DVOSetting ;
+ pVBInfo->pCR2E = &XG21_CR2E ;
+ pVBInfo->pCR2F = &XG21_CR2F ;
+ pVBInfo->pCR46 = &XG21_CR46 ;
+ pVBInfo->pCR47 = &XG21_CR47 ;
+ }
+
+}
+
+
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGISetModeNew */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo )
+{
+ USHORT ModeIdIndex ;
+ /* PUCHAR pVBInfo->FBAddr = HwDeviceExtension->pjVideoMemoryAddress ; */
+ VB_DEVICE_INFO VBINF;
+ PVB_DEVICE_INFO pVBInfo = &VBINF;
+ pVBInfo->ROMAddr = HwDeviceExtension->pjVirtualRomBase ;
+ pVBInfo->BaseAddr = (ULONG)HwDeviceExtension->pjIOAddress ;
+ pVBInfo->IF_DEF_LVDS = 0 ;
+ pVBInfo->IF_DEF_CH7005 = 0 ;
+ pVBInfo->IF_DEF_LCDA = 1 ;
+ pVBInfo->IF_DEF_CH7017 = 0 ;
+ pVBInfo->IF_DEF_CH7007 = 0 ; /* [Billy] 2007/05/14 */
+ pVBInfo->IF_DEF_VideoCapture = 0 ;
+ pVBInfo->IF_DEF_ScaleLCD = 0 ;
+ pVBInfo->IF_DEF_OEMUtil = 0 ;
+ pVBInfo->IF_DEF_PWD = 0 ;
+
+
+ if ( HwDeviceExtension->jChipType >= XG20 ) /* kuku 2004/06/25 */
+ {
+ pVBInfo->IF_DEF_YPbPr = 0 ;
+ pVBInfo->IF_DEF_HiVision = 0 ;
+ pVBInfo->IF_DEF_CRT2Monitor = 0 ;
+ pVBInfo->VBType = 0 ; /*set VBType default 0*/
+ }
+ else if ( HwDeviceExtension->jChipType >= XG40 )
+ {
+ pVBInfo->IF_DEF_YPbPr = 1 ;
+ pVBInfo->IF_DEF_HiVision = 1 ;
+ pVBInfo->IF_DEF_CRT2Monitor = 1 ;
+ }
+ else
+ {
+ pVBInfo->IF_DEF_YPbPr = 1 ;
+ pVBInfo->IF_DEF_HiVision = 1 ;
+ pVBInfo->IF_DEF_CRT2Monitor = 0 ;
+ }
+
+ pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14 ;
+ pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24 ;
+ pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10 ;
+ pVBInfo->P3ce = pVBInfo->BaseAddr + 0x1e ;
+ pVBInfo->P3c2 = pVBInfo->BaseAddr + 0x12 ;
+ pVBInfo->P3cc = pVBInfo->BaseAddr + 0x1C ;
+ pVBInfo->P3ca = pVBInfo->BaseAddr + 0x1a ;
+ pVBInfo->P3c6 = pVBInfo->BaseAddr + 0x16 ;
+ pVBInfo->P3c7 = pVBInfo->BaseAddr + 0x17 ;
+ pVBInfo->P3c8 = pVBInfo->BaseAddr + 0x18 ;
+ pVBInfo->P3c9 = pVBInfo->BaseAddr + 0x19 ;
+ pVBInfo->P3da = pVBInfo->BaseAddr + 0x2A ;
+ pVBInfo->Part0Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_00 ;
+ pVBInfo->Part1Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_04 ;
+ pVBInfo->Part2Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_10 ;
+ pVBInfo->Part3Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_12 ;
+ pVBInfo->Part4Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 ;
+ pVBInfo->Part5Port = pVBInfo->BaseAddr + XGI_CRT2_PORT_14 + 2 ;
+
+ if ( HwDeviceExtension->jChipType == XG21 ) /* for x86 Linux, XG21 LVDS */
+ {
+ if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 )
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ }
+ }
+ if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ if ( ( XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) & 0xE0 ) == 0xC0 )
+ {
+ if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) & 0x20 )
+ {
+ pVBInfo->IF_DEF_LVDS = 1 ;
+ }
+ }
+ }
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ XGI_GetVBType( pVBInfo ) ;
+
+ InitTo330Pointer( HwDeviceExtension->jChipType, pVBInfo ) ;
+#ifdef WIN2000
+ ReadVBIOSTablData( HwDeviceExtension->jChipType , pVBInfo) ;
+#endif
+ if ( ModeNo & 0x80 )
+ {
+ ModeNo = ModeNo & 0x7F ;
+/* XGINew_flag_clearbuffer = 0 ; */
+ }
+/* else
+ {
+ XGINew_flag_clearbuffer = 1 ;
+ }
+*/
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 1.Openkey */
+ XGI_UnLockCRT2( HwDeviceExtension , pVBInfo ) ;
+
+ XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ;
+
+ XGI_GetVGAType(HwDeviceExtension, pVBInfo) ;
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+ {
+ XGI_GetVBInfo(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_GetTVInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetLCDInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_DisableBridge( HwDeviceExtension,pVBInfo ) ;
+/* XGI_OpenCRTC( HwDeviceExtension, pVBInfo ) ; */
+
+ if ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToLCDA ) )
+ {
+ XGI_SetCRT1Group(HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ XGI_SetLCDAGroup(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ;
+ }
+ }
+ else
+ {
+ if ( !( pVBInfo->VBInfo & SwitchToCRT2) )
+ {
+ XGI_SetCRT1Group( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ XGI_SetLCDAGroup( ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ;
+ }
+ }
+ }
+
+ if ( pVBInfo->VBInfo & ( SetSimuScanMode | SwitchToCRT2 ) )
+ {
+ switch( HwDeviceExtension->ujVBChipID )
+ {
+ case VB_CHIP_301:
+ XGI_SetCRT2Group301( ModeNo , HwDeviceExtension, pVBInfo ) ; /*add for CRT2 */
+ break ;
+
+ case VB_CHIP_302:
+ XGI_SetCRT2Group301(ModeNo , HwDeviceExtension, pVBInfo ) ; /*add for CRT2 */
+ break ;
+
+ default:
+ break ;
+ }
+ }
+
+ XGI_SetCRT2ModeRegs( ModeNo, HwDeviceExtension,pVBInfo ) ;
+ XGI_OEM310Setting( ModeNo, ModeIdIndex,pVBInfo ) ; /*0212*/
+ XGI_CloseCRTC( HwDeviceExtension, pVBInfo ) ;
+ XGI_EnableBridge( HwDeviceExtension ,pVBInfo) ;
+ } /* !XG20 */
+ else
+ {
+#ifdef WIN2000
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+
+ VideoDebugPrint((0, "XGISetModeNew: pVBIfo->IF_DEF_CH7007==1\n"));
+ pVBInfo->VBType = VB_CH7007 ;
+ XGI_GetVBInfo(ModeNo , ModeIdIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_GetTVInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetLCDInfo(ModeNo , ModeIdIndex, pVBInfo ) ;
+ if( !(XGI_XG21CheckCH7007TVMode(ModeNo, ModeIdIndex, pVBInfo )) )
+ {
+ return FALSE;
+ }
+ }
+#endif
+
+
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ if ( !XGI_XG21CheckLVDSMode(ModeNo , ModeIdIndex, pVBInfo) )
+ {
+ return FALSE;
+ }
+ }
+
+ if ( ModeNo <= 0x13 )
+ {
+ pVBInfo->ModeType = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag & ModeInfoFlag;
+ }
+ else
+ {
+ pVBInfo->ModeType = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag & ModeInfoFlag;
+ }
+
+ pVBInfo->SetFlag = 0 ;
+ if ( pVBInfo->IF_DEF_CH7007 != 1 )
+ {
+ pVBInfo->VBInfo = DisableCRT2Display ;
+ }
+
+
+ XGI_DisplayOff(HwDeviceExtension, pVBInfo) ;
+
+ XGI_SetCRT1Group(HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ;
+
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo ) ;
+ /*
+ if( HwDeviceExtension->jChipType == XG21 )
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0x80 , 0x80 ) ;
+ */
+ }
+
+
+/*
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+ pVBInfo->ModeType = modeflag&ModeInfoFlag ;
+ pVBInfo->SetFlag = 0x00 ;
+ pVBInfo->VBInfo = DisableCRT2Display ;
+ temp = XGINew_CheckMemorySize( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ;
+
+ if ( temp == 0 )
+ return( 0 ) ;
+
+ XGI_DisplayOff( HwDeviceExtension, pVBInfo) ;
+ XGI_SetCRT1Group( HwDeviceExtension , ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo) ;
+*/
+
+ XGI_UpdateModeInfo( HwDeviceExtension, pVBInfo ) ;
+
+ if ( HwDeviceExtension->jChipType < XG20 ) /* kuku 2004/06/25 */
+{
+ XGI_LockCRT2( HwDeviceExtension, pVBInfo ) ;
+}
+
+ return( TRUE ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1Group */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1Group( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT StandTableIndex ,
+ RefreshRateTableIndex ,
+ b3CC ,
+ temp ;
+
+ USHORT XGINew_P3cc = pVBInfo->P3cc;
+
+ /* XGINew_CRT1Mode = ModeNo ; // SaveModeID */
+ StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ;
+ /* XGI_SetBIOSData(ModeNo , ModeIdIndex ) ; */
+ /* XGI_ClearBankRegs( ModeNo , ModeIdIndex ) ; */
+ XGI_SetSeqRegs( ModeNo , StandTableIndex , ModeIdIndex, pVBInfo ) ;
+ XGI_SetMiscRegs( StandTableIndex, pVBInfo ) ;
+ XGI_SetCRTCRegs( HwDeviceExtension , StandTableIndex, pVBInfo) ;
+ XGI_SetATTRegs( ModeNo , StandTableIndex , ModeIdIndex, pVBInfo ) ;
+ XGI_SetGRCRegs( StandTableIndex, pVBInfo ) ;
+ XGI_ClearExt1Regs(pVBInfo) ;
+
+/* if ( pVBInfo->IF_DEF_ExpLink ) */
+ if ( HwDeviceExtension->jChipType == XG27 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ XGI_SetDefaultVCLK( pVBInfo ) ;
+ }
+ }
+
+ temp = ~ProgrammingCRT2 ;
+ pVBInfo->SetFlag &= temp ;
+ pVBInfo->SelectCRT2Rate = 0 ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToLCDA | SetInSlaveMode ) )
+ {
+ pVBInfo->SetFlag |= ProgrammingCRT2 ;
+ }
+ }
+
+ RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( RefreshRateTableIndex != 0xFFFF )
+ {
+ XGI_SetSync( RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetCRT1CRTC( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo, HwDeviceExtension ) ;
+ XGI_SetCRT1DE( HwDeviceExtension , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetCRT1Offset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT1VCLK( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ;
+ }
+
+ if ( ( HwDeviceExtension->jChipType >= XG20 )&&
+ ( HwDeviceExtension->jChipType < XG27 ) ) /* fix H/W DCLK/2 bug */
+ {
+ if ( ( ModeNo == 0x00 ) | (ModeNo == 0x01) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x4E) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE9) ;
+ b3CC =(UCHAR) XGINew_GetReg2(XGINew_P3cc) ;
+ XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ;
+ }
+ else if ( ( ModeNo == 0x04) | ( ModeNo == 0x05) | ( ModeNo == 0x0D) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE3) ;
+ b3CC = (UCHAR)XGINew_GetReg2(XGINew_P3cc) ;
+ XGINew_SetReg3(XGINew_P3cc , (b3CC |= 0x0C) ) ;
+ }
+ }
+
+ if ( HwDeviceExtension->jChipType >= XG21 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+ if ( temp & 0xA0 )
+ {
+
+ /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x20 ) ;*/ /* Enable write GPIOF */
+ /*XGINew_SetRegAND( pVBInfo->P3d4 , 0x48 , ~0x20 ) ;*/ /* P. DWN */
+ /* XG21 CRT1 Timing */
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGI_SetXG27CRTC( ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo );
+ else
+ XGI_SetXG21CRTC( ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo );
+
+ XGI_UpdateXG21CRTC( ModeNo , pVBInfo , RefreshRateTableIndex) ;
+
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGI_SetXG27LCD( pVBInfo , RefreshRateTableIndex , ModeNo );
+ else
+ XGI_SetXG21LCD( pVBInfo , RefreshRateTableIndex , ModeNo );
+
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ if ( HwDeviceExtension->jChipType == XG27 )
+ XGI_SetXG27LVDSPara(ModeNo,ModeIdIndex, pVBInfo );
+ else
+ XGI_SetXG21LVDSPara(ModeNo,ModeIdIndex, pVBInfo );
+ }
+ /*XGINew_SetRegOR( pVBInfo->P3d4 , 0x48 , 0x20 ) ;*/ /* P. ON */
+ }
+ }
+
+ pVBInfo->SetFlag &= ( ~ProgrammingCRT2 ) ;
+ XGI_SetCRT1FIFO( ModeNo , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT1ModeRegs( HwDeviceExtension , ModeNo , ModeIdIndex , RefreshRateTableIndex , pVBInfo) ;
+
+
+ /* XGI_LoadCharacter(); //dif ifdef TVFont */
+
+ XGI_LoadDAC( ModeNo , ModeIdIndex, pVBInfo ) ;
+ /* XGI_ClearBuffer( HwDeviceExtension , ModeNo, pVBInfo ) ; */
+#ifdef WIN2000
+ if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/14 */
+ {
+ VideoDebugPrint((0, "XGI_SetCRT1Group: VBInfo->IF_DEF_CH7007==1\n"));
+ SetCH7007Regs(HwDeviceExtension, ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo ) ; /* 07/05/28 */
+ }
+#endif
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetModePtr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGI_GetModePtr( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR index ;
+
+ if ( ModeNo <= 0x13 )
+ index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_StTableIndex ;
+ else
+ {
+ if ( pVBInfo->ModeType <= 0x02 )
+ index = 0x1B ; /* 02 -> ModeEGA */
+ else
+ index = 0x0F ;
+ }
+ return( index ) ; /* Get pVBInfo->StandTable index */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetBIOSData */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+/*UCHAR XGI_SetBIOSData( USHORT ModeNo , USHORT ModeIdIndex )
+{
+ return( 0 ) ;
+}
+*/
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_ClearBankRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+/*UCHAR XGI_ClearBankRegs( USHORT ModeNo , USHORT ModeIdIndex )
+{
+ return( 0 ) ;
+}
+*/
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetSeqRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetSeqRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR tempah ,
+ SRdata ;
+
+ USHORT i ,
+ modeflag ;
+
+ if ( ModeNo <= 0x13 )
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ else
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x00 , 0x03 ) ; /* Set SR0 */
+ tempah=pVBInfo->StandTable[ StandTableIndex ].SR[ 0 ] ;
+
+ i = SetCRT2ToLCDA ;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ tempah |= 0x01 ;
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ tempah |= 0x01 ;
+ }
+ }
+
+ tempah |= 0x20 ; /* screen off */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , tempah ) ; /* Set SR1 */
+
+ for( i = 02 ; i <= 04 ; i++ )
+ {
+ SRdata = pVBInfo->StandTable[ StandTableIndex ].SR[ i - 1 ] ; /* Get SR2,3,4 from file */
+ XGINew_SetReg1( pVBInfo->P3c4 , i , SRdata ) ; /* Set SR2 3 4 */
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetMiscRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetMiscRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR Miscdata ;
+
+ Miscdata = pVBInfo->StandTable[ StandTableIndex ].MISC ; /* Get Misc from file */
+/*
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ Miscdata |= 0x0C ;
+ }
+ }
+*/
+
+ XGINew_SetReg3( pVBInfo->P3c2 , Miscdata ) ; /* Set Misc(3c2) */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRTCRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRTCRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR CRTCdata ;
+ USHORT i ;
+
+ CRTCdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ CRTCdata &= 0x7f ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , CRTCdata ) ; /* Unlock CRTC */
+
+ for( i = 0 ; i <= 0x18 ; i++ )
+ {
+ CRTCdata = pVBInfo->StandTable[ StandTableIndex ].CRTC[ i ] ; /* Get CRTC from file */
+ XGINew_SetReg1( pVBInfo->P3d4 , i , CRTCdata ) ; /* Set CRTC( 3d4 ) */
+ }
+/*
+ if ( ( HwDeviceExtension->jChipType == XGI_630 )&& ( HwDeviceExtension->jChipRevision == 0x30 ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV ) )
+ {
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x18 , 0xFE ) ;
+ }
+ }
+ }
+*/
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetATTRegs( USHORT ModeNo , USHORT StandTableIndex , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR ARdata ;
+ USHORT i ,
+ modeflag ;
+
+ if ( ModeNo <= 0x13 )
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ else
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+
+ for( i = 0 ; i <= 0x13 ; i++ )
+ {
+ ARdata = pVBInfo->StandTable[ StandTableIndex ].ATTR[ i ] ;
+ if ( modeflag & Charx8Dot ) /* ifndef Dot9 */
+ {
+ if ( i == 0x13 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ ARdata = 0 ;
+ else
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ ARdata = 0 ;
+ }
+ }
+ }
+ }
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ XGINew_SetReg3( pVBInfo->P3c0 , i ) ; /* set index */
+ XGINew_SetReg3( pVBInfo->P3c0 , ARdata ) ; /* set data */
+ }
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x14 ) ; /* set index */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data */
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGRCRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGRCRegs( USHORT StandTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR GRdata ;
+ USHORT i ;
+
+ for( i = 0 ; i <= 0x08 ; i++ )
+ {
+ GRdata = pVBInfo->StandTable[ StandTableIndex ].GRC[ i ] ; /* Get GR from file */
+ XGINew_SetReg1( pVBInfo->P3ce , i , GRdata ) ; /* Set GR(3ce) */
+ }
+
+ if ( pVBInfo->ModeType > ModeVGA )
+ {
+ GRdata = ( UCHAR )XGINew_GetReg1( pVBInfo->P3ce , 0x05 ) ;
+ GRdata &= 0xBF ; /* 256 color disable */
+ XGINew_SetReg1( pVBInfo->P3ce , 0x05 , GRdata ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_ClearExt1Regs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_ClearExt1Regs(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT i ;
+
+ for( i = 0x0A ; i <= 0x0E ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , i , 0x00 ) ; /* Clear SR0A-SR0E */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetDefaultVCLK */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGI_SetDefaultVCLK( PVB_DEVICE_INFO pVBInfo )
+{
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , 0x20 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ 0 ].SR2B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ 0 ].SR2C ) ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , 0x10 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ 1 ].SR2B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ 1 ].SR2C ) ;
+
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x31 , ~0x30 ) ;
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetRatePtrCRT2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ SHORT LCDRefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 } ,
+ LCDARefreshIndex[] = { 0x00 , 0x00 , 0x03 , 0x01 , 0x01 , 0x01 , 0x01 } ;
+
+ USHORT RefreshRateTableIndex , i ,
+ modeflag , index , temp ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ if ( pVBInfo->IF_DEF_CH7005 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( modeflag & HalfDCLK )
+ return( 0 ) ;
+ }
+ }
+
+ if ( ModeNo < 0x14 )
+ return( 0xFFFF ) ;
+
+ index = XGINew_GetReg1( pVBInfo->P3d4 , 0x33 ) ;
+ index = index >> pVBInfo->SelectCRT2Rate ;
+ index &= 0x0F ;
+
+ if ( pVBInfo->LCDInfo & LCDNonExpanding )
+ index = 0 ;
+
+ if ( index > 0 )
+ index-- ;
+
+ if ( pVBInfo->SetFlag & ProgrammingCRT2 )
+ {
+ if ( pVBInfo->IF_DEF_CH7005 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ index = 0 ;
+ }
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ if( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ temp = LCDARefreshIndex[ pVBInfo->LCDResInfo & 0x0F ] ; /* 301b */
+ else
+ temp = LCDRefreshIndex[ pVBInfo->LCDResInfo & 0x0F ] ;
+
+ if ( index > temp )
+ {
+ index = temp ;
+ }
+ }
+ else
+ {
+ index = 0 ;
+ }
+ }
+ }
+
+ RefreshRateTableIndex = pVBInfo->EModeIDTable[ ModeIdIndex ].REFindex ;
+ ModeNo = pVBInfo->RefIndex[ RefreshRateTableIndex ].ModeID ;
+ if ( pXGIHWDE->jChipType >= XG20 ) /* for XG20, XG21, XG27 */
+ {
+ /*
+ if ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag & XG2xNotSupport )
+ {
+ index++;
+ }
+ */
+ if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 800 ) &&
+ ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 600 ) )
+ {
+ index++;
+ }
+/* Alan 10/19/2007; do the similiar adjustment like XGISearchCRT1Rate() */
+ if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 1024 ) &&
+ ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 768 ) )
+ {
+ index++;
+ }
+ if ( ( pVBInfo->RefIndex[ RefreshRateTableIndex ].XRes == 1280 ) &&
+ ( pVBInfo->RefIndex[ RefreshRateTableIndex ].YRes == 1024 ) )
+ {
+ index++;
+ }
+ }
+
+ i = 0 ;
+ do
+ {
+ if ( pVBInfo->RefIndex[ RefreshRateTableIndex + i ].ModeID != ModeNo )
+ break ;
+ temp = pVBInfo->RefIndex[ RefreshRateTableIndex + i ].Ext_InfoFlag ;
+ temp &= ModeInfoFlag ;
+ if ( temp < pVBInfo->ModeType )
+ break ;
+ i++ ;
+ index-- ;
+
+ } while( index != 0xFFFF ) ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ temp = pVBInfo->RefIndex[ RefreshRateTableIndex + i - 1 ].Ext_InfoFlag ;
+ if ( temp & InterlaceMode )
+ {
+ i++ ;
+ }
+ }
+ }
+ i-- ;
+ if ( ( pVBInfo->SetFlag & ProgrammingCRT2 ) )
+ {
+ temp = XGI_AjustCRT2Rate( ModeNo , ModeIdIndex , RefreshRateTableIndex , &i, pVBInfo) ;
+ }
+ return( RefreshRateTableIndex + i ) ; /*return(0x01|(temp1<<1)); */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_AjustCRT2Rate */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_AjustCRT2Rate( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , USHORT *i, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempax ,
+ tempbx ,
+ resinfo ,
+ modeflag ,
+ infoflag ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ tempbx = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID ;
+ tempax = 0 ;
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ {
+ tempax |= SupportRAMDAC2 ;
+
+ if ( pVBInfo->VBType & VB_XGI301C )
+ tempax |= SupportCRT2in301C ;
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) /* 301b */
+ {
+ tempax |= SupportLCD ;
+
+ if ( pVBInfo->LCDResInfo != Panel1280x1024 )
+ {
+ if ( pVBInfo->LCDResInfo != Panel1280x960 )
+ {
+ if ( pVBInfo->LCDInfo & LCDNonExpanding )
+ {
+ if ( resinfo >= 9 )
+ {
+ tempax = 0 ;
+ return( 0 ) ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) /* for HiTV */
+ {
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) && ( pVBInfo->VBExtInfo == VB_YPbPr1080i ) )
+ {
+ tempax |= SupportYPbPr ;
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( resinfo == 4 )
+ return( 0 ) ;
+
+ if ( resinfo == 3 )
+ return( 0 ) ;
+
+ if ( resinfo > 7 )
+ return( 0 ) ;
+ }
+ }
+ else
+ {
+ tempax |= SupportHiVisionTV ;
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( resinfo == 4 )
+ return( 0 ) ;
+
+ if ( resinfo == 3 )
+ {
+ if ( pVBInfo->SetFlag & TVSimuMode )
+ return( 0 ) ;
+ }
+
+ if ( resinfo > 7 )
+ return( 0 ) ;
+ }
+ }
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr | SetCRT2ToHiVisionTV ) )
+ {
+ tempax |= SupportTV ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempax |= SupportTV1024 ;
+ }
+
+ if ( !( pVBInfo->VBInfo & SetPALTV ) )
+ {
+ if ( modeflag & NoSupportSimuTV )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( !( pVBInfo->VBInfo & SetNotSimuMode ) )
+ {
+ return( 0 ) ;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else /* for LVDS */
+ {
+ if ( pVBInfo->IF_DEF_CH7005 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ tempax |= SupportCHTV ;
+ }
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ {
+ tempax |= SupportLCD ;
+
+ if ( resinfo > 0x08 )
+ return( 0 ) ; /* 1024x768 */
+
+ if ( pVBInfo->LCDResInfo < Panel1024x768 )
+ {
+ if ( resinfo > 0x07 )
+ return( 0 ) ; /* 800x600 */
+
+ if ( resinfo == 0x04 )
+ return( 0 ) ; /* 512x384 */
+ }
+ }
+ }
+
+ for( ; pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID == tempbx ; ( *i )-- )
+ {
+ infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].Ext_InfoFlag ;
+ if ( infoflag & tempax )
+ {
+ return( 1 ) ;
+ }
+ if ( ( *i ) == 0 )
+ break ;
+ }
+
+ for( ( *i ) = 0 ; ; ( *i )++ )
+ {
+ infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].Ext_InfoFlag ;
+ if ( pVBInfo->RefIndex[ RefreshRateTableIndex + ( *i ) ].ModeID != tempbx )
+ {
+ return( 0 ) ;
+ }
+
+ if ( infoflag & tempax )
+ {
+ return( 1 ) ;
+ }
+ }
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetSync */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetSync(USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT sync ,
+ temp ;
+
+ sync = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag >> 8 ; /* di+0x00 */
+ sync &= 0xC0 ;
+ temp = 0x2F ;
+ temp |= sync ;
+ XGINew_SetReg3( pVBInfo->P3c2 , temp ) ; /* Set Misc(3c2) */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1CRTC */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1CRTC( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+ UCHAR index ,
+ data ;
+
+ USHORT i ;
+
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ; /* Get index */
+ index = index&IndexMask ;
+
+ data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ data &= 0x7F ;
+ XGINew_SetReg1(pVBInfo->P3d4,0x11,data); /* Unlock CRTC */
+
+ for( i = 0 ; i < 8 ; i++ )
+ pVBInfo->TimingH[ 0 ].data[ i ] = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ i ] ;
+
+ for( i = 0 ; i < 7 ; i++ )
+ pVBInfo->TimingV[ 0 ].data[ i ] = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ i + 8 ] ;
+
+ XGI_SetCRT1Timing_H( pVBInfo, HwDeviceExtension ) ;
+
+
+
+ XGI_SetCRT1Timing_V( ModeIdIndex , ModeNo, pVBInfo ) ;
+
+
+ if( pVBInfo->ModeType > 0x03 )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x14 , 0x4F ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1Timing_H */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1Timing_H( PVB_DEVICE_INFO pVBInfo, PXGI_HW_DEVICE_INFO HwDeviceExtension )
+{
+ UCHAR data , data1, pushax;
+ USHORT i , j ;
+
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */
+ /* XGINew_SetRegANDOR( pVBInfo->P3d4 ,0x11 , 0x7f , 0x00 ) ; */
+
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ; /* unlock cr0-7 */
+ data &= 0x7F ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ;
+
+ data = pVBInfo->TimingH[ 0 ].data[ 0 ] ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0 , data ) ;
+
+ for( i = 0x01 ; i <= 0x04 ; i++ )
+ {
+ data = pVBInfo->TimingH[ 0 ].data[ i ] ;
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 1 ) , data ) ;
+ }
+
+ for( i = 0x05 ; i <= 0x06 ; i++ )
+ {
+ data = pVBInfo->TimingH[ 0 ].data[ i ];
+ XGINew_SetReg1( pVBInfo->P3c4 ,( USHORT )( i + 6 ) , data ) ;
+ }
+
+ j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ;
+ j &= 0x1F ;
+ data = pVBInfo->TimingH[ 0 ].data[ 7 ] ;
+ data &= 0xE0 ;
+ data |= j ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0e , data ) ;
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ {
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x04 ) ;
+ data = data - 1 ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x04 , data ) ;
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x05 ) ;
+ data1 = data ;
+ data1 &= 0xE0 ;
+ data &= 0x1F ;
+ if ( data == 0 )
+ {
+ pushax = data ;
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0c ) ;
+ data &= 0xFB ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0c , data ) ;
+ data = pushax ;
+ }
+ data = data - 1 ;
+ data |= data1 ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x05 , data ) ;
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0e ) ;
+ data = data >> 5 ;
+ data = data + 3 ;
+ if ( data > 7 )
+ data = data - 7 ;
+ data = data << 5 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0e , ~0xE0 , data ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1Timing_V */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1Timing_V( USHORT ModeIdIndex , USHORT ModeNo,PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR data ;
+ USHORT i , j ;
+
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0 ) ; */
+ /* XGINew_SetReg1( pVBInfo->P3d4 , 0x56 , 0 ) ; */
+ /* XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , 0x7f , 0x00 ) ; */
+
+ for( i = 0x00 ; i <= 0x01 ; i++ )
+ {
+ data = pVBInfo->TimingV[ 0 ].data[ i ] ;
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 6 ) , data ) ;
+ }
+
+ for( i = 0x02 ; i <= 0x03 ; i++ )
+ {
+ data = pVBInfo->TimingV[ 0 ].data[ i ] ;
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x0e ) , data ) ;
+ }
+
+ for( i = 0x04 ; i <= 0x05 ; i++ )
+ {
+ data = pVBInfo->TimingV[ 0 ].data[ i ] ;
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 0x11 ) , data ) ;
+ }
+
+ j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x0a ) ;
+ j &= 0xC0 ;
+ data = pVBInfo->TimingV[ 0 ].data[ 6 ] ;
+ data &= 0x3F ;
+ data |= j ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0a , data ) ;
+
+ data = pVBInfo->TimingV[ 0 ].data[ 6 ] ;
+ data &= 0x80 ;
+ data = data >> 2 ;
+
+ if ( ModeNo <= 0x13 )
+ i = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ else
+ i = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+
+ i &= DoubleScanMode ;
+ if ( i )
+ data |= 0x80 ;
+
+ j = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x09 ) ;
+ j &= 0x5F ;
+ data |= j ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x09 , data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetXG21CRTC */
+/* Input : Stand or enhance CRTC table */
+/* Output : Fill CRT Hsync/Vsync to SR2E/SR2F/SR30/SR33/SR34/SR3F */
+/* Description : Set LCD timing */
+/* --------------------------------------------------------------------- */
+void XGI_SetXG21CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ;
+ USHORT Temp1, Temp2, Temp3 ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ;
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 4 ] ; /* CR04 HRS */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E [7:0]->HRS */
+ Tempbx = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 5 ] ; /* Tempbx: CR05 HRE */
+ Tempbx &= 0x1F ; /* Tempbx: HRE[4:0] */
+ Tempcx = Tempax ;
+ Tempcx &= 0xE0 ; /* Tempcx: HRS[7:5] */
+ Tempdx = Tempcx | Tempbx ; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
+ if ( Tempbx < ( Tempax & 0x1F ) ) /* IF HRE < HRS */
+ Tempdx |= 0x20 ; /* Tempdx: HRE = HRE + 0x20 */
+ Tempdx <<= 2 ; /* Tempdx << 2 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempdx ) ; /* SR2F [7:2]->HRE */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ;
+
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 16 ] ; /* Tempax: CR16 VRS */
+ Tempbx = Tempax ; /* Tempbx=Tempax */
+ Tempax &= 0x01 ; /* Tempax: VRS[0] */
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x33 , Tempax ) ; /* SR33[0]->VRS */
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ; /* Tempax: CR7 VRS */
+ Tempdx = Tempbx >> 1 ; /* Tempdx: VRS[7:1] */
+ Tempcx = Tempax & 0x04 ; /* Tempcx: CR7[2] */
+ Tempcx <<= 5 ; /* Tempcx[7]: VRS[8] */
+ Tempdx |= Tempcx ; /* Tempdx: VRS[8:1] */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempdx ) ; /* SR34[7:0]: VRS[8:1] */
+
+ Temp1 = Tempcx << 1 ; /* Temp1[8]: VRS[8] UCHAR -> USHORT */
+ Temp1 |= Tempbx ; /* Temp1[8:0]: VRS[8:0] */
+ Tempax &= 0x80 ; /* Tempax[7]: CR7[7] */
+ Temp2 = Tempax << 2 ; /* Temp2[9]: VRS[9] */
+ Temp1 |= Temp2 ; /* Temp1[9:0]: VRS[9:0] */
+
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 17 ] ; /* CR16 VRE */
+ Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */
+ Temp2 = Temp1 & 0x3F0 ; /* Temp2[9:4]: VRS[9:4] */
+ Temp2 |= Tempax ; /* Temp2[9:0]: VRE[9:0] */
+ Temp3 = Temp1 & 0x0F ; /* Temp3[3:0]: VRS[3:0] */
+ if ( Tempax < Temp3 ) /* VRE[3:0]<VRS[3:0] */
+ Temp2 |= 0x10 ; /* Temp2: VRE + 0x10 */
+ Temp2 &= 0xFF ; /* Temp2[7:0]: VRE[7:0] */
+ Tempax = (UCHAR)Temp2 ; /* Tempax[7:0]: VRE[7:0] */
+ Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */
+ Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */
+ Temp1 >>= 9 ; /* [10:9]->[1:0] */
+ Tempbx = (UCHAR)Temp1 ; /* Tempbx[1:0]: VRS[10:9] */
+ Tempax |= Tempbx ; /* VRE[5:0]VRS[10:9] */
+ Tempax &= 0x7F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */
+ }
+ else
+ {
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */
+ Tempcx = Tempax ; /* Tempcx: HRS */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E[7:0]->HRS */
+
+ Tempdx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SRB */
+ Tempdx &= 0xC0 ; /* Tempdx[7:6]: SRB[7:6] */
+ Temp1 = Tempdx ; /* Temp1[7:6]: HRS[9:8] */
+ Temp1 <<= 2 ; /* Temp1[9:8]: HRS[9:8] */
+ Temp1 |= Tempax ; /* Temp1[9:0]: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 4 ] ; /* CR5 HRE */
+ Tempax &= 0x1F ; /* Tempax[4:0]: HRE[4:0] */
+
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 6 ] ; /* SRC */
+ Tempbx &= 0x04 ; /* Tempbx[2]: HRE[5] */
+ Tempbx <<= 3 ; /* Tempbx[5]: HRE[5] */
+ Tempax |= Tempbx ; /* Tempax[5:0]: HRE[5:0] */
+
+ Temp2 = Temp1 & 0x3C0 ; /* Temp2[9:6]: HRS[9:6] */
+ Temp2 |= Tempax ; /* Temp2[9:0]: HRE[9:0] */
+
+ Tempcx &= 0x3F ; /* Tempcx[5:0]: HRS[5:0] */
+ if( Tempax < Tempcx ) /* HRE < HRS */
+ Temp2 |= 0x40 ; /* Temp2 + 0x40 */
+
+ Temp2 &= 0xFF ;
+ Tempax = (UCHAR)Temp2 ; /* Tempax: HRE[7:0] */
+ Tempax <<= 2 ; /* Tempax[7:2]: HRE[5:0] */
+ Tempdx >>= 6 ; /* Tempdx[7:6]->[1:0] HRS[9:8] */
+ Tempax |= Tempdx ; /* HRE[5:0]HRS[9:8] */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempax ) ; /* SR2F D[7:2]->HRE, D[1:0]->HRS */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ;
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 10 ] ; /* CR10 VRS */
+ Tempbx = Tempax ; /* Tempbx: VRS */
+ Tempax &= 0x01 ; /* Tempax[0]: VRS[0] */
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x33 , Tempax ) ; /* SR33[0]->VRS[0] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 9 ] ; /* CR7[2][7] VRE */
+ Tempcx = Tempbx >> 1 ; /* Tempcx[6:0]: VRS[7:1] */
+ Tempdx = Tempax & 0x04 ; /* Tempdx[2]: CR7[2] */
+ Tempdx <<= 5 ; /* Tempdx[7]: VRS[8] */
+ Tempcx |= Tempdx ; /* Tempcx[7:0]: VRS[8:1] */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempcx ) ; /* SR34[8:1]->VRS */
+
+ Temp1 = Tempdx ; /* Temp1[7]: Tempdx[7] */
+ Temp1 <<= 1 ; /* Temp1[8]: VRS[8] */
+ Temp1 |= Tempbx ; /* Temp1[8:0]: VRS[8:0] */
+ Tempax &= 0x80 ;
+ Temp2 = Tempax << 2 ; /* Temp2[9]: VRS[9] */
+ Temp1 |= Temp2 ; /* Temp1[9:0]: VRS[9:0] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempax: SRA */
+ Tempax &= 0x08 ; /* Tempax[3]: VRS[3] */
+ Temp2 = Tempax ;
+ Temp2 <<= 7 ; /* Temp2[10]: VRS[10] */
+ Temp1 |= Temp2 ; /* Temp1[10:0]: VRS[10:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 11 ] ; /* Tempax: CR11 VRE */
+ Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempbx: SRA */
+ Tempbx &= 0x20 ; /* Tempbx[5]: VRE[5] */
+ Tempbx >>= 1 ; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx ; /* Tempax[4:0]: VRE[4:0] */
+ Temp2 = Temp1 & 0x7E0 ; /* Temp2[10:5]: VRS[10:5] */
+ Temp2 |= Tempax ; /* Temp2[10:5]: VRE[10:5] */
+
+ Temp3 = Temp1 & 0x1F ; /* Temp3[4:0]: VRS[4:0] */
+ if ( Tempax < Temp3 ) /* VRE < VRS */
+ Temp2 |= 0x20 ; /* VRE + 0x20 */
+
+ Temp2 &= 0xFF ;
+ Tempax = (UCHAR)Temp2 ; /* Tempax: VRE[7:0] */
+ Tempax <<= 2 ; /* Tempax[7:0]; VRE[5:0]00 */
+ Temp1 &= 0x600 ; /* Temp1[10:9]: VRS[10:9] */
+ Temp1 >>= 9 ; /* Temp1[1:0]: VRS[10:9] */
+ Tempbx = (UCHAR)Temp1 ;
+ Tempax |= Tempbx ; /* Tempax[7:0]: VRE[5:0]VRS[10:9] */
+ Tempax &= 0x7F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , Tempax ) ; /* SR3F D[7:2]->VRE D[1:0]->VRS */
+ }
+}
+
+void XGI_SetXG27CRTC(USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT StandTableIndex, index, Tempax, Tempbx, Tempcx, Tempdx ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ;
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 4 ] ; /* CR04 HRS */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E [7:0]->HRS */
+ Tempbx = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 5 ] ; /* Tempbx: CR05 HRE */
+ Tempbx &= 0x1F ; /* Tempbx: HRE[4:0] */
+ Tempcx = Tempax ;
+ Tempcx &= 0xE0 ; /* Tempcx: HRS[7:5] */
+ Tempdx = Tempcx | Tempbx ; /* Tempdx(HRE): HRS[7:5]HRE[4:0] */
+ if ( Tempbx < ( Tempax & 0x1F ) ) /* IF HRE < HRS */
+ Tempdx |= 0x20 ; /* Tempdx: HRE = HRE + 0x20 */
+ Tempdx <<= 2 ; /* Tempdx << 2 */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempdx ) ; /* SR2F [7:2]->HRE */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ;
+
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 16 ] ; /* Tempax: CR10 VRS */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempax ) ; /* SR34[7:0]->VRS */
+ Tempcx = Tempax ; /* Tempcx=Tempax=VRS[7:0] */
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ; /* Tempax[7][2]: CR7[7][2] VRS[9][8] */
+ Tempbx = Tempax ; /* Tempbx=CR07 */
+ Tempax &= 0x04 ; /* Tempax[2]: CR07[2] VRS[8] */
+ Tempax >>= 2;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x01, Tempax ) ; /* SR35 D[0]->VRS D[8] */
+ Tempcx |= (Tempax << 8) ; /* Tempcx[8] |= VRS[8] */
+ Tempcx |= (Tempbx & 0x80)<<2; /* Tempcx[9] |= VRS[9] */
+
+
+ Tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 17 ] ; /* CR11 VRE */
+ Tempax &= 0x0F ; /* Tempax: VRE[3:0] */
+ Tempbx = Tempcx ; /* Tempbx=Tempcx=VRS[9:0] */
+ Tempbx &= 0x3F0 ; /* Tempbx[9:4]: VRS[9:4] */
+ Tempbx |= Tempax ; /* Tempbx[9:0]: VRE[9:0] */
+ if ( Tempax <= (Tempcx & 0x0F) ) /* VRE[3:0]<=VRS[3:0] */
+ Tempbx |= 0x10 ; /* Tempbx: VRE + 0x10 */
+ Tempax = (UCHAR)Tempbx & 0xFF; /* Tempax[7:0]: VRE[7:0] */
+ Tempax <<= 2 ; /* Tempax << 2: VRE[5:0] */
+ Tempcx = (Tempcx&0x600)>>8; /* Tempcx VRS[10:9] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC, Tempax ) ; /* SR3F D[7:2]->VRE D[5:0] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x06, Tempcx ) ; /* SR35 D[2:1]->VRS[10:9] */
+ }
+ else
+ {
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */
+ Tempbx = Tempax ; /* Tempbx: HRS[7:0] */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , Tempax ) ; /* SR2E[7:0]->HRS */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SR0B */
+ Tempax &= 0xC0 ; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempbx |= (Tempax << 2); /* Tempbx: HRS[9:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 4 ] ; /* CR5 HRE */
+ Tempax &= 0x1F ; /* Tempax[4:0]: HRE[4:0] */
+ Tempcx = Tempax ; /* Tempcx: HRE[4:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 6 ] ; /* SRC */
+ Tempax &= 0x04 ; /* Tempax[2]: HRE[5] */
+ Tempax <<= 3 ; /* Tempax[5]: HRE[5] */
+ Tempcx |= Tempax ; /* Tempcx[5:0]: HRE[5:0] */
+
+ Tempbx = Tempbx & 0x3C0 ; /* Tempbx[9:6]: HRS[9:6] */
+ Tempbx |= Tempcx ; /* Tempbx: HRS[9:6]HRE[5:0] */
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 3 ] ; /* Tempax: CR4 HRS */
+ Tempax &= 0x3F ; /* Tempax: HRS[5:0] */
+ if( Tempcx <= Tempax ) /* HRE[5:0] < HRS[5:0] */
+ Tempbx += 0x40 ; /* Tempbx= Tempbx + 0x40 : HRE[9:0]*/
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 5 ] ; /* SR0B */
+ Tempax &= 0xC0 ; /* Tempax[7:6]: SR0B[7:6]: HRS[9:8]*/
+ Tempax >>= 6; /* Tempax[1:0]: HRS[9:8]*/
+ Tempax |= ((Tempbx << 2) & 0xFF); /* Tempax[7:2]: HRE[5:0] */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , Tempax ) ; /* SR2F [7:2][1:0]: HRE[5:0]HRS[9:8] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , 0xE3 , 00 ) ;
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 10 ] ; /* CR10 VRS */
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , Tempax ) ; /* SR34[7:0]->VRS[7:0] */
+
+ Tempcx = Tempax ; /* Tempcx <= VRS[7:0] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 9 ] ; /* CR7[7][2] VRS[9][8] */
+ Tempbx = Tempax ; /* Tempbx <= CR07[7:0] */
+ Tempax = Tempax & 0x04 ; /* Tempax[2]: CR7[2]: VRS[8] */
+ Tempax >>= 2 ; /* Tempax[0]: VRS[8] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x01 , Tempax ) ; /* SR35[0]: VRS[8] */
+ Tempcx |= (Tempax<<8) ; /* Tempcx <= VRS[8:0] */
+ Tempcx |= ((Tempbx&0x80)<<2) ; /* Tempcx <= VRS[9:0] */
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempax: SR0A */
+ Tempax &= 0x08; /* SR0A[3] VRS[10] */
+ Tempcx |= (Tempax<<7) ; /* Tempcx <= VRS[10:0] */
+
+
+ Tempax = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 11 ] ; /* Tempax: CR11 VRE */
+ Tempax &= 0x0F ; /* Tempax[3:0]: VRE[3:0] */
+ Tempbx = pVBInfo->XGINEWUB_CRT1Table[ index ].CR[ 14 ] ; /* Tempbx: SR0A */
+ Tempbx &= 0x20 ; /* Tempbx[5]: SR0A[5]: VRE[4] */
+ Tempbx >>= 1 ; /* Tempbx[4]: VRE[4] */
+ Tempax |= Tempbx ; /* Tempax[4:0]: VRE[4:0] */
+ Tempbx = Tempcx ; /* Tempbx: VRS[10:0] */
+ Tempbx &= 0x7E0 ; /* Tempbx[10:5]: VRS[10:5] */
+ Tempbx |= Tempax ; /* Tempbx: VRS[10:5]VRE[4:0] */
+
+ if ( Tempbx <= Tempcx ) /* VRE <= VRS */
+ Tempbx |= 0x20 ; /* VRE + 0x20 */
+
+ Tempax = (Tempbx<<2) & 0xFF ; /* Tempax: Tempax[7:0]; VRE[5:0]00 */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , Tempax ) ; /* SR3F[7:2]:VRE[5:0] */
+ Tempax = Tempcx >> 8;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x07 , Tempax ) ; /* SR35[2:0]:VRS[10:8] */
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetXG21LCD */
+/* Input : */
+/* Output : FCLK duty cycle, FCLK delay compensation */
+/* Description : All values set zero */
+/* --------------------------------------------------------------------- */
+void XGI_SetXG21LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo)
+{
+ USHORT Data , Temp , b3CC ;
+ USHORT XGI_P3cc ;
+
+ XGI_P3cc = pVBInfo->P3cc ;
+
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x00 ) ;
+ if ( ((*pVBInfo->pDVOSetting)&0xC0) == 0xC0 )
+ {
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , *pVBInfo->pCR2E ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , *pVBInfo->pCR2F ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , *pVBInfo->pCR46 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , *pVBInfo->pCR47 ) ;
+ }
+
+ Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ;
+
+ if ( Temp & 0x01 )
+ {
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x06 , 0x40 ) ; /* 18 bits FP */
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x09 , 0x40 ) ;
+ }
+
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x01 ) ; /* Negative blank polarity */
+
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x30 , ~0x20 ) ;
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x35 , ~0x80 ) ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ;
+ if ( b3CC & 0x40 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
+ if ( b3CC & 0x80 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */
+ }
+ else
+ {
+ Data = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+ if ( Data & 0x4000 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
+ if ( Data & 0x8000 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */
+ }
+}
+
+void XGI_SetXG27LCD(PVB_DEVICE_INFO pVBInfo,USHORT RefreshRateTableIndex,USHORT ModeNo)
+{
+ USHORT Data , Temp , b3CC ;
+ USHORT XGI_P3cc ;
+
+ XGI_P3cc = pVBInfo->P3cc ;
+
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x00 ) ;
+
+ Temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ;
+ if ( ( Temp & 0x03 ) == 0 ) /* dual 12 */
+ {
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , 0x13 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , 0x13 ) ;
+ }
+
+ if ( ((*pVBInfo->pDVOSetting)&0xC0) == 0xC0 )
+ {
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2E , *pVBInfo->pCR2E ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2F , *pVBInfo->pCR2F ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x46 , *pVBInfo->pCR46 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x47 , *pVBInfo->pCR47 ) ;
+ }
+
+ XGI_SetXG27FPBits(pVBInfo);
+
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x01 ) ; /* Negative blank polarity */
+
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x30 , ~0x20 ) ; /* Hsync polarity */
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x35 , ~0x80 ) ; /* Vsync polarity */
+
+ if ( ModeNo <= 0x13 )
+ {
+ b3CC = (UCHAR) XGINew_GetReg2( XGI_P3cc ) ;
+ if ( b3CC & 0x40 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
+ if ( b3CC & 0x80 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */
+ }
+ else
+ {
+ Data = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+ if ( Data & 0x4000 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x30 , 0x20 ) ; /* Hsync polarity */
+ if ( Data & 0x8000 )
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x35 , 0x80 ) ; /* Vsync polarity */
+ }
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_UpdateXG21CRTC */
+/* Input : */
+/* Output : CRT1 CRTC */
+/* Description : Modify CRT1 Hsync/Vsync to fix LCD mode timing */
+/* --------------------------------------------------------------------- */
+void XGI_UpdateXG21CRTC( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo , USHORT RefreshRateTableIndex )
+{
+ int i , index = -1;
+
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x11 , 0x7F ) ; /* Unlock CR0~7 */
+ if ( ModeNo <= 0x13 )
+ {
+ for( i = 0 ; i < 12 ; i++ )
+ {
+ if ( ModeNo == pVBInfo->UpdateCRT1[ i ].ModeID )
+ index = i ;
+ }
+ }
+ else
+ {
+ if ( ModeNo == 0x2E && ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC == RES640x480x60 ) )
+ index = 12 ;
+ else if ( ModeNo == 0x2E && ( pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC == RES640x480x72 ) )
+ index = 13 ;
+ else if ( ModeNo == 0x2F )
+ index = 14 ;
+ else if ( ModeNo == 0x50 )
+ index = 15 ;
+ else if ( ModeNo == 0x59 )
+ index = 16 ;
+ }
+
+ if( index != -1 )
+ {
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x02 , pVBInfo->UpdateCRT1[ index ].CR02 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x03 , pVBInfo->UpdateCRT1[ index ].CR03 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , pVBInfo->UpdateCRT1[ index ].CR15 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , pVBInfo->UpdateCRT1[ index ].CR16 ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1DE */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1DE( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo,USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT resindex ,
+ tempax ,
+ tempbx ,
+ tempcx ,
+ temp ,
+ modeflag ;
+
+ UCHAR data ;
+
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ tempax = pVBInfo->StResInfo[ resindex ].HTotal ;
+ tempbx = pVBInfo->StResInfo[ resindex ].VTotal ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ tempax = pVBInfo->ModeResInfo[ resindex ].HTotal ;
+ tempbx = pVBInfo->ModeResInfo[ resindex ].VTotal ;
+ }
+
+ if ( modeflag & HalfDCLK )
+ tempax = tempax >> 1 ;
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( modeflag & HalfDCLK )
+ tempax = tempax << 1 ;
+
+ temp = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+
+ if ( temp & InterlaceMode )
+ tempbx = tempbx >> 1 ;
+
+ if ( modeflag & DoubleScanMode )
+ tempbx = tempbx << 1 ;
+ }
+
+ tempcx = 8 ;
+
+ /* if ( !( modeflag & Charx8Dot ) ) */
+ /* tempcx = 9 ; */
+
+ tempax /= tempcx ;
+ tempax -= 1 ;
+ tempbx -= 1 ;
+ tempcx = tempax ;
+ temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ data = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ data &= 0x7F ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , data ) ; /* Unlock CRTC */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x01 , ( USHORT )( tempcx & 0xff ) ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x0b , ~0x0c , ( USHORT )( ( tempcx & 0x0ff00 ) >> 10 ) ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x12 , ( USHORT )( tempbx & 0xff ) ) ;
+ tempax = 0 ;
+ tempbx = tempbx >> 8 ;
+
+ if ( tempbx & 0x01 )
+ tempax |= 0x02 ;
+
+ if ( tempbx & 0x02 )
+ tempax |= 0x40 ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x42 , tempax ) ;
+ data =( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x07 ) ;
+ data &= 0xFF ;
+ tempax = 0 ;
+
+ if ( tempbx & 0x04 )
+ tempax |= 0x02 ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 ,0x0a , ~0x02 , tempax ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetResInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetResInfo(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT resindex ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ resindex = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */
+ }
+ else
+ {
+ resindex = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */
+ }
+ return( resindex ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1Offset */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1Offset( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp ,
+ ah ,
+ al ,
+ temp2 ,
+ i ,
+ DisplayUnit ;
+
+ /* GetOffset */
+ temp = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeInfo ;
+ temp = temp >> 8 ;
+ temp = pVBInfo->ScreenOffset[ temp ] ;
+
+ temp2 = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+ temp2 &= InterlaceMode ;
+
+ if ( temp2 )
+ temp = temp << 1;
+
+ temp2 = pVBInfo->ModeType - ModeEGA ;
+
+ switch( temp2 )
+ {
+ case 0:
+ temp2 = 1 ;
+ break ;
+ case 1:
+ temp2 = 2 ;
+ break ;
+ case 2:
+ temp2 = 4 ;
+ break ;
+ case 3:
+ temp2 = 4 ;
+ break ;
+ case 4:
+ temp2 = 6 ;
+ break;
+ case 5:
+ temp2 = 8 ;
+ break ;
+ default:
+ break ;
+ }
+
+ if ( ( ModeNo >= 0x26 ) && ( ModeNo <= 0x28 ) )
+ temp = temp * temp2 + temp2 / 2 ;
+ else
+ temp *= temp2 ;
+
+ /* SetOffset */
+ DisplayUnit = temp ;
+ temp2 = temp ;
+ temp = temp >> 8 ; /* ah */
+ temp &= 0x0F ;
+ i = XGINew_GetReg1( pVBInfo->P3c4 , 0x0E ) ;
+ i &= 0xF0 ;
+ i |= temp ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , i ) ;
+
+ temp =( UCHAR )temp2 ;
+ temp &= 0xFF ; /* al */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x13 , temp ) ;
+
+ /* SetDisplayUnit */
+ temp2 = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+ temp2 &= InterlaceMode ;
+ if ( temp2 )
+ DisplayUnit >>= 1 ;
+
+ DisplayUnit = DisplayUnit << 5 ;
+ ah = ( DisplayUnit & 0xff00 ) >> 8 ;
+ al = DisplayUnit & 0x00ff ;
+ if ( al == 0 )
+ ah += 1 ;
+ else
+ ah += 2 ;
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ if ( ( ModeNo == 0x4A ) | (ModeNo == 0x49 ) )
+ ah -= 1 ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x10 , ah ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1VCLK */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1VCLK( USHORT ModeNo , USHORT ModeIdIndex ,
+ PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR index , data ;
+ USHORT vclkindex ;
+
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ index ].SR2B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ index ].SR2C ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ;
+ }
+ else if ( ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) && ( pVBInfo->VBInfo & SetCRT2ToLCDA ) )
+ {
+ vclkindex = XGI_GetVCLK2Ptr( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ;
+ data = pVBInfo->VBVCLKData[ vclkindex ].Part4_A ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , data ) ;
+ data = pVBInfo->VBVCLKData[ vclkindex ].Part4_B ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , data ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ;
+ }
+ else
+ {
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) & 0xCF ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , data ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->VCLKData[ index ].SR2B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->VCLKData[ index ].SR2C ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2D , 0x01 ) ;
+ }
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ {
+ if ( pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag & HalfDCLK )
+ {
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x2B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , data ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x2C ) ;
+ index = data ;
+ index &= 0xE0 ;
+ data &= 0x1F ;
+ data = data << 1 ;
+ data += 1 ;
+ data |= index ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , data ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1FIFO */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1FIFO( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT data ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3D ) ;
+ data &= 0xfe ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3D , data ) ; /* diable auto-threshold */
+
+ if ( ModeNo > 0x13 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0x34 ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ;
+ data &= 0xC0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data | 0x30) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x3D ) ;
+ data |= 0x01 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3D , data ) ;
+ }
+ else
+ {
+ if (HwDeviceExtension->jChipType == XG27)
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0x0E ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ;
+ data &= 0xC0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data | 0x20 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x08 , 0xAE ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x09 ) ;
+ data &= 0xF0 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x09 , data ) ;
+ }
+ }
+
+ if (HwDeviceExtension->jChipType == XG21)
+ {
+ XGI_SetXG21FPBits(pVBInfo); /* Fix SR9[7:6] can't read back */
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT1ModeRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT1ModeRegs( PXGI_HW_DEVICE_INFO HwDeviceExtension ,
+ USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT data ,
+ data2 ,
+ data3 ,
+ infoflag = 0 ,
+ modeflag ,
+ resindex ,
+ xres ;
+
+ if ( ModeNo > 0x13 )
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+ }
+ else
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */
+
+ if ( XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) & 0x01 )
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1F , 0x3F , 0x00 ) ;
+
+ if ( ModeNo > 0x13 )
+ data = infoflag ;
+ else
+ data = 0 ;
+
+ data2 = 0 ;
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( pVBInfo->ModeType > 0x02 )
+ {
+ data2 |= 0x02 ;
+ data3 = pVBInfo->ModeType - ModeVGA ;
+ data3 = data3 << 2 ;
+ data2 |= data3 ;
+ }
+ }
+
+ data &= InterlaceMode ;
+
+ if ( data )
+ data2 |= 0x20 ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0x3F , data2 ) ;
+ /* XGINew_SetReg1(pVBInfo->P3c4,0x06,data2); */
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( ModeNo <= 0x13 )
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ else
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+
+ data = 0x0000 ;
+ if ( infoflag & InterlaceMode )
+ {
+ if ( xres == 1024 )
+ data = 0x0035 ;
+ else if ( xres == 1280 )
+ data = 0x0048 ;
+ }
+
+ data2 = data & 0x00FF ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x19 , 0xFF , data2 ) ;
+ data2 = ( data & 0xFF00 ) >> 8 ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x19 , 0xFC , data2 ) ;
+
+ if( modeflag & HalfDCLK )
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xF7 , 0x08 ) ;
+
+ data2 = 0 ;
+
+ if ( modeflag & LineCompareOff )
+ data2 |= 0x08 ;
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( pVBInfo->ModeType == ModeEGA )
+ data2 |= 0x40 ;
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0F , ~0x48 , data2 ) ;
+ data = 0x60 ;
+ if ( pVBInfo->ModeType != ModeText )
+ {
+ data = data ^ 0x60 ;
+ if ( pVBInfo->ModeType != ModeEGA )
+ {
+ data = data ^ 0xA0 ;
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x21 , 0x1F , data ) ;
+
+ XGI_SetVCLKState( HwDeviceExtension , ModeNo , RefreshRateTableIndex, pVBInfo) ;
+
+ /* if(modeflag&HalfDCLK)//030305 fix lowresolution bug */
+ /* if(XGINew_IF_DEF_NEW_LOWRES) */
+ /* XGI_VesaLowResolution(ModeNo,ModeIdIndex);//030305 fix lowresolution bug */
+
+ data=XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ;
+
+ if (HwDeviceExtension->jChipType == XG27 )
+ {
+ if ( data & 0x40 )
+ data = 0x2c ;
+ else
+ data = 0x6c ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ;
+ XGINew_SetRegOR( pVBInfo->P3d4 , 0x51 , 0x10 ) ;
+ }
+ else
+ if (HwDeviceExtension->jChipType >= XG20 )
+ {
+ if ( data & 0x40 )
+ data = 0x33 ;
+ else
+ data = 0x73 ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x51 , 0x02 ) ;
+ }
+ else
+ {
+ if ( data & 0x40 )
+ data = 0x2c ;
+ else
+ data = 0x6c ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x52 , data ) ;
+ }
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetVCLKState */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetVCLKState( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo , USHORT RefreshRateTableIndex,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT data ,
+ data2 = 0 ;
+ SHORT VCLK ;
+
+ UCHAR index ;
+
+ if ( ModeNo <= 0x13 )
+ VCLK = 0 ;
+ else
+ {
+ index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ;
+ index &= IndexMask ;
+ VCLK = pVBInfo->VCLKData[ index ].CLOCK ;
+ }
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) ;
+ data &= 0xf3 ;
+ if ( VCLK >= 200 )
+ data |= 0x0c ; /* VCLK > 200 */
+
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ data &= ~0x04 ; /* 2 pixel mode */
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , data ) ;
+
+ if ( HwDeviceExtension->jChipType < XG20 )
+ {
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ;
+ data &= 0xE7 ;
+ if ( VCLK < 200 )
+ data |= 0x10 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , data ) ;
+ }
+
+/* Jong for Adavantech LCD ripple issue
+ if ( ( VCLK >= 0 ) && ( VCLK < 135 ) )
+ data2 = 0x03 ;
+ else if ( ( VCLK >= 135 ) && ( VCLK < 160 ) )
+ data2 = 0x02 ;
+ else if ( ( VCLK >= 160 ) && ( VCLK < 260 ) )
+ data2 = 0x01 ;
+ else if ( VCLK > 260 )
+ data2 = 0x00 ;
+*/
+ data2 = 0x00 ;
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x07 , 0xFC , data2 ) ;
+ if (HwDeviceExtension->jChipType >= XG27 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x40 , 0xFC , data2&0x03 ) ;
+ }
+
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_VesaLowResolution */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+/*void XGI_VesaLowResolution( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT modeflag;
+
+ if ( ModeNo > 0x13 )
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ else
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( modeflag & DoubleScanMode )
+ {
+ if ( modeflag & HalfDCLK )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xf7 , 0x00 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0x7f , 0x00 ) ;
+ return ;
+ }
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0xff , 0x80 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xf7 , 0x00 ) ;
+ return ;
+ }
+ }
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0f , 0x7f , 0x00 ) ;
+}
+*/
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_LoadDAC */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_LoadDAC( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT data , data2 , time ,
+ i , j , k , m , n , o ,
+ si , di , bx , dl , al , ah , dh ,
+ *table = NULL ;
+
+ if ( ModeNo <= 0x13 )
+ data = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ else
+ data = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+
+ data &= DACInfoFlag ;
+ time = 64 ;
+
+ if ( data == 0x00 )
+ table = XGINew_MDA_DAC ;
+ else if ( data == 0x08 )
+ table = XGINew_CGA_DAC ;
+ else if ( data == 0x10 )
+ table = XGINew_EGA_DAC ;
+ else if ( data == 0x18 )
+ {
+ time = 256 ;
+ table = XGINew_VGA_DAC ;
+ }
+
+ if ( time == 256 )
+ j = 16 ;
+ else
+ j = time ;
+
+ XGINew_SetReg3( pVBInfo->P3c6 , 0xFF ) ;
+ XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ;
+
+ for( i = 0 ; i < j ; i++ )
+ {
+ data = table[ i ] ;
+
+ for( k = 0 ; k < 3 ; k++ )
+ {
+ data2 = 0 ;
+
+ if ( data & 0x01 )
+ data2 = 0x2A ;
+
+ if ( data & 0x02 )
+ data2 += 0x15 ;
+
+ XGINew_SetReg3( pVBInfo->P3c9 , data2 ) ;
+ data = data >> 2 ;
+ }
+ }
+
+ if ( time == 256 )
+ {
+ for( i = 16 ; i < 32 ; i++ )
+ {
+ data = table[ i ] ;
+
+ for( k = 0 ; k < 3 ; k++ )
+ XGINew_SetReg3( pVBInfo->P3c9 , data ) ;
+ }
+
+ si = 32 ;
+
+ for( m = 0 ; m < 9 ; m++ )
+ {
+ di = si ;
+ bx = si + 0x04 ;
+ dl = 0 ;
+
+ for( n = 0 ; n < 3 ; n++ )
+ {
+ for( o = 0 ; o < 5 ; o++ )
+ {
+ dh = table[ si ] ;
+ ah = table[ di ] ;
+ al = table[ bx ] ;
+ si++ ;
+ XGI_WriteDAC( dl , ah , al , dh, pVBInfo ) ;
+ }
+
+ si -= 2 ;
+
+ for( o = 0 ; o < 3 ; o++ )
+ {
+ dh = table[ bx ] ;
+ ah = table[ di ] ;
+ al = table[ si ] ;
+ si-- ;
+ XGI_WriteDAC( dl , ah , al , dh, pVBInfo ) ;
+ }
+
+ dl++ ;
+ }
+
+ si += 5 ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_WriteDAC */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_WriteDAC( USHORT dl , USHORT ah , USHORT al , USHORT dh,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp , bh , bl ;
+
+ bh = ah ;
+ bl = al ;
+
+ if ( dl != 0 )
+ {
+ temp = bh ;
+ bh = dh ;
+ dh = temp ;
+ if ( dl == 1 )
+ {
+ temp = bl ;
+ bl = dh ;
+ dh = temp ;
+ }
+ else
+ {
+ temp = bl ;
+ bl = bh ;
+ bh = temp ;
+ }
+ }
+ XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )dh ) ;
+ XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bh ) ;
+ XGINew_SetReg3( pVBInfo->P3c9 , ( USHORT )bl ) ;
+}
+
+#if 0
+/* --------------------------------------------------------------------- */
+/* Function : XGI_ClearBuffer */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_ClearBuffer( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo, PVB_DEVICE_INFO pVBInfo)
+{
+ PVOID VideoMemoryAddress = ( PVOID )HwDeviceExtension->pjVideoMemoryAddress ;
+ ULONG AdapterMemorySize = ( ULONG )HwDeviceExtension->ulVideoMemorySize ;
+ PUSHORT pBuffer ;
+#ifndef LINUX_XF86
+ int i ;
+#endif
+
+ if ( pVBInfo->ModeType >= ModeEGA )
+ {
+ if ( ModeNo > 0x13 )
+ {
+ AdapterMemorySize = 0x40000 ; /* clear 256k */
+ /* GetDRAMSize( HwDeviceExtension ) ; */
+ XGI_SetMemory( VideoMemoryAddress , AdapterMemorySize , 0 ) ;
+ }
+ else
+ {
+/*
+ pBuffer = VideoMemoryAddress ;
+ for( i = 0 ; i < 0x4000 ; i++ )
+ pBuffer[ i ] = 0x0000 ;
+*/
+ }
+ }
+ else
+ {
+ pBuffer = VideoMemoryAddress ;
+ if ( pVBInfo->ModeType < ModeCGA )
+ {
+/*
+ for ( i = 0 ; i < 0x4000 ; i++ )
+ pBuffer[ i ] = 0x0720 ;
+*/
+ }
+ else
+ XGI_SetMemory( VideoMemoryAddress , 0x8000 , 0 ) ;
+ }
+}
+
+#endif
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLCDAGroup */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLCDAGroup( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT RefreshRateTableIndex ;
+ /* USHORT temp ; */
+
+ /* pVBInfo->SelectCRT2Rate = 0 ; */
+
+ pVBInfo->SetFlag |= ProgrammingCRT2 ;
+ RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetLVDSResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetLVDSData( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo);
+ XGI_ModCRT1Regs( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetLVDSRegs( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetCRT2ECLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLVDSResInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetLVDSResInfo( USHORT ModeNo , USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT resindex , xres , yres , modeflag ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */
+ }
+
+
+ /* if ( ModeNo > 0x13 ) */
+ /* modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; */
+ /* else */
+ /* modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; */
+
+ if ( ModeNo <= 0x13 )
+ {
+ resindex = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */
+ }
+ else
+ {
+ resindex = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */
+ }
+
+ /* resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ; */
+
+ if ( ModeNo <= 0x13 )
+ {
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->StResInfo[ resindex ].VTotal ;
+ }
+ else
+ {
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->ModeResInfo[ resindex ].VTotal ;
+ }
+ if ( ModeNo > 0x13 )
+ {
+ if ( modeflag & HalfDCLK )
+ xres = xres << 1 ;
+
+ if ( modeflag & DoubleScanMode )
+ yres = yres << 1 ;
+ }
+ /* if ( modeflag & Charx8Dot ) */
+ /* { */
+
+ if ( xres == 720 )
+ xres = 640 ;
+
+ /* } */
+ pVBInfo->VGAHDE = xres ;
+ pVBInfo->HDE = xres ;
+ pVBInfo->VGAVDE = yres ;
+ pVBInfo->VDE = yres ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLVDSData */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetLVDSData( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ;
+ XGI330_LVDSDataStruct *LCDPtr = NULL ;
+ XGI330_CHTVDataStruct *TVPtr = NULL ;
+
+ tempbx = 2 ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ LCDPtr = ( XGI330_LVDSDataStruct * )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo) ;
+ pVBInfo->VGAHT = LCDPtr->VGAHT ;
+ pVBInfo->VGAVT = LCDPtr->VGAVT ;
+ pVBInfo->HT = LCDPtr->LCDHT ;
+ pVBInfo->VT = LCDPtr->LCDVT ;
+ }
+ if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ TVPtr = ( XGI330_CHTVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ pVBInfo->VGAHT = TVPtr->VGAHT ;
+ pVBInfo->VGAVT = TVPtr->VGAVT ;
+ pVBInfo->HT = TVPtr->LCDHT ;
+ pVBInfo->VT = TVPtr->LCDVT ;
+ }
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ if ( !( pVBInfo->LCDInfo & ( SetLCDtoNonExpanding | EnableScalingLCD ) ) )
+ {
+ if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) )
+ {
+ pVBInfo->HDE = 1024 ;
+ pVBInfo->VDE = 768 ;
+ }
+ else if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) )
+ {
+ pVBInfo->HDE = 1280 ;
+ pVBInfo->VDE = 1024 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1400x1050 )
+ {
+ pVBInfo->HDE = 1400 ;
+ pVBInfo->VDE = 1050 ;
+ }
+ else
+ {
+ pVBInfo->HDE = 1600 ;
+ pVBInfo->VDE = 1200 ;
+ }
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_ModCRT1Regs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_ModCRT1Regs( USHORT ModeNo , USHORT ModeIdIndex ,
+ USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR index ;
+ USHORT tempbx , i ;
+ XGI_LVDSCRT1HDataStruct *LCDPtr = NULL ;
+ XGI_LVDSCRT1VDataStruct *LCDPtr1 =NULL ;
+ /* XGI330_CHTVDataStruct *TVPtr = NULL ; */
+ XGI_CH7007TV_TimingHStruct *CH7007TV_TimingHPtr = NULL;
+ XGI_CH7007TV_TimingVStruct *CH7007TV_TimingVPtr = NULL;
+
+ if( ModeNo <= 0x13 )
+ index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ else
+ index = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+
+ index= index & IndexMask ;
+
+ if ( ( pVBInfo->IF_DEF_ScaleLCD == 0 ) || ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( !( pVBInfo->LCDInfo & EnableScalingLCD ) ) ) )
+ {
+ tempbx = 0 ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ LCDPtr = ( XGI_LVDSCRT1HDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+
+ for( i = 0 ; i < 8 ; i++ )
+ pVBInfo->TimingH[ 0 ].data[ i ] = LCDPtr[ 0 ].Reg[ i ] ;
+ }
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ CH7007TV_TimingHPtr = ( XGI_CH7007TV_TimingHStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+
+ for( i = 0 ; i < 8 ; i++ )
+ pVBInfo->TimingH[ 0 ].data[ i ] = CH7007TV_TimingHPtr[ 0 ].data[ i ] ;
+ }
+ }
+
+ /* if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ } */
+
+ XGI_SetCRT1Timing_H(pVBInfo,HwDeviceExtension) ;
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , CH7007TV_TimingHPtr[ 0 ].data[ 8 ] ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2F , CH7007TV_TimingHPtr[ 0 ].data[ 9 ] ) ;
+ }
+
+ tempbx = 1 ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ LCDPtr1 = ( XGI_LVDSCRT1VDataStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ for( i = 0 ; i < 7 ; i++ )
+ pVBInfo->TimingV[ 0 ].data[ i ] = LCDPtr1[ 0 ].Reg[ i ] ;
+ }
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ CH7007TV_TimingVPtr = ( XGI_CH7007TV_TimingVStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+
+ for( i = 0 ; i < 7 ; i++ )
+ pVBInfo->TimingV[ 0 ].data[ i ] = CH7007TV_TimingVPtr[ 0 ].data[ i ] ;
+ }
+ }
+ /* if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ TVPtr = ( XGI330_CHTVDataStruct *)XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ } */
+
+ XGI_SetCRT1Timing_V( ModeIdIndex , ModeNo , pVBInfo) ;
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x33 , ~0x01 , CH7007TV_TimingVPtr[ 0 ].data[ 7 ]&0x01 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , CH7007TV_TimingVPtr[ 0 ].data[8 ] ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x3F , CH7007TV_TimingVPtr[ 0 ].data[9 ] ) ;
+
+ }
+ }
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLVDSRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLVDSRegs( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx , tempax , tempcx , tempdx , push1 , push2 , modeflag ;
+ unsigned long temp , temp1 , temp2 , temp3 , push3 ;
+ XGI330_LCDDataDesStruct *LCDPtr = NULL ;
+ XGI330_LCDDataDesStruct2 *LCDPtr1 = NULL ;
+
+ if ( ModeNo > 0x13 )
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ else
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+
+ if ( !( pVBInfo->SetFlag & Win9xDOSMode ) )
+ {
+ if ( ( pVBInfo->IF_DEF_CH7017 == 0 ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) )
+ {
+ if ( pVBInfo->IF_DEF_OEMUtil == 1 )
+ {
+ tempbx = 8 ;
+ LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ }
+
+ if ( ( pVBInfo->IF_DEF_OEMUtil == 0 ) || ( LCDPtr == 0 ) )
+ {
+ tempbx = 3 ;
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ LCDPtr1 = ( XGI330_LCDDataDesStruct2 * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ else
+ LCDPtr = ( XGI330_LCDDataDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ }
+
+ XGI_GetLCDSync( &tempax , &tempbx ,pVBInfo) ;
+ push1 = tempbx ;
+ push2 = tempax ;
+
+ /* GetLCDResInfo */
+ if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) )
+ {
+ tempax = 1024 ;
+ tempbx = 768 ;
+ }
+ else if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) )
+ {
+ tempax = 1280 ;
+ tempbx = 1024 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1400x1050 )
+ {
+ tempax = 1400 ;
+ tempbx = 1050 ;
+ }
+ else
+ {
+ tempax = 1600 ;
+ tempbx = 1200 ;
+ }
+
+ if ( pVBInfo->LCDInfo & SetLCDtoNonExpanding )
+ {
+ pVBInfo->HDE=tempax;
+ pVBInfo->VDE=tempbx;
+ pVBInfo->VGAHDE=tempax;
+ pVBInfo->VGAVDE=tempbx;
+ }
+
+ if ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( pVBInfo->LCDInfo & EnableScalingLCD ) )
+ {
+ tempax=pVBInfo->HDE;
+ tempbx=pVBInfo->VDE;
+ }
+
+ tempax = pVBInfo->HT ;
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempbx = LCDPtr1->LCDHDES ;
+ else
+ tempbx = LCDPtr->LCDHDES ;
+
+ tempcx = pVBInfo->HDE ;
+ tempbx = tempbx & 0x0fff ;
+ tempcx += tempbx ;
+
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1A , tempbx & 0x07 ) ;
+
+ tempcx = tempcx >> 3 ;
+ tempbx = tempbx >> 3 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x16 , ( USHORT )( tempbx & 0xff ) ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x17 , ( USHORT )( tempcx & 0xff ) ) ;
+
+ tempax = pVBInfo->HT ;
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempbx = LCDPtr1->LCDHRS ;
+ else
+ tempbx = LCDPtr->LCDHRS ;
+
+ tempcx = push2 ;
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempcx = LCDPtr1->LCDHSync ;
+
+ tempcx += tempbx ;
+
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ tempax = tempbx & 0x07 ;
+ tempax = tempax >> 5 ;
+ tempcx = tempcx >> 3 ;
+ tempbx = tempbx >> 3 ;
+
+ tempcx &= 0x1f ;
+ tempax |= tempcx ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x15 , tempax ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x14 , ( USHORT )( tempbx & 0xff ) ) ;
+
+ tempax = pVBInfo->VT ;
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempbx = LCDPtr1->LCDVDES ;
+ else
+ tempbx = LCDPtr->LCDVDES ;
+ tempcx = pVBInfo->VDE ;
+
+ tempbx = tempbx & 0x0fff ;
+ tempcx += tempbx ;
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1b , ( USHORT )( tempbx & 0xff ) ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1c , ( USHORT )( tempcx & 0xff ) ) ;
+
+ tempbx = ( tempbx >> 8 ) & 0x07 ;
+ tempcx = ( tempcx >> 8 ) & 0x07 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1d , ( USHORT )( ( tempcx << 3 ) | tempbx ) ) ;
+
+ tempax = pVBInfo->VT ;
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempbx = LCDPtr1->LCDVRS ;
+ else
+ tempbx = LCDPtr->LCDVRS ;
+
+ /* tempbx = tempbx >> 4 ; */
+ tempcx = push1 ;
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempcx = LCDPtr1->LCDVSync ;
+
+ tempcx += tempbx ;
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x18 , ( USHORT )( tempbx & 0xff ) ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , ~0x0f , ( USHORT )( tempcx & 0x0f ) ) ;
+
+ tempax = ( ( tempbx >> 8 ) & 0x07 ) << 3 ;
+
+ tempbx = pVBInfo->VGAVDE ;
+ if ( tempbx != pVBInfo->VDE )
+ tempax |= 0x40 ;
+
+ if ( pVBInfo->LCDInfo & EnableLVDSDDA )
+ tempax |= 0x40 ;
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1a , 0x07 , tempax ) ;
+
+ tempcx = pVBInfo->VGAVT ;
+ tempbx = pVBInfo->VDE ;
+ tempax = pVBInfo->VGAVDE ;
+ tempcx -= tempax ;
+
+ temp = tempax ; /* 0430 ylshieh */
+ temp1 = ( temp << 18 ) / tempbx ;
+
+ tempdx = ( USHORT )( ( temp << 18 ) % tempbx ) ;
+
+ if ( tempdx != 0 )
+ temp1 += 1 ;
+
+ temp2 = temp1 ;
+ push3 = temp2 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x37 , ( USHORT )( temp2 & 0xff ) ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x36 , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ;
+
+ tempbx = ( USHORT )( temp2 >> 16 ) ;
+ tempax = tempbx & 0x03 ;
+
+ tempbx = pVBInfo->VGAVDE ;
+ if ( tempbx == pVBInfo->VDE )
+ tempax |= 0x04 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x35 , tempax ) ;
+
+ if ( pVBInfo->VBType & VB_XGI301C )
+ {
+ temp2 = push3 ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x3c , ( USHORT )( temp2 & 0xff ) ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x3b , ( USHORT )( ( temp2 >> 8 ) & 0xff ) ) ;
+ tempbx = ( USHORT )( temp2 >> 16 ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x3a , ~0xc0 , ( USHORT )( ( tempbx & 0xff ) << 6 ) ) ;
+
+ tempcx = pVBInfo->VGAVDE ;
+ if ( tempcx == pVBInfo->VDE )
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x30 , ~0x0c , 0x00 ) ;
+ else
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x30 , ~0x0c , 0x08 ) ;
+ }
+
+ tempcx = pVBInfo->VGAHDE ;
+ tempbx = pVBInfo->HDE ;
+
+ temp1 = tempcx << 16 ;
+
+ tempax = ( USHORT )( temp1 / tempbx ) ;
+
+ if ( ( tempbx & 0xffff ) == ( tempcx & 0xffff ) )
+ tempax = 65535 ;
+
+ temp3 = tempax ;
+ temp1 = pVBInfo->VGAHDE << 16 ;
+
+ temp1 /= temp3 ;
+ temp3 = temp3 << 16 ;
+ temp1 -= 1 ;
+
+ temp3 = ( temp3 & 0xffff0000 ) + ( temp1 & 0xffff ) ;
+
+ tempax = ( USHORT )( temp3 & 0xff ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1f , tempax ) ;
+
+ temp1 = pVBInfo->VGAVDE << 18 ;
+ temp1 = temp1 / push3 ;
+ tempbx = ( USHORT )( temp1 & 0xffff ) ;
+
+ if ( pVBInfo->LCDResInfo == Panel1024x768 )
+ tempbx -= 1 ;
+
+ tempax = ( ( tempbx >> 8 ) & 0xff ) << 3 ;
+ tempax |= ( USHORT )( ( temp3 >> 8 ) & 0x07 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x20 , ( USHORT )( tempax & 0xff ) ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x21 , ( USHORT )( tempbx & 0xff ) ) ;
+
+ temp3 = temp3 >> 16 ;
+
+ if ( modeflag & HalfDCLK )
+ temp3 = temp3 >> 1 ;
+
+ XGINew_SetReg1(pVBInfo->Part1Port , 0x22 , ( USHORT )( ( temp3 >> 8 ) & 0xff ) ) ;
+ XGINew_SetReg1(pVBInfo->Part1Port , 0x23 , ( USHORT )( temp3 & 0xff ) ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2ECLK */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT2ECLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR di_0 , di_1 , tempal ;
+ int i ;
+
+ tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetVCLKLen( tempal , &di_0 , &di_1, pVBInfo ) ;
+ XGI_GetLCDVCLKPtr( &di_0 , &di_1, pVBInfo ) ;
+
+ for( i = 0 ; i < 4 ; i++ )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x31 , ~0x30 , ( USHORT )( 0x10 * i ) ) ;
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2b , di_0 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2c , di_1 ) ;
+ }
+ else if ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) )
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2e , di_0 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2f , di_1 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2b , di_0 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2c , di_1 ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_UpdateModeInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_UpdateModeInfo( PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempcl ,
+ tempch ,
+ temp ,
+ tempbl ,
+ tempax ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempcl = 0 ;
+ tempch = 0 ;
+ temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ;
+
+ if ( !( temp & 0x20 ) )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ;
+ if ( temp & 0x80 )
+ {
+ if ( ( HwDeviceExtension->jChipType >= XG20 ) || ( HwDeviceExtension->jChipType >= XG40 ) )
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) ;
+ else
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x63 ) ;
+
+ if ( !( temp & 0x40 ) )
+ tempcl |= ActiveCRT1 ;
+ }
+ }
+
+ temp = XGINew_GetReg1( pVBInfo->Part1Port , 0x2e ) ;
+ temp &= 0x0f ;
+
+ if ( !( temp == 0x08 ) )
+ {
+ tempax = XGINew_GetReg1( pVBInfo->Part1Port , 0x13 ) ; /* Check ChannelA by Part1_13 [2003/10/03] */
+ if ( tempax & 0x04 )
+ tempcl = tempcl | ActiveLCD ;
+
+ temp &= 0x05 ;
+
+ if ( !( tempcl & ActiveLCD ) )
+ if ( temp == 0x01 )
+ tempcl |= ActiveCRT2 ;
+
+ if ( temp == 0x04 )
+ tempcl |= ActiveLCD ;
+
+ if ( temp == 0x05 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->Part2Port , 0x00 ) ;
+
+ if( !( temp & 0x08 ) )
+ tempch |= ActiveAVideo ;
+
+ if ( !( temp & 0x04 ) )
+ tempch |= ActiveSVideo ;
+
+ if ( temp & 0x02 )
+ tempch |= ActiveSCART ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( temp & 0x01 )
+ tempch |= ActiveHiTV ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ temp = XGINew_GetReg1( pVBInfo->Part2Port , 0x4d ) ;
+
+ if ( temp & 0x10 )
+ tempch |= ActiveYPbPr ;
+ }
+
+ if ( tempch != 0 )
+ tempcl |= ActiveTV ;
+ }
+ }
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x3d ) ;
+ if ( tempcl & ActiveLCD )
+ {
+ if ( ( pVBInfo->SetFlag & ReserveTVOption ) )
+ {
+ if ( temp & ActiveTV )
+ tempcl |= ActiveTV ;
+ }
+ }
+ temp = tempcl ;
+ tempbl = ~ModeSwitchStatus ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x3d , tempbl , temp ) ;
+
+ if ( !( pVBInfo->SetFlag & ReserveTVOption ) )
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x3e , tempch ) ;
+ }
+ else
+ {
+ return ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVGAType */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetVGAType( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ /*
+ if ( HwDeviceExtension->jChipType >= XG20 )
+ {
+ pVBInfo->Set_VGAType = XG20;
+ }
+ else if ( HwDeviceExtension->jChipType >= XG40 )
+ {
+ pVBInfo->Set_VGAType = VGA_XGI340 ;
+ }
+ */
+ pVBInfo->Set_VGAType = HwDeviceExtension->jChipType;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVBType */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetVBType(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT flag , tempbx , tempah ;
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ pVBInfo->VBType = VB_CH7007 ;
+ return;
+ }
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ tempbx = VB_XGI302B ;
+ flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x00 ) ;
+ if ( flag != 0x02 )
+ {
+ tempbx = VB_XGI301 ;
+ flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x01 ) ;
+ if ( flag >= 0xB0 )
+ {
+ tempbx = VB_XGI301B ;
+ if ( flag >= 0xC0 )
+ {
+ tempbx = VB_XGI301C ;
+ if ( flag >= 0xD0 )
+ {
+ tempbx = VB_XGI301LV ;
+ if ( flag >= 0xE0 )
+ {
+ tempbx = VB_XGI302LV ;
+ tempah = XGINew_GetReg1( pVBInfo->Part4Port , 0x39 ) ;
+ if ( tempah != 0xFF )
+ tempbx = VB_XGI301C ;
+ }
+ }
+ }
+
+ if ( tempbx & ( VB_XGI301B | VB_XGI302B ) )
+ {
+ flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x23 ) ;
+
+ if ( !( flag & 0x02 ) )
+ tempbx = tempbx | VB_NoLCD ;
+ }
+ }
+ }
+ pVBInfo->VBType = tempbx ;
+ }
+/*
+ else if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ pVBInfo->VBType = VB_CH7017 ;
+ else //LVDS
+ pVBInfo->VBType = VB_LVDS_NS ;
+*/
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVBInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetVBInfo( USHORT ModeNo , USHORT ModeIdIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempax ,
+ push ,
+ tempbx ,
+ temp ,
+ modeflag ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ pVBInfo->SetFlag = 0 ;
+ pVBInfo->ModeType = modeflag & ModeInfoFlag ;
+ tempbx = 0 ;
+
+ if ( pVBInfo->VBType & 0xFFFF )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x30 ) ; /* Check Display Device */
+ tempbx = tempbx | temp ;
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x31 ) ;
+ push = temp ;
+ push = push << 8 ;
+ tempax = temp << 8 ;
+ tempbx = tempbx | tempax ;
+ temp = ( SetCRT2ToDualEdge | SetCRT2ToYPbPr | SetCRT2ToLCDA | SetInSlaveMode | DisableCRT2Display ) ;
+ temp = 0xFFFF ^ temp ;
+ tempbx &= temp ;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ;
+
+ if ( pVBInfo->IF_DEF_LCDA == 1 )
+ {
+
+ if ( ( pVBInfo->Set_VGAType >= XG20 ) || ( pVBInfo->Set_VGAType >= XG40 ))
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ /* if ( ( pVBInfo->VBType & VB_XGI302B ) || ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) */
+ if ( pVBInfo->VBType & ( VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( temp & EnableDualEdge )
+ {
+ tempbx |= SetCRT2ToDualEdge ;
+
+ if ( temp & SetToLCDA )
+ tempbx |= SetCRT2ToLCDA ;
+ }
+ }
+ }
+ else if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ if ( pVBInfo->VBType & VB_CH7017 )
+ {
+ if ( temp & EnableDualEdge )
+ {
+ tempbx |= SetCRT2ToDualEdge ;
+
+ if ( temp & SetToLCDA )
+ tempbx |= SetCRT2ToLCDA ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( ( ( pVBInfo->IF_DEF_LVDS == 0 ) && ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) )
+ || ( ( pVBInfo->IF_DEF_CH7017 == 1 ) && ( pVBInfo->VBType&VB_CH7017 ) ) || ( (pVBInfo->IF_DEF_CH7007 == 1) && (pVBInfo->VBType&VB_CH7007) ) ) /* [Billy] 07/05/04 */
+ {
+ if ( temp & SetYPbPr ) /* temp = CR38 */
+ {
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ; /* shampoo add for new scratch */
+ temp &= YPbPrMode ;
+ tempbx |= SetCRT2ToHiVisionTV ;
+
+ if ( temp != YPbPrMode1080i ) {
+ tempbx &= ( ~SetCRT2ToHiVisionTV ) ;
+ tempbx |= SetCRT2ToYPbPr ; }
+ }
+
+ /* tempbx |= SetCRT2ToYPbPr ; */
+ }
+ }
+ }
+
+ tempax = push ; /* restore CR31 */
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ temp = 0x09FC ;
+ else
+ temp = 0x097C ;
+ }
+ else
+ {
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ temp = 0x01FC ;
+ else
+ temp = 0x017C ;
+ }
+ }
+ else /* 3nd party chip */
+ {
+ if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ temp = ( SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) ;
+ else if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 07/05/03 */
+ {
+ temp = SetCRT2ToTV ;
+ }
+ else
+ temp = SetCRT2ToLCD ;
+ }
+
+ if ( !( tempbx & temp ) )
+ {
+ tempax |= DisableCRT2Display ;
+ tempbx = 0 ;
+ }
+
+ if ( pVBInfo->IF_DEF_LCDA == 1 ) /* Select Display Device */
+ {
+ if ( !( pVBInfo->VBType & VB_NoLCD ) )
+ {
+ if ( tempbx & SetCRT2ToLCDA )
+ {
+ if ( tempbx & SetSimuScanMode )
+ tempbx &= ( ~( SetCRT2ToLCD | SetCRT2ToRAMDAC | SwitchToCRT2 ) ) ;
+ else
+ tempbx &= ( ~( SetCRT2ToLCD | SetCRT2ToRAMDAC | SetCRT2ToTV | SwitchToCRT2 ) ) ;
+ }
+ }
+ }
+
+ /* shampoo add */
+ if ( !( tempbx & ( SwitchToCRT2 | SetSimuScanMode ) ) ) /* for driver abnormal */
+ {
+ if ( pVBInfo->IF_DEF_CRT2Monitor == 1 )
+ {
+ if ( tempbx & SetCRT2ToRAMDAC )
+ {
+ tempbx &= ( 0xFF00 | SetCRT2ToRAMDAC | SwitchToCRT2 | SetSimuScanMode ) ;
+ tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ;
+ }
+ }
+ else
+ tempbx &= ( ~( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) ;
+ }
+
+ if ( !( pVBInfo->VBType & VB_NoLCD ) )
+ {
+ if ( tempbx & SetCRT2ToLCD )
+ {
+ tempbx &= ( 0xFF00 | SetCRT2ToLCD | SwitchToCRT2 | SetSimuScanMode ) ;
+ tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ;
+ }
+ }
+
+ if ( tempbx & SetCRT2ToSCART )
+ {
+ tempbx &= ( 0xFF00 | SetCRT2ToSCART | SwitchToCRT2 | SetSimuScanMode ) ;
+ tempbx &= ( 0x00FF | ( ~SetCRT2ToYPbPr ) ) ;
+ }
+
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( tempbx & SetCRT2ToYPbPr )
+ tempbx &= ( 0xFF00 | SwitchToCRT2 | SetSimuScanMode ) ;
+ }
+
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ {
+ if ( tempbx & SetCRT2ToHiVisionTV )
+ tempbx &= ( 0xFF00 | SetCRT2ToHiVisionTV | SwitchToCRT2 | SetSimuScanMode ) ;
+ }
+
+ if ( tempax & DisableCRT2Display ) /* Set Display Device Info */
+ {
+ if ( !( tempbx & ( SwitchToCRT2 | SetSimuScanMode ) ) )
+ tempbx = DisableCRT2Display ;
+ }
+
+ if ( !( tempbx & DisableCRT2Display ) )
+ {
+ if ( ( !( tempbx & DriverMode ) ) || ( !( modeflag & CRT2Mode ) ) )
+ {
+ if ( pVBInfo->IF_DEF_LCDA == 1 )
+ {
+ if ( !( tempbx & SetCRT2ToLCDA ) )
+ tempbx |= ( SetInSlaveMode | SetSimuScanMode ) ;
+ }
+
+ if ( pVBInfo->IF_DEF_VideoCapture == 1 )
+ {
+ if ( ( ( HwDeviceExtension->jChipType == XG40 ) && ( pVBInfo->Set_VGAType == XG40 ) )
+ || ( ( HwDeviceExtension->jChipType == XG41 ) && ( pVBInfo->Set_VGAType == XG41 ) )
+ || ( ( HwDeviceExtension->jChipType == XG42 ) && ( pVBInfo->Set_VGAType == XG42 ) )
+ || ( ( HwDeviceExtension->jChipType == XG45 ) && ( pVBInfo->Set_VGAType == XG45 ) ) )
+ {
+ if ( ModeNo <= 13 )
+ {
+ if ( !( tempbx & SetCRT2ToRAMDAC ) ) /*CRT2 not need to support*/
+ {
+ tempbx &= ( 0x00FF | ( ~SetInSlaveMode ) ) ;
+ pVBInfo->SetFlag |= EnableVCMode ;
+ }
+ }
+ }
+ }
+ }
+
+ /*LCD+TV can't support in slave mode (Force LCDA+TV->LCDB)*/
+ if ( ( tempbx & SetInSlaveMode ) && ( tempbx & SetCRT2ToLCDA ) )
+ {
+ tempbx ^= ( SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToDualEdge ) ;
+ pVBInfo->SetFlag |= ReserveTVOption ;
+ }
+ }
+ }
+
+ pVBInfo->VBInfo = tempbx ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetTVInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetTVInfo( USHORT ModeNo , USHORT ModeIdIndex ,PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp ,
+ tempbx = 0 ,
+ resinfo = 0 ,
+ modeflag ,
+ index1 ;
+
+ tempbx = 0 ;
+ resinfo = 0 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ; /* si+St_ResInfo */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo */
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ;
+ tempbx = temp;
+ if ( tempbx & SetPALTV )
+ {
+ tempbx &= ( SetCHTVOverScan | SetPALMTV | SetPALNTV | SetPALTV ) ;
+ if ( tempbx & SetPALMTV )
+ tempbx &= ~SetPALTV ; /* set to NTSC if PAL-M */
+ }
+ else
+ tempbx &= ( SetCHTVOverScan | SetNTSCJ | SetPALTV ) ;
+/*
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ index1 = XGINew_GetReg1( pVBInfo->P3d4 , 0x38 ) ; //PAL-M/PAL-N Info
+ temp2 = ( index1 & 0xC0 ) >> 5 ; //00:PAL, 01:PAL-M, 10:PAL-N
+ tempbx |= temp2 ;
+ if ( temp2 & 0x02 ) //PAL-M
+ tempbx &= ( ~SetPALTV ) ;
+ }
+*/
+ }
+
+ if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ tempbx = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ;
+
+ if ( tempbx & TVOverScan )
+ tempbx |= SetCHTVOverScan ;
+ }
+
+ if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 07/05/04 */
+ {
+ tempbx = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ;
+
+ if ( tempbx & TVOverScan )
+ {
+ tempbx |= SetCHTVOverScan ;
+ }
+ }
+
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToSCART )
+ tempbx |= SetPALTV ;
+ }
+
+ if ( pVBInfo->IF_DEF_YPbPr == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ index1 = XGINew_GetReg1( pVBInfo->P3d4 , 0x35 ) ;
+ index1 &= YPbPrMode ;
+
+ if ( index1 == YPbPrMode525i )
+ tempbx |= SetYPbPrMode525i ;
+
+ if ( index1 == YPbPrMode525p )
+ tempbx = tempbx | SetYPbPrMode525p;
+ if ( index1 == YPbPrMode750p)
+ tempbx = tempbx | SetYPbPrMode750p;
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_HiVision == 1 )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ tempbx = tempbx | SetYPbPrMode1080i | SetPALTV ;
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ { /* shampoo */
+ if ( ( pVBInfo->VBInfo & SetInSlaveMode ) && ( !( pVBInfo->VBInfo & SetNotSimuMode ) ) )
+ tempbx |= TVSimuMode ;
+
+ if ( !( tempbx & SetPALTV ) && ( modeflag > 13 ) && ( resinfo == 8 ) ) /* NTSC 1024x768, */
+ tempbx |= NTSC1024x768 ;
+
+ tempbx |= RPLLDIV2XO ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ tempbx &=( ~RPLLDIV2XO ) ;
+ }
+ else
+ {
+ if ( tempbx & ( SetYPbPrMode525p | SetYPbPrMode750p ) )
+ tempbx &= ( ~RPLLDIV2XO ) ;
+ else if ( !( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) )
+ {
+ if ( tempbx & TVSimuMode )
+ tempbx &= ( ~RPLLDIV2XO ) ;
+ }
+ }
+ }
+ }
+ pVBInfo->TVInfo = tempbx ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLCDInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_GetLCDInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT temp ,
+ tempax ,
+ tempbx ,
+ modeflag ,
+ resinfo = 0 ,
+ LCDIdIndex ;
+
+ pVBInfo->LCDResInfo = 0 ;
+ pVBInfo->LCDTypeInfo = 0 ;
+ pVBInfo->LCDInfo = 0 ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ModeFlag // */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ; /* si+Ext_ResInfo// */
+ }
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ; /* Get LCD Res.Info */
+ tempbx = temp & 0x0F ;
+
+ if ( tempbx == 0 )
+ tempbx = Panel1024x768 ; /* default */
+
+ /* LCD75 [2003/8/22] Vicent */
+ if ( ( tempbx == Panel1024x768 ) || ( tempbx == Panel1280x1024 ) )
+ {
+ if ( pVBInfo->VBInfo & DriverMode )
+ {
+ tempax = XGINew_GetReg1( pVBInfo->P3d4 , 0x33 ) ;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ tempax &= 0x0F ;
+ else
+ tempax = tempax >> 4 ;
+
+ if ( ( resinfo == 6 ) || ( resinfo == 9 ) )
+ {
+ if ( tempax >= 3 )
+ tempbx |= PanelRef75Hz ;
+ }
+ else if ( ( resinfo == 7 ) || ( resinfo == 8 ) )
+ {
+ if ( tempax >= 4 )
+ tempbx |= PanelRef75Hz ;
+ }
+ }
+ }
+
+ pVBInfo->LCDResInfo = tempbx ;
+
+ /* End of LCD75 */
+
+ if( pVBInfo->IF_DEF_OEMUtil == 1 )
+ {
+ pVBInfo->LCDTypeInfo = ( temp & 0xf0 ) >> 4 ;
+ }
+
+ if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) )
+ {
+ return 0;
+ }
+
+ tempbx = 0 ;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ;
+
+ temp &= ( ScalingLCD | LCDNonExpanding | LCDSyncBit | SetPWDEnable ) ;
+
+ if ( ( pVBInfo->IF_DEF_ScaleLCD == 1 ) && ( temp & LCDNonExpanding ) )
+ temp &= ~EnableScalingLCD ;
+
+ tempbx |= temp ;
+
+ LCDIdIndex = XGI_GetLCDCapPtr1(pVBInfo) ;
+
+ tempax = pVBInfo->LCDCapList[ LCDIdIndex ].LCD_Capability ;
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 ) /* shampoo */
+ {
+ if ( ( ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) ) && ( tempax & LCDDualLink ) )
+ {
+ tempbx |= SetLCDDualLink ;
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_CH7017 == 1 )
+ {
+ if ( tempax & LCDDualLink )
+ {
+ tempbx |= SetLCDDualLink ;
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( ( pVBInfo->LCDResInfo == Panel1400x1050 ) && ( pVBInfo->VBInfo & SetCRT2ToLCD ) && ( ModeNo > 0x13 ) && ( resinfo == 9 ) && ( !( tempbx & EnableScalingLCD ) ) )
+ tempbx |= SetLCDtoNonExpanding ; /* set to center in 1280x1024 LCDB for Panel1400x1050 */
+ }
+
+/*
+ if ( tempax & LCDBToA )
+ {
+ tempbx |= SetLCDBToA ;
+ }
+*/
+
+ if ( pVBInfo->IF_DEF_ExpLink == 1 )
+ {
+ if ( modeflag & HalfDCLK )
+ {
+ /* if ( !( pVBInfo->LCDInfo&LCDNonExpanding ) ) */
+ if ( !( tempbx & SetLCDtoNonExpanding ) )
+ {
+ tempbx |= EnableLVDSDDA ;
+ }
+ else
+ {
+ if ( ModeNo > 0x13 )
+ {
+ if ( pVBInfo->LCDResInfo == Panel1024x768 )
+ {
+ if ( resinfo == 4 )
+ { /* 512x384 */
+ tempbx |= EnableLVDSDDA ;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( pVBInfo->VBInfo & SetNotSimuMode )
+ {
+ tempbx |= LCDVESATiming ;
+ }
+ }
+ else
+ {
+ tempbx |= LCDVESATiming ;
+ }
+
+ pVBInfo->LCDInfo = tempbx ;
+
+ if ( pVBInfo->IF_DEF_PWD == 1 )
+ {
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ {
+ if ( ( pVBInfo->VBType & VB_XGI302LV ) || ( pVBInfo->VBType & VB_XGI301C ) )
+ {
+ if ( !( tempax & PWDEnable ) )
+ {
+ pVBInfo->LCDInfo &= ~SetPWDEnable ;
+ }
+ }
+ }
+ }
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( tempax & ( LockLCDBToA | StLCDBToA ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( !( tempax & LockLCDBToA ) )
+ {
+ if ( ModeNo <= 0x13 )
+ {
+ pVBInfo->VBInfo &= ~( SetSimuScanMode | SetInSlaveMode | SetCRT2ToLCD ) ;
+ pVBInfo->VBInfo |= SetCRT2ToLCDA | SetCRT2ToDualEdge ;
+ }
+ }
+ }
+ }
+ }
+
+/*
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( tempax & ( LockLCDBToA | StLCDBToA ) )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( !( ( !( tempax & LockLCDBToA ) ) && ( ModeNo > 0x13 ) ) )
+ {
+ pVBInfo->VBInfo&=~(SetSimuScanMode|SetInSlaveMode|SetCRT2ToLCD);
+ pVBInfo->VBInfo|=SetCRT2ToLCDA|SetCRT2ToDualEdge;
+ }
+ }
+ }
+ }
+*/
+
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SearchModeID */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_SearchModeID( USHORT ModeNo , USHORT *ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+
+#ifdef TC
+
+ if ( ModeNo <= 5 )
+ ModeNo |= 1 ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+
+ VGA_INFO = ( PUCHAR )MK_FP( 0 , 0x489 ) ;
+
+ if ( ModeNo == 0x07 )
+ {
+ if ( ( *VGA_INFO & 0x10 ) != 0 )
+ ( *ModeIdIndex )++ ; /* 400 lines */
+ /* else 350 lines */
+ }
+
+ if ( ModeNo <= 3 )
+ {
+ if ( ( *VGA_INFO & 0x80 ) == 0 )
+ {
+ ( *ModeIdIndex )++ ;
+ if ( ( *VGA_INFO & 0x10 ) != 0 )
+ ( *ModeIdIndex )++ ; /* 400 lines */
+ /* else 350 lines */
+ }
+ /* else 200 lines */
+ }
+ }
+ else
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+ }
+
+
+#endif
+
+#ifdef WIN2000
+
+ if ( ModeNo <= 5 )
+ ModeNo |= 1 ;
+ if ( ModeNo <= 0x13 )
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+
+ if ( ModeNo == 0x07 )
+ ( *ModeIdIndex )++ ; /* 400 lines */
+
+ if ( ModeNo <=3 )
+ ( *ModeIdIndex ) += 2 ; /* 400 lines */
+ /* else 350 lines */
+ }
+ else
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+ }
+
+#endif
+
+#ifdef LINUX /* chiawen for linux solution */
+
+ if ( ModeNo <= 5 )
+ ModeNo |= 1 ;
+ if ( ModeNo <= 0x13 )
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->SModeIDTable)/sizeof(XGI_StStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->SModeIDTable[ *ModeIdIndex ].St_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+
+ if ( ModeNo == 0x07 )
+ ( *ModeIdIndex )++ ; /* 400 lines */
+
+ if ( ModeNo <= 3 )
+ ( *ModeIdIndex ) += 2 ; /* 400 lines */
+ /* else 350 lines */
+ }
+ else
+ {
+ /* for (*ModeIdIndex=0;*ModeIdIndex<sizeof(pVBInfo->EModeIDTable)/sizeof(XGI_ExtStruct);(*ModeIdIndex)++) */
+ for( *ModeIdIndex = 0 ; ; ( *ModeIdIndex )++ )
+ {
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == ModeNo )
+ break ;
+ if ( pVBInfo->EModeIDTable[ *ModeIdIndex ].Ext_ModeID == 0xFF )
+ return( FALSE ) ;
+ }
+ }
+
+#endif
+
+ return( TRUE ) ;
+}
+
+
+
+
+/* win2000 MM adapter not support standard mode! */
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT memorysize ,
+ modeflag ,
+ temp ,
+ temp1 ,
+ tmp ;
+
+/* if ( ( HwDeviceExtension->jChipType == XGI_650 ) ||
+ ( HwDeviceExtension->jChipType == XGI_650M ) )
+ {
+ return( TRUE ) ;
+ } */
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ /* ModeType = modeflag&ModeInfoFlag ; // Get mode type */
+
+ memorysize = modeflag & MemoryInfoFlag ;
+ memorysize = memorysize > MemorySizeShift ;
+ memorysize++ ; /* Get memory size */
+
+ temp = XGINew_GetReg1( pVBInfo->P3c4 , 0x14 ) ; /* Get DRAM Size */
+ tmp = temp ;
+
+ if ( HwDeviceExtension->jChipType == XG40 )
+ {
+ temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */
+ if ( ( tmp & 0x0c ) == 0x0C ) /* Qual channels */
+ {
+ temp <<= 2 ;
+ }
+ else if ( ( tmp & 0x0c ) == 0x08 ) /* Dual channels */
+ {
+ temp <<= 1 ;
+ }
+ }
+ else if ( HwDeviceExtension->jChipType == XG42 )
+ {
+ temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */
+ if ( ( tmp & 0x04 ) == 0x04 ) /* Dual channels */
+ {
+ temp <<= 1 ;
+ }
+ }
+ else if ( HwDeviceExtension->jChipType == XG45 )
+ {
+ temp = 1 << ( ( temp & 0x0F0 ) >> 4 ) ; /* memory size per channel SR14[7:4] */
+ if ( ( tmp & 0x0c ) == 0x0C ) /* Qual channels */
+ {
+ temp <<= 2 ;
+ }
+ else if ( ( tmp & 0x0c ) == 0x08 ) /* triple channels */
+ {
+ temp1 = temp ;
+ temp <<= 1 ;
+ temp += temp1 ;
+ }
+ else if ( ( tmp & 0x0c ) == 0x04 ) /* Dual channels */
+ {
+ temp <<= 1 ;
+ }
+ }
+ if ( temp < memorysize )
+ return( FALSE ) ;
+ else
+ return( TRUE ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_IsLowResolution */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+/*void XGINew_IsLowResolution( USHORT ModeNo , USHORT ModeIdIndex, BOOLEAN XGINew_CheckMemorySize(PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT data ;
+ USHORT ModeFlag ;
+
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x0F ) ;
+ data &= 0x7F ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0F , data ) ;
+
+ if ( ModeNo > 0x13 )
+ {
+ ModeFlag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ if ( ( ModeFlag & HalfDCLK ) && ( ModeFlag & DoubleScanMode ) )
+ {
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x0F ) ;
+ data |= 0x80 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0F , data ) ;
+ data = XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ;
+ data &= 0xF7 ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , data ) ;
+ }
+ }
+}
+
+*/
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisplayOn */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_DisplayOn( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
+{
+
+ XGINew_SetRegANDOR(pVBInfo->P3c4,0x01,0xDF,0x00);
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ if (!(XGI_XG21GetPSCValue( pVBInfo )&0x1))
+ {
+ XGI_XG21BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */
+ XGI_XG21SetPanelDelay( 2,pVBInfo ) ;
+ }
+ if (!(XGI_XG21GetPSCValue( pVBInfo )&0x20))
+ {
+ XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */
+ }
+ XGI_XG21SetPanelDelay( 3,pVBInfo ) ;
+ XGI_XG21BLSignalVDD( 0x02 , 0x02, pVBInfo ) ; /* LVDS backlight on */
+ }
+ else
+ {
+ XGI_XG21BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* DVO/DVI signal on */
+ }
+
+ }
+
+ if (pVBInfo->IF_DEF_CH7007 == 1) /* [Billy] 07/05/23 For CH7007 */
+ {
+#ifdef WIN2000
+ if ( IsCH7007TVMode( pVBInfo ) )
+ {
+ TurnOnCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */
+ }
+#endif
+
+ }
+
+
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ if (!(XGI_XG27GetPSCValue( pVBInfo )&0x1))
+ {
+ XGI_XG27BLSignalVDD( 0x01 , 0x01, pVBInfo ) ; /* LVDS VDD on */
+ XGI_XG21SetPanelDelay( 2,pVBInfo ) ;
+ }
+ if (!(XGI_XG27GetPSCValue( pVBInfo )&0x20))
+ {
+ XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* LVDS signal on */
+ }
+ XGI_XG21SetPanelDelay( 3,pVBInfo ) ;
+ XGI_XG27BLSignalVDD( 0x02 , 0x02, pVBInfo ) ; /* LVDS backlight on */
+ }
+ else
+ {
+ XGI_XG27BLSignalVDD( 0x20 , 0x20, pVBInfo ) ; /* DVO/DVI signal on */
+ }
+
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisplayOff */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_DisplayOff( PXGI_HW_DEVICE_INFO pXGIHWDE , PVB_DEVICE_INFO pVBInfo )
+{
+
+ if ( pXGIHWDE->jChipType == XG21 )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ XGI_XG21BLSignalVDD( 0x02 , 0x00, pVBInfo ) ; /* LVDS backlight off */
+ XGI_XG21SetPanelDelay( 3,pVBInfo ) ;
+ }
+ else
+ {
+ XGI_XG21BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* DVO/DVI signal off */
+ }
+ }
+
+ if (pVBInfo->IF_DEF_CH7007 == 1) /*[Billy] 07/05/23 For CH7007 */
+ {
+ /* if( IsCH7007TVMode( pVBInfo ) == 0 ) */
+ {
+#ifdef WIN2000
+ TurnOffCH7007(pXGIHWDE->pDevice) ; /* 07/05/28 */
+#endif
+ }
+ }
+
+
+ if ( pXGIHWDE->jChipType == XG27 )
+ {
+ if ((XGI_XG27GetPSCValue( pVBInfo )&0x2))
+ {
+ XGI_XG27BLSignalVDD( 0x02 , 0x00, pVBInfo ) ; /* LVDS backlight off */
+ XGI_XG21SetPanelDelay( 3,pVBInfo ) ;
+ }
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ XGI_XG27BLSignalVDD( 0x20 , 0x00, pVBInfo ) ; /* DVO/DVI signal off */
+ }
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x01 , 0xDF , 0x20 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_WaitDisply */
+/* Input : */
+/* Output : */
+/* Description : chiawen for sensecrt1 */
+/* --------------------------------------------------------------------- */
+void XGI_WaitDisply( PVB_DEVICE_INFO pVBInfo )
+{
+ while( ( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) )
+ break ;
+
+ while( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) )
+ break ;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SenseCRT1 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+
+void XGI_SenseCRT1( PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR CRTCData[ 17 ] = { 0x5F , 0x4F , 0x50 , 0x82 , 0x55 , 0x81 ,
+ 0x0B , 0x3E , 0xE9 , 0x0B , 0xDF , 0xE7 ,
+ 0x04 , 0x00 , 0x00 , 0x05 , 0x00 } ;
+
+ UCHAR SR01 = 0 , SR1F = 0 , SR07 = 0 , SR06 = 0 ;
+
+ UCHAR CR17 , CR63 , SR31 ;
+ USHORT temp ;
+ UCHAR DAC_TEST_PARMS[ 3 ] = { 0x0F , 0x0F , 0x0F } ;
+
+ int i ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x05 , 0x86 ) ;
+
+ /* [2004/05/06] Vicent to fix XG42 single LCD sense to CRT+LCD */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x57 , 0x4A ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) | 0x02 ) ) ;
+
+ SR31 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x31 ) ;
+ CR63 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x63 ) ;
+ SR01 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x01 ) ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , ( UCHAR )( SR01 & 0xDF ) ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x63 , ( UCHAR )( CR63 & 0xBF ) ) ;
+
+ CR17 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x17 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x17 , ( UCHAR )( CR17 | 0x80 ) ) ;
+
+ SR1F = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR )( SR1F | 0x04 ) ) ;
+
+ SR07 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x07 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x07 , ( UCHAR )( SR07 & 0xFB ) ) ;
+ SR06 = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x06 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x06 , ( UCHAR )( SR06 & 0xC3 ) ) ;
+
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , 0x00 ) ;
+
+ for( i = 0 ; i < 8 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )i , CRTCData[ i ] ) ;
+
+ for( i = 8 ; i < 11 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 8 ) , CRTCData[ i ] ) ;
+
+ for( i = 11 ; i < 13 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3d4 , ( USHORT )( i + 4 ) , CRTCData[ i ] ) ;
+
+ for( i = 13 ; i < 16 ; i++ )
+ XGINew_SetReg1( pVBInfo->P3c4 , ( USHORT )( i - 3 ) , CRTCData[ i ] ) ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x0E , ( UCHAR )( CRTCData[ 16 ] & 0xE0 ) ) ;
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , 0x1B ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , 0xE1 ) ;
+
+ XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ;
+
+ for( i = 0 ; i < 256 ; i++ )
+ {
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 0 ] ) ;
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 1 ] ) ;
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , ( UCHAR )DAC_TEST_PARMS[ 2 ] ) ;
+ }
+
+ XGI_VBLongWait( pVBInfo ) ;
+ XGI_VBLongWait( pVBInfo ) ;
+ XGI_VBLongWait( pVBInfo ) ;
+
+ XGINew_LCD_Wait_Time( 0x01 , pVBInfo ) ;
+
+ XGI_WaitDisply( pVBInfo ) ;
+ temp = XGINew_GetReg2( pVBInfo->P3c2 ) ;
+
+ if( temp & 0x10 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xDF , 0x20 ) ;
+ }
+ else
+ {
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x32 , 0xDF , 0x00 ) ;
+ }
+
+ /* alan, avoid display something, set BLACK DAC if not restore DAC */
+ XGINew_SetReg3( pVBInfo->P3c8 , 0x00 ) ;
+
+ for( i = 0 ; i < 256 ; i++ )
+ {
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ;
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ;
+ XGINew_SetReg3( ( pVBInfo->P3c8 + 1 ) , 0 ) ;
+ }
+
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x01 , SR01 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x63 , CR63 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x31 , SR31 ) ;
+
+ /* [2004/05/11] Vicent */
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x53 , ( UCHAR )( XGINew_GetReg1( pVBInfo->P3d4 , 0x53 ) & 0xFD ) ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x1F , ( UCHAR ) SR1F ) ;
+}
+
+
+
+
+
+#ifdef TC
+/* --------------------------------------------------------------------- */
+/* Function : INT1AReturnCode */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+int INT1AReturnCode( union REGS regs )
+{
+ if ( regs.x.cflag )
+ {
+ /* printf( "Error to find pci device!\n" ) ; */
+ return( 1 ) ;
+ }
+
+ switch(regs.h.ah)
+ {
+ case 0: return 0;
+ break ;
+ case 0x81:
+ printf( "Function not support\n" ) ;
+ break ;
+ case 0x83:
+ printf( "bad vendor id\n" ) ;
+ break ;
+ case 0x86:
+ printf( "device not found\n" ) ;
+ break ;
+ case 0x87:
+ printf( "bad register number\n" ) ;
+ break ;
+ case 0x88:
+ printf( "set failed\n" ) ;
+ break ;
+ case 0x89:
+ printf( "buffer too small" ) ;
+ break ;
+ default:
+ break ;
+ }
+ return( 1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : FindPCIIOBase */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+unsigned FindPCIIOBase( unsigned index , unsigned deviceid )
+{
+ union REGS regs ;
+
+ regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */
+ regs.h.al = 0x02 ; /* FIND_PCI_DEVICE */
+ regs.x.cx = deviceid ;
+ regs.x.dx = 0x1039 ;
+ regs.x.si = index ; /* find n-th device */
+
+ int86( 0x1A , &regs , &regs ) ;
+
+ if ( INT1AReturnCode( regs ) != 0 )
+ return( 0 ) ;
+
+ /* regs.h.bh bus number */
+ /* regs.h.bl device number */
+ regs.h.ah = 0xb1 ; /* PCI_FUNCTION_ID */
+ regs.h.al = 0x09 ; /* READ_CONFIG_WORD */
+ regs.x.cx = deviceid ;
+ regs.x.dx = 0x1039 ;
+ regs.x.di = 0x18 ; /* register number */
+ int86( 0x1A , &regs , &regs ) ;
+
+ if ( INT1AReturnCode( regs ) != 0 )
+ return( 0 ) ;
+
+ return( regs.x.cx ) ;
+}
+
+#endif
+
+
+
+#ifdef TC
+/* --------------------------------------------------------------------- */
+/* Function : main */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void main(int argc, char *argv[])
+{
+ XGI_HW_DEVICE_INFO HwDeviceExtension ;
+ USHORT temp ;
+ USHORT ModeNo ;
+
+ /* HwDeviceExtension.pjVirtualRomBase =(PUCHAR) MK_FP(0xC000,0); */
+ /* HwDeviceExtension.pjVideoMemoryAddress = (PUCHAR)MK_FP(0xA000,0); */
+
+
+ HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 ,0x6300 ) & 0xFF80 ) + 0x30 ;
+ HwDeviceExtension.jChipType = XGI_340 ;
+
+
+
+ /* HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x5315 ) & 0xFF80 ) + 0x30 ; */
+
+ HwDeviceExtension.pjIOAddress = ( FindPCIIOBase( 0 , 0x330 ) & 0xFF80 ) + 0x30 ;
+ HwDeviceExtension.jChipType = XGI_340 ;
+
+
+ HwDeviceExtension.ujVBChipID = VB_CHIP_301 ;
+ StrCpy(HwDeviceExtension.szVBIOSVer , "0.84" ) ;
+ HwDeviceExtension.bSkipDramSizing = FALSE ;
+ HwDeviceExtension.ulVideoMemorySize = 0 ;
+
+ if ( argc == 2 )
+ {
+ ModeNo = atoi( argv[ 1 ] ) ;
+ }
+ else
+ {
+ ModeNo = 0x2e ;
+ /* ModeNo = 0x37 ; 1024x768x 4bpp */
+ /* ModeNo = 0x38 ; 1024x768x 8bpp */
+ /* ModeNo = 0x4A ; 1024x768x 16bpp */
+ /* ModeNo = 0x47 ; 800x600x 16bpp */
+ }
+
+ /* XGIInitNew( &HwDeviceExtension ) ; */
+ XGISetModeNew( &HwDeviceExtension , ModeNo ) ;
+}
+#endif
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_WaitDisplay */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_WaitDisplay( PVB_DEVICE_INFO pVBInfo )
+{
+ while( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ) ;
+
+ while( XGINew_GetReg2( pVBInfo->P3da ) & 0x01 ) ;
+}
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2Group301 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_SetCRT2Group301( USHORT ModeNo , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ,
+ ModeIdIndex ,
+ RefreshRateTableIndex ;
+
+ tempbx=pVBInfo->VBInfo ;
+ pVBInfo->SetFlag |= ProgrammingCRT2 ;
+ XGI_SearchModeID( ModeNo , &ModeIdIndex, pVBInfo ) ;
+ pVBInfo->SelectCRT2Rate = 4 ;
+ RefreshRateTableIndex = XGI_GetRatePtrCRT2( HwDeviceExtension, ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_SaveCRT2Info( ModeNo, pVBInfo ) ;
+ XGI_GetCRT2ResInfo( ModeNo , ModeIdIndex, pVBInfo) ;
+ XGI_GetCRT2Data( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_PreSetGroup1( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetGroup1( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetLockRegs( ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetGroup2( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetLCDRegs(ModeNo , ModeIdIndex , HwDeviceExtension , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetTap4Regs(pVBInfo) ;
+ XGI_SetGroup3(ModeNo, ModeIdIndex, pVBInfo);
+ XGI_SetGroup4( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT2VCLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ XGI_SetGroup5( ModeNo , ModeIdIndex, pVBInfo) ;
+ XGI_AutoThreshold( pVBInfo) ;
+ return 1 ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_AutoThreshold */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_AutoThreshold( PVB_DEVICE_INFO pVBInfo )
+{
+ if ( !( pVBInfo->SetFlag & Win9xDOSMode ) )
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x01 , 0x40 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SaveCRT2Info */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SaveCRT2Info( USHORT ModeNo , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT temp1 ,
+ temp2 ;
+
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x34 , ModeNo ) ; /* reserve CR34 for CRT1 Mode No */
+ temp1 = ( pVBInfo->VBInfo&SetInSlaveMode ) >> 8 ;
+ temp2 = ~( SetInSlaveMode >> 8 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x31 , temp2 , temp1 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetCRT2ResInfo */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetCRT2ResInfo( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT xres ,
+ yres ,
+ modeflag ,
+ resindex ;
+
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo) ;
+ if ( ModeNo <= 0x13 )
+ {
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->StResInfo[ resindex ].VTotal ;
+ /* modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; si+St_ResInfo */
+ }
+ else
+ {
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */
+
+/* if ( pVBInfo->IF_DEF_FSTN )
+ {
+ xres *= 2 ;
+ yres *= 2 ;
+ }
+ else
+ {
+*/
+ if ( modeflag & HalfDCLK )
+ xres *= 2;
+
+ if ( modeflag & DoubleScanMode )
+ yres *= 2 ;
+/* } */
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ {
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ if ( pVBInfo->LCDResInfo == Panel1600x1200 )
+ {
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( yres == 1024 )
+ yres = 1056 ;
+ }
+ }
+
+ if ( pVBInfo->LCDResInfo == Panel1280x1024 )
+ {
+ if ( yres == 400 )
+ yres = 405 ;
+ else if ( yres == 350 )
+ yres = 360 ;
+
+ if ( pVBInfo->LCDInfo & LCDVESATiming )
+ {
+ if ( yres == 360 )
+ yres = 375 ;
+ }
+ }
+
+ if ( pVBInfo->LCDResInfo == Panel1024x768 )
+ {
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( !( pVBInfo->LCDInfo & LCDNonExpanding ) )
+ {
+ if ( yres == 350 )
+ yres = 357 ;
+ else if ( yres == 400 )
+ yres = 420 ;
+ else if ( yres == 480 )
+ yres = 525 ;
+ }
+ }
+ }
+ }
+
+ if ( xres == 720 )
+ xres = 640 ;
+ }
+
+ pVBInfo->VGAHDE = xres ;
+ pVBInfo->HDE = xres ;
+ pVBInfo->VGAVDE = yres ;
+ pVBInfo->VDE = yres ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_IsLCDDualLink */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_IsLCDDualLink( PVB_DEVICE_INFO pVBInfo )
+{
+
+ if ( ( ( ( pVBInfo->VBInfo & SetCRT2ToLCD ) | SetCRT2ToLCDA ) ) && ( pVBInfo->LCDInfo & SetLCDDualLink ) ) /* shampoo0129 */
+ return ( 1 ) ;
+
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetCRT2Data */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetCRT2Data( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempax = 0,
+ tempbx ,
+ modeflag ,
+ resinfo ;
+
+ XGI_LCDDataStruct *LCDPtr = NULL ;
+ XGI_TVDataStruct *TVPtr = NULL ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ }
+
+ pVBInfo->NewFlickerMode = 0 ;
+ pVBInfo->RVBHRS = 50 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ {
+ XGI_GetRAMDAC2DATA( ModeNo , ModeIdIndex , RefreshRateTableIndex,pVBInfo ) ;
+ return ;
+ }
+
+ tempbx = 4 ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ LCDPtr = (XGI_LCDDataStruct* )XGI_GetLcdPtr( tempbx, ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+
+ pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX ;
+ pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT ;
+ pVBInfo->VGAHT = LCDPtr->VGAHT ;
+ pVBInfo->VGAVT = LCDPtr->VGAVT ;
+ pVBInfo->HT = LCDPtr->LCDHT ;
+ pVBInfo->VT = LCDPtr->LCDVT ;
+
+ if ( pVBInfo->LCDResInfo == Panel1024x768 )
+ {
+ tempax = 1024 ;
+ tempbx = 768 ;
+
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( pVBInfo->VGAVDE == 357 )
+ tempbx = 527 ;
+ else if ( pVBInfo->VGAVDE == 420 )
+ tempbx = 620 ;
+ else if ( pVBInfo->VGAVDE == 525 )
+ tempbx = 775 ;
+ else if ( pVBInfo->VGAVDE == 600 )
+ tempbx = 775 ;
+ /* else if(pVBInfo->VGAVDE==350) tempbx=560; */
+ /* else if(pVBInfo->VGAVDE==400) tempbx=640; */
+ else
+ tempbx = 768 ;
+ }
+ else
+ tempbx = 768 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1024x768x75 )
+ {
+ tempax = 1024 ;
+ tempbx = 768 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1280x1024 )
+ {
+ tempax = 1280 ;
+ if ( pVBInfo->VGAVDE == 360 )
+ tempbx = 768 ;
+ else if ( pVBInfo->VGAVDE == 375 )
+ tempbx = 800 ;
+ else if ( pVBInfo->VGAVDE == 405 )
+ tempbx = 864 ;
+ else
+ tempbx = 1024 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1280x1024x75 )
+ {
+ tempax = 1280 ;
+ tempbx = 1024 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1280x960 )
+ {
+ tempax = 1280 ;
+ if ( pVBInfo->VGAVDE == 350 )
+ tempbx = 700 ;
+ else if ( pVBInfo->VGAVDE == 400 )
+ tempbx = 800 ;
+ else if ( pVBInfo->VGAVDE == 1024 )
+ tempbx = 960 ;
+ else
+ tempbx = 960 ;
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1400x1050 )
+ {
+ tempax = 1400 ;
+ tempbx = 1050 ;
+
+ if ( pVBInfo->VGAVDE == 1024 )
+ {
+ tempax = 1280 ;
+ tempbx = 1024 ;
+ }
+ }
+ else if ( pVBInfo->LCDResInfo == Panel1600x1200 )
+ {
+ tempax = 1600 ;
+ tempbx = 1200 ; /* alan 10/14/2003 */
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( pVBInfo->VGAVDE == 350 )
+ tempbx = 875 ;
+ else if ( pVBInfo->VGAVDE == 400 )
+ tempbx = 1000 ;
+ }
+ }
+
+ if ( pVBInfo->LCDInfo & LCDNonExpanding )
+ {
+ tempax = pVBInfo->VGAHDE ;
+ tempbx = pVBInfo->VGAVDE ;
+ }
+
+ pVBInfo->HDE = tempax ;
+ pVBInfo->VDE = tempbx ;
+ return ;
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV ) )
+ {
+ tempbx = 4 ;
+ TVPtr = ( XGI_TVDataStruct * )XGI_GetTVPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+
+ pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX ;
+ pVBInfo->RVBHCFACT = TVPtr->RVBHCFACT ;
+ pVBInfo->VGAHT = TVPtr->VGAHT ;
+ pVBInfo->VGAVT = TVPtr->VGAVT ;
+ pVBInfo->HDE = TVPtr->TVHDE ;
+ pVBInfo->VDE = TVPtr->TVVDE ;
+ pVBInfo->RVBHRS = TVPtr->RVBHRS ;
+ pVBInfo->NewFlickerMode = TVPtr->FlickerMode ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( resinfo == 0x08 )
+ pVBInfo->NewFlickerMode = 0x40 ;
+ else if ( resinfo == 0x09 )
+ pVBInfo->NewFlickerMode = 0x40 ;
+ else if ( resinfo == 0x12 )
+ pVBInfo->NewFlickerMode = 0x40 ;
+
+ if ( pVBInfo->VGAVDE == 350 )
+ pVBInfo->TVInfo |= TVSimuMode ;
+
+ tempax = ExtHiTVHT ;
+ tempbx = ExtHiTVVT ;
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ {
+ tempax = StHiTVHT ;
+ tempbx = StHiTVVT ;
+
+ if ( !( modeflag & Charx8Dot ) )
+ {
+ tempax = StHiTextTVHT ;
+ tempbx = StHiTextTVVT ;
+ }
+ }
+ }
+ }
+ else if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ {
+ tempax = YPbPrTV750pHT ; /* Ext750pTVHT */
+ tempbx = YPbPrTV750pVT ; /* Ext750pTVVT */
+ }
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ {
+ tempax = YPbPrTV525pHT ; /* Ext525pTVHT */
+ tempbx = YPbPrTV525pVT ; /* Ext525pTVVT */
+ }
+ else if ( pVBInfo->TVInfo & SetYPbPrMode525i )
+ {
+ tempax = YPbPrTV525iHT ; /* Ext525iTVHT */
+ tempbx = YPbPrTV525iVT ; /* Ext525iTVVT */
+ if ( pVBInfo->TVInfo & NTSC1024x768 )
+ tempax = NTSC1024x768HT ;
+ }
+ }
+ else
+ {
+ tempax = PALHT ;
+ tempbx = PALVT ;
+ if ( !( pVBInfo->TVInfo & SetPALTV ) )
+ {
+ tempax = NTSCHT ;
+ tempbx = NTSCVT ;
+ if ( pVBInfo->TVInfo & NTSC1024x768 )
+ tempax = NTSC1024x768HT ;
+ }
+ }
+
+ pVBInfo->HT = tempax ;
+ pVBInfo->VT = tempbx ;
+ return ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2VCLK */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT2VCLK( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR di_0 ,
+ di_1 ,
+ tempal ;
+
+ tempal = XGI_GetVCLKPtr( RefreshRateTableIndex , ModeNo , ModeIdIndex, pVBInfo ) ;
+ XGI_GetVCLKLen( tempal, &di_0 , &di_1, pVBInfo ) ;
+ XGI_GetLCDVCLKPtr( &di_0 , &di_1, pVBInfo ) ;
+
+ if ( pVBInfo->VBType & VB_XGI301 ) /* shampoo 0129 */
+ { /* 301 */
+ XGINew_SetReg1(pVBInfo->Part4Port , 0x0A , 0x10 ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port , 0x0B , di_1 ) ;
+ XGINew_SetReg1(pVBInfo->Part4Port , 0x0A , di_0 ) ;
+ }
+ else
+ { /* 301b/302b/301lv/302lv */
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0A , di_0 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0B , di_1 ) ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x00 , 0x12 ) ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x12 , 0x28 ) ;
+ else
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x12 , 0x08 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GETLCDVCLKPtr */
+/* Input : */
+/* Output : al -> VCLK Index */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetLCDVCLKPtr( UCHAR* di_0 , UCHAR *di_1, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT index ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ if ( pVBInfo->IF_DEF_ScaleLCD == 1 )
+ {
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ return ;
+ }
+
+ /* index = XGI_GetLCDCapPtr(pVBInfo) ; */
+ index = XGI_GetLCDCapPtr1( pVBInfo) ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ { /* LCDB */
+ *di_0 = pVBInfo->LCDCapList[ index ].LCUCHAR_VCLKData1 ;
+ *di_1 = pVBInfo->LCDCapList[ index ].LCUCHAR_VCLKData2 ;
+ }
+ else
+ { /* LCDA */
+ *di_0 = pVBInfo->LCDCapList[ index ].LCDA_VCLKData1 ;
+ *di_1 = pVBInfo->LCDCapList[ index ].LCDA_VCLKData2 ;
+ }
+ }
+ return ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVCLKPtr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGI_GetVCLKPtr(USHORT RefreshRateTableIndex,USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+
+ USHORT index ,
+ modeflag ;
+#ifndef LINUX_XF86
+ USHORT tempbx ;
+#endif
+
+ UCHAR tempal ;
+ UCHAR *CHTVVCLKPtr = NULL ;
+
+ if ( ModeNo <= 0x13 )
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ else
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */
+
+
+ if ( ( pVBInfo->SetFlag & ProgrammingCRT2 ) && ( !( pVBInfo->LCDInfo & EnableScalingLCD ) ) )
+ { /* {LCDA/LCDB} */
+ index = XGI_GetLCDCapPtr(pVBInfo) ;
+ tempal = pVBInfo->LCDCapList[ index ].LCD_VCLK ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ return tempal ;
+
+ /* {TV} */
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV| VB_XGI302LV| VB_XGI301C ) )
+ {
+ if(pVBInfo->VBInfo&SetCRT2ToHiVisionTV)
+ {
+ tempal = HiTVVCLKDIV2;
+ if(!(pVBInfo->TVInfo & RPLLDIV2XO))
+ tempal = HiTVVCLK;
+ if(pVBInfo->TVInfo & TVSimuMode)
+ {
+ tempal = HiTVSimuVCLK;
+ if(!(modeflag & Charx8Dot))
+ tempal = HiTVTextVCLK;
+
+ }
+ return tempal;
+ }
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ {
+ tempal = YPbPr750pVCLK ;
+ return tempal ;
+ }
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ {
+ tempal = YPbPr525pVCLK ;
+ return tempal ;
+ }
+
+ tempal = NTSC1024VCLK ;
+
+ if ( !( pVBInfo->TVInfo & NTSC1024x768 ) )
+ {
+ tempal = TVVCLKDIV2 ;
+ if ( !( pVBInfo->TVInfo & RPLLDIV2XO ) )
+ tempal = TVVCLK ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ return tempal ;
+ }
+ /*else
+ if((pVBInfo->IF_DEF_CH7017==1)&&(pVBInfo->VBType&VB_CH7017))
+ {
+ if(ModeNo<=0x13)
+ *tempal = pVBInfo->SModeIDTable[ModeIdIndex].St_CRT2CRTC;
+ else
+ *tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+ *tempal = *tempal & 0x1F;
+
+ tempbx = 0;
+ if(pVBInfo->TVInfo & SetPALTV)
+ tempbx = tempbx + 2;
+ if(pVBInfo->TVInfo & SetCHTVOverScan)
+ tempbx++;
+ tempbx = tempbx << 1;
+ } */
+ } /* {End of VB} */
+
+ if((pVBInfo->IF_DEF_CH7007==1)&&(pVBInfo->VBType&VB_CH7007)) /* [Billy] 07/05/08 CH7007 */
+ {
+ /* VideoDebugPrint((0, "XGI_GetVCLKPtr: pVBInfo->IF_DEF_CH7007==1\n")); */
+ if ( (pVBInfo->VBInfo & SetCRT2ToTV) )
+ {
+ if( ModeNo <= 0x13 )
+ {
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ }
+ else
+ {
+ tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC;
+ }
+
+ tempal = tempal & 0x0F;
+ tempbx = 0;
+
+ if(pVBInfo->TVInfo & SetPALTV)
+ {
+ tempbx = tempbx + 2;
+ }
+ if(pVBInfo->TVInfo & SetCHTVOverScan)
+ {
+ tempbx++;
+ }
+ /** tempbx = tempbx << 1; CH7007 ? **/
+
+/*[Billy]07/05/29 CH7007*/
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ switch( tempbx )
+ {
+ case 0:
+ CHTVVCLKPtr = XGI7007_CHTVVCLKUNTSC ;
+ break ;
+ case 1:
+ CHTVVCLKPtr = XGI7007_CHTVVCLKONTSC ;
+ break ;
+ case 2:
+ CHTVVCLKPtr = XGI7007_CHTVVCLKUPAL ;
+ break ;
+ case 3:
+ CHTVVCLKPtr = XGI7007_CHTVVCLKOPAL ;
+ break ;
+ default:
+ break ;
+
+ }
+ }
+ /*else
+ {
+ switch( tempbx )
+ {
+ case 0:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKUNTSC ;
+ break ;
+ case 1:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKONTSC ;
+ break ;
+ case 2:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKUPAL ;
+ break ;
+ case 3:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKOPAL ;
+ break ;
+ default:
+ break ;
+ }
+ }*/
+
+ tempal = CHTVVCLKPtr[ tempal ] ;
+ return tempal ;
+ }
+
+ }
+
+ tempal = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ;
+ tempal = tempal >> 2 ;
+ tempal &= 0x03 ;
+
+ if ( ( pVBInfo->LCDInfo & EnableScalingLCD ) && ( modeflag & Charx8Dot ) ) /* for Dot8 Scaling LCD */
+ tempal = tempal ^ tempal ; /* ; set to VCLK25MHz always */
+
+ if ( ModeNo <= 0x13 )
+ return tempal ;
+
+ tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ;
+ return tempal ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVCLKLen */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetVCLKLen(UCHAR tempal,UCHAR* di_0,UCHAR* di_1, PVB_DEVICE_INFO pVBInfo)
+{
+ if ( pVBInfo->IF_DEF_CH7007 == 1 ) /* [Billy] 2007/05/16 */
+ {
+ /* VideoDebugPrint((0, "XGI_GetVCLKLen: pVBInfo->IF_DEF_CH7007==1\n")); */
+ *di_0 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2B ;
+ *di_1 = ( UCHAR )XGI_CH7007VCLKData[ tempal ].SR2C ;
+ }
+ else if ( pVBInfo->VBType & ( VB_XGI301 | VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( pVBInfo->SetFlag & ProgrammingCRT2 ) )
+ {
+ *di_0 = ( UCHAR )XGI_VBVCLKData[ tempal ].SR2B ;
+ *di_1 = XGI_VBVCLKData[ tempal ].SR2C ;
+ }
+ }
+ else
+ {
+ *di_0 = XGI_VCLKData[ tempal ].SR2B ;
+ *di_1 = XGI_VCLKData[ tempal ].SR2C ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2Offset */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT2Offset( USHORT ModeNo ,
+ USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT offset ;
+ UCHAR temp ;
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ return ;
+ }
+
+ offset = XGI_GetOffset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ temp = ( UCHAR )( offset & 0xFF ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , temp ) ;
+ temp =( UCHAR)( ( offset & 0xFF00 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x09 , temp ) ;
+ temp =( UCHAR )( ( ( offset >> 3 ) & 0xFF ) + 1 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetOffset */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetOffset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT temp ,
+ colordepth ,
+ modeinfo ,
+ index ,
+ infoflag ,
+ ColorDepth[] = { 0x01 , 0x02 , 0x04 } ;
+
+ modeinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeInfo ;
+ if ( ModeNo <= 0x14 )
+ infoflag = 0 ;
+ else
+ infoflag = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_InfoFlag ;
+
+
+ index = ( modeinfo >> 8 ) & 0xFF ;
+
+ temp = pVBInfo->ScreenOffset[ index ] ;
+
+ if ( infoflag & InterlaceMode )
+ {
+ temp = temp << 1 ;
+ }
+
+ colordepth = XGI_GetColorDepth( ModeNo , ModeIdIndex, pVBInfo ) ;
+
+ if ( ( ModeNo >= 0x7C ) && ( ModeNo <= 0x7E ) )
+ {
+ temp = ModeNo - 0x7C ;
+ colordepth = ColorDepth[ temp ] ;
+ temp = 0x6B ;
+ if ( infoflag & InterlaceMode )
+ {
+ temp = temp << 1 ;
+ }
+ return( temp * colordepth ) ;
+ }
+ else
+ return( temp * colordepth ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2FIFO */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT2FIFO( PVB_DEVICE_INFO pVBInfo)
+{
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x01 , 0x3B ) ; /* threshold high ,disable auto threshold */
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x02 , ~( 0x3F ) , 0x04 ) ; /* threshold low default 04h */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_PreSetGroup1 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_PreSetGroup1(USHORT ModeNo , USHORT ModeIdIndex ,PXGI_HW_DEVICE_INFO HwDeviceExtension,
+ USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempcx = 0 ,
+ CRT1Index = 0 ,
+ resinfo = 0 ;
+
+ if ( ModeNo > 0x13 )
+ {
+ CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ CRT1Index &= IndexMask ;
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ }
+
+ XGI_SetCRT2Offset( ModeNo , ModeIdIndex , RefreshRateTableIndex , HwDeviceExtension, pVBInfo ) ;
+ XGI_SetCRT2FIFO(pVBInfo) ;
+ /* XGI_SetCRT2Sync(ModeNo,RefreshRateTableIndex); */
+
+ for( tempcx = 4 ; tempcx < 7 ; tempcx++ )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , tempcx , 0x0 ) ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x50 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x02 , 0x44 ) ; /* temp 0206 */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGroup1 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGroup1( USHORT ModeNo , USHORT ModeIdIndex ,
+ PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT temp = 0 ,
+ tempax = 0 ,
+ tempbx = 0 ,
+ tempcx = 0 ,
+ pushbx = 0 ,
+ CRT1Index = 0 ,
+ modeflag ,
+ resinfo = 0 ;
+
+ if ( ModeNo > 0x13 )
+ {
+ CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ CRT1Index &= IndexMask ;
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ }
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ /* bainy change table name */
+ if ( modeflag & HalfDCLK )
+ {
+ temp = ( pVBInfo->VGAHT / 2 - 1 ) & 0x0FF ; /* BTVGA2HT 0x08,0x09 */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , temp ) ;
+ temp = ( ( ( pVBInfo->VGAHT / 2 - 1 ) & 0xFF00 ) >> 8 ) << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x09 , ~0x0F0 , temp ) ;
+ temp = ( pVBInfo->VGAHDE / 2 + 16 ) & 0x0FF ; /* BTVGA2HDEE 0x0A,0x0C */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ;
+ tempcx = ( ( pVBInfo->VGAHT - pVBInfo->VGAHDE ) / 2 ) >> 2 ;
+ pushbx = pVBInfo->VGAHDE / 2 + 16 ;
+ tempcx = tempcx >> 1 ;
+ tempbx = pushbx + tempcx ; /* bx BTVGA@HRS 0x0B,0x0C */
+ tempcx += tempbx ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ {
+ tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 4 ] ;
+ tempbx |= ( ( pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] & 0xC0 ) << 2 ) ;
+ tempbx = ( tempbx - 3 ) << 3 ; /* (VGAHRS-3)*8 */
+ tempcx = pVBInfo->XGINEWUB_CRT1Table[CRT1Index].CR[ 5 ] ;
+ tempcx &= 0x1F ;
+ temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 15 ] ;
+ temp = ( temp & 0x04 ) << ( 5 - 2 ) ; /* VGAHRE D[5] */
+ tempcx = ( ( tempcx | temp ) - 3 ) << 3 ; /* (VGAHRE-3)*8 */
+ }
+
+ tempbx += 4 ;
+ tempcx += 4 ;
+
+ if ( tempcx > ( pVBInfo->VGAHT / 2 ) )
+ tempcx = pVBInfo->VGAHT / 2 ;
+
+ temp = tempbx & 0x00FF ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ;
+ }
+ else
+ {
+ temp = ( pVBInfo->VGAHT - 1 ) & 0x0FF ; /* BTVGA2HT 0x08,0x09 */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , temp ) ;
+ temp = ( ( ( pVBInfo->VGAHT - 1 ) & 0xFF00 ) >> 8 ) << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x09 , ~0x0F0 , temp ) ;
+ temp = ( pVBInfo->VGAHDE + 16 ) & 0x0FF ; /* BTVGA2HDEE 0x0A,0x0C */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ;
+ tempcx = ( pVBInfo->VGAHT - pVBInfo->VGAHDE ) >> 2 ; /* cx */
+ pushbx = pVBInfo->VGAHDE + 16 ;
+ tempcx = tempcx >> 1 ;
+ tempbx = pushbx + tempcx ; /* bx BTVGA@HRS 0x0B,0x0C */
+ tempcx += tempbx ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ {
+ tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 3 ] ;
+ tempbx |= ( ( pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 5 ] & 0xC0 ) << 2 ) ;
+ tempbx = ( tempbx - 3 ) << 3 ; /* (VGAHRS-3)*8 */
+ tempcx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 4 ] ;
+ tempcx &= 0x1F ;
+ temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 6 ] ;
+ temp = ( temp & 0x04 ) << ( 5 - 2 ) ; /* VGAHRE D[5] */
+ tempcx = ( ( tempcx | temp ) - 3 ) << 3 ; /* (VGAHRE-3)*8 */
+ tempbx += 16 ;
+ tempcx += 16 ;
+ }
+
+ if ( tempcx > pVBInfo->VGAHT )
+ tempcx = pVBInfo->VGAHT ;
+
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ;
+ }
+
+ tempax = ( tempax & 0x00FF ) | ( tempbx & 0xFF00 ) ;
+ tempbx = pushbx ;
+ tempbx = ( tempbx & 0x00FF ) | ( ( tempbx & 0xFF00 ) << 4 ) ;
+ tempax |= ( tempbx & 0xFF00 ) ;
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , temp ) ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0D , temp ) ;
+ tempcx = ( pVBInfo->VGAVT - 1 ) ;
+ temp = tempcx & 0x00FF ;
+
+ if ( pVBInfo->IF_DEF_CH7005 == 1 )
+ {
+ if ( pVBInfo->VBInfo & 0x0C )
+ {
+ temp-- ;
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0E , temp ) ;
+ tempbx = pVBInfo->VGAVDE - 1 ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0F , temp ) ;
+ temp = ( ( tempbx & 0xFF00 ) << 3 ) >> 8 ;
+ temp |= ( ( tempcx & 0xFF00 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x12 , temp ) ;
+
+ tempax = pVBInfo->VGAVDE ;
+ tempbx = pVBInfo->VGAVDE ;
+ tempcx = pVBInfo->VGAVT ;
+ tempbx = ( pVBInfo->VGAVT + pVBInfo->VGAVDE ) >> 1 ; /* BTVGA2VRS 0x10,0x11 */
+ tempcx = ( ( pVBInfo->VGAVT - pVBInfo->VGAVDE ) >> 4 ) + tempbx + 1 ; /* BTVGA2VRE 0x11 */
+
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ {
+ tempbx = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 10 ] ;
+ temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 9 ] ;
+
+ if ( temp & 0x04 )
+ tempbx |= 0x0100 ;
+
+ if ( temp & 0x080 )
+ tempbx |= 0x0200 ;
+
+ temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] ;
+
+ if ( temp & 0x08 )
+ tempbx |= 0x0400 ;
+
+ temp = pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 11 ] ;
+ tempcx = ( tempcx & 0xFF00 ) | ( temp & 0x00FF ) ;
+ }
+
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x10 , temp ) ;
+ temp = ( ( tempbx & 0xFF00 ) >> 8 ) << 4 ;
+ temp = ( ( tempcx & 0x000F ) | ( temp ) ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x11 , temp ) ;
+ tempax = 0 ;
+
+ if ( modeflag & DoubleScanMode )
+ tempax |= 0x80 ;
+
+ if ( modeflag & HalfDCLK )
+ tempax |= 0x40 ;
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2C , ~0x0C0 , tempax ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLockRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLockRegs( USHORT ModeNo , USHORT ModeIdIndex ,
+ PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT push1 ,
+ push2 ,
+ tempax ,
+ tempbx = 0 ,
+ tempcx ,
+ temp ,
+ resinfo ,
+ modeflag ,
+ CRT1Index ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ CRT1Index &= IndexMask;
+ }
+
+ if ( !( pVBInfo->VBInfo & SetInSlaveMode ) )
+ {
+ return ;
+ }
+
+ temp = 0xFF ; /* set MAX HT */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , temp ) ;
+ /* if ( modeflag & Charx8Dot ) tempcx = 0x08 ; */
+ /* else */
+ tempcx=0x08;
+
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ modeflag |= Charx8Dot ;
+
+ tempax = pVBInfo->VGAHDE ; /* 0x04 Horizontal Display End */
+
+ if ( modeflag & HalfDCLK )
+ tempax = tempax >> 1 ;
+
+ tempax = ( tempax / tempcx ) - 1 ;
+ tempbx |= ( ( tempax & 0x00FF ) << 8 ) ;
+ temp = tempax & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x04 , temp ) ;
+
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( !( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) )
+ temp += 2 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( pVBInfo->VBExtInfo == VB_YPbPr1080i )
+ {
+ if ( resinfo == 7 )
+ temp -= 2 ;
+ }
+ }
+ else
+ if ( resinfo == 7 )
+ temp -= 2 ;
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x05 , temp ) ; /* 0x05 Horizontal Display Start */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x06 , 0x03 ) ; /* 0x06 Horizontal Blank end */
+
+ if ( !( pVBInfo->VBInfo & DisableCRT2Display ) )
+ { /* 030226 bainy */
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ tempax = pVBInfo->VGAHT ;
+ else
+ tempax = XGI_GetVGAHT2( pVBInfo) ;
+ }
+
+ if ( tempax >= pVBInfo->VGAHT )
+ {
+ tempax = pVBInfo->VGAHT ;
+ }
+
+ if ( modeflag & HalfDCLK )
+ {
+ tempax = tempax >> 1 ;
+ }
+
+ tempax = ( tempax / tempcx ) - 5 ;
+ tempcx = tempax ; /* 20030401 0x07 horizontal Retrace Start */
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ temp = ( tempbx & 0x00FF ) - 1 ;
+ if ( !( modeflag & HalfDCLK ) )
+ {
+ temp -= 6 ;
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ {
+ temp -= 4 ;
+ if ( ModeNo > 0x13 )
+ temp -= 10 ;
+ }
+ }
+ }
+ else
+ {
+ /* tempcx = tempbx & 0x00FF ; */
+ tempbx = ( tempbx & 0xFF00 ) >> 8 ;
+ tempcx = ( tempcx + tempbx ) >> 1 ;
+ temp = ( tempcx & 0x00FF ) + 2 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ temp -= 1 ;
+ if ( !( modeflag & HalfDCLK ) )
+ {
+ if ( ( modeflag & Charx8Dot ) )
+ {
+ temp += 4 ;
+ if ( pVBInfo->VGAHDE >= 800 )
+ {
+ temp -= 6 ;
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( !( modeflag & HalfDCLK ) )
+ {
+ temp -= 4 ;
+ if ( pVBInfo->LCDResInfo != Panel1280x960 )
+ {
+ if( pVBInfo->VGAHDE >= 800 )
+ {
+ temp -= 7 ;
+ if ( pVBInfo->ModeType == ModeEGA )
+ {
+ if ( pVBInfo->VGAVDE == 1024 )
+ {
+ temp += 15 ;
+ if ( pVBInfo->LCDResInfo != Panel1280x1024 )
+ {
+ temp += 7 ;
+ }
+ }
+ }
+
+ if ( pVBInfo->VGAHDE >= 1280 )
+ {
+ if ( pVBInfo->LCDResInfo != Panel1280x960 )
+ {
+ if ( pVBInfo->LCDInfo & LCDNonExpanding )
+ {
+ temp += 28 ;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , temp ) ; /* 0x07 Horizontal Retrace Start */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0 ) ; /* 0x08 Horizontal Retrace End */
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ {
+ if ( ( ModeNo == 0x06 ) || ( ModeNo == 0x10 ) || ( ModeNo == 0x11 ) || ( ModeNo == 0x13 ) || ( ModeNo == 0x0F ) )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x5b ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x03 ) ;
+ }
+
+ if ( ( ModeNo == 0x00 ) || ( ModeNo == 0x01 ) )
+ {
+ if ( pVBInfo->TVInfo & SetNTSCTV )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2A ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x61 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2A ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x41 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , 0xF0 ) ;
+ }
+ }
+
+ if ( ( ModeNo == 0x02 ) || ( ModeNo == 0x03 ) || ( ModeNo == 0x07 ) )
+ {
+ if ( pVBInfo->TVInfo & SetNTSCTV )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x54 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x00 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x55 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , 0xF0 ) ;
+ }
+ }
+
+ if ( ( ModeNo == 0x04 ) || ( ModeNo == 0x05 ) || ( ModeNo == 0x0D ) || ( ModeNo == 0x50 ) )
+ {
+ if ( pVBInfo->TVInfo & SetNTSCTV )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x30 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x03 ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x07 , 0x2f ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x08 , 0x02 ) ;
+ }
+ }
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x18 , 0x03 ) ; /* 0x18 SR0B */
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0xF0 , 0x00 ) ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x09 , 0xFF ) ; /* 0x09 Set Max VT */
+
+ tempbx = pVBInfo->VGAVT ;
+ push1 = tempbx ;
+ tempcx = 0x121 ;
+ tempbx = pVBInfo->VGAVDE ; /* 0x0E Virtical Display End */
+
+ if ( tempbx == 357 )
+ tempbx = 350 ;
+ if ( tempbx == 360 )
+ tempbx =350 ;
+ if ( tempbx == 375 )
+ tempbx = 350 ;
+ if ( tempbx == 405 )
+ tempbx = 400 ;
+ if ( tempbx == 525 )
+ tempbx = 480 ;
+
+ push2 = tempbx ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ {
+ if ( pVBInfo->LCDResInfo == Panel1024x768 )
+ {
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( tempbx == 350 )
+ tempbx += 5 ;
+ if ( tempbx == 480 )
+ tempbx += 5 ;
+ }
+ }
+ }
+ tempbx-- ;
+ temp = tempbx & 0x00FF ;
+ tempbx-- ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x10 ,temp ) ; /* 0x10 vertical Blank Start */
+ tempbx = push2 ;
+ tempbx-- ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0E , temp ) ;
+
+ if ( tempbx & 0x0100 )
+ {
+ tempcx |= 0x0002 ;
+ }
+
+ tempax = 0x000B ;
+
+ if ( modeflag & DoubleScanMode )
+ {
+ tempax |= 0x08000 ;
+ }
+
+ if ( tempbx & 0x0200 )
+ {
+ tempcx |= 0x0040 ;
+ }
+
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0B , temp ) ;
+
+ if ( tempbx & 0x0400 )
+ {
+ tempcx |= 0x0600 ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x11 , 0x00 ) ; /* 0x11 Vertival Blank End */
+
+ tempax = push1 ;
+ tempax -= tempbx ; /* 0x0C Vertical Retrace Start */
+ tempax = tempax >> 2 ;
+ push1 = tempax ; /* push ax */
+
+ if ( resinfo != 0x09 )
+ {
+ tempax = tempax << 1 ;
+ tempbx += tempax ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode1080i )
+ tempbx -= 10 ;
+ else
+ {
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ {
+ if ( pVBInfo->TVInfo & SetPALTV )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) )
+ tempbx += 40 ;
+ }
+ else
+ tempbx += 40 ;
+ }
+ }
+ }
+ }
+ else
+ tempbx -= 10 ;
+ }
+ else
+ {
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ {
+ if ( pVBInfo->TVInfo & SetPALTV )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) )
+ tempbx += 40 ;
+ }
+ else
+ tempbx += 40 ;
+ }
+ }
+ }
+ tempax = push1 ;
+ tempax = tempax >> 2 ;
+ tempax++ ;
+ tempax += tempbx ;
+ push1 = tempax ; /* push ax */
+
+ if ( ( pVBInfo->TVInfo & SetPALTV ) )
+ {
+ if ( tempbx <= 513 )
+ {
+ if ( tempax >= 513 )
+ {
+ tempbx = 513 ;
+ }
+ }
+ }
+
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0C , temp ) ;
+ tempbx-- ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x10 , temp ) ;
+
+ if ( tempbx & 0x0100 )
+ {
+ tempcx |= 0x0008 ;
+ }
+
+ if ( tempbx & 0x0200 )
+ {
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x0B , 0x0FF , 0x20 ) ;
+ }
+
+ tempbx++ ;
+
+ if ( tempbx & 0x0100 )
+ {
+ tempcx |= 0x0004 ;
+ }
+
+ if ( tempbx & 0x0200 )
+ {
+ tempcx |= 0x0080 ;
+ }
+
+ if ( tempbx & 0x0400 )
+ {
+ tempcx |= 0x0C00 ;
+ }
+
+ tempbx = push1 ; /* pop ax */
+ temp = tempbx & 0x00FF ;
+ temp &= 0x0F ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0D , temp ) ; /* 0x0D vertical Retrace End */
+
+ if ( tempbx & 0x0010 )
+ {
+ tempcx |= 0x2000 ;
+ }
+
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0A , temp ) ; /* 0x0A CR07 */
+ temp = ( tempcx & 0x0FF00 ) >> 8 ;
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x17 , temp ) ; /* 0x17 SR0A */
+ tempax = modeflag ;
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+
+ temp = ( temp >> 1 ) & 0x09 ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ temp |= 0x01 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x16 , temp ) ; /* 0x16 SR01 */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x0F , 0 ) ; /* 0x0F CR14 */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x12 , 0 ) ; /* 0x12 CR17 */
+
+ if ( pVBInfo->LCDInfo & LCDRGB18Bit )
+ temp = 0x80 ;
+ else
+ temp = 0x00 ;
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1A , temp ) ; /* 0x1A SR0E */
+
+ return ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGroup2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGroup2( USHORT ModeNo, USHORT ModeIdIndex, USHORT RefreshRateTableIndex,
+ PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT i ,
+ j ,
+ tempax ,
+ tempbx ,
+ tempcx ,
+ temp ,
+ push1 ,
+ push2 ,
+ modeflag ,
+ resinfo ,
+ crt2crtc ;
+ UCHAR *TimingPoint ;
+
+ ULONG longtemp ,
+ tempeax ,
+ tempebx ,
+ temp2 ,
+ tempecx ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ;
+ crt2crtc = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ crt2crtc = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ;
+ }
+
+ tempax = 0 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToAVIDEO ) )
+ tempax |= 0x0800 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) )
+ tempax |= 0x0400 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToSCART )
+ tempax |= 0x0200 ;
+
+ if ( !( pVBInfo->TVInfo & SetPALTV ) )
+ tempax |= 0x1000 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ tempax |= 0x0100 ;
+
+ if ( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) )
+ tempax &= 0xfe00 ;
+
+ tempax = ( tempax & 0xff00 ) >> 8 ;
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x0 , tempax ) ;
+ TimingPoint = pVBInfo->NTSCTiming ;
+
+ if ( pVBInfo->TVInfo & SetPALTV )
+ {
+ TimingPoint = pVBInfo->PALTiming ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ TimingPoint = pVBInfo->HiTVExtTiming ;
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ TimingPoint = pVBInfo->HiTVSt2Timing ;
+
+ if ( pVBInfo->SetFlag & TVSimuMode )
+ TimingPoint = pVBInfo->HiTVSt1Timing ;
+
+ if ( !(modeflag & Charx8Dot) )
+ TimingPoint = pVBInfo->HiTVTextTiming ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode525i )
+ TimingPoint = pVBInfo->YPbPr525iTiming ;
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ TimingPoint = pVBInfo->YPbPr525pTiming ;
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ TimingPoint = pVBInfo->YPbPr750pTiming ;
+ }
+
+ for( i = 0x01 , j = 0 ; i <= 0x2D ; i++ , j++ )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ;
+ }
+
+ for( i = 0x39 ; i <= 0x45 ; i++ , j++ )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ; /* di->temp2[j] */
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x3A , 0x1F , 0x00 ) ;
+ }
+
+ temp = pVBInfo->NewFlickerMode ;
+ temp &= 0x80 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0xFF , temp ) ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ tempax = 950 ;
+
+ if ( pVBInfo->TVInfo & SetPALTV )
+ tempax = 520 ;
+ else
+ tempax = 440 ;
+
+ if ( pVBInfo->VDE <= tempax )
+ {
+ tempax -= pVBInfo->VDE ;
+ tempax = tempax >> 2 ;
+ tempax = ( tempax & 0x00FF ) | ( ( tempax & 0x00FF ) << 8 ) ;
+ push1 = tempax ;
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ temp += ( USHORT )TimingPoint[ 0 ] ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr ) )
+ {
+ tempcx=pVBInfo->VGAHDE;
+ if ( tempcx >= 1024 )
+ {
+ temp = 0x17 ; /* NTSC */
+ if ( pVBInfo->TVInfo & SetPALTV )
+ temp = 0x19 ; /* PAL */
+ }
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x01 , temp ) ;
+ tempax = push1 ;
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ temp += TimingPoint[ 1 ] ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( ( pVBInfo->VBInfo & ( SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr ) ) )
+ {
+ tempcx = pVBInfo->VGAHDE ;
+ if ( tempcx >= 1024 )
+ {
+ temp = 0x1D ; /* NTSC */
+ if ( pVBInfo->TVInfo & SetPALTV )
+ temp = 0x52 ; /* PAL */
+ }
+ }
+ }
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x02 , temp ) ;
+ }
+
+ /* 301b */
+ tempcx = pVBInfo->HT ;
+
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ tempcx = tempcx >> 1 ;
+
+ tempcx -= 2 ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x1B , temp ) ;
+
+ temp = ( tempcx & 0xFF00 ) >> 8 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1D , ~0x0F , temp ) ;
+
+ tempcx = pVBInfo->HT >> 1 ;
+ push1 = tempcx ; /* push cx */
+ tempcx += 7 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ tempcx -= 4 ;
+ }
+
+ temp = tempcx & 0x00FF ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x22 , 0x0F , temp ) ;
+
+ tempbx = TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ;
+ tempbx += tempcx ;
+ push2 = tempbx ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x24 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR(pVBInfo->Part2Port,0x25,0x0F,temp);
+
+ tempbx=push2;
+ tempbx=tempbx+8;
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ tempbx=tempbx-4;
+ tempcx=tempbx;
+ }
+
+ temp = ( tempbx & 0x00FF ) << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x29 , 0x0F , temp ) ;
+
+ j += 2 ;
+ tempcx += ( TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ) ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x27 , temp ) ;
+ temp = ( ( tempcx & 0xFF00 ) >> 8 ) << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x28 , 0x0F , temp ) ;
+
+ tempcx += 8 ;
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ tempcx -= 4 ;
+ }
+
+ temp = tempcx & 0xFF ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2A , 0x0F , temp ) ;
+
+ tempcx = push1 ; /* pop cx */
+ j += 2 ;
+ temp = TimingPoint[ j ] | ( ( TimingPoint[ j + 1 ] ) << 8 ) ;
+ tempcx -= temp ;
+ temp = tempcx & 0x00FF ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2D , 0x0F ,temp ) ;
+
+ tempcx -= 11 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) )
+ {
+ tempax = XGI_GetVGAHT2( pVBInfo) ;
+ tempcx = tempax - 1 ;
+ }
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x2E , temp ) ;
+
+ tempbx = pVBInfo->VDE ;
+
+ if ( pVBInfo->VGAVDE == 360 )
+ tempbx = 746 ;
+ if ( pVBInfo->VGAVDE == 375 )
+ tempbx = 746 ;
+ if ( pVBInfo->VGAVDE == 405 )
+ tempbx = 853 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) )
+ tempbx = tempbx >> 1 ;
+ }
+ else
+ tempbx = tempbx >> 1 ;
+ }
+
+ tempbx -= 2 ;
+ temp = tempbx & 0x00FF ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode1080i )
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( ModeNo == 0x2f )
+ temp += 1 ;
+ }
+ }
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( ModeNo == 0x2f )
+ temp += 1 ;
+ }
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x2F , temp ) ;
+
+ temp = ( tempcx & 0xFF00 ) >> 8 ;
+ temp |= ( ( tempbx & 0xFF00 ) >> 8 ) << 6 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode1080i )
+ {
+ temp |= 0x10 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) )
+ temp |= 0x20 ;
+ }
+ }
+ else
+ {
+ temp |= 0x10 ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToSVIDEO ) )
+ temp |= 0x20 ;
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x30 , temp ) ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) ) /* TV gatingno */
+ {
+ tempbx = pVBInfo->VDE ;
+ tempcx = tempbx - 2 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) )
+ tempbx = tempbx >> 1 ;
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) )
+ {
+ temp=0;
+ if( tempcx & 0x0400 )
+ temp |= 0x20 ;
+
+ if ( tempbx & 0x0400 )
+ temp |= 0x40 ;
+
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x10 , temp ) ;
+ }
+
+ temp = ( ( ( tempbx - 3 ) & 0x0300 ) >> 8 ) << 5 ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x46 , temp ) ;
+ temp = ( tempbx - 3 ) & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x47 , temp ) ;
+ }
+
+ tempbx = tempbx & 0x00FF ;
+
+ if ( !( modeflag & HalfDCLK ) )
+ {
+ tempcx = pVBInfo->VGAHDE ;
+ if ( tempcx >= pVBInfo->HDE )
+ {
+ tempbx |= 0x2000 ;
+ tempax &= 0x00FF ;
+ }
+ }
+
+ tempcx = 0x0101 ;
+
+ if( pVBInfo->VBInfo & SetCRT2ToTV ) { /*301b*/
+ if(pVBInfo->VGAHDE>=1024)
+ {
+ tempcx=0x1920;
+ if(pVBInfo->VGAHDE>=1280)
+ {
+ tempcx=0x1420;
+ tempbx=tempbx&0xDFFF;
+ }
+ }
+ }
+
+ if ( !( tempbx & 0x2000 ) )
+ {
+ if ( modeflag & HalfDCLK )
+ {
+ tempcx = ( tempcx & 0xFF00 ) | ( ( tempcx & 0x00FF ) << 1 ) ;
+ }
+
+ push1 = tempbx ;
+ tempeax = pVBInfo->VGAHDE ;
+ tempebx = ( tempcx & 0xFF00 ) >> 8 ;
+ longtemp = tempeax * tempebx ;
+ tempecx = tempcx & 0x00FF ;
+ longtemp = longtemp / tempecx ;
+
+ /* 301b */
+ tempecx = 8 * 1024 ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempecx = tempecx * 8 ;
+ }
+
+ longtemp = longtemp * tempecx ;
+ tempecx = pVBInfo->HDE ;
+ temp2 = longtemp % tempecx ;
+ tempeax = longtemp / tempecx ;
+ if ( temp2 != 0 )
+ {
+ tempeax += 1 ;
+ }
+
+ tempax = ( USHORT )tempeax ;
+
+ /* 301b */
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempcx = ( ( tempax & 0xFF00 ) >> 5 ) >> 8 ;
+ }
+ /* end 301b */
+
+ tempbx = push1 ;
+ tempbx =( USHORT )( ( ( tempeax & 0x0000FF00 ) & 0x1F00 ) | ( tempbx & 0x00FF ) ) ;
+ tempax =( USHORT )( ( ( tempeax & 0x000000FF ) << 8 ) | ( tempax & 0x00FF ) ) ;
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ }
+ else
+ {
+ temp = ( tempax & 0x00FF ) >> 8 ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x44 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x45 , ~0x03F , temp ) ;
+ temp = tempcx & 0x00FF ;
+
+ if ( tempbx & 0x2000 )
+ temp = 0 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) )
+ temp |= 0x18 ;
+
+ XGINew_SetRegANDOR(pVBInfo->Part2Port,0x46,~0x1F,temp);
+ if ( pVBInfo->TVInfo & SetPALTV )
+ {
+ tempbx = 0x0382 ;
+ tempcx = 0x007e ;
+ }
+ else
+ {
+ tempbx = 0x0369 ;
+ tempcx = 0x0061 ;
+ }
+
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x4b , temp ) ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x4c , temp ) ;
+
+ temp = ( ( tempcx & 0xFF00 ) >> 8 ) & 0x03 ;
+ temp = temp << 2 ;
+ temp |= ( ( tempbx & 0xFF00 ) >> 8 ) & 0x03 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ temp |= 0x10 ;
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ temp |= 0x20 ;
+
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ temp |= 0x60 ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x4d , temp ) ;
+ temp=XGINew_GetReg1( pVBInfo->Part2Port , 0x43 ) ; /* 301b change */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x43 , ( USHORT )( temp - 3 ) ) ;
+
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) )
+ {
+ if ( pVBInfo->TVInfo & NTSC1024x768 )
+ {
+ TimingPoint = XGI_NTSC1024AdjTime ;
+ for( i = 0x1c , j = 0 ; i <= 0x30 ; i++ , j++ )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , i , TimingPoint[ j ] ) ;
+ }
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x43 , 0x72 ) ;
+ }
+ }
+
+ /* [ycchen] 01/14/03 Modify for 301C PALM Support */
+ if ( pVBInfo->VBType & VB_XGI301C )
+ {
+ if ( pVBInfo->TVInfo & SetPALMTV )
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x08 , 0x08 ) ; /* PALM Mode */
+ }
+
+ if ( pVBInfo->TVInfo & SetPALMTV )
+ {
+ tempax = ( UCHAR )XGINew_GetReg1( pVBInfo->Part2Port , 0x01 ) ;
+ tempax-- ;
+ XGINew_SetRegAND( pVBInfo->Part2Port , 0x01 , tempax ) ;
+
+ /* if ( !( pVBInfo->VBType & VB_XGI301C ) ) */
+ XGINew_SetRegAND( pVBInfo->Part2Port , 0x00 , 0xEF ) ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( !( pVBInfo->VBInfo & SetInSlaveMode ) )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x0B , 0x00 ) ;
+ }
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ return ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLCDRegs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLCDRegs(USHORT ModeNo,USHORT ModeIdIndex, PXGI_HW_DEVICE_INFO HwDeviceExtension,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT push1 ,
+ push2 ,
+ pushbx ,
+ tempax ,
+ tempbx ,
+ tempcx ,
+ temp ,
+ tempah ,
+ tempbh ,
+ tempch ,
+ resinfo ,
+ modeflag ,
+ CRT1Index ;
+
+ XGI_LCDDesStruct *LCDBDesPtr = NULL ;
+
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ CRT1Index &= IndexMask ;
+ }
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) )
+ {
+ return ;
+ }
+
+ tempbx = pVBInfo->HDE ; /* RHACTE=HDE-1 */
+
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ tempbx = tempbx >> 1 ;
+
+ tempbx -= 1 ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x2C , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x2B , 0x0F , temp ) ;
+ temp = 0x01 ;
+
+ if ( pVBInfo->LCDResInfo == Panel1280x1024 )
+ {
+ if ( pVBInfo->ModeType == ModeEGA )
+ {
+ if ( pVBInfo->VGAHDE >= 1024 )
+ {
+ temp = 0x02 ;
+ if ( pVBInfo->LCDInfo & LCDVESATiming )
+ temp = 0x01 ;
+ }
+ }
+ }
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x0B , temp ) ;
+ tempbx = pVBInfo->VDE ; /* RTVACTEO=(VDE-1)&0xFF */
+ push1 = tempbx ;
+ tempbx-- ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x03 , temp ) ;
+ temp = ( ( tempbx & 0xFF00 ) >> 8 ) & 0x07 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0C , ~0x07 , temp ) ;
+
+ tempcx = pVBInfo->VT - 1 ;
+ push2 = tempcx + 1 ;
+ temp = tempcx & 0x00FF ; /* RVTVT=VT-1 */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x19 , temp ) ;
+ temp = ( tempcx & 0xFF00 ) >> 8 ;
+ temp = temp << 5 ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x1A , temp ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x09 , 0xF0 , 0x00 ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0xF0 , 0x00 ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x17 , 0xFB , 0x00 ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x18 , 0xDF , 0x00 ) ;
+
+ /* Customized LCDB Des no add */
+ tempbx = 5 ;
+ LCDBDesPtr = ( XGI_LCDDesStruct * )XGI_GetLcdPtr( tempbx , ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+ tempah = pVBInfo->LCDResInfo ;
+ tempah &= PanelResInfo ;
+
+ if ( ( tempah == Panel1024x768 ) || ( tempah == Panel1024x768x75 ) )
+ {
+ tempbx = 1024 ;
+ tempcx = 768 ;
+ }
+ else if ( ( tempah == Panel1280x1024 ) || ( tempah == Panel1280x1024x75 ) )
+ {
+ tempbx = 1280 ;
+ tempcx = 1024 ;
+ }
+ else if ( tempah == Panel1400x1050 )
+ {
+ tempbx = 1400 ;
+ tempcx = 1050 ;
+ }
+ else
+ {
+ tempbx = 1600 ;
+ tempcx = 1200 ;
+ }
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ {
+ tempbx = pVBInfo->HDE ;
+ tempcx = pVBInfo->VDE ;
+ }
+
+ pushbx = tempbx ;
+ tempax = pVBInfo->VT ;
+ pVBInfo->LCDHDES = LCDBDesPtr->LCDHDES ;
+ pVBInfo->LCDHRS = LCDBDesPtr->LCDHRS ;
+ pVBInfo->LCDVDES = LCDBDesPtr->LCDVDES ;
+ pVBInfo->LCDVRS = LCDBDesPtr->LCDVRS ;
+ tempbx = pVBInfo->LCDVDES ;
+ tempcx += tempbx ;
+
+ if ( tempcx >= tempax )
+ tempcx -= tempax ; /* lcdvdes */
+
+ temp = tempbx & 0x00FF ; /* RVEQ1EQ=lcdvdes */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x05 , temp ) ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x06 , temp ) ;
+ tempch = ( ( tempcx & 0xFF00 ) >> 8 ) & 0x07 ;
+ tempbh = ( ( tempbx & 0xFF00 ) >> 8 ) & 0x07 ;
+ tempah = tempch ;
+ tempah = tempah << 3 ;
+ tempah |= tempbh ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x02 , tempah ) ;
+
+ /* getlcdsync() */
+ XGI_GetLCDSync( &tempax , &tempbx,pVBInfo ) ;
+ tempcx = tempbx ;
+ tempax = pVBInfo->VT ;
+ tempbx = pVBInfo->LCDVRS ;
+
+ /* if ( SetLCD_Info & EnableScalingLCD ) */
+ tempcx += tempbx ;
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ temp = tempbx & 0x00FF ; /* RTVACTEE=lcdvrs */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x04 , temp ) ;
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp = temp << 4 ;
+ temp |= ( tempcx & 0x000F ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x01 , temp ) ;
+ tempcx = pushbx ;
+ tempax = pVBInfo->HT ;
+ tempbx = pVBInfo->LCDHDES ;
+ tempbx &= 0x0FFF ;
+
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ {
+ tempax = tempax >> 1 ;
+ tempbx = tempbx >> 1 ;
+ tempcx = tempcx >> 1 ;
+ }
+
+ if ( pVBInfo->VBType & VB_XGI302LV )
+ tempbx += 1 ;
+
+ if ( pVBInfo->VBType & VB_XGI301C ) /* tap4 */
+ tempbx += 1 ;
+
+ tempcx += tempbx ;
+
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x1F , temp ) ; /* RHBLKE=lcdhdes */
+ temp = ( ( tempbx & 0xFF00 ) >> 8 ) << 4 ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x20 , temp ) ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x23 , temp ) ; /* RHEQPLE=lcdhdee */
+ temp = ( tempcx & 0xFF00 ) >> 8 ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x25 , temp ) ;
+
+ /* getlcdsync() */
+ XGI_GetLCDSync( &tempax , &tempbx ,pVBInfo) ;
+ tempcx = tempax ;
+ tempax = pVBInfo->HT ;
+ tempbx = pVBInfo->LCDHRS ;
+ /* if ( SetLCD_Info & EnableScalingLCD) */
+ if ( XGI_IsLCDDualLink( pVBInfo) )
+ {
+ tempax = tempax >> 1 ;
+ tempbx = tempbx >> 1 ;
+ tempcx = tempcx >> 1 ;
+ }
+
+ if ( pVBInfo->VBType & VB_XGI302LV )
+ tempbx += 1 ;
+
+ tempcx += tempbx ;
+
+ if ( tempcx >= tempax )
+ tempcx -= tempax ;
+
+ temp = tempbx & 0x00FF ; /* RHBURSTS=lcdhrs */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x1C , temp ) ;
+
+ temp = ( tempbx & 0xFF00 ) >> 8 ;
+ temp = temp << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1D , ~0x0F0 , temp ) ;
+ temp = tempcx & 0x00FF ; /* RHSYEXP2S=lcdhre */
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x21 , temp ) ;
+
+ if ( !( pVBInfo->LCDInfo & LCDVESATiming ) )
+ {
+ if ( pVBInfo->VGAVDE == 525 )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ temp = 0xC6 ;
+ }
+ else
+ temp = 0xC4 ;
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x2f , temp ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x30 , 0xB3 ) ;
+ }
+
+ if ( pVBInfo->VGAVDE == 420 )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ temp = 0x4F ;
+ }
+ else
+ temp = 0x4E ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x2f , temp ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetTap4Ptr */
+/* Input : */
+/* Output : di -> Tap4 Reg. Setting Pointer */
+/* Description : */
+/* --------------------------------------------------------------------- */
+XGI301C_Tap4TimingStruct* XGI_GetTap4Ptr(USHORT tempcx, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax ,
+ tempbx ,
+ i ;
+
+ XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
+
+ if ( tempcx == 0 )
+ {
+ tempax = pVBInfo->VGAHDE ;
+ tempbx = pVBInfo->HDE ;
+ }
+ else
+ {
+ tempax = pVBInfo->VGAVDE ;
+ tempbx = pVBInfo->VDE ;
+ }
+
+ if ( tempax < tempbx )
+ return &EnlargeTap4Timing[ 0 ] ;
+ else if( tempax == tempbx )
+ return &NoScaleTap4Timing[ 0 ] ; /* 1:1 */
+ else
+ Tap4TimingPtr = NTSCTap4Timing ; /* NTSC */
+
+ if ( pVBInfo->TVInfo & SetPALTV )
+ Tap4TimingPtr = PALTap4Timing ;
+
+
+ if ( pVBInfo->VBInfo & SetCRT2ToYPbPr )
+ {
+ if ( pVBInfo->TVInfo & SetYPbPrMode525i )
+ Tap4TimingPtr = YPbPr525iTap4Timing ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ Tap4TimingPtr = YPbPr525pTap4Timing ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ Tap4TimingPtr = YPbPr750pTap4Timing ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ Tap4TimingPtr = HiTVTap4Timing ;
+
+ i = 0 ;
+ while( Tap4TimingPtr[ i ].DE != 0xFFFF )
+ {
+ if ( Tap4TimingPtr[ i ].DE == tempax )
+ break ;
+ i++ ;
+ }
+ return &Tap4TimingPtr[ i ] ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetTap4Regs */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetTap4Regs( PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT i ,
+ j ;
+
+ XGI301C_Tap4TimingStruct *Tap4TimingPtr ;
+
+ if ( !( pVBInfo->VBType & VB_XGI301C ) )
+ return ;
+
+#ifndef Tap4
+ XGINew_SetRegAND( pVBInfo->Part2Port , 0x4E , 0xEB ) ; /* Disable Tap4 */
+#else /* Tap4 Setting */
+
+ Tap4TimingPtr = XGI_GetTap4Ptr( 0 , pVBInfo) ; /* Set Horizontal Scaling */
+ for( i = 0x80 , j = 0 ; i <= 0xBF ; i++ , j++ )
+ XGINew_SetReg1( pVBInfo->Part2Port , i , Tap4TimingPtr->Reg[ j ] ) ;
+
+ if ( ( pVBInfo->VBInfo & SetCRT2ToTV ) && ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) )
+ {
+ Tap4TimingPtr = XGI_GetTap4Ptr( 1 , pVBInfo); /* Set Vertical Scaling */
+ for( i = 0xC0 , j = 0 ; i < 0xFF ; i++ , j++ )
+ XGINew_SetReg1( pVBInfo->Part2Port , i , Tap4TimingPtr->Reg[ j ] ) ;
+ }
+
+ if ( ( pVBInfo->VBInfo & SetCRT2ToTV ) && ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) )
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x14 , 0x04 ) ; /* Enable V.Scaling */
+ else
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x4E , ~0x14 , 0x10 ) ; /* Enable H.Scaling */
+#endif
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGroup3 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGroup3(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT i;
+ UCHAR *tempdi;
+ USHORT modeflag;
+
+ if(ModeNo<=0x13)
+ {
+ modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; /* si+Ext_ResInfo */
+ }
+
+
+ XGINew_SetReg1(pVBInfo->Part3Port,0x00,0x00);
+ if(pVBInfo->TVInfo&SetPALTV)
+ {
+ XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xFA);
+ XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xC8);
+ }
+ else
+ {
+ XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xF5);
+ XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xB7);
+ }
+
+ if(!(pVBInfo->VBInfo&SetCRT2ToTV))
+ {
+ return;
+ }
+
+ if(pVBInfo->TVInfo&SetPALMTV)
+ {
+ XGINew_SetReg1(pVBInfo->Part3Port,0x13,0xFA);
+ XGINew_SetReg1(pVBInfo->Part3Port,0x14,0xC8);
+ XGINew_SetReg1(pVBInfo->Part3Port,0x3D,0xA8);
+ }
+
+ if((pVBInfo->VBInfo&SetCRT2ToHiVisionTV)|| (pVBInfo->VBInfo&SetCRT2ToYPbPr))
+ {
+ if(pVBInfo->TVInfo & SetYPbPrMode525i)
+ {
+ return;
+ }
+ tempdi=pVBInfo->HiTVGroup3Data;
+ if(pVBInfo->SetFlag&TVSimuMode)
+ {
+ tempdi=pVBInfo->HiTVGroup3Simu;
+ if(!(modeflag&Charx8Dot))
+ {
+ tempdi=pVBInfo->HiTVGroup3Text;
+ }
+ }
+
+ if(pVBInfo->TVInfo & SetYPbPrMode525p)
+ {
+ tempdi=pVBInfo->Ren525pGroup3;
+ }
+ if(pVBInfo->TVInfo & SetYPbPrMode750p)
+ {
+ tempdi=pVBInfo->Ren750pGroup3;
+ }
+
+ for(i=0;i<=0x3E;i++)
+ {
+ XGINew_SetReg1(pVBInfo->Part3Port,i,tempdi[i]);
+ }
+ if(pVBInfo->VBType&VB_XGI301C) /* Marcovision */
+ {
+ if(pVBInfo->TVInfo & SetYPbPrMode525p)
+ {
+ XGINew_SetReg1(pVBInfo->Part3Port,0x28,0x3f);
+ }
+ }
+ }
+ return;
+} /* {end of XGI_SetGroup3} */
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGroup4 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGroup4(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax ,
+ tempcx ,
+ tempbx ,
+ modeflag ,
+ temp ,
+ temp2 ;
+
+ ULONG tempebx ,
+ tempeax ,
+ templong ;
+
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ }
+
+ temp = pVBInfo->RVBHCFACT ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x13 , temp ) ;
+
+ tempbx = pVBInfo->RVBHCMAX ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x14 , temp ) ;
+ temp2 = ( ( tempbx & 0xFF00 ) >> 8 ) << 7 ;
+ tempcx = pVBInfo->VGAHT - 1 ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x16 , temp ) ;
+
+ temp =( ( tempcx & 0xFF00 ) >> 8 ) << 3 ;
+ temp2 |= temp ;
+
+ tempcx = pVBInfo->VGAVT - 1 ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) )
+ {
+ tempcx -= 5 ;
+ }
+
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x17 , temp ) ;
+ temp = temp2 | ( ( tempcx & 0xFF00 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x15 , temp ) ;
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x0D , 0x08 ) ;
+ tempcx = pVBInfo->VBInfo ;
+ tempbx = pVBInfo->VGAHDE ;
+
+ if ( modeflag & HalfDCLK )
+ {
+ tempbx = tempbx >> 1 ;
+ }
+
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ tempbx = tempbx >> 1 ;
+
+ if(tempcx&SetCRT2ToHiVisionTV)
+ {
+ temp=0;
+ if(tempbx<=1024)
+ temp=0xA0;
+ if(tempbx == 1280)
+ temp = 0xC0;
+ }
+ else if(tempcx&SetCRT2ToTV)
+ {
+ temp=0xA0;
+ if(tempbx <= 800)
+ temp=0x80;
+ }
+ else
+ {
+ temp=0x80;
+ if(pVBInfo->VBInfo&SetCRT2ToLCD)
+ {
+ temp=0;
+ if(tempbx>800)
+ temp=0x60;
+ }
+ }
+
+ if ( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) )
+ {
+ temp = 0x00 ;
+ if ( pVBInfo->VGAHDE == 1280 )
+ temp = 0x40 ;
+ if ( pVBInfo->VGAHDE == 1024 )
+ temp = 0x20 ;
+ }
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0E , ~0xEF , temp ) ;
+
+ tempebx = pVBInfo->VDE ;
+
+ if ( tempcx & SetCRT2ToHiVisionTV )
+ {
+ if ( !( temp & 0xE000 ) )
+ tempbx = tempbx >> 1 ;
+ }
+
+ tempcx = pVBInfo->RVBHRS ;
+ temp = tempcx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x18 , temp );
+
+ tempeax = pVBInfo->VGAVDE ;
+ tempcx |= 0x04000 ;
+
+
+ if ( tempeax <= tempebx )
+ {
+ tempcx=(tempcx&(~0x4000));
+ tempeax = pVBInfo->VGAVDE ;
+ }
+ else
+ {
+ tempeax -= tempebx ;
+ }
+
+
+ templong = ( tempeax * 256 * 1024 ) % tempebx ;
+ tempeax = ( tempeax * 256 * 1024 ) / tempebx ;
+ tempebx = tempeax ;
+
+ if ( templong != 0 )
+ {
+ tempebx++ ;
+ }
+
+
+ temp = ( USHORT )( tempebx & 0x000000FF ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x1B , temp ) ;
+
+ temp = ( USHORT )( ( tempebx & 0x0000FF00 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x1A , temp ) ;
+ tempbx = ( USHORT )( tempebx >> 16 ) ;
+ temp = tempbx & 0x00FF ;
+ temp = temp << 4 ;
+ temp |= ( ( tempcx & 0xFF00 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x19 , temp ) ;
+
+ /* 301b */
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ temp = 0x0028 ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x1C , temp ) ;
+ tempax = pVBInfo->VGAHDE ;
+ if ( modeflag & HalfDCLK )
+ {
+ tempax = tempax >> 1 ;
+ }
+
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ tempax = tempax >> 1 ;
+
+ /* if((pVBInfo->VBInfo&(SetCRT2ToLCD))||((pVBInfo->TVInfo&SetYPbPrMode525p)||(pVBInfo->TVInfo&SetYPbPrMode750p))) { */
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ {
+ if ( tempax > 800 )
+ tempax -= 800 ;
+ }
+ else
+ {
+ if ( pVBInfo->VGAHDE > 800 )
+ {
+ if ( pVBInfo->VGAHDE == 1024 )
+ tempax = ( tempax * 25 / 32 ) - 1 ;
+ else
+ tempax = ( tempax * 20 / 32 ) - 1 ;
+ }
+ }
+ tempax -= 1 ;
+
+/*
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToHiVisionTV ) )
+ {
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) )
+ {
+ if ( pVBInfo->VGAHDE > 800 )
+ {
+ if ( pVBInfo->VGAHDE == 1024 )
+ tempax = ( tempax * 25 / 32 ) - 1 ;
+ else
+ tempax = ( tempax * 20 / 32 ) - 1 ;
+ }
+ }
+ }
+ else
+ {
+ if ( pVBInfo->VGAHDE > 800 )
+ {
+ if ( pVBInfo->VGAHDE == 1024 )
+ tempax = ( tempax * 25 / 32 ) - 1 ;
+ else
+ tempax = ( tempax * 20 / 32 ) - 1 ;
+ }
+ }
+ }
+*/
+
+ temp = ( tempax & 0xFF00 ) >> 8 ;
+ temp = ( ( temp & 0x0003 ) << 4 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x1E , temp ) ;
+ temp = ( tempax & 0x00FF ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x1D , temp ) ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToHiVisionTV ) )
+ {
+ if ( pVBInfo->VGAHDE > 800 )
+ {
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x1E , 0x08 ) ;
+ }
+ }
+ temp = 0x0036 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( !( pVBInfo->TVInfo & ( NTSC1024x768 | SetYPbPrMode525p | SetYPbPrMode750p | SetYPbPrMode1080i ) ) )
+ {
+ temp |= 0x0001 ;
+ if ( ( pVBInfo->VBInfo & SetInSlaveMode ) && ( !( pVBInfo->TVInfo & TVSimuMode ) ) )
+ temp &= ( ~0x0001 ) ;
+ }
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x1F , 0x00C0 , temp ) ;
+ tempbx = pVBInfo->HT ;
+ if ( XGI_IsLCDDualLink( pVBInfo ) )
+ tempbx = tempbx >> 1 ;
+ tempbx = ( tempbx >> 1 ) - 2 ;
+ temp = ( ( tempbx & 0x0700 ) >> 8 ) << 3 ;
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x21 , 0x00C0 , temp ) ;
+ temp = tempbx & 0x00FF ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x22 , temp ) ;
+ }
+ /* end 301b */
+
+ if ( pVBInfo->ISXPDOS == 0 )
+ XGI_SetCRT2VCLK( ModeNo , ModeIdIndex , RefreshRateTableIndex, pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetGroup5 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetGroup5( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT Pindex ,
+ Pdata ;
+
+ Pindex = pVBInfo->Part5Port ;
+ Pdata = pVBInfo->Part5Port + 1 ;
+ if ( pVBInfo->ModeType == ModeVGA )
+ {
+ if ( !( pVBInfo->VBInfo & ( SetInSlaveMode | LoadDACFlag | CRT2DisplayFlag ) ) )
+ {
+ XGINew_EnableCRT2(pVBInfo) ;
+ /* LoadDAC2(pVBInfo->Part5Port,ModeNo,ModeIdIndex); */
+ }
+ }
+ return ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLcdPtr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void* XGI_GetLcdPtr( USHORT BX , USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT i ,
+ tempdx ,
+ tempcx ,
+ tempbx ,
+ tempal ,
+ modeflag ,
+ table ;
+
+ XGI330_LCDDataTablStruct *tempdi = 0 ;
+
+
+ tempbx = BX;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ;
+ }
+
+ tempal = tempal & 0x0f ;
+
+ if ( tempbx <= 1 ) /* ExpLink */
+ {
+ if ( ModeNo <= 0x13 )
+ {
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ; /* find no Ext_CRT2CRTC2 */
+ }
+ else
+ {
+ tempal= pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ if ( ModeNo <= 0x13 )
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC2 ;
+ else
+ tempal= pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC2 ;
+ }
+
+ if ( tempbx & 0x01 )
+ tempal = ( tempal >> 4 ) ;
+
+ tempal = ( tempal & 0x0f ) ;
+ }
+
+ tempcx = LCDLenList[ tempbx ] ; /* mov cl,byte ptr cs:LCDLenList[bx] */
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD ) /* ScaleLCD */
+ {
+ if ( ( tempbx == 5 ) || ( tempbx ) == 7 )
+ tempcx = LCDDesDataLen2 ;
+ else if ( ( tempbx == 3 ) || ( tempbx == 8 ) )
+ tempcx = LVDSDesDataLen2 ;
+ }
+ /* mov di, word ptr cs:LCDDataList[bx] */
+ /* tempdi=pVideoMemory[LCDDataList+tempbx*2]|(pVideoMemory[LCDDataList+tempbx*2+1]<<8); */
+
+ switch( tempbx )
+ {
+ case 0:
+ tempdi = XGI_EPLLCDCRT1Ptr_H ;
+ break ;
+ case 1:
+ tempdi = XGI_EPLLCDCRT1Ptr_V ;
+ break ;
+ case 2:
+ tempdi = XGI_EPLLCDDataPtr ;
+ break ;
+ case 3:
+ tempdi = XGI_EPLLCDDesDataPtr ;
+ break ;
+ case 4:
+ tempdi = XGI_LCDDataTable ;
+ break ;
+ case 5:
+ tempdi = XGI_LCDDesDataTable ;
+ break ;
+ case 6:
+ tempdi = XGI_EPLCHLCDRegPtr ;
+ break ;
+ case 7:
+ case 8:
+ case 9:
+ tempdi = 0 ;
+ break ;
+ default:
+ break ;
+ }
+
+ if ( tempdi == 0x00 ) /* OEMUtil */
+ return 0 ;
+
+ table = tempbx ;
+ i = 0 ;
+
+ while( tempdi[ i ].PANELID != 0xff )
+ {
+ tempdx = pVBInfo->LCDResInfo ;
+ if ( tempbx & 0x0080 ) /* OEMUtil */
+ {
+ tempbx &= ( ~0x0080 ) ;
+ tempdx = pVBInfo->LCDTypeInfo ;
+ }
+
+ if ( pVBInfo->LCDInfo & EnableScalingLCD )
+ tempdx &= ( ~PanelResInfo ) ;
+
+ if ( tempdi[ i ].PANELID == tempdx )
+ {
+ tempbx = tempdi[ i ].MASK ;
+ tempdx = pVBInfo->LCDInfo ;
+
+ if ( ModeNo <= 0x13 ) /* alan 09/10/2003 */
+ tempdx |= SetLCDStdMode ;
+
+ if ( modeflag & HalfDCLK )
+ tempdx |= SetLCDLowResolution ;
+
+ tempbx &= tempdx;
+ if ( tempbx == tempdi[ i ].CAP )
+ break ;
+ }
+ i++ ;
+ }
+
+ if ( table == 0 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_LVDSCRT11024x768_1_H[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_LVDSCRT11024x768_2_H[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_LVDSCRT11280x1024_1_H[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_LVDSCRT11280x1024_2_H[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_LVDSCRT11400x1050_1_H[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_LVDSCRT11400x1050_2_H[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_LVDSCRT11600x1200_1_H[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_LVDSCRT11024x768_1_Hx75[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_LVDSCRT11024x768_2_Hx75[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_LVDSCRT11280x1024_1_Hx75[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_LVDSCRT11280x1024_2_Hx75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 1 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_LVDSCRT11024x768_1_V[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_LVDSCRT11024x768_2_V[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_LVDSCRT11280x1024_1_V[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_LVDSCRT11280x1024_2_V[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_LVDSCRT11400x1050_1_V[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_LVDSCRT11400x1050_2_V[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_LVDSCRT11600x1200_1_V[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_LVDSCRT11024x768_1_Vx75[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_LVDSCRT11024x768_2_Vx75[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_LVDSCRT11280x1024_1_Vx75[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_LVDSCRT11280x1024_2_Vx75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 2 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_LVDS1024x768Data_1[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_LVDS1024x768Data_2[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_LVDS1280x1024Data_1[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_LVDS1280x1024Data_2[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_LVDS1400x1050Data_1[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_LVDS1400x1050Data_2[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_LVDS1600x1200Data_1[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_LVDSNoScalingData[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_LVDS1024x768Data_1x75[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_LVDS1024x768Data_2x75[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_LVDS1280x1024Data_1x75[ tempal ] ;
+ break ;
+ case 11:
+ return &XGI_LVDS1280x1024Data_2x75[ tempal ] ;
+ break ;
+ case 12:
+ return &XGI_LVDSNoScalingDatax75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 3 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_LVDS1024x768Des_1[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_LVDS1024x768Des_3[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_LVDS1024x768Des_2[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_LVDS1280x1024Des_1[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_LVDS1280x1024Des_2[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_LVDS1400x1050Des_1[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_LVDS1400x1050Des_2[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_LVDS1600x1200Des_1[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_LVDSNoScalingDesData[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_LVDS1024x768Des_1x75[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_LVDS1024x768Des_3x75[ tempal ] ;
+ break ;
+ case 11:
+ return &XGI_LVDS1024x768Des_2x75[ tempal ] ;
+ break;
+ case 12:
+ return &XGI_LVDS1280x1024Des_1x75[ tempal ] ;
+ break ;
+ case 13:
+ return &XGI_LVDS1280x1024Des_2x75[ tempal ] ;
+ break ;
+ case 14:
+ return &XGI_LVDSNoScalingDesDatax75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 4 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_ExtLCD1024x768Data[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_StLCD1024x768Data[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_CetLCD1024x768Data[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_ExtLCD1280x1024Data[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_StLCD1280x1024Data[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_CetLCD1280x1024Data[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_ExtLCD1400x1050Data[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_StLCD1400x1050Data[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_CetLCD1400x1050Data[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_ExtLCD1600x1200Data[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_StLCD1600x1200Data[ tempal ] ;
+ break ;
+ case 11:
+ return &XGI_NoScalingData[ tempal ] ;
+ break ;
+ case 12:
+ return &XGI_ExtLCD1024x768x75Data[ tempal ] ;
+ break ;
+ case 13:
+ return &XGI_ExtLCD1024x768x75Data[ tempal ] ;
+ break ;
+ case 14:
+ return &XGI_CetLCD1024x768x75Data[ tempal ] ;
+ break ;
+ case 15:
+ return &XGI_ExtLCD1280x1024x75Data[ tempal ] ;
+ break ;
+ case 16:
+ return &XGI_StLCD1280x1024x75Data[ tempal ] ;
+ break;
+ case 17:
+ return &XGI_CetLCD1280x1024x75Data[ tempal ] ;
+ break;
+ case 18:
+ return &XGI_NoScalingDatax75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 5 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_ExtLCDDes1024x768Data[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_StLCDDes1024x768Data[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_CetLCDDes1024x768Data[ tempal ] ;
+ break ;
+ case 3:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_ExtLCDDLDes1280x1024Data[ tempal ] ;
+ else
+ return &XGI_ExtLCDDes1280x1024Data[ tempal ] ;
+ break ;
+ case 4:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_StLCDDLDes1280x1024Data[ tempal ] ;
+ else
+ return &XGI_StLCDDes1280x1024Data[ tempal ] ;
+ break ;
+ case 5:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_CetLCDDLDes1280x1024Data[ tempal ] ;
+ else
+ return &XGI_CetLCDDes1280x1024Data[ tempal ] ;
+ break ;
+ case 6:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_ExtLCDDLDes1400x1050Data[ tempal ] ;
+ else
+ return &XGI_ExtLCDDes1400x1050Data[ tempal ] ;
+ break ;
+ case 7:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_StLCDDLDes1400x1050Data[ tempal ] ;
+ else
+ return &XGI_StLCDDes1400x1050Data[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_CetLCDDes1400x1050Data[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_CetLCDDes1400x1050Data2[ tempal ] ;
+ break ;
+ case 10:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_ExtLCDDLDes1600x1200Data[ tempal ] ;
+ else
+ return &XGI_ExtLCDDes1600x1200Data[ tempal ] ;
+ break ;
+ case 11:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_StLCDDLDes1600x1200Data[ tempal ] ;
+ else
+ return &XGI_StLCDDes1600x1200Data[ tempal ] ;
+ break ;
+ case 12:
+ return &XGI_NoScalingDesData[ tempal ] ;
+ break;
+ case 13:
+ return &XGI_ExtLCDDes1024x768x75Data[ tempal ] ;
+ break ;
+ case 14:
+ return &XGI_StLCDDes1024x768x75Data[ tempal ] ;
+ break ;
+ case 15:
+ return &XGI_CetLCDDes1024x768x75Data[ tempal ] ;
+ break ;
+ case 16:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_ExtLCDDLDes1280x1024x75Data[ tempal ] ;
+ else
+ return &XGI_ExtLCDDes1280x1024x75Data[ tempal ] ;
+ break ;
+ case 17:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_StLCDDLDes1280x1024x75Data[ tempal ] ;
+ else
+ return &XGI_StLCDDes1280x1024x75Data[ tempal ] ;
+ break ;
+ case 18:
+ if ( ( pVBInfo->VBType & VB_XGI301LV ) || ( pVBInfo->VBType & VB_XGI302LV ) )
+ return &XGI_CetLCDDLDes1280x1024x75Data[ tempal ] ;
+ else
+ return &XGI_CetLCDDes1280x1024x75Data[ tempal ] ;
+ break ;
+ case 19:
+ return &XGI_NoScalingDesDatax75[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if ( table == 6 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_CH7017LV1024x768[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_CH7017LV1400x1050[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ return 0 ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetTVPtr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void* XGI_GetTVPtr (USHORT BX,USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT i , tempdx , tempbx , tempal , modeflag , table ;
+ XGI330_TVDataTablStruct *tempdi = 0 ;
+
+ tempbx = BX ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ tempal = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ;
+ }
+
+ tempal = tempal & 0x3f ;
+ table = tempbx ;
+
+ switch( tempbx )
+ {
+ case 0:
+ tempdi = 0 ; /*EPLCHTVCRT1Ptr_H;*/
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ tempdi = XGI_EPLCHTVCRT1Ptr;
+ }
+ break ;
+ case 1:
+ tempdi = 0 ; /*EPLCHTVCRT1Ptr_V;*/
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ tempdi = XGI_EPLCHTVCRT1Ptr;
+ }
+ break ;
+ case 2:
+ tempdi = XGI_EPLCHTVDataPtr ;
+ break ;
+ case 3:
+ tempdi = 0 ;
+ break ;
+ case 4:
+ tempdi = XGI_TVDataTable ;
+ break ;
+ case 5:
+ tempdi = 0 ;
+ break ;
+ case 6:
+ tempdi = XGI_EPLCHTVRegPtr ;
+ break ;
+ default:
+ break ;
+ }
+
+ if ( tempdi == 0x00 ) /* OEMUtil */
+ return( 0 ) ;
+
+ tempdx = pVBInfo->TVInfo ;
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ tempdx = tempdx | SetTVLockMode ;
+
+ if ( modeflag & HalfDCLK )
+ tempdx = tempdx | SetTVLowResolution ;
+
+ i = 0 ;
+
+ while( tempdi[ i ].MASK != 0xffff )
+ {
+ if ( ( tempdx & tempdi[ i ].MASK ) == tempdi[ i ].CAP )
+ break ;
+ i++ ;
+ }
+
+ if ( table == 0x00 ) /* 07/05/22 */
+ {
+#ifdef WIN2000
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &CH7007TVCRT1UNTSC_H[ tempal ] ;
+ break ;
+ case 1:
+ return &CH7007TVCRT1ONTSC_H[ tempal ] ;
+ break ;
+ case 2:
+ return &CH7007TVCRT1UPAL_H[ tempal ] ;
+ break ;
+ case 3:
+ return &CH7007TVCRT1OPAL_H[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+#endif
+ }
+ else if ( table == 0x01 )
+ {
+#ifdef WIN2000
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &CH7007TVCRT1UNTSC_V[ tempal ] ;
+ break ;
+ case 1:
+ return &CH7007TVCRT1ONTSC_V[ tempal ] ;
+ break ;
+ case 2:
+ return &CH7007TVCRT1UPAL_V[ tempal ] ;
+ break ;
+ case 3:
+ return &CH7007TVCRT1OPAL_V[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+#endif
+ }
+ else if ( table == 0x04 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_ExtPALData[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_ExtNTSCData[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_StPALData[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_StNTSCData[ tempal ] ;
+ break ;
+ case 4:
+ return &XGI_ExtHiTVData[ tempal ] ;
+ break ;
+ case 5:
+ return &XGI_St2HiTVData[ tempal ] ;
+ break ;
+ case 6:
+ return &XGI_ExtYPbPr525iData[ tempal ] ;
+ break ;
+ case 7:
+ return &XGI_ExtYPbPr525pData[ tempal ] ;
+ break ;
+ case 8:
+ return &XGI_ExtYPbPr750pData[ tempal ] ;
+ break ;
+ case 9:
+ return &XGI_StYPbPr525iData[ tempal ] ;
+ break ;
+ case 10:
+ return &XGI_StYPbPr525pData[ tempal ] ;
+ break ;
+ case 11:
+ return &XGI_StYPbPr750pData[ tempal ] ;
+ break;
+ case 12: /* avoid system hang */
+ return &XGI_ExtNTSCData[ tempal ] ;
+ break ;
+ case 13:
+ return &XGI_St1HiTVData[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if( table == 0x02 )
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_CHTVUNTSCData[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_CHTVONTSCData[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_CHTVUPALData[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_CHTVOPALData[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else if( table == 0x06 )
+ {
+#ifdef WIN2000
+ if ( pVBInfo->IF_DEF_CH7007 == 1 )
+ {
+ /* VideoDebugPrint((0, "XGI_GetTVPtr: pVBInfo->IF_DEF_CH7007==1\n")); */
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &CH7007TVReg_UNTSC[ tempal ] ;
+ break ;
+ case 1:
+ return &CH7007TVReg_ONTSC[ tempal ] ;
+ break ;
+ case 2:
+ return &CH7007TVReg_UPAL[ tempal ] ;
+ break ;
+ case 3:
+ return &CH7007TVReg_OPAL[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+ else
+ {
+ switch( tempdi[ i ].DATAPTR )
+ {
+ case 0:
+ return &XGI_CHTVRegUNTSC[ tempal ] ;
+ break ;
+ case 1:
+ return &XGI_CHTVRegONTSC[ tempal ] ;
+ break ;
+ case 2:
+ return &XGI_CHTVRegUPAL[ tempal ] ;
+ break ;
+ case 3:
+ return &XGI_CHTVRegOPAL[ tempal ] ;
+ break ;
+ default:
+ break ;
+ }
+ }
+#endif
+ }
+ return( 0 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_BacklightByDrv */
+/* Input : */
+/* Output : TRUE -> Skip backlight control */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_BacklightByDrv( PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR tempah ;
+
+ tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x3A ) ;
+ if ( tempah & BacklightControlBit )
+ return TRUE ;
+ else
+ return FALSE ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_FirePWDDisable */
+/* Input : */
+/* Output : */
+/* Description : Turn off VDD & Backlight : Fire disable procedure */
+/* --------------------------------------------------------------------- */
+/*
+void XGI_FirePWDDisable( PVB_DEVICE_INFO pVBInfo )
+{
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x00 , 0xFC ) ;
+}
+*/
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_FirePWDEnable */
+/* Input : */
+/* Output : */
+/* Description : Turn on VDD & Backlight : Fire enable procedure */
+/* --------------------------------------------------------------------- */
+void XGI_FirePWDEnable(PVB_DEVICE_INFO pVBInfo )
+{
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x26 , 0x03 , 0xFC ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_EnableGatingCRT */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_EnableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x40 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisableGatingCRT */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_DisableGatingCRT(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x63 , 0xBF , 0x00 ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetPanelDelay */
+/* Input : */
+/* Output : */
+/* Description : */
+/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */
+/* : bl : 2 ; T2 : the duration signal on and Vdd on */
+/* : bl : 3 ; T3 : the duration between CPL off and signal off */
+/* : bl : 4 ; T4 : the duration signal off and Vdd off */
+/* --------------------------------------------------------------------- */
+void XGI_SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT index ;
+
+ index = XGI_GetLCDCapPtr(pVBInfo) ;
+
+ if ( tempbl == 1 )
+ XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S1, pVBInfo ) ;
+
+ if ( tempbl == 2 )
+ XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S2, pVBInfo ) ;
+
+ if ( tempbl == 3 )
+ XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S3, pVBInfo ) ;
+
+ if ( tempbl == 4 )
+ XGINew_LCD_Wait_Time( pVBInfo->LCDCapList[ index ].PSC_S4, pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetPanelPower */
+/* Input : */
+/* Output : */
+/* Description : */
+/* I/O : ah = 0011b = 03h ; Backlight on, Power on */
+/* = 0111b = 07h ; Backlight on, Power off */
+/* = 1011b = 0Bh ; Backlight off, Power on */
+/* = 1111b = 0Fh ; Backlight off, Power off */
+/* --------------------------------------------------------------------- */
+void XGI_SetPanelPower(USHORT tempah,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+{
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x26 , tempbl , tempah ) ;
+ else
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x11 , tempbl , tempah ) ;
+}
+
+UCHAR XG21GPIODataTransfer(UCHAR ujDate)
+{
+ UCHAR ujRet = 0;
+ UCHAR i = 0;
+
+ for (i=0; i<8; i++)
+ {
+ ujRet = ujRet << 1;
+ /* ujRet |= GETBITS(ujDate >> i, 0:0); */
+ ujRet |= (ujDate >> i) & 1;
+ }
+
+ return ujRet;
+}
+
+/*----------------------------------------------------------------------------*/
+/* output */
+/* bl[5] : LVDS signal */
+/* bl[1] : LVDS backlight */
+/* bl[0] : LVDS VDD */
+/*----------------------------------------------------------------------------*/
+UCHAR XGI_XG21GetPSCValue(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR4A,temp;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x23 ) ; /* enable GPIO write */
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ;
+
+ temp = XG21GPIODataTransfer(temp);
+ temp &= 0x23;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x4A , CR4A ) ;
+ return temp;
+}
+
+/*----------------------------------------------------------------------------*/
+/* output */
+/* bl[5] : LVDS signal */
+/* bl[1] : LVDS backlight */
+/* bl[0] : LVDS VDD */
+/*----------------------------------------------------------------------------*/
+UCHAR XGI_XG27GetPSCValue(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR4A,CRB4,temp;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~0x0C ) ; /* enable GPIO write */
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ;
+
+ temp &= 0x0C;
+ temp >>= 2;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x4A , CR4A ) ;
+ CRB4 = XGINew_GetReg1( pVBInfo->P3d4 , 0xB4 ) ;
+ temp |= ((CRB4&0x04)<<3);
+ return temp;
+}
+/*----------------------------------------------------------------------------*/
+/* input */
+/* bl[5] : 1;LVDS signal on */
+/* bl[1] : 1;LVDS backlight on */
+/* bl[0] : 1:LVDS VDD on */
+/* bh: 100000b : clear bit 5, to set bit5 */
+/* 000010b : clear bit 1, to set bit1 */
+/* 000001b : clear bit 0, to set bit0 */
+/*----------------------------------------------------------------------------*/
+void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR4A,temp;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ tempbh &= 0x23;
+ tempbl &= 0x23;
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~tempbh ) ; /* enable GPIO write */
+
+ if (tempbh&0x20)
+ {
+ temp = (tempbl>>4)&0x02;
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~0x02 , temp) ; /* CR B4[1] */
+
+ }
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x48 ) ;
+
+ temp = XG21GPIODataTransfer(temp);
+ temp &= ~tempbh;
+ temp |= tempbl;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x48 , temp ) ;
+}
+
+void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR CR4A,temp;
+ USHORT tempbh0,tempbl0;
+
+ tempbh0 = tempbh;
+ tempbl0 = tempbl;
+ tempbh0 &= 0x20;
+ tempbl0 &= 0x20;
+ tempbh0 >>= 3;
+ tempbl0 >>= 3;
+
+ if (tempbh&0x20)
+ {
+ temp = (tempbl>>4)&0x02;
+
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~0x02 , temp) ; /* CR B4[1] */
+
+ }
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0xB4 , ~tempbh0 , tempbl0 ) ;
+
+ CR4A = XGINew_GetReg1( pVBInfo->P3d4 , 0x4A ) ;
+ tempbh &= 0x03;
+ tempbl &= 0x03;
+ tempbh <<= 2;
+ tempbl <<= 2; /* GPIOC,GPIOD */
+ XGINew_SetRegAND( pVBInfo->P3d4 , 0x4A , ~tempbh ) ; /* enable GPIO write */
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x48 , ~tempbh , tempbl ) ;
+}
+
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT index ;
+
+ index = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ;
+ if (index<sizeof(XGI21_LCDCapList)/sizeof(XGI21_LVDSCapStruct))
+ {
+ return index;
+ }
+ return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_XG21SetPanelDelay */
+/* Input : */
+/* Output : */
+/* Description : */
+/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */
+/* : bl : 2 ; T2 : the duration signal on and Vdd on */
+/* : bl : 3 ; T3 : the duration between CPL off and signal off */
+/* : bl : 4 ; T4 : the duration signal off and Vdd off */
+/* --------------------------------------------------------------------- */
+void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT index ;
+
+ index = XGI_GetLVDSOEMTableIndex( pVBInfo );
+ if ( tempbl == 1 )
+ XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S1, pVBInfo ) ;
+
+ if ( tempbl == 2 )
+ XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S2, pVBInfo ) ;
+
+ if ( tempbl == 3 )
+ XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S3, pVBInfo ) ;
+
+ if ( tempbl == 4 )
+ XGINew_LCD_Wait_Time( pVBInfo->XG21_LVDSCapList[ index ].PSC_S4, pVBInfo ) ;
+}
+
+BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT xres ,
+ yres ,
+ colordepth ,
+ modeflag ,
+ resindex ,
+ lvdstableindex;
+
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( ModeNo <= 0x13 )
+ {
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->StResInfo[ resindex ].VTotal ;
+ modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */
+ }
+ else
+ {
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */
+ }
+
+ if ( !( modeflag & Charx8Dot ) )
+ {
+ xres /= 9;
+ xres *= 8;
+ }
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( ( ModeNo>0x13 ) && ( modeflag & HalfDCLK ) )
+ {
+ xres *= 2 ;
+ }
+ if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) )
+ {
+ yres *= 2 ;
+ }
+ }
+
+ lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
+ if ( xres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE) )
+ return FALSE;
+
+ if ( yres > (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE) )
+ return FALSE;
+
+ if ( ModeNo > 0x13 )
+ {
+ if ( ( xres != (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE) ) ||
+ ( yres != (pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE)) )
+ {
+ colordepth = XGI_GetColorDepth( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( colordepth > 2 )
+ {
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR temp;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[0] 1: 18bit */
+ temp = ( temp & 1 ) << 6;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0x40 , temp ) ; /* SR06[6] 18bit Dither */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0xc0 , temp | 0x80 ) ; /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: dual 12bits */
+
+}
+
+void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo)
+{
+ UCHAR temp;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ; /* D[1:0] 01: 18bit, 00: dual 12, 10: single 24 */
+ temp = ( temp & 3 ) << 6;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x06 , ~0xc0 , temp & 0x80 ) ; /* SR06[7]0: dual 12/1: single 24 [6] 18bit Dither <= 0 h/w recommend */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x09 , ~0xc0 , temp | 0x80 ) ; /* SR09[7] enable FP output, SR09[6] 1: sigle 18bits, 0: 24bits */
+
+}
+
+void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR temp,Miscdata;
+ USHORT xres ,
+ yres ,
+ modeflag ,
+ resindex ,
+ lvdstableindex ;
+ USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
+ USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
+ USHORT value;
+
+ lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
+
+ temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 );
+ temp &= LCDPolarity;
+ Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ;
+
+ XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ;
+
+ temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */
+
+ XGI_SetXG21FPBits(pVBInfo);
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( ModeNo <= 0x13 )
+ {
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->StResInfo[ resindex ].VTotal ;
+ modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */
+ }
+ else
+ {
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */
+ }
+
+ if (!( modeflag & Charx8Dot ))
+ xres = xres * 8 / 9;
+
+ LVDSHT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT;
+
+ LVDSHBS = xres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE - xres ) / 2 ;
+ if ( ( ModeNo<=0x13 ) && ( modeflag & HalfDCLK ) )
+ {
+ LVDSHBS -= xres/4 ;
+ }
+ if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT ;
+
+ LVDSHRS = LVDSHBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP ;
+ if (LVDSHRS > LVDSHT) LVDSHRS -= LVDSHT ;
+
+ LVDSHRE = LVDSHRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC ;
+ if (LVDSHRE > LVDSHT) LVDSHRE -= LVDSHT ;
+
+ LVDSHBE = LVDSHBS + LVDSHT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE ;
+
+ LVDSVT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT;
+
+ LVDSVBS = yres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE - yres ) / 2 ;
+ if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) )
+ {
+ LVDSVBS += yres/2 ;
+ }
+ if (LVDSVBS > LVDSVT) LVDSVBS -= LVDSVT ;
+
+ LVDSVRS = LVDSVBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP ;
+ if (LVDSVRS > LVDSVT) LVDSVRS -= LVDSVT ;
+
+ LVDSVRE = LVDSVRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC ;
+ if (LVDSVRE > LVDSVT) LVDSVRE -= LVDSVT ;
+
+ LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ;
+
+ temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */
+
+ if (!( modeflag & Charx8Dot ))
+ {
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1 , 0x1 ) ;
+ }
+
+ /* HT SR0B[1:0] CR00 */
+ value = ( LVDSHT >> 3 ) - 5;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x03 , ( value & 0x300 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x0 , (value & 0xFF) ) ;
+
+ /* HBS SR0B[5:4] CR02 */
+ value = ( LVDSHBS >> 3 ) - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x30 , ( value & 0x300 ) >> 4 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2 , (value & 0xFF) ) ;
+
+ /* HBE SR0C[1:0] CR05[7] CR03[4:0] */
+ value = ( LVDSHBE >> 3 ) - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x03 , ( value & 0xC0 ) >> 6 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x80 , ( value & 0x20 ) << 2 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x03 , ~0x1F , value & 0x1F ) ;
+
+ /* HRS SR0B[7:6] CR04 */
+ value = ( LVDSHRS >> 3 ) + 2;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0xC0 , ( value & 0x300 ) >> 2 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x4 , (value & 0xFF) ) ;
+
+ /* Panel HRS SR2F[1:0] SR2E[7:0] */
+ value--;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0x03 , ( value & 0x300 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , (value & 0xFF) ) ;
+
+ /* HRE SR0C[2] CR05[4:0] */
+ value = ( LVDSHRE >> 3 ) + 2;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x04 , ( value & 0x20 ) >> 3 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x1F , value & 0x1F ) ;
+
+ /* Panel HRE SR2F[7:2] */
+ value--;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0xFC , value << 2 ) ;
+
+ /* VT SR0A[0] CR07[5][0] CR06 */
+ value = LVDSVT - 2 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x01 , ( value & 0x400 ) >> 10 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x20 , ( value & 0x200 ) >> 4 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x01 , ( value & 0x100 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x06 , (value & 0xFF) ) ;
+
+ /* VBS SR0A[2] CR09[5] CR07[3] CR15 */
+ value = LVDSVBS - 1 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x04 , ( value & 0x400 ) >> 8 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x09 , ~0x20 , ( value & 0x200 ) >> 4 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x08 , ( value & 0x100 ) >> 5 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , (value & 0xFF) ) ;
+
+ /* VBE SR0A[4] CR16 */
+ value = LVDSVBE - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x10 , ( value & 0x100 ) >> 4 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , (value & 0xFF) ) ;
+
+ /* VRS SR0A[3] CR7[7][2] CR10 */
+ value = LVDSVRS - 1 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x08 , ( value & 0x400 ) >> 7 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x80 , ( value & 0x200 ) >> 2 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x04 , ( value & 0x100 ) >> 6 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x10 , (value & 0xFF) ) ;
+
+ /* Panel VRS SR3F[1:0] SR34[7:0] SR33[0] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0x03 , ( value & 0x600 ) >> 9 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , (value >> 1) & 0xFF ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x33 , ~0x01 , value & 0x01 ) ;
+
+ /* VRE SR0A[5] CR11[3:0] */
+ value = LVDSVRE - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x20 , ( value & 0x10 ) << 1 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , ~0x0F , value & 0x0F ) ;
+
+ /* Panel VRE SR3F[7:2] */ /* SR3F[7] has to be 0, h/w bug */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , ( value << 2 ) & 0x7C ) ;
+
+ for ( temp=0, value = 0; temp < 3; temp++)
+ {
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , value ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2) ;
+ value += 0x10;
+ }
+
+ if (!( modeflag & Charx8Dot ))
+ {
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x13 ) ; /* set index */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data, panning = 0, shift left 1 dot*/
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ;
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ }
+
+
+}
+
+/* no shadow case */
+void XGI_SetXG27LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR temp,Miscdata;
+ USHORT xres ,
+ yres ,
+ modeflag ,
+ resindex ,
+ lvdstableindex ;
+ USHORT LVDSHT,LVDSHBS,LVDSHRS,LVDSHRE,LVDSHBE;
+ USHORT LVDSVT,LVDSVBS,LVDSVRS,LVDSVRE,LVDSVBE;
+ USHORT value;
+
+ lvdstableindex = XGI_GetLVDSOEMTableIndex( pVBInfo );
+ temp = (UCHAR) ( ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & (LCDPolarity << 8 ) ) >> 8 );
+ temp &= LCDPolarity;
+ Miscdata =(UCHAR) XGINew_GetReg2(pVBInfo->P3cc) ;
+
+ XGINew_SetReg3( pVBInfo->P3c2 , (Miscdata & 0x3F) | temp ) ;
+
+ temp = (UCHAR) ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDS_Capability & LCDPolarity ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x80 , temp&0x80 ) ; /* SR35[7] FP VSync polarity */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x30 , ~0x20 , (temp&0x40)>>1 ) ; /* SR30[5] FP HSync polarity */
+
+ XGI_SetXG27FPBits(pVBInfo);
+ resindex = XGI_GetResInfo( ModeNo , ModeIdIndex, pVBInfo ) ;
+ if ( ModeNo <= 0x13 )
+ {
+ xres = pVBInfo->StResInfo[ resindex ].HTotal ;
+ yres = pVBInfo->StResInfo[ resindex ].VTotal ;
+ modeflag = pVBInfo->SModeIDTable[ModeIdIndex].St_ModeFlag; /* si+St_ResInfo */
+ }
+ else
+ {
+ xres = pVBInfo->ModeResInfo[ resindex ].HTotal ; /* xres->ax */
+ yres = pVBInfo->ModeResInfo[ resindex ].VTotal ; /* yres->bx */
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex].Ext_ModeFlag ; /* si+St_ModeFlag */
+ }
+
+ if (!( modeflag & Charx8Dot ))
+ xres = xres * 8 / 9;
+
+ LVDSHT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHT;
+
+ LVDSHBS = xres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE - xres ) / 2 ;
+ if ( ( ModeNo<=0x13 ) && ( modeflag & HalfDCLK ) )
+ {
+ LVDSHBS -= xres/4 ;
+ }
+ if (LVDSHBS > LVDSHT) LVDSHBS -= LVDSHT ;
+
+ LVDSHRS = LVDSHBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHFP ;
+ if (LVDSHRS > LVDSHT) LVDSHRS -= LVDSHT ;
+
+ LVDSHRE = LVDSHRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHSYNC ;
+ if (LVDSHRE > LVDSHT) LVDSHRE -= LVDSHT ;
+
+ LVDSHBE = LVDSHBS + LVDSHT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSHDE ;
+
+ LVDSVT = pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVT;
+
+ LVDSVBS = yres + ( pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE - yres ) / 2 ;
+ if ( ( ModeNo>0x13 ) && ( modeflag & DoubleScanMode ) )
+ {
+ LVDSVBS += yres/2 ;
+ }
+ if (LVDSVBS > LVDSVT) LVDSVBS -= LVDSVT ;
+
+ LVDSVRS = LVDSVBS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVFP ;
+ if (LVDSVRS > LVDSVT) LVDSVRS -= LVDSVT ;
+
+ LVDSVRE = LVDSVRS + pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVSYNC ;
+ if (LVDSVRE > LVDSVT) LVDSVRE -= LVDSVT ;
+
+ LVDSVBE = LVDSVBS + LVDSVT - pVBInfo->XG21_LVDSCapList[lvdstableindex].LVDSVDE ;
+
+ temp = ( UCHAR )XGINew_GetReg1( pVBInfo->P3d4 , 0x11 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x11 , temp & 0x7f ) ; /* Unlock CRTC */
+
+ if (!( modeflag & Charx8Dot ))
+ {
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1 , 0x1 ) ;
+ }
+
+ /* HT SR0B[1:0] CR00 */
+ value = ( LVDSHT >> 3 ) - 5;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x03 , ( value & 0x300 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x0 , (value & 0xFF) ) ;
+
+ /* HBS SR0B[5:4] CR02 */
+ value = ( LVDSHBS >> 3 ) - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0x30 , ( value & 0x300 ) >> 4 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x2 , (value & 0xFF) ) ;
+
+ /* HBE SR0C[1:0] CR05[7] CR03[4:0] */
+ value = ( LVDSHBE >> 3 ) - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x03 , ( value & 0xC0 ) >> 6 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x80 , ( value & 0x20 ) << 2 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x03 , ~0x1F , value & 0x1F ) ;
+
+ /* HRS SR0B[7:6] CR04 */
+ value = ( LVDSHRS >> 3 ) + 2;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0B , ~0xC0 , ( value & 0x300 ) >> 2 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x4 , (value & 0xFF) ) ;
+
+ /* Panel HRS SR2F[1:0] SR2E[7:0] */
+ value--;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0x03 , ( value & 0x300 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2E , (value & 0xFF) ) ;
+
+ /* HRE SR0C[2] CR05[4:0] */
+ value = ( LVDSHRE >> 3 ) + 2;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0C , ~0x04 , ( value & 0x20 ) >> 3 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x05 , ~0x1F , value & 0x1F ) ;
+
+ /* Panel HRE SR2F[7:2] */
+ value--;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x2F , ~0xFC , value << 2 ) ;
+
+ /* VT SR0A[0] CR07[5][0] CR06 */
+ value = LVDSVT - 2 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x01 , ( value & 0x400 ) >> 10 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x20 , ( value & 0x200 ) >> 4 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x01 , ( value & 0x100 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x06 , (value & 0xFF) ) ;
+
+ /* VBS SR0A[2] CR09[5] CR07[3] CR15 */
+ value = LVDSVBS - 1 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x04 , ( value & 0x400 ) >> 8 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x09 , ~0x20 , ( value & 0x200 ) >> 4 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x08 , ( value & 0x100 ) >> 5 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x15 , (value & 0xFF) ) ;
+
+ /* VBE SR0A[4] CR16 */
+ value = LVDSVBE - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x10 , ( value & 0x100 ) >> 4 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x16 , (value & 0xFF) ) ;
+
+ /* VRS SR0A[3] CR7[7][2] CR10 */
+ value = LVDSVRS - 1 ;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x08 , ( value & 0x400 ) >> 7 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x80 , ( value & 0x200 ) >> 2 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x07 , ~0x04 , ( value & 0x100 ) >> 6 ) ;
+ XGINew_SetReg1( pVBInfo->P3d4 , 0x10 , (value & 0xFF) ) ;
+
+ /* Panel VRS SR35[2:0] SR34[7:0] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x35 , ~0x07 , ( value & 0x700 ) >> 8 ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x34 , value & 0xFF ) ;
+
+ /* VRE SR0A[5] CR11[3:0] */
+ value = LVDSVRE - 1;
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x0A , ~0x20 , ( value & 0x10 ) << 1 ) ;
+ XGINew_SetRegANDOR( pVBInfo->P3d4 , 0x11 , ~0x0F , value & 0x0F ) ;
+
+ /* Panel VRE SR3F[7:2] */
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x3F , ~0xFC , ( value << 2 ) & 0xFC ) ;
+
+ for ( temp=0, value = 0; temp < 3; temp++)
+ {
+
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x31 , ~0x30 , value ) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2B , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData1) ;
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x2C , pVBInfo->XG21_LVDSCapList[lvdstableindex].VCLKData2) ;
+ value += 0x10;
+ }
+
+ if (!( modeflag & Charx8Dot ))
+ {
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x13 ) ; /* set index */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x00 ) ; /* set data, panning = 0, shift left 1 dot*/
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* Enable Attribute */
+ XGINew_SetReg3( pVBInfo->P3c0 , 0x20 ) ;
+
+ XGINew_GetReg2( pVBInfo->P3da ) ; /* reset 3da */
+ }
+
+
+}
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_IsLCDON */
+/* Input : */
+/* Output : FALSE : Skip PSC Control */
+/* TRUE: Disable PSC */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_IsLCDON(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax ;
+
+ tempax = pVBInfo->VBInfo ;
+ if ( tempax & SetCRT2ToDualEdge )
+ return FALSE ;
+ else if ( tempax & ( DisableCRT2Display | SwitchToCRT2 | SetSimuScanMode ) )
+ return TRUE ;
+
+ return FALSE ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_EnablePWD */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_EnablePWD( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT index ,
+ temp ;
+
+ index = XGI_GetLCDCapPtr(pVBInfo) ;
+ temp = pVBInfo->LCDCapList[ index ].PWD_2B ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x2B , temp ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x2C , pVBInfo->LCDCapList[ index ].PWD_2C ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x2D , pVBInfo->LCDCapList[ index ].PWD_2D ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x2E , pVBInfo->LCDCapList[ index ].PWD_2E ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x2F , pVBInfo->LCDCapList[ index ].PWD_2F ) ;
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x27 , 0x80 ) ; /* enable PWD */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisablePWD */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_DisablePWD( PVB_DEVICE_INFO pVBInfo )
+{
+ XGINew_SetRegAND( pVBInfo->Part4Port , 0x27 , 0x7F ) ; /* disable PWD */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisableChISLCD */
+/* Input : */
+/* Output : FALSE -> Not LCD Mode */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_DisableChISLCD(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx ,
+ tempah ;
+
+ tempbx = pVBInfo->SetFlag & ( DisableChA | DisableChB ) ;
+ tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ;
+
+ if ( tempbx & ( EnableChA | DisableChA ) )
+ {
+ if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */
+ return FALSE ;
+ }
+
+ if ( !( tempbx & ( EnableChB | DisableChB ) ) )
+ return FALSE ;
+
+ if ( tempah & 0x01 ) /* Chk LCDB Mode */
+ return TRUE ;
+
+ return FALSE ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_EnableChISLCD */
+/* Input : */
+/* Output : 0 -> Not LCD mode */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_EnableChISLCD(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx ,
+ tempah ;
+
+
+ tempbx = pVBInfo->SetFlag & ( EnableChA | EnableChB ) ;
+ tempah = ~( ( USHORT )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ) ;
+
+ if ( tempbx & ( EnableChA | DisableChA ) )
+ {
+ if ( !( tempah & 0x08 ) ) /* Chk LCDA Mode */
+ return FALSE ;
+ }
+
+ if ( !( tempbx & ( EnableChB | DisableChB ) ) )
+ return FALSE ;
+
+ if ( tempah & 0x01 ) /* Chk LCDB Mode */
+ return TRUE ;
+
+ return FALSE ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLCDCapPtr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetLCDCapPtr( PVB_DEVICE_INFO pVBInfo )
+{
+ UCHAR tempal ,
+ tempah ,
+ tempbl ,
+ i ;
+
+ tempah = XGINew_GetReg1( pVBInfo->P3d4 , 0x36 ) ;
+ tempal = tempah & 0x0F ;
+ tempah = tempah & 0xF0 ;
+ i = 0 ;
+ tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ;
+
+ while( tempbl != 0xFF )
+ {
+ if ( tempbl & 0x80 ) /* OEMUtil */
+ {
+ tempal = tempah ;
+ tempbl = tempbl & ~( 0x80 ) ;
+ }
+
+ if ( tempal == tempbl )
+ break ;
+
+ i++ ;
+
+ tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ;
+ }
+
+ return i ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLCDCapPtr1 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetLCDCapPtr1( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempah ,
+ tempal ,
+ tempbl ,
+ i ;
+
+ tempal = pVBInfo->LCDResInfo ;
+ tempah = pVBInfo->LCDTypeInfo ;
+
+ i = 0 ;
+ tempbl = pVBInfo->LCDCapList[ i ].LCD_ID;
+
+ while( tempbl != 0xFF )
+ {
+ if ( ( tempbl & 0x80 ) && ( tempbl != 0x80 ) )
+ {
+ tempal = tempah ;
+ tempbl &= ~0x80 ;
+ }
+
+ if ( tempal == tempbl )
+ break ;
+
+ i++ ;
+ tempbl = pVBInfo->LCDCapList[ i ].LCD_ID ;
+ }
+
+ if ( tempbl == 0xFF )
+ {
+ pVBInfo->LCDResInfo = Panel1024x768 ;
+ pVBInfo->LCDTypeInfo = 0 ;
+ i = 0 ;
+ }
+
+ return i ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetLCDSync */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetLCDSync( USHORT* HSyncWidth , USHORT* VSyncWidth, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT Index ;
+
+ Index = XGI_GetLCDCapPtr(pVBInfo) ;
+ *HSyncWidth = pVBInfo->LCDCapList[ Index ].LCD_HSyncWidth ;
+ *VSyncWidth = pVBInfo->LCDCapList[ Index ].LCD_VSyncWidth ;
+
+ return ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_EnableBridge */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_EnableBridge( PXGI_HW_DEVICE_INFO HwDeviceExtension , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbl ,
+ tempah ;
+
+ if ( pVBInfo->SetFlag == Win9xDOSMode )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo) ;
+ return ;
+ }
+ else /* LVDS or CH7017 */
+ return ;
+ }
+
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ {
+ if ( !XGI_DisableChISLCD(pVBInfo) )
+ {
+ if ( ( XGI_EnableChISLCD(pVBInfo) ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) )
+ {
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ {
+ XGI_EnablePWD( pVBInfo);
+ }
+ else
+ {
+ pVBInfo->LCDInfo &= ( ~SetPWDEnable ) ;
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempbl = 0xFD ;
+ tempah = 0x02 ;
+ }
+ else
+ {
+ tempbl = 0xFB ;
+ tempah = 0x00 ;
+ }
+
+ XGI_SetPanelPower( tempah , tempbl, pVBInfo ) ;
+ XGI_SetPanelDelay( 1,pVBInfo ) ;
+ }
+ }
+ }
+ } /* Not 340 */
+
+
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( !( pVBInfo->SetFlag & DisableChA ) )
+ {
+ if ( pVBInfo->SetFlag & EnableChA )
+ {
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x1E , 0x20 ) ; /* Power on */
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge ) /* SetCRT2ToLCDA ) */
+ {
+ XGINew_SetReg1(pVBInfo->Part1Port,0x1E,0x20); /* Power on */
+ }
+ }
+ }
+
+ if ( !( pVBInfo->SetFlag & DisableChB ) )
+ {
+ if ( ( pVBInfo->SetFlag & EnableChB ) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV | SetCRT2ToRAMDAC ) ) )
+ {
+ tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->P3c4 , 0x32 ) ;
+ tempah &= 0xDF;
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) )
+ tempah |= 0x20 ;
+ }
+ XGINew_SetReg1( pVBInfo->P3c4 , 0x32 , tempah ) ;
+ XGINew_SetRegOR( pVBInfo->P3c4 , 0x1E , 0x20 ) ;
+
+
+ tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ;
+
+ if ( !( tempah & 0x80 ) )
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */
+
+ XGINew_SetRegAND( pVBInfo->Part1Port , 0x00 , 0x7F ) ; /* BScreenOFF = 0 */
+ }
+ }
+
+ if ( ( pVBInfo->SetFlag & ( EnableChA | EnableChB ) ) || ( !( pVBInfo->VBInfo & DisableCRT2Display ) ) )
+ {
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x00 , ~0xE0 , 0x20 ) ; /* shampoo 0129 */
+ if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( !XGI_DisableChISLCD(pVBInfo) )
+ {
+ if ( XGI_EnableChISLCD( pVBInfo) || ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) )
+ XGINew_SetRegAND( pVBInfo->Part4Port ,0x2A , 0x7F ) ; /* LVDS PLL power on */
+ }
+ XGINew_SetRegAND( pVBInfo->Part4Port , 0x30 , 0x7F ) ; /* LVDS Driver power on */
+ }
+ }
+
+ tempah = 0x00 ;
+
+ if ( !( pVBInfo->VBInfo & DisableCRT2Display ) )
+ {
+ tempah = 0xc0 ;
+
+ if ( !( pVBInfo->VBInfo & SetSimuScanMode ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ {
+ tempah = tempah & 0x40;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ tempah = tempah ^ 0xC0 ;
+
+ if ( pVBInfo->SetFlag & DisableChB )
+ tempah &= 0xBF ;
+
+ if ( pVBInfo->SetFlag & DisableChA )
+ tempah &= 0x7F ;
+
+ if ( pVBInfo->SetFlag & EnableChB )
+ tempah |= 0x40 ;
+
+ if ( pVBInfo->SetFlag & EnableChA )
+ tempah |= 0x80 ;
+ }
+ }
+ }
+ }
+
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x1F , tempah ) ; /* EnablePart4_1F */
+
+ if ( pVBInfo->SetFlag & Win9xDOSMode )
+ {
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo) ;
+ return ;
+ }
+
+ if ( !( pVBInfo->SetFlag & DisableChA ) )
+ {
+ XGI_VBLongWait( pVBInfo) ;
+ if ( !( pVBInfo->SetFlag & GatingCRT ) )
+ {
+ XGI_DisableGatingCRT( HwDeviceExtension, pVBInfo ) ;
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo) ;
+ XGI_VBLongWait( pVBInfo) ;
+ }
+ }
+ } /* 301 */
+ else /* LVDS */
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x1E , 0x20 ) ; /* enable CRT2 */
+
+
+
+ tempah = ( UCHAR )XGINew_GetReg1( pVBInfo->Part1Port , 0x2E ) ;
+ if ( !( tempah & 0x80 ) )
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x2E , 0x80 ) ; /* BVBDOENABLE = 1 */
+
+ XGINew_SetRegAND(pVBInfo->Part1Port,0x00,0x7F);
+ XGI_DisplayOn( HwDeviceExtension, pVBInfo);
+ } /* End of VB */
+
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ {
+ if ( !XGI_EnableChISLCD(pVBInfo) )
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ if ( XGI_BacklightByDrv(pVBInfo) )
+ return ;
+ }
+ else
+ return ;
+ }
+
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ {
+ XGI_FirePWDEnable(pVBInfo) ;
+ return ;
+ }
+
+ XGI_SetPanelDelay( 2,pVBInfo ) ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempah = 0x01 ;
+ tempbl = 0xFE ; /* turn on backlght */
+ }
+ else
+ {
+ tempbl = 0xF7 ;
+ tempah = 0x00 ;
+ }
+ XGI_SetPanelPower( tempah , tempbl , pVBInfo) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_DisableBridge */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempax ,
+ tempbx ,
+ tempah = 0 ,
+ tempbl = 0 ;
+
+ if ( pVBInfo->SetFlag == Win9xDOSMode )
+ return ;
+
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ {
+ if ( ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) || ( XGI_DisableChISLCD(pVBInfo) ) )
+ {
+ if ( !XGI_IsLCDON(pVBInfo) )
+ {
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ XGI_EnablePWD( pVBInfo) ;
+ else
+ {
+ pVBInfo->LCDInfo &= ~SetPWDEnable ;
+ XGI_DisablePWD(pVBInfo) ;
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempbx = 0xFE ; /* not 01h */
+ tempax = 0 ;
+ }
+ else
+ {
+ tempbx = 0xF7 ; /* not 08h */
+ tempax = 0x08 ;
+ }
+ XGI_SetPanelPower( tempax , tempbx , pVBInfo) ;
+ XGI_SetPanelDelay( 3,pVBInfo ) ;
+ }
+ } /* end if(!XGI_IsLCDON(pVBInfo)) */
+ }
+ }
+
+/* if ( CH7017 )
+ {
+ if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2toLCDA ) ) || ( XGI_DisableChISLCD(pVBInfo) ) )
+ {
+ if ( !XGI_IsLCDON(pVBInfo) )
+ {
+ if ( DISCHARGE )
+ {
+ tempbx = XGINew_GetCH7005( 0x61 ) ;
+ if ( tempbx < 0x01 ) //first time we power up
+ XGINew_SetCH7005( 0x0066 ) ; //and disable power sequence
+ else
+ XGINew_SetCH7005( 0x5f66 ) ; //leave VDD on - disable power
+ }
+ }
+ }
+ } */
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B| VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempah = 0x3F ;
+ if ( !( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ {
+ tempah = 0x7F; /* Disable Channel A */
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) )
+ tempah = 0xBF ; /* Disable Channel B */
+
+ if ( pVBInfo->SetFlag & DisableChB )
+ tempah &= 0xBF ; /* force to disable Cahnnel */
+
+ if ( pVBInfo->SetFlag & DisableChA )
+ tempah &= 0x7F ; /* Force to disable Channel B */
+ }
+ }
+ }
+
+ XGINew_SetRegAND( pVBInfo->Part4Port , 0x1F , tempah ) ; /* disable part4_1f */
+
+ if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( ( ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) ) || ( XGI_DisableChISLCD(pVBInfo) ) || ( XGI_IsLCDON(pVBInfo) ) )
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x80 ) ; /* LVDS Driver power down */
+ }
+
+ if ( ( pVBInfo->SetFlag & DisableChA ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetCRT2ToLCDA | SetSimuScanMode ) ) )
+ {
+ if ( pVBInfo->SetFlag & GatingCRT )
+ XGI_EnableGatingCRT( HwDeviceExtension, pVBInfo ) ;
+ XGI_DisplayOff( HwDeviceExtension, pVBInfo) ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ if ( ( pVBInfo->SetFlag & DisableChA ) || ( pVBInfo->VBInfo & SetCRT2ToLCDA ) )
+ XGINew_SetRegAND( pVBInfo->Part1Port , 0x1e , 0xdf ) ; /* Power down */
+ }
+
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x32 , 0xdf ) ; /* disable TV as primary VGA swap */
+
+ if ( ( pVBInfo->VBInfo & ( SetSimuScanMode | SetCRT2ToDualEdge ) ) )
+ XGINew_SetRegAND(pVBInfo->Part2Port,0x00,0xdf);
+
+ if ( ( pVBInfo->SetFlag & DisableChB ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) )
+ || ( ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) && ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) ) )
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x80 ) ; /* BScreenOff=1 */
+
+ if ( ( pVBInfo->SetFlag & DisableChB ) || ( pVBInfo->VBInfo & ( DisableCRT2Display | SetSimuScanMode ) )
+ || ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) ) || ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) )
+ {
+ tempah= XGINew_GetReg1( pVBInfo->Part1Port , 0x00 ) ; /* save Part1 index 0 */
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x10 ) ; /* BTDAC = 1, avoid VB reset */
+ XGINew_SetRegAND( pVBInfo->Part1Port , 0x1E , 0xDF ) ; /* disable CRT2 */
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ; /* restore Part1 index 0 */
+ }
+ }
+ else /* {301} */
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToTV ) )
+ {
+ XGINew_SetRegOR( pVBInfo->Part1Port , 0x00 , 0x80 ) ; /* BScreenOff=1 */
+ XGINew_SetRegAND( pVBInfo->Part1Port , 0x1E , 0xDF ) ; /* Disable CRT2 */
+ XGINew_SetRegAND( pVBInfo->P3c4 , 0x32 , 0xDF ) ; /* Disable TV asPrimary VGA swap */
+ }
+
+ if ( pVBInfo->VBInfo & ( DisableCRT2Display | SetCRT2ToLCDA | SetSimuScanMode ) )
+ XGI_DisplayOff( HwDeviceExtension, pVBInfo) ;
+ }
+
+
+
+
+ if ( HwDeviceExtension->jChipType < XG40 )
+ {
+ if ( !( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) ) || ( XGI_DisableChISLCD(pVBInfo) ) || ( XGI_IsLCDON(pVBInfo) ) )
+ {
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ {
+ if ( pVBInfo->LCDInfo & SetPWDEnable )
+ XGI_BacklightByDrv(pVBInfo) ;
+ else
+ {
+ XGI_SetPanelDelay( 4 ,pVBInfo) ;
+ if ( pVBInfo->VBType & VB_XGI301LV )
+ {
+ tempbl = 0xFD ;
+ tempah = 0x00 ;
+ }
+ else
+ {
+ tempbl = 0xFB ;
+ tempah = 0x04 ;
+ }
+ }
+ }
+ XGI_SetPanelPower( tempah , tempbl , pVBInfo) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetTVPtrIndex */
+/* Input : */
+/* Output : */
+/* Description : bx 0 : ExtNTSC */
+/* 1 : StNTSC */
+/* 2 : ExtPAL */
+/* 3 : StPAL */
+/* 4 : ExtHiTV */
+/* 5 : StHiTV */
+/* 6 : Ext525i */
+/* 7 : St525i */
+/* 8 : Ext525p */
+/* 9 : St525p */
+/* A : Ext750p */
+/* B : St750p */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetTVPtrIndex( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx = 0 ;
+
+ if ( pVBInfo->TVInfo & SetPALTV )
+ tempbx = 2 ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode1080i )
+ tempbx = 4 ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode525i )
+ tempbx = 6 ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode525p )
+ tempbx = 8 ;
+ if ( pVBInfo->TVInfo & SetYPbPrMode750p )
+ tempbx = 10 ;
+ if ( pVBInfo->TVInfo & TVSimuMode )
+ tempbx++ ;
+
+ return tempbx ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_OEM310Setting */
+/* Input : */
+/* Output : */
+/* Description : Customized Param. for 301 */
+/* --------------------------------------------------------------------- */
+void XGI_OEM310Setting( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ if ( pVBInfo->SetFlag & Win9xDOSMode )
+ return ;
+
+ /* GetPart1IO(); */
+ XGI_SetDelayComp(pVBInfo) ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ XGI_SetLCDCap(pVBInfo) ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ /* GetPart2IO() */
+ XGI_SetPhaseIncr(pVBInfo) ;
+ XGI_SetYFilter( ModeNo , ModeIdIndex,pVBInfo ) ;
+ XGI_SetAntiFlicker( ModeNo , ModeIdIndex,pVBInfo ) ;
+
+ if ( pVBInfo->VBType&VB_XGI301)
+ XGI_SetEdgeEnhance( ModeNo , ModeIdIndex ,pVBInfo) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetDelayComp */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetDelayComp( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT index ;
+
+ UCHAR tempah ,
+ tempbl ,
+ tempbh ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA | SetCRT2ToTV | SetCRT2ToRAMDAC ) )
+ {
+ tempbl = 0;
+ tempbh = 0;
+
+ index = XGI_GetTVPtrIndex(pVBInfo ) ; /* Get TV Delay */
+ tempbl = pVBInfo->XGI_TVDelayList[ index ] ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ tempbl = pVBInfo->XGI_TVDelayList2[ index ] ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ tempbl = tempbl >> 4 ;
+/*
+ if ( pVBInfo->VBInfo & SetCRT2ToRAMDAC )
+ tempbl = CRT2Delay1 ; // Get CRT2 Delay
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ tempbl = CRT2Delay2 ;
+*/
+ if ( pVBInfo->VBInfo & ( SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ index = XGI_GetLCDCapPtr(pVBInfo) ; /* Get LCD Delay */
+ tempbh=pVBInfo->LCDCapList[ index ].LCD_DelayCompensation ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) )
+ tempbl = tempbh ;
+ }
+
+ tempbl &= 0x0F ;
+ tempbh &= 0xF0 ;
+ tempah = XGINew_GetReg1( pVBInfo->Part1Port , 0x2D ) ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToLCD | SetCRT2ToTV ) ) /* Channel B */
+ {
+ tempah &= 0xF0 ;
+ tempah |= tempbl ;
+ }
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA ) /* Channel A */
+ {
+ tempah &= 0x0F ;
+ tempah |= tempbh ;
+ }
+ XGINew_SetReg1(pVBInfo->Part1Port,0x2D,tempah);
+ }
+ }
+ else if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ tempbl = 0;
+ tempbh = 0;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ {
+ tempah = pVBInfo->LCDCapList[ XGI_GetLCDCapPtr(pVBInfo) ].LCD_DelayCompensation ; /* / Get LCD Delay */
+ tempah &= 0x0f ;
+ tempah = tempah << 4 ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2D , 0x0f , tempah ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLCDCap */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLCDCap( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempcx ;
+
+ tempcx = pVBInfo->LCDCapList[ XGI_GetLCDCapPtr(pVBInfo) ].LCD_Capability ;
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBType & ( VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ { /* 301LV/302LV only */
+ /* Set 301LV Capability */
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x24 , ( UCHAR )( tempcx & 0x1F ) ) ;
+ }
+ /* VB Driving */
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~( ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) >> 8 ) , ( USHORT )( ( tempcx & ( EnableVBCLKDRVLOW | EnablePLLSPLOW ) ) >> 8 ) ) ;
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCD )
+ XGI_SetLCDCap_B( tempcx,pVBInfo ) ;
+ else if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ XGI_SetLCDCap_A( tempcx,pVBInfo ) ;
+
+ if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( tempcx & EnableSpectrum )
+ SetSpectrum( pVBInfo) ;
+ }
+ }
+ else /* LVDS,CH7017 */
+ XGI_SetLCDCap_A( tempcx, pVBInfo ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLCDCap_A */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLCDCap_A(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT temp ;
+
+ temp = XGINew_GetReg1( pVBInfo->P3d4 , 0x37 ) ;
+
+ if ( temp & LCDRGB18Bit )
+ {
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x20 | ( tempcx & 0x00C0 ) ) ) ; /* Enable Dither */
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x80 ) ;
+ }
+ else
+ {
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x19 , 0x0F , ( USHORT )( 0x30 | ( tempcx & 0x00C0 ) ) ) ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x1A , 0x7F , 0x00 ) ;
+ }
+
+/*
+ if ( tempcx & EnableLCD24bpp ) // 24bits
+ {
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x30|(tempcx&0x00C0)) );
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x00);
+ }
+ else
+ {
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x19, 0x0F,(USHORT)(0x20|(tempcx&0x00C0)) );//Enable Dither
+ XGINew_SetRegANDOR(pVBInfo->Part1Port,0x1A,0x7F,0x80);
+ }
+*/
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetLCDCap_B */
+/* Input : cx -> LCD Capability */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetLCDCap_B(USHORT tempcx,PVB_DEVICE_INFO pVBInfo)
+{
+ if ( tempcx & EnableLCD24bpp ) /* 24bits */
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x0c ) ) ;
+ else
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x1A , 0xE0 , ( USHORT )( ( ( tempcx & 0x00ff ) >> 6 ) | 0x18 ) ) ; /* Enable Dither */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : SetSpectrum */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void SetSpectrum( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT index ;
+
+ index = XGI_GetLCDCapPtr(pVBInfo) ;
+
+ XGINew_SetRegAND( pVBInfo->Part4Port , 0x30 , 0x8F ) ; /* disable down spectrum D[4] */
+ XGI_LongWait(pVBInfo) ;
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x20 ) ; /* reset spectrum */
+ XGI_LongWait(pVBInfo) ;
+
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x31 , pVBInfo->LCDCapList[ index ].Spectrum_31 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x32 , pVBInfo->LCDCapList[ index ].Spectrum_32 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x33 , pVBInfo->LCDCapList[ index ].Spectrum_33 ) ;
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x34 , pVBInfo->LCDCapList[ index ].Spectrum_34 ) ;
+ XGI_LongWait(pVBInfo) ;
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x30 , 0x40 ) ; /* enable spectrum */
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetAntiFlicker */
+/* Input : */
+/* Output : */
+/* Description : Set TV Customized Param. */
+/* --------------------------------------------------------------------- */
+void XGI_SetAntiFlicker( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ,
+ index ;
+
+ UCHAR tempah ;
+
+ if (pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) )
+ return ;
+
+ tempbx = XGI_GetTVPtrIndex(pVBInfo ) ;
+ tempbx &= 0xFE ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ index = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVFlickerIndex ;
+ }
+ else
+ {
+ index = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVFlickerIndex ;
+ }
+
+ tempbx += index ;
+ tempah = TVAntiFlickList[ tempbx ] ;
+ tempah = tempah << 4 ;
+
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x0A , 0x8F , tempah ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetEdgeEnhance */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetEdgeEnhance( USHORT ModeNo , USHORT ModeIdIndex , PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx ,
+ index ;
+
+ UCHAR tempah ;
+
+
+ tempbx = XGI_GetTVPtrIndex(pVBInfo ) ;
+ tempbx &= 0xFE ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ index = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVEdgeIndex ;
+ }
+ else
+ {
+ index = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVEdgeIndex ;
+ }
+
+ tempbx += index ;
+ tempah = TVEdgeList[ tempbx ] ;
+ tempah = tempah << 5 ;
+
+ XGINew_SetRegANDOR( pVBInfo->Part2Port , 0x3A , 0x1F , tempah ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetPhaseIncr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetPhaseIncr( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ;
+
+ UCHAR tempcl ,
+ tempch ;
+
+ ULONG tempData ;
+
+ XGI_GetTVPtrIndex2( &tempbx , &tempcl , &tempch, pVBInfo ) ; /* bx, cl, ch */
+ tempData = TVPhaseList[ tempbx ] ;
+
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x31 , ( USHORT )( tempData & 0x000000FF ) ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x32 , ( USHORT )( ( tempData & 0x0000FF00 ) >> 8 ) ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x33 , ( USHORT )( ( tempData & 0x00FF0000 ) >> 16 ) ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x34 , ( USHORT )( ( tempData & 0xFF000000 ) >> 24 ) ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetYFilter */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_SetYFilter( USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx ,
+ index ;
+
+ UCHAR tempcl ,
+ tempch ,
+ tempal ,
+ *filterPtr ;
+
+ XGI_GetTVPtrIndex2( &tempbx , &tempcl , &tempch, pVBInfo ) ; /* bx, cl, ch */
+
+ switch( tempbx )
+ {
+ case 0x00:
+ case 0x04:
+ filterPtr = NTSCYFilter1 ;
+ break ;
+
+ case 0x01:
+ filterPtr = PALYFilter1 ;
+ break ;
+
+ case 0x02:
+ case 0x05:
+ case 0x0D:
+ filterPtr = PALMYFilter1 ;
+ break ;
+
+ case 0x03:
+ filterPtr = PALNYFilter1 ;
+ break ;
+
+ case 0x08:
+ case 0x0C:
+ filterPtr = NTSCYFilter2 ;
+ break ;
+
+ case 0x0A:
+ filterPtr = PALMYFilter2 ;
+ break ;
+
+ case 0x0B:
+ filterPtr = PALNYFilter2 ;
+ break ;
+
+ case 0x09:
+ filterPtr = PALYFilter2 ;
+ break ;
+
+ default:
+ return ;
+ }
+
+ if ( ModeNo <= 0x13 )
+ tempal = pVBInfo->SModeIDTable[ ModeIdIndex ].VB_StTVYFilterIndex ;
+ else
+ tempal = pVBInfo->EModeIDTable[ ModeIdIndex ].VB_ExtTVYFilterIndex ;
+
+ if ( tempcl == 0 )
+ index = tempal * 4;
+ else
+ index = tempal * 7;
+
+ if ( ( tempcl == 0 ) && ( tempch == 1 ) )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x35 , 0 ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x36 , 0 ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x37 , 0 ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x38 , filterPtr[ index++ ] ) ;
+ }
+ else
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x35 , filterPtr[ index++ ] ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x36 , filterPtr[ index++ ] ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x37 , filterPtr[ index++ ] ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x38 , filterPtr[ index++ ] ) ;
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x48 , filterPtr[ index++ ] ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x49 , filterPtr[ index++ ] ) ;
+ XGINew_SetReg1( pVBInfo->Part2Port , 0x4A , filterPtr[ index++ ] ) ;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetTVPtrIndex2 */
+/* Input : */
+/* Output : bx 0 : NTSC */
+/* 1 : PAL */
+/* 2 : PALM */
+/* 3 : PALN */
+/* 4 : NTSC1024x768 */
+/* 5 : PAL-M 1024x768 */
+/* 6-7: reserved */
+/* cl 0 : YFilter1 */
+/* 1 : YFilter2 */
+/* ch 0 : 301A */
+/* 1 : 301B/302B/301LV/302LV */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetTVPtrIndex2(USHORT* tempbx,UCHAR* tempcl,UCHAR* tempch, PVB_DEVICE_INFO pVBInfo)
+{
+ *tempbx = 0 ;
+ *tempcl = 0 ;
+ *tempch = 0 ;
+
+ if ( pVBInfo->TVInfo & SetPALTV )
+ *tempbx = 1 ;
+
+ if ( pVBInfo->TVInfo & SetPALMTV )
+ *tempbx = 2 ;
+
+ if ( pVBInfo->TVInfo & SetPALNTV )
+ *tempbx = 3 ;
+
+ if ( pVBInfo->TVInfo & NTSC1024x768 )
+ {
+ *tempbx = 4 ;
+ if ( pVBInfo->TVInfo & SetPALMTV )
+ *tempbx = 5 ;
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) || ( pVBInfo->TVInfo & TVSimuMode ) )
+ {
+ *tempbx += 8 ;
+ *tempcl += 1 ;
+ }
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ (*tempch)++ ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_SetCRT2ModeRegs */
+/* Input : */
+/* Output : */
+/* Description : Origin code for crt2group */
+/* --------------------------------------------------------------------- */
+void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbl ;
+ SHORT tempcl ;
+
+ UCHAR tempah ;
+
+ /* XGINew_SetReg1( pVBInfo->Part1Port , 0x03 , 0x00 ) ; // fix write part1 index 0 BTDRAM bit Bug */
+ tempah=0;
+ if ( !( pVBInfo->VBInfo & DisableCRT2Display ) )
+ {
+ tempah=XGINew_GetReg1( pVBInfo->Part1Port , 0x00 ) ;
+ tempah &= ~0x10 ; /* BTRAMDAC */
+ tempah |= 0x40 ; /* BTRAM */
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) )
+ {
+ tempah=0x40; /* BTDRAM */
+ if ( ModeNo > 0x13 )
+ {
+ tempcl = pVBInfo->ModeType ;
+ tempcl -= ModeVGA ;
+ if ( tempcl >= 0 )
+ {
+ tempah = ( 0x008 >> tempcl ) ; /* BT Color */
+ if ( tempah == 0 )
+ tempah = 1 ;
+ tempah |= 0x040 ;
+ }
+ }
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ tempah ^= 0x50 ; /* BTDAC */
+ }
+ }
+
+/* 0210 shampoo
+ if ( pVBInfo->VBInfo & DisableCRT2Display )
+ {
+ tempah = 0 ;
+ }
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ;
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) )
+ {
+ tempcl = pVBInfo->ModeType ;
+ if ( ModeNo > 0x13 )
+ {
+ tempcl -= ModeVGA ;
+ if ( ( tempcl > 0 ) || ( tempcl == 0 ) )
+ {
+ tempah=(0x008>>tempcl) ;
+ if ( tempah == 0 )
+ tempah = 1 ;
+ tempah |= 0x040;
+ }
+ }
+ else
+ {
+ tempah = 0x040 ;
+ }
+
+ if ( pVBInfo->VBInfo & SetInSlaveMode )
+ {
+ tempah = ( tempah ^ 0x050 ) ;
+ }
+ }
+*/
+
+ XGINew_SetReg1( pVBInfo->Part1Port , 0x00 , tempah ) ;
+ tempah = 0x08 ;
+ tempbl = 0xf0 ;
+
+ if ( pVBInfo->VBInfo & DisableCRT2Display )
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ;
+ else
+ {
+ tempah = 0x00 ;
+ tempbl = 0xff ;
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ if ( ( pVBInfo->VBInfo & SetCRT2ToLCDA ) && ( !( pVBInfo->VBInfo & SetSimuScanMode ) ) )
+ {
+ tempbl &= 0xf7 ;
+ tempah |= 0x01 ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ;
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ {
+ tempbl &= 0xf7 ;
+ tempah |= 0x01 ;
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD ) )
+ {
+ tempbl &= 0xf8 ;
+ tempah = 0x01 ;
+
+ if ( !( pVBInfo->VBInfo & SetInSlaveMode ) )
+ tempah |= 0x02 ;
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToRAMDAC ) )
+ {
+ tempah = tempah ^ 0x05 ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) )
+ tempah = tempah ^ 0x01 ;
+ }
+
+ if ( !( pVBInfo->VBInfo & SetCRT2ToDualEdge ) )
+ tempah |= 0x08 ;
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ;
+ }
+ else
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ;
+ }
+ }
+ else
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2e , tempbl , tempah ) ;
+ }
+
+ if ( pVBInfo->VBInfo & ( SetCRT2ToRAMDAC | SetCRT2ToTV | SetCRT2ToLCD | SetCRT2ToLCDA ) )
+ {
+ tempah &= ( ~0x08 ) ;
+ if ( ( pVBInfo->ModeType == ModeVGA ) && ( !( pVBInfo->VBInfo & SetInSlaveMode ) ) )
+ {
+ tempah |= 0x010 ;
+ }
+ tempah |= 0x080 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ /* if ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) */
+ /* { */
+ tempah |= 0x020 ;
+ if ( ModeNo > 0x13 )
+ {
+ if ( pVBInfo->VBInfo & DriverMode )
+ tempah = tempah ^ 0x20 ;
+ }
+ /* } */
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x0D , ~0x0BF , tempah ) ;
+ tempah = 0 ;
+
+ if ( pVBInfo->LCDInfo & SetLCDDualLink )
+ tempah |= 0x40 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ /* if ( ( !( pVBInfo->VBInfo & SetCRT2ToHiVisionTV ) ) && ( !( pVBInfo->TVInfo & ( SetYPbPrMode525p | SetYPbPrMode750p ) ) ) ) */
+ /* { */
+ if ( pVBInfo->TVInfo & RPLLDIV2XO )
+ tempah |= 0x40 ;
+ /* } */
+ }
+
+ if ( ( pVBInfo->LCDResInfo == Panel1280x1024 ) || ( pVBInfo->LCDResInfo == Panel1280x1024x75 ) )
+ tempah |= 0x80 ;
+
+ if ( pVBInfo->LCDResInfo == Panel1280x960 )
+ tempah |= 0x80 ;
+
+ XGINew_SetReg1( pVBInfo->Part4Port , 0x0C , tempah ) ;
+ }
+
+ if ( pVBInfo->VBType & ( VB_XGI301B | VB_XGI302B | VB_XGI301LV | VB_XGI302LV | VB_XGI301C ) )
+ {
+ tempah = 0 ;
+ tempbl = 0xfb ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ {
+ tempbl=0xff;
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ tempah |= 0x04 ; /* shampoo 0129 */
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x13 , tempbl , tempah ) ;
+ tempah = 0x00 ;
+ tempbl = 0xcf ;
+ if ( !( pVBInfo->VBInfo & DisableCRT2Display ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ tempah |= 0x30 ;
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2c , tempbl , tempah ) ;
+ tempah = 0 ;
+ tempbl = 0x3f ;
+
+ if ( !( pVBInfo->VBInfo & DisableCRT2Display ) )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToDualEdge )
+ tempah |= 0xc0 ;
+ }
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x21 , tempbl , tempah ) ;
+ }
+
+ tempah = 0 ;
+ tempbl = 0x7f ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCDA ) )
+ {
+ tempbl = 0xff ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToDualEdge ) )
+ tempah |= 0x80 ;
+ }
+
+ XGINew_SetRegANDOR( pVBInfo->Part4Port , 0x23 , tempbl , tempah ) ;
+
+ if ( pVBInfo->VBType & ( VB_XGI302LV | VB_XGI301C ) )
+ {
+ if ( pVBInfo->LCDInfo & SetLCDDualLink )
+ {
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x27 , 0x20 ) ;
+ XGINew_SetRegOR( pVBInfo->Part4Port , 0x34 , 0x10 ) ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_CloseCRTC */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_CloseCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ;
+
+ tempbx = 0 ;
+
+ if ( pVBInfo->VBInfo & SetCRT2ToLCDA )
+ tempbx = 0x08A0 ;
+
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_OpenCRTC */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_OpenCRTC( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempbx ;
+
+ tempbx = 0 ;
+
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetRAMDAC2DATA */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_GetRAMDAC2DATA(USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex, PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempax ,
+ tempbx ,
+ temp1 ,
+ temp2 ,
+ modeflag = 0 ,
+ tempcx ,
+ StandTableIndex ,
+ CRT1Index ;
+
+ pVBInfo->RVBHCMAX = 1 ;
+ pVBInfo->RVBHCFACT = 1 ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ StandTableIndex = XGI_GetModePtr( ModeNo , ModeIdIndex, pVBInfo ) ;
+ tempax = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 0 ] ;
+ tempbx = pVBInfo->StandTable[StandTableIndex ].CRTC[ 6 ] ;
+ temp1 = pVBInfo->StandTable[ StandTableIndex ].CRTC[ 7 ] ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ CRT1Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT1CRTC ;
+ CRT1Index &= IndexMask ;
+ temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 0 ] ;
+ temp2 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 5 ] ;
+ tempax = ( temp1 & 0xFF ) | ( ( temp2 & 0x03 ) << 8 ) ;
+ tempbx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 8 ] ;
+ tempcx = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 14 ] << 8 ;
+ tempcx &= 0x0100 ;
+ tempcx = tempcx << 2 ;
+ tempbx |= tempcx;
+ temp1 = ( USHORT )pVBInfo->XGINEWUB_CRT1Table[ CRT1Index ].CR[ 9 ] ;
+ }
+
+ if ( temp1 & 0x01 )
+ tempbx |= 0x0100 ;
+
+ if ( temp1 & 0x20 )
+ tempbx |= 0x0200 ;
+ tempax += 5 ;
+
+ if ( modeflag & Charx8Dot )
+ tempax *= 8 ;
+ else
+ tempax *= 9 ;
+
+ pVBInfo->VGAHT = tempax ;
+ pVBInfo->HT = tempax ;
+ tempbx++ ;
+ pVBInfo->VGAVT = tempbx ;
+ pVBInfo->VT = tempbx ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetColorDepth */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetColorDepth(USHORT ModeNo , USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT ColorDepth[ 6 ] = { 1 , 2 , 4 , 4 , 6 , 8 } ;
+ SHORT index ;
+ USHORT modeflag ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ;
+ }
+
+ index=(modeflag&ModeInfoFlag)-ModeEGA;
+
+ if ( index < 0 )
+ index = 0 ;
+
+ return( ColorDepth[ index ] ) ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_UnLockCRT2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_UnLockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2f , 0xFF , 0x01 ) ;
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_LockCRT2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_LockCRT2( PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO pVBInfo )
+{
+
+ XGINew_SetRegANDOR( pVBInfo->Part1Port , 0x2F , 0xFE , 0x00 ) ;
+
+
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_EnableCRT2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_EnableCRT2( PVB_DEVICE_INFO pVBInfo)
+{
+ XGINew_SetRegANDOR( pVBInfo->P3c4 , 0x1E , 0xFF , 0x20 ) ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_LCD_Wait_Time(UCHAR DelayTime, PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT i ,
+ j ;
+
+ ULONG temp ,
+ flag ;
+
+ flag = 0 ;
+//printk("XGINew_LCD_Wait_Time");
+//return;
+ for( i = 0 ; i < DelayTime ; i++ )
+ {
+ for( j = 0 ; j < 66 ; j++ )
+ {
+
+ temp = XGINew_GetReg3( 0x61 ) ;
+
+ //temp &= 0x10000000;
+ temp &= 0x10;
+ if ( temp == flag )
+ continue ;
+
+ flag = temp ;
+ }
+ }
+}
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_BridgeIsOn */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT flag ;
+
+ if ( pVBInfo->IF_DEF_LVDS == 1 )
+ {
+ return( 1 ) ;
+ }
+ else
+ {
+ flag = XGINew_GetReg1( pVBInfo->Part4Port , 0x00 ) ;
+ if ( ( flag == 1 ) || ( flag == 2 ) )
+ return( 1 ) ; /* 301b */
+ else
+ return( 0 ) ;
+ }
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_LongWait */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_LongWait(PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT i ;
+
+ i = XGINew_GetReg1( pVBInfo->P3c4 , 0x1F ) ;
+
+ if ( !( i & 0xC0 ) )
+ {
+ for( i = 0 ; i < 0xFFFF ; i++ )
+ {
+ if ( !( XGINew_GetReg2( pVBInfo->P3da ) & 0x08 ) )
+ break ;
+ }
+
+ for( i = 0 ; i < 0xFFFF ; i++ )
+ {
+ if ( ( XGINew_GetReg2( pVBInfo->P3da ) & 0x08 ) )
+ break ;
+ }
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_VBLongWait */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGI_VBLongWait( PVB_DEVICE_INFO pVBInfo )
+{
+ USHORT tempal ,
+ temp ,
+ i ,
+ j ;
+return ;
+ if ( !( pVBInfo->VBInfo & SetCRT2ToTV ) )
+ {
+ temp = 0 ;
+ for( i = 0 ; i < 3 ; i++ )
+ {
+ for( j = 0 ; j < 100 ; j++ )
+ {
+ tempal = XGINew_GetReg2( pVBInfo->P3da ) ;
+ if ( temp & 0x01 )
+ { /* VBWaitMode2 */
+ if ( ( tempal & 0x08 ) )
+ {
+ continue ;
+ }
+
+ if ( !( tempal & 0x08 ) )
+ {
+ break ;
+ }
+ }
+ else
+ { /* VBWaitMode1 */
+ if ( !( tempal & 0x08 ) )
+ {
+ continue ;
+ }
+
+ if ( ( tempal & 0x08 ) )
+ {
+ break ;
+ }
+ }
+ }
+ temp = temp ^ 0x01 ;
+ }
+ }
+ else
+ {
+ XGI_LongWait(pVBInfo) ;
+ }
+ return ;
+}
+
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVGAHT2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetVGAHT2( PVB_DEVICE_INFO pVBInfo )
+{
+ ULONG tempax ,
+ tempbx ;
+
+ tempbx = ( ( pVBInfo->VGAVT - pVBInfo->VGAVDE ) * pVBInfo->RVBHCMAX ) & 0xFFFF ;
+ tempax = ( pVBInfo->VT - pVBInfo->VDE ) * pVBInfo->RVBHCFACT ;
+ tempax = ( tempax * pVBInfo->HT ) /tempbx ;
+
+ return( ( USHORT )tempax ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGI_GetVCLK2Ptr */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+USHORT XGI_GetVCLK2Ptr( USHORT ModeNo , USHORT ModeIdIndex , USHORT RefreshRateTableIndex , PXGI_HW_DEVICE_INFO HwDeviceExtension ,PVB_DEVICE_INFO pVBInfo)
+{
+ USHORT tempbx ;
+
+ USHORT LCDXlat1VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+ USHORT LCDXlat2VCLK[ 4 ] = { VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 , VCLK108_2 + 5 } ;
+ USHORT LVDSXlat1VCLK[ 4 ] = { VCLK40 , VCLK40 , VCLK40 , VCLK40 } ;
+ USHORT LVDSXlat2VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+ USHORT LVDSXlat3VCLK[ 4 ] = { VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 , VCLK65 + 2 } ;
+
+ USHORT CRT2Index , VCLKIndex ;
+ USHORT modeflag , resinfo ;
+ UCHAR *CHTVVCLKPtr = NULL ;
+
+ if ( ModeNo <= 0x13 )
+ {
+ modeflag = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ModeFlag ; /* si+St_ResInfo */
+ resinfo = pVBInfo->SModeIDTable[ ModeIdIndex ].St_ResInfo ;
+ CRT2Index = pVBInfo->SModeIDTable[ ModeIdIndex ].St_CRT2CRTC ;
+ }
+ else
+ {
+ modeflag = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_ModeFlag ; /* si+Ext_ResInfo */
+ resinfo = pVBInfo->EModeIDTable[ ModeIdIndex ].Ext_RESINFO ;
+ CRT2Index = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRT2CRTC ;
+ }
+
+ if ( pVBInfo->IF_DEF_LVDS == 0 )
+ {
+ CRT2Index = CRT2Index >> 6 ; /* for LCD */
+ if ( ( ( pVBInfo->VBInfo & SetCRT2ToLCD ) | SetCRT2ToLCDA ) ) /*301b*/
+ {
+ if ( pVBInfo->LCDResInfo != Panel1024x768 )
+ {
+ VCLKIndex = LCDXlat2VCLK[ CRT2Index ] ;
+ }
+ else
+ {
+ VCLKIndex = LCDXlat1VCLK[ CRT2Index ] ;
+ }
+ }
+ else /* for TV */
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToHiVisionTV )
+ {
+ if ( pVBInfo->SetFlag & RPLLDIV2XO )
+ {
+ VCLKIndex = HiTVVCLKDIV2 ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+ else
+ {
+ VCLKIndex = HiTVVCLK ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+
+ if ( pVBInfo->SetFlag & TVSimuMode )
+ {
+ if( modeflag & Charx8Dot )
+ {
+ VCLKIndex = HiTVSimuVCLK ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+ else
+ {
+ VCLKIndex = HiTVTextVCLK ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+ }
+
+ if ( pVBInfo->VBType & VB_XGI301LV ) /* 301lv */
+ {
+ if ( !( pVBInfo->VBExtInfo == VB_YPbPr1080i ) )
+ {
+ VCLKIndex = YPbPr750pVCLK ;
+ if ( !( pVBInfo->VBExtInfo == VB_YPbPr750p ) )
+ {
+ VCLKIndex = YPbPr525pVCLK ;
+ if ( !( pVBInfo->VBExtInfo == VB_YPbPr525p ) )
+ {
+ VCLKIndex = YPbPr525iVCLK_2 ;
+ if ( !( pVBInfo->SetFlag & RPLLDIV2XO ) )
+ VCLKIndex = YPbPr525iVCLK ;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if ( pVBInfo->VBInfo & SetCRT2ToTV )
+ {
+ if ( pVBInfo->SetFlag & RPLLDIV2XO )
+ {
+ VCLKIndex = TVVCLKDIV2 ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+ else
+ {
+ VCLKIndex = TVVCLK ;
+
+
+ VCLKIndex += 25 ;
+
+ }
+ }
+ }
+ }
+ else
+ { /* for CRT2 */
+ VCLKIndex = ( UCHAR )XGINew_GetReg2( ( pVBInfo->P3ca + 0x02 ) ) ; /* Port 3cch */
+ VCLKIndex = ( ( VCLKIndex >> 2 ) & 0x03 ) ;
+ if ( ModeNo > 0x13 )
+ {
+ VCLKIndex = pVBInfo->RefIndex[ RefreshRateTableIndex ].Ext_CRTVCLK ; /* di+Ext_CRTVCLK */
+ VCLKIndex &= IndexMask ;
+ }
+ }
+ }
+ }
+ else
+ { /* LVDS */
+ if ( ModeNo <= 0x13 )
+ VCLKIndex = CRT2Index ;
+ else
+ VCLKIndex = CRT2Index ;
+
+ if ( pVBInfo->IF_DEF_CH7005 == 1 )
+ {
+ if ( !( pVBInfo->VBInfo & SetCRT2ToLCD ) )
+ {
+ VCLKIndex &= 0x1f ;
+ tempbx = 0 ;
+
+ if ( pVBInfo->VBInfo & SetPALTV )
+ tempbx += 2 ;
+
+ if ( pVBInfo->VBInfo & SetCHTVOverScan )
+ tempbx += 1 ;
+
+ switch( tempbx )
+ {
+ case 0:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKUNTSC ;
+ break ;
+ case 1:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKONTSC ;
+ break;
+ case 2:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKUPAL ;
+ break ;
+ case 3:
+ CHTVVCLKPtr = pVBInfo->CHTVVCLKOPAL ;
+ break ;
+ default:
+ break ;
+ }
+
+ VCLKIndex = CHTVVCLKPtr[ VCLKIndex ] ;
+ }
+ }
+ else
+ {
+ VCLKIndex = VCLKIndex >> 6 ;
+ if ( ( pVBInfo->LCDResInfo == Panel800x600 ) || ( pVBInfo->LCDResInfo == Panel320x480 ) )
+ VCLKIndex = LVDSXlat1VCLK[ VCLKIndex ] ;
+ else if ( ( pVBInfo->LCDResInfo == Panel1024x768 ) || ( pVBInfo->LCDResInfo == Panel1024x768x75 ) )
+ VCLKIndex = LVDSXlat2VCLK[ VCLKIndex ] ;
+ else
+ VCLKIndex = LVDSXlat3VCLK[ VCLKIndex ] ;
+ }
+ }
+ /* VCLKIndex = VCLKIndex&IndexMask ; */
+
+
+
+ return( VCLKIndex ) ;
+}
+
diff --git a/drivers/staging/xgifb/vb_setmode.h b/drivers/staging/xgifb/vb_setmode.h
new file mode 100644
index 000000000000..09753d706665
--- /dev/null
+++ b/drivers/staging/xgifb/vb_setmode.h
@@ -0,0 +1,40 @@
+#ifndef _VBSETMODE_
+#define _VBSETMODE_
+
+extern void InitTo330Pointer(UCHAR,PVB_DEVICE_INFO);
+extern void XGI_UnLockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_LockCRT2(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_LongWait( PVB_DEVICE_INFO );
+extern void XGI_SetCRT2ModeRegs(USHORT ModeNo,PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
+extern void XGI_DisableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_EnableBridge(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_DisplayOff( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
+extern void XGI_DisplayOn( PXGI_HW_DEVICE_INFO, PVB_DEVICE_INFO );
+extern void XGI_GetVBType(PVB_DEVICE_INFO);
+extern void XGI_SenseCRT1(PVB_DEVICE_INFO );
+extern void XGI_GetVGAType(PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_GetVBInfo(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_GetTVInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO );
+extern void XGI_SetCRT1Offset(USHORT ModeNo,USHORT ModeIdIndex,USHORT RefreshRateTableIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_SetLCDAGroup(USHORT ModeNo,USHORT ModeIdIndex,PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO );
+extern void XGI_WaitDisply( PVB_DEVICE_INFO );
+extern USHORT XGI_GetResInfo(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo);
+
+extern BOOLEAN XGISetModeNew( PXGI_HW_DEVICE_INFO HwDeviceExtension , USHORT ModeNo ) ;
+
+extern BOOLEAN XGI_SearchModeID( USHORT ModeNo,USHORT *ModeIdIndex, PVB_DEVICE_INFO );
+extern BOOLEAN XGI_GetLCDInfo(USHORT ModeNo,USHORT ModeIdIndex,PVB_DEVICE_INFO );
+extern BOOLEAN XGI_BridgeIsOn( PVB_DEVICE_INFO );
+extern BOOLEAN XGI_SetCRT2Group301(USHORT ModeNo, PXGI_HW_DEVICE_INFO HwDeviceExtension, PVB_DEVICE_INFO);
+extern USHORT XGI_GetRatePtrCRT2( PXGI_HW_DEVICE_INFO pXGIHWDE, USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO );
+
+extern void XGI_SetXG21FPBits(PVB_DEVICE_INFO pVBInfo);
+extern void XGI_SetXG27FPBits(PVB_DEVICE_INFO pVBInfo);
+extern void XGI_XG21BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+extern void XGI_XG27BLSignalVDD(USHORT tempbh,USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+extern void XGI_XG21SetPanelDelay(USHORT tempbl, PVB_DEVICE_INFO pVBInfo);
+extern BOOLEAN XGI_XG21CheckLVDSMode(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
+extern void XGI_SetXG21LVDSPara(USHORT ModeNo,USHORT ModeIdIndex, PVB_DEVICE_INFO pVBInfo );
+extern USHORT XGI_GetLVDSOEMTableIndex(PVB_DEVICE_INFO pVBInfo);
+
+#endif
diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h
new file mode 100644
index 000000000000..bb25c0e2785e
--- /dev/null
+++ b/drivers/staging/xgifb/vb_struct.h
@@ -0,0 +1,534 @@
+#ifndef _VB_STRUCT_
+#define _VB_STRUCT_
+
+#ifdef _INITNEW_
+#define EXTERN
+#else
+#define EXTERN extern
+#endif
+
+
+
+
+typedef struct _XGI_PanelDelayTblStruct
+{
+ UCHAR timer[2];
+} XGI_PanelDelayTblStruct;
+
+typedef struct _XGI_LCDDataStruct
+{
+ USHORT RVBHCMAX;
+ USHORT RVBHCFACT;
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT LCDHT;
+ USHORT LCDVT;
+} XGI_LCDDataStruct;
+
+
+typedef struct _XGI_LVDSCRT1HDataStruct
+{
+ UCHAR Reg[8];
+} XGI_LVDSCRT1HDataStruct;
+typedef struct _XGI_LVDSCRT1VDataStruct
+{
+ UCHAR Reg[7];
+} XGI_LVDSCRT1VDataStruct;
+
+
+typedef struct _XGI_TVDataStruct
+{
+ USHORT RVBHCMAX;
+ USHORT RVBHCFACT;
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT TVHDE;
+ USHORT TVVDE;
+ USHORT RVBHRS;
+ UCHAR FlickerMode;
+ USHORT HALFRVBHRS;
+ UCHAR RY1COE;
+ UCHAR RY2COE;
+ UCHAR RY3COE;
+ UCHAR RY4COE;
+} XGI_TVDataStruct;
+
+typedef struct _XGI_LVDSDataStruct
+{
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT LCDHT;
+ USHORT LCDVT;
+} XGI_LVDSDataStruct;
+
+typedef struct _XGI_LVDSDesStruct
+{
+ USHORT LCDHDES;
+ USHORT LCDVDES;
+} XGI_LVDSDesStruct;
+
+typedef struct _XGI_LVDSCRT1DataStruct
+{
+ UCHAR CR[15];
+} XGI_LVDSCRT1DataStruct;
+
+/*add for LCDA*/
+
+
+typedef struct _XGI_StStruct
+{
+ UCHAR St_ModeID;
+ USHORT St_ModeFlag;
+ UCHAR St_StTableIndex;
+ UCHAR St_CRT2CRTC;
+ UCHAR St_CRT2CRTC2;
+ UCHAR St_ResInfo;
+ UCHAR VB_StTVFlickerIndex;
+ UCHAR VB_StTVEdgeIndex;
+ UCHAR VB_StTVYFilterIndex;
+} XGI_StStruct;
+
+typedef struct _XGI_StandTableStruct
+{
+ UCHAR CRT_COLS;
+ UCHAR ROWS;
+ UCHAR CHAR_HEIGHT;
+ USHORT CRT_LEN;
+ UCHAR SR[4];
+ UCHAR MISC;
+ UCHAR CRTC[0x19];
+ UCHAR ATTR[0x14];
+ UCHAR GRC[9];
+} XGI_StandTableStruct;
+
+typedef struct _XGI_ExtStruct
+{
+ UCHAR Ext_ModeID;
+ USHORT Ext_ModeFlag;
+ USHORT Ext_ModeInfo;
+ USHORT Ext_Point;
+ USHORT Ext_VESAID;
+ UCHAR Ext_VESAMEMSize;
+ UCHAR Ext_RESINFO;
+ UCHAR VB_ExtTVFlickerIndex;
+ UCHAR VB_ExtTVEdgeIndex;
+ UCHAR VB_ExtTVYFilterIndex;
+ UCHAR REFindex;
+} XGI_ExtStruct;
+
+typedef struct _XGI_Ext2Struct
+{
+ USHORT Ext_InfoFlag;
+ UCHAR Ext_CRT1CRTC;
+ UCHAR Ext_CRTVCLK;
+ UCHAR Ext_CRT2CRTC;
+ UCHAR Ext_CRT2CRTC2;
+ UCHAR ModeID;
+ USHORT XRes;
+ USHORT YRes;
+ /* USHORT ROM_OFFSET; */
+} XGI_Ext2Struct;
+
+
+typedef struct _XGI_MCLKDataStruct
+{
+ UCHAR SR28,SR29,SR2A;
+ USHORT CLOCK;
+} XGI_MCLKDataStruct;
+
+typedef struct _XGI_ECLKDataStruct
+{
+ UCHAR SR2E,SR2F,SR30;
+ USHORT CLOCK;
+} XGI_ECLKDataStruct;
+
+typedef struct _XGI_VCLKDataStruct
+{
+ UCHAR SR2B,SR2C;
+ USHORT CLOCK;
+} XGI_VCLKDataStruct;
+
+typedef struct _XGI_VBVCLKDataStruct
+{
+ UCHAR Part4_A,Part4_B;
+ USHORT CLOCK;
+} XGI_VBVCLKDataStruct;
+
+typedef struct _XGI_StResInfoStruct
+{
+ USHORT HTotal;
+ USHORT VTotal;
+} XGI_StResInfoStruct;
+
+typedef struct _XGI_ModeResInfoStruct
+{
+ USHORT HTotal;
+ USHORT VTotal;
+ UCHAR XChar;
+ UCHAR YChar;
+} XGI_ModeResInfoStruct;
+
+typedef struct _XGI_LCDNBDesStruct
+{
+ UCHAR NB[12];
+} XGI_LCDNBDesStruct;
+ /*add for new UNIVGABIOS*/
+typedef struct _XGI_LCDDesStruct
+{
+ USHORT LCDHDES;
+ USHORT LCDHRS;
+ USHORT LCDVDES;
+ USHORT LCDVRS;
+} XGI_LCDDesStruct;
+
+typedef struct _XGI_LCDDataTablStruct
+{
+ UCHAR PANELID;
+ USHORT MASK;
+ USHORT CAP;
+ USHORT DATAPTR;
+} XGI_LCDDataTablStruct;
+
+typedef struct _XGI_TVTablDataStruct
+{
+ USHORT MASK;
+ USHORT CAP;
+ USHORT DATAPTR;
+} XGI_TVDataTablStruct;
+
+typedef struct _XGI330_LCDDesDataStruct
+{
+ USHORT LCDHDES;
+ USHORT LCDHRS;
+ USHORT LCDVDES;
+ USHORT LCDVRS;
+} XGI330_LCDDataDesStruct;
+
+
+typedef struct _XGI330_LVDSDataStruct
+{
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT LCDHT;
+ USHORT LCDVT;
+} XGI330_LVDSDataStruct;
+
+typedef struct _XGI330_LCDDesDataStruct2
+{
+ USHORT LCDHDES;
+ USHORT LCDHRS;
+ USHORT LCDVDES;
+ USHORT LCDVRS;
+ USHORT LCDHSync;
+ USHORT LCDVSync;
+} XGI330_LCDDataDesStruct2;
+
+typedef struct _XGI330_LCDDataStruct
+{
+ USHORT RVBHCMAX;
+ USHORT RVBHCFACT;
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT LCDHT;
+ USHORT LCDVT;
+} XGI330_LCDDataStruct;
+
+
+typedef struct _XGI330_TVDataStruct
+{
+ USHORT RVBHCMAX;
+ USHORT RVBHCFACT;
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT TVHDE;
+ USHORT TVVDE;
+ USHORT RVBHRS;
+ UCHAR FlickerMode;
+ USHORT HALFRVBHRS;
+} XGI330_TVDataStruct;
+
+typedef struct _XGI330_LCDDataTablStruct
+{
+ UCHAR PANELID;
+ USHORT MASK;
+ USHORT CAP;
+ USHORT DATAPTR;
+} XGI330_LCDDataTablStruct;
+
+typedef struct _XGI330_TVDataTablStruct
+{
+ USHORT MASK;
+ USHORT CAP;
+ USHORT DATAPTR;
+} XGI330_TVDataTablStruct;
+
+
+typedef struct _XGI330_CHTVDataStruct
+{
+ USHORT VGAHT;
+ USHORT VGAVT;
+ USHORT LCDHT;
+ USHORT LCDVT;
+} XGI330_CHTVDataStruct;
+
+typedef struct _XGI_TimingHStruct
+{
+ UCHAR data[8];
+} XGI_TimingHStruct;
+
+typedef struct _XGI_TimingVStruct
+{
+ UCHAR data[7];
+} XGI_TimingVStruct;
+
+typedef struct _XGI_CH7007TV_TimingHStruct
+{
+ UCHAR data[10];
+} XGI_CH7007TV_TimingHStruct;
+
+typedef struct _XGI_CH7007TV_TimingVStruct
+{
+ UCHAR data[10];
+} XGI_CH7007TV_TimingVStruct;
+
+typedef struct _XGI_XG21CRT1Struct
+{
+ UCHAR ModeID,CR02,CR03,CR15,CR16;
+} XGI_XG21CRT1Struct;
+
+typedef struct _XGI330_CHTVRegDataStruct
+{
+ UCHAR Reg[16];
+} XGI330_CHTVRegDataStruct;
+
+typedef struct _XGI330_LCDCapStruct
+{
+ UCHAR LCD_ID;
+ USHORT LCD_Capability;
+ UCHAR LCD_SetFlag;
+ UCHAR LCD_DelayCompensation;
+ UCHAR LCD_HSyncWidth;
+ UCHAR LCD_VSyncWidth;
+ UCHAR LCD_VCLK;
+ UCHAR LCDA_VCLKData1;
+ UCHAR LCDA_VCLKData2;
+ UCHAR LCUCHAR_VCLKData1;
+ UCHAR LCUCHAR_VCLKData2;
+ UCHAR PSC_S1;
+ UCHAR PSC_S2;
+ UCHAR PSC_S3;
+ UCHAR PSC_S4;
+ UCHAR PSC_S5;
+ UCHAR PWD_2B;
+ UCHAR PWD_2C;
+ UCHAR PWD_2D;
+ UCHAR PWD_2E;
+ UCHAR PWD_2F;
+ UCHAR Spectrum_31;
+ UCHAR Spectrum_32;
+ UCHAR Spectrum_33;
+ UCHAR Spectrum_34;
+} XGI330_LCDCapStruct;
+
+typedef struct _XGI21_LVDSCapStruct
+{
+ USHORT LVDS_Capability;
+ USHORT LVDSHT;
+ USHORT LVDSVT;
+ USHORT LVDSHDE;
+ USHORT LVDSVDE;
+ USHORT LVDSHFP;
+ USHORT LVDSVFP;
+ USHORT LVDSHSYNC;
+ USHORT LVDSVSYNC;
+ UCHAR VCLKData1;
+ UCHAR VCLKData2;
+ UCHAR PSC_S1;
+ UCHAR PSC_S2;
+ UCHAR PSC_S3;
+ UCHAR PSC_S4;
+ UCHAR PSC_S5;
+} XGI21_LVDSCapStruct;
+
+typedef struct _XGI_CRT1TableStruct
+{
+ UCHAR CR[16];
+} XGI_CRT1TableStruct;
+
+
+typedef struct _XGI330_VCLKDataStruct
+{
+ UCHAR SR2B,SR2C;
+ USHORT CLOCK;
+} XGI330_VCLKDataStruct;
+
+typedef struct _XGI301C_Tap4TimingStruct
+{
+ USHORT DE;
+ UCHAR Reg[64]; /* C0-FF */
+} XGI301C_Tap4TimingStruct;
+
+typedef struct _XGI_New_StandTableStruct
+{
+ UCHAR CRT_COLS;
+ UCHAR ROWS;
+ UCHAR CHAR_HEIGHT;
+ USHORT CRT_LEN;
+ UCHAR SR[4];
+ UCHAR MISC;
+ UCHAR CRTC[0x19];
+ UCHAR ATTR[0x14];
+ UCHAR GRC[9];
+} XGI_New_StandTableStruct;
+
+typedef UCHAR DRAM8Type[8];
+typedef UCHAR DRAM4Type[4];
+typedef UCHAR DRAM32Type[32];
+typedef UCHAR DRAM2Type[2];
+
+typedef struct _VB_DEVICE_INFO VB_DEVICE_INFO;
+typedef VB_DEVICE_INFO * PVB_DEVICE_INFO;
+
+struct _VB_DEVICE_INFO
+{
+ BOOLEAN ISXPDOS;
+ ULONG P3c4,P3d4,P3c0,P3ce,P3c2,P3cc;
+ ULONG P3ca,P3c6,P3c7,P3c8,P3c9,P3da;
+ ULONG Part0Port,Part1Port,Part2Port;
+ ULONG Part3Port,Part4Port,Part5Port;
+ USHORT RVBHCFACT,RVBHCMAX,RVBHRS;
+ USHORT VGAVT,VGAHT,VGAVDE,VGAHDE;
+ USHORT VT,HT,VDE,HDE;
+ USHORT LCDHRS,LCDVRS,LCDHDES,LCDVDES;
+
+ USHORT ModeType;
+ USHORT IF_DEF_LVDS,IF_DEF_TRUMPION,IF_DEF_DSTN;/* ,IF_DEF_FSTN; add for dstn */
+ USHORT IF_DEF_CRT2Monitor,IF_DEF_VideoCapture;
+ USHORT IF_DEF_LCDA,IF_DEF_CH7017,IF_DEF_YPbPr,IF_DEF_ScaleLCD,IF_DEF_OEMUtil,IF_DEF_PWD;
+ USHORT IF_DEF_ExpLink;
+ USHORT IF_DEF_CH7005,IF_DEF_HiVision;
+ USHORT IF_DEF_CH7007; /* Billy 2007/05/03 */
+ USHORT LCDResInfo,LCDTypeInfo, VBType;/*301b*/
+ USHORT VBInfo,TVInfo,LCDInfo, Set_VGAType;
+ USHORT VBExtInfo;/*301lv*/
+ USHORT SetFlag;
+ USHORT NewFlickerMode;
+ USHORT SelectCRT2Rate;
+
+ PUCHAR ROMAddr;
+ PUCHAR FBAddr;
+ ULONG BaseAddr;
+ ULONG RelIO;
+
+ DRAM4Type *CR6B;
+ DRAM4Type *CR6E;
+ DRAM32Type *CR6F;
+ DRAM2Type *CR89;
+
+ DRAM8Type *SR15; /* pointer : point to array */
+ DRAM8Type *CR40;
+ UCHAR *pSoftSetting;
+ UCHAR *pOutputSelect;
+
+ USHORT *pRGBSenseData;
+ USHORT *pRGBSenseData2; /*301b*/
+ USHORT *pVideoSenseData;
+ USHORT *pVideoSenseData2;
+ USHORT *pYCSenseData;
+ USHORT *pYCSenseData2;
+
+ UCHAR *pSR07;
+ UCHAR *CR49;
+ UCHAR *pSR1F;
+ UCHAR *AGPReg;
+ UCHAR *SR16;
+ UCHAR *pSR21;
+ UCHAR *pSR22;
+ UCHAR *pSR23;
+ UCHAR *pSR24;
+ UCHAR *SR25;
+ UCHAR *pSR31;
+ UCHAR *pSR32;
+ UCHAR *pSR33;
+ UCHAR *pSR36; /* alan 12/07/2006 */
+ UCHAR *pCRCF;
+ UCHAR *pCRD0; /* alan 12/07/2006 */
+ UCHAR *pCRDE; /* alan 12/07/2006 */
+ UCHAR *pCR8F; /* alan 12/07/2006 */
+ UCHAR *pSR40; /* alan 12/07/2006 */
+ UCHAR *pSR41; /* alan 12/07/2006 */
+ UCHAR *pDVOSetting;
+ UCHAR *pCR2E;
+ UCHAR *pCR2F;
+ UCHAR *pCR46;
+ UCHAR *pCR47;
+ UCHAR *pCRT2Data_1_2;
+ UCHAR *pCRT2Data_4_D;
+ UCHAR *pCRT2Data_4_E;
+ UCHAR *pCRT2Data_4_10;
+ XGI_MCLKDataStruct *MCLKData;
+ XGI_ECLKDataStruct *ECLKData;
+
+ UCHAR *XGI_TVDelayList;
+ UCHAR *XGI_TVDelayList2;
+ UCHAR *CHTVVCLKUNTSC;
+ UCHAR *CHTVVCLKONTSC;
+ UCHAR *CHTVVCLKUPAL;
+ UCHAR *CHTVVCLKOPAL;
+ UCHAR *NTSCTiming;
+ UCHAR *PALTiming;
+ UCHAR *HiTVExtTiming;
+ UCHAR *HiTVSt1Timing;
+ UCHAR *HiTVSt2Timing;
+ UCHAR *HiTVTextTiming;
+ UCHAR *YPbPr750pTiming;
+ UCHAR *YPbPr525pTiming;
+ UCHAR *YPbPr525iTiming;
+ UCHAR *HiTVGroup3Data;
+ UCHAR *HiTVGroup3Simu;
+ UCHAR *HiTVGroup3Text;
+ UCHAR *Ren525pGroup3;
+ UCHAR *Ren750pGroup3;
+ UCHAR *ScreenOffset;
+ UCHAR *pXGINew_DRAMTypeDefinition;
+ UCHAR *pXGINew_I2CDefinition ;
+ UCHAR *pXGINew_CR97 ;
+
+ XGI330_LCDCapStruct *LCDCapList;
+ XGI21_LVDSCapStruct *XG21_LVDSCapList;
+
+ XGI_TimingHStruct *TimingH;
+ XGI_TimingVStruct *TimingV;
+
+ XGI_StStruct *SModeIDTable;
+ XGI_StandTableStruct *StandTable;
+ XGI_ExtStruct *EModeIDTable;
+ XGI_Ext2Struct *RefIndex;
+ /* XGINew_CRT1TableStruct *CRT1Table; */
+ XGI_CRT1TableStruct *XGINEWUB_CRT1Table;
+ XGI_VCLKDataStruct *VCLKData;
+ XGI_VBVCLKDataStruct *VBVCLKData;
+ XGI_StResInfoStruct *StResInfo;
+ XGI_ModeResInfoStruct *ModeResInfo;
+ XGI_XG21CRT1Struct *UpdateCRT1;
+}; /* _VB_DEVICE_INFO */
+
+
+typedef struct
+{
+ USHORT Horizontal_ACTIVE;
+ USHORT Horizontal_FP;
+ USHORT Horizontal_SYNC;
+ USHORT Horizontal_BP;
+ USHORT Vertical_ACTIVE;
+ USHORT Vertical_FP;
+ USHORT Vertical_SYNC;
+ USHORT Vertical_BP;
+ double DCLK;
+ UCHAR FrameRate;
+ UCHAR Interlace;
+ USHORT Margin;
+} TimingInfo;
+
+#define _VB_STRUCT_
+#endif /* _VB_STRUCT_ */
diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h
new file mode 100644
index 000000000000..781caefc56b1
--- /dev/null
+++ b/drivers/staging/xgifb/vb_table.h
@@ -0,0 +1,4406 @@
+#define Tap4
+
+
+XGI_MCLKDataStruct XGI330New_MCLKData[]=
+{
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166},
+ { 0x7C,0x08,0x80,200},
+ { 0x79,0x06,0x80,250},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300}
+};
+//yilin modify for xgi20
+XGI_MCLKDataStruct XGI340New_MCLKData[]=
+{
+ { 0x16,0x01,0x01,166},
+ { 0x19,0x02,0x01,124},
+ { 0x7C,0x08,0x01,200},
+ { 0x79,0x06,0x01,250},
+ { 0x29,0x01,0x81,301},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166}
+};
+
+XGI_MCLKDataStruct XGI27New_MCLKData[]=
+{
+ { 0x5c,0x23,0x01,166},
+ { 0x19,0x02,0x01,124},
+ { 0x7C,0x08,0x80,200},
+ { 0x79,0x06,0x80,250},
+ { 0x29,0x01,0x81,300},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166}
+};
+
+XGI_ECLKDataStruct XGI330_ECLKData[]=
+{
+ { 0x7c,0x08,0x01,200},
+ { 0x7c,0x08,0x01,200},
+ { 0x7C,0x08,0x80,200},
+ { 0x79,0x06,0x80,250},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300},
+ { 0x29,0x01,0x81,300}
+};
+//yilin modify for xgi20
+XGI_ECLKDataStruct XGI340_ECLKData[]=
+{
+ { 0x5c,0x23,0x01,166},
+ { 0x55,0x84,0x01,123},
+ { 0x7C,0x08,0x01,200},
+ { 0x79,0x06,0x01,250},
+ { 0x29,0x01,0x81,301},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166},
+ { 0x5c,0x23,0x01,166}
+};
+
+
+
+UCHAR XGI340_SR13[4][8]={
+{0x35,0x45,0xb1,0x00,0x00,0x00,0x00,0x00},/* SR13 */
+{0x41,0x51,0x5c,0x00,0x00,0x00,0x00,0x00},/* SR14 */
+{0x31,0x42,0x42,0x00,0x00,0x00,0x00,0x00},/* SR18 */
+{0x03,0x03,0x03,0x00,0x00,0x00,0x00,0x00}/* SR1B */
+};
+
+UCHAR XGI340_cr41[24][8]=
+{{0x20,0x50,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
+{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
+{0xc4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */
+{0xb5,0xa4,0xa4,0x00,0x00,0x00,0x00,0x00},
+{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},
+{0x90,0x90,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */
+{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */
+{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */
+{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */
+{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */
+{0x88,0xa8,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */
+{0x44,0x44,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */
+{0x48,0x48,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */
+{0x54,0x54,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */
+{0x54,0x54,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */
+{0x0a,0x0a,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */
+{0x44,0x44,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */
+{0x10,0x10,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */
+{0x11,0x11,0x0a,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */
+{0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */
+{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */
+{0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */
+};
+
+
+UCHAR XGI27_cr41[24][8]=
+{
+{0x20,0x40,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
+{0xC4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
+{0xC4,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */
+{0xB5,0x13,0xa4,0x00,0x00,0x00,0x00,0x00},/* 3 CR40[7],CR99[2:0],CR45[3:0]*/
+{0xf0,0xf5,0xf0,0x00,0x00,0x00,0x00,0x00},/* 4 CR59 */
+{0x90,0x90,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */
+{0x77,0x67,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */
+{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */
+{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */
+{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */
+{0x88,0xcc,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */
+{0x44,0x88,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */
+{0x48,0x88,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */
+{0x54,0x32,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */
+{0x54,0x33,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */
+{0x0a,0x07,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */
+{0x44,0x63,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */
+{0x10,0x14,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */
+{0x11,0x0B,0x0C,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */
+{0x05,0x22,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */
+{0xf0,0xf0,0x00,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */
+{0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */
+};
+
+
+#if 0
+UCHAR XGI27_cr41[24][8]=
+{
+{0x20,0x60,0x60,0x00,0x00,0x00,0x00,0x00},/* 0 CR41 */
+{0x04,0x44,0x84,0x00,0x00,0x00,0x00,0x00},/* 1 CR8A */
+{0x04,0x40,0x84,0x00,0x00,0x00,0x00,0x00},/* 2 CR8B */
+{0xb5,0x03,0xa4,0x00,0x00,0x00,0x00,0x00},/* 3 CR40[7],CR99[2:0],CR45[3:0]*/
+{0xf0,0xf5,0xf0,0x00,0x00,0x00,0x00,0x00},/* 4 CR59 */
+{0xa4,0x1C,0x24,0x00,0x00,0x00,0x00,0x00},/* 5 CR68 */
+{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 6 CR69 */
+{0x77,0x77,0x44,0x00,0x00,0x00,0x00,0x00},/* 7 CR6A */
+{0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00},/* 8 CR6D */
+{0x55,0x55,0x55,0x00,0x00,0x00,0x00,0x00},/* 9 CR80 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/* 10 CR81 */
+{0x48,0xa8,0x48,0x00,0x00,0x00,0x00,0x00},/* 11 CR82 */
+{0x77,0x88,0x77,0x00,0x00,0x00,0x00,0x00},/* 12 CR85 */
+{0x88,0x88,0x88,0x00,0x00,0x00,0x00,0x00},/* 13 CR86 */
+{0x44,0x32,0x44,0x00,0x00,0x00,0x00,0x00},/* 14 CR90 */
+{0x44,0x33,0x44,0x00,0x00,0x00,0x00,0x00},/* 15 CR91 */
+{0x07,0x07,0x07,0x00,0x00,0x00,0x00,0x00},/* 16 CR92 */
+{0x44,0x63,0x44,0x00,0x00,0x00,0x00,0x00},/* 17 CR93 */
+{0x0A,0x14,0x0A,0x00,0x00,0x00,0x00,0x00},/* 18 CR94 */
+{0x0C,0x0B,0x0C,0x00,0x00,0x00,0x00,0x00},/* 19 CR95 */
+{0x05,0x22,0x05,0x00,0x00,0x00,0x00,0x00},/* 20 CR96 */
+{0xf0,0xf0,0xf0,0x00,0x00,0x00,0x00,0x00},/* 21 CRC3 */
+{0x03,0x00,0x02,0x00,0x00,0x00,0x00,0x00},/* 22 CRC4 */
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}/* 23 CRC5 */
+};
+#endif
+UCHAR XGI340_CR6B[8][4]={
+{0xaa,0xaa,0xaa,0xaa},
+{0xaa,0xaa,0xaa,0xaa},
+{0xaa,0xaa,0xaa,0xaa},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00}
+};
+
+UCHAR XGI340_CR6E[8][4]={
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00}
+};
+
+UCHAR XGI340_CR6F[8][32]={
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+UCHAR XGI340_CR89[8][2]={
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00},
+{0x00,0x00}
+};
+ /* CR47,CR48,CR49,CR4A,CR4B,CR4C,CR70,CR71,CR74,CR75,CR76,CR77 */
+UCHAR XGI340_AGPReg[12]={0x28,0x23,0x00,0x20,0x00,0x20,0x00,0x05,0xd0,0x10,0x10,0x00};
+
+UCHAR XGI340_SR16[4]={0x03,0x83,0x03,0x83};
+
+UCHAR XGI330_SR15_1[8][8]={
+{0x0,0x0,0x00,0x00,0x20,0x20,0x00,0x00},
+{0x5,0x15,0x15,0x15,0x15,0x15,0x00,0x00},
+{0xba,0xba,0xba,0xba,0xBA,0xBA,0x00,0x00},
+{0x55,0x57,0x57,0xAB,0xAB,0xAB,0x00,0x00},
+{0x60,0x34,0x34,0x34,0x34,0x34,0x00,0x00},
+{0x0,0x80,0x80,0x80,0x83,0x83,0x00,0x00},
+{0x50,0x50,0x50,0x3C,0x3C,0x3C,0x00,0x00},
+{0x0,0xa5,0xfb,0xf6,0xF6,0xF6,0x00,0x00}
+};
+
+UCHAR XGI330_cr40_1[15][8]={
+{0x66,0x40,0x40,0x28,0x24,0x24,0x00,0x00},
+{0x66,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x0F,0x0F,0x00,0x00},
+{0x00,0xf0,0xf0,0xf0,0xF0,0xF0,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x10,0x10,0x10,0x10,0x20,0x20,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x88,0x88,0x88,0xAA,0xAC,0xAC,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x77,0x77,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
+{0x00,0xA2,0x00,0x00,0xA2,0xA2,0x00,0x00},
+};
+
+UCHAR XGI330_sr25[]={0x00,0x0};
+UCHAR XGI330_sr31=0xc0;
+UCHAR XGI330_sr32=0x11;
+UCHAR XGI330_SR33=0x00;
+UCHAR XG40_CRCF=0x13;
+UCHAR XG40_DRAMTypeDefinition=0xFF ;
+
+XGI_StStruct XGI330_SModeIDTable[]=
+{
+ {0x01,0x9208,0x01,0x00,0x10,0x00,0x00,0x01,0x00},
+ {0x01,0x1210,0x14,0x01,0x00,0x01,0x00,0x01,0x00},
+ {0x01,0x1010,0x17,0x02,0x11,0x00,0x00,0x01,0x01},
+ {0x03,0x8208,0x03,0x00,0x14,0x00,0x00,0x01,0x02},
+ {0x03,0x0210,0x16,0x01,0x04,0x01,0x00,0x01,0x02},
+ {0x03,0x0010,0x18,0x02,0x15,0x00,0x00,0x01,0x03},
+ {0x05,0x9209,0x05,0x00,0x10,0x00,0x00,0x00,0x04},
+ {0x06,0x8209,0x06,0x00,0x14,0x00,0x00,0x00,0x05},
+ {0x07,0x0000,0x07,0x03,0x05,0x03,0x00,0x01,0x03},
+ {0x07,0x0000,0x19,0x02,0x15,0x02,0x00,0x01,0x03},
+ {0x0d,0x920a,0x0d,0x00,0x10,0x00,0x00,0x00,0x04},
+ {0x0e,0x820a,0x0e,0x00,0x14,0x00,0x00,0x00,0x05},
+ {0x0f,0x0202,0x11,0x01,0x04,0x01,0x00,0x00,0x05},
+ {0x10,0x0212,0x12,0x01,0x04,0x01,0x00,0x00,0x05},
+ {0x11,0x0212,0x1a,0x04,0x24,0x04,0x00,0x00,0x05},
+ {0x12,0x0212,0x1b,0x04,0x24,0x04,0x00,0x00,0x05},
+ {0x13,0x021b,0x1c,0x00,0x14,0x00,0x00,0x00,0x04},
+ {0x12,0x0010,0x18,0x02,0x24,0x02,0x00,0x00,0x05},/* St_CRT2CRTC2 not sure */
+ {0x12,0x0210,0x18,0x01,0x24,0x01,0x00,0x00,0x05},/* St_CRT2CRTC2 not sure */
+ {0xff,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+
+XGI_ExtStruct XGI330_EModeIDTable[]=
+{
+ {0x6a,0x2212,0x0407,0x3a81,0x0102,0x08,0x07,0x00,0x00,0x07,0x0e},
+ {0x2e,0x0a1b,0x0306,0x3a57,0x0101,0x08,0x06,0x00,0x00,0x05,0x06},
+ {0x2f,0x0a1b,0x0305,0x3a50,0x0100,0x08,0x05,0x00,0x00,0x05,0x05},
+ {0x30,0x2a1b,0x0407,0x3a81,0x0103,0x08,0x07,0x00,0x00,0x07,0x0e},
+ {0x31,0x0a1b,0x030d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d},
+ {0x32,0x0a1b,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e},
+ {0x33,0x0a1d,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d},
+ {0x34,0x2a1d,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e},
+ {0x35,0x0a1f,0x0a0d,0x3b85,0x0000,0x08,0x0d,0x00,0x00,0x06,0x3d},
+ {0x36,0x2a1f,0x0a0e,0x3b8c,0x0000,0x08,0x0e,0x00,0x00,0x06,0x3e},
+ {0x37,0x0212,0x0508,0x3aab,0x0104,0x08,0x08,0x00,0x00,0x00,0x16},
+ {0x38,0x0a1b,0x0508,0x3aab,0x0105,0x08,0x08,0x00,0x00,0x00,0x16},
+ {0x3a,0x0e3b,0x0609,0x3adc,0x0107,0x08,0x09,0x00,0x00,0x00,0x1e},
+ {0x3c,0x0e3b,0x070a,0x3af2,0x0130,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE [2003/10/07] */
+ {0x3d,0x0e7d,0x070a,0x3af2,0x0131,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE */
+ {0x40,0x9a1c,0x0000,0x3a34,0x010d,0x08,0x00,0x00,0x00,0x04,0x00},
+ {0x41,0x9a1d,0x0000,0x3a34,0x010e,0x08,0x00,0x00,0x00,0x04,0x00}, /* ModeIdIndex = 0x10 */
+ {0x43,0x0a1c,0x0306,0x3a57,0x0110,0x08,0x06,0x00,0x00,0x05,0x06},
+ {0x44,0x0a1d,0x0306,0x3a57,0x0111,0x08,0x06,0x00,0x00,0x05,0x06},
+ {0x46,0x2a1c,0x0407,0x3a81,0x0113,0x08,0x07,0x00,0x00,0x07,0x0e},
+ {0x47,0x2a1d,0x0407,0x3a81,0x0114,0x08,0x07,0x00,0x00,0x07,0x0e},
+ {0x49,0x0a3c,0x0508,0x3aab,0x0116,0x08,0x08,0x00,0x00,0x00,0x16},
+ {0x4a,0x0a3d,0x0508,0x3aab,0x0117,0x08,0x08,0x00,0x00,0x00,0x16},
+ {0x4c,0x0e7c,0x0609,0x3adc,0x0119,0x08,0x09,0x00,0x00,0x00,0x1e},
+ {0x4d,0x0e7d,0x0609,0x3adc,0x011a,0x08,0x09,0x00,0x00,0x00,0x1e},
+ {0x50,0x9a1b,0x0001,0x3a3b,0x0132,0x08,0x01,0x00,0x00,0x04,0x02},
+ {0x51,0xba1b,0x0103,0x3a42,0x0133,0x08,0x03,0x00,0x00,0x07,0x03},
+ {0x52,0x9a1b,0x0204,0x3a49,0x0134,0x08,0x04,0x00,0x00,0x00,0x04},
+ {0x56,0x9a1d,0x0001,0x3a3b,0x0135,0x08,0x01,0x00,0x00,0x04,0x02},
+ {0x57,0xba1d,0x0103,0x3a42,0x0136,0x08,0x03,0x00,0x00,0x07,0x03},
+ {0x58,0x9a1d,0x0204,0x3a49,0x0137,0x08,0x04,0x00,0x00,0x00,0x04},
+ {0x59,0x9a1b,0x0000,0x3a34,0x0138,0x08,0x00,0x00,0x00,0x04,0x00},
+ {0x5A,0x021b,0x0014,0x3b83,0x0138,0x08,0x01,0x00,0x00,0x04,0x3f}, /* ModeIdIndex = 0x20 */
+ {0x5B,0x0a1d,0x0014,0x3b83,0x0135,0x08,0x01,0x00,0x00,0x04,0x3f},
+ {0x5d,0x0a1d,0x0305,0x3a50,0x0139,0x08,0x05,0x00,0x00,0x07,0x05},
+ {0x62,0x0a3f,0x0306,0x3a57,0x013a,0x08,0x06,0x00,0x00,0x05,0x06},
+ {0x63,0x2a3f,0x0407,0x3a81,0x013b,0x08,0x07,0x00,0x00,0x07,0x0e},
+ {0x64,0x0a7f,0x0508,0x3aab,0x013c,0x08,0x08,0x00,0x00,0x00,0x16},
+ {0x65,0x0eff,0x0609,0x3adc,0x013d,0x08,0x09,0x00,0x00,0x00,0x1e},
+ {0x66,0x0eff,0x070a,0x3af2,0x013e,0x08,0x0a,0x00,0x00,0x00,0x22}, /* mode 1600x1200 add CRT2MODE */
+ {0x68,0x067b,0x080b,0x3b17,0x013f,0x08,0x0b,0x00,0x00,0x00,0x29},
+ {0x69,0x06fd,0x080b,0x3b17,0x0140,0x08,0x0b,0x00,0x00,0x00,0x29},
+ {0x6b,0x07ff,0x080b,0x3b17,0x0141,0x10,0x0b,0x00,0x00,0x00,0x29},
+ {0x6c,0x067b,0x090c,0x3b37,0x0000,0x08,0x0c,0x00,0x00,0x00,0x2f},
+ {0x6d,0x06fd,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
+ {0x6e,0x07ff,0x090c,0x3b37,0x0000,0x10,0x0c,0x00,0x00,0x00,0x2f},
+ {0x70,0x2a1b,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
+ {0x71,0x0a1b,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
+ {0x74,0x0a1d,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37}, /* ModeIdIndex = 0x30 */
+ {0x75,0x0a3d,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
+ {0x76,0x2a1f,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
+ {0x77,0x0a1f,0x0511,0x3b63,0x0000,0x08,0x11,0x00,0x00,0x00,0x37},
+ {0x78,0x0a3f,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
+ {0x79,0x0a3b,0x0612,0x3b74,0x0000,0x08,0x12,0x00,0x00,0x00,0x3a},
+ {0x7a,0x2a1d,0x0410,0x3b52,0x0000,0x08,0x10,0x00,0x00,0x07,0x34},
+ {0x7b,0x0e3b,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d},
+ {0x7c,0x0e7d,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d},
+ {0x7d,0x0eff,0x060f,0x3ad0,0x0000,0x08,0x0f,0x00,0x00,0x00,0x1d},
+ {0x20,0x0e3b,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},
+ {0x21,0x0e7d,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},
+ {0x22,0x0eff,0x0D16,0x49e0,0x0000,0x08,0x16,0x00,0x00,0x00,0x43},
+ {0x23,0x0e3b,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41},
+ {0x24,0x0e7d,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41},
+ {0x25,0x0eff,0x0614,0x49d5,0x0000,0x08,0x14,0x00,0x00,0x00,0x41},
+ {0x26,0x063b,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42}, /* ModeIdIndex = 0x40 */
+ {0x27,0x067d,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42},
+ {0x28,0x06ff,0x0c15,0x49dc,0x0000,0x08,0x15,0x00,0x00,0x00,0x42},
+ {0xff,0x0000,0x0000,0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00}
+};
+
+XGI_StandTableStruct XGI330_StandTable[]=
+{
+/* MD_0_200 */
+ {
+ 0x28,0x18,0x08,0x0800,
+ {0x09,0x03,0x00,0x02},
+ 0x63,
+ {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+ 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_1_200 */
+ {
+ 0x28,0x18,0x08,0x0800,
+ {0x09,0x03,0x00,0x02},
+ 0x63,
+ {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+ 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_2_200 */
+ {
+ 0x50,0x18,0x08,0x1000,
+ {0x01,0x03,0x00,0x02},
+ 0x63,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_3_200 */
+ {
+ 0x50,0x18,0x08,0x1000,
+ {0x01,0x03,0x00,0x02},
+ 0x63,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0xc7,0x06,0x07,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_4 */
+ {
+ 0x28,0x18,0x08,0x4000,
+ {0x09,0x03,0x00,0x02},
+ 0x63,
+ {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+ 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+ 0xff},
+ {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x01,0x00,0x03,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+ 0xff}
+ },
+/* MD_5 */
+ {
+ 0x28,0x18,0x08,0x4000,
+ {0x09,0x03,0x00,0x02},
+ 0x63,
+ {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+ 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xa2,
+ 0xff},
+ {0x00,0x13,0x15,0x17,0x02,0x04,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x01,0x00,0x03,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x30,0x0f,0x00,
+ 0xff}
+ },
+/* MD_6 */
+ {
+ 0x50,0x18,0x08,0x4000,
+ {0x01,0x01,0x00,0x06},
+ 0x63,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0xc1,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xc2,
+ 0xff},
+ {0x00,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+ 0x17,0x17,0x17,0x17,0x17,0x17,0x17,0x17,
+ 0x01,0x00,0x01,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x0d,0x00,
+ 0xff}
+ },
+/* MD_7 */
+ {
+ 0x50,0x18,0x0e,0x1000,
+ {0x00,0x03,0x00,0x03},
+ 0xa6,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+ 0x83,0x85,0x5d,0x28,0x0d,0x63,0xba,0xa3,
+ 0xff},
+ {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x0e,0x00,0x0f,0x08},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+ 0xff}
+ },
+/* MDA_DAC */
+ {
+ 0x00,0x00,0x00,0x0000,
+ {0x00,0x00,0x00,0x15},
+ 0x15,
+ {0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x3f,0x3f,
+ 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x00,0x00,
+ 0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15,0x15,0x15,0x15,0x15,
+ 0x15,0x15,0x15,0x15},
+ {0x15,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+ 0x3f}
+ },
+/* CGA_DAC */
+ {
+ 0x00,0x10,0x04,0x0114,
+ {0x11,0x09,0x15,0x00},
+ 0x10,
+ {0x04,0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,
+ 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x2a,0x3a,
+ 0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x10,
+ 0x04},
+ {0x14,0x01,0x11,0x09,0x15,0x00,0x10,0x04,
+ 0x14,0x01,0x11,0x09,0x15,0x2a,0x3a,0x2e,
+ 0x3e,0x2b,0x3b,0x2f},
+ {0x3f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+ 0x3f}
+ },
+/* EGA_DAC */
+ {
+ 0x00,0x10,0x04,0x0114,
+ {0x11,0x05,0x15,0x20},
+ 0x30,
+ {0x24,0x34,0x21,0x31,0x25,0x35,0x08,0x18,
+ 0x0c,0x1c,0x09,0x19,0x0d,0x1d,0x28,0x38,
+ 0x2c,0x3c,0x29,0x39,0x2d,0x3d,0x02,0x12,
+ 0x06},
+ {0x16,0x03,0x13,0x07,0x17,0x22,0x32,0x26,
+ 0x36,0x23,0x33,0x27,0x37,0x0a,0x1a,0x0e,
+ 0x1e,0x0b,0x1b,0x0f},
+ {0x1f,0x2a,0x3a,0x2e,0x3e,0x2b,0x3b,0x2f,
+ 0x3f}
+ },
+/* VGA_DAC */
+ {
+ 0x00,0x10,0x04,0x0114,
+ {0x11,0x09,0x15,0x2a},
+ 0x3a,
+ {0x2e,0x3e,0x2b,0x3b,0x2f,0x3f,0x00,0x05,
+ 0x08,0x0b,0x0e,0x11,0x14,0x18,0x1c,0x20,
+ 0x24,0x28,0x2d,0x32,0x38,0x3f,0x00,0x10,
+ 0x1f},
+ {0x2f,0x3f,0x1f,0x27,0x2f,0x37,0x3f,0x2d,
+ 0x31,0x36,0x3a,0x3f,0x00,0x07,0x0e,0x15,
+ 0x1c,0x0e,0x11,0x15},
+ {0x18,0x1c,0x14,0x16,0x18,0x1a,0x1c,0x00,
+ 0x04}
+ },
+ {
+ 0x08,0x0c,0x10,0x0a08,
+ {0x0c,0x0e,0x10,0x0b},
+ 0x0c,
+ {0x0d,0x0f,0x10,0x10,0x01,0x08,0x00,0x00,
+ 0x00,0x00,0x01,0x00,0x02,0x02,0x01,0x00,
+ 0x04,0x04,0x01,0x00,0x05,0x02,0x05,0x00,
+ 0x06},
+ {0x01,0x06,0x05,0x06,0x00,0x08,0x01,0x08,
+ 0x00,0x07,0x02,0x07,0x06,0x07,0x00,0x00,
+ 0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00}
+ },
+/* MD_D */
+ {
+ 0x28,0x18,0x08,0x2000,
+ {0x09,0x0f,0x00,0x06},
+ 0x63,
+ {0x2d,0x27,0x28,0x90,0x2c,0x80,0xbf,0x1f,
+ 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x00,0x96,0xb9,0xe3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+/* MD_E */
+ {
+ 0x50,0x18,0x08,0x4000,
+ {0x01,0x0f,0x00,0x06},
+ 0x63,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x00,0x96,0xb9,0xe3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+/* ExtVGATable */
+ {
+ 0x00,0x00,0x00,0x0000,
+ {0x01,0x0f,0x00,0x0e},
+ 0x23,
+ {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x01,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+ 0xff}
+ },
+/* ROM_SAVEPTR */
+ {
+ 0x9f,0x3b,0x00,0x00c0,
+ {0x00,0x00,0x00,0x00},
+ 0x00,
+ {0x00,0x00,0x00,0x00,0x00,0x00,0xbb,0x3f,
+ 0x00,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x1a,0x00,0xac,0x3e,0x00,0xc0,
+ 0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00}
+ },
+/* MD_F */
+ {
+ 0x50,0x18,0x0e,0x8000,
+ {0x01,0x0f,0x00,0x06},
+ 0xa2,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+ 0xff},
+ {0x00,0x08,0x00,0x00,0x18,0x18,0x00,0x00,
+ 0x00,0x08,0x00,0x00,0x00,0x18,0x00,0x00,
+ 0x0b,0x00,0x05,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x05,
+ 0xff}
+ },
+/* MD_10 */
+ {
+ 0x50,0x18,0x0e,0x8000,
+ {0x01,0x0f,0x00,0x06},
+ 0xa3,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x82,0x84,0x5d,0x28,0x0f,0x63,0xba,0xe3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+/* MD_0_350 */
+ {
+ 0x28,0x18,0x0e,0x0800,
+ {0x09,0x03,0x00,0x02},
+ 0xa3,
+ {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
+ 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+ 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_1_350 */
+ {
+ 0x28,0x18,0x0e,0x0800,
+ {0x09,0x03,0x00,0x02},
+ 0xa3,
+ {0x2d,0x27,0x28,0x90,0x2b,0xa0,0xbf,0x1f,
+ 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+ 0x83,0x85,0x5d,0x14,0x1f,0x63,0xba,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_2_350 */
+ {
+ 0x50,0x18,0x0e,0x1000,
+ {0x01,0x03,0x00,0x02},
+ 0xa3,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+ 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_3_350 */
+ {
+ 0x50,0x18,0x0e,0x1000,
+ {0x01,0x03,0x00,0x02},
+ 0xa3,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4d,0x0b,0x0c,0x00,0x00,0x00,0x00,
+ 0x83,0x85,0x5d,0x28,0x1f,0x63,0xba,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x08,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_0_1_400 */
+ {
+ 0x28,0x18,0x10,0x0800,
+ {0x08,0x03,0x00,0x02},
+ 0x67,
+ {0x2d,0x27,0x28,0x90,0x2b,0xb1,0xbf,0x1f,
+ 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x14,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x0c,0x00,0x0f,0x08},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_2_3_400 */
+ {
+ 0x50,0x18,0x10,0x1000,
+ {0x00,0x03,0x00,0x02},
+ 0x67,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x0c,0x00,0x0f,0x08},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+ 0xff}
+ },
+/* MD_7_400 */
+ {
+ 0x50,0x18,0x10,0x1000,
+ {0x00,0x03,0x00,0x02},
+ 0x66,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x0f,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
+ 0x10,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x0e,0x00,0x0f,0x08},
+ {0x00,0x00,0x00,0x00,0x00,0x10,0x0a,0x00,
+ 0xff}
+ },
+/* MD_11 */
+ {
+ 0x50,0x1d,0x10,0xa000,
+ {0x01,0x0f,0x00,0x06},
+ 0xe3,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xc3,
+ 0xff},
+ {0x00,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+ 0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,0x3f,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x01,
+ 0xff}
+ },
+/* ExtEGATable */
+ {
+ 0x50,0x1d,0x10,0xa000,
+ {0x01,0x0f,0x00,0x06},
+ 0xe3,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+ 0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+ 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+ 0x01,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+ 0xff}
+ },
+/* MD_13 */
+ {
+ 0x28,0x18,0x08,0x2000,
+ {0x01,0x0f,0x00,0x0e},
+ 0x63,
+ {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+ 0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x9c,0x8e,0x8f,0x28,0x40,0x96,0xb9,0xa3,
+ 0xff},
+ {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+ 0x41,0x00,0x0f,0x00},
+ {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+ 0xff}
+ }
+};
+
+XGI_TimingHStruct XGI_TimingH[]=
+{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}};
+
+XGI_TimingVStruct XGI_TimingV[]=
+{{{0x00,0x00,0x00,0x00,0x00,0x00,0x00}}};
+
+XGI_XG21CRT1Struct XGI_UpdateCRT1Table[]=
+{
+ {0x01,0x27,0x91,0x8f,0xc0}, /* 00 */
+ {0x03,0x4f,0x83,0x8f,0xc0}, /* 01 */
+ {0x05,0x27,0x91,0x8f,0xc0}, /* 02 */
+ {0x06,0x4f,0x83,0x8f,0xc0}, /* 03 */
+ {0x07,0x4f,0x83,0x8f,0xc0}, /* 04 */
+ {0x0d,0x27,0x91,0x8f,0xc0}, /* 05 */
+ {0x0e,0x4f,0x83,0x8f,0xc0}, /* 06 */
+ {0x0f,0x4f,0x83,0x5d,0xc0}, /* 07 */
+ {0x10,0x4f,0x83,0x5d,0xc0}, /* 08 */
+ {0x11,0x4f,0x83,0xdf,0x0c}, /* 09 */
+ {0x12,0x4f,0x83,0xdf,0x0c}, /* 10 */
+ {0x13,0x4f,0x83,0x8f,0xc0}, /* 11 */
+ {0x2e,0x4f,0x83,0xdf,0x0c}, /* 12 */
+ {0x2e,0x4f,0x87,0xdf,0xc0}, /* 13 */
+ {0x2f,0x4f,0x83,0x8f,0xc0}, /* 14 */
+ {0x50,0x27,0x91,0xdf,0x0c}, /* 15 */
+ {0x59,0x27,0x91,0x8f,0xc0} /* 16 */
+};
+
+XGI_CRT1TableStruct XGI_CRT1Table[]=
+{
+ {{0x2d,0x28,0x90,0x2c,0x90,0x00,0x04,0x00,
+ 0xbf,0x1f,0x9c,0x8e,0x96,0xb9,0x30}}, /* 0x0 */
+ {{0x2d,0x28,0x90,0x2c,0x90,0x00,0x04,0x00,
+ 0x0b,0x3e,0xe9,0x8b,0xe7,0x04,0x00}}, /* 0x1 */
+ {{0x3D,0x31,0x81,0x37,0x1F,0x00,0x05,0x00,
+ 0x72,0xF0,0x58,0x8C,0x57,0x73,0xA0}}, /* 0x2 */
+ {{0x4F,0x3F,0x93,0x45,0x0D,0x00,0x01,0x00,
+ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x3 */
+ {{0x5F,0x50,0x82,0x55,0x81,0x00,0x05,0x00,
+ 0xBF,0x1F,0x9C,0x8E,0x96,0xB9,0x30}}, /* 0x4 */
+ {{0x5F,0x50,0x82,0x55,0x81,0x00,0x05,0x00,
+ 0x0B,0x3E,0xE9,0x8B,0xE7,0x04,0x00}}, /* 0x5 */
+ {{0x63,0x50,0x86,0x56,0x9B,0x00,0x01,0x00,
+ 0x06,0x3E,0xE8,0x8B,0xE7,0xFF,0x10}}, /* 0x6 */
+ {{0x64,0x4F,0x88,0x55,0x9D,0x00,0x01,0x00,
+ 0xF2,0x1F,0xE0,0x83,0xDF,0xF3,0x10}}, /* 0x7 */
+ {{0x63,0x4F,0x87,0x5A,0x81,0x00,0x05,0x00,
+ 0xFB,0x1F,0xE0,0x83,0xDF,0xFC,0x10}}, /* 0x8 */
+ {{0x65,0x4F,0x89,0x58,0x80,0x00,0x05,0x60,
+ 0xFB,0x1F,0xE0,0x83,0xDF,0xFC,0x80}}, /* 0x9 */
+ {{0x65,0x4F,0x89,0x58,0x80,0x00,0x05,0x60,
+ 0x01,0x3E,0xE0,0x83,0xDF,0x02,0x80}}, /* 0xa */
+ {{0x67,0x4F,0x8B,0x58,0x81,0x00,0x05,0x60,
+ 0x0D,0x3E,0xE0,0x83,0xDF,0x0E,0x90}}, /* 0xb */
+ {{0x65,0x4F,0x89,0x57,0x9F,0x00,0x01,0x00,
+ 0xFB,0x1F,0xE6,0x8A,0xDF,0xFC,0x10}}, /* 0xc */
+ {{0x7B,0x63,0x9F,0x6A,0x93,0x00,0x05,0x00, /* ; 0D (800x600,56Hz) */
+ 0x6F,0xF0,0x58,0x8A,0x57,0x70,0xA0}}, /* ; (VCLK 36.0MHz) */
+ {{0x7F,0x63,0x83,0x6C,0x1C,0x00,0x06,0x00, /* ; 0E (800x600,60Hz) */
+ 0x72,0xF0,0x58,0x8C,0x57,0x73,0xA0}}, /* ; (VCLK 40.0MHz) */
+ {{0x7D,0x63,0x81,0x6E,0x1D,0x00,0x06,0x00, /* ; 0F (800x600,72Hz) */
+ 0x98,0xF0,0x7C,0x82,0x57,0x99,0x80}}, /* ; (VCLK 50.0MHz) */
+ {{0x7F,0x63,0x83,0x69,0x13,0x00,0x06,0x00, /* ; 10 (800x600,75Hz) */
+ 0x6F,0xF0,0x58,0x8B,0x57,0x70,0xA0}}, /* ; (VCLK 49.5MHz) */
+ {{0x7E,0x63,0x82,0x6B,0x13,0x00,0x06,0x00, /* ; 11 (800x600,85Hz) */
+ 0x75,0xF0,0x58,0x8B,0x57,0x76,0xA0}}, /* ; (VCLK 56.25MHz) */
+ {{0x81,0x63,0x85,0x6D,0x18,0x00,0x06,0x60, /* ; 12 (800x600,100Hz) */
+ 0x7A,0xF0,0x58,0x8B,0x57,0x7B,0xA0}}, /* ; (VCLK 75.8MHz) */
+ {{0x83,0x63,0x87,0x6E,0x19,0x00,0x06,0x60, /* ; 13 (800x600,120Hz) */
+ 0x81,0xF0,0x58,0x8B,0x57,0x82,0xA0}}, /* ; (VCLK 79.411MHz) */
+ {{0x85,0x63,0x89,0x6F,0x1A,0x00,0x06,0x60, /* ; 14 (800x600,160Hz) */
+ 0x91,0xF0,0x58,0x8B,0x57,0x92,0xA0}}, /* ; (VCLK 105.822MHz) */
+ {{0x99,0x7F,0x9D,0x84,0x1A,0x00,0x02,0x00,
+ 0x96,0x1F,0x7F,0x83,0x7F,0x97,0x10}}, /* 0x15 */
+ {{0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00,
+ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x16 */
+ {{0xA1,0x7F,0x85,0x86,0x97,0x00,0x02,0x00,
+ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90}}, /* 0x17 */
+ {{0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00,
+ 0x1E,0xF5,0x00,0x83,0xFF,0x1F,0x90}}, /* 0x18 */
+ {{0xA7,0x7F,0x8B,0x89,0x95,0x00,0x02,0x00,
+ 0x26,0xF5,0x00,0x83,0xFF,0x27,0x90}}, /* 0x19 */
+ {{0xA9,0x7F,0x8D,0x8C,0x9A,0x00,0x02,0x62,
+ 0x2C,0xF5,0x00,0x83,0xFF,0x2D,0x14}}, /* 0x1a */
+ {{0xAB,0x7F,0x8F,0x8D,0x9B,0x00,0x02,0x62,
+ 0x35,0xF5,0x00,0x83,0xFF,0x36,0x14}}, /* 0x1b */
+ {{0xCF,0x9F,0x93,0xB2,0x01,0x00,0x03,0x00,
+ 0x14,0xBA,0x00,0x83,0xFF,0x15,0x00}}, /* 0x1c */
+ {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00,
+ 0x28,0x5A,0x00,0x83,0xFF,0x29,0x89}}, /* 0x1d */
+ {{0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00,
+ 0x28,0x5A,0x00,0x83,0xFF,0x29,0x89}}, /* 0x1e */
+ {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x00,
+ 0x2E,0x5A,0x00,0x83,0xFF,0x2F,0x89}}, /* 0x1f */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x20 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x21 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x22 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x23 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x24 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x25 */
+ {{0x09,0xC7,0x8D,0xD3,0x0B,0x01,0x04,0x00,
+ 0xE0,0x10,0xB0,0x83,0xAF,0xE1,0x2F}}, /* 0x26 */
+ {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00,
+ 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x27 */
+ {{0x43,0xEF,0x87,0x06,0x00,0x41,0x05,0x62,
+ 0xD4,0x1F,0xA0,0x83,0x9F,0xD5,0x9F}}, /* 0x28 */
+ {{0x45,0xEF,0x89,0x07,0x01,0x41,0x05,0x62,
+ 0xD9,0x1F,0xA0,0x83,0x9F,0xDA,0x9F}}, /* 0x29 */
+ {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00,
+ 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2a */
+ {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00,
+ 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2b */
+ {{0x40,0xEF,0x84,0x03,0x1D,0x41,0x01,0x00,
+ 0xDA,0x1F,0xA0,0x83,0x9F,0xDB,0x1F}}, /* 0x2c */
+ {{0x59,0xFF,0x9D,0x17,0x13,0x41,0x05,0x44,
+ 0x33,0xBA,0x00,0x83,0xFF,0x34,0x0F}}, /* 0x2d */
+ {{0x5B,0xFF,0x9F,0x18,0x14,0x41,0x05,0x44,
+ 0x38,0xBA,0x00,0x83,0xFF,0x39,0x0F}}, /* 0x2e */
+ {{0x5B,0xFF,0x9F,0x18,0x14,0x41,0x05,0x44,
+ 0x3D,0xBA,0x00,0x83,0xFF,0x3E,0x0F}}, /* 0x2f */
+ {{0x5D,0xFF,0x81,0x19,0x95,0x41,0x05,0x44,
+ 0x41,0xBA,0x00,0x84,0xFF,0x42,0x0F}}, /* 0x30 */
+ {{0x55,0xFF,0x99,0x0D,0x0C,0x41,0x05,0x00,
+ 0x3E,0xBA,0x00,0x84,0xFF,0x3F,0x0F}}, /* 0x31 */
+ {{0x7F,0x63,0x83,0x6C,0x1C,0x00,0x06,0x00,
+ 0x72,0xBA,0x27,0x8B,0xDF,0x73,0x80}}, /* 0x32 */
+ {{0x7F,0x63,0x83,0x69,0x13,0x00,0x06,0x00,
+ 0x6F,0xBA,0x26,0x89,0xDF,0x6F,0x80}}, /* 0x33 */
+ {{0x7F,0x63,0x82,0x6B,0x13,0x00,0x06,0x00,
+ 0x75,0xBA,0x29,0x8C,0xDF,0x75,0x80}}, /* 0x34 */
+ {{0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00,
+ 0x24,0xF1,0xAF,0x85,0x3F,0x25,0xB0}}, /* 0x35 */
+ {{0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00,
+ 0x1E,0xF1,0xAD,0x81,0x3F,0x1F,0xB0}}, /* 0x36 */
+ {{0xA7,0x7F,0x88,0x89,0x15,0x00,0x02,0x00,
+ 0x26,0xF1,0xB1,0x85,0x3F,0x27,0xB0}}, /* 0x37 */
+ {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00,
+ 0x28,0xC4,0x7A,0x8E,0xCF,0x29,0xA1}}, /* 0x38 */
+ {{0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00,
+ 0x28,0xD4,0x7A,0x8E,0xCF,0x29,0xA1}}, /* 0x39 */
+ {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x00,
+ 0x2E,0xD4,0x7D,0x81,0xCF,0x2F,0xA1}}, /* 0x3a */
+ {{0xDC,0x9F,0x00,0xAB,0x19,0x00,0x07,0x00,
+ 0xE6,0xEF,0xC0,0xC3,0xBF,0xE7,0x90}}, /* 0x3b */
+ {{0x6B,0x59,0x8F,0x5E,0x8C,0x00,0x05,0x00,
+ 0x0B,0x3E,0xE9,0x8B,0xE7,0x04,0x00}}, /* 0x3c */
+ {{0x7B,0x63,0x9F,0x6A,0x93,0x00,0x05,0x00,
+ 0x6F,0xF0,0x58,0x8A,0x57,0x70,0xA0}}, /* 0x3d */
+ {{0x86,0x6A,0x8a,0x74,0x06,0x00,0x02,0x00,
+ 0x8c,0x15,0x4f,0x83,0xef,0x8d,0x30}}, /* 0x3e */
+ {{0x81,0x6A,0x85,0x70,0x00,0x00,0x02,0x00,
+ 0x0f,0x3e,0xeb,0x8e,0xdf,0x10,0x00}}, /* 0x3f */
+ {{0xCE,0x9F,0x92,0xA9,0x17,0x00,0x07,0x00,
+ 0x20,0xF5,0x03,0x88,0xFF,0x21,0x90}}, /* 0x40 */
+ {{0xE6,0xAE,0x8A,0xBD,0x90,0x00,0x03,0x00,
+ 0x3D,0x10,0x1A,0x8D,0x19,0x3E,0x2F}}, /* 0x41 */
+ {{0xB9,0x8F,0x9D,0x9B,0x8A,0x00,0x06,0x00,
+ 0x7D,0xFF,0x60,0x83,0x5F,0x7E,0x90}}, /* 0x42 */
+ {{0xC3,0x8F,0x87,0x9B,0x0B,0x00,0x07,0x00,
+ 0x82,0xFF,0x60,0x83,0x5F,0x83,0x90}}, /* 0x43 */
+ {{0xAD,0x7F,0x91,0x8E,0x9C,0x00,0x02,0x82,
+ 0x49,0xF5,0x00,0x83,0xFF,0x4A,0x90}}, /* 0x44 */
+ {{0xCD,0x9F,0x91,0xA7,0x19,0x00,0x07,0x60,
+ 0xE6,0xFF,0xC0,0x83,0xBF,0xE7,0x90}}, /* 0x45 */
+ {{0xD3,0x9F,0x97,0xAB,0x1F,0x00,0x07,0x60,
+ 0xF1,0xFF,0xC0,0x83,0xBF,0xF2,0x90}}, /* 0x46 */
+ {{0xD7,0x9F,0x9B,0xAC,0x1E,0x00,0x07,0x00,
+ 0x03,0xDE,0xC0,0x84,0xBF,0x04,0x90}} /* 0x47 */
+};
+
+XGI330_CHTVRegDataStruct XGI_CHTVRegUNTSC[] = {
+ /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
+ {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
+ {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
+ {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */
+ {{ 0x4A,0x77,0xBB,0x94,0x84,0x48,0xFE,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */
+ {{ 0x6A,0x77,0xBB,0x6E,0x84,0x2E,0x02,0x5A,0x04,0x00,0x80,0x20,0x7E,0x80,0x97,0x00 }},/* 04 (640x480) ;;5/6/02 */
+ {{ 0xCF,0x77,0xB7,0xC8,0x84,0x3B,0x02,0x5A,0x04,0x00,0x80,0x19,0x88,0xAE,0xA3,0x00 }},/* 05 (800x600) ;;1/12/02 */
+ {{ 0xEE,0x77,0xBB,0x66,0x87,0x32,0x01,0x5A,0x04,0x00,0x80,0x1B,0xD4,0x2F,0x6F,0x00 }}/* 06 (1024x768) ;;5/6/02 */
+ };
+
+XGI330_CHTVRegDataStruct XGI_CHTVRegONTSC[]= {
+ /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
+ {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
+ {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
+ {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */
+ {{ 0x49,0x77,0xBB,0x7B,0x84,0x34,0x00,0x50,0x04,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */
+ {{ 0x69,0x77,0xBB,0x6E,0x84,0x1E,0x00,0x5A,0x04,0x00,0x80,0x25,0x1A,0x80,0x26,0x00 }},/* 04 (640x480) ;;5/6/02 */
+ {{ 0xCE,0x77,0xB7,0xB6,0x83,0x2C,0x02,0x5A,0x04,0x00,0x80,0x1C,0x00,0x82,0x97,0x00 }},/* 05 (800x600) ;;5/6/02 */
+ {{ 0xED,0x77,0xBB,0x66,0x8C,0x21,0x02,0x5A,0x04,0x00,0x80,0x1F,0xA0,0x7E,0x73,0x00 }}/* 06 (1024x768) ;;5/6/02 */
+ };
+
+XGI330_CHTVRegDataStruct XGI_CHTVRegUPAL[]= {
+ /* Index:000h,001h,002h,004h,003h,005h,006h,007h,008h,015h,01Fh,00Ch,00Dh,00Eh,00Fh,010h */
+ {{ 0x41,0x7F,0xB7,0x34,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 00 (640x200,640x400) */
+ {{ 0x41,0x7F,0xB7,0x80,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 01 (640x350) */
+ {{ 0x41,0x7F,0xB7,0x34,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 02 (720x400) */
+ {{ 0x41,0x7F,0xB7,0x12,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* ; 03 (720x350) */
+ {{ 0x61,0x7F,0xB7,0x99,0x84,0x35,0x04,0x5A,0x05,0x00,0x80,0x26,0x2A,0x55,0x5D,0x00 }},/* ; 04 (640x480) */
+ {{ 0xC3,0x7F,0xB7,0x7A,0x84,0x40,0x02,0x5A,0x05,0x00,0x80,0x1F,0x84,0x3D,0x28,0x00 }},/* ; 05 (800x600) ;;1/12/02 */
+ {{ 0xE5,0x7F,0xB7,0x1D,0xA7,0x3E,0x04,0x5A,0x05,0x00,0x80,0x20,0x3E,0xE4,0x22,0x00 }}/* ; 06 (1024x768) ;;1/12/02 */
+ };
+
+XGI330_CHTVRegDataStruct XGI_CHTVRegOPAL[]={
+ /* Index:000,0x01,0x02,0x04,0x03,0x05,0x06,0x07,0x08,0x15,0x1F,0x0C,0x0D,0x0E,0x0F,0x10h */
+ {{ 0x41,0x7F,0xB7,0x36,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 00 (640x200,640x400) */
+ {{ 0x41,0x7F,0xB7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 01 (640x350) */
+ {{ 0x41,0x7F,0xB7,0x36,0xAD,0x50,0x34,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 02 (720x400) */
+ {{ 0x41,0x7F,0xB7,0x86,0x85,0x50,0x00,0x83,0x05,0x00,0x80,0x00,0x00,0x00,0x00,0x01 }},/* 03 (720x350) */
+ {{ 0x61,0x7F,0xB7,0x99,0x84,0x35,0x04,0x5A,0x05,0x00,0x80,0x26,0x2A,0x55,0x5D,0x00 }},/* 04 (640x480) */
+ {{ 0xC1,0x7F,0xB7,0x4D,0x8C,0x1E,0x31,0x5A,0x05,0x00,0x80,0x26,0x78,0x19,0x34,0x00 }},/* 05 (800x600) ;;1/12/02 */
+ {{ 0xE4,0x7F,0xB7,0x1E,0xAF,0x29,0x37,0x5A,0x05,0x00,0x80,0x25,0x8C,0xB2,0x2A,0x00 }}/* 06 (1024x768) ;;1/12/02 */
+ };
+
+UCHAR XGI_CH7017LV1024x768[]={0x60,0x02,0x00,0x07,0x40,0xED,0xA3,
+ 0xC8,0xC7,0xAC,0xE0,0x02};
+UCHAR XGI_CH7017LV1400x1050[]={0x60,0x03,0x11,0x00,0x40,0xE3,0xAD,
+ 0xDB,0xF6,0xAC,0xE0,0x02};
+
+
+/*add for new UNIVGABIOS*/
+XGI330_LCDDataStruct XGI_StLCD1024x768Data[]=
+{
+ { 62, 25, 800, 546,1344, 806},
+ { 32, 15, 930, 546,1344, 806},
+ { 62, 25, 800, 546,1344, 806}, /* chiawen for dot9 -> dot8 */
+ { 104, 45, 945, 496,1344, 806},
+ { 62, 25, 800, 546,1344, 806},
+ { 31, 18,1008, 624,1344, 806},
+ { 1, 1,1344, 806,1344, 806}
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1024x768Data[]=
+{
+ { 42, 25,1536, 419,1344, 806}, /* { 12, 5, 896, 512,1344, 806}, // alan 09/12/2003 */
+ { 48, 25,1536, 369,1344, 806}, /* { 12, 5, 896, 510,1344, 806}, // alan 09/12/2003 */
+ { 42, 25,1536, 419,1344, 806}, /* { 32, 15,1008, 505,1344, 806}, // alan 09/12/2003 */
+ { 48, 25,1536, 369,1344, 806}, /* { 32, 15,1008, 514,1344, 806}, // alan 09/12/2003 */
+ { 12, 5, 896, 500,1344, 806},
+ { 42, 25,1024, 625,1344, 806},
+ { 1, 1,1344, 806,1344, 806},
+ { 12, 5, 896, 500,1344, 806},
+ { 42, 25,1024, 625,1344, 806},
+ { 1, 1,1344, 806,1344, 806},
+ { 12, 5, 896, 500,1344, 806},
+ { 42, 25,1024, 625,1344, 806},
+ { 1, 1,1344, 806,1344, 806}
+};
+
+/*XGI330_LCDDataStruct XGI_St2LCD1024x768Data[]=
+{
+ { 62, 25, 800, 546,1344, 806},
+ { 32, 15, 930, 546,1344, 806},
+ { 62, 25, 800, 546,1344, 806},
+ { 104, 45, 945, 496,1344, 806},
+ { 62, 25, 800, 546,1344, 806},
+ { 31, 18,1008, 624,1344, 806},
+ { 1, 1,1344, 806,1344, 806}
+};*/
+
+XGI330_LCDDataStruct XGI_CetLCD1024x768Data[]=
+{
+ { 1,1,1344,806,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 1,1,1344,806,1344,806 }, /* 01 (320x350,640x350) */
+ { 1,1,1344,806,1344,806 }, /* 02 (360x400,720x400) */
+ { 1,1,1344,806,1344,806 }, /* 03 (720x350) */
+ { 1,1,1344,806,1344,806 }, /* 04 (640x480x60Hz) */
+ { 1,1,1344,806,1344,806 }, /* 05 (800x600x60Hz) */
+ { 1,1,1344,806,1344,806 } /* 06 (1024x768x60Hz) */
+};
+
+XGI330_LCDDataStruct XGI_StLCD1280x1024Data[]=
+{
+ { 22, 5, 800, 510,1650,1088},
+ { 22, 5, 800, 510,1650,1088},
+ { 176, 45, 900, 510,1650,1088},
+ { 176, 45, 900, 510,1650,1088},
+ { 22, 5, 800, 510,1650,1088},
+ { 13, 5,1024, 675,1560,1152},
+ { 16, 9,1266, 804,1688,1072},
+ { 1, 1,1688,1066,1688,1066}
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1280x1024Data[]=
+{
+ { 211, 60,1024, 501,1688,1066},
+ { 211, 60,1024, 508,1688,1066},
+ { 211, 60,1024, 501,1688,1066},
+ { 211, 60,1024, 508,1688,1066},
+ { 211, 60,1024, 500,1688,1066},
+ { 211, 75,1024, 625,1688,1066},
+ { 211, 120,1280, 798,1688,1066},
+ { 1, 1,1688,1066,1688,1066}
+};
+
+XGI330_LCDDataStruct XGI_St2LCD1280x1024Data[]=
+{
+ { 22, 5, 800, 510,1650,1088},
+ { 22, 5, 800, 510,1650,1088},
+ { 176, 45, 900, 510,1650,1088},
+ { 176, 45, 900, 510,1650,1088},
+ { 22, 5, 800, 510,1650,1088},
+ { 13, 5,1024, 675,1560,1152},
+ { 16, 9,1266, 804,1688,1072},
+ { 1, 1,1688,1066,1688,1066}
+};
+
+XGI330_LCDDataStruct XGI_CetLCD1280x1024Data[]=
+{
+ { 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */
+ { 1,1,1688,1066,1688,1066 }, /* 02 (360x400,720x400) */
+ { 1,1,1688,1066,1688,1066 }, /* 03 (720x350) */
+ { 1,1,1688,1066,1688,1066 }, /* 04 (640x480x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 05 (800x600x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 06 (1024x768x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */
+ { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataStruct XGI_StLCD1400x1050Data[]=
+{
+ { 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */
+ { 211,100,2100,408,1688,1066 }, /* 02 (360x400,720x400) */
+ { 211,64,1536,358,1688,1066 }, /* 03 (720x350) */
+ { 211,48,840,488,1688,1066 }, /* 04 (640x480x60Hz) */
+ { 211,72,1008,609,1688,1066 }, /* 05 (800x600x60Hz) */
+ { 211,128,1400,776,1688,1066 }, /* 06 (1024x768x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz w/o Scaling) */
+ { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1400x1050Data[]=
+{
+ { 211,100,2100,408,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 211,64,1536,358,1688,1066 }, /* 01 (320x350,640x350) */
+ { 211,100,2100,408,1688,1066 }, /* 02 (360x400,720x400) */
+ { 211,64,1536,358,1688,1066 }, /* 03 (720x350) */
+ { 211,48,840,488,1688,1066 }, /* 04 (640x480x60Hz) */
+ { 211,72,1008,609,1688,1066 }, /* 05 (800x600x60Hz) */
+ { 211,128,1400,776,1688,1066 }, /* 06 (1024x768x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz w/o Scaling) */
+ { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1600x1200Data[]=
+{
+ { 4,1,1620,420,2160,1250 }, /* { 3,1,2160,425,2160,1250 }, // 00 (320x200,320x400,640x200,640x400) // alan 10/14/2003 */
+ { 27,7,1920,375,2160,1250 }, /* 01 (320x350,640x350) */
+ { 4,1,1620,420,2160,1250 }, /* { 3,1,2160,425,2160,1250 }, // 02 (360x400,720x400) // alan 10/14/2003 */
+ { 27,7,1920,375,2160,1250 }, /* 03 (720x350) */
+ { 27,4,800,500,2160,1250 }, /* 04 (640x480x60Hz) */
+ { 4,1,1080,625,2160,1250 }, /* 05 (800x600x60Hz) */
+ { 5,2,1350,800,2160,1250 }, /* 06 (1024x768x60Hz) */
+ { 27,16,1500,1064,2160,1250 }, /* 07 (1280x1024x60Hz) */
+ { 9,7,1920,1106,2160,1250 }, /* 08 (1400x1050x60Hz) */
+ { 1,1,2160,1250,2160,1250 } /* 09 (1600x1200x60Hz) ;302lv */
+};
+
+XGI330_LCDDataStruct XGI_StLCD1600x1200Data[]=
+{
+ { 27,4,800,500,2160,1250 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 27,4,800,500,2160,1250 },/* 01 (320x350,640x350) */
+ { 27,4,800,500,2160,1250 },/* 02 (360x400,720x400) */
+ { 27,4,800,500,2160,1250 },/* 03 (720x350) */
+ { 27,4,800,500,2160,1250 },/* 04 (320x240,640x480) */
+ { 4,1,1080,625,2160,1250 },/* 05 (400x300,800x600) */
+ { 5,2,1350,800,2160,1250 },/* 06 (512x384,1024x768) */
+ { 135,88,1600,1100,2160,1250 },/* 07 (1280x1024) */
+ { 1,1,1800,1500,2160,1250 },/* 08 (1400x1050) */
+ { 1,1,2160,1250,2160,1250 } /* 09 (1600x1200) */
+};
+
+XGI330_LCDDataStruct XGI_CetLCD1400x1050Data[]=
+{
+ { 1,1,1688,1066,1688,1066 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1,1,1688,1066,1688,1066 }, /* 01 (320x350,640x350) */
+ { 1,1,1688,1066,1688,1066 }, /* 02 (360x400,720x400) */
+ { 1,1,1688,1066,1688,1066 }, /* 03 (720x350) */
+ { 1,1,1688,1066,1688,1066 }, /* 04 (640x480x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 05 (800x600x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 06 (1024x768x60Hz) */
+ { 1,1,1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */
+ { 1,1,1688,1066,1688,1066 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataStruct XGI_NoScalingData[]=
+{
+ { 1, 1, 800, 449, 800, 449},
+ { 1, 1, 800, 449, 800, 449},
+ { 1, 1, 900, 449, 900, 449},
+ { 1, 1, 900, 449, 900, 449},
+ { 1, 1, 800, 525, 800, 525},
+ { 1, 1,1056, 628,1056, 628},
+ { 1, 1,1344, 806,1344, 806},
+ { 1, 1,1688,1066,1688,1066}
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1024x768x75Data[]=
+{
+ {42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */
+ {42,25,1536,419,1344,806 }, /* ; 02 (360x400,720x400) */
+ {48,25,1536,369,1344,806 }, /* ; 03 (720x350) */
+ {8,5,1312,500,1312,800 }, /* ; 04 (640x480x75Hz) */
+ {41,25,1024,625,1312,800 }, /* ; 05 (800x600x75Hz) */
+ {1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_StLCD1024x768x75Data[]=
+{
+ {42,25,1536,419,1344,806 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {48,25,1536,369,1344,806 }, /* ; 01 (320x350,640x350) */
+ {42,25,1536,419,1344,806 }, /* ; 02 (360x400,720x400) */
+ {48,25,1536,369,1344,806 }, /* ; 03 (720x350) */
+ {8,5,1312,500,1312,800 }, /* ; 04 (640x480x75Hz) */
+ {41,25,1024,625,1312,800 }, /* ; 05 (800x600x75Hz) */
+ {1,1,1312,800,1312,800 } /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_CetLCD1024x768x75Data[]=
+{
+ {1,1,1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1,1,1312,800,1312,800}, /* ; 01 (320x350,640x350) */
+ {1,1,1312,800,1312,800}, /* ; 02 (360x400,720x400) */
+ {1,1,1312,800,1312,800}, /* ; 03 (720x350) */
+ {1,1,1312,800,1312,800}, /* ; 04 (640x480x75Hz) */
+ {1,1,1312,800,1312,800}, /* ; 05 (800x600x75Hz) */
+ {1,1,1312,800,1312,800} /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_ExtLCD1280x1024x75Data[]=
+{
+ {211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */
+ {211,60,1024,501,1688,1066 }, /* ; 02 (360x400,720x400) */
+ {211,60,1024,508,1688,1066 }, /* ; 03 (720x350) */
+ {211,45,768,498,1688,1066 }, /* ; 04 (640x480x75Hz) */
+ {211,75,1024,625,1688,1066 }, /* ; 05 (800x600x75Hz) */
+ {211,120,1280,798,1688,1066 }, /* ; 06 (1024x768x75Hz) */
+ {1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_StLCD1280x1024x75Data[]=
+{
+ {211,60,1024,501,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {211,60,1024,508,1688,1066 }, /* ; 01 (320x350,640x350) */
+ {211,60,1024,501,1688,1066 }, /* ; 02 (360x400,720x400) */
+ {211,60,1024,508,1688,1066 }, /* ; 03 (720x350) */
+ {211,45,768,498,1688,1066 }, /* ; 04 (640x480x75Hz) */
+ {211,75,1024,625,1688,1066 }, /* ; 05 (800x600x75Hz) */
+ {211,120,1280,798,1688,1066}, /* ; 06 (1024x768x75Hz) */
+ {1,1,1688,1066,1688,1066 } /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_CetLCD1280x1024x75Data[]=
+{
+ {1,1,1688,1066,1688,1066}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1,1,1688,1066,1688,1066}, /* ; 01 (320x350,640x350) */
+ {1,1,1688,1066,1688,1066}, /* ; 02 (360x400,720x400) */
+ {1,1,1688,1066,1688,1066}, /* ; 03 (720x350) */
+ {1,1,1688,1066,1688,1066}, /* ; 04 (640x480x75Hz) */
+ {1,1,1688,1066,1688,1066}, /* ; 05 (800x600x75Hz) */
+ {1,1,1688,1066,1688,1066}, /* ; 06 (1024x768x75Hz) */
+ {1,1,1688,1066,1688,1066} /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataStruct XGI_NoScalingDatax75[]=
+{
+ {1,1,800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1,1,800,449,800,449 }, /* ; 01 (320x350,640x350) */
+ {1,1,900,449,900,449 }, /* ; 02 (360x400,720x400) */
+ {1,1,900,449,900,449 }, /* ; 03 (720x350) */
+ {1,1,840,500,840,500 }, /* ; 04 (640x480x75Hz) */
+ {1,1,1056,625,1056,625 }, /* ; 05 (800x600x75Hz) */
+ {1,1,1312,800,1312,800 }, /* ; 06 (1024x768x75Hz) */
+ {1,1,1688,1066,1688,1066}, /* ; 07 (1280x1024x75Hz) */
+ {1,1,1688,1066,1688,1066}, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */
+ {1,1,2160,1250,2160,1250}, /* ; 09 (1600x1200x75Hz) */
+ {1,1,1688,806,1688,806 } /* ; 0A (1280x768x75Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768Data[]=
+{
+ { 9,1057,0, 771 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 9,1057,0, 771 }, /* ; 01 (320x350,640x350) */
+ { 9,1057,0, 771 }, /* ; 02 (360x400,720x400) */
+ { 9,1057,0, 771 }, /* ; 03 (720x350) */
+ { 9,1057,0, 771 }, /* ; 04 (640x480x60Hz) */
+ { 9,1057,0, 771 }, /* ; 05 (800x600x60Hz) */
+ { 9,1057,805, 770 } /* ; 06 (1024x768x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1024x768Data[]=
+{
+ { 9,1057,737,703 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 9,1057,686,651 }, /* ; 01 (320x350,640x350) */
+ { 9,1057,737,703 }, /* ; 02 (360x400,720x400) */
+ { 9,1057,686,651 }, /* ; 03 (720x350) */
+ { 9,1057,776,741 }, /* ; 04 (640x480x60Hz) */
+ { 9,1057, 0 ,771 }, /* ; 05 (800x600x60Hz) */
+ { 9,1057,805,770 } /* ; 06 (1024x768x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768Data[]=
+{
+ { 1152,856,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 1152,856,597,562 }, /* ; 01 (320x350,640x350) */
+ { 1152,856,622,587 }, /* ; 02 (360x400,720x400) */
+ { 1152,856,597,562 }, /* ; 03 (720x350) */
+ { 1152,856,662,627 }, /* ; 04 (640x480x60Hz) */
+ { 1232,936,722,687 }, /* ; 05 (800x600x60Hz) */
+ { 0,1048,805,770 } /* ; 06 (1024x768x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024Data[]=
+{
+ { 18,1346,981,940 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1346,926,865 },/* 01 (320x350,640x350) */
+ { 18,1346,981,940 },/* 02 (360x400,720x400) */
+ { 18,1346,926,865 },/* 03 (720x350) */
+ { 18,1346,0,1025 },/* 04 (640x480x60Hz) */
+ { 18,1346,0,1025 },/* 05 (800x600x60Hz) */
+ { 18,1346,1065,1024 },/* 06 (1024x768x60Hz) */
+ { 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024Data[]=
+{
+ { 18,1346,970,907 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1346,917,854 },/* 01 (320x350,640x350) */
+ { 18,1346,970,907 },/* 02 (360x400,720x400) */
+ { 18,1346,917,854 },/* 03 (720x350) */
+ { 18,1346,0,1025 },/* 04 (640x480x60Hz) */
+ { 18,1346,0,1025 },/* 05 (800x600x60Hz) */
+ { 18,1346,1065,1024 },/* 06 (1024x768x60Hz) */
+ { 18,1346,1065,1024 }/* 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024Data[]=
+{
+ { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1368,1008,729,688 }, /* 01 (320x350,640x350) */
+ { 1368,1008,752,711 }, /* 02 (360x400,720x400) */
+ { 1368,1008,729,688 }, /* 03 (720x350) */
+ { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */
+ { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */
+ { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */
+ { 18,1346,1065,1024 } /* 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024Data[]=
+{
+ { 9,1337,981,940 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 9,1337,926,884 }, /* ; 01 (320x350,640x350) alan, 2003/09/30 */
+ { 9,1337,981,940 }, /* ; 02 (360x400,720x400) */
+ { 9,1337,926,884 }, /* ; 03 (720x350) alan, 2003/09/30 */
+ { 9,1337,0,1025 }, /* ; 04 (640x480x60Hz) */
+ { 9,1337,0,1025 }, /* ; 05 (800x600x60Hz) */
+ { 9,1337,1065,1024 }, /* ; 06 (1024x768x60Hz) */
+ { 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024Data[]=
+{
+ { 9,1337,970,907 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 9,1337,917,854 }, /* ; 01 (320x350,640x350) */
+ { 9,1337,970,907 }, /* ; 02 (360x400,720x400) */
+ { 9,1337,917,854 }, /* ; 03 (720x350) */
+ { 9,1337,0,1025 }, /* ; 04 (640x480x60Hz) */
+ { 9,1337,0,1025 }, /* ; 05 (800x600x60Hz) */
+ { 9,1337,1065,1024 }, /* ; 06 (1024x768x60Hz) */
+ { 9,1337,1065,1024 } /* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024Data[]=
+{
+ { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1368,1008,729,688 }, /* 01 (320x350,640x350) */
+ { 1368,1008,752,711 }, /* 02 (360x400,720x400) */
+ { 1368,1008,729,688 }, /* 03 (720x350) */
+ { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */
+ { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */
+ { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */
+ { 9,1337,1065,1024 } /* 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDLDes1400x1050Data[]=
+{
+ { 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1464,0,1051 }, /* 01 (320x350,640x350) */
+ { 18,1464,0,1051 }, /* 02 (360x400,720x400) */
+ { 18,1464,0,1051 }, /* 03 (720x350) */
+ { 18,1464,0,1051 }, /* 04 (640x480x60Hz) */
+ { 18,1464,0,1051 }, /* 05 (800x600x60Hz) */
+ { 18,1464,0,1051 }, /* 06 (1024x768x60Hz) */
+ { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */
+ { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1400x1050Data[]=
+{
+ { 18,1464,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1464,0,1051 }, /* 01 (320x350,640x350) */
+ { 18,1464,0,1051 }, /* 02 (360x400,720x400) */
+ { 18,1464,0,1051 }, /* 03 (720x350) */
+ { 18,1464,0,1051 }, /* 04 (640x480x60Hz) */
+ { 18,1464,0,1051 }, /* 05 (800x600x60Hz) */
+ { 18,1464,0,1051 }, /* 06 (1024x768x60Hz) */
+ { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */
+ { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1400x1050Data[]=
+{
+ { 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 9,1455,0,1051 },/* 01 (320x350,640x350) */
+ { 9,1455,0,1051 },/* 02 (360x400,720x400) */
+ { 9,1455,0,1051 },/* 03 (720x350) */
+ { 9,1455,0,1051 },/* 04 (640x480x60Hz) */
+ { 9,1455,0,1051 },/* 05 (800x600x60Hz) */
+ { 9,1455,0,1051 },/* 06 (1024x768x60Hz) */
+ { 1637,1397,1053,1038 },/* 07 (1280x1024x60Hz) */
+ { 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1400x1050Data[]=
+{
+ { 9,1455,0,1051 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 9,1455,0,1051 },/* 01 (320x350,640x350) */
+ { 9,1455,0,1051 },/* 02 (360x400,720x400) */
+ { 9,1455,0,1051 },/* 03 (720x350) */
+ { 9,1455,0,1051 },/* 04 (640x480x60Hz) */
+ { 9,1455,0,1051 },/* 05 (800x600x60Hz) */
+ { 9,1455,0,1051 },/* 06 (1024x768x60Hz) */
+ { 1637,1397,1053,1038 },/* 07 (1280x1024x60Hz) */
+ { 9,1455,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data[]=
+{
+ { 1308,1068,781,766 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1308,1068,781,766 }, /* 01 (320x350,640x350) */
+ { 1308,1068,781,766 }, /* 02 (360x400,720x400) */
+ { 1308,1068,781,766 }, /* 03 (720x350) */
+ { 1308,1068,781,766 }, /* 04 (640x480x60Hz) */
+ { 1388,1148,841,826 }, /* 05 (800x600x60Hz) */
+ { 1490,1250,925,910 }, /* 06 (1024x768x60Hz) */
+ { 1646,1406,1053,1038 }, /* 07 (1280x1024x60Hz) */
+ { 18,1464,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1400x1050Data2[]=
+{
+ { 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0,1448,0,1051 }, /* 01 (320x350,640x350) */
+ { 0,1448,0,1051 }, /* 02 (360x400,720x400) */
+ { 0,1448,0,1051 }, /* 03 (720x350) */
+ { 0,1448,0,1051 } /* 04 (640x480x60Hz) */
+};
+
+
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1600x1200Data[]=
+{
+ { 18,1682,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1682,0,1201 }, /* 01 (320x350,640x350) */
+ { 18,1682,0,1201 }, /* 02 (360x400,720x400) */
+ { 18,1682,0,1201 }, /* 03 (720x350) */
+ { 18,1682,0,1201 }, /* 04 (640x480x60Hz) */
+ { 18,1682,0,1201 }, /* 05 (800x600x60Hz) */
+ { 18,1682,0,1201 }, /* 06 (1024x768x60Hz) */
+ { 18,1682,0,1201 }, /* 07 (1280x1024x60Hz) */
+ { 18,1682,0,1201 }, /* 08 (1400x1050x60Hz) */
+ { 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDLDes1600x1200Data[]=
+{
+ { 18,1682,1150,1101 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 18,1682,1083,1034 }, /* 01 (320x350,640x350) */
+ { 18,1682,1150,1101 }, /* 02 (360x400,720x400) */
+ { 18,1682,1083,1034 }, /* 03 (720x350) */
+ { 18,1682,0,1201 }, /* 04 (640x480x60Hz) */
+ { 18,1682,0,1201 }, /* 05 (800x600x60Hz) */
+ { 18,1682,0,1201 }, /* 06 (1024x768x60Hz) */
+ { 18,1682,1232,1183 }, /* 07 (1280x1024x60Hz) */
+ { 18,1682,0,1201 }, /* 08 (1400x1050x60Hz) */
+ { 18,1682,0,1201 } /* 09 (1600x1200x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1600x1200Data[]=
+{
+ { 9,1673,0,1201 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 9,1673,0,1201 },/* 01 (320x350,640x350) */
+ { 9,1673,0,1201 },/* 02 (360x400,720x400) */
+ { 9,1673,0,1201 },/* 03 (720x350) */
+ { 9,1673,0,1201 },/* 04 (640x480x60Hz) */
+ { 9,1673,0,1201 },/* 05 (800x600x60Hz) */
+ { 9,1673,0,1201 },/* 06 (1024x768x60Hz) */
+ { 9,1673,0,1201 },/* 07 (1280x1024x60Hz) */
+ { 9,1673,0,1201 },/* 08 (1400x1050x60Hz) */
+ { 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1600x1200Data[]=
+{
+ { 9,1673,1150,1101 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 9,1673,1083,1034 },/* 01 (320x350,640x350) */
+ { 9,1673,1150,1101 },/* 02 (360x400,720x400) */
+ { 9,1673,1083,1034 },/* 03 (720x350) */
+ { 9,1673,0,1201 },/* 04 (640x480x60Hz) */
+ { 9,1673,0,1201 },/* 05 (800x600x60Hz) */
+ { 9,1673,0,1201 },/* 06 (1024x768x60Hz) */
+ { 9,1673,1232,1183 },/* 07 (1280x1024x60Hz) */
+ { 9,1673,0,1201 },/* 08 (1400x1050x60Hz) */
+ { 9,1673,0,1201 } /* 09 (1600x1200x60Hz) */
+};
+
+XGI330_LCDDataDesStruct2 XGI_NoScalingDesData[]=
+{
+ { 9,657,448,405,96,2 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 9,657,448,355,96,2 }, /* 01 (320x350,640x350) */
+ { 9,657,448,405,96,2 }, /* 02 (360x400,720x400) */
+ { 9,657,448,355,96,2 }, /* 03 (720x350) */
+ { 9,657,1,483,96,2 }, /* 04 (640x480x60Hz) */
+ { 9,849,627,600,128,4 }, /* 05 (800x600x60Hz) */
+ { 9,1057,805,770,0136,6 }, /* 06 (1024x768x60Hz) */
+ { 9,1337,0,1025,112,3 }, /* 07 (1280x1024x60Hz) */
+ { 9,1457,0,1051,112,3 }, /* 08 (1400x1050x60Hz) }, //;[ycchen] 12/19/02 */
+ { 9,1673,0,1201,192,3 }, /* 09 (1600x1200x60Hz) */
+ { 9,1337,0,771,112,6 } /* 0A (1280x768x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
+{
+ {9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {9,1049,0,769}, /* ; 01 (320x350,640x350) */
+ {9,1049,0,769}, /* ; 02 (360x400,720x400) */
+ {9,1049,0,769}, /* ; 03 (720x350) */
+ {9,1049,0,769}, /* ; 04 (640x480x75Hz) */
+ {9,1049,0,769}, /* ; 05 (800x600x75Hz) */
+ {9,1049,0,769} /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1024x768x75Data[]=
+{
+ {9,1049,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {9,1049,0,769}, /* ; 01 (320x350,640x350) */
+ {9,1049,0,769}, /* ; 02 (360x400,720x400) */
+ {9,1049,0,769}, /* ; 03 (720x350) */
+ {9,1049,0,769}, /* ; 04 (640x480x75Hz) */
+ {9,1049,0,769}, /* ; 05 (800x600x75Hz) */
+ {9,1049,0,769} /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1024x768x75Data[]= /* ;;1024x768x75Hz */
+{
+ {1152,856,622,587}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1152,856,597,562}, /* ; 01 (320x350,640x350) */
+ {1192,896,622,587}, /* ; 02 (360x400,720x400) */
+ {1192,896,597,562}, /* ; 03 (720x350) */
+ {1129,857,656,625}, /* ; 04 (640x480x75Hz) */
+ {1209,937,716,685}, /* ; 05 (800x600x75Hz) */
+ {9,1049,0,769} /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDLDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */
+{
+ {18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */
+ {18,1314,0,1025 },/* ; 01 (320x350,640x350) */
+ {18,1314,0,1025 },/* ; 02 (360x400,720x400) */
+ {18,1314,0,1025 },/* ; 03 (720x350) */
+ {18,1314,0,1025 },/* ; 04 (640x480x60Hz) */
+ {18,1314,0,1025 },/* ; 05 (800x600x60Hz) */
+ {18,1314,0,1025 },/* ; 06 (1024x768x60Hz) */
+ {18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDLDes1280x1024x75Data[]=
+{
+ {18,1314,0,1025 },/* ; 00 (320x200,320x400,640x200,640x400) */
+ {18,1314,0,1025 },/* ; 01 (320x350,640x350) */
+ {18,1314,0,1025 },/* ; 02 (360x400,720x400) */
+ {18,1314,0,1025 },/* ; 03 (720x350) */
+ {18,1314,0,1025 },/* ; 04 (640x480x60Hz) */
+ {18,1314,0,1025 },/* ; 05 (800x600x60Hz) */
+ {18,1314,0,1025 },/* ; 06 (1024x768x60Hz) */
+ {18,1314,0,1025 }/* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDLDes1280x1024x75Data[]= /* 1280x1024x75Hz */
+{
+ {1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1368,1008,729,688}, /* ; 01 (320x350,640x350) */
+ {1408,1048,752,711}, /* ; 02 (360x400,720x400) */
+ {1408,1048,729,688}, /* ; 03 (720x350) */
+ {1377,985,794,753}, /* ; 04 (640x480x75Hz) */
+ {1457,1065,854,813}, /* ; 05 (800x600x75Hz) */
+ {1569,1177,938,897}, /* ; 06 (1024x768x75Hz) */
+ {18,1314,0,1025} /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_ExtLCDDes1280x1024x75Data[]= /* ;;1280x1024x75Hz */
+{
+ {9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */
+ {9,1305,0,1025},/* ; 01 (320x350,640x350) */
+ {9,1305,0,1025},/* ; 02 (360x400,720x400) */
+ {9,1305,0,1025},/* ; 03 (720x350) */
+ {9,1305,0,1025},/* ; 04 (640x480x60Hz) */
+ {9,1305,0,1025},/* ; 05 (800x600x60Hz) */
+ {9,1305,0,1025},/* ; 06 (1024x768x60Hz) */
+ {9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_StLCDDes1280x1024x75Data[]=
+{
+ {9,1305,0,1025},/* ; 00 (320x200,320x400,640x200,640x400) */
+ {9,1305,0,1025},/* ; 01 (320x350,640x350) */
+ {9,1305,0,1025},/* ; 02 (360x400,720x400) */
+ {9,1305,0,1025},/* ; 03 (720x350) */
+ {9,1305,0,1025},/* ; 04 (640x480x60Hz) */
+ {9,1305,0,1025},/* ; 05 (800x600x60Hz) */
+ {9,1305,0,1025},/* ; 06 (1024x768x60Hz) */
+ {9,1305,0,1025} /* ; 07 (1280x1024x60Hz) */
+};
+
+XGI330_LCDDataDesStruct XGI_CetLCDDes1280x1024x75Data[]= /* 1280x1024x75Hz */
+{
+ {1368,1008,752,711}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1368,1008,729,688}, /* ; 01 (320x350,640x350) */
+ {1408,1048,752,711}, /* ; 02 (360x400,720x400) */
+ {1408,1048,729,688}, /* ; 03 (720x350) */
+ {1377,985,794,753}, /* ; 04 (640x480x75Hz) */
+ {1457,1065,854,813}, /* ; 05 (800x600x75Hz) */
+ {1569,1177,938,897}, /* ; 06 (1024x768x75Hz) */
+ {9,1305,0,1025} /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[]= /* Scaling LCD 75Hz */
+{
+ {9,657,448,405,96,2}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {9,657,448,355,96,2}, /* ; 01 (320x350,640x350) */
+ {9,738,448,405,108,2}, /* ; 02 (360x400,720x400) */
+ {9,738,448,355,108,2}, /* ; 03 (720x350) */
+ {9,665,0,481,64,3}, /* ; 04 (640x480x75Hz) */
+ {9,825,0,601,80,3}, /* ; 05 (800x600x75Hz) */
+ {9,1049,0,769,96,3}, /* ; 06 (1024x768x75Hz) */
+ {9,1305,0,1025,144,3}, /* ; 07 (1280x1024x75Hz) */
+ {9,1457,0,1051,112,3}, /* ; 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */
+ {9,1673,0,1201,192,3}, /* ; 09 (1600x1200x75Hz) */
+ {9,1337,0,771,112,6} /* ; 0A (1280x768x60Hz) */
+};
+
+XGI330_TVDataStruct XGI_StPALData[]=
+{
+ { 1, 1, 864, 525,1270, 400, 100, 0, 760},
+ { 1, 1, 864, 525,1270, 350, 100, 0, 760},
+ { 1, 1, 864, 525,1270, 400, 0, 0, 720},
+ { 1, 1, 864, 525,1270, 350, 0, 0, 720},
+ { 1, 1, 864, 525,1270, 480, 50, 0, 760},
+ { 1, 1, 864, 525,1270, 600, 50, 0, 0}
+};
+
+XGI330_TVDataStruct XGI_ExtPALData[]=
+{
+ { 2, 1,1080, 463,1270, 500, 50, 0, 50},
+ { 15, 7,1152, 413,1270, 500, 50, 0, 50},
+ { 2, 1,1080, 463,1270, 500, 50, 0, 50},
+ { 15, 7,1152, 413,1270, 500, 50, 0, 50},
+ { 2, 1, 900, 543,1270, 500, 0, 0, 50},
+ { 4, 3,1080, 663,1270, 500, 438, 0, 438},
+ { 1, 1,1125, 831,1270, 500, 686, 0, 686}, /*301b*/
+ { 3, 2,1080, 619,1270, 540, 438, 0, 438}
+};
+
+XGI330_TVDataStruct XGI_StNTSCData[]=
+{
+ { 1, 1, 858, 525,1270, 400, 50, 0, 760},
+ { 1, 1, 858, 525,1270, 350, 50, 0, 640},
+ { 1, 1, 858, 525,1270, 400, 0, 0, 720},
+ { 1, 1, 858, 525,1270, 350, 0, 0, 720},
+ { 1, 1, 858, 525,1270, 480, 0, 0, 760}
+};
+
+XGI330_TVDataStruct XGI_ExtNTSCData[]=
+{
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 143, 80, 836, 523,1270, 420, 224, 0, 0},
+ { 143, 120,1008, 643,1270, 420, 0, 1, 0},
+ { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/
+ { 2, 1, 858, 503,1584, 480, 0, 1, 0},
+ { 3, 2,1001, 533,1270, 420, 0, 0, 0}
+};
+
+XGI330_TVDataStruct XGI_St1HiTVData[]=
+{
+ { 1,1,892,563,690,800,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */
+ { 1,1,1000,563,785,800,0,0,0 }, /* 02 (360x400,720x400) */
+ { 1,1,1000,563,785,700,0,0,0 }, /* 03 (720x350) */
+ { 1,1,892,563,690,960,0,0,0 }, /* 04 (320x240,640x480) */
+ { 8,5,1050,683,1648,960,0x150,1,0 } /* 05 (400x300,800x600) */
+};
+
+XGI330_TVDataStruct XGI_St2HiTVData[]=
+{
+ { 3,1,840,483,1648,960,0x032,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1,1,892,563,690,700,0,0,0 }, /* 01 (320x350,640x350) */
+ { 3,1,840,483,1648,960,0x032,0,0 }, /* 02 (360x400,720x400) */
+ { 1,1,1000,563,785,700,0,0,0 }, /* 03 (720x350) */
+ { 5,2,840,563,1648,960,0x08D,1,0 }, /* 04 (320x240,640x480) */
+ { 8,5,1050,683,1648,960,0x17C,1,0 } /* 05 (400x300,800x600) */
+
+};
+
+XGI330_TVDataStruct XGI_ExtHiTVData[]=
+{
+ { 6,1,840,563,1632,960,0,0,0 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 3,1,960,563,1632,960,0,0,0 }, /* 01 (320x350,640x350) */
+ { 3,1,840,483,1632,960,0,0,0 }, /* 02 (360x400,720x400) */
+ { 3,1,960,563,1632,960,0,0,0 }, /* 03 (720x350) */
+ { 5,1,840,563,1648,960,0x166,1,0 }, /* 04 (320x240,640x480) */
+ { 16,5,1050,683,1648,960,0x143,1,0 }, /* 05 (400x300,800x600) */
+ { 25,12,1260,851,1648,960,0x032,0,0 }, /* 06 (512x384,1024x768) */
+ { 5,4,1575,1124,1648,960,0x128,0,0 }, /* 07 (1280x1024) */
+ { 4,1,1050,563,1548,960,0x143,1,0 }, /* 08 (800x480) */
+ { 5,2,1400,659,1648,960,0x032,0,0 }, /* 09 (1024x576) */
+ { 8,5,1750,803,1648,960,0x128,0,0 } /* 0A (1280x720) */
+
+};
+
+XGI330_TVDataStruct XGI_ExtYPbPr525iData[]=
+{
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 143, 80, 836, 523,1250, 420, 224, 0, 0},
+ { 143, 120,1008, 643,1250, 420, 0, 1, 0},
+ { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/
+ { 2, 1, 858, 503,1584, 480, 0, 1, 0},
+ { 3, 2,1001, 533,1250, 420, 0, 0, 0}
+};
+
+XGI330_TVDataStruct XGI_StYPbPr525iData[]=
+{
+ { 1, 1, 858, 525,1270, 400, 50, 0, 760},
+ { 1, 1, 858, 525,1270, 350, 50, 0, 640},
+ { 1, 1, 858, 525,1270, 400, 0, 0, 720},
+ { 1, 1, 858, 525,1270, 350, 0, 0, 720},
+ { 1, 1, 858, 525,1270, 480, 0, 0, 760},
+};
+
+XGI330_TVDataStruct XGI_ExtYPbPr525pData[]=
+{
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 9, 5, 1001, 453,1270, 420, 171, 0, 171},
+ { 12, 5, 858, 403,1270, 420, 171, 0, 171},
+ { 143, 80, 836, 523,1270, 420, 224, 0, 0},
+ { 143, 120,1008, 643,1270, 420, 0, 1, 0},
+ { 1, 1,1120, 821,1516, 420, 0, 1, 0}, /*301b*/
+ { 2, 1, 858, 503,1584, 480, 0, 1, 0},
+ { 3, 2,1001, 533,1270, 420, 0, 0, 0}
+ };
+
+XGI330_TVDataStruct XGI_StYPbPr525pData[]=
+{
+ { 1, 1,1716, 525,1270, 400, 50, 0, 760},
+ { 1, 1,1716, 525,1270, 350, 50, 0, 640},
+ { 1, 1,1716, 525,1270, 400, 0, 0, 720},
+ { 1, 1,1716, 525,1270, 350, 0, 0, 720},
+ { 1, 1,1716, 525,1270, 480, 0, 0, 760},
+};
+
+XGI330_TVDataStruct XGI_ExtYPbPr750pData[]=
+{
+ { 3, 1, 935, 470,1130, 680, 50, 0, 0}, /* 00 (320x200,320x400,640x200,640x400) */
+ { 24, 7, 935, 420,1130, 680, 50, 0, 0}, /* 01 (320x350,640x350) */
+ { 3, 1, 935, 470,1130, 680, 50, 0, 0}, /* 02 (360x400,720x400) */
+ { 24, 7, 935, 420,1130, 680, 50, 0, 0}, /* 03 (720x350) */
+ { 2, 1,1100, 590,1130, 640, 50, 0, 0}, /* 04 (320x240,640x480) */
+ { 3, 2,1210, 690,1130, 660, 50, 0, 0}, /* 05 (400x300,800x600) */
+ { 1, 1,1375, 878,1130, 640, 638, 0, 0}, /* 06 (1024x768) */
+ { 2, 1, 858, 503,1130, 480, 0, 1, 0}, /* 07 (720x480) */
+ { 5, 4,1815, 570,1130, 660, 50, 0, 0},
+ { 5, 3,1100, 686,1130, 640, 50, 1, 0},
+ { 10, 9,1320, 830,1130, 640, 50, 0, 0}
+};
+
+XGI330_TVDataStruct XGI_StYPbPr750pData[]=
+{
+ { 1, 1,1650, 750,1280, 400, 50, 0, 760},
+ { 1, 1,1650, 750,1280, 350, 50, 0, 640},
+ { 1, 1,1650, 750,1280, 400, 0, 0, 720},
+ { 1, 1,1650, 750,1280, 350, 0, 0, 720},
+ { 1, 1,1650, 750,1280, 480, 0, 0, 760},
+};
+
+UCHAR XGI330_NTSCTiming[] = {
+ 0x17,0x1d,0x03,0x09,0x05,0x06,0x0c,0x0c,
+ 0x94,0x49,0x01,0x0a,0x06,0x0d,0x04,0x0a,
+ 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x1b,
+ 0x0c,0x50,0x00,0x97,0x00,0xda,0x4a,0x17,
+ 0x7d,0x05,0x4b,0x00,0x00,0xe2,0x00,0x02,
+ 0x03,0x0a,0x65,0x9d,0x08,0x92,0x8f,0x40,
+ 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x50,
+ 0x00,0x40,0x44,0x00,0xdb,0x02,0x3b,0x00};
+
+UCHAR XGI330_PALTiming[] = {
+ 0x21,0x5A,0x35,0x6e,0x04,0x38,0x3d,0x70,
+ 0x94,0x49,0x01,0x12,0x06,0x3e,0x35,0x6d,
+ 0x06,0x14,0x3e,0x35,0x6d,0x00,0x45,0x2b,
+ 0x70,0x50,0x00,0x9b,0x00,0xd9,0x5d,0x17,
+ 0x7d,0x05,0x45,0x00,0x00,0xe8,0x00,0x02,
+ 0x0d,0x00,0x68,0xb0,0x0b,0x92,0x8f,0x40,
+ 0x60,0x80,0x14,0x90,0x8c,0x60,0x14,0x63,
+ 0x00,0x40,0x3e,0x00,0xe1,0x02,0x28,0x00};
+
+UCHAR XGI330_HiTVExtTiming[] =
+{
+ 0x2D,0x60,0x2C,0x5F,0x08,0x31,0x3A,0x64,
+ 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
+ 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F,
+ 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13,
+ 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40,
+ 0x8E,0x8E,0x82,0x07,0x0B,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x14,0x3D,0x63,0x4F,
+ 0x27,0x00,0xfc,0xff,0x6a,0x00
+
+};
+
+UCHAR XGI330_HiTVSt1Timing[] =
+{
+ 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65,
+ 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
+ 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F,
+ 0x65,0x90,0x7B,0xA8,0x03,0xF0,0x87,0x03,
+ 0x11,0x15,0x11,0xCF,0x10,0x11,0xCF,0x10,
+ 0x35,0x35,0x3B,0x69,0x1D,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x04,0x86,0xAF,0x5D,
+ 0x0E,0x00,0xfc,0xff,0x2d,0x00
+};
+
+UCHAR XGI330_HiTVSt2Timing[] =
+{
+ 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x64,
+ 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
+ 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F,
+ 0x64,0x90,0x33,0x8C,0x18,0x36,0x3E,0x13,
+ 0x2A,0xDE,0x2A,0x44,0x40,0x2A,0x44,0x40,
+ 0x8E,0x8E,0x82,0x07,0x0B,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x14,0x3D,0x63,0x4F,
+ 0x27,0x00,0xFC,0xff,0x6a,0x00
+};
+
+UCHAR XGI330_HiTVTextTiming[] =
+{
+ 0x32,0x65,0x2C,0x5F,0x08,0x31,0x3A,0x65,
+ 0x28,0x02,0x01,0x3D,0x06,0x3E,0x35,0x6D,
+ 0x06,0x14,0x3E,0x35,0x6D,0x00,0xC5,0x3F,
+ 0x65,0x90,0xE7,0xBC,0x03,0x0C,0x97,0x03,
+ 0x14,0x78,0x14,0x08,0x20,0x14,0x08,0x20,
+ 0xC8,0xC8,0x3B,0xD2,0x26,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x04,0x96,0x72,0x5C,
+ 0x11,0x00,0xFC,0xFF,0x32,0x00
+};
+
+UCHAR XGI330_YPbPr750pTiming[] =
+{
+ 0x30,0x1d,0xe8,0x09,0x09,0xed,0x0c,0x0c,
+ 0x98,0x0a,0x01,0x0c,0x06,0x0d,0x04,0x0a,
+ 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+ 0xed,0x50,0x70,0x9f,0x16,0x59,0x60,0x13,
+ 0x27,0x0b,0x27,0xfc,0x30,0x27,0x1c,0xb0,
+ 0x4b,0x4b,0x6f,0x2f,0x63,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x14,0x73,0x00,0x40,
+ 0x11,0x00,0xfc,0xff,0x32,0x00
+};
+
+UCHAR XGI330_YPbPr525pTiming[] =
+{
+ 0x3E,0x11,0x06,0x09,0x0b,0x0c,0x0c,0x0c,
+ 0x98,0x0a,0x01,0x0d,0x06,0x0d,0x04,0x0a,
+ 0x06,0x14,0x0d,0x04,0x0a,0x00,0x85,0x3f,
+ 0x0c,0x50,0xb2,0x9f,0x16,0x59,0x4f,0x13,
+ 0xad,0x11,0xad,0x1d,0x40,0x8a,0x3d,0xb8,
+ 0x51,0x5e,0x60,0x49,0x7d,
+ 0x92,0x0F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x14,0x4B,0x43,0x41,
+ 0x11,0x00,0xFC,0xFF,0x32,0x00
+};
+
+UCHAR XGI330_YPbPr525iTiming[] =
+{
+ 0x1B,0x21,0x03,0x09,0x05,0x06,0x0C,0x0C,
+ 0x94,0x49,0x01,0x0A,0x06,0x0D,0x04,0x0A,
+ 0x06,0x14,0x0D,0x04,0x0A,0x00,0x85,0x1B,
+ 0x0C,0x50,0x00,0x97,0x00,0xDA,0x4A,0x17,
+ 0x7D,0x05,0x4B,0x00,0x00,0xE2,0x00,0x02,
+ 0x03,0x0A,0x65,0x9D,0x08,
+ 0x92,0x8F,0x40,0x60,0x80,0x14,0x90,0x8C,
+ 0x60,0x14,0x4B,0x00,0x40,
+ 0x44,0x00,0xDB,0x02,0x3B,0x00
+
+};
+
+UCHAR XGI330_HiTVGroup3Data[] =
+{
+ 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x5F,
+ 0x05,0x21,0xB2,0xB2,0x55,0x77,0x2A,0xA6,
+ 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20,
+ 0x8C,0x6E,0x60,0x2E,0x58,0x48,0x72,0x44,
+ 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80,
+ 0x4F,0x7F,0x03,0xA8,0x7D,0x20,0x1A,0xA9,
+ 0x14,0x05,0x03,0x7E,0x64,0x31,0x14,0x75,
+ 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
+};
+
+UCHAR XGI330_HiTVGroup3Simu[] =
+{
+ 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0x95,
+ 0xDB,0x20,0xB8,0xB8,0x55,0x47,0x2A,0xA6,
+ 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20,
+ 0x8C,0x6E,0x60,0x15,0x26,0xD3,0xE4,0x11,
+ 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80,
+ 0x67,0x36,0x01,0x47,0x0E,0x10,0xBE,0xB4,
+ 0x01,0x05,0x03,0x7E,0x65,0x31,0x14,0x75,
+ 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
+};
+
+UCHAR XGI330_HiTVGroup3Text[] =
+{
+ 0x00,0x1A,0x22,0x63,0x62,0x22,0x08,0xA7,
+ 0xF5,0x20,0xCE,0xCE,0x55,0x47,0x2A,0xA6,
+ 0x25,0x2F,0x47,0xFA,0xC8,0xFF,0x8E,0x20,
+ 0x8C,0x6E,0x60,0x18,0x2C,0x0C,0x20,0x22,
+ 0x56,0x36,0x4F,0x6E,0x3F,0x80,0x00,0x80,
+ 0x93,0x3C,0x01,0x50,0x2F,0x10,0xF4,0xCA,
+ 0x01,0x05,0x03,0x7E,0x65,0x31,0x14,0x75,
+ 0x18,0x05,0x18,0x05,0x4C,0xA8,0x01
+};
+
+UCHAR XGI330_Ren525pGroup3[] =
+{
+ 0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x13,
+ 0xB1,0x41,0x62,0x62,0xFF,0xF4,0x45,0xa6,
+ 0x25,0x2F,0x67,0xF6,0xbf,0xFF,0x8E,0x20,
+ 0xAC,0xDA,0x60,0xFe,0x6A,0x9A,0x06,0x10,
+ 0xd1,0x04,0x18,0x0a,0xFF,0x80,0x00,0x80,
+ 0x3c,0x77,0x00,0xEF,0xE0,0x10,0xB0,0xE0,
+ 0x10,0x4F,0x0F,0x0F,0x05,0x0F,0x08,0x6E,
+ 0x1a,0x1F,0x25,0x2a,0x4C,0xAA,0x01
+};
+
+UCHAR XGI330_Ren750pGroup3[] =
+{
+ 0x00,0x14,0x15,0x25,0x55,0x15,0x0b,0x7a,
+ 0x54,0x41,0xE7,0xE7,0xFF,0xF4,0x45,0xa6,
+ 0x25,0x2F,0x67,0xF6,0xbf,0xFF,0x8E,0x20,
+ 0xAC,0x6A,0x60,0x2b,0x52,0xCD,0x61,0x10,
+ 0x51,0x04,0x18,0x0a,0x1F,0x80,0x00,0x80,
+ 0xFF,0xA4,0x04,0x2B,0x94,0x21,0x72,0x94,
+ 0x26,0x05,0x01,0x0F,0xed,0x0F,0x0A,0x64,
+ 0x18,0x1D,0x23,0x28,0x4C,0xAA,0x01
+};
+
+XGI_PanelDelayTblStruct XGI330_PanelDelayTbl[]=
+{
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}},
+{{0x00,0x00}}
+};
+
+XGI330_LVDSDataStruct XGI330_LVDS320x480Data_1[]=
+{
+ {848, 433,400,525},
+ {848, 389,400,525},
+ {848, 433,400,525},
+ {848, 389,400,525},
+ {848, 518,400, 525},
+ {1056, 628,400,525},
+ {400, 525,400,525},
+ {800, 449,1000, 644},
+ {800, 525,1000, 635}
+};
+
+XGI330_LVDSDataStruct XGI330_LVDS800x600Data_1[]=
+{
+ {848, 433,1060, 629},
+ {848, 389,1060, 629},
+ {848, 433,1060, 629},
+ {848, 389,1060, 629},
+ {848, 518,1060, 629},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {800, 449,1000, 644},
+ {800, 525,1000, 635}
+};
+
+XGI330_LVDSDataStruct XGI330_LVDS800x600Data_2[]=
+{
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {800, 449,1000, 644},
+ {800, 525,1000, 635}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1[]=
+{
+ { 960 , 438 , 1344 , 806 } , /* 00 (320x200,320x400,640x200,640x400) */
+ { 960 , 388 , 1344 , 806 } , /* 01 (320x350,640x350) */
+ { 1040, 438 , 1344 , 806 } , /* 02 (360x400,720x400) */
+ { 1040, 388 , 1344 , 806 } , /* 03 (720x350) */
+ { 960 , 518 , 1344 , 806 } , /* 04 (320x240,640x480) */
+ {1120 , 638 , 1344 , 806 } , /* 05 (400x300,800x600) */
+ {1344 , 806 , 1344 , 806 } /* 06 (512x384,1024x768) */
+};
+
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2[]=
+{
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {800, 449,1280, 801},
+ {800, 525,1280, 813}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1[]=
+{
+ {1048, 442,1688, 1066},
+ {1048, 392,1688, 1066},
+ {1048, 442,1688, 1066},
+ {1048, 392,1688, 1066},
+ {1048, 522,1688, 1066},
+ {1208, 642,1688, 1066},
+ {1432, 810,1688, 1066},
+ {1688, 1066,1688, 1066}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2[]=
+{
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {800, 449,1280, 801},
+ {800, 525,1280, 813}
+};
+/*
+XGI330_LVDSDataStruct XGI_LVDS1280x768Data_1[]=
+{
+ {768,438,1408,806},
+ {768,388,1408,806},
+ {768,438,1408,806},
+ {768,388,1408,806},
+ {768,518,1408,806},
+ {928,638,1408,806},
+ {1408,806,1408,806},
+ {1408,806,1408,806},
+ {1408,806,1408,806}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x768Data_2[]=
+{
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806},
+ {1408, 806,1408, 806}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x768NData_1[]=
+{
+ {704, 438,1344, 806},
+ {704, 388,1344, 806},
+ {704, 438,1344, 806},
+ {704, 388,1344, 806},
+ {704, 518,1344, 806},
+ {864, 638,1344, 806},
+ {1088, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x768NData_2[]=
+{
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806},
+ {1344, 806,1344, 806}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x768SData_1[]=
+{
+ {1048,438,1688,806},
+ {1048,388,1688,806},
+ {1148,438,1688,806},
+ {1148,388,1688,806},
+ {1048,518,1688,806},
+ {1208,638,1688,806},
+ {1432,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x768SData_2[]=
+{
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806},
+ {1688,806,1688,806}
+};
+*/
+XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_1[]=
+{
+ {928,416,1688,1066},
+ {928,366,1688,1066},
+ {928,416,1688,1066},
+ {928,366,1688,1066},
+ {928,496,1688,1066},
+ {1088,616,1688,1066},
+ {1312,784,1688,1066},
+ {1568,1040,1688,1066},
+ {1688,1066,1688,1066}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1400x1050Data_2[]=
+{
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066},
+ {1688,1066,1688,1066}
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1600x1200Data_1[]=
+{ /* ;;[ycchen] 12/05/02 LCDHTxLCDVT=2048x1320 */
+ { 1088,520,2048,1320 },/* 00 (320x200,320x400,640x200,640x400) */
+ { 1088,470,2048,1320 },/* 01 (320x350,640x350) */
+ { 1088,520,2048,1320 },/* 02 (360x400,720x400) */
+ { 1088,470,2048,1320 },/* 03 (720x350) */
+ { 1088,600,2048,1320 },/* 04 (320x240,640x480) */
+ { 1248,720,2048,1320 },/* 05 (400x300,800x600) */
+ { 1472,888,2048,1320 },/* 06 (512x384,1024x768) */
+ { 1728,1144,2048,1320 },/* 07 (640x512,1280x1024) */
+ { 1848,1170,2048,1320 },/* 08 (1400x1050) */
+ { 2048,1320,2048,1320 } /* 09 (1600x1200) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDSNoScalingData[]=
+{
+ { 800,449,800,449 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 800,449,800,449 }, /* 01 (320x350,640x350) */
+ { 800,449,800,449 }, /* 02 (360x400,720x400) */
+ { 800,449,800,449 }, /* 03 (720x350) */
+ { 800,525,800,525 }, /* 04 (640x480x60Hz) */
+ { 1056,628,1056,628 }, /* 05 (800x600x60Hz) */
+ { 1344,806,1344,806 }, /* 06 (1024x768x60Hz) */
+ { 1688,1066,1688,1066 }, /* 07 (1280x1024x60Hz) */
+ { 1688,1066,1688,1066 }, /* 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */
+ { 2160,1250,2160,1250 }, /* 09 (1600x1200x60Hz) */
+ { 1688,806,1688,806 } /* 0A (1280x768x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Data_1x75[]=
+{
+ {960,438,1312,800 }, /* 00 (320x200,320x400,640x200,640x400) */
+ {960,388,1312,800 }, /* 01 (320x350,640x350) */
+ {1040,438,1312,800 }, /* 02 (360x400,720x400) */
+ {1040,388,1312,800 }, /* 03 (720x350) */
+ {928,512,1312,800 }, /* 04 (320x240,640x480) */
+ {1088,632,1312,800 }, /* 05 (400x300,800x600) */
+ {1312,800,1312,800 }, /* 06 (512x384,1024x768) */
+};
+
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Data_2x75[]=
+{
+ {1312,800,1312,800}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1312,800,1312,800}, /* ; 01 (320x350,640x350) */
+ {1312,800,1312,800}, /* ; 02 (360x400,720x400) */
+ {1312,800,1312,800}, /* ; 03 (720x350) */
+ {1312,800,1312,800}, /* ; 04 (320x240,640x480) */
+ {1312,800,1312,800}, /* ; 05 (400x300,800x600) */
+ {1312,800,1312,800}, /* ; 06 (512x384,1024x768) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_1x75[]=
+{
+ {1048,442,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1048,392,1688,1066 }, /* ; 01 (320x350,640x350) */
+ {1128,442,1688,1066 }, /* ; 02 (360x400,720x400) */
+ {1128,392,1688,1066 }, /* ; 03 (720x350) */
+ {1048,522,1688,1066 }, /* ; 04 (320x240,640x480) */
+ {1208,642,1688,1066 }, /* ; 05 (400x300,800x600) */
+ {1432,810,1688,1066 }, /* ; 06 (512x384,1024x768) */
+ {1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Data_2x75[]=
+{
+ {1688,1066,1688,1066 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1688,1066,1688,1066 }, /* ; 01 (320x350,640x350) */
+ {1688,1066,1688,1066 }, /* ; 02 (360x400,720x400) */
+ {1688,1066,1688,1066 }, /* ; 03 (720x350) */
+ {1688,1066,1688,1066 }, /* ; 04 (320x240,640x480) */
+ {1688,1066,1688,1066 }, /* ; 05 (400x300,800x600) */
+ {1688,1066,1688,1066 }, /* ; 06 (512x384,1024x768) */
+ {1688,1066,1688,1066 }, /* ; 06; 07 (640x512,1280x1024) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDSNoScalingDatax75[]=
+{
+ {800,449,800,449 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {800,449,800,449 }, /* ; 01 (320x350,640x350) */
+ {900,449,900,449 }, /* ; 02 (360x400,720x400) */
+ {900,449,900,449 }, /* ; 03 (720x350) */
+ {800,500,800,500 }, /* ; 04 (640x480x75Hz) */
+ {1056,625,1056,625 }, /* ; 05 (800x600x75Hz) */
+ {1312,800,1312,800 }, /* ; 06 (1024x768x75Hz) */
+ {1688,1066,1688,1066 }, /* ; 07 (1280x1024x75Hz) */
+ {1688,1066,1688,1066 }, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */
+ {2160,1250,2160,1250 }, /* ; 09 (1600x1200x75Hz) */
+ {1688,806,1688,806 }, /* ; 0A (1280x768x75Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1[]=
+{
+ { 0,1048, 0, 771 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0,1048, 0, 771 }, /* 01 (320x350,640x350) */
+ { 0,1048, 0, 771 }, /* 02 (360x400,720x400) */
+ { 0,1048, 0, 771 }, /* 03 (720x350) */
+ { 0,1048, 0, 771 }, /* 04 (640x480x60Hz) */
+ { 0,1048, 0, 771 }, /* 05 (800x600x60Hz) */
+ { 0,1048, 805, 770 } /* 06 (1024x768x60Hz) */
+} ;
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2[]=
+{
+ { 1142, 856, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1142, 856, 597, 562 }, /* 01 (320x350,640x350) */
+ { 1142, 856, 622, 587 }, /* 02 (360x400,720x400) */
+ { 1142, 856, 597, 562 }, /* 03 (720x350) */
+ { 1142,1048, 722, 687 }, /* 04 (640x480x60Hz) */
+ { 1232, 936, 722, 687 }, /* 05 (800x600x60Hz) */
+ { 0,1048, 805, 771 } /* 06 (1024x768x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3[]=
+{
+ { 320, 24, 622, 587 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 320, 24, 597, 562 }, /* 01 (320x350,640x350) */
+ { 320, 24, 622, 587 }, /* 02 (360x400,720x400) */
+ { 320, 24, 597, 562 }, /* 03 (720x350) */
+ { 320, 24, 722, 687 } /* 04 (640x480x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1[]=
+{
+ { 0,1328, 0, 1025 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0,1328, 0, 1025 }, /* 01 (320x350,640x350) */
+ { 0,1328, 0, 1025 }, /* 02 (360x400,720x400) */
+ { 0,1328, 0, 1025 }, /* 03 (720x350) */
+ { 0,1328, 0, 1025 }, /* 04 (640x480x60Hz) */
+ { 0,1328, 0, 1025 }, /* 05 (800x600x60Hz) */
+ { 0,1328, 0, 1025 }, /* 06 (1024x768x60Hz) */
+ { 0,1328, 1065, 1024 } /* 07 (1280x1024x60Hz) */
+};
+
+ /* The Display setting for DE Mode Panel */
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2[]=
+{
+ { 1368,1008,752,711 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1368,1008,729,688 }, /* 01 (320x350,640x350) */
+ { 1408,1048,752,711 }, /* 02 (360x400,720x400) */
+ { 1408,1048,729,688 }, /* 03 (720x350) */
+ { 1368,1008,794,753 }, /* 04 (640x480x60Hz) */
+ { 1448,1068,854,813 }, /* 05 (800x600x60Hz) */
+ { 1560,1200,938,897 }, /* 06 (1024x768x60Hz) */
+ { 0000,1328,0,1025 } /* 07 (1280x1024x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_1[]=
+{
+ { 0,1448,0,1051 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0,1448,0,1051 }, /* 01 (320x350,640x350) */
+ { 0,1448,0,1051 }, /* 02 (360x400,720x400) */
+ { 0,1448,0,1051 }, /* 03 (720x350) */
+ { 0,1448,0,1051 }, /* 04 (640x480x60Hz) */
+ { 0,1448,0,1051 }, /* 05 (800x600x60Hz) */
+ { 0,1448,0,1051 }, /* 06 (1024x768x60Hz) */
+ { 0,1448,0,1051 }, /* 07 (1280x1024x60Hz) */
+ { 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1400x1050Des_2[]=
+{
+ { 1308,1068, 781, 766 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 1308,1068, 781, 766 }, /* 01 (320x350,640x350) */
+ { 1308,1068, 781, 766 }, /* 02 (360x400,720x400) */
+ { 1308,1068, 781, 766 }, /* 03 (720x350) */
+ { 1308,1068, 781, 766 }, /* 04 (640x480x60Hz) */
+ { 1388,1148, 841, 826 }, /* 05 (800x600x60Hz) */
+ { 1490,1250, 925, 910 }, /* 06 (1024x768x60Hz) */
+ { 1608,1368,1053,1038 }, /* 07 (1280x1024x60Hz) */
+ { 0,1448,0,1051 } /* 08 (1400x1050x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1600x1200Des_1[]=
+{
+ { 0,1664,0,1201 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0,1664,0,1201 }, /* 01 (320x350,640x350) */
+ { 0,1664,0,1201 }, /* 02 (360x400,720x400) */
+ { 0,1664,0,1201 }, /* 03 (720x350) */
+ { 0,1664,0,1201 }, /* 04 (640x480x60Hz) */
+ { 0,1664,0,1201 }, /* 05 (800x600x60Hz) */
+ { 0,1664,0,1201 }, /* 06 (1024x768x60Hz) */
+ { 0,1664,0,1201 }, /* 07 (1280x1024x60Hz) */
+ { 0,1664,0,1201 }, /* 08 (1400x1050x60Hz) */
+ { 0,1664,0,1201 } /* 09 (1600x1200x60Hz) */
+};
+
+
+
+XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesData[]=
+{
+ { 0, 648, 448, 405, 96, 2 }, /* 00 (320x200,320x400,640x200,640x400) */
+ { 0, 648, 448, 355, 96, 2 }, /* 01 (320x350,640x350) */
+ { 0, 648, 448, 405, 96, 2 }, /* 02 (360x400,720x400) */
+ { 0, 648, 448, 355, 96, 2 }, /* 03 (720x350) */
+ { 0, 648, 1, 483, 96, 2 }, /* 04 (640x480x60Hz) */
+ { 0, 840, 627, 600, 128, 4 }, /* 05 (800x600x60Hz) */
+ { 0,1048, 805, 770, 136, 6 }, /* 06 (1024x768x60Hz) */
+ { 0,1328,0,1025, 112, 3 }, /* 07 (1280x1024x60Hz) */
+ { 0,1438,0,1051, 112, 3 }, /* 08 (1400x1050x60Hz) ;;[ycchen] 12/19/02 */
+ { 0,1664,0,1201, 192, 3 }, /* 09 (1600x1200x60Hz) */
+ { 0,1328,0,0771, 112, 6 } /* 0A (1280x768x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_1x75[]= /* ; 1024x768 Full-screen */
+{
+ {0,1040,0,769}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {0,1040,0,769}, /* ; 01 (320x350,640x350) */
+ {0,1040,0,769}, /* ; 02 (360x400,720x400) */
+ {0,1040,0,769}, /* ; 03 (720x350) */
+ {0,1040,0,769}, /* ; 04 (640x480x75Hz) */
+ {0,1040,0,769}, /* ; 05 (800x600x75Hz) */
+ {0,1040,0,769} /* ; 06 (1024x768x75Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_2x75[]= /* ; 1024x768 center-screen (Enh. Mode) */
+{
+ {1142, 856,622,587 }, /* 00 (320x200,320x400,640x200,640x400) */
+ {1142, 856,597,562 }, /* 01 (320x350,640x350) */
+ {1142, 856,622,587 }, /* 02 (360x400,720x400) */
+ {1142, 856,597,562 }, /* 03 (720x350) */
+ {1142,1048,722,687 }, /* 04 (640x480x60Hz) */
+ {1232, 936,722,687 }, /* 05 (800x600x60Hz) */
+ { 0,1048,805,771 } /* 06 (1024x768x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1024x768Des_3x75[]= /* ; 1024x768 center-screen (St.Mode) */
+{
+ {320,24,622,587 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {320,24,597,562 }, /* ; 01 (320x350,640x350) */
+ {320,24,622,587 }, /* ; 02 (360x400,720x400) */
+ {320,24,597,562 }, /* ; 03 (720x350) */
+ {320,24,722,687 } /* ; 04 (640x480x60Hz) */
+};
+
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_1x75[]=
+{
+ {0,1296,0,1025}, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {0,1296,0,1025}, /* ; 01 (320x350,640x350) */
+ {0,1296,0,1025}, /* ; 02 (360x400,720x400) */
+ {0,1296,0,1025}, /* ; 03 (720x350) */
+ {0,1296,0,1025}, /* ; 04 (640x480x75Hz) */
+ {0,1296,0,1025}, /* ; 05 (800x600x75Hz) */
+ {0,1296,0,1025}, /* ; 06 (1024x768x75Hz) */
+ {0,1296,0,1025} /* ; 07 (1280x1024x75Hz) */
+};
+
+/* The Display setting for DE Mode Panel */
+XGI330_LVDSDataStruct XGI_LVDS1280x1024Des_2x75[]= /* [ycchen] 02/18/03 Set DE as default */
+{
+ {1368,976,752,711 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ {1368,976,729,688 }, /* ; 01 (320x350,640x350) */
+ {1408,976,752,711 }, /* ; 02 (360x400,720x400) */
+ {1408,976,729,688 }, /* ; 03 (720x350) */
+ {1368,976,794,753 }, /* ; 04 (640x480x75Hz) */
+ {1448,1036,854,813}, /* ; 05 (800x600x75Hz) */
+ {1560,1168,938,897}, /* ; 06 (1024x768x75Hz) */
+ {0,1296,0,1025 } /* ; 07 (1280x1024x75Hz) */
+};
+
+XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[]= /* Scaling LCD 75Hz */
+{
+ { 0,648,448,405,96,2 }, /* ; 00 (320x200,320x400,640x200,640x400) */
+ { 0,648,448,355,96,2 }, /* ; 01 (320x350,640x350) */
+ { 0,729,448,405,108,2 }, /* ; 02 (360x400,720x400) */
+ { 0,729,448,355,108,2 }, /* ; 03 (720x350) */
+ { 0,656,0,481,64,3 }, /* ; 04 (640x480x75Hz) */
+ { 0,816,0,601,80,3 }, /* ; 05 (800x600x75Hz) */
+ { 0,1040,0,769,96,3 }, /* ; 06 (1024x768x75Hz) */
+ { 0,1296,0,1025,144,3 }, /* ; 07 (1280x1024x75Hz) */
+ { 0,1448,0,1051,112,3 }, /* ; 08 (1400x1050x75Hz) ;;[ycchen] 12/19/02 */
+ { 0,1664,0,1201,192,3 }, /* ; 09 (1600x1200x75Hz) */
+ { 0,1328,0,771,112,6 } /* ; 0A (1280x768x75Hz) */
+};
+
+XGI330_LVDSDataStruct XGI330_LVDS640x480Data_1[]=
+{
+ {800, 449, 800, 449},
+ {800, 449, 800, 449},
+ {800, 449, 800, 449},
+ {800, 449, 800, 449},
+ {800, 525, 800, 525},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628},
+ {1056, 628,1056, 628}
+};
+
+XGI330_CHTVDataStruct XGI_CHTVUNTSCData[]=
+{
+ {840, 600, 840, 600},
+ {840, 600, 840, 600},
+ {840, 600, 840, 600},
+ {840, 600, 840, 600},
+ {784, 600, 784, 600},
+ {1064, 750,1064, 750}
+};
+
+XGI330_CHTVDataStruct XGI_CHTVONTSCData[]=
+{
+ {840, 525, 840, 525},
+ {840, 525, 840, 525},
+ {840, 525, 840, 525},
+ {840, 525, 840, 525},
+ {784, 525, 784, 525},
+ {1040, 700,1040, 700}
+};
+
+XGI330_CHTVDataStruct XGI_CHTVUPALData[]=
+{
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {840, 750, 840, 750},
+ {936, 836, 936, 836}
+};
+
+XGI330_CHTVDataStruct XGI_CHTVOPALData[]=
+{
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {1008, 625,1008, 625},
+ {840, 625, 840, 625},
+ {960, 750, 960, 750}
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[]=
+{
+ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }}, /* 00 (320x) */
+ {{ 0x4B,0x27,0x8F,0x2B,0x03,0x00,0x44,0x00 }}, /* 01 (360x) */
+ {{ 0x55,0x31,0x99,0x46,0x1D,0x00,0x55,0x00 }}, /* 02 (400x) */
+ {{ 0x63,0x3F,0x87,0x4A,0x93,0x00,0x01,0x00 }}, /* 03 (512x) */
+ {{ 0x73,0x4F,0x97,0x55,0x86,0x00,0x05,0x00 }}, /* 04 (640x) */
+ {{ 0x73,0x4F,0x97,0x55,0x86,0x00,0x05,0x00 }}, /* 05 (720x) */
+ {{ 0x87,0x63,0x8B,0x69,0x1A,0x00,0x26,0x00 }}, /* 06 (800x) */
+ {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_H[]=
+{
+ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }}, /* 00 (320x) */
+ {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }}, /* 01 (360x) */
+ {{ 0x60,0x31,0x84,0x3A,0x88,0x00,0x01,0x00 }}, /* 02 (400x) */
+ {{ 0x6E,0x3F,0x92,0x48,0x96,0x00,0x01,0x00 }}, /* 03 (512x) */
+ {{ 0x7E,0x4F,0x82,0x58,0x06,0x00,0x06,0x00 }}, /* 04 (640x) */
+ {{ 0x7E,0x4F,0x82,0x58,0x06,0x00,0x06,0x00 }}, /* 05 (720x) */
+ {{ 0x92,0x63,0x96,0x6C,0x1A,0x00,0x06,0x00 }}, /* 06 (800x) */
+ {{ 0xAE,0x7F,0x92,0x88,0x96,0x00,0x02,0x00 }}, /* 07 (1024x) */
+ {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_H[]=
+{
+ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }}, /* 00 (320x) */
+ {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }}, /* 01 (360x) */
+ {{ 0x63,0x31,0x87,0x3D,0x8E,0x00,0x01,0x00 }}, /* 02 (400x) */
+ {{ 0x63,0x3F,0x87,0x45,0x96,0x00,0x01,0x00 }}, /* 03 (512x) */
+ {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }}, /* 04 (640x) */
+ {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }}, /* 05 (720x) */
+ {{ 0xA3,0x63,0x87,0x78,0x89,0x00,0x02,0x00 }}, /* 06 (800x) */
+ {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* 07 (1024x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_H[]=
+{
+ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }}, /* 00 (320x) */
+ {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }}, /* 01 (360x) */
+ {{ 0x7E,0x40,0x84,0x49,0x91,0x00,0x01,0x00 }}, /* 02 (400x) */
+ {{ 0x7E,0x47,0x93,0x50,0x9E,0x00,0x01,0x00 }}, /* 03 (512x) */
+ {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }}, /* 04 (640x) */
+ {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }}, /* 05 (720x) */
+ {{ 0xCE,0x81,0x94,0x8A,0x98,0x00,0x02,0x00 }}, /* 06 (800x) */
+ {{ 0xCE,0x8F,0x82,0x98,0x06,0x00,0x07,0x00 }}, /* 07 (1024x) */
+ {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* 08 (1280x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_1_H[]=
+{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x47,0x27,0x8B,0x2C,0x1A,0x00,0x05,0x00 }}, /* 00 (320x) */
+ {{ 0x47,0x27,0x8B,0x30,0x1E,0x00,0x05,0x00 }}, /* 01 (360x) */
+ {{ 0x51,0x31,0x95,0x36,0x04,0x00,0x01,0x00 }}, /* 02 (400x) */
+ {{ 0x5F,0x3F,0x83,0x44,0x92,0x00,0x01,0x00 }}, /* 03 (512x) */
+ {{ 0x6F,0x4F,0x93,0x54,0x82,0x00,0x05,0x00 }}, /* 04 (640x) */
+ {{ 0x6F,0x4F,0x93,0x54,0x82,0x00,0x05,0x00 }}, /* 05 (720x) */
+ {{ 0x83,0x63,0x87,0x68,0x16,0x00,0x06,0x00 }}, /* 06 (800x) */
+ {{ 0x9F,0x7F,0x83,0x84,0x92,0x00,0x02,0x00 }}, /* 07 (1024x) */
+ {{ 0xBF,0x9F,0x83,0xA4,0x12,0x00,0x07,0x00 }}, /* 08 (1280x) */
+ {{ 0xCE,0xAE,0x92,0xB3,0x01,0x00,0x03,0x00 }} /* 09 (1400x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11400x1050_2_H[]=
+{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 00 (320x) */
+ {{ 0x76,0x3F,0x83,0x45,0x8C,0x00,0x41,0x00 }}, /* 01 (360x) */
+ {{ 0x76,0x31,0x9A,0x48,0x9F,0x00,0x41,0x00 }}, /* 02 (400x) */
+ {{ 0x76,0x3F,0x9A,0x4F,0x96,0x00,0x41,0x00 }}, /* 03 (512x) */
+ {{ 0xCE,0x7E,0x82,0x87,0x9E,0x00,0x02,0x00 }}, /* 04 (640x) */
+ {{ 0xCE,0x7E,0x82,0x87,0x9E,0x00,0x02,0x00 }}, /* 05 (720x) */
+ {{ 0xCE,0x63,0x92,0x96,0x04,0x00,0x07,0x00 }}, /* 06 (800x) */
+ {{ 0xCE,0x7F,0x92,0xA4,0x12,0x00,0x07,0x00 }}, /* 07 (1024x) */
+ {{ 0xCE,0x9F,0x92,0xB4,0x02,0x00,0x03,0x00 }}, /* 08 (1280x) */
+ {{ 0xCE,0xAE,0x92,0xBC,0x0A,0x00,0x03,0x00 }} /* 09 (1400x) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11600x1200_1_H[]=
+/* ;302lv channelA [ycchen] 12/05/02 LCDHT=2048 */
+{ /* ; CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x5B,0x27,0x9F,0x32,0x0A,0x00,0x01,0x00 }},/* 00 (320x) */
+ {{ 0x5B,0x27,0x9F,0x32,0x0A,0x00,0x01,0x00 }},/* 01 (360x) */
+ {{ 0x65,0x31,0x89,0x3C,0x94,0x00,0x01,0x00 }},/* 02 (400x) */
+ {{ 0x73,0x3F,0x97,0x4A,0x82,0x00,0x05,0x00 }},/* 03 (512x) */
+ {{ 0x83,0x4F,0x87,0x51,0x09,0x00,0x06,0x00 }},/* 04 (640x) */
+ {{ 0x83,0x4F,0x87,0x51,0x09,0x00,0x06,0x00 }},/* 05 (720x) */
+ {{ 0x97,0x63,0x9B,0x65,0x1D,0x00,0x06,0xF0 }},/* 06 (800x) */
+ {{ 0xB3,0x7F,0x97,0x81,0x99,0x00,0x02,0x00 }},/* 07 (1024x) */
+ {{ 0xD3,0x9F,0x97,0xA1,0x19,0x00,0x07,0x00 }},/* 08 (1280x) */
+ {{ 0xE2,0xAE,0x86,0xB9,0x91,0x00,0x03,0x00 }},/* 09 (1400x) */
+ {{ 0xFB,0xC7,0x9F,0xC9,0x81,0x00,0x07,0x00 }} /* 0A (1600x) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
+ {{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }}, /* 00 (x350) */
+ {{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }}, /* 01 (x400) */
+ {{ 0x04,0x3E,0xE2,0x89,0xDF,0x05,0x00 }}, /* 02 (x480) */
+ {{ 0x7C,0xF0,0x5A,0x8F,0x57,0x7D,0xA0 }}, /* 03 (x600) */
+ {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }}, /* 00 (x350) */
+ {{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }}, /* 01 (x400) */
+ {{ 0x24,0xBB,0x72,0x88,0xDF,0x25,0x30 }}, /* 02 (x480) */
+ {{ 0x24,0xF1,0xAE,0x84,0x57,0x25,0xB0 }}, /* 03 (x600) */
+ {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* 04 (x768) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x86,0x1F,0x5E,0x82,0x5D,0x87,0x00 }}, /* 00 (x350) */
+ {{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }}, /* 01 (x400) */
+ {{ 0x08,0x3E,0xE0,0x84,0xDF,0x09,0x00 }}, /* 02 (x480) */
+ {{ 0x80,0xF0,0x58,0x8C,0x57,0x81,0xA0 }}, /* 03 (x600) */
+ {{ 0x28,0xF5,0x00,0x84,0xFF,0x29,0x90 }}, /* 04 (x768) */
+ {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }}, /* 00 (x350) */
+ {{ 0x28,0xD2,0xC8,0x8C,0xC7,0xF2,0x81 }}, /* 01 (x400) */
+ {{ 0x28,0xD2,0xF0,0x84,0xEF,0x1A,0xB1 }}, /* 02 (x480) */
+ {{ 0x28,0xDE,0x2C,0x8F,0x2B,0x56,0x91 }}, /* 03 (x600) */
+ {{ 0x28,0xDE,0x80,0x83,0x7F,0xAA,0x91 }}, /* 04 (x768) */
+ {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* 05 (x1024) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_1_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x6C,0x1F,0x60,0x84,0x5D,0x6D,0x10 }}, /* 00 (x350) */
+ {{ 0x9E,0x1F,0x93,0x86,0x8F,0x9F,0x30 }}, /* 01 (x400) */
+ {{ 0xEE,0x1F,0xE2,0x86,0xDF,0xEF,0x10 }}, /* 02 (x480) */
+ {{ 0x66,0xF0,0x5A,0x8e,0x57,0x67,0xA0 }}, /* 03 (x600) */
+ {{ 0x0E,0xF5,0x02,0x86,0xFF,0x0F,0x90 }}, /* 04 (x768) */
+ {{ 0x0E,0x5A,0x02,0x86,0xFF,0x0F,0x89 }}, /* 05 (x1024) */
+ {{ 0x28,0x10,0x1A,0x80,0x19,0x29,0x0F }} /* 06 (x1050) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11400x1050_2_V[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x28,0x92,0xB6,0x83,0xB5,0xCF,0x81 }}, /* 00 (x350) */
+ {{ 0x28,0x92,0xD5,0x82,0xD4,0xEE,0x81 }}, /* 01 (x400) */
+ {{ 0x28,0x92,0xFD,0x8A,0xFC,0x16,0xB1 }}, /* 02 (x480) */
+ {{ 0x28,0xD4,0x39,0x86,0x57,0x29,0x81 }}, /* 03 (x600) */
+ {{ 0x28,0xD4,0x8D,0x9A,0xFF,0x29,0xA1 }}, /* 04 (x768) */
+ {{ 0x28,0x5A,0x0D,0x9A,0xFF,0x29,0xA9 }}, /* 05 (x1024) */
+ {{ 0x28,0x10,0x1A,0x87,0x19,0x29,0x8F }} /* 06 (x1050) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11600x1200_1_V[]=
+{
+ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
+ {{ 0xd4,0x1F,0x81,0x84,0x5D,0xd5,0x10 }}, /* 00 (x350) */
+ {{ 0x06,0x3e,0xb3,0x86,0x8F,0x07,0x20 }}, /* 01 (x400) */
+ {{ 0x56,0xba,0x03,0x86,0xDF,0x57,0x00 }}, /* 02 (x480) */
+ {{ 0xce,0xF0,0x7b,0x8e,0x57,0xcf,0xa0 }}, /* 03 (x600) */
+ {{ 0x76,0xF5,0x23,0x86,0xFF,0x77,0x90 }}, /* 04 (x768) */
+ {{ 0x76,0x5A,0x23,0x86,0xFF,0x77,0x89 }}, /* 05 (x1024) */
+ {{ 0x90,0x10,0x1A,0x8E,0x19,0x91,0x2F }}, /* 06 (x1050) */
+ {{ 0x26,0x11,0xd3,0x86,0xaF,0x27,0x3f }} /* 07 (x1200) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_Hx75[]=
+{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x4B,0x27,0x8F,0x32,0x1B,0x00,0x45,0x00 }},/* ; 00 (320x) */
+ {{ 0x4B,0x27,0x8F,0x2B,0x03,0x00,0x44,0x00 }},/* ; 01 (360x) */
+ {{ 0x55,0x31,0x99,0x46,0x1D,0x00,0x55,0x00 }},/* ; 02 (400x) */
+ {{ 0x63,0x3F,0x87,0x4A,0x93,0x00,0x01,0x00 }},/* ; 03 (512x) */
+ {{ 0x6F,0x4F,0x93,0x54,0x80,0x00,0x05,0x00 }},/* ; 04 (640x) */
+ {{ 0x6F,0x4F,0x93,0x54,0x80,0x00,0x05,0x00 }},/* ; 05 (720x) */
+ {{ 0x83,0x63,0x87,0x68,0x14,0x00,0x26,0x00 }},/* ; 06 (800x) */
+ {{ 0x9F,0x7F,0x83,0x85,0x91,0x00,0x02,0x00 }} /* ; 07 (1024x) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_1_Vx75[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A+CR09(5->7) */
+ {{ 0x97,0x1F,0x60,0x87,0x5D,0x83,0x10 }},/* ; 00 (x350) */
+ {{ 0xB4,0x1F,0x92,0x89,0x8F,0xB5,0x30 }},/* ; 01 (x400) */
+ {{ 0xFE,0x1F,0xE0,0x84,0xDF,0xFF,0x10 }},/* ; 02 (x480) */
+ {{ 0x76,0xF0,0x58,0x8C,0x57,0x77,0xA0 }},/* ; 03 (x600) */
+ {{ 0x1E,0xF5,0x00,0x83,0xFF,0x1F,0x90 }} /* ; 04 (x768) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_2_Hx75[]=
+{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 00 (320x) */
+ {{ 0x63,0x27,0x87,0x3B,0x8C,0x00,0x01,0x00 }},/* ; 01 (360x) */
+ {{ 0x63,0x31,0x87,0x3D,0x8E,0x00,0x01,0x00 }},/* ; 02 (400x) */
+ {{ 0x63,0x3F,0x87,0x45,0x96,0x00,0x01,0x00 }},/* ; 03 (512x) */
+ {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }},/* ; 04 (640x) */
+ {{ 0xA3,0x4F,0x87,0x6E,0x9F,0x00,0x06,0x00 }},/* ; 05 (720x) */
+ {{ 0xA3,0x63,0x87,0x78,0x89,0x00,0x02,0x00 }},/* ; 06 (800x) */
+ {{ 0xA3,0x7F,0x87,0x86,0x97,0x00,0x02,0x00 }} /* ; 07 (1024x) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11024x768_2_Vx75[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x24,0xBB,0x31,0x87,0x5D,0x25,0x30 }},/* ; 00 (x350) */
+ {{ 0x24,0xBB,0x4A,0x80,0x8F,0x25,0x30 }},/* ; 01 (x400) */
+ {{ 0x24,0xBB,0x72,0x88,0xDF,0x25,0x30 }},/* ; 02 (x480) */
+ {{ 0x24,0xF1,0xAE,0x84,0x57,0x25,0xB0 }},/* ; 03 (x600) */
+ {{ 0x24,0xF5,0x02,0x88,0xFF,0x25,0x90 }} /* ; 04 (x768) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_1_Hx75[]=
+{ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 00 (320x) */
+ {{ 0x56,0x27,0x9A,0x30,0x1E,0x00,0x05,0x00 }},/* ; 01 (360x) */
+ {{ 0x60,0x31,0x84,0x3A,0x88,0x00,0x01,0x00 }},/* ; 02 (400x) */
+ {{ 0x6E,0x3F,0x92,0x48,0x96,0x00,0x01,0x00 }},/* ; 03 (512x) */
+ {{ 0x7E,0x4F,0x82,0x54,0x06,0x00,0x06,0x00 }},/* ; 04 (640x) */
+ {{ 0x7E,0x4F,0x82,0x54,0x06,0x00,0x06,0x00 }},/* ; 05 (720x) */
+ {{ 0x92,0x63,0x96,0x68,0x1A,0x00,0x06,0x00 }},/* ; 06 (800x) */
+ {{ 0xAE,0x7F,0x92,0x84,0x96,0x00,0x02,0x00 }},/* ; 07 (1024x) */
+ {{ 0xCE,0x9F,0x92,0xA5,0x17,0x00,0x07,0x00 }} /* ; 08 (1280x) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_1_Vx75[]=
+{ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x86,0xD1,0xBC,0x80,0xBB,0xE5,0x00 }},/* ; 00 (x350) */
+ {{ 0xB8,0x1F,0x90,0x84,0x8F,0xB9,0x30 }},/* ; 01 (x400) */
+ {{ 0x08,0x3E,0xE0,0x84,0xDF,0x09,0x00 }},/* ; 02 (x480) */
+ {{ 0x80,0xF0,0x58,0x8C,0x57,0x81,0xA0 }},/* ; 03 (x600) */
+ {{ 0x28,0xF5,0x00,0x84,0xFF,0x29,0x90 }},/* ; 04 (x768) */
+ {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */
+};
+
+XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11280x1024_2_Hx75[]=
+{
+ /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */
+ {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }},/* ; 00 (320x) */
+ {{ 0x7E,0x3B,0x9A,0x44,0x12,0x00,0x01,0x00 }},/* ; 01 (360x) */
+ {{ 0x7E,0x40,0x84,0x49,0x91,0x00,0x01,0x00 }},/* ; 02 (400x) */
+ {{ 0x7E,0x47,0x93,0x50,0x9E,0x00,0x01,0x00 }},/* ; 03 (512x) */
+ {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }},/* ; 04 (640x) */
+ {{ 0xCE,0x77,0x8A,0x80,0x8E,0x00,0x02,0x00 }},/* ; 05 (720x) */
+ {{ 0xCE,0x81,0x94,0x8A,0x98,0x00,0x02,0x00 }},/* ; 06 (800x) */
+ {{ 0xCE,0x8F,0x82,0x98,0x06,0x00,0x07,0x00 }},/* ; 07 (1024x) */
+ {{ 0xCE,0x9F,0x92,0xA8,0x16,0x00,0x07,0x00 }} /* ; 08 (1280x) */
+};
+
+XGI_LVDSCRT1VDataStruct XGI_LVDSCRT11280x1024_2_Vx75[]=
+{
+ /* CR06,CR07,CR10,CR11,CR15,CR16,SR0A */
+ {{ 0x28,0xD2,0xAF,0x83,0xAE,0xD8,0xA1 }},/* ; 00 (x350) */
+ {{ 0x28,0xD2,0xC8,0x8C,0xC7,0xF2,0x81 }},/* ; 01 (x400) */
+ {{ 0x28,0xD2,0xF0,0x84,0xEF,0x1A,0xB1 }},/* ; 02 (x480) */
+ {{ 0x28,0xDE,0x2C,0x8F,0x2B,0x56,0x91 }},/* ; 03 (x600) */
+ {{ 0x28,0xDE,0x80,0x83,0x7F,0xAA,0x91 }},/* ; 04 (x768) */
+ {{ 0x28,0x5A,0x13,0x87,0xFF,0x29,0xA9 }} /* ; 05 (x1024) */
+};
+
+XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UNTSC[]=
+{
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+ 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+ 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+ 0xe8,0x84,0x8f,0x57,0x20,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x56,0x9f,0x56,0x3e,
+ 0xd0,0x82,0x5d,0x57,0x00,0x00,0x01,0x00 }},
+ {{0x5d,0x4f,0x81,0x53,0x9c,0x56,0xba,
+ 0x18,0x84,0xdf,0x57,0x00,0x00,0x01,0x00 }},
+ {{0x80,0x63,0x84,0x6c,0x17,0xec,0xf0,
+ 0x90,0x8c,0x57,0xed,0x20,0x00,0x06,0x01 }}
+};
+
+XGI_LVDSCRT1DataStruct XGI_CHTVCRT1ONTSC[]=
+{
+ {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+ 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+ 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+ 0xc0,0x84,0x8f,0x0c,0x20,0x00,0x01,0x00 }},
+ {{0x64,0x4f,0x88,0x5a,0x9f,0x0b,0x3e,
+ 0xb0,0x8d,0x5d,0x0c,0x00,0x00,0x01,0x00 }},
+ {{0x5d,0x4f,0x81,0x56,0x9c,0x0b,0x3e,
+ 0xe8,0x84,0xdf,0x0c,0x00,0x00,0x01,0x00 }},
+ {{0x7d,0x63,0x81,0x6a,0x16,0xba,0xf0,
+ 0x7f,0x86,0x57,0xbb,0x00,0x00,0x06,0x01 }}
+};
+
+XGI_LVDSCRT1DataStruct XGI_CHTVCRT1UPAL[]=
+{
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xf8,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }},
+ {{0x64,0x4f,0x88,0x55,0x80,0xec,0xba,
+ 0x50,0x84,0xdf,0xed,0x00,0x00,0x05,0x00 }},
+ {{0x70,0x63,0x94,0x68,0x8d,0x42,0xf1,
+ 0xc8,0x8c,0x57,0xe9,0x20,0x00,0x05,0x01 }}
+};
+
+XGI_LVDSCRT1DataStruct XGI_CHTVCRT1OPAL[]=
+{
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xf0,0x83,0x8f,0x70,0x20,0x00,0x05,0x00 }},
+ {{0x79,0x4f,0x9d,0x5a,0x90,0x6f,0x3e,
+ 0xde,0x81,0x5d,0x70,0x00,0x00,0x05,0x00 }},
+ {{0x64,0x4f,0x88,0x55,0x80,0x6f,0xba,
+ 0x20,0x83,0xdf,0x70,0x00,0x00,0x05,0x00 }},
+ {{0x73,0x63,0x97,0x69,0x8e,0xec,0xf0,
+ 0x90,0x8c,0x57,0xed,0x20,0x00,0x05,0x01 }}
+};
+
+/*add for new UNIVGABIOS*/
+XGI330_LCDDataTablStruct XGI_LCDDataTable[]=
+{
+ {Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCD1024x768Data */
+ {Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCD1024x768Data */
+ {Panel1024x768,0x0018,0x0010,2}, /* XGI_CetLCD1024x768Data */
+ {Panel1280x1024,0x0019,0x0001,3}, /* XGI_ExtLCD1280x1024Data */
+ {Panel1280x1024,0x0019,0x0000,4}, /* XGI_StLCD1280x1024Data */
+ {Panel1280x1024,0x0018,0x0010,5}, /* XGI_CetLCD1280x1024Data */
+ {Panel1400x1050,0x0019,0x0001,6}, /* XGI_ExtLCD1400x1050Data */
+ {Panel1400x1050,0x0019,0x0000,7}, /* XGI_StLCD1400x1050Data */
+ {Panel1400x1050,0x0018,0x0010,8}, /* XGI_CetLCD1400x1050Data */
+ {Panel1600x1200,0x0019,0x0001,9}, /* XGI_ExtLCD1600x1200Data */
+ {Panel1600x1200,0x0019,0x0000,10}, /* XGI_StLCD1600x1200Data */
+ {PanelRef60Hz,0x0008,0x0008,11}, /* XGI_NoScalingData */
+ {Panel1024x768x75,0x0019,0x0001,12}, /* XGI_ExtLCD1024x768x75Data */
+ {Panel1024x768x75,0x0019,0x0000,13}, /* XGI_StLCD1024x768x75Data */
+ {Panel1024x768x75,0x0018,0x0010,14}, /* XGI_CetLCD1024x768x75Data */
+ {Panel1280x1024x75,0x0019,0x0001,15}, /* XGI_ExtLCD1280x1024x75Data */
+ {Panel1280x1024x75,0x0019,0x0000,16}, /* XGI_StLCD1280x1024x75Data */
+ {Panel1280x1024x75,0x0018,0x0010,17}, /* XGI_CetLCD1280x1024x75Data */
+ {PanelRef75Hz,0x0008,0x0008,18}, /* XGI_NoScalingDatax75 */
+ {0xFF,0x0000,0x0000,0} /* End of table */
+};
+
+XGI330_LCDDataTablStruct XGI_LCDDesDataTable[]=
+{
+ {Panel1024x768,0x0019,0x0001,0}, /* XGI_ExtLCDDes1024x768Data */
+ {Panel1024x768,0x0019,0x0000,1}, /* XGI_StLCDDes1024x768Data */
+ {Panel1024x768,0x0018,0x0010,2}, /* XGI_CetLCDDes1024x768Data */
+ {Panel1280x1024,0x0019,0x0001,3}, /* XGI_ExtLCDDes1280x1024Data */
+ {Panel1280x1024,0x0019,0x0000,4}, /* XGI_StLCDDes1280x1024Data */
+ {Panel1280x1024,0x0018,0x0010,5}, /* XGI_CetLCDDes1280x1024Data */
+ {Panel1400x1050,0x0019,0x0001,6}, /* XGI_ExtLCDDes1400x1050Data */
+ {Panel1400x1050,0x0019,0x0000,7}, /* XGI_StLCDDes1400x1050Data */
+ {Panel1400x1050,0x0418,0x0010,8}, /* XGI_CetLCDDes1400x1050Data */
+ {Panel1400x1050,0x0418,0x0410,9}, /* XGI_CetLCDDes1400x1050Data2 */
+ {Panel1600x1200,0x0019,0x0001,10}, /* XGI_ExtLCDDes1600x1200Data */
+ {Panel1600x1200,0x0019,0x0000,11}, /* XGI_StLCDDes1600x1200Data */
+ {PanelRef60Hz,0x0008,0x0008,12}, /* XGI_NoScalingDesData */
+ {Panel1024x768x75,0x0019,0x0001,13}, /* XGI_ExtLCDDes1024x768x75Data */
+ {Panel1024x768x75,0x0019,0x0000,14}, /* XGI_StLCDDes1024x768x75Data */
+ {Panel1024x768x75,0x0018,0x0010,15}, /* XGI_CetLCDDes1024x768x75Data */
+ {Panel1280x1024x75,0x0019,0x0001,16}, /* XGI_ExtLCDDes1280x1024x75Data */
+ {Panel1280x1024x75,0x0019,0x0000,17}, /* XGI_StLCDDes1280x1024x75Data */
+ {Panel1280x1024x75,0x0018,0x0010,18}, /* XGI_CetLCDDes1280x1024x75Data */
+ {PanelRef75Hz,0x0008,0x0008,19}, /* XGI_NoScalingDesDatax75 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_H[]=
+{
+ {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_H */
+ {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_H */
+ {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDSCRT11280x1024_1_H */
+ {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDSCRT11280x1024_2_H */
+ {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDSCRT11400x1050_1_H */
+ {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDSCRT11400x1050_2_H */
+ {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDSCRT11600x1200_1_H */
+ {Panel1024x768x75,0x0018,0x0000,7}, /* XGI_LVDSCRT11024x768_1_Hx75 */
+ {Panel1024x768x75,0x0018,0x0010,8}, /* XGI_LVDSCRT11024x768_2_Hx75 */
+ {Panel1280x1024x75,0x0018,0x0000,9}, /* XGI_LVDSCRT11280x1024_1_Hx75 */
+ {Panel1280x1024x75,0x0018,0x0010,10}, /* XGI_LVDSCRT11280x1024_2_Hx75 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_LCDDataTablStruct XGI_EPLLCDCRT1Ptr_V[]=
+{
+ {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDSCRT11024x768_1_V */
+ {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDSCRT11024x768_2_V */
+ {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDSCRT11280x1024_1_V */
+ {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDSCRT11280x1024_2_V */
+ {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDSCRT11400x1050_1_V */
+ {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDSCRT11400x1050_2_V */
+ {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDSCRT11600x1200_1_V */
+ {Panel1024x768x75,0x0018,0x0000,7}, /* XGI_LVDSCRT11024x768_1_Vx75 */
+ {Panel1024x768x75,0x0018,0x0010,8}, /* XGI_LVDSCRT11024x768_2_Vx75 */
+ {Panel1280x1024x75,0x0018,0x0000,9}, /* XGI_LVDSCRT11280x1024_1_Vx75 */
+ {Panel1280x1024x75,0x0018,0x0010,10}, /* XGI_LVDSCRT11280x1024_2_Vx75 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_LCDDataTablStruct XGI_EPLLCDDataPtr[]=
+{
+ {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Data_1 */
+ {Panel1024x768,0x0018,0x0010,1}, /* XGI_LVDS1024x768Data_2 */
+ {Panel1280x1024,0x0018,0x0000,2}, /* XGI_LVDS1280x1024Data_1 */
+ {Panel1280x1024,0x0018,0x0010,3}, /* XGI_LVDS1280x1024Data_2 */
+ {Panel1400x1050,0x0018,0x0000,4}, /* XGI_LVDS1400x1050Data_1 */
+ {Panel1400x1050,0x0018,0x0010,5}, /* XGI_LVDS1400x1050Data_2 */
+ {Panel1600x1200,0x0018,0x0000,6}, /* XGI_LVDS1600x1200Data_1 */
+ {PanelRef60Hz,0x0008,0x0008,7}, /* XGI_LVDSNoScalingData */
+ {Panel1024x768x75,0x0018,0x0000,8}, /* XGI_LVDS1024x768Data_1x75 */
+ {Panel1024x768x75,0x0018,0x0010,9}, /* XGI_LVDS1024x768Data_2x75 */
+ {Panel1280x1024x75,0x0018,0x0000,10}, /* XGI_LVDS1280x1024Data_1x75 */
+ {Panel1280x1024x75,0x0018,0x0010,11}, /* XGI_LVDS1280x1024Data_2x75 */
+ {PanelRef75Hz,0x0008,0x0008,12}, /* XGI_LVDSNoScalingDatax75 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[]=
+{
+ {Panel1024x768,0x0018,0x0000,0}, /* XGI_LVDS1024x768Des_1 */
+ {Panel1024x768,0x0618,0x0410,1}, /* XGI_LVDS1024x768Des_3 */
+ {Panel1024x768,0x0018,0x0010,2}, /* XGI_LVDS1024x768Des_2 */
+ {Panel1280x1024,0x0018,0x0000,3}, /* XGI_LVDS1280x1024Des_1 */
+ {Panel1280x1024,0x0018,0x0010,4}, /* XGI_LVDS1280x1024Des_2 */
+ {Panel1400x1050,0x0018,0x0000,5}, /* XGI_LVDS1400x1050Des_1 */
+ {Panel1400x1050,0x0018,0x0010,6}, /* XGI_LVDS1400x1050Des_2 */
+ {Panel1600x1200,0x0018,0x0000,7}, /* XGI_LVDS1600x1200Des_1 */
+ {PanelRef60Hz,0x0008,0x0008,8}, /* XGI_LVDSNoScalingDesData */
+ {Panel1024x768x75,0x0018,0x0000,9}, /* XGI_LVDS1024x768Des_1x75 */
+ {Panel1024x768x75,0x0618,0x0410,10}, /* XGI_LVDS1024x768Des_3x75 */
+ {Panel1024x768x75,0x0018,0x0010,11}, /* XGI_LVDS1024x768Des_2x75 */
+ {Panel1280x1024x75,0x0018,0x0000,12}, /* XGI_LVDS1280x1024Des_1x75 */
+ {Panel1280x1024x75,0x0018,0x0010,13}, /* XGI_LVDS1280x1024Des_2x75 */
+ {PanelRef75Hz,0x0008,0x0008,14}, /* XGI_LVDSNoScalingDesDatax75 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[]=
+{
+ {Panel1024x768,0x0000,0x0000,0}, /* XGI_CH7017LV1024x768 */
+ {Panel1400x1050,0x0000,0x0000,1}, /* XGI_CH7017LV1400x1050 */
+ {0xFF,0x0000,0x0000,0}
+};
+
+XGI330_TVDataTablStruct XGI_TVDataTable[]=
+{
+ {0x09E1,0x0001,0}, /* XGI_ExtPALData */
+ {0x09E1,0x0000,1}, /* XGI_ExtNTSCData */
+ {0x09E1,0x0801,2}, /* XGI_StPALData */
+ {0x09E1,0x0800,3}, /* XGI_StNTSCData */
+ {0x49E0,0x0100,4}, /* XGI_ExtHiTVData */
+ {0x49E0,0x4100,5}, /* XGI_St2HiTVData */
+ {0x49E0,0x4900,13}, /* XGI_St1HiTVData */
+ {0x09E0,0x0020,6}, /* XGI_ExtYPbPr525iData */
+ {0x09E0,0x0040,7}, /* XGI_ExtYPbPr525pData */
+ {0x09E0,0x0080,8}, /* XGI_ExtYPbPr750pData */
+ {0x09E0,0x0820,9}, /* XGI_StYPbPr525iData */
+ {0x09E0,0x0840,10}, /* XGI_StYPbPr525pData */
+ {0x09E0,0x0880,11}, /* XGI_StYPbPr750pData */
+ {0xffff,0x0000,12} /* END */
+};
+
+USHORT TVLenList[]=
+{
+ LVDSCRT1Len_H,
+ LVDSCRT1Len_V,
+ LVDSDataLen,
+ 0,
+ TVDataLen,
+ 0,
+ 0,
+ CHTVRegLen
+} ;
+
+/* Chrontel 7017 TV CRT1 Timing List */
+XGI330_TVDataTablStruct XGI_EPLCHTVCRT1Ptr[]=
+{
+ {0x0011,0x0000,0}, /* XGI_CHTVCRT1UNTSC */
+ {0x0011,0x0010,1}, /* XGI_CHTVCRT1ONTSC */
+ {0x0011,0x0001,2}, /* XGI_CHTVCRT1UPAL */
+ {0x0011,0x0011,3}, /* XGI_CHTVCRT1OPAL */
+ {0xFFFF,0x0000,4}
+};
+
+/* ;;Chrontel 7017 TV Timing List */
+XGI330_TVDataTablStruct XGI_EPLCHTVDataPtr[]=
+{
+ {0x0011,0x0000,0}, /* XGI_CHTVUNTSCData */
+ {0x0011,0x0010,1}, /* XGI_CHTVONTSCData */
+ {0x0011,0x0001,2}, /* XGI_CHTVUPALData */
+ {0x0011,0x0011,3}, /* XGI_CHTVOPALData */
+ {0xFFFF,0x0000,4}
+};
+
+/* ;;Chrontel 7017 TV Reg. List */
+XGI330_TVDataTablStruct XGI_EPLCHTVRegPtr[]=
+{
+ {0x0011,0x0000,0}, /* XGI_CHTVRegUNTSC */
+ {0x0011,0x0010,1}, /* XGI_CHTVRegONTSC */
+ {0x0011,0x0001,2}, /* XGI_CHTVRegUPAL */
+ {0x0011,0x0011,3}, /* XGI_CHTVRegOPAL */
+ {0xFFFF,0x0000,4}
+};
+
+USHORT LCDLenList[]=
+{
+ LVDSCRT1Len_H,
+ LVDSCRT1Len_V,
+ LVDSDataLen,
+ LCDDesDataLen,
+ LCDDataLen,
+ LCDDesDataLen,
+ 0,
+ LCDDesDataLen,
+ LCDDesDataLen,
+ 0
+} ;
+
+XGI330_LCDCapStruct XGI660_LCDDLCapList[]= /* 660, Dual link */
+{
+/* LCDCap1024x768 */
+ {Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024 */
+ {Panel1280x1024, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1400x1050 */
+ {Panel1400x1050, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1600x1200 */
+ {Panel1600x1200, LCDDualLink+DefaultLCDCap, LCDToFull, 0x053, 0xC0, 0x03, VCLK162,
+ 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1024x768x75 */
+ {Panel1024x768x75, DefaultLCDCap, 0, 0x014, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024x75 */
+ {Panel1280x1024x75, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x053, 0x90, 0x03, VCLK135_5,
+ 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCapDefault */
+ {0xFF, DefaultLCDCap, 0, 0x053, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+};
+
+XGI330_LCDCapStruct XGI_LCDDLCapList[]= /* Dual link only */
+{
+/* LCDCap1024x768 */
+ {Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024 */
+ {Panel1280x1024, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1400x1050 */
+ {Panel1400x1050, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1600x1200 */
+ {Panel1600x1200, LCDDualLink+DefaultLCDCap, LCDToFull, 0x012, 0xC0, 0x03, VCLK162,
+ 0x43, 0x22, 0x70, 0x24, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1024x768x75 */
+ {Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024x75 */
+ {Panel1280x1024x75, LCDDualLink+DefaultLCDCap, StLCDBToA, 0x012, 0x90, 0x03, VCLK135_5,
+ 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCapDefault */
+ {0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+};
+
+XGI330_LCDCapStruct XGI660_LCDCapList[]=
+{
+/* LCDCap1024x768 */
+ {Panel1024x768, DefaultLCDCap, 0, 0x014, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024 */
+ {Panel1280x1024, DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1400x1050 */
+ {Panel1400x1050, DefaultLCDCap, StLCDBToA, 0x053, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1600x1200 */
+ {Panel1600x1200, DefaultLCDCap, LCDToFull, 0x053, 0xC0, 0x03, VCLK162,
+ 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1024x768x75 */
+ {Panel1024x768x75, DefaultLCDCap, 0, 0x014, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024x75 */
+ {Panel1280x1024x75,+DefaultLCDCap, StLCDBToA, 0x053, 0x90, 0x03, VCLK135_5,
+ 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCapDefault */
+ {0xFF, DefaultLCDCap, 0, 0x053, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+};
+
+XGI330_LCDCapStruct XGI_LCDCapList[]=
+{
+/* LCDCap1024x768 */
+ {Panel1024x768, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024 */
+ {Panel1280x1024, DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1400x1050 */
+ {Panel1400x1050, DefaultLCDCap, StLCDBToA, 0x012, 0x70, 0x03, VCLK108_2,
+ 0x70, 0x44, 0xF8, 0x2F, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1600x1200 */
+ {Panel1600x1200, DefaultLCDCap, LCDToFull, 0x012, 0xC0, 0x03, VCLK162,
+ 0x5A, 0x23, 0x5A, 0x23, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCap1024x768x75 */
+ {Panel1024x768x75, DefaultLCDCap, 0, 0x012, 0x60, 0, VCLK78_75,
+ 0x2B, 0x61, 0x2B, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10},
+/* LCDCap1280x1024x75 */
+ {Panel1280x1024x75, DefaultLCDCap, StLCDBToA, 0x012, 0x90, 0x03, VCLK135_5,
+ 0x54, 0x42, 0x4A, 0x61, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x30, 0x10},
+/* LCDCapDefault */
+ {0xFF, DefaultLCDCap, 0, 0x012, 0x88, 0x06, VCLK65,
+ 0x6C, 0xC3, 0x35, 0x62, 0x02, 0x14, 0x0A, 0x02, 0x00,
+ 0x30, 0x10, 0x5A, 0x10, 0x10, 0x0A, 0xC0, 0x28, 0x10}
+};
+
+XGI21_LVDSCapStruct XGI21_LCDCapList[]=
+{
+ {DisableLCD24bpp + LCDPolarity,
+ 2160,1250,1600,1200, 64, 1, 192, 3,
+ 0x70,0x24,0x20,0x04,0x0A,0x02,0xC8
+ },
+ {DisableLCD24bpp + LCDPolarity,
+ 1688,1066,1280,1024, 48, 1, 112, 3,
+ 0x70,0x44,0x20,0x04,0x0A,0x02,0xC8
+ },
+ {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8),
+ 1344, 806,1024, 768, 24, 3, 136, 6,
+ 0x6C,0x65,0x20,0x04,0x0A,0x02,0xC8
+ },
+ {DisableLCD24bpp + LCDPolarity,
+ 1056, 628, 800, 600, 40, 1, 128, 4,
+ 0x42,0xE2,0x20,0x14,0x0A,0x02,0x00
+ },
+ {DisableLCD24bpp + LCDPolarity,
+ 928, 525, 800, 480, 40, 13, 48, 3,
+ 0x52,0xC5,0x20,0x14,0x0A,0x02,0x00
+ },
+ {DisableLCD24bpp + LCDPolarity + (LCDPolarity << 8),
+ 800, 525, 640, 480, 16, 10, 96, 2,
+ 0x1B,0xE1,0x20,0x04,0x0A,0x02,0xC8
+ }
+
+};
+
+XGI_Ext2Struct XGI330_RefIndex[]=
+{
+{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x59, 320, 200},/* 00 */
+{Support32Bpp + SupportAllCRT2 + SyncPN, RES320x200, VCLK25_175, 0x00,0x10,0x00, 320, 400},/* 01 */
+{Support32Bpp + SupportAllCRT2 + SyncNN, RES320x240, VCLK25_175, 0x04,0x20,0x50, 320, 240},/* 02 */
+{Support32Bpp + SupportAllCRT2 + SyncPP, RES400x300, VCLK40, 0x05,0x32,0x51, 400, 300},/* 03 */
+{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES512x384, VCLK65, 0x06,0x43,0x52, 512, 384},/* 04 */
+{Support32Bpp + SupportAllCRT2 + SyncPN, RES640x400, VCLK25_175, 0x00,0x14,0x2f, 640, 400},/* 05 */
+{Support32Bpp + SupportAllCRT2 + SyncNN, RES640x480x60, VCLK25_175, 0x04,0x24,0x2e, 640, 480},/* 06 640x480x60Hz (LCD 640x480x60z) */
+{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x72, VCLK31_5, 0x04,0x24,0x2e, 640, 480},/* 07 640x480x72Hz (LCD 640x480x70Hz) */
+{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES640x480x75, VCLK31_5, 0x47,0x24,0x2e, 640, 480},/* 08 640x480x75Hz (LCD 640x480x75Hz) */
+{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x85, VCLK36, 0x8A,0x24,0x2e, 640, 480},/* 09 640x480x85Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x100, VCLK43_163, 0x00,0x24,0x2e, 640, 480},/* 0a 640x480x100Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x120, VCLK52_406, 0x00,0x24,0x2e, 640, 480},/* 0b 640x480x120Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES640x480x160, VCLK72_852, 0x00,0x24,0x2e, 640, 480},/* 0c 640x480x160Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncNN, RES640x480x200, VCLK86_6, 0x00,0x24,0x2e, 640, 480},/* 0d 640x480x200Hz */
+{Support32Bpp + NoSupportLCD + SyncPP, RES800x600x56, VCLK36, 0x05,0x36,0x6a, 800, 600},/* 0e 800x600x56Hz */
+{Support32Bpp + NoSupportTV + SyncPP, RES800x600x60, VCLK40, 0x05,0x36,0x6a, 800, 600},/* 0f 800x600x60Hz (LCD 800x600x60Hz) */
+{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x72, VCLK50, 0x48,0x36,0x6a, 800, 600},/* 10 800x600x72Hz (LCD 800x600x70Hz) */
+{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES800x600x75, VCLK49_5, 0x8B,0x36,0x6a, 800, 600},/* 11 800x600x75Hz (LCD 800x600x75Hz) */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x600x85, VCLK56_25, 0x00,0x36,0x6a, 800, 600},/* 12 800x600x85Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x100, VCLK68_179, 0x00,0x36,0x6a, 800, 600},/* 13 800x600x100Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x120, VCLK83_95, 0x00,0x36,0x6a, 800, 600},/* 14 800x600x120Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES800x600x160, VCLK116_406,0x00,0x36,0x6a, 800, 600},/* 15 800x600x160Hz */
+{Support32Bpp + InterlaceMode + SyncPP, RES1024x768x43, VCLK44_9, 0x00,0x47,0x37,1024, 768},/* 16 1024x768x43Hz */
+{Support32Bpp + NoSupportTV + SyncNN + SupportTV1024, RES1024x768x60, VCLK65, 0x06,0x47,0x37,1024, 768},/* 17 1024x768x60Hz (LCD 1024x768x60Hz) */
+{Support32Bpp + NoSupportHiVisionTV + SyncNN, RES1024x768x70, VCLK75, 0x49,0x47,0x37,1024, 768},/* 18 1024x768x70Hz (LCD 1024x768x70Hz) */
+{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1024x768x75, VCLK78_75, 0x00,0x47,0x37,1024, 768},/* 19 1024x768x75Hz (LCD 1024x768x75Hz) */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x768x85, VCLK94_5, 0x8C,0x47,0x37,1024, 768},/* 1a 1024x768x85Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x100, VCLK113_309,0x00,0x47,0x37,1024, 768},/* 1b 1024x768x100Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x120, VCLK139_054,0x00,0x47,0x37,1024, 768},/* 1c 1024x768x120Hz */
+{Support32Bpp + SupportLCD + SyncPP, RES1280x960x60, VCLK108_2, 0x08,0x58,0x7b,1280, 960},/* 1d 1280x960x60Hz */
+{Support32Bpp + InterlaceMode + SyncPP, RES1280x1024x43, VCLK78_75, 0x00,0x58,0x3a,1280,1024},/* 1e 1280x1024x43Hz */
+{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x60, VCLK108_2, 0x07,0x58,0x3a,1280,1024},/* 1f 1280x1024x60Hz (LCD 1280x1024x60Hz) */
+{Support32Bpp + NoSupportTV + SyncPP, RES1280x1024x75, VCLK135_5, 0x00,0x58,0x3a,1280,1024},/* 20 1280x1024x75Hz (LCD 1280x1024x75Hz) */
+{Support32Bpp + SyncPP, RES1280x1024x85, VCLK157_5, 0x00,0x58,0x3a,1280,1024},/* 21 1280x1024x85Hz */
+{Support32Bpp + SupportLCD + SyncPP + SupportCRT2in301C, RES1600x1200x60, VCLK162, 0x09,0x7A,0x3c,1600,1200},/* 22 1600x1200x60Hz */
+{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x65, VCLK175, 0x00,0x69,0x3c,1600,1200},/* 23 1600x1200x65Hz */
+{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x70, VCLK189, 0x00,0x69,0x3c,1600,1200},/* 24 1600x1200x70Hz */
+{Support32Bpp + SyncPP + SupportCRT2in301C, RES1600x1200x75, VCLK202_5, 0x00,0x69,0x3c,1600,1200},/* 25 1600x1200x75Hz */
+{Support32Bpp + SyncPP, RES1600x1200x85, VCLK229_5, 0x00,0x69,0x3c,1600,1200},/* 26 1600x1200x85Hz */
+{Support32Bpp + SyncPP, RES1600x1200x100,VCLK269_655,0x00,0x69,0x3c,1600,1200},/* 27 1600x1200x100Hz */
+{Support32Bpp + SyncPP, RES1600x1200x120,VCLK323_586,0x00,0x69,0x3c,1600,1200},/* 28 1600x1200x120Hz */
+{Support32Bpp + SupportLCD + SyncNP, RES1920x1440x60, VCLK234, 0x00,0x00,0x68,1920,1440},/* 29 1920x1440x60Hz */
+{Support32Bpp + SyncPN, RES1920x1440x65, VCLK254_817,0x00,0x00,0x68,1920,1440},/* 2a 1920x1440x65Hz */
+{Support32Bpp + SyncPN, RES1920x1440x70, VCLK277_015,0x00,0x00,0x68,1920,1440},/* 2b 1920x1440x70Hz */
+{Support32Bpp + SyncPN, RES1920x1440x75, VCLK291_132,0x00,0x00,0x68,1920,1440},/* 2c 1920x1440x75Hz */
+{Support32Bpp + SyncPN, RES1920x1440x85, VCLK330_615,0x00,0x00,0x68,1920,1440},/* 2d 1920x1440x85Hz */
+{Support16Bpp + SyncPN, RES1920x1440x100,VCLK388_631,0x00,0x00,0x68,1920,1440},/* 2e 1920x1440x100Hz */
+{Support32Bpp + SupportLCD + SyncPN, RES2048x1536x60, VCLK266_952,0x00,0x00,0x6c,2048,1536},/* 2f 2048x1536x60Hz */
+{Support32Bpp + SyncPN, RES2048x1536x65, VCLK291_766,0x00,0x00,0x6c,2048,1536},/* 30 2048x1536x65Hz */
+{Support32Bpp + SyncPN, RES2048x1536x70, VCLK315_195,0x00,0x00,0x6c,2048,1536},/* 31 2048x1536x70Hz */
+{Support32Bpp + SyncPN, RES2048x1536x75, VCLK340_477,0x00,0x00,0x6c,2048,1536},/* 32 2048x1536x75Hz */
+{Support16Bpp + SyncPN, RES2048x1536x85, VCLK375_847,0x00,0x00,0x6c,2048,1536},/* 33 2048x1536x85Hz */
+{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES800x480x60, VCLK39_77, 0x08,0x00,0x70, 800, 480},/* 34 800x480x60Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x75, VCLK49_5, 0x08,0x00,0x70, 800, 480},/* 35 800x480x75Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES800x480x85, VCLK56_25, 0x08,0x00,0x70, 800, 480},/* 36 800x480x85Hz */
+{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES1024x576x60, VCLK65, 0x09,0x00,0x71,1024, 576},/* 37 1024x576x60Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x75, VCLK78_75, 0x09,0x00,0x71,1024, 576},/* 38 1024x576x75Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1024x576x85, VCLK94_5, 0x09,0x00,0x71,1024, 576},/* 39 1024x576x85Hz */
+{Support32Bpp + SupportHiVisionTV + SupportRAMDAC2 + SyncPP + SupportYPbPr, RES1280x720x60, VCLK108_2, 0x0A,0x00,0x75,1280, 720},/* 3a 1280x720x60Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x75, VCLK135_5, 0x0A,0x00,0x75,1280, 720},/* 3b 1280x720x75Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1280x720x85, VCLK157_5, 0x0A,0x00,0x75,1280, 720},/* 3c 1280x720x85Hz */
+{Support32Bpp + SupportTV + SyncNN, RES720x480x60, VCLK28_322, 0x06,0x00,0x31, 720, 480},/* 3d 720x480x60Hz */
+{Support32Bpp + SupportTV + SyncPP, RES720x576x56, VCLK36, 0x06,0x00,0x32, 720, 576},/* 3e 720x576x56Hz */
+{Support32Bpp + InterlaceMode + NoSupportLCD + SyncPP, RES856x480x79I, VCLK35_2, 0x00,0x00,0x00, 856, 480},/* 3f 856x480x79I */
+{Support32Bpp + NoSupportLCD + SyncNN, RES856x480x60, VCLK35_2, 0x00,0x00,0x00, 856, 480},/* 40 856x480x60Hz */
+{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1280x768x60, VCLK79_411, 0x08,0x48,0x23,1280, 768},/* 41 1280x768x60Hz */
+{Support32Bpp + NoSupportHiVisionTV + SyncPP, RES1400x1050x60, VCLK122_61, 0x08,0x69,0x26,1400,1050},/* 42 1400x1050x60Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x60, VCLK80_350, 0x37,0x00,0x20,1152, 864},/* 43 1152x864x60Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPP, RES1152x864x75, VCLK107_385,0x37,0x00,0x20,1152, 864},/* 44 1152x864x75Hz */
+{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x75, VCLK125_999,0x3A,0x88,0x7b,1280, 960},/* 45 1280x960x75Hz */
+{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x85, VCLK148_5, 0x0A,0x88,0x7b,1280, 960},/* 46 1280x960x85Hz */
+{Support32Bpp + SupportLCD + SupportRAMDAC2 + SyncPP, RES1280x960x120, VCLK217_325,0x3A,0x88,0x7b,1280, 960},/* 47 1280x960x120Hz */
+{Support32Bpp + SupportRAMDAC2 + SyncPN, RES1024x768x160, VCLK139_054,0x30,0x47,0x37,1024, 768},/* 48 1024x768x160Hz */
+};
+
+
+
+XGI330_VCLKDataStruct XGI330_VCLKData[]=
+{
+ { 0x1b,0xe1, 25}, /* 0x0 */
+ { 0x4e,0xe4, 28}, /* 0x1 */
+ { 0x57,0xe4, 31}, /* 0x2 */
+ { 0xc3,0xc8, 36}, /* 0x3 */
+ { 0x42,0xe2, 40}, /* 0x4 */
+ { 0xfe,0xcd, 43}, /* 0x5 */
+ { 0x5d,0xc4, 44}, /* 0x6 */
+ { 0x52,0xe2, 49}, /* 0x7 */
+ { 0x53,0xe2, 50}, /* 0x8 */
+ { 0x74,0x67, 52}, /* 0x9 */
+ { 0x6d,0x66, 56}, /* 0xa */
+ { 0x6c,0xc3, 65}, /* 0xb */
+ { 0x46,0x44, 67}, /* 0xc */
+ { 0xb1,0x46, 68}, /* 0xd */
+ { 0xd3,0x4a, 72}, /* 0xe */
+ { 0x29,0x61, 75}, /* 0xf */
+ { 0x6e,0x46, 76}, /* 0x10 */
+ { 0x2b,0x61, 78}, /* 0x11 */
+ { 0x31,0x42, 79}, /* 0x12 */
+ { 0xab,0x44, 83}, /* 0x13 */
+ { 0x46,0x25, 84}, /* 0x14 */
+ { 0x78,0x29, 86}, /* 0x15 */
+ { 0x62,0x44, 94}, /* 0x16 */
+ { 0x2b,0x41,104}, /* 0x17 */
+ { 0x3a,0x23,105}, /* 0x18 */
+ { 0x70,0x44,108}, /* 0x19 */
+ { 0x3c,0x23,109}, /* 0x1a */
+ { 0x5e,0x43,113}, /* 0x1b */
+ { 0xbc,0x44,116}, /* 0x1c */
+ { 0xe0,0x46,132}, /* 0x1d */
+ { 0x54,0x42,135}, /* 0x1e */
+ { 0xea,0x2a,139}, /* 0x1f */
+ { 0x41,0x22,157}, /* 0x20 */
+ { 0x70,0x24,162}, /* 0x21 */
+ { 0x30,0x21,175}, /* 0x22 */
+ { 0x4e,0x22,189}, /* 0x23 */
+ { 0xde,0x26,194}, /* 0x24 */
+ { 0x62,0x06,202}, /* 0x25 */
+ { 0x3f,0x03,229}, /* 0x26 */
+ { 0xb8,0x06,234}, /* 0x27 */
+ { 0x34,0x02,253}, /* 0x28 */
+ { 0x58,0x04,255}, /* 0x29 */
+ { 0x24,0x01,265}, /* 0x2a */
+ { 0x9b,0x02,267}, /* 0x2b */
+ { 0x70,0x05,270}, /* 0x2c */
+ { 0x25,0x01,272}, /* 0x2d */
+ { 0x9c,0x02,277}, /* 0x2e */
+ { 0x27,0x01,286}, /* 0x2f */
+ { 0x3c,0x02,291}, /* 0x30 */
+ { 0xef,0x0a,292}, /* 0x31 */
+ { 0xf6,0x0a,310}, /* 0x32 */
+ { 0x95,0x01,315}, /* 0x33 */
+ { 0xf0,0x09,324}, /* 0x34 */
+ { 0xfe,0x0a,331}, /* 0x35 */
+ { 0xf3,0x09,332}, /* 0x36 */
+ { 0xea,0x08,340}, /* 0x37 */
+ { 0xe8,0x07,376}, /* 0x38 */
+ { 0xde,0x06,389}, /* 0x39 */
+ { 0x52,0x2a, 54}, /* 0x3a */
+ { 0x52,0x6a, 27}, /* 0x3b */
+ { 0x62,0x24, 70}, /* 0x3c */
+ { 0x62,0x64, 70}, /* 0x3d */
+ { 0xa8,0x4c, 30}, /* 0x3e */
+ { 0x20,0x26, 33}, /* 0x3f */
+ { 0x31,0xc2, 39}, /* 0x40 */
+ { 0x60,0x36, 30}, /* 0x41 */
+ { 0x40,0x4A, 28}, /* 0x42 */
+ { 0x9F,0x46, 44}, /* 0x43 */
+ { 0x97,0x2C, 26}, /* 0x44 */
+ { 0x44,0xE4, 25}, /* 0x45 */
+ { 0x7E,0x32, 47}, /* 0x46 */
+ { 0x08,0x24, 31}, /* 0x47 */
+ { 0x97,0x2c, 26}, /* 0x48 */
+ { 0xCE,0x3c, 39}, /* 0x49 */
+ { 0x52,0x4A, 36}, /* 0x4a */
+ { 0x2C,0x61, 95}, /* 0x4b */
+ { 0x78,0x27,108}, /* 0x4c */
+ { 0x66,0x43,123}, /* 0x4d */
+ { 0x2c,0x61, 80}, /* 0x4e */
+ { 0x3b,0x61,108} /* 0x4f */
+};
+
+XGI_VBVCLKDataStruct XGI330_VBVCLKData[]=
+{
+ { 0x1b,0xe1, 25}, /* 0x0 */
+ { 0x4e,0xe4, 28}, /* 0x1 */
+ { 0x57,0xe4, 31}, /* 0x2 */
+ { 0xc3,0xc8, 36}, /* 0x3 */
+ { 0x42,0x47, 40}, /* 0x4 */
+ { 0xfe,0xcd, 43}, /* 0x5 */
+ { 0x5d,0xc4, 44}, /* 0x6 */
+ { 0x52,0x47, 49}, /* 0x7 */
+ { 0x53,0x47, 50}, /* 0x8 */
+ { 0x74,0x67, 52}, /* 0x9 */
+ { 0x6d,0x66, 56}, /* 0xa */
+ { 0x5a,0x64, 65}, /* 0xb */
+ { 0x46,0x44, 67}, /* 0xc */
+ { 0xb1,0x46, 68}, /* 0xd */
+ { 0xd3,0x4a, 72}, /* 0xe */
+ { 0x29,0x61, 75}, /* 0xf */
+ { 0x6d,0x46, 75}, /* 0x10 */
+ { 0x41,0x43, 78}, /* 0x11 */
+ { 0x31,0x42, 79}, /* 0x12 */
+ { 0xab,0x44, 83}, /* 0x13 */
+ { 0x46,0x25, 84}, /* 0x14 */
+ { 0x78,0x29, 86}, /* 0x15 */
+ { 0x62,0x44, 94}, /* 0x16 */
+ { 0x2b,0x22,104}, /* 0x17 */
+ { 0x49,0x24,105}, /* 0x18 */
+ { 0xf8,0x2f,108}, /* 0x19 */
+ { 0x3c,0x23,109}, /* 0x1a */
+ { 0x5e,0x43,113}, /* 0x1b */
+ { 0xbc,0x44,116}, /* 0x1c */
+ { 0xe0,0x46,132}, /* 0x1d */
+ { 0xd4,0x28,135}, /* 0x1e */
+ { 0xea,0x2a,139}, /* 0x1f */
+ { 0x41,0x22,157}, /* 0x20 */
+ { 0x70,0x24,162}, /* 0x21 */
+ { 0x30,0x21,175}, /* 0x22 */
+ { 0x4e,0x22,189}, /* 0x23 */
+ { 0xde,0x26,194}, /* 0x24 */
+ { 0x70,0x07,202}, /* 0x25 */
+ { 0x3f,0x03,229}, /* 0x26 */
+ { 0xb8,0x06,234}, /* 0x27 */
+ { 0x34,0x02,253}, /* 0x28 */
+ { 0x58,0x04,255}, /* 0x29 */
+ { 0x24,0x01,265}, /* 0x2a */
+ { 0x9b,0x02,267}, /* 0x2b */
+ { 0x70,0x05,270}, /* 0x2c */
+ { 0x25,0x01,272}, /* 0x2d */
+ { 0x9c,0x02,277}, /* 0x2e */
+ { 0x27,0x01,286}, /* 0x2f */
+ { 0x3c,0x02,291}, /* 0x30 */
+ { 0xef,0x0a,292}, /* 0x31 */
+ { 0xf6,0x0a,310}, /* 0x32 */
+ { 0x95,0x01,315}, /* 0x33 */
+ { 0xf0,0x09,324}, /* 0x34 */
+ { 0xfe,0x0a,331}, /* 0x35 */
+ { 0xf3,0x09,332}, /* 0x36 */
+ { 0xea,0x08,340}, /* 0x37 */
+ { 0xe8,0x07,376}, /* 0x38 */
+ { 0xde,0x06,389}, /* 0x39 */
+ { 0x52,0x2a, 54}, /* 0x3a */
+ { 0x52,0x6a, 27}, /* 0x3b */
+ { 0x62,0x24, 70}, /* 0x3c */
+ { 0x62,0x64, 70}, /* 0x3d */
+ { 0xa8,0x4c, 30}, /* 0x3e */
+ { 0x20,0x26, 33}, /* 0x3f */
+ { 0x31,0xc2, 39}, /* 0x40 */
+ { 0x2e,0x48, 25}, /* 0x41 */
+ { 0x24,0x46, 25}, /* 0x42 */
+ { 0x26,0x64, 28}, /* 0x43 */
+ { 0x37,0x64, 40}, /* 0x44 */
+ { 0xa1,0x42,108}, /* 0x45 */
+ { 0x37,0x61,100}, /* 0x46 */
+ { 0x78,0x27,108}, /* 0x47 */
+ { 0x5e,0x64,68}, /* 0x48 chiawen for fuj1280x768*/
+ { 0x70,0x44,108}, /* 0x49 chiawen for 1400x1050*/
+};
+
+UCHAR XGI330_ScreenOffset[]={ 0x14,0x19,0x20,0x28,0x32,0x40,0x50,0x64,0x78,0x80,0x2d,0x35,0x57,0x48 };
+
+XGI_StResInfoStruct XGI330_StResInfo[]=
+{
+ { 640,400},
+ { 640,350},
+ { 720,400},
+ { 720,350},
+ { 640,480}
+};
+
+XGI_ModeResInfoStruct XGI330_ModeResInfo[]=
+{
+ { 320, 200, 8, 8},
+ { 320, 240, 8, 8},
+ { 320, 400, 8, 8},
+ { 400, 300, 8, 8},
+ { 512, 384, 8, 8},
+ { 640, 400, 8,16},
+ { 640, 480, 8,16},
+ { 800, 600, 8,16},
+ { 1024, 768, 8,16},
+ { 1280,1024, 8,16},
+ { 1600,1200, 8,16},
+ { 1920,1440, 8,16},
+ { 2048,1536, 8,16},
+ { 720, 480, 8,16},
+ { 720, 576, 8,16},
+ { 1280, 960, 8,16},
+ { 800, 480, 8,16},
+ { 1024, 576, 8,16},
+ { 1280, 720, 8,16},
+ { 856, 480, 8,16},
+ { 1280, 768, 8,16},
+ { 1400,1050, 8,16},
+ { 1152, 864, 8,16}
+};
+
+UCHAR XGI330_OutputSelect =0x40;
+UCHAR XGI330_SoftSetting = 0x30;
+UCHAR XGI330_SR07=0x18;
+UCHAR XGI330New_SR15[8][8]={
+{0x0,0x4,0x60,0x60},
+{0xf,0xf,0xf,0xf},
+{0xba,0xba,0xba,0xba},
+{0xa9,0xa9,0xac,0xac},
+{0xa0,0xa0,0xa0,0xa8},
+{0x0,0x0,0x2,0x2},
+{0x30,0x30,0x40,0x40},
+{0x0,0xa5,0xfb,0xf6}
+};
+
+UCHAR XGI330New_CR40[5][8]={
+{0x77,0x77,0x44,0x44},
+{0x77,0x77,0x44,0x44},
+{0x0,0x0,0x0,0x0},
+{0x5b,0x5b,0xab,0xab},
+{0x0,0x0,0xf0,0xf8}
+};
+
+UCHAR XGI330_CR49[]={0xaa,0x88};
+UCHAR XGI330_SR1F=0x0;
+UCHAR XGI330_SR21=0xa3;
+UCHAR XGI330_650_SR21=0xa7;
+UCHAR XGI330_SR22=0xfb;
+UCHAR XGI330_SR23=0xf6;
+UCHAR XGI330_SR24=0xd;
+
+UCHAR XGI660_SR21=0xa3;/* 2003.0312 */
+UCHAR XGI660_SR22=0xf3;/* 2003.0312 */
+
+UCHAR XGI330_LVDS_SR32=0x00; /* ynlai for 650 LVDS */
+UCHAR XGI330_LVDS_SR33=0x00; /* chiawen for 650 LVDS */
+UCHAR XGI330_650_SR31=0x40;
+UCHAR XGI330_650_SR33=0x04;
+UCHAR XGI330_CRT2Data_1_2 = 0x0;
+UCHAR XGI330_CRT2Data_4_D = 0x0;
+UCHAR XGI330_CRT2Data_4_E = 0x0;
+UCHAR XGI330_CRT2Data_4_10 = 0x80;
+USHORT XGI330_RGBSenseData = 0xd1;
+USHORT XGI330_VideoSenseData = 0xb9;
+USHORT XGI330_YCSenseData = 0xb3;
+USHORT XGI330_RGBSenseData2 = 0x0190; /*301b*/
+USHORT XGI330_VideoSenseData2 = 0x0110;
+USHORT XGI330_YCSenseData2 = 0x016B;
+UCHAR XGI330_NTSCPhase[] = {0x21,0xed,0x8a,0x8};
+UCHAR XGI330_PALPhase[] = {0x2a,0x5,0xd3,0x0};
+UCHAR XGI330_NTSCPhase2[] = {0x21,0xF0,0x7B,0xD6};/*301b*/
+UCHAR XGI330_PALPhase2[] = {0x2a,0x09,0x86,0xe9};
+UCHAR XGI330_PALMPhase[] = {0x21,0xE4,0x2E,0x9B}; /*palmn*/
+UCHAR XGI330_PALNPhase[] = {0x21,0xF4,0x3E,0xBA};
+UCHAR XG40_I2CDefinition = 0x00 ;
+UCHAR XG20_CR97 = 0x10 ;
+
+UCHAR XG21_DVOSetting = 0x00 ;
+UCHAR XG21_CR2E = 0x00 ;
+UCHAR XG21_CR2F = 0x00 ;
+UCHAR XG21_CR46 = 0x00 ;
+UCHAR XG21_CR47 = 0x00 ;
+
+UCHAR XG27_CR97 = 0xC1 ;
+UCHAR XG27_SR36 = 0x30 ;
+UCHAR XG27_CR8F = 0x0C ;
+UCHAR XG27_CRD0[] = {0,0,0,0,0,0,0,0x82,0x00,0x66,0x01,0x00} ;
+UCHAR XG27_CRDE[] = {0,0} ;
+UCHAR XG27_SR40 = 0x04 ;
+UCHAR XG27_SR41 = 0x00 ;
+
+UCHAR XGI330_CHTVVCLKUNTSC[]={0x00 };
+
+UCHAR XGI330_CHTVVCLKONTSC[]={0x00 };
+
+UCHAR XGI330_CHTVVCLKUPAL[]={0x00 };
+
+UCHAR XGI330_CHTVVCLKOPAL[]={0x00 };
+
+UCHAR XGI7007_CHTVVCLKUNTSC[]={CH7007TVVCLK30_2,
+ CH7007TVVCLK30_2,
+ CH7007TVVCLK30_2,
+ CH7007TVVCLK30_2,
+ CH7007TVVCLK28_1,
+ CH7007TVVCLK47_8
+ };
+
+UCHAR XGI7007_CHTVVCLKONTSC[]={CH7007TVVCLK26_4,
+ CH7007TVVCLK26_4,
+ CH7007TVVCLK26_4,
+ CH7007TVVCLK26_4,
+ CH7007TVVCLK24_6,
+ CH7007TVVCLK43_6
+ };
+
+UCHAR XGI7007_CHTVVCLKUPAL[]={CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK26_2,
+ CH7007TVVCLK39
+ };
+
+UCHAR XGI7007_CHTVVCLKOPAL[]={CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK31_5,
+ CH7007TVVCLK26_2,
+ CH7007TVVCLK36
+ };
+
+XGI330_VCLKDataStruct XGI_CH7007VCLKData[]=
+{
+ { 0x60,0x36,30}, /* 0 30.2 MHZ */
+ { 0x40,0x4A,28}, /* 1 28.19 MHZ */
+ { 0x9F,0x46,44}, /* 2 43.6 MHZ */
+ { 0x97,0x2C,26}, /* 3 26.4 MHZ */
+ { 0x44,0xE4,25}, /* 4 24.6 MHZ */
+ { 0x7E,0x32,47}, /* 5 47.832 MHZ */
+ { 0x8A,0x24,31}, /* 6 31.5 MHZ */
+ { 0x97,0x2C,26}, /* 7 26.2 MHZ */
+ { 0xCE,0x3C,39}, /* 8 39 MHZ */
+ { 0x52,0x4A,36}, /* 9 36 MHZ */
+ { 0xFF,0x00,0 } /* End mark */
+};
+
+XGI330_VCLKDataStruct XGI_VCLKData[]=
+{
+ /* SR2B,SR2C,SR2D */
+ { 0x1B,0xE1,25 },/* 00 (25.175MHz) */
+
+ { 0x4E,0xE4,28 },/* 01 (28.322MHz) */
+
+ { 0x57,0xE4,31 },/* 02 (31.500MHz) */
+
+ { 0xC3,0xC8,36 },/* 03 (36.000MHz) */
+
+ { 0x42,0xE2,40 },/* 04 (40.000MHz) */
+
+ { 0xFE,0xCD,43 },/* 05 (43.163MHz) */
+
+ { 0x5D,0xC4,44 },/* 06 (44.900MHz) */
+
+ { 0x52,0xE2,49 },/* 07 (49.500MHz) */
+
+ { 0x53,0xE2,50 },/* 08 (50.000MHz) */
+
+ { 0x74,0x67,52 },/* 09 (52.406MHz) */
+
+ { 0x6D,0x66,56 },/* 0A (56.250MHz) */
+
+ { 0x6C,0xC3,65 },/* 0B (65.000MHz) */
+
+ { 0x46,0x44,67 },/* 0C (67.765MHz) */
+
+ { 0xB1,0x46,68 },/* 0D (68.179MHz) */
+
+ { 0xD3,0x4A,72 },/* 0E (72.852MHz) */
+
+ { 0x29,0x61,75 },/* 0F (75.000MHz) */
+
+ { 0x6E,0x46,76 },/* 10 (75.800MHz) */
+
+ { 0x2B,0x61,78 },/* 11 (78.750MHz) */
+
+ { 0x31,0x42,79 },/* 12 (79.411MHz) */
+
+ { 0xAB,0x44,83 },/* 13 (83.950MHz) */
+
+ { 0x46,0x25,84 },/* 14 (84.800MHz) */
+
+ { 0x78,0x29,86 },/* 15 (86.600MHz) */
+
+ { 0x62,0x44,94 },/* 16 (94.500MHz) */
+
+ { 0x2B,0x41,104 },/* 17 (104.998MHz) */
+
+ { 0x3A,0x23,105 },/* 18 (105.882MHz) */
+
+ { 0x70,0x44,108 },/* 19 (107.862MHz) */
+
+ { 0x3C,0x23,109 },/* 1A (109.175MHz) */
+
+ { 0x5E,0x43,113 },/* 1B (113.309MHz) */
+
+ { 0xBC,0x44,116 },/* 1C (116.406MHz) */
+
+ { 0xE0,0x46,132 },/* 1D (132.258MHz) */
+
+ { 0x54,0x42,135 },/* 1E (135.500MHz) */
+
+ { 0x9C,0x22,139 },/* 1F (139.275MHz) */
+
+ { 0x41,0x22,157 },/* 20 (157.500MHz) */
+
+ { 0x70,0x24,162 },/* 21 (161.793MHz) */
+
+ { 0x30,0x21,175 },/* 22 (175.000MHz) */
+
+ { 0x4E,0x22,189 },/* 23 (188.520MHz) */
+
+ { 0xDE,0x26,194 },/* 24 (194.400MHz) */
+
+ { 0x62,0x06,202 },/* 25 (202.500MHz) */
+
+ { 0x3F,0x03,229 },/* 26 (229.500MHz) */
+
+ { 0xB8,0x06,234 },/* 27 (233.178MHz) */
+
+ { 0x34,0x02,253 },/* 28 (252.699MHz) */
+
+ { 0x58,0x04,255 },/* 29 (254.817MHz) */
+
+ { 0x24,0x01,265 },/* 2A (265.728MHz) */
+
+ { 0x9B,0x02,267 },/* 2B (266.952MHz) */
+
+ { 0x70,0x05,270 },/* 2C (269.65567MHz) */
+
+ { 0x25,0x01,272 },/* 2D (272.04199MHz) */
+
+ { 0x9C,0x02,277 },/* 2E (277.015MHz) */
+
+ { 0x27,0x01,286 },/* 2F (286.359985MHz) */
+
+ { 0xB3,0x04,291 },/* 30 (291.13266MHz) */
+
+ { 0xBC,0x05,292 },/* 31 (291.766MHz) */
+
+ { 0xF6,0x0A,310 },/* 32 (309.789459MHz) */
+
+ { 0x95,0x01,315 },/* 33 (315.195MHz) */
+
+ { 0xF0,0x09,324 },/* 34 (323.586792MHz) */
+
+ { 0xFE,0x0A,331 },/* 35 (330.615631MHz) */
+
+ { 0xF3,0x09,332 },/* 36 (332.177612MHz) */
+
+ { 0x5E,0x03,340 },/* 37 (340.477MHz) */
+
+ { 0xE8,0x07,376 },/* 38 (375.847504MHz) */
+
+ { 0xDE, 0x06,389 },/* 39 (388.631439MHz) */
+
+ { 0x52,0x2A,54 },/* 3A (54.000MHz) */
+
+ { 0x52,0x6A,27 },/* 3B (27.000MHz) */
+
+ { 0x62,0x24,70 },/* 3C (70.874991MHz) */
+
+ { 0x62,0x64,70 },/* 3D (70.1048912MHz) */
+
+ { 0xA8,0x4C,30 },/* 3E (30.1048912MHz) */
+
+ { 0x20,0x26,33 },/* 3F (33.7499957MHz) */
+
+ { 0x31,0xc2,39 },/* 40 (39.77MHz) */
+
+ { 0x11,0x21,30 },/* 41 (30MHz) }// NTSC 1024X768 */
+
+ { 0x2E,0x48,25 },/* 42 (25.175MHz) }// ScaleLCD */
+
+ { 0x24,0x46,25 },/* 43 (25.175MHz) */
+
+ { 0x26,0x64,28 },/* 44 (28.322MHz) */
+
+ { 0x37,0x64,40 },/* 45 (40.000MHz) */
+
+ { 0xA1,0x42,108 },/* 46 (95.000MHz) }// QVGA */
+
+ { 0x37,0x61,100 },/* 47 (100.00MHz) */
+
+ { 0x78,0x27,108 },/* 48 (108.200MHz) */
+
+ { 0xBF,0xC8,35 },/* 49 (35.2MHz) */
+
+ { 0x66,0x43,123 },/* 4A (122.61Mhz) */
+
+ { 0x2C,0x61,80 },/* 4B (80.350Mhz) */
+
+ { 0x3B,0x61,108 },/* 4C (107.385Mhz) */
+
+
+/* { 0x60,0x36,30 },// 4D (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 4E (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 4F (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 50 (30.200MHz) }// CHTV
+
+ { 0x40,0x4A,28 },// 51 (28.190MHz)
+
+ { 0x9F,0x46,44 },// 52 (43.600MHz)
+
+ { 0x97,0x2C,26 },// 53 (26.400MHz)
+
+ { 0x44,0xE4,25 },// 54 (24.600MHz)
+
+ { 0x7E,0x32,47 },// 55 (47.832MHz)
+
+ { 0x8A,0x24,31 },// 56 (31.500MHz)
+
+ { 0x97,0x2C,26 },// 57 (26.200MHz)
+
+ { 0xCE,0x3C,39 },// 58 (39.000MHz)
+
+ { 0x52,0x4A,36 },// 59 (36.000MHz)
+
+*/
+ { 0x69,0x61,191 }, /* 4D (190.96MHz ) */
+ { 0x4F,0x22,192 }, /* 4E (192.069MHz) */
+ { 0x28,0x26,322 }, /* 4F (322.273MHz) */
+ { 0x5C,0x6B,27 }, /* 50 (27.74HMz) */
+ { 0x57,0x24,126 }, /* 51 (125.999MHz) */
+ { 0x5C,0x42,148 }, /* 52 (148.5MHz) */
+ { 0x42,0x61,120 }, /* 53 (120.839MHz) */
+ { 0x62,0x61,178 }, /* 54 (178.992MHz) */
+ { 0x59,0x22,217 }, /* 55 (217.325MHz) */
+ { 0x29,0x01,300 }, /* 56 (299.505Mhz) */
+ { 0x52,0x63,74 }, /* 57 (74.25MHz) */
+
+
+ { 0xFF,0x00,0 }/* End mark */
+ } ;
+
+XGI330_VCLKDataStruct XGI_VBVCLKData[]=
+{
+ { 0x1B,0xE1,25 },/* 00 (25.175MHz) */
+
+ { 0x4E,0xE4,28 },/* 01 (28.322MHz) */
+
+ { 0x57,0xE4,31 },/* 02 (31.500MHz) */
+
+ { 0xC3,0xC8,36 },/* 03 (36.000MHz) */
+
+ { 0x42,0x47,40 },/* 04 (40.000MHz) */
+
+ { 0xFE,0xCD,43 },/* 05 (43.163MHz) */
+
+ { 0x5D,0xC4,44 },/* 06 (44.900MHz) */
+
+ { 0x52,0x47,49 },/* 07 (49.500MHz) */
+
+ { 0x53,0x47,50 },/* 08 (50.000MHz) */
+
+ { 0x74,0x67,52 },/* 09 (52.406MHz) */
+
+ { 0x6D,0x66,56 },/* 0A (56.250MHz) */
+
+ { 0x35,0x62,65 },/* 0B (65.000MHz) */
+
+ { 0x46,0x44,67 },/* 0C (67.765MHz) */
+
+ { 0xB1,0x46,68 },/* 0D (68.179MHz) */
+
+ { 0xD3,0x4A,72 },/* 0E (72.852MHz) */
+
+ { 0x29,0x61,75 },/* 0F (75.000MHz) */
+
+ { 0x6D,0x46,75 },/* 10 (75.800MHz) */
+
+ { 0x41,0x43,78 },/* 11 (78.750MHz) */
+
+ { 0x31,0x42,79 },/* 12 (79.411MHz) */
+
+ { 0xAB,0x44,83 },/* 13 (83.950MHz) */
+
+ { 0x46,0x25,84 },/* 14 (84.800MHz) */
+
+ { 0x78,0x29,86 },/* 15 (86.600MHz) */
+
+ { 0x62,0x44,94 },/* 16 (94.500MHz) */
+
+ { 0x2B,0x22,104 },/* 17 (104.998MHz) */
+
+ { 0x49,0x24,105 },/* 18 (105.882MHz) */
+
+ { 0xF8,0x2F,108 },/* 19 (108.279MHz) */
+
+ { 0x3C,0x23,109 },/* 1A (109.175MHz) */
+
+ { 0x5E,0x43,113 },/* 1B (113.309MHz) */
+
+ { 0xBC,0x44,116 },/* 1C (116.406MHz) */
+
+ { 0xE0,0x46,132 },/* 1D (132.258MHz) */
+
+ { 0xD4,0x28,135 },/* 1E (135.220MHz) */
+
+ { 0xEA,0x2A,139 },/* 1F (139.275MHz) */
+
+ { 0x41,0x22,157 },/* 20 (157.500MHz) */
+
+ { 0x70,0x24,162 },/* 21 (161.793MHz) */
+
+ { 0x30,0x21,175 },/* 22 (175.000MHz) */
+
+ { 0x4E,0x22,189 },/* 23 (188.520MHz) */
+
+ { 0xDE,0x26,194 },/* 24 (194.400MHz) */
+
+ { 0x70,0x07,202 },/* 25 (202.500MHz) */
+
+ { 0x3F,0x03,229 },/* 26 (229.500MHz) */
+
+ { 0xB8,0x06,234 },/* 27 (233.178MHz) */
+
+ { 0x34,0x02,253 },/* 28 (252.699997 MHz) */
+
+ { 0x58,0x04,255 },/* 29 (254.817MHz) */
+
+ { 0x24,0x01,265 },/* 2A (265.728MHz) */
+
+ { 0x9B,0x02,267 },/* 2B (266.952MHz) */
+
+ { 0x70,0x05,270 },/* 2C (269.65567 MHz) */
+
+ { 0x25,0x01,272 },/* 2D (272.041992 MHz) */
+
+ { 0x9C,0x02,277 },/* 2E (277.015MHz) */
+
+ { 0x27,0x01,286 },/* 2F (286.359985 MHz) */
+
+ { 0x3C,0x02,291 },/* 30 (291.132660 MHz) */
+
+ { 0xEF,0x0A,292 },/* 31 (291.766MHz) */
+
+ { 0xF6,0x0A,310 },/* 32 (309.789459 MHz) */
+
+ { 0x95,0x01,315 },/* 33 (315.195MHz) */
+
+ { 0xF0,0x09,324 },/* 34 (323.586792 MHz) */
+
+ { 0xFE,0x0A,331 },/* 35 (330.615631 MHz) */
+
+ { 0xF3,0x09,332 },/* 36 (332.177612 MHz) */
+
+ { 0xEA,0x08,340 },/* 37 (340.477MHz) */
+
+ { 0xE8,0x07,376 },/* 38 (375.847504 MHz) */
+
+ { 0xDE,0x06,389 },/* 39 (388.631439 MHz) */
+
+ { 0x52,0x2A,54 },/* 3A (54.000MHz) */
+
+ { 0x52,0x6A,27 },/* 3B (27.000MHz) */
+
+
+ { 0x62,0x24,70 },/* 3C (70.874991MHz) */
+
+
+ { 0x62,0x64,70 },/* 3D (70.1048912MHz) */
+
+ { 0xA8,0x4C,30 },/* 3E (30.1048912MHz) */
+
+ { 0x20,0x26,33 },/* 3F (33.7499957MHz) */
+
+ { 0x31,0xc2,39 },/* 40 (39.77MHz) */
+
+ { 0x11,0x21,30 },/* 41 (30MHz) }// NTSC 1024X768 */
+
+ { 0x2E,0x48,25 },/* 42 (25.175MHz) }// ScaleLCD */
+
+ { 0x24,0x46,25 },/* 43 (25.175MHz) */
+
+ { 0x26,0x64,28 },/* 44 (28.322MHz) */
+
+ { 0x37,0x64,40 },/* 45 (40.000MHz) */
+
+ { 0xA1,0x42,108 },/* 46 (95.000MHz) }// QVGA */
+
+ { 0x37,0x61,100 },/* 47 (100.00MHz) */
+
+ { 0x78,0x27,108 },/* 48 (108.200MHz) */
+
+ { 0xBF,0xC8,35 },/* 49 (35.2MHz) */
+
+ { 0x66,0x43,123 },/* 4A (122.61Mhz) */
+
+ { 0x2C,0x61,80 },/* 4B (80.350Mhz) */
+
+ { 0x3B,0x61,108 },/* 4C (107.385Mhz) */
+
+/*
+ { 0x60,0x36,30 },// 4D (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 4E (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 4F (30.200MHz) }// No use
+
+ { 0x60,0x36,30 },// 50 (30.200MHz) }// CHTV
+
+ { 0x40,0x4A,28 },// 51 (28.190MHz)
+
+ { 0x9F,0x46,44 },// 52 (43.600MHz)
+
+ { 0x97,0x2C,26 },// 53 (26.400MHz)
+
+ { 0x44,0xE4,25 },// 54 (24.600MHz)
+
+ { 0x7E,0x32,47 },// 55 (47.832MHz)
+
+ { 0x8A,0x24,31 },// 56 (31.500MHz)
+
+ { 0x97,0x2C,26 },// 57 (26.200MHz)
+
+ { 0xCE,0x3C,39 },// 58 (39.000MHz)
+
+ { 0x52,0x4A,36 },// 59 (36.000MHz)
+*/
+ { 0x69,0x61,191 }, /* 4D (190.96MHz ) */
+ { 0x4F,0x22,192 }, /* 4E (192.069MHz) */
+ { 0x28,0x26,322 }, /* 4F (322.273MHz) */
+ { 0x5C,0x6B,27 }, /* 50 (27.74HMz) */
+ { 0x57,0x24,126 }, /* 51 (125.999MHz) */
+ { 0x5C,0x42,148 }, /* 52 (148.5MHz) */
+ { 0x42,0x61,120 }, /* 53 (120.839MHz) */
+ { 0x62,0x61,178 }, /* 54 (178.992MHz) */
+ { 0x59,0x22,217 }, /* 55 (217.325MHz) */
+ { 0x29,0x01,300 }, /* 56 (299.505Mhz) */
+ { 0x52,0x63,74 }, /* 57 (74.25MHz) */
+
+
+ { 0xFF,0x00,0 } /* End mark */
+};
+
+UCHAR XGI660_TVDelayList[]=
+{
+ 0x44, /* ; 0 ExtNTSCDelay */
+ 0x44, /* ; 1 StNTSCDelay */
+ 0x44, /* ; 2 ExtPALDelay */
+ 0x44, /* ; 3 StPALDelay */
+ 0x44, /* ; 4 ExtHiTVDelay(1080i) */
+ 0x44, /* ; 5 StHiTVDelay(1080i) */
+ 0x44, /* ; 6 ExtYPbPrDelay(525i) */
+ 0x44, /* ; 7 StYPbPrDealy(525i) */
+ 0x44, /* ; 8 ExtYPbPrDelay(525p) */
+ 0x44, /* ; 9 StYPbPrDealy(525p) */
+ 0x44, /* ; A ExtYPbPrDelay(750p) */
+ 0x44 /* ; B StYPbPrDealy(750p) */
+};
+
+UCHAR XGI660_TVDelayList2[]=
+{
+ 0x44, /* ; 0 ExtNTSCDelay */
+ 0x44, /* ; 1 StNTSCDelay */
+ 0x44, /* ; 2 ExtPALDelay */
+ 0x44, /* ; 3 StPALDelay */
+ 0x44, /* ; 4 ExtHiTVDelay */
+ 0x44, /* ; 5 StHiTVDelay */
+ 0x44, /* ; 6 ExtYPbPrDelay(525i) */
+ 0x44, /* ; 7 StYPbPrDealy(525i) */
+ 0x44, /* ; 8 ExtYPbPrDelay(525p) */
+ 0x44, /* ; 9 StYPbPrDealy(525p) */
+ 0x44, /* ; A ExtYPbPrDelay(750p) */
+ 0x44 /* ; B StYPbPrDealy(750p) */
+};
+
+UCHAR XGI301TVDelayList[]=
+{
+ 0x22, /* ; 0 ExtNTSCDelay */
+ 0x22, /* ; 1 StNTSCDelay */
+ 0x22, /* ; 2 ExtPALDelay */
+ 0x22, /* ; 3 StPALDelay */
+ 0x88, /* ; 4 ExtHiTVDelay(1080i) */
+ 0xBB, /* ; 5 StHiTVDelay(1080i) */
+ 0x22, /* ; 6 ExtYPbPrDelay(525i) */
+ 0x22, /* ; 7 StYPbPrDealy(525i) */
+ 0x22, /* ; 8 ExtYPbPrDelay(525p) */
+ 0x22, /* ; 9 StYPbPrDealy(525p) */
+ 0x22, /* ; A ExtYPbPrDelay(750p) */
+ 0x22 /* B StYPbPrDealy(750p) */
+};
+
+UCHAR XGI301TVDelayList2[]=
+{
+ 0x22, /* ; 0 ExtNTSCDelay */
+ 0x22, /* ; 1 StNTSCDelay */
+ 0x22, /* ; 2 ExtPALDelay */
+ 0x22, /* ; 3 StPALDelay */
+ 0x22, /* ; 4 ExtHiTVDelay */
+ 0x22, /* ; 5 StHiTVDelay */
+ 0x22, /* ; 6 ExtYPbPrDelay(525i) */
+ 0x22, /* ; 7 StYPbPrDealy(525i) */
+ 0x22, /* ; 8 ExtYPbPrDelay(525p) */
+ 0x22, /* ; 9 StYPbPrDealy(525p) */
+ 0x22, /* ; A ExtYPbPrDelay(750p) */
+ 0x22 /* ; B StYPbPrDealy(750p) */
+};
+
+
+UCHAR TVAntiFlickList[]=
+{/* NTSCAntiFlicker */
+ 0x04, /* ; 0 Adaptive */
+ 0x00, /* ; 1 new anti-flicker ? */
+/* PALAntiFlicker */
+ 0x04, /* ; 0 Adaptive */
+ 0x08, /* ; 1 new anti-flicker ? */
+/* HiTVAntiFlicker */
+ 0x04, /* ; 0 ? */
+ 0x00 /* ; 1 new anti-flicker ? */
+};
+
+
+UCHAR TVEdgeList[]=
+{
+ 0x00, /* ; 0 NTSC No Edge enhance */
+ 0x04, /* ; 1 NTSC Adaptive Edge enhance */
+ 0x00, /* ; 0 PAL No Edge enhance */
+ 0x04, /* ; 1 PAL Adaptive Edge enhance */
+ 0x00, /* ; 0 HiTV */
+ 0x00 /* ; 1 HiTV */
+};
+
+ULONG TVPhaseList[]=
+{ 0x08BAED21, /* ; 0 NTSC phase */
+ 0x00E3052A, /* ; 1 PAL phase */
+ 0x9B2EE421, /* ; 2 PAL-M phase */
+ 0xBA3EF421, /* ; 3 PAL-N phase */
+ 0xA7A28B1E, /* ; 4 NTSC 1024x768 */
+ 0xE00A831E, /* ; 5 PAL-M 1024x768 */
+ 0x00000000, /* ; 6 reserved */
+ 0x00000000, /* ; 7 reserved */
+ 0xD67BF021, /* ; 8 NTSC phase */
+ 0xE986092A, /* ; 9 PAL phase */
+ 0xA4EFE621, /* ; A PAL-M phase */
+ 0x4694F621, /* ; B PAL-N phase */
+ 0x8BDE711C, /* ; C NTSC 1024x768 */
+ 0xE00A831E /* ; D PAL-M 1024x768 */
+};
+
+UCHAR NTSCYFilter1[]=
+{
+ 0x00,0xF4,0x10,0x38 ,/* 0 : 320x text mode */
+ 0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */
+ 0xEB,0x04,0x25,0x18 ,/* 2 : 640x text mode */
+ 0xF1,0x04,0x1F,0x18 ,/* 3 : 720x text mode */
+ 0x00,0xF4,0x10,0x38 ,/* 4 : 320x gra. mode */
+ 0xEB,0x04,0x25,0x18 ,/* 5 : 640x gra. mode */
+ 0xEB,0x15,0x25,0xF6 /* 6 : 800x gra. mode */
+};
+
+UCHAR PALYFilter1[]=
+{
+ 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
+ 0x00,0xF4,0x10,0x38 ,/* 1 : 360x text mode */
+ 0xF1,0xF7,0x1F,0x32 ,/* 2 : 640x text mode */
+ 0xF3,0x00,0x1D,0x20 ,/* 3 : 720x text mode */
+ 0x00,0xF4,0x10,0x38 ,/* 4 : 320x gra. mode */
+ 0xF1,0xF7,0x1F,0x32 ,/* 5 : 640x gra. mode */
+ 0xFC,0xFB,0x14,0x2A /* 6 : 800x gra. mode */
+};
+
+UCHAR PALMYFilter1[]=
+{
+ 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
+ 0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */
+ 0xEB,0x04,0x10,0x18, /* 2 : 640x text mode */
+ 0xF7,0x06,0x19,0x14, /* 3 : 720x text mode */
+ 0x00,0xF4,0x10,0x38, /* 4 : 320x gra. mode */
+ 0xEB,0x04,0x25,0x18, /* 5 : 640x gra. mode */
+ 0xEB,0x15,0x25,0xF6, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFF,0xFF /* End of Table */
+};
+
+UCHAR PALNYFilter1[]=
+{
+ 0x00,0xF4,0x10,0x38, /* 0 : 320x text mode */
+ 0x00,0xF4,0x10,0x38, /* 1 : 360x text mode */
+ 0xEB,0x04,0x10,0x18, /* 2 : 640x text mode */
+ 0xF7,0x06,0x19,0x14, /* 3 : 720x text mode */
+ 0x00,0xF4,0x10,0x38, /* 4 : 320x gra. mode */
+ 0xEB,0x04,0x25,0x18, /* 5 : 640x gra. mode */
+ 0xEB,0x15,0x25,0xF6, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFF,0xFF /* End of Table */
+};
+
+UCHAR NTSCYFilter2[]=
+{
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */
+ 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
+};
+
+UCHAR PALYFilter2[]=
+{
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */
+ 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
+};
+
+UCHAR PALMYFilter2[]=
+{
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */
+ 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
+};
+
+UCHAR PALNYFilter2[]=
+{
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 0 : 320x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 1 : 360x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 2 : 640x text mode */
+ 0x01,0x02,0xFE,0xF7,0x03,0x27,0x3C, /* 3 : 720x text mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 4 : 320x gra. mode */
+ 0xFF,0x03,0x02,0xF6,0xFC,0x27,0x46, /* 5 : 640x gra. mode */
+ 0x01,0x01,0xFC,0xF8,0x08,0x26,0x38, /* 6 : 800x gra. mode */
+ 0xFF,0xFF,0xFC,0x00,0x0F,0x22,0x28 /* 7 : 1024xgra. mode */
+};
+
+UCHAR XGI_NTSC1024AdjTime[]=
+{
+ 0xa7,0x07,0xf2,0x6e,0x17,0x8b,0x73,0x53,
+ 0x13,0x40,0x34,0xF4,0x63,0xBB,0xCC,0x7A,
+ 0x58,0xe4,0x73,0xd0,0x13
+};
+
+XGI301C_Tap4TimingStruct HiTVTap4Timing[]=
+{
+ {0,{
+ 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
+ 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */
+ 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */
+ 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */
+ 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */
+ 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */
+ 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */
+ 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct EnlargeTap4Timing[]=
+{
+ {0,{
+ 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
+ 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */
+ 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */
+ 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */
+ 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */
+ 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */
+ 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */
+ 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct NoScaleTap4Timing[]=
+{
+ {0,{
+ 0x00,0x20,0x00,0x00,0x7F,0x20,0x02,0x7F, /* ; C0-C7 */
+ 0x7D,0x20,0x04,0x7F,0x7D,0x1F,0x06,0x7E, /* ; C8-CF */
+ 0x7C,0x1D,0x09,0x7E,0x7C,0x1B,0x0B,0x7E, /* ; D0-D7 */
+ 0x7C,0x19,0x0E,0x7D,0x7C,0x17,0x11,0x7C, /* ; D8-DF */
+ 0x7C,0x14,0x14,0x7C,0x7C,0x11,0x17,0x7C, /* ; E0-E7 */
+ 0x7D,0x0E,0x19,0x7C,0x7E,0x0B,0x1B,0x7C, /* ; EA-EF */
+ 0x7E,0x09,0x1D,0x7C,0x7F,0x06,0x1F,0x7C, /* ; F0-F7 */
+ 0x7F,0x04,0x20,0x7D,0x00,0x02,0x20,0x7E /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct PALTap4Timing[]=
+{
+ {600, {
+ 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */
+ 0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, /* ; C8-CF */
+ 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C, /* ; D0-D7 */
+ 0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, /* ; D8-DF */
+ 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E, /* ; E0-E7 */
+ 0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, /* ; EA-EF */
+ 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01, /* ; F0-F7 */
+ 0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04 /* ; F8-FF */
+ }
+ },
+ {768, {
+ 0x08,0x12,0x08,0x7E,0x07,0x12,0x09,0x7E, /* ; C0-C7 */
+ 0x06,0x12,0x0A,0x7E,0x05,0x11,0x0B,0x7F, /* ; C8-CF */
+ 0x04,0x11,0x0C,0x7F,0x03,0x11,0x0C,0x00, /* ; D0-D7 */
+ 0x03,0x10,0x0D,0x00,0x02,0x0F,0x0E,0x01, /* ; D8-DF */
+ 0x01,0x0F,0x0F,0x01,0x01,0x0E,0x0F,0x02, /* ; E0-E7 */
+ 0x00,0x0D,0x10,0x03,0x7F,0x0C,0x11,0x04, /* ; EA-EF */
+ 0x7F,0x0C,0x11,0x04,0x7F,0x0B,0x11,0x05, /* ; F0-F7 */
+ 0x7E,0x0A,0x12,0x06,0x7E,0x09,0x12,0x07 /* ; F8-FF */
+ }
+ },
+ {0xFFFF,
+ {
+ 0x04,0x1A,0x04,0x7E,0x02,0x1B,0x05,0x7E, /* ; C0-C7 */
+ 0x01,0x1A,0x07,0x7E,0x00,0x1A,0x09,0x7D, /* ; C8-CF */
+ 0x7F,0x19,0x0B,0x7D,0x7E,0x18,0x0D,0x7D, /* ; D0-D7 */
+ 0x7D,0x17,0x10,0x7C,0x7D,0x15,0x12,0x7C, /* ; D8-DF */
+ 0x7C,0x14,0x14,0x7C,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */
+ 0x7C,0x10,0x17,0x7D,0x7C,0x0D,0x18,0x7F, /* ; EA-EF */
+ 0x7D,0x0B,0x19,0x7F,0x7D,0x09,0x1A,0x00, /* ; F0-F7 */
+ 0x7D,0x07,0x1A,0x02,0x7E,0x05,0x1B,0x02 /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct NTSCTap4Timing[]=
+{
+ {480, {
+ 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
+ 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */
+ 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */
+ 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */
+ 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */
+ 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */
+ 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */
+ 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */
+ }
+ },
+ {600, {
+ 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */
+ 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */
+ 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */
+ 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */
+ 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */
+ 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */
+ 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */
+ 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */
+ }
+ },
+ {0xFFFF,
+ {
+ 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */
+ 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */
+ 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */
+ 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */
+ 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */
+ 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */
+ 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */
+ 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct YPbPr525pTap4Timing[]=
+{
+ {480, {
+ 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
+ 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */
+ 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */
+ 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */
+ 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */
+ 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */
+ 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */
+ 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */
+ }
+ },
+ {600, {
+ 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */
+ 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */
+ 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */
+ 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */
+ 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */
+ 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */
+ 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */
+ 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */
+ }
+ },
+ {0xFFFF,
+ {
+ 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */
+ 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */
+ 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */
+ 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */
+ 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */
+ 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */
+ 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */
+ 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct YPbPr525iTap4Timing[]=
+{
+ {480, {
+ 0x04,0x1A,0x04,0x7E,0x03,0x1A,0x06,0x7D, /* ; C0-C7 */
+ 0x01,0x1A,0x08,0x7D,0x00,0x19,0x0A,0x7D, /* ; C8-CF */
+ 0x7F,0x19,0x0C,0x7C,0x7E,0x18,0x0E,0x7C, /* ; D0-D7 */
+ 0x7E,0x17,0x10,0x7B,0x7D,0x15,0x12,0x7C, /* ; D8-DF */
+ 0x7D,0x13,0x13,0x7D,0x7C,0x12,0x15,0x7D, /* ; E0-E7 */
+ 0x7C,0x10,0x17,0x7D,0x7C,0x0E,0x18,0x7E, /* ; EA-EF */
+ 0x7D,0x0C,0x19,0x7E,0x7D,0x0A,0x19,0x00, /* ; F0-F7 */
+ 0x7D,0x08,0x1A,0x01,0x7E,0x06,0x1A,0x02 /* ; F8-FF */
+ }
+ },
+ {600, {
+ 0x07,0x14,0x07,0x7E,0x06,0x14,0x09,0x7D, /* ; C0-C7 */
+ 0x05,0x14,0x0A,0x7D,0x04,0x13,0x0B,0x7E, /* ; C8-CF */
+ 0x03,0x13,0x0C,0x7E,0x02,0x12,0x0D,0x7F, /* ; D0-D7 */
+ 0x01,0x12,0x0E,0x7F,0x01,0x11,0x0F,0x7F, /* ; D8-DF */
+ 0x01,0x10,0x10,0x00,0x7F,0x0F,0x11,0x01, /* ; E0-E7 */
+ 0x7F,0x0E,0x12,0x01,0x7E,0x0D,0x12,0x03, /* ; EA-EF */
+ 0x7E,0x0C,0x13,0x03,0x7E,0x0B,0x13,0x04, /* ; F0-F7 */
+ 0x7E,0x0A,0x14,0x04,0x7D,0x09,0x14,0x06 /* ; F8-FF */
+ }
+ },
+ {0xFFFF,
+ {
+ 0x09,0x0F,0x09,0x7F,0x08,0x0F,0x09,0x00, /* ; C0-C7 */
+ 0x07,0x0F,0x0A,0x00,0x06,0x0F,0x0A,0x01, /* ; C8-CF */
+ 0x06,0x0E,0x0B,0x01,0x05,0x0E,0x0B,0x02, /* ; D0-D7 */
+ 0x04,0x0E,0x0C,0x02,0x04,0x0D,0x0C,0x03, /* ; D8-DF */
+ 0x03,0x0D,0x0D,0x03,0x02,0x0C,0x0D,0x05, /* ; E0-E7 */
+ 0x02,0x0C,0x0E,0x04,0x01,0x0B,0x0E,0x06, /* ; EA-EF */
+ 0x01,0x0B,0x0E,0x06,0x00,0x0A,0x0F,0x07, /* ; F0-F7 */
+ 0x00,0x0A,0x0F,0x07,0x00,0x09,0x0F,0x08 /* ; F8-FF */
+ }
+ }
+};
+
+XGI301C_Tap4TimingStruct YPbPr750pTap4Timing[]=
+{ {0xFFFF,
+ {
+ 0x05,0x19,0x05,0x7D,0x03,0x19,0x06,0x7E, /* ; C0-C7 */
+ 0x02,0x19,0x08,0x7D,0x01,0x18,0x0A,0x7D, /* ; C8-CF */
+ 0x00,0x18,0x0C,0x7C,0x7F,0x17,0x0E,0x7C, /* ; D0-D7 */
+ 0x7E,0x16,0x0F,0x7D,0x7E,0x14,0x11,0x7D, /* ; D8-DF */
+ 0x7D,0x13,0x13,0x7D,0x7D,0x11,0x14,0x7E, /* ; E0-E7 */
+ 0x7D,0x0F,0x16,0x7E,0x7D,0x0E,0x17,0x7E, /* ; EA-EF */
+ 0x7D,0x0C,0x18,0x7F,0x7D,0x0A,0x18,0x01, /* ; F0-F7 */
+ 0x7D,0x08,0x19,0x02,0x7D,0x06,0x19,0x04 /* F8-FF */
+ }
+ }
+};
diff --git a/drivers/staging/xgifb/vb_util.c b/drivers/staging/xgifb/vb_util.c
new file mode 100644
index 000000000000..87531b49b739
--- /dev/null
+++ b/drivers/staging/xgifb/vb_util.c
@@ -0,0 +1,263 @@
+#include "osdef.h"
+#include "vb_def.h"
+#include "vgatypes.h"
+#include "vb_struct.h"
+
+#ifdef LINUX_KERNEL
+#include "XGIfb.h"
+#include <asm/io.h>
+#include <linux/types.h>
+#endif
+
+#ifdef TC
+#include <stdio.h>
+#include <string.h>
+#include <conio.h>
+#include <dos.h>
+#endif
+
+#ifdef WIN2000
+#include <dderror.h>
+#include <devioctl.h>
+#include <miniport.h>
+#include <ntddvdeo.h>
+#include <video.h>
+
+#include "xgiv.h"
+#include "dd_i2c.h"
+#include "tools.h"
+#endif
+
+#ifdef LINUX_XF86
+#include "xf86.h"
+#include "xf86PciInfo.h"
+#include "xgi.h"
+#include "xgi_regs.h"
+#endif
+
+
+
+
+void XGINew_SetReg1( ULONG , USHORT , USHORT ) ;
+void XGINew_SetReg2( ULONG , USHORT , USHORT ) ;
+void XGINew_SetReg3( ULONG , USHORT ) ;
+void XGINew_SetReg4( ULONG , ULONG ) ;
+UCHAR XGINew_GetReg1( ULONG , USHORT) ;
+UCHAR XGINew_GetReg2( ULONG ) ;
+ULONG XGINew_GetReg3( ULONG ) ;
+void XGINew_ClearDAC( PUCHAR ) ;
+void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR);
+void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR);
+void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND);
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetReg1 */
+/* Input : */
+/* Output : */
+/* Description : SR CRTC GR */
+/* --------------------------------------------------------------------- */
+void XGINew_SetReg1( ULONG port , USHORT index , USHORT data )
+{
+#ifdef LINUX_XF86
+ OutPortByte( ( PUCHAR )(ULONG)port , index ) ;
+ OutPortByte( ( PUCHAR )(ULONG)port + 1 , data ) ;
+#else
+ OutPortByte( port , index ) ;
+ OutPortByte( port + 1 , data ) ;
+#endif
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetReg2 */
+/* Input : */
+/* Output : */
+/* Description : AR( 3C0 ) */
+/* --------------------------------------------------------------------- */
+/*void XGINew_SetReg2( ULONG port , USHORT index , USHORT data )
+{
+ InPortByte( ( PUCHAR )port + 0x3da - 0x3c0 ) ;
+ OutPortByte( XGINew_P3c0 , index ) ;
+ OutPortByte( XGINew_P3c0 , data ) ;
+ OutPortByte( XGINew_P3c0 , 0x20 ) ;
+}*/
+
+
+/* --------------------------------------------------------------------- */
+/* Function : */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetReg3( ULONG port , USHORT data )
+{
+ OutPortByte( port , data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetReg4 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetReg4( ULONG port , ULONG data )
+{
+ OutPortLong( port , data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_GetReg1 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGINew_GetReg1( ULONG port , USHORT index )
+{
+ UCHAR data ;
+
+#ifdef LINUX_XF86
+ OutPortByte( ( PUCHAR )(ULONG)port , index ) ;
+ data = InPortByte( ( PUCHAR )(ULONG)port + 1 ) ;
+#else
+ OutPortByte( port , index ) ;
+ data = InPortByte( port + 1 ) ;
+#endif
+
+ return( data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_GetReg2 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+UCHAR XGINew_GetReg2( ULONG port )
+{
+ UCHAR data ;
+
+ data = InPortByte( port ) ;
+
+ return( data ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_GetReg3 */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+ULONG XGINew_GetReg3( ULONG port )
+{
+ ULONG data ;
+
+ data = InPortLong( port ) ;
+
+ return( data ) ;
+}
+
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetRegANDOR */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetRegANDOR( ULONG Port , USHORT Index , USHORT DataAND , USHORT DataOR )
+{
+ USHORT temp ;
+
+ temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
+ temp = ( temp & ( DataAND ) ) | DataOR ;
+ XGINew_SetReg1( Port , Index , temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetRegAND */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND)
+{
+ USHORT temp ;
+
+ temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
+ temp &= DataAND ;
+ XGINew_SetReg1( Port , Index , temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : XGINew_SetRegOR */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void XGINew_SetRegOR( ULONG Port , USHORT Index , USHORT DataOR )
+{
+ USHORT temp ;
+
+ temp = XGINew_GetReg1( Port , Index ) ; /* XGINew_Part1Port index 02 */
+ temp |= DataOR ;
+ XGINew_SetReg1( Port , Index , temp ) ;
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : NewDelaySecond */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void NewDelaySeconds( int seconds )
+{
+#ifdef WIN2000
+ int j ;
+#endif
+ int i ;
+
+
+ for( i = 0 ; i < seconds ; i++ )
+ {
+#ifdef TC
+ delay( 1000 ) ;
+#endif
+
+#ifdef WIN2000
+
+ for ( j = 0 ; j < 20000 ; j++ )
+ VideoPortStallExecution( 50 ) ;
+#endif
+
+#ifdef WINCE_HEADER
+#endif
+
+#ifdef LINUX_KERNEL
+#endif
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+/* Function : Newdebugcode */
+/* Input : */
+/* Output : */
+/* Description : */
+/* --------------------------------------------------------------------- */
+void Newdebugcode( UCHAR code )
+{
+// OutPortByte ( 0x80 , code ) ;
+ /* OutPortByte ( 0x300 , code ) ; */
+ /* NewDelaySeconds( 0x3 ) ; */
+}
+
+
+
diff --git a/drivers/staging/xgifb/vb_util.h b/drivers/staging/xgifb/vb_util.h
new file mode 100644
index 000000000000..91779d8cfdc6
--- /dev/null
+++ b/drivers/staging/xgifb/vb_util.h
@@ -0,0 +1,15 @@
+#ifndef _VBUTIL_
+#define _VBUTIL_
+extern void NewDelaySeconds( int );
+extern void Newdebugcode( UCHAR );
+extern void XGINew_SetReg1(ULONG, USHORT, USHORT);
+extern void XGINew_SetReg3(ULONG, USHORT);
+extern UCHAR XGINew_GetReg1(ULONG, USHORT);
+extern UCHAR XGINew_GetReg2(ULONG);
+extern void XGINew_SetReg4(ULONG, ULONG);
+extern ULONG XGINew_GetReg3(ULONG);
+extern void XGINew_SetRegOR(ULONG Port,USHORT Index,USHORT DataOR);
+extern void XGINew_SetRegAND(ULONG Port,USHORT Index,USHORT DataAND);
+extern void XGINew_SetRegANDOR(ULONG Port,USHORT Index,USHORT DataAND,USHORT DataOR);
+#endif
+
diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h
new file mode 100644
index 000000000000..295ea860ae47
--- /dev/null
+++ b/drivers/staging/xgifb/vgatypes.h
@@ -0,0 +1,325 @@
+
+#ifndef _VGATYPES_
+#define _VGATYPES_
+
+#include "osdef.h"
+
+#ifdef LINUX_XF86
+#include "xf86Version.h"
+#include "xf86Pci.h"
+#endif
+
+#ifdef LINUX_KERNEL /* We don't want the X driver to depend on kernel source */
+#include <linux/ioctl.h>
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CHAR
+typedef char CHAR;
+#endif
+
+#ifndef SHORT
+typedef short SHORT;
+#endif
+
+#ifndef LONG
+typedef long LONG;
+#endif
+
+#ifndef UCHAR
+typedef unsigned char UCHAR;
+#endif
+
+#ifndef USHORT
+typedef unsigned short USHORT;
+#endif
+
+#ifndef ULONG
+typedef unsigned long ULONG;
+#endif
+
+#ifndef PUCHAR
+typedef UCHAR *PUCHAR;
+#endif
+
+#ifndef PUSHORT
+typedef USHORT *PUSHORT;
+#endif
+
+#ifndef PLONGU
+typedef ULONG *PULONG;
+#endif
+
+#ifndef VOID
+typedef void VOID;
+#endif
+
+#ifndef PVOID
+typedef void *PVOID;
+#endif
+
+#ifndef BOOLEAN
+typedef UCHAR BOOLEAN;
+#endif
+/*
+#ifndef bool
+typedef UCHAR bool;
+#endif
+*/
+#ifdef LINUX_KERNEL
+typedef unsigned long XGIIOADDRESS;
+#endif
+
+#ifdef LINUX_XF86
+#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
+typedef unsigned char IOADDRESS;
+typedef unsigned char XGIIOADDRESS;
+#else
+typedef IOADDRESS XGIIOADDRESS;
+#endif
+#endif
+
+#ifndef VBIOS_VER_MAX_LENGTH
+#define VBIOS_VER_MAX_LENGTH 4
+#endif
+
+#ifndef WIN2000
+
+#ifndef LINUX_KERNEL /* For the linux kernel, this is defined in xgifb.h */
+#ifndef XGI_CHIP_TYPE
+typedef enum _XGI_CHIP_TYPE {
+ XGI_VGALegacy = 0,
+#ifdef LINUX_XF86
+ XGI_530,
+ XGI_OLD,
+#endif
+ XGI_300,
+ XGI_630,
+ XGI_640,
+ XGI_315H,
+ XGI_315,
+ XGI_315PRO,
+ XGI_550,
+ XGI_650,
+ XGI_650M,
+ XGI_740,
+ XGI_330,
+ XGI_661,
+ XGI_660,
+ XGI_760,
+ XG40 = 32,
+ XG41,
+ XG42,
+ XG45,
+ XG20 = 48,
+ XG21,
+ XG27,
+ MAX_XGI_CHIP
+} XGI_CHIP_TYPE;
+#endif
+#endif
+
+#ifndef XGI_VB_CHIP_TYPE
+typedef enum _XGI_VB_CHIP_TYPE {
+ VB_CHIP_Legacy = 0,
+ VB_CHIP_301,
+ VB_CHIP_301B,
+ VB_CHIP_301LV,
+ VB_CHIP_302,
+ VB_CHIP_302B,
+ VB_CHIP_302LV,
+ VB_CHIP_301C,
+ VB_CHIP_302ELV,
+ VB_CHIP_UNKNOWN, /* other video bridge or no video bridge */
+ MAX_VB_CHIP
+} XGI_VB_CHIP_TYPE;
+#endif
+
+#ifndef XGI_LCD_TYPE
+typedef enum _XGI_LCD_TYPE {
+ LCD_INVALID = 0,
+ LCD_320x480, /* FSTN, DSTN */
+ LCD_640x480,
+ LCD_640x480_2, /* FSTN, DSTN */
+ LCD_640x480_3, /* FSTN, DSTN */
+ LCD_800x600,
+ LCD_848x480,
+ LCD_1024x600,
+ LCD_1024x768,
+ LCD_1152x768,
+ LCD_1152x864,
+ LCD_1280x720,
+ LCD_1280x768,
+ LCD_1280x800,
+ LCD_1280x960,
+ LCD_1280x1024,
+ LCD_1400x1050,
+ LCD_1600x1200,
+ LCD_1680x1050,
+ LCD_1920x1440,
+ LCD_2048x1536,
+ LCD_CUSTOM,
+ LCD_UNKNOWN
+} XGI_LCD_TYPE;
+#endif
+
+#endif /* not WIN2000 */
+
+#ifndef PXGI_DSReg
+typedef struct _XGI_DSReg
+{
+ UCHAR jIdx;
+ UCHAR jVal;
+} XGI_DSReg, *PXGI_DSReg;
+#endif
+
+#ifndef XGI_HW_DEVICE_INFO
+
+typedef struct _XGI_HW_DEVICE_INFO XGI_HW_DEVICE_INFO, *PXGI_HW_DEVICE_INFO;
+
+typedef BOOLEAN (*PXGI_QUERYSPACE) (PXGI_HW_DEVICE_INFO, ULONG, ULONG, ULONG *);
+
+struct _XGI_HW_DEVICE_INFO
+{
+ ULONG ulExternalChip; /* NO VB or other video bridge*/
+ /* if ujVBChipID = VB_CHIP_UNKNOWN, */
+#ifdef LINUX_XF86
+ PCITAG PciTag; /* PCI Tag */
+#endif
+
+ PUCHAR pjVirtualRomBase; /* ROM image */
+
+ BOOLEAN UseROM; /* Use the ROM image if provided */
+
+ PVOID pDevice;
+
+ PUCHAR pjVideoMemoryAddress;/* base virtual memory address */
+ /* of Linear VGA memory */
+
+ ULONG ulVideoMemorySize; /* size, in bytes, of the memory on the board */
+
+ PUCHAR pjIOAddress; /* base I/O address of VGA ports (0x3B0) */
+
+ PUCHAR pjCustomizedROMImage;
+
+ PUCHAR pj2ndVideoMemoryAddress;
+ ULONG ul2ndVideoMemorySize;
+
+ PUCHAR pj2ndIOAddress;
+/*#ifndef WIN2000
+ XGIIOADDRESS pjIOAddress; // base I/O address of VGA ports (0x3B0)
+#endif */
+ UCHAR jChipType; /* Used to Identify Graphics Chip */
+ /* defined in the data structure type */
+ /* "XGI_CHIP_TYPE" */
+
+ UCHAR jChipRevision; /* Used to Identify Graphics Chip Revision */
+
+ UCHAR ujVBChipID; /* the ID of video bridge */
+ /* defined in the data structure type */
+ /* "XGI_VB_CHIP_TYPE" */
+
+ BOOLEAN bNewScratch;
+
+ ULONG ulCRT2LCDType; /* defined in the data structure type */
+
+ ULONG usExternalChip; /* NO VB or other video bridge (other than */
+ /* video bridge) */
+
+ BOOLEAN bIntegratedMMEnabled;/* supporting integration MM enable */
+
+ BOOLEAN bSkipDramSizing; /* True: Skip video memory sizing. */
+
+ BOOLEAN bSkipSense;
+
+ BOOLEAN bIsPowerSaving; /* True: XGIInit() is invoked by power management,
+ otherwise by 2nd adapter's initialzation */
+
+ PXGI_DSReg pSR; /* restore SR registers in initial function. */
+ /* end data :(idx, val) = (FF, FF). */
+ /* Note : restore SR registers if */
+ /* bSkipDramSizing = TRUE */
+
+ PXGI_DSReg pCR; /* restore CR registers in initial function. */
+ /* end data :(idx, val) = (FF, FF) */
+ /* Note : restore cR registers if */
+ /* bSkipDramSizing = TRUE */
+/*
+#endif
+*/
+
+ PXGI_QUERYSPACE pQueryVGAConfigSpace;
+
+ PXGI_QUERYSPACE pQueryNorthBridgeSpace;
+
+ UCHAR szVBIOSVer[VBIOS_VER_MAX_LENGTH];
+
+};
+#endif
+
+/* Addtional IOCTL for communication xgifb <> X driver */
+/* If changing this, xgifb.h must also be changed (for xgifb) */
+
+#ifdef LINUX_XF86 /* We don't want the X driver to depend on the kernel source */
+
+/* ioctl for identifying and giving some info (esp. memory heap start) */
+#define XGIFB_GET_INFO 0x80046ef8 /* Wow, what a terrible hack... */
+
+/* Structure argument for XGIFB_GET_INFO ioctl */
+typedef struct _XGIFB_INFO xgifb_info, *pxgifb_info;
+
+struct _XGIFB_INFO {
+ CARD32 xgifb_id; /* for identifying xgifb */
+#ifndef XGIFB_ID
+#define XGIFB_ID 0x53495346 /* Identify myself with 'XGIF' */
+#endif
+ CARD32 chip_id; /* PCI ID of detected chip */
+ CARD32 memory; /* video memory in KB which xgifb manages */
+ CARD32 heapstart; /* heap start (= xgifb "mem" argument) in KB */
+ CARD8 fbvidmode; /* current xgifb mode */
+
+ CARD8 xgifb_version;
+ CARD8 xgifb_revision;
+ CARD8 xgifb_patchlevel;
+
+ CARD8 xgifb_caps; /* xgifb's capabilities */
+
+ CARD32 xgifb_tqlen; /* turbo queue length (in KB) */
+
+ CARD32 xgifb_pcibus; /* The card's PCI ID */
+ CARD32 xgifb_pcislot;
+ CARD32 xgifb_pcifunc;
+
+ CARD8 xgifb_lcdpdc;
+
+ CARD8 xgifb_lcda;
+
+ CARD32 xgifb_vbflags;
+ CARD32 xgifb_currentvbflags;
+
+ CARD32 xgifb_scalelcd;
+ CARD32 xgifb_specialtiming;
+
+ CARD8 xgifb_haveemi;
+ CARD8 xgifb_emi30,xgifb_emi31,xgifb_emi32,xgifb_emi33;
+ CARD8 xgifb_haveemilcd;
+
+ CARD8 xgifb_lcdpdca;
+
+ CARD8 reserved[212]; /* for future use */
+};
+#endif
+
+#endif
+
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index e213d3fa4920..3133217541e7 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1569,6 +1569,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
char file_arr[] = "CMVxy.bin";
char *file;
+ kparam_block_sysfs_write(cmv_file);
/* set proper name corresponding modem version and line type */
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
@@ -1587,6 +1588,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
strlcat(cmv_name, file, UEA_FW_NAME_MAX);
if (ver == 2)
strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX);
+ kparam_unblock_sysfs_write(cmv_file);
}
static int request_cmvs_old(struct uea_softc *sc,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 0c2f14ff9696..61d75507d5d0 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1201,7 +1201,7 @@ made_compressed_probe:
if (rcv->urb == NULL) {
dev_dbg(&intf->dev,
"out of memory (read urbs usb_alloc_urb)\n");
- goto alloc_fail7;
+ goto alloc_fail6;
}
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -1225,7 +1225,7 @@ made_compressed_probe:
if (snd->urb == NULL) {
dev_dbg(&intf->dev,
"out of memory (write urbs usb_alloc_urb)");
- goto alloc_fail7;
+ goto alloc_fail8;
}
if (usb_endpoint_xfer_int(epwrite))
@@ -1264,6 +1264,7 @@ made_compressed_probe:
i = device_create_file(&intf->dev,
&dev_attr_iCountryCodeRelDate);
if (i < 0) {
+ device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
kfree(acm->country_codes);
goto skip_countries;
}
@@ -1300,6 +1301,7 @@ alloc_fail8:
usb_free_urb(acm->wb[i].urb);
alloc_fail7:
acm_read_buffers_free(acm);
+alloc_fail6:
for (i = 0; i < num_rx_buf; i++)
usb_free_urb(acm->ru[i].urb);
usb_free_urb(acm->ctrlurb);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index ded550eda5d9..de98a94d1853 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1328,6 +1328,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
/* For all other calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously.
+ * Unbind the interfaces that will need rebinding later.
*/
} else {
status = usb_resume_both(udev, msg);
@@ -1336,6 +1337,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
udev->last_busy = jiffies;
+ do_unbind_rebind(udev, DO_REBIND);
}
}
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 649c0c5f7158..591ae9fde199 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -295,6 +295,7 @@ config USB_GADGET_S3C_HSOTG
boolean "S3C HS/OtG USB Device controller"
depends on S3C_DEV_USB_HSOTG
select USB_GADGET_S3C_HSOTG_PIO
+ select USB_GADGET_DUALSPEED
help
The Samsung S3C64XX USB2.0 high-speed gadget controller
integrated into the S3C64XX series SoC.
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c
index 43bf44514c41..b91115f84b13 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_audio.c
@@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
static struct usb_audio_control mute_control = {
.list = LIST_HEAD_INIT(mute_control.list),
.name = "Mute Control",
- .type = UAC_MUTE_CONTROL,
+ .type = UAC_FU_MUTE,
/* Todo: add real Mute control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
@@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = {
static struct usb_audio_control volume_control = {
.list = LIST_HEAD_INIT(volume_control.list),
.name = "Volume Control",
- .type = UAC_VOLUME_CONTROL,
+ .type = UAC_FU_VOLUME,
/* Todo: add real Volume control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index 2928523268b5..82506ca297d5 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2400,7 +2400,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev)
{
struct qe_udc *udc;
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
unsigned int tmp_addr = 0;
struct usb_device_para __iomem *usbpram;
unsigned int i;
@@ -2525,7 +2525,7 @@ static void qe_udc_release(struct device *dev)
static int __devinit qe_udc_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct qe_ep *ep;
unsigned int ret = 0;
unsigned int i;
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h
index 8b960deed680..c3caf1ac73ce 100644
--- a/drivers/usb/gadget/m66592-udc.h
+++ b/drivers/usb/gadget/m66592-udc.h
@@ -537,35 +537,35 @@ struct m66592 {
/*-------------------------------------------------------------------------*/
static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
{
- return inw((unsigned long)m66592->reg + offset);
+ return ioread16(m66592->reg + offset);
}
static inline void m66592_read_fifo(struct m66592 *m66592,
unsigned long offset,
void *buf, unsigned long len)
{
- unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+ void __iomem *fifoaddr = m66592->reg + offset;
if (m66592->pdata->on_chip) {
len = (len + 3) / 4;
- insl(fifoaddr, buf, len);
+ ioread32_rep(fifoaddr, buf, len);
} else {
len = (len + 1) / 2;
- insw(fifoaddr, buf, len);
+ ioread16_rep(fifoaddr, buf, len);
}
}
static inline void m66592_write(struct m66592 *m66592, u16 val,
unsigned long offset)
{
- outw(val, (unsigned long)m66592->reg + offset);
+ iowrite16(val, m66592->reg + offset);
}
static inline void m66592_write_fifo(struct m66592 *m66592,
unsigned long offset,
void *buf, unsigned long len)
{
- unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+ void __iomem *fifoaddr = m66592->reg + offset;
if (m66592->pdata->on_chip) {
unsigned long count;
@@ -573,25 +573,25 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
int i;
count = len / 4;
- outsl(fifoaddr, buf, count);
+ iowrite32_rep(fifoaddr, buf, count);
if (len & 0x00000003) {
pb = buf + count * 4;
for (i = 0; i < (len & 0x00000003); i++) {
if (m66592_read(m66592, M66592_CFBCFG)) /* le */
- outb(pb[i], fifoaddr + (3 - i));
+ iowrite8(pb[i], fifoaddr + (3 - i));
else
- outb(pb[i], fifoaddr + i);
+ iowrite8(pb[i], fifoaddr + i);
}
}
} else {
unsigned long odd = len & 0x0001;
len = len / 2;
- outsw(fifoaddr, buf, len);
+ iowrite16_rep(fifoaddr, buf, len);
if (odd) {
unsigned char *p = buf + len*2;
- outb(*p, fifoaddr);
+ iowrite8(*p, fifoaddr);
}
}
}
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index 888d8f166c0b..70a817842755 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1500,7 +1500,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev)
struct r8a66597 *r8a66597 = dev_get_drvdata(&pdev->dev);
del_timer_sync(&r8a66597->timer);
- iounmap((void *)r8a66597->reg);
+ iounmap(r8a66597->reg);
free_irq(platform_get_irq(pdev, 0), r8a66597);
r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
#ifdef CONFIG_HAVE_CLK
@@ -1578,7 +1578,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
init_timer(&r8a66597->timer);
r8a66597->timer.function = r8a66597_timer;
r8a66597->timer.data = (unsigned long)r8a66597;
- r8a66597->reg = (unsigned long)reg;
+ r8a66597->reg = reg;
#ifdef CONFIG_HAVE_CLK
if (r8a66597->pdata->on_chip) {
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 9a537aa07968..f763b5190afa 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -91,7 +91,7 @@ struct r8a66597_ep {
struct r8a66597 {
spinlock_t lock;
- unsigned long reg;
+ void __iomem *reg;
#ifdef CONFIG_HAVE_CLK
struct clk *clk;
@@ -127,7 +127,7 @@ struct r8a66597 {
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
- return inw(r8a66597->reg + offset);
+ return ioread16(r8a66597->reg + offset);
}
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
@@ -135,7 +135,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned char *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
unsigned int data;
int i;
@@ -144,7 +144,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
/* aligned buf case */
if (len >= 4 && !((unsigned long)buf & 0x03)) {
- insl(fifoaddr, buf, len / 4);
+ ioread32_rep(fifoaddr, buf, len / 4);
buf += len & ~0x03;
len &= 0x03;
}
@@ -152,7 +152,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
/* unaligned buf case */
for (i = 0; i < len; i++) {
if (!(i & 0x03))
- data = inl(fifoaddr);
+ data = ioread32(fifoaddr);
buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
}
@@ -161,7 +161,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
/* aligned buf case */
if (len >= 2 && !((unsigned long)buf & 0x01)) {
- insw(fifoaddr, buf, len / 2);
+ ioread16_rep(fifoaddr, buf, len / 2);
buf += len & ~0x01;
len &= 0x01;
}
@@ -169,7 +169,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
/* unaligned buf case */
for (i = 0; i < len; i++) {
if (!(i & 0x01))
- data = inw(fifoaddr);
+ data = ioread16(fifoaddr);
buf[i] = (data >> ((i & 0x01) * 8)) & 0xff;
}
@@ -179,7 +179,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
unsigned long offset)
{
- outw(val, r8a66597->reg + offset);
+ iowrite16(val, r8a66597->reg + offset);
}
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
@@ -187,21 +187,21 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
unsigned char *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
int adj = 0;
int i;
if (r8a66597->pdata->on_chip) {
/* 32-bit access only if buf is 32-bit aligned */
if (len >= 4 && !((unsigned long)buf & 0x03)) {
- outsl(fifoaddr, buf, len / 4);
+ iowrite32_rep(fifoaddr, buf, len / 4);
buf += len & ~0x03;
len &= 0x03;
}
} else {
/* 16-bit access only if buf is 16-bit aligned */
if (len >= 2 && !((unsigned long)buf & 0x01)) {
- outsw(fifoaddr, buf, len / 2);
+ iowrite16_rep(fifoaddr, buf, len / 2);
buf += len & ~0x01;
len &= 0x01;
}
@@ -216,7 +216,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
}
for (i = 0; i < len; i++)
- outb(buf[i], fifoaddr + adj - (i & adj));
+ iowrite8(buf[i], fifoaddr + adj - (i & adj));
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 1f73b485732d..26193eceb323 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -297,6 +297,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg,
*/
static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
{
+ unsigned int ep;
+ unsigned int addr;
+ unsigned int size;
+ int timeout;
+ u32 val;
+
/* the ryu 2.6.24 release ahs
writel(0x1C0, hsotg->regs + S3C_GRXFSIZ);
writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) |
@@ -310,6 +316,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) |
S3C_GNPTXFSIZ_NPTxFDep(0x1C0),
hsotg->regs + S3C_GNPTXFSIZ);
+
+ /* arange all the rest of the TX FIFOs, as some versions of this
+ * block have overlapping default addresses. This also ensures
+ * that if the settings have been changed, then they are set to
+ * known values. */
+
+ /* start at the end of the GNPTXFSIZ, rounded up */
+ addr = 2048 + 1024;
+ size = 768;
+
+ /* currently we allocate TX FIFOs for all possible endpoints,
+ * and assume that they are all the same size. */
+
+ for (ep = 0; ep <= 15; ep++) {
+ val = addr;
+ val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
+ addr += size;
+
+ writel(val, hsotg->regs + S3C_DPTXFSIZn(ep));
+ }
+
+ /* according to p428 of the design guide, we need to ensure that
+ * all fifos are flushed before continuing */
+
+ writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh |
+ S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL);
+
+ /* wait until the fifos are both flushed */
+ timeout = 100;
+ while (1) {
+ val = readl(hsotg->regs + S3C_GRSTCTL);
+
+ if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0)
+ break;
+
+ if (--timeout == 0) {
+ dev_err(hsotg->dev,
+ "%s: timeout flushing fifos (GRSTCTL=%08x)\n",
+ __func__, val);
+ }
+
+ udelay(1);
+ }
+
+ dev_dbg(hsotg->dev, "FIFOs reset, timeout at %d\n", timeout);
}
/**
@@ -2574,6 +2625,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK,
hsotg->regs + S3C_DCTL);
+ /* must be at-least 3ms to allow bus to see disconnect */
+ msleep(3);
+
/* remove the soft-disconnect and let's go */
__bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
@@ -2730,6 +2784,9 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg)
writel(0, hsotg->regs + S3C_DAINTMSK);
+ /* Be in disconnected state until gadget is registered */
+ __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon);
+
if (0) {
/* post global nak until we're ready */
writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak,
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ef3e88f0b3c3..a3ef2a9d9dc2 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1135,7 +1135,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_XPS_USB_HCD_XILINX
#include "ehci-xilinx-of.c"
-#define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
+#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
#endif
#ifdef CONFIG_PLAT_ORION
@@ -1159,7 +1159,8 @@ MODULE_LICENSE ("GPL");
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+ !defined(XILINX_OF_PLATFORM_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@@ -1213,10 +1214,20 @@ static int __init ehci_hcd_init(void)
if (retval < 0)
goto clean3;
#endif
+
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto clean4;
+#endif
return retval;
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ /* of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); */
+clean4:
+#endif
#ifdef OF_PLATFORM_DRIVER
- /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
clean3:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
@@ -1243,6 +1254,9 @@ module_init(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+#endif
#ifdef OF_PLATFORM_DRIVER
of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
#endif
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 013972bbde57..4899f451add9 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -151,7 +151,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
static int __devinit
ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dn = op->node;
+ struct device_node *dn = op->dev.of_node;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource res;
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 5151516ea1de..d995351f9bed 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -65,7 +65,7 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len)
unsigned short *bp = (unsigned short *)buf;
while (len--) {
DUMMY_DELAY_ACCESS;
- *bp++ = inw((void *)addr);
+ *bp++ = inw(addr);
}
}
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6db57ab6079d..1a2bb4ce638f 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2404,7 +2404,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
del_timer_sync(&r8a66597->rh_timer);
usb_remove_hcd(hcd);
- iounmap((void *)r8a66597->reg);
+ iounmap(r8a66597->reg);
#ifdef CONFIG_HAVE_CLK
if (r8a66597->pdata->on_chip)
clk_put(r8a66597->clk);
@@ -2496,7 +2496,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
init_timer(&r8a66597->rh_timer);
r8a66597->rh_timer.function = r8a66597_timer;
r8a66597->rh_timer.data = (unsigned long)r8a66597;
- r8a66597->reg = (unsigned long)reg;
+ r8a66597->reg = reg;
/* make sure no interrupts are pending */
ret = r8a66597_clock_enable(r8a66597);
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 228e3fb23854..95d0f5adfdcf 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -112,7 +112,7 @@ struct r8a66597_root_hub {
struct r8a66597 {
spinlock_t lock;
- unsigned long reg;
+ void __iomem *reg;
#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
@@ -170,67 +170,67 @@ static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597,
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
- return inw(r8a66597->reg + offset);
+ return ioread16(r8a66597->reg + offset);
}
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
unsigned long count;
if (r8a66597->pdata->on_chip) {
count = len / 4;
- insl(fifoaddr, buf, count);
+ ioread32_rep(fifoaddr, buf, count);
if (len & 0x00000003) {
- unsigned long tmp = inl(fifoaddr);
+ unsigned long tmp = ioread32(fifoaddr);
memcpy((unsigned char *)buf + count * 4, &tmp,
len & 0x03);
}
} else {
len = (len + 1) / 2;
- insw(fifoaddr, buf, len);
+ ioread16_rep(fifoaddr, buf, len);
}
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
unsigned long offset)
{
- outw(val, r8a66597->reg + offset);
+ iowrite16(val, r8a66597->reg + offset);
}
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
unsigned long count;
unsigned char *pb;
int i;
if (r8a66597->pdata->on_chip) {
count = len / 4;
- outsl(fifoaddr, buf, count);
+ iowrite32_rep(fifoaddr, buf, count);
if (len & 0x00000003) {
pb = (unsigned char *)buf + count * 4;
for (i = 0; i < (len & 0x00000003); i++) {
if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
- outb(pb[i], fifoaddr + i);
+ iowrite8(pb[i], fifoaddr + i);
else
- outb(pb[i], fifoaddr + 3 - i);
+ iowrite8(pb[i], fifoaddr + 3 - i);
}
}
} else {
int odd = len & 0x0001;
len = len / 2;
- outsw(fifoaddr, buf, len);
+ ioread16_rep(fifoaddr, buf, len);
if (unlikely(odd)) {
buf = &buf[len];
- outb((unsigned char)*buf, fifoaddr);
+ iowrite8((unsigned char)*buf, fifoaddr);
}
}
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index edffd81fc253..11482b6b9381 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -78,6 +78,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
" endpoint cmd after reset endpoint\n");
}
+ if (pdev->vendor == PCI_VENDOR_ID_NEC)
+ xhci->quirks |= XHCI_NEC_HOST;
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 36c858e5b529..9012098add6b 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1071,6 +1071,15 @@ bandwidth_change:
xhci_warn(xhci, "Reset device command completion "
"for disabled slot %u\n", slot_id);
break;
+ case TRB_TYPE(TRB_NEC_GET_FW):
+ if (!(xhci->quirks & XHCI_NEC_HOST)) {
+ xhci->error_bitmask |= 1 << 6;
+ break;
+ }
+ xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
+ NEC_FW_MAJOR(event->status),
+ NEC_FW_MINOR(event->status));
+ break;
default:
/* Skip over unknown commands on the event ring */
xhci->error_bitmask |= 1 << 6;
@@ -1079,6 +1088,17 @@ bandwidth_change:
inc_deq(xhci, xhci->cmd_ring, false);
}
+static void handle_vendor_event(struct xhci_hcd *xhci,
+ union xhci_trb *event)
+{
+ u32 trb_type;
+
+ trb_type = TRB_FIELD_TO_TYPE(event->generic.field[3]);
+ xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type);
+ if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST))
+ handle_cmd_completion(xhci, &event->event_cmd);
+}
+
static void handle_port_status(struct xhci_hcd *xhci,
union xhci_trb *event)
{
@@ -1659,7 +1679,10 @@ void xhci_handle_event(struct xhci_hcd *xhci)
update_ptrs = 0;
break;
default:
- xhci->error_bitmask |= 1 << 3;
+ if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48))
+ handle_vendor_event(xhci, event);
+ else
+ xhci->error_bitmask |= 1 << 3;
}
/* Any of the above functions may drop and re-acquire the lock, so check
* to make sure a watchdog timer didn't mark the host as non-responsive.
@@ -2378,6 +2401,12 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
false);
}
+int xhci_queue_vendor_command(struct xhci_hcd *xhci,
+ u32 field1, u32 field2, u32 field3, u32 field4)
+{
+ return queue_command(xhci, field1, field2, field3, field4, false);
+}
+
/* Queue a reset device command TRB */
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
{
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 40e0a0c221b8..27345cd04da0 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -106,6 +106,33 @@ int xhci_halt(struct xhci_hcd *xhci)
}
/*
+ * Set the run bit and wait for the host to be running.
+ */
+int xhci_start(struct xhci_hcd *xhci)
+{
+ u32 temp;
+ int ret;
+
+ temp = xhci_readl(xhci, &xhci->op_regs->command);
+ temp |= (CMD_RUN);
+ xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+ temp);
+ xhci_writel(xhci, temp, &xhci->op_regs->command);
+
+ /*
+ * Wait for the HCHalted Status bit to be 0 to indicate the host is
+ * running.
+ */
+ ret = handshake(xhci, &xhci->op_regs->status,
+ STS_HALT, 0, XHCI_MAX_HALT_USEC);
+ if (ret == -ETIMEDOUT)
+ xhci_err(xhci, "Host took too long to start, "
+ "waited %u microseconds.\n",
+ XHCI_MAX_HALT_USEC);
+ return ret;
+}
+
+/*
* Reset a halted HC, and set the internal HC state to HC_STATE_HALT.
*
* This resets pipelines, timers, counters, state machines, etc.
@@ -116,6 +143,7 @@ int xhci_reset(struct xhci_hcd *xhci)
{
u32 command;
u32 state;
+ int ret;
state = xhci_readl(xhci, &xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
@@ -130,7 +158,17 @@ int xhci_reset(struct xhci_hcd *xhci)
/* XXX: Why does EHCI set this here? Shouldn't other code do this? */
xhci_to_hcd(xhci)->state = HC_STATE_HALT;
- return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000);
+ ret = handshake(xhci, &xhci->op_regs->command,
+ CMD_RESET, 0, 250 * 1000);
+ if (ret)
+ return ret;
+
+ xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n");
+ /*
+ * xHCI cannot write to any doorbells or operational registers other
+ * than status until the "Controller Not Ready" flag is cleared.
+ */
+ return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
}
@@ -448,17 +486,20 @@ int xhci_run(struct usb_hcd *hcd)
if (NUM_TEST_NOOPS > 0)
doorbell = xhci_setup_one_noop(xhci);
+ if (xhci->quirks & XHCI_NEC_HOST)
+ xhci_queue_vendor_command(xhci, 0, 0, 0,
+ TRB_TYPE(TRB_NEC_GET_FW));
+
+ if (xhci_start(xhci)) {
+ xhci_halt(xhci);
+ return -ENODEV;
+ }
- temp = xhci_readl(xhci, &xhci->op_regs->command);
- temp |= (CMD_RUN);
- xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
- temp);
- xhci_writel(xhci, temp, &xhci->op_regs->command);
- /* Flush PCI posted writes */
- temp = xhci_readl(xhci, &xhci->op_regs->command);
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
if (doorbell)
(*doorbell)(xhci);
+ if (xhci->quirks & XHCI_NEC_HOST)
+ xhci_ring_cmd_db(xhci);
xhci_dbg(xhci, "Finished xhci_run\n");
return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dada2fb59261..8b4b7d39f79c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -925,6 +925,7 @@ union xhci_trb {
/* TRB bit mask */
#define TRB_TYPE_BITMASK (0xfc00)
#define TRB_TYPE(p) ((p) << 10)
+#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10)
/* TRB type IDs */
/* bulk, interrupt, isoc scatter/gather, and control data stage */
#define TRB_NORMAL 1
@@ -992,6 +993,14 @@ union xhci_trb {
#define TRB_MFINDEX_WRAP 39
/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
+/* Nec vendor-specific command completion event. */
+#define TRB_NEC_CMD_COMP 48
+/* Get NEC firmware revision. */
+#define TRB_NEC_GET_FW 49
+
+#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff)
+#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff)
+
/*
* TRBS_PER_SEGMENT must be a multiple of 4,
* since the command ring is 64-byte aligned.
@@ -1172,6 +1181,7 @@ struct xhci_hcd {
unsigned int quirks;
#define XHCI_LINK_TRB_QUIRK (1 << 0)
#define XHCI_RESET_EP_QUIRK (1 << 1)
+#define XHCI_NEC_HOST (1 << 2)
};
/* For testing purposes */
@@ -1379,6 +1389,8 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
+int xhci_queue_vendor_command(struct xhci_hcd *xhci,
+ u32 field1, u32 field2, u32 field3, u32 field4);
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 3edda3ed822a..fd35f73b5721 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1239,8 +1239,7 @@ static void digi_write_bulk_callback(struct urb *urb)
/* port and serial sanity check */
if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) {
- dev_err(&port->dev,
- "%s: port or port->private is NULL, status=%d\n",
+ pr_err("%s: port or port->private is NULL, status=%d\n",
__func__, status);
return;
}
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 050211afc07e..79dd1ae195e5 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2005,6 +2005,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
"urb failed to set to rts/cts flow control\n");
}
+ /* raise DTR/RTS */
+ set_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
/*
* Xon/Xoff code
@@ -2052,6 +2054,8 @@ static void ftdi_set_termios(struct tty_struct *tty,
}
}
+ /* lower DTR/RTS */
+ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
}
return;
}
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index f8424d1bfc1b..585b7e663740 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -730,7 +730,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
mos7840_port = urb->context;
if (!mos7840_port) {
dbg("%s", "NULL mos7840_port pointer");
- mos7840_port->read_urb_busy = false;
return;
}
diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c
index def778cf2216..daf793559bcf 100644
--- a/drivers/uwb/i1480/i1480u-wlp/lc.c
+++ b/drivers/uwb/i1480/i1480u-wlp/lc.c
@@ -93,28 +93,28 @@ void i1480u_init(struct i1480u *i1480u)
* information elements have intuitive mappings, other not.
*/
static
-void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *dev_info)
+void i1480u_fill_device_info(struct wlp *wlp, struct wlp_device_info *wdi)
{
struct i1480u *i1480u = container_of(wlp, struct i1480u, wlp);
struct usb_device *usb_dev = i1480u->usb_dev;
/* Treat device name and model name the same */
if (usb_dev->descriptor.iProduct) {
usb_string(usb_dev, usb_dev->descriptor.iProduct,
- dev_info->name, sizeof(dev_info->name));
+ wdi->name, sizeof(wdi->name));
usb_string(usb_dev, usb_dev->descriptor.iProduct,
- dev_info->model_name, sizeof(dev_info->model_name));
+ wdi->model_name, sizeof(wdi->model_name));
}
if (usb_dev->descriptor.iManufacturer)
usb_string(usb_dev, usb_dev->descriptor.iManufacturer,
- dev_info->manufacturer,
- sizeof(dev_info->manufacturer));
- scnprintf(dev_info->model_nr, sizeof(dev_info->model_nr), "%04x",
+ wdi->manufacturer,
+ sizeof(wdi->manufacturer));
+ scnprintf(wdi->model_nr, sizeof(wdi->model_nr), "%04x",
__le16_to_cpu(usb_dev->descriptor.bcdDevice));
if (usb_dev->descriptor.iSerialNumber)
usb_string(usb_dev, usb_dev->descriptor.iSerialNumber,
- dev_info->serial, sizeof(dev_info->serial));
+ wdi->serial, sizeof(wdi->serial));
/* FIXME: where should we obtain category? */
- dev_info->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
+ wdi->prim_dev_type.category = cpu_to_le16(WLP_DEV_CAT_OTHER);
/* FIXME: Complete OUI and OUIsubdiv attributes */
}
diff --git a/drivers/uwb/wlp/messages.c b/drivers/uwb/wlp/messages.c
index 3a8e033dce21..6daa464bed24 100644
--- a/drivers/uwb/wlp/messages.c
+++ b/drivers/uwb/wlp/messages.c
@@ -713,7 +713,7 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
struct sk_buff *_skb;
void *d1_itr;
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0) {
dev_err(dev, "WLP: Unable to setup device "
@@ -721,7 +721,7 @@ static int wlp_build_assoc_d1(struct wlp *wlp, struct wlp_wss *wss,
goto error;
}
}
- info = wlp->dev_info;
+ info = wlp->wdi;
_skb = dev_alloc_skb(sizeof(*_d1)
+ sizeof(struct wlp_attr_uuid_e)
+ sizeof(struct wlp_attr_wss_sel_mthd)
@@ -795,7 +795,7 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
void *d2_itr;
size_t mem_needed;
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0) {
dev_err(dev, "WLP: Unable to setup device "
@@ -803,7 +803,7 @@ int wlp_build_assoc_d2(struct wlp *wlp, struct wlp_wss *wss,
goto error;
}
}
- info = wlp->dev_info;
+ info = wlp->wdi;
mem_needed = sizeof(*_d2)
+ sizeof(struct wlp_attr_uuid_e)
+ sizeof(struct wlp_attr_uuid_r)
@@ -971,7 +971,7 @@ error_parse:
*/
static
int wlp_get_variable_info(struct wlp *wlp, void *data,
- struct wlp_device_info *dev_info, ssize_t len)
+ struct wlp_device_info *wdi, ssize_t len)
{
struct device *dev = &wlp->rc->uwb_dev.dev;
size_t used = 0;
@@ -994,7 +994,7 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
goto error_parse;
}
result = wlp_get_manufacturer(wlp, data + used,
- dev_info->manufacturer,
+ wdi->manufacturer,
len - used);
if (result < 0) {
dev_err(dev, "WLP: Unable to obtain "
@@ -1012,7 +1012,7 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
goto error_parse;
}
result = wlp_get_model_name(wlp, data + used,
- dev_info->model_name,
+ wdi->model_name,
len - used);
if (result < 0) {
dev_err(dev, "WLP: Unable to obtain Model "
@@ -1029,7 +1029,7 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
goto error_parse;
}
result = wlp_get_model_nr(wlp, data + used,
- dev_info->model_nr,
+ wdi->model_nr,
len - used);
if (result < 0) {
dev_err(dev, "WLP: Unable to obtain Model "
@@ -1046,7 +1046,7 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
goto error_parse;
}
result = wlp_get_serial(wlp, data + used,
- dev_info->serial, len - used);
+ wdi->serial, len - used);
if (result < 0) {
dev_err(dev, "WLP: Unable to obtain Serial "
"number attribute from D1 message.\n");
@@ -1062,7 +1062,7 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
goto error_parse;
}
result = wlp_get_prim_dev_type(wlp, data + used,
- &dev_info->prim_dev_type,
+ &wdi->prim_dev_type,
len - used);
if (result < 0) {
dev_err(dev, "WLP: Unable to obtain Primary "
@@ -1070,10 +1070,10 @@ int wlp_get_variable_info(struct wlp *wlp, void *data,
"message.\n");
goto error_parse;
}
- dev_info->prim_dev_type.category =
- le16_to_cpu(dev_info->prim_dev_type.category);
- dev_info->prim_dev_type.subID =
- le16_to_cpu(dev_info->prim_dev_type.subID);
+ wdi->prim_dev_type.category =
+ le16_to_cpu(wdi->prim_dev_type.category);
+ wdi->prim_dev_type.subID =
+ le16_to_cpu(wdi->prim_dev_type.subID);
last = WLP_ATTR_PRI_DEV_TYPE;
used += result;
break;
@@ -1099,7 +1099,7 @@ static
int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
struct wlp_uuid *uuid_e,
enum wlp_wss_sel_mthd *sel_mthd,
- struct wlp_device_info *dev_info,
+ struct wlp_device_info *wdi,
enum wlp_assc_error *assc_err)
{
struct device *dev = &wlp->rc->uwb_dev.dev;
@@ -1124,7 +1124,7 @@ int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
goto error_parse;
}
used += result;
- result = wlp_get_dev_name(wlp, ptr + used, dev_info->name,
+ result = wlp_get_dev_name(wlp, ptr + used, wdi->name,
len - used);
if (result < 0) {
dev_err(dev, "WLP: unable to obtain Device Name from D1 "
@@ -1132,7 +1132,7 @@ int wlp_parse_d1_frame(struct wlp *wlp, struct sk_buff *skb,
goto error_parse;
}
used += result;
- result = wlp_get_variable_info(wlp, ptr + used, dev_info, len - used);
+ result = wlp_get_variable_info(wlp, ptr + used, wdi, len - used);
if (result < 0) {
dev_err(dev, "WLP: unable to obtain Device Information from "
"D1 message.\n");
@@ -1172,15 +1172,15 @@ void wlp_handle_d1_frame(struct work_struct *ws)
struct device *dev = &wlp->rc->uwb_dev.dev;
struct wlp_uuid uuid_e;
enum wlp_wss_sel_mthd sel_mthd = 0;
- struct wlp_device_info dev_info;
+ struct wlp_device_info wdi;
enum wlp_assc_error assc_err;
struct sk_buff *resp = NULL;
/* Parse D1 frame */
mutex_lock(&wss->mutex);
mutex_lock(&wlp->mutex); /* to access wlp->uuid */
- memset(&dev_info, 0, sizeof(dev_info));
- result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &dev_info,
+ memset(&wdi, 0, sizeof(wdi));
+ result = wlp_parse_d1_frame(wlp, skb, &uuid_e, &sel_mthd, &wdi,
&assc_err);
if (result < 0) {
dev_err(dev, "WLP: Unable to parse incoming D1 frame.\n");
diff --git a/drivers/uwb/wlp/sysfs.c b/drivers/uwb/wlp/sysfs.c
index 6627c94cc854..b24751c3430b 100644
--- a/drivers/uwb/wlp/sysfs.c
+++ b/drivers/uwb/wlp/sysfs.c
@@ -333,12 +333,12 @@ ssize_t wlp_dev_##type##_show(struct wlp *wlp, char *buf) \
{ \
ssize_t result = 0; \
mutex_lock(&wlp->mutex); \
- if (wlp->dev_info == NULL) { \
+ if (wlp->wdi == NULL) { \
result = __wlp_setup_device_info(wlp); \
if (result < 0) \
goto out; \
} \
- result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->dev_info->type);\
+ result = scnprintf(buf, PAGE_SIZE, "%s\n", wlp->wdi->type); \
out: \
mutex_unlock(&wlp->mutex); \
return result; \
@@ -360,14 +360,14 @@ ssize_t wlp_dev_##type##_store(struct wlp *wlp, const char *buf, size_t size)\
ssize_t result; \
char format[10]; \
mutex_lock(&wlp->mutex); \
- if (wlp->dev_info == NULL) { \
+ if (wlp->wdi == NULL) { \
result = __wlp_alloc_device_info(wlp); \
if (result < 0) \
goto out; \
} \
- memset(wlp->dev_info->type, 0, sizeof(wlp->dev_info->type)); \
+ memset(wlp->wdi->type, 0, sizeof(wlp->wdi->type)); \
sprintf(format, "%%%uc", len); \
- result = sscanf(buf, format, wlp->dev_info->type); \
+ result = sscanf(buf, format, wlp->wdi->type); \
out: \
mutex_unlock(&wlp->mutex); \
return result < 0 ? result : size; \
@@ -409,13 +409,13 @@ ssize_t wlp_dev_prim_category_show(struct wlp *wlp, char *buf)
{
ssize_t result = 0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0)
goto out;
}
result = scnprintf(buf, PAGE_SIZE, "%s\n",
- wlp_dev_category_str(wlp->dev_info->prim_dev_type.category));
+ wlp_dev_category_str(wlp->wdi->prim_dev_type.category));
out:
mutex_unlock(&wlp->mutex);
return result;
@@ -428,7 +428,7 @@ ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
ssize_t result;
u16 cat;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_alloc_device_info(wlp);
if (result < 0)
goto out;
@@ -436,7 +436,7 @@ ssize_t wlp_dev_prim_category_store(struct wlp *wlp, const char *buf,
result = sscanf(buf, "%hu", &cat);
if ((cat >= WLP_DEV_CAT_COMPUTER && cat <= WLP_DEV_CAT_TELEPHONE)
|| cat == WLP_DEV_CAT_OTHER)
- wlp->dev_info->prim_dev_type.category = cat;
+ wlp->wdi->prim_dev_type.category = cat;
else
result = -EINVAL;
out:
@@ -449,15 +449,15 @@ ssize_t wlp_dev_prim_OUI_show(struct wlp *wlp, char *buf)
{
ssize_t result = 0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0)
goto out;
}
result = scnprintf(buf, PAGE_SIZE, "%02x:%02x:%02x\n",
- wlp->dev_info->prim_dev_type.OUI[0],
- wlp->dev_info->prim_dev_type.OUI[1],
- wlp->dev_info->prim_dev_type.OUI[2]);
+ wlp->wdi->prim_dev_type.OUI[0],
+ wlp->wdi->prim_dev_type.OUI[1],
+ wlp->wdi->prim_dev_type.OUI[2]);
out:
mutex_unlock(&wlp->mutex);
return result;
@@ -469,7 +469,7 @@ ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
ssize_t result;
u8 OUI[3];
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_alloc_device_info(wlp);
if (result < 0)
goto out;
@@ -480,7 +480,7 @@ ssize_t wlp_dev_prim_OUI_store(struct wlp *wlp, const char *buf, size_t size)
result = -EINVAL;
goto out;
} else
- memcpy(wlp->dev_info->prim_dev_type.OUI, OUI, sizeof(OUI));
+ memcpy(wlp->wdi->prim_dev_type.OUI, OUI, sizeof(OUI));
out:
mutex_unlock(&wlp->mutex);
return result < 0 ? result : size;
@@ -492,13 +492,13 @@ ssize_t wlp_dev_prim_OUI_sub_show(struct wlp *wlp, char *buf)
{
ssize_t result = 0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0)
goto out;
}
result = scnprintf(buf, PAGE_SIZE, "%u\n",
- wlp->dev_info->prim_dev_type.OUIsubdiv);
+ wlp->wdi->prim_dev_type.OUIsubdiv);
out:
mutex_unlock(&wlp->mutex);
return result;
@@ -512,14 +512,14 @@ ssize_t wlp_dev_prim_OUI_sub_store(struct wlp *wlp, const char *buf,
unsigned sub;
u8 max_sub = ~0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_alloc_device_info(wlp);
if (result < 0)
goto out;
}
result = sscanf(buf, "%u", &sub);
if (sub <= max_sub)
- wlp->dev_info->prim_dev_type.OUIsubdiv = sub;
+ wlp->wdi->prim_dev_type.OUIsubdiv = sub;
else
result = -EINVAL;
out:
@@ -532,13 +532,13 @@ ssize_t wlp_dev_prim_subcat_show(struct wlp *wlp, char *buf)
{
ssize_t result = 0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_setup_device_info(wlp);
if (result < 0)
goto out;
}
result = scnprintf(buf, PAGE_SIZE, "%u\n",
- wlp->dev_info->prim_dev_type.subID);
+ wlp->wdi->prim_dev_type.subID);
out:
mutex_unlock(&wlp->mutex);
return result;
@@ -552,14 +552,14 @@ ssize_t wlp_dev_prim_subcat_store(struct wlp *wlp, const char *buf,
unsigned sub;
__le16 max_sub = ~0;
mutex_lock(&wlp->mutex);
- if (wlp->dev_info == NULL) {
+ if (wlp->wdi == NULL) {
result = __wlp_alloc_device_info(wlp);
if (result < 0)
goto out;
}
result = sscanf(buf, "%u", &sub);
if (sub <= max_sub)
- wlp->dev_info->prim_dev_type.subID = sub;
+ wlp->wdi->prim_dev_type.subID = sub;
else
result = -EINVAL;
out:
diff --git a/drivers/uwb/wlp/wlp-lc.c b/drivers/uwb/wlp/wlp-lc.c
index 7f6a630bf26c..202655d4fc20 100644
--- a/drivers/uwb/wlp/wlp-lc.c
+++ b/drivers/uwb/wlp/wlp-lc.c
@@ -40,9 +40,9 @@ void wlp_neighbor_init(struct wlp_neighbor_e *neighbor)
int __wlp_alloc_device_info(struct wlp *wlp)
{
struct device *dev = &wlp->rc->uwb_dev.dev;
- BUG_ON(wlp->dev_info != NULL);
- wlp->dev_info = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
- if (wlp->dev_info == NULL) {
+ BUG_ON(wlp->wdi != NULL);
+ wlp->wdi = kzalloc(sizeof(struct wlp_device_info), GFP_KERNEL);
+ if (wlp->wdi == NULL) {
dev_err(dev, "WLP: Unable to allocate memory for "
"device information.\n");
return -ENOMEM;
@@ -59,7 +59,7 @@ int __wlp_alloc_device_info(struct wlp *wlp)
static
void __wlp_fill_device_info(struct wlp *wlp)
{
- wlp->fill_device_info(wlp, wlp->dev_info);
+ wlp->fill_device_info(wlp, wlp->wdi);
}
/**
@@ -539,8 +539,8 @@ void wlp_remove(struct wlp *wlp)
uwb_notifs_deregister(wlp->rc, &wlp->uwb_notifs_handler);
wlp_eda_release(&wlp->eda);
mutex_lock(&wlp->mutex);
- if (wlp->dev_info != NULL)
- kfree(wlp->dev_info);
+ if (wlp->wdi != NULL)
+ kfree(wlp->wdi);
mutex_unlock(&wlp->mutex);
wlp->rc = NULL;
}
diff --git a/drivers/vbus/Kconfig b/drivers/vbus/Kconfig
new file mode 100644
index 000000000000..f51cba10913e
--- /dev/null
+++ b/drivers/vbus/Kconfig
@@ -0,0 +1,25 @@
+#
+# Virtual-Bus (VBus) driver configuration
+#
+
+config VBUS_PROXY
+ bool "Virtual-Bus support"
+ select SHM_SIGNAL
+ select IOQ
+ default n
+ help
+ Adds support for a virtual-bus model drivers in a guest to connect
+ to host side virtual-bus resources. If you are using this kernel
+ in a virtualization solution which implements virtual-bus devices
+ on the backend, say Y. If unsure, say N.
+
+config VBUS_PCIBRIDGE
+ bool "PCI to Virtual-Bus bridge"
+ depends on PCI
+ depends on VBUS_PROXY
+ select IOQ
+ default n
+ help
+ Provides a way to bridge host side vbus devices via a PCI-BRIDGE
+ object. If you are running virtualization with vbus devices on the
+ host, and the vbus is exposed via PCI, say Y. Otherwise, say N.
diff --git a/drivers/vbus/Makefile b/drivers/vbus/Makefile
new file mode 100644
index 000000000000..944b7f1fec90
--- /dev/null
+++ b/drivers/vbus/Makefile
@@ -0,0 +1,6 @@
+
+vbus-proxy-objs += bus-proxy.o
+obj-$(CONFIG_VBUS_PROXY) += vbus-proxy.o
+
+vbus-pcibridge-objs += pci-bridge.o
+obj-$(CONFIG_VBUS_PCIBRIDGE) += vbus-pcibridge.o
diff --git a/drivers/vbus/bus-proxy.c b/drivers/vbus/bus-proxy.c
new file mode 100644
index 000000000000..ae11f679d34e
--- /dev/null
+++ b/drivers/vbus/bus-proxy.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vbus_driver.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+
+#define VBUS_PROXY_NAME "vbus-proxy"
+
+static struct vbus_device_proxy *to_dev(struct device *_dev)
+{
+ return _dev ? container_of(_dev, struct vbus_device_proxy, dev) : NULL;
+}
+
+static struct vbus_driver *to_drv(struct device_driver *_drv)
+{
+ return container_of(_drv, struct vbus_driver, drv);
+}
+
+/*
+ * This function is invoked whenever a new driver and/or device is added
+ * to check if there is a match
+ */
+static int vbus_dev_proxy_match(struct device *_dev, struct device_driver *_drv)
+{
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ struct vbus_driver *drv = to_drv(_drv);
+
+ return !strcmp(dev->type, drv->type);
+}
+
+static int vbus_dev_proxy_uevent(struct device *_dev, struct kobj_uevent_env *env)
+{
+ struct vbus_device_proxy *dev = to_dev(_dev);
+
+ if (add_uevent_var(env, "MODALIAS=vbus-proxy:%s", dev->type))
+ return -ENOMEM;
+
+ return 0;
+}
+
+/*
+ * This function is invoked after the bus infrastructure has already made a
+ * match. The device will contain a reference to the paired driver which
+ * we will extract.
+ */
+static int vbus_dev_proxy_probe(struct device *_dev)
+{
+ int ret = 0;
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ struct vbus_driver *drv = to_drv(_dev->driver);
+
+ if (drv->ops->probe)
+ ret = drv->ops->probe(dev);
+
+ return ret;
+}
+
+static struct bus_type vbus_proxy = {
+ .name = VBUS_PROXY_NAME,
+ .match = vbus_dev_proxy_match,
+ .uevent = vbus_dev_proxy_uevent,
+};
+
+static struct device vbus_proxy_rootdev = {
+ .parent = NULL,
+ .init_name = VBUS_PROXY_NAME,
+};
+
+static int __init vbus_init(void)
+{
+ int ret;
+
+ ret = bus_register(&vbus_proxy);
+ BUG_ON(ret < 0);
+
+ ret = device_register(&vbus_proxy_rootdev);
+ BUG_ON(ret < 0);
+
+ return 0;
+}
+
+postcore_initcall(vbus_init);
+
+static void device_release(struct device *dev)
+{
+ struct vbus_device_proxy *_dev;
+
+ _dev = container_of(dev, struct vbus_device_proxy, dev);
+
+ _dev->ops->release(_dev);
+}
+
+static ssize_t _show_modalias(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "vbus-proxy:%s\n", to_dev(dev)->type);
+}
+static DEVICE_ATTR(modalias, S_IRUSR | S_IRGRP | S_IROTH, _show_modalias, NULL);
+
+int vbus_device_proxy_register(struct vbus_device_proxy *new)
+{
+ int ret;
+
+ new->dev.parent = &vbus_proxy_rootdev;
+ new->dev.bus = &vbus_proxy;
+ new->dev.release = &device_release;
+
+ ret = device_register(&new->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = device_create_file(&new->dev, &dev_attr_modalias);
+ if (ret < 0) {
+ device_unregister(&new->dev);
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_register);
+
+void vbus_device_proxy_unregister(struct vbus_device_proxy *dev)
+{
+ device_remove_file(&dev->dev, &dev_attr_modalias);
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_unregister);
+
+static int match_device_id(struct device *_dev, void *data)
+{
+ struct vbus_device_proxy *dev = to_dev(_dev);
+ u64 id = *(u64 *)data;
+
+ return dev->id == id;
+}
+
+struct vbus_device_proxy *vbus_device_proxy_find(u64 id)
+{
+ struct device *dev;
+
+ dev = bus_find_device(&vbus_proxy, NULL, &id, &match_device_id);
+
+ return to_dev(dev);
+}
+EXPORT_SYMBOL_GPL(vbus_device_proxy_find);
+
+int vbus_driver_register(struct vbus_driver *new)
+{
+ new->drv.bus = &vbus_proxy;
+ new->drv.name = new->type;
+ new->drv.owner = new->owner;
+ new->drv.probe = vbus_dev_proxy_probe;
+
+ return driver_register(&new->drv);
+}
+EXPORT_SYMBOL_GPL(vbus_driver_register);
+
+void vbus_driver_unregister(struct vbus_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(vbus_driver_unregister);
+
+/*
+ *---------------------------------
+ * driver-side IOQ helper
+ *---------------------------------
+ */
+static void
+vbus_driver_ioq_release(struct ioq *ioq)
+{
+ kfree(ioq->head_desc);
+ kfree(ioq);
+}
+
+static struct ioq_ops vbus_driver_ioq_ops = {
+ .release = vbus_driver_ioq_release,
+};
+
+
+int vbus_driver_ioq_alloc(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio, size_t count, struct ioq **ioq)
+{
+ struct ioq *_ioq;
+ struct ioq_ring_head *head = NULL;
+ struct shm_signal *signal = NULL;
+ size_t len = IOQ_HEAD_DESC_SIZE(count);
+ int ret = -ENOMEM;
+
+ _ioq = kzalloc(sizeof(*_ioq), GFP_KERNEL);
+ if (!_ioq)
+ goto error;
+
+ head = kzalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!head)
+ goto error;
+
+ head->magic = IOQ_RING_MAGIC;
+ head->ver = IOQ_RING_VER;
+ head->count = cpu_to_le32(count);
+
+ ret = dev->ops->shm(dev, name, id, prio, head, len,
+ &head->signal, &signal, 0);
+ if (ret < 0)
+ goto error;
+
+ ioq_init(_ioq,
+ &vbus_driver_ioq_ops,
+ ioq_locality_north,
+ head,
+ signal,
+ count);
+
+ *ioq = _ioq;
+
+ return 0;
+
+ error:
+ kfree(_ioq);
+ kfree(head);
+
+ if (signal)
+ shm_signal_put(signal);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vbus_driver_ioq_alloc);
diff --git a/drivers/vbus/pci-bridge.c b/drivers/vbus/pci-bridge.c
new file mode 100644
index 000000000000..36de7c48891c
--- /dev/null
+++ b/drivers/vbus/pci-bridge.c
@@ -0,0 +1,1016 @@
+/*
+ * Copyright (C) 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/mm.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/ioq.h>
+#include <linux/interrupt.h>
+#include <linux/vbus_driver.h>
+#include <linux/vbus_pci.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+#define VBUS_PCI_NAME "pci-to-vbus-bridge"
+
+struct vbus_pci {
+ spinlock_t lock;
+ struct pci_dev *dev;
+ struct ioq eventq;
+ struct vbus_pci_event *ring;
+ struct vbus_pci_regs *regs;
+ struct vbus_pci_signals *signals;
+ int irq;
+ bool enabled;
+ struct {
+ struct dentry *fs;
+ int events;
+ int qnotify;
+ int qinject;
+ int notify;
+ int inject;
+ int bridgecalls;
+ int buscalls;
+ } stats;
+};
+
+static struct vbus_pci vbus_pci;
+
+struct vbus_pci_device {
+ char type[VBUS_MAX_DEVTYPE_LEN];
+ u64 handle;
+ struct list_head shms;
+ struct vbus_device_proxy vdev;
+ struct work_struct drop;
+};
+
+static DEFINE_PER_CPU(struct vbus_pci_fastcall_desc, vbus_pci_percpu_fastcall)
+____cacheline_aligned;
+
+/*
+ * -------------------
+ * common routines
+ * -------------------
+ */
+
+static int
+vbus_pci_bridgecall(unsigned long nr, void *data, unsigned long len)
+{
+ struct vbus_pci_call_desc params = {
+ .vector = nr,
+ .len = len,
+ .datap = __pa(data),
+ };
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&vbus_pci.lock, flags);
+
+ memcpy_toio(&vbus_pci.regs->bridgecall, &params, sizeof(params));
+ ret = ioread32(&vbus_pci.regs->bridgecall);
+
+ spin_unlock_irqrestore(&vbus_pci.lock, flags);
+
+ vbus_pci.stats.bridgecalls++;
+
+ return ret;
+}
+
+static int
+vbus_pci_buscall(unsigned long nr, void *data, unsigned long len)
+{
+ struct vbus_pci_fastcall_desc *params;
+ int ret;
+
+ preempt_disable();
+
+ params = &get_cpu_var(vbus_pci_percpu_fastcall);
+
+ params->call.vector = nr;
+ params->call.len = len;
+ params->call.datap = __pa(data);
+
+ iowrite32(smp_processor_id(), &vbus_pci.signals->fastcall);
+
+ ret = params->result;
+
+ preempt_enable();
+
+ vbus_pci.stats.buscalls++;
+
+ return ret;
+}
+
+static struct vbus_pci_device *
+to_dev(struct vbus_device_proxy *vdev)
+{
+ return container_of(vdev, struct vbus_pci_device, vdev);
+}
+
+static void
+_signal_init(struct shm_signal *signal, struct shm_signal_desc *desc,
+ struct shm_signal_ops *ops)
+{
+ desc->magic = SHM_SIGNAL_MAGIC;
+ desc->ver = SHM_SIGNAL_VER;
+
+ shm_signal_init(signal, shm_locality_north, ops, desc);
+}
+
+/*
+ * -------------------
+ * _signal
+ * -------------------
+ */
+
+struct _signal {
+ char name[64];
+ struct vbus_pci *pcivbus;
+ struct shm_signal signal;
+ u32 handle;
+ struct rb_node node;
+ struct list_head list;
+ int irq;
+ struct irq_desc *desc;
+};
+
+static struct _signal *
+to_signal(struct shm_signal *signal)
+{
+ return container_of(signal, struct _signal, signal);
+}
+
+static int
+_signal_inject(struct shm_signal *signal)
+{
+ struct _signal *_signal = to_signal(signal);
+
+ vbus_pci.stats.inject++;
+ iowrite32(_signal->handle, &vbus_pci.signals->shmsignal);
+
+ return 0;
+}
+
+static void
+_signal_release(struct shm_signal *signal)
+{
+ struct _signal *_signal = to_signal(signal);
+
+ kfree(_signal);
+}
+
+static struct shm_signal_ops _signal_ops = {
+ .inject = _signal_inject,
+ .release = _signal_release,
+};
+
+static void shmsignal_disconnect(struct _signal *_signal);
+
+/*
+ * -------------------
+ * vbus_device_proxy routines
+ * -------------------
+ */
+
+static int
+vbus_pci_device_open(struct vbus_device_proxy *vdev, int version, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct vbus_pci_deviceopen params;
+ int ret;
+
+ if (dev->handle)
+ return -EINVAL;
+
+ params.devid = vdev->id;
+ params.version = version;
+
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVOPEN,
+ &params, sizeof(params));
+ if (ret < 0)
+ return ret;
+
+ dev->handle = params.handle;
+
+ return 0;
+}
+
+static int
+vbus_pci_device_close(struct vbus_device_proxy *vdev, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ unsigned long iflags;
+ int ret;
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+
+ while (!list_empty(&dev->shms)) {
+ struct _signal *_signal;
+
+ _signal = list_first_entry(&dev->shms, struct _signal, list);
+
+ list_del(&_signal->list);
+ shmsignal_disconnect(_signal);
+
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+ shm_signal_put(&_signal->signal);
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+ }
+
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+
+ /*
+ * The DEVICECLOSE will implicitly close all of the shm on the
+ * host-side, so there is no need to do an explicit per-shm
+ * hypercall
+ */
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVCLOSE,
+ &dev->handle, sizeof(dev->handle));
+
+ if (ret < 0)
+ printk(KERN_ERR "VBUS-PCI: Error closing device %s/%lld: %d\n",
+ vdev->type, vdev->id, ret);
+
+ dev->handle = 0;
+
+ return 0;
+}
+
+/*
+ * -------------------
+ * shmsignal interrupt routines
+ * -------------------
+ */
+
+/* We abstract these routines so that we can drop in irqchip later */
+
+static void
+shmsignal_wakeup(struct _signal *_signal)
+{
+ _shm_signal_wakeup(&_signal->signal);
+}
+
+static int
+shmsignal_connect(struct _signal *_signal)
+{
+ return 0;
+}
+
+static void
+shmsignal_disconnect(struct _signal *_signal)
+{
+
+}
+
+static int
+vbus_pci_device_shm(struct vbus_device_proxy *vdev, const char *name,
+ int id, int prio,
+ void *ptr, size_t len,
+ struct shm_signal_desc *sdesc, struct shm_signal **signal,
+ int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct _signal *_signal = NULL;
+ struct vbus_pci_deviceshm params;
+ unsigned long iflags;
+ int ret;
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ params.devh = dev->handle;
+ params.id = id;
+ params.flags = flags;
+ params.datap = (u64)__pa(ptr);
+ params.len = len;
+
+ if (signal) {
+ /*
+ * The signal descriptor must be embedded within the
+ * provided ptr
+ */
+ if (!sdesc
+ || (len < sizeof(*sdesc))
+ || ((void *)sdesc < ptr)
+ || ((void *)sdesc > (ptr + len - sizeof(*sdesc))))
+ return -EINVAL;
+
+ _signal = kzalloc(sizeof(*_signal), GFP_KERNEL);
+ if (!_signal)
+ return -ENOMEM;
+
+ _signal_init(&_signal->signal, sdesc, &_signal_ops);
+
+ /*
+ * take another reference for the host. This is dropped
+ * by a SHMCLOSE event
+ */
+ shm_signal_get(&_signal->signal);
+
+ params.signal.offset = (u64)(unsigned long)sdesc -
+ (u64)(unsigned long)ptr;
+ params.signal.prio = prio;
+ params.signal.cookie = (u64)(unsigned long)_signal;
+
+ } else
+ params.signal.offset = -1; /* yes, this is a u32, but its ok */
+
+ ret = vbus_pci_buscall(VBUS_PCI_HC_DEVSHM,
+ &params, sizeof(params));
+ if (ret < 0)
+ goto fail;
+
+ if (signal) {
+
+ BUG_ON(ret < 0);
+
+ _signal->handle = ret;
+
+ if (!name)
+ snprintf(_signal->name, sizeof(_signal->name),
+ "dev%lld-id%d", vdev->id, id);
+ else
+ snprintf(_signal->name, sizeof(_signal->name),
+ "%s", name);
+
+ shmsignal_connect(_signal);
+
+ spin_lock_irqsave(&vbus_pci.lock, iflags);
+ list_add_tail(&_signal->list, &dev->shms);
+ spin_unlock_irqrestore(&vbus_pci.lock, iflags);
+
+ shm_signal_get(&_signal->signal);
+ *signal = &_signal->signal;
+ }
+
+ return 0;
+
+fail:
+ if (_signal) {
+ /*
+ * We held two references above, so we need to drop
+ * both of them
+ */
+ shm_signal_put(&_signal->signal);
+ shm_signal_put(&_signal->signal);
+ }
+
+ return ret;
+}
+
+static int
+vbus_pci_device_call(struct vbus_device_proxy *vdev, u32 func, void *data,
+ size_t len, int flags)
+{
+ struct vbus_pci_device *dev = to_dev(vdev);
+ struct vbus_pci_devicecall params = {
+ .devh = dev->handle,
+ .func = func,
+ .datap = (u64)__pa(data),
+ .len = len,
+ .flags = flags,
+ };
+
+ if (!dev->handle)
+ return -EINVAL;
+
+ return vbus_pci_buscall(VBUS_PCI_HC_DEVCALL, &params, sizeof(params));
+}
+
+static void
+vbus_pci_device_release(struct vbus_device_proxy *vdev)
+{
+ struct vbus_pci_device *_dev = to_dev(vdev);
+
+ vbus_pci_device_close(vdev, 0);
+
+ kfree(_dev);
+}
+
+static struct vbus_device_proxy_ops vbus_pci_device_ops = {
+ .open = vbus_pci_device_open,
+ .close = vbus_pci_device_close,
+ .shm = vbus_pci_device_shm,
+ .call = vbus_pci_device_call,
+ .release = vbus_pci_device_release,
+};
+
+/*
+ * -------------------
+ * vbus events
+ * -------------------
+ */
+
+struct deferred_devadd_event {
+ struct work_struct work;
+ struct vbus_pci_add_event event;
+};
+
+static void deferred_devdrop(struct work_struct *work);
+
+static void
+deferred_devadd(struct work_struct *work)
+{
+ struct deferred_devadd_event *_event;
+ struct vbus_pci_device *new;
+ int ret;
+
+ _event = container_of(work, struct deferred_devadd_event, work);
+
+ new = kzalloc(sizeof(*new), GFP_KERNEL);
+ if (!new) {
+ printk(KERN_ERR "VBUS_PCI: Out of memory on add_event\n");
+ return;
+ }
+
+ INIT_LIST_HEAD(&new->shms);
+
+ memcpy(new->type, _event->event.type, VBUS_MAX_DEVTYPE_LEN);
+ new->vdev.type = new->type;
+ new->vdev.id = _event->event.id;
+ new->vdev.ops = &vbus_pci_device_ops;
+
+ dev_set_name(&new->vdev.dev, "%lld", _event->event.id);
+
+ INIT_WORK(&new->drop, deferred_devdrop);
+
+ ret = vbus_device_proxy_register(&new->vdev);
+ if (ret < 0)
+ panic("failed to register device %lld(%s): %d\n",
+ new->vdev.id, new->type, ret);
+
+ kfree(_event);
+}
+
+static void
+deferred_devdrop(struct work_struct *work)
+{
+ struct vbus_pci_device *dev;
+
+ dev = container_of(work, struct vbus_pci_device, drop);
+ vbus_device_proxy_unregister(&dev->vdev);
+}
+
+static void
+event_devadd(struct vbus_pci_add_event *event)
+{
+ struct deferred_devadd_event *_event;
+
+ _event = kzalloc(sizeof(*_event), GFP_ATOMIC);
+ if (!_event) {
+ printk(KERN_ERR \
+ "VBUS_PCI: Out of ATOMIC memory on add_event\n");
+ return;
+ }
+
+ INIT_WORK(&_event->work, deferred_devadd);
+ memcpy(&_event->event, event, sizeof(*event));
+
+ schedule_work(&_event->work);
+}
+
+static void
+event_devdrop(struct vbus_pci_handle_event *event)
+{
+ struct vbus_device_proxy *dev = vbus_device_proxy_find(event->handle);
+
+ if (!dev) {
+ printk(KERN_WARNING "VBUS-PCI: devdrop failed: %lld\n",
+ event->handle);
+ return;
+ }
+
+ schedule_work(&to_dev(dev)->drop);
+}
+
+static void
+event_shmsignal(struct vbus_pci_handle_event *event)
+{
+ struct _signal *_signal = (struct _signal *)(unsigned long)event->handle;
+
+ vbus_pci.stats.notify++;
+
+ shmsignal_wakeup(_signal);
+}
+
+static void
+event_shmclose(struct vbus_pci_handle_event *event)
+{
+ struct _signal *_signal = (struct _signal *)(unsigned long)event->handle;
+
+ /*
+ * This reference was taken during the DEVICESHM call
+ */
+ shm_signal_put(&_signal->signal);
+}
+
+/*
+ * -------------------
+ * eventq routines
+ * -------------------
+ */
+
+static struct ioq_notifier eventq_notifier;
+
+static int __devinit
+eventq_init(int qlen)
+{
+ struct ioq_iterator iter;
+ int ret;
+ int i;
+
+ vbus_pci.ring = kzalloc(sizeof(struct vbus_pci_event) * qlen,
+ GFP_KERNEL);
+ if (!vbus_pci.ring)
+ return -ENOMEM;
+
+ /*
+ * We want to iterate on the "valid" index. By default the iterator
+ * will not "autoupdate" which means it will not hypercall the host
+ * with our changes. This is good, because we are really just
+ * initializing stuff here anyway. Note that you can always manually
+ * signal the host with ioq_signal() if the autoupdate feature is not
+ * used.
+ */
+ ret = ioq_iter_init(&vbus_pci.eventq, &iter, ioq_idxtype_valid, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Seek to the tail of the valid index (which should be our first
+ * item since the queue is brand-new)
+ */
+ ret = ioq_iter_seek(&iter, ioq_seek_tail, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * Now populate each descriptor with an empty vbus_event and mark it
+ * valid
+ */
+ for (i = 0; i < qlen; i++) {
+ struct vbus_pci_event *event = &vbus_pci.ring[i];
+ size_t len = sizeof(*event);
+ struct ioq_ring_desc *desc = iter.desc;
+
+ BUG_ON(iter.desc->valid);
+
+ desc->cookie = (u64)(unsigned long)event;
+ desc->ptr = cpu_to_le64(__pa(event));
+ desc->len = cpu_to_le64(len); /* total length */
+ desc->valid = 1;
+
+ /*
+ * This push operation will simultaneously advance the
+ * valid-tail index and increment our position in the queue
+ * by one.
+ */
+ ret = ioq_iter_push(&iter, 0);
+ BUG_ON(ret < 0);
+ }
+
+ vbus_pci.eventq.notifier = &eventq_notifier;
+
+ /*
+ * And finally, ensure that we can receive notification
+ */
+ ioq_notify_enable(&vbus_pci.eventq, 0);
+
+ return 0;
+}
+
+/* Invoked whenever the hypervisor ioq_signal()s our eventq */
+static void
+eventq_wakeup(struct ioq_notifier *notifier)
+{
+ struct ioq_iterator iter;
+ int ret;
+
+ /* We want to iterate on the head of the in-use index */
+ ret = ioq_iter_init(&vbus_pci.eventq, &iter, ioq_idxtype_inuse, 0);
+ BUG_ON(ret < 0);
+
+ ret = ioq_iter_seek(&iter, ioq_seek_head, 0, 0);
+ BUG_ON(ret < 0);
+
+ /*
+ * The EOM is indicated by finding a packet that is still owned by
+ * the south side.
+ *
+ * FIXME: This in theory could run indefinitely if the host keeps
+ * feeding us events since there is nothing like a NAPI budget. We
+ * might need to address that
+ */
+ while (!iter.desc->sown) {
+ struct ioq_ring_desc *desc = iter.desc;
+ struct vbus_pci_event *event;
+
+ event = (struct vbus_pci_event *)(unsigned long)desc->cookie;
+
+ switch (event->eventid) {
+ case VBUS_PCI_EVENT_DEVADD:
+ event_devadd(&event->data.add);
+ break;
+ case VBUS_PCI_EVENT_DEVDROP:
+ event_devdrop(&event->data.handle);
+ break;
+ case VBUS_PCI_EVENT_SHMSIGNAL:
+ event_shmsignal(&event->data.handle);
+ break;
+ case VBUS_PCI_EVENT_SHMCLOSE:
+ event_shmclose(&event->data.handle);
+ break;
+ default:
+ printk(KERN_WARNING "VBUS_PCI: Unexpected event %d\n",
+ event->eventid);
+ break;
+ };
+
+ memset(event, 0, sizeof(*event));
+
+ /* Advance the in-use head */
+ ret = ioq_iter_pop(&iter, 0);
+ BUG_ON(ret < 0);
+
+ vbus_pci.stats.events++;
+ }
+
+ /* And let the south side know that we changed the queue */
+ ioq_signal(&vbus_pci.eventq, 0);
+}
+
+static struct ioq_notifier eventq_notifier = {
+ .signal = &eventq_wakeup,
+};
+
+/* Injected whenever the host issues an ioq_signal() on the eventq */
+static irqreturn_t
+eventq_intr(int irq, void *dev)
+{
+ vbus_pci.stats.qnotify++;
+ _shm_signal_wakeup(vbus_pci.eventq.signal);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * -------------------
+ */
+
+static int
+eventq_signal_inject(struct shm_signal *signal)
+{
+ vbus_pci.stats.qinject++;
+
+ /* The eventq uses the special-case handle=0 */
+ iowrite32(0, &vbus_pci.signals->eventq);
+
+ return 0;
+}
+
+static void
+eventq_signal_release(struct shm_signal *signal)
+{
+ kfree(signal);
+}
+
+static struct shm_signal_ops eventq_signal_ops = {
+ .inject = eventq_signal_inject,
+ .release = eventq_signal_release,
+};
+
+/*
+ * -------------------
+ */
+
+static void
+eventq_ioq_release(struct ioq *ioq)
+{
+ /* released as part of the vbus_pci object */
+}
+
+static struct ioq_ops eventq_ioq_ops = {
+ .release = eventq_ioq_release,
+};
+
+/*
+ * -------------------
+ */
+
+static void
+vbus_pci_release(void)
+{
+#ifdef CONFIG_DEBUG_FS
+ if (vbus_pci.stats.fs)
+ debugfs_remove(vbus_pci.stats.fs);
+#endif
+
+ if (vbus_pci.irq > 0)
+ free_irq(vbus_pci.irq, NULL);
+
+ if (vbus_pci.signals)
+ pci_iounmap(vbus_pci.dev, (void *)vbus_pci.signals);
+
+ if (vbus_pci.regs)
+ pci_iounmap(vbus_pci.dev, (void *)vbus_pci.regs);
+
+ pci_release_regions(vbus_pci.dev);
+ pci_disable_device(vbus_pci.dev);
+
+ kfree(vbus_pci.eventq.head_desc);
+ kfree(vbus_pci.ring);
+
+ vbus_pci.enabled = false;
+}
+
+static int __devinit
+vbus_pci_open(void)
+{
+ struct vbus_pci_bridge_negotiate params = {
+ .magic = VBUS_PCI_ABI_MAGIC,
+ .version = VBUS_PCI_HC_VERSION,
+ .capabilities = 0,
+ };
+
+ return vbus_pci_bridgecall(VBUS_PCI_BRIDGE_NEGOTIATE,
+ &params, sizeof(params));
+}
+
+#define QLEN 1024
+
+static int __devinit
+vbus_pci_eventq_register(void)
+{
+ struct vbus_pci_busreg params = {
+ .count = 1,
+ .eventq = {
+ {
+ .count = QLEN,
+ .ring = (u64)__pa(vbus_pci.eventq.head_desc),
+ .data = (u64)__pa(vbus_pci.ring),
+ },
+ },
+ };
+
+ return vbus_pci_bridgecall(VBUS_PCI_BRIDGE_QREG,
+ &params, sizeof(params));
+}
+
+static int __devinit
+_ioq_init(size_t ringsize, struct ioq *ioq, struct ioq_ops *ops)
+{
+ struct shm_signal *signal = NULL;
+ struct ioq_ring_head *head = NULL;
+ size_t len = IOQ_HEAD_DESC_SIZE(ringsize);
+
+ head = kzalloc(len, GFP_KERNEL | GFP_DMA);
+ if (!head)
+ return -ENOMEM;
+
+ signal = kzalloc(sizeof(*signal), GFP_KERNEL);
+ if (!signal) {
+ kfree(head);
+ return -ENOMEM;
+ }
+
+ head->magic = IOQ_RING_MAGIC;
+ head->ver = IOQ_RING_VER;
+ head->count = cpu_to_le32(ringsize);
+
+ _signal_init(signal, &head->signal, &eventq_signal_ops);
+
+ ioq_init(ioq, ops, ioq_locality_north, head, signal, ringsize);
+
+ return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int _debugfs_seq_show(struct seq_file *m, void *p)
+{
+#define P(F) \
+ seq_printf(m, " .%-30s: %d\n", #F, (int)vbus_pci.stats.F)
+
+ P(events);
+ P(qnotify);
+ P(qinject);
+ P(notify);
+ P(inject);
+ P(bridgecalls);
+ P(buscalls);
+
+#undef P
+
+ return 0;
+}
+
+static int _debugfs_fops_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, _debugfs_seq_show, inode->i_private);
+}
+
+static const struct file_operations stat_fops = {
+ .open = _debugfs_fops_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+#endif
+
+static int __devinit
+vbus_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ret;
+ int cpu;
+
+ if (vbus_pci.enabled)
+ return -EEXIST; /* we only support one bridge per kernel */
+
+ if (pdev->revision != VBUS_PCI_ABI_VERSION) {
+ printk(KERN_DEBUG "VBUS_PCI: expected ABI version %d, got %d\n",
+ VBUS_PCI_ABI_VERSION,
+ pdev->revision);
+ return -ENODEV;
+ }
+
+ vbus_pci.dev = pdev;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ return ret;
+
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, VBUS_PCI_NAME);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Could not init BARs: %d\n", ret);
+ goto out_fail;
+ }
+
+ vbus_pci.regs = pci_iomap(pdev, 0, sizeof(struct vbus_pci_regs));
+ if (!vbus_pci.regs) {
+ printk(KERN_ERR "VBUS_PCI: Could not map BARs\n");
+ goto out_fail;
+ }
+
+ vbus_pci.signals = pci_iomap(pdev, 1, sizeof(struct vbus_pci_signals));
+ if (!vbus_pci.signals) {
+ printk(KERN_ERR "VBUS_PCI: Could not map BARs\n");
+ goto out_fail;
+ }
+
+ ret = vbus_pci_open();
+ if (ret < 0) {
+ printk(KERN_DEBUG "VBUS_PCI: Could not register with host: %d\n",
+ ret);
+ goto out_fail;
+ }
+
+ /*
+ * Allocate an IOQ to use for host-2-guest event notification
+ */
+ ret = _ioq_init(QLEN, &vbus_pci.eventq, &eventq_ioq_ops);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not init eventq: %d\n", ret);
+ goto out_fail;
+ }
+
+ ret = eventq_init(QLEN);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not setup ring: %d\n", ret);
+ goto out_fail;
+ }
+
+ ret = pci_enable_msi(pdev);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Cound not enable MSI: %d\n", ret);
+ goto out_fail;
+ }
+
+ vbus_pci.irq = pdev->irq;
+
+ ret = request_irq(pdev->irq, eventq_intr, 0, "vbus", NULL);
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Failed to register IRQ %d\n: %d",
+ pdev->irq, ret);
+ goto out_fail;
+ }
+
+ /*
+ * Add one fastcall vector per cpu so that we can do lockless
+ * hypercalls
+ */
+ for_each_possible_cpu(cpu) {
+ struct vbus_pci_fastcall_desc *desc =
+ &per_cpu(vbus_pci_percpu_fastcall, cpu);
+ struct vbus_pci_call_desc params = {
+ .vector = cpu,
+ .len = sizeof(*desc),
+ .datap = __pa(desc),
+ };
+
+ ret = vbus_pci_bridgecall(VBUS_PCI_BRIDGE_FASTCALL_ADD,
+ &params, sizeof(params));
+ if (ret < 0) {
+ printk(KERN_ERR \
+ "VBUS_PCI: Failed to register cpu:%d\n: %d",
+ cpu, ret);
+ goto out_fail;
+ }
+ }
+
+ /*
+ * Finally register our queue on the host to start receiving events
+ */
+ ret = vbus_pci_eventq_register();
+ if (ret < 0) {
+ printk(KERN_ERR "VBUS_PCI: Could not register with host: %d\n",
+ ret);
+ goto out_fail;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ vbus_pci.stats.fs = debugfs_create_file(VBUS_PCI_NAME, S_IRUGO,
+ NULL, NULL, &stat_fops);
+ if (IS_ERR(vbus_pci.stats.fs)) {
+ ret = PTR_ERR(vbus_pci.stats.fs);
+ printk(KERN_ERR "VBUS_PCI: error creating stats-fs: %d\n", ret);
+ goto out_fail;
+ }
+#endif
+
+ vbus_pci.enabled = true;
+
+ printk(KERN_INFO "Virtual-Bus: Copyright (c) 2009, " \
+ "Gregory Haskins <ghaskins@novell.com>\n");
+
+ return 0;
+
+ out_fail:
+ vbus_pci_release();
+
+ return ret;
+}
+
+static void __devexit
+vbus_pci_remove(struct pci_dev *pdev)
+{
+ vbus_pci_release();
+}
+
+static DEFINE_PCI_DEVICE_TABLE(vbus_pci_tbl) = {
+ { PCI_DEVICE(0x11da, 0x2000) },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, vbus_pci_tbl);
+
+static struct pci_driver vbus_pci_driver = {
+ .name = VBUS_PCI_NAME,
+ .id_table = vbus_pci_tbl,
+ .probe = vbus_pci_probe,
+ .remove = vbus_pci_remove,
+};
+
+static int __init
+vbus_pci_init(void)
+{
+ memset(&vbus_pci, 0, sizeof(vbus_pci));
+ spin_lock_init(&vbus_pci.lock);
+
+ return pci_register_driver(&vbus_pci_driver);
+}
+
+static void __exit
+vbus_pci_exit(void)
+{
+ pci_unregister_driver(&vbus_pci_driver);
+}
+
+module_init(vbus_pci_init);
+module_exit(vbus_pci_exit);
+
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 0f41c9195e9b..4c218e910635 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -519,13 +519,12 @@ static long vhost_net_set_backend(struct vhost_net *n, unsigned index, int fd)
/* start polling new socket */
oldsock = vq->private_data;
- if (sock == oldsock)
- goto done;
+ if (sock != oldsock){
+ vhost_net_disable_vq(n, vq);
+ rcu_assign_pointer(vq->private_data, sock);
+ vhost_net_enable_vq(n, vq);
+ }
- vhost_net_disable_vq(n, vq);
- rcu_assign_pointer(vq->private_data, sock);
- vhost_net_enable_vq(n, vq);
-done:
if (oldsock) {
vhost_net_flush_vq(n, index);
fput(oldsock->file);
@@ -626,7 +625,7 @@ static long vhost_net_compat_ioctl(struct file *f, unsigned int ioctl,
}
#endif
-const static struct file_operations vhost_net_fops = {
+static const struct file_operations vhost_net_fops = {
.owner = THIS_MODULE,
.release = vhost_net_release,
.unlocked_ioctl = vhost_net_ioctl,
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index 3b83382e06eb..04344b711c56 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -237,8 +237,8 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
{
int i;
- if (!mem)
- return 0;
+ if (!mem)
+ return 0;
for (i = 0; i < mem->nregions; ++i) {
struct vhost_memory_region *m = mem->regions + i;
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 1e6fec487973..a9f9e5eaa040 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -8,6 +8,9 @@ menu "Graphics support"
config HAVE_FB_ATMEL
bool
+config HAVE_FB_IMX
+ bool
+
source "drivers/char/agp/Kconfig"
source "drivers/gpu/vga/Kconfig"
@@ -400,9 +403,6 @@ config FB_SA1100
If you plan to use the LCD display with your SA-1100 system, say
Y here.
-config HAVE_FB_IMX
- bool
-
config FB_IMX
tristate "Motorola i.MX LCD support"
depends on FB && (HAVE_FB_IMX || ARCH_MX1 || ARCH_MX2)
@@ -1895,6 +1895,13 @@ config FB_W100
If unsure, say N.
+config SH_MIPI_DSI
+ tristate
+ depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+
+config SH_LCD_MIPI_DSI
+ bool
+
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
@@ -1903,6 +1910,7 @@ config FB_SH_MOBILE_LCDC
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
+ select SH_MIPI_DSI if SH_LCD_MIPI_DSI
---help---
Frame buffer driver for the on-chip SH-Mobile LCD controller.
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ddc2af2ba45b..3c3bf867ef18 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -123,6 +123,7 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
+obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index 51fcc0a2c94a..e45833ce975b 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -242,7 +242,7 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
- u32 color = rect->color, dx = rect->dx, width = rect->width, rotation = 0;
+ u32 color, dx = rect->dx, width = rect->width, rotation = 0;
if (par->asleep)
return;
@@ -253,8 +253,11 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
return;
}
- color |= (rect->color << 8);
- color |= (rect->color << 16);
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR)
+ color = ((u32 *)(info->pseudo_palette))[rect->color];
+ else
+ color = rect->color;
if (info->var.bits_per_pixel == 24) {
/* In 24 bpp, the engine is in 8 bpp - this requires that all */
diff --git a/drivers/video/backlight/adp8860_bl.c b/drivers/video/backlight/adp8860_bl.c
index 921ca37398f3..3ec24609151e 100644
--- a/drivers/video/backlight/adp8860_bl.c
+++ b/drivers/video/backlight/adp8860_bl.c
@@ -756,7 +756,6 @@ out:
out1:
backlight_device_unregister(bl);
out2:
- i2c_set_clientdata(client, NULL);
kfree(data);
return ret;
@@ -776,7 +775,6 @@ static int __devexit adp8860_remove(struct i2c_client *client)
&adp8860_bl_attr_group);
backlight_device_unregister(data->bl);
- i2c_set_clientdata(client, NULL);
kfree(data);
return 0;
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index e03e60bbfd85..2a04b382ec48 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -119,7 +119,6 @@ static int __devinit tosa_bl_probe(struct i2c_client *client,
err_reg:
data->bl = NULL;
- i2c_set_clientdata(client, NULL);
err_gpio_dir:
gpio_free(TOSA_GPIO_BL_C20MA);
err_gpio_bl:
@@ -133,7 +132,6 @@ static int __devexit tosa_bl_remove(struct i2c_client *client)
backlight_device_unregister(data->bl);
data->bl = NULL;
- i2c_set_clientdata(client, NULL);
gpio_free(TOSA_GPIO_BL_C20MA);
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 2c371c07f0da..09f1b9b462f4 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -275,7 +275,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par,
static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct bw2_par *par;
int linebytes, err;
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index d12e05b6e63f..e5dc2241194f 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -465,7 +465,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct cg14_par *par;
int is_8mb, linebytes, i, err;
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index b98f93f7f663..558d73a948a0 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -349,7 +349,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par)
static int __devinit cg3_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct cg3_par *par;
int linebytes, err;
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index 073c9b408cf7..6b93ef93cb12 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -100,6 +100,16 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma,
/* protect against the workqueue changing the page list */
mutex_lock(&fbdefio->lock);
+ /*
+ * We want the page to remain locked from ->page_mkwrite until
+ * the PTE is marked dirty to avoid page_mkclean() being called
+ * before the PTE is updated, which would leave the page ignored
+ * by defio.
+ * Do this by locking the page here and informing the caller
+ * about it with VM_FAULT_LOCKED.
+ */
+ lock_page(page);
+
/* we loop through the pagelist before adding in order
to keep the pagelist sorted */
list_for_each_entry(cur, &fbdefio->pagelist, lru) {
@@ -121,7 +131,7 @@ page_already_added:
/* come back after delay to process the deferred IO */
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
- return 0;
+ return VM_FAULT_LOCKED;
}
static const struct vm_operations_struct fb_deferred_io_vm_ops = {
@@ -155,41 +165,25 @@ static void fb_deferred_io_work(struct work_struct *work)
{
struct fb_info *info = container_of(work, struct fb_info,
deferred_work.work);
+ struct list_head *node, *next;
+ struct page *cur;
struct fb_deferred_io *fbdefio = info->fbdefio;
- struct page *page, *tmp_page;
- struct list_head *node, *tmp_node;
- struct list_head non_dirty;
-
- INIT_LIST_HEAD(&non_dirty);
/* here we mkclean the pages, then do all deferred IO */
mutex_lock(&fbdefio->lock);
- list_for_each_entry_safe(page, tmp_page, &fbdefio->pagelist, lru) {
- lock_page(page);
- /*
- * The workqueue callback can be triggered after a
- * ->page_mkwrite() call but before the PTE has been marked
- * dirty. In this case page_mkclean() won't "rearm" the page.
- *
- * To avoid this, remove those "non-dirty" pages from the
- * pagelist before calling the driver's callback, then add
- * them back to get processed on the next work iteration.
- * At that time, their PTEs will hopefully be dirty for real.
- */
- if (!page_mkclean(page))
- list_move_tail(&page->lru, &non_dirty);
- unlock_page(page);
+ list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+ lock_page(cur);
+ page_mkclean(cur);
+ unlock_page(cur);
}
/* driver's callback with pagelist */
fbdefio->deferred_io(info, &fbdefio->pagelist);
- /* clear the list... */
- list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
+ /* clear the list */
+ list_for_each_safe(node, next, &fbdefio->pagelist) {
list_del(node);
}
- /* ... and add back the "non-dirty" pages to the list */
- list_splice_tail(&non_dirty, &fbdefio->pagelist);
mutex_unlock(&fbdefio->lock);
}
@@ -218,7 +212,6 @@ EXPORT_SYMBOL_GPL(fb_deferred_io_open);
void fb_deferred_io_cleanup(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
- struct list_head *node, *tmp_node;
struct page *page;
int i;
@@ -226,13 +219,6 @@ void fb_deferred_io_cleanup(struct fb_info *info)
cancel_delayed_work(&info->deferred_work);
flush_scheduled_work();
- /* the list may have still some non-dirty pages at this point */
- mutex_lock(&fbdefio->lock);
- list_for_each_safe(node, tmp_node, &fbdefio->pagelist) {
- list_del(node);
- }
- mutex_unlock(&fbdefio->lock);
-
/* clear out the mapping that we setup */
for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {
page = fb_deferred_io_page(info, i);
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index 3d7895316eaf..9e8bf7d5e249 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -550,7 +550,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit leo_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct leo_par *par;
int linebytes, err;
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index 0540de4f5cb4..4e2b8cc3d460 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -553,7 +553,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par)
static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
const struct of_device_id *id)
{
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct device *dev = &ofdev->dev;
struct mb862xxfb_par *par;
struct fb_info *info;
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index c85dd408a9b8..6552751e81aa 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -251,7 +251,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no
static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct p9100_par *par;
int linebytes, err;
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c
new file mode 100644
index 000000000000..017ae9f47d36
--- /dev/null
+++ b/drivers/video/sh_mipi_dsi.c
@@ -0,0 +1,505 @@
+/*
+ * Renesas SH-mobile MIPI DSI support
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <video/mipi_display.h>
+#include <video/sh_mipi_dsi.h>
+#include <video/sh_mobile_lcdc.h>
+
+#define CMTSRTCTR 0x80d0
+#define CMTSRTREQ 0x8070
+
+#define DSIINTE 0x0060
+
+/* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
+#define MAX_SH_MIPI_DSI 2
+
+struct sh_mipi {
+ void __iomem *base;
+ struct clk *dsit_clk;
+ struct clk *dsip_clk;
+};
+
+static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
+
+/* Protect the above array */
+static DEFINE_MUTEX(array_lock);
+
+static struct sh_mipi *sh_mipi_by_handle(int handle)
+{
+ if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
+ return NULL;
+
+ return mipi_dsi[handle];
+}
+
+static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
+ u8 cmd, u8 param)
+{
+ u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
+ int cnt = 100;
+
+ /* transmit a short packet to LCD panel */
+ iowrite32(1 | data, mipi->base + 0x80d0); /* CMTSRTCTR */
+ iowrite32(1, mipi->base + 0x8070); /* CMTSRTREQ */
+
+ while ((ioread32(mipi->base + 0x8070) & 1) && --cnt)
+ udelay(1);
+
+ return cnt ? 0 : -ETIMEDOUT;
+}
+
+#define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
+ -EINVAL : (c) - 1)
+
+static int sh_mipi_dcs(int handle, u8 cmd)
+{
+ struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
+ if (!mipi)
+ return -ENODEV;
+ return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
+}
+
+static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
+{
+ struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
+ if (!mipi)
+ return -ENODEV;
+ return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
+ param);
+}
+
+static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
+{
+ /*
+ * enable LCDC data tx, transition to LPS after completion of each HS
+ * packet
+ */
+ iowrite32(0x00000002 | enable, mipi->base + 0x8000); /* DTCTR */
+}
+
+static void sh_mipi_shutdown(struct platform_device *pdev)
+{
+ struct sh_mipi *mipi = platform_get_drvdata(pdev);
+
+ sh_mipi_dsi_enable(mipi, false);
+}
+
+static void mipi_display_on(void *arg)
+{
+ struct sh_mipi *mipi = arg;
+
+ sh_mipi_dsi_enable(mipi, true);
+}
+
+static void mipi_display_off(void *arg)
+{
+ struct sh_mipi *mipi = arg;
+
+ sh_mipi_dsi_enable(mipi, false);
+}
+
+static int __init sh_mipi_setup(struct sh_mipi *mipi,
+ struct sh_mipi_dsi_info *pdata)
+{
+ void __iomem *base = mipi->base;
+ struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
+ u32 pctype, datatype, pixfmt;
+ u32 linelength;
+ bool yuv;
+
+ /* Select data format */
+ switch (pdata->data_format) {
+ case MIPI_RGB888:
+ pctype = 0;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+ pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
+ linelength = ch->lcd_cfg.xres * 3;
+ yuv = false;
+ break;
+ case MIPI_RGB565:
+ pctype = 1;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+ pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
+ linelength = ch->lcd_cfg.xres * 2;
+ yuv = false;
+ break;
+ case MIPI_RGB666_LP:
+ pctype = 2;
+ datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+ pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
+ linelength = ch->lcd_cfg.xres * 3;
+ yuv = false;
+ break;
+ case MIPI_RGB666:
+ pctype = 3;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+ pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
+ linelength = (ch->lcd_cfg.xres * 18 + 7) / 8;
+ yuv = false;
+ break;
+ case MIPI_BGR888:
+ pctype = 8;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
+ pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
+ linelength = ch->lcd_cfg.xres * 3;
+ yuv = false;
+ break;
+ case MIPI_BGR565:
+ pctype = 9;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
+ pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
+ linelength = ch->lcd_cfg.xres * 2;
+ yuv = false;
+ break;
+ case MIPI_BGR666_LP:
+ pctype = 0xa;
+ datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
+ pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
+ linelength = ch->lcd_cfg.xres * 3;
+ yuv = false;
+ break;
+ case MIPI_BGR666:
+ pctype = 0xb;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
+ pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
+ linelength = (ch->lcd_cfg.xres * 18 + 7) / 8;
+ yuv = false;
+ break;
+ case MIPI_YUYV:
+ pctype = 4;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
+ pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
+ linelength = ch->lcd_cfg.xres * 2;
+ yuv = true;
+ break;
+ case MIPI_UYVY:
+ pctype = 5;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
+ pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
+ linelength = ch->lcd_cfg.xres * 2;
+ yuv = true;
+ break;
+ case MIPI_YUV420_L:
+ pctype = 6;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
+ pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
+ linelength = (ch->lcd_cfg.xres * 12 + 7) / 8;
+ yuv = true;
+ break;
+ case MIPI_YUV420:
+ pctype = 7;
+ datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
+ pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
+ /* Length of U/V line */
+ linelength = (ch->lcd_cfg.xres + 1) / 2;
+ yuv = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if ((yuv && ch->interface_type != YUV422) ||
+ (!yuv && ch->interface_type != RGB24))
+ return -EINVAL;
+
+ /* reset DSI link */
+ iowrite32(0x00000001, base); /* SYSCTRL */
+ /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
+ udelay(50);
+ iowrite32(0x00000000, base); /* SYSCTRL */
+
+ /* setup DSI link */
+
+ /*
+ * Default = ULPS enable |
+ * Contention detection enabled |
+ * EoT packet transmission enable |
+ * CRC check enable |
+ * ECC check enable
+ * additionally enable first two lanes
+ */
+ iowrite32(0x00003703, base + 0x04); /* SYSCONF */
+ /*
+ * T_wakeup = 0x7000
+ * T_hs-trail = 3
+ * T_hs-prepare = 3
+ * T_clk-trail = 3
+ * T_clk-prepare = 2
+ */
+ iowrite32(0x70003332, base + 0x08); /* TIMSET */
+ /* no responses requested */
+ iowrite32(0x00000000, base + 0x18); /* RESREQSET0 */
+ /* request response to packets of type 0x28 */
+ iowrite32(0x00000100, base + 0x1c); /* RESREQSET1 */
+ /* High-speed transmission timeout, default 0xffffffff */
+ iowrite32(0x0fffffff, base + 0x20); /* HSTTOVSET */
+ /* LP reception timeout, default 0xffffffff */
+ iowrite32(0x0fffffff, base + 0x24); /* LPRTOVSET */
+ /* Turn-around timeout, default 0xffffffff */
+ iowrite32(0x0fffffff, base + 0x28); /* TATOVSET */
+ /* Peripheral reset timeout, default 0xffffffff */
+ iowrite32(0x0fffffff, base + 0x2c); /* PRTOVSET */
+ /* Enable timeout counters */
+ iowrite32(0x00000f00, base + 0x30); /* DSICTRL */
+ /* Interrupts not used, disable all */
+ iowrite32(0, base + DSIINTE);
+ /* DSI-Tx bias on */
+ iowrite32(0x00000001, base + 0x70); /* PHYCTRL */
+ udelay(200);
+ /* Deassert resets, power on, set multiplier */
+ iowrite32(0x03070b01, base + 0x70); /* PHYCTRL */
+
+ /* setup l-bridge */
+
+ /*
+ * Enable transmission of all packets,
+ * transmit LPS after each HS packet completion
+ */
+ iowrite32(0x00000006, base + 0x8000); /* DTCTR */
+ /* VSYNC width = 2 (<< 17) */
+ iowrite32(0x00040000 | (pctype << 12) | datatype, base + 0x8020); /* VMCTR1 */
+ /*
+ * Non-burst mode with sync pulses: VSE and HSE are output,
+ * HSA period allowed, no commands in LP
+ */
+ iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */
+ /*
+ * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see
+ * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default
+ * (unused, since VMCTR2[HSABM] = 0)
+ */
+ iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */
+
+ msleep(5);
+
+ /* setup LCD panel */
+
+ /* cf. drivers/video/omap/lcd_mipid.c */
+ sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(120);
+ /*
+ * [7] - Page Address Mode
+ * [6] - Column Address Mode
+ * [5] - Page / Column Address Mode
+ * [4] - Display Device Line Refresh Order
+ * [3] - RGB/BGR Order
+ * [2] - Display Data Latch Data Order
+ * [1] - Flip Horizontal
+ * [0] - Flip Vertical
+ */
+ sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
+ /* cf. set_data_lines() */
+ sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT,
+ pixfmt << 4);
+ sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
+
+ return 0;
+}
+
+static int __init sh_mipi_probe(struct platform_device *pdev)
+{
+ struct sh_mipi *mipi;
+ struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ unsigned long rate, f_current;
+ int idx = pdev->id, ret;
+ char dsip_clk[] = "dsi.p_clk";
+
+ if (!res || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
+ return -ENODEV;
+
+ mutex_lock(&array_lock);
+ if (idx < 0)
+ for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
+ ;
+
+ if (idx == ARRAY_SIZE(mipi_dsi)) {
+ ret = -EBUSY;
+ goto efindslot;
+ }
+
+ mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
+ if (!mipi) {
+ ret = -ENOMEM;
+ goto ealloc;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "MIPI register region already claimed\n");
+ ret = -EBUSY;
+ goto ereqreg;
+ }
+
+ mipi->base = ioremap(res->start, resource_size(res));
+ if (!mipi->base) {
+ ret = -ENOMEM;
+ goto emap;
+ }
+
+ mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
+ if (IS_ERR(mipi->dsit_clk)) {
+ ret = PTR_ERR(mipi->dsit_clk);
+ goto eclktget;
+ }
+
+ f_current = clk_get_rate(mipi->dsit_clk);
+ /* 80MHz required by the datasheet */
+ rate = clk_round_rate(mipi->dsit_clk, 80000000);
+ if (rate > 0 && rate != f_current)
+ ret = clk_set_rate(mipi->dsit_clk, rate);
+ else
+ ret = rate;
+ if (ret < 0)
+ goto esettrate;
+
+ dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
+
+ sprintf(dsip_clk, "dsi%1.1dp_clk", idx);
+ mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk);
+ if (IS_ERR(mipi->dsip_clk)) {
+ ret = PTR_ERR(mipi->dsip_clk);
+ goto eclkpget;
+ }
+
+ f_current = clk_get_rate(mipi->dsip_clk);
+ /* Between 10 and 50MHz */
+ rate = clk_round_rate(mipi->dsip_clk, 24000000);
+ if (rate > 0 && rate != f_current)
+ ret = clk_set_rate(mipi->dsip_clk, rate);
+ else
+ ret = rate;
+ if (ret < 0)
+ goto esetprate;
+
+ dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate);
+
+ msleep(10);
+
+ ret = clk_enable(mipi->dsit_clk);
+ if (ret < 0)
+ goto eclkton;
+
+ ret = clk_enable(mipi->dsip_clk);
+ if (ret < 0)
+ goto eclkpon;
+
+ mipi_dsi[idx] = mipi;
+
+ ret = sh_mipi_setup(mipi, pdata);
+ if (ret < 0)
+ goto emipisetup;
+
+ mutex_unlock(&array_lock);
+ platform_set_drvdata(pdev, mipi);
+
+ /* Set up LCDC callbacks */
+ pdata->lcd_chan->board_cfg.board_data = mipi;
+ pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
+ pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
+
+ return 0;
+
+emipisetup:
+ mipi_dsi[idx] = NULL;
+ clk_disable(mipi->dsip_clk);
+eclkpon:
+ clk_disable(mipi->dsit_clk);
+eclkton:
+esetprate:
+ clk_put(mipi->dsip_clk);
+eclkpget:
+esettrate:
+ clk_put(mipi->dsit_clk);
+eclktget:
+ iounmap(mipi->base);
+emap:
+ release_mem_region(res->start, resource_size(res));
+ereqreg:
+ kfree(mipi);
+ealloc:
+efindslot:
+ mutex_unlock(&array_lock);
+
+ return ret;
+}
+
+static int __exit sh_mipi_remove(struct platform_device *pdev)
+{
+ struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct sh_mipi *mipi = platform_get_drvdata(pdev);
+ int i, ret;
+
+ mutex_lock(&array_lock);
+
+ for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
+ ;
+
+ if (i == ARRAY_SIZE(mipi_dsi)) {
+ ret = -EINVAL;
+ } else {
+ ret = 0;
+ mipi_dsi[i] = NULL;
+ }
+
+ mutex_unlock(&array_lock);
+
+ if (ret < 0)
+ return ret;
+
+ pdata->lcd_chan->board_cfg.display_on = NULL;
+ pdata->lcd_chan->board_cfg.display_off = NULL;
+ pdata->lcd_chan->board_cfg.board_data = NULL;
+
+ clk_disable(mipi->dsip_clk);
+ clk_disable(mipi->dsit_clk);
+ clk_put(mipi->dsit_clk);
+ clk_put(mipi->dsip_clk);
+ iounmap(mipi->base);
+ if (res)
+ release_mem_region(res->start, resource_size(res));
+ platform_set_drvdata(pdev, NULL);
+ kfree(mipi);
+
+ return 0;
+}
+
+static struct platform_driver sh_mipi_driver = {
+ .remove = __exit_p(sh_mipi_remove),
+ .shutdown = sh_mipi_shutdown,
+ .driver = {
+ .name = "sh-mipi-dsi",
+ },
+};
+
+static int __init sh_mipi_init(void)
+{
+ return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
+}
+module_init(sh_mipi_init);
+
+static void __exit sh_mipi_exit(void)
+{
+ platform_driver_unregister(&sh_mipi_driver);
+}
+module_exit(sh_mipi_exit);
+
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index e8c769944812..12c451a711e9 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -991,13 +991,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
priv->ch[j].lcdc = priv;
memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i]));
- error = sh_mobile_lcdc_check_interface(&priv->ch[i]);
+ error = sh_mobile_lcdc_check_interface(&priv->ch[j]);
if (error) {
dev_err(&pdev->dev, "unsupported interface type\n");
goto err1;
}
- init_waitqueue_head(&priv->ch[i].frame_end_wait);
- init_completion(&priv->ch[i].vsync_completion);
+ init_waitqueue_head(&priv->ch[j].frame_end_wait);
+ init_completion(&priv->ch[j].vsync_completion);
priv->ch[j].pan_offset = 0;
switch (pdata->ch[i].chan) {
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index ef7a7bd8b503..cc039b33d2d8 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -365,7 +365,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
static int __devinit tcx_probe(struct of_device *op,
const struct of_device_id *match)
{
- struct device_node *dp = op->node;
+ struct device_node *dp = op->dev.of_node;
struct fb_info *info;
struct tcx_par *par;
int linebytes, i, err;
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 7b8839ebf3c4..52ec0959d462 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -1977,8 +1977,7 @@ static void __devexit uvesafb_exit(void)
module_exit(uvesafb_exit);
-#define param_get_scroll NULL
-static int param_set_scroll(const char *val, struct kernel_param *kp)
+static int param_set_scroll(const char *val, const struct kernel_param *kp)
{
ypan = 0;
@@ -1993,7 +1992,9 @@ static int param_set_scroll(const char *val, struct kernel_param *kp)
return 0;
}
-
+static struct kernel_param_ops param_ops_scroll = {
+ .set = param_set_scroll,
+};
#define param_check_scroll(name, p) __param_check(name, p, void)
module_param_named(scroll, ypan, scroll, 0);
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index e44893ea590d..04bec058569c 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -370,7 +370,7 @@ int viafb_init_engine(struct fb_info *info)
viapar->shared->vq_vram_addr = viapar->fbmem_free;
viapar->fbmem_used += VQ_SIZE;
-#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
/*
* Set aside a chunk of framebuffer memory for the camera
* driver. Someday this driver probably needs a proper allocator
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c
index e8cfe8392110..2433259e9ea6 100644
--- a/drivers/video/via/via-core.c
+++ b/drivers/video/via/via-core.c
@@ -95,6 +95,13 @@ EXPORT_SYMBOL_GPL(viafb_irq_disable);
/* ---------------------------------------------------------------------- */
/*
+ * Currently, the camera driver is the only user of the DMA code, so we
+ * only compile it in if the camera driver is being built. Chances are,
+ * most viafb systems will not need to have this extra code for a while.
+ * As soon as another user comes long, the ifdef can be removed.
+ */
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
+/*
* Access to the DMA engine. This currently provides what the camera
* driver needs (i.e. outgoing only) but is easily expandable if need
* be.
@@ -322,7 +329,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg)
return 0;
}
EXPORT_SYMBOL_GPL(viafb_dma_copy_out_sg);
-
+#endif /* CONFIG_VIDEO_VIA_CAMERA */
/* ---------------------------------------------------------------------- */
/*
@@ -507,7 +514,12 @@ static struct viafb_subdev_info {
},
{
.name = "viafb-i2c",
- }
+ },
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
+ {
+ .name = "viafb-camera",
+ },
+#endif
};
#define N_SUBDEVS ARRAY_SIZE(viafb_subdevs)
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index d31dc96f838a..85d76ec4c63e 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -726,7 +726,9 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
/* Prepare startup mode */
+ kparam_block_sysfs_write(mode_option);
rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
+ kparam_unblock_sysfs_write(mode_option);
if (! ((rc == 1) || (rc == 2))) {
rc = -EINVAL;
dev_err(info->device, "mode %s not found\n", mode_option);
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index ca0f4c6cf5ab..1df284f9c2a1 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -273,7 +273,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev,
bus_clk = freq;
/* Map devices registers into memory */
- gef_wdt_regs = of_iomap(dev->node, 0);
+ gef_wdt_regs = of_iomap(dev->dev.of_node, 0);
if (gef_wdt_regs == NULL)
return -ENOMEM;
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 809e7167a624..dbe650e6537d 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -49,6 +49,10 @@
#define ROM_SIZE 0x10000
#define HPWDT_VERSION "1.1.1"
+#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
+#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
+#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
+
struct bios32_service_dir {
u32 signature;
u32 entry_point;
@@ -420,7 +424,7 @@ static int __devinit detect_cru_service(void)
*/
static void hpwdt_start(void)
{
- reload = (soft_margin * 1000) / 128;
+ reload = SECS_TO_TICKS(soft_margin);
iowrite16(reload, hpwdt_timer_reg);
iowrite16(0x85, hpwdt_timer_con);
}
@@ -439,10 +443,14 @@ static void hpwdt_ping(void)
iowrite16(reload, hpwdt_timer_reg);
}
+static int hpwdt_time_left(void)
+{
+ return TICKS_TO_SECS(ioread16(hpwdt_timer_reg));
+}
+
static int hpwdt_change_timer(int new_margin)
{
- /* Arbitrary, can't find the card's limits */
- if (new_margin < 5 || new_margin > 600) {
+ if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) {
printk(KERN_WARNING
"hpwdt: New value passed in is invalid: %d seconds.\n",
new_margin);
@@ -453,7 +461,7 @@ static int hpwdt_change_timer(int new_margin)
printk(KERN_DEBUG
"hpwdt: New timer passed in is %d seconds.\n",
new_margin);
- reload = (soft_margin * 1000) / 128;
+ reload = SECS_TO_TICKS(soft_margin);
return 0;
}
@@ -580,6 +588,10 @@ static long hpwdt_ioctl(struct file *file, unsigned int cmd,
ret = put_user(0, p);
break;
+ case WDIOC_GETTIMELEFT:
+ ret = put_user(hpwdt_time_left(), p);
+ break;
+
case WDIOC_KEEPALIVE:
hpwdt_ping();
ret = 0;
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c
index 6622335773bb..4cda64dd309c 100644
--- a/drivers/watchdog/mpc8xxx_wdt.c
+++ b/drivers/watchdog/mpc8xxx_wdt.c
@@ -189,7 +189,7 @@ static int __devinit mpc8xxx_wdt_probe(struct of_device *ofdev,
const struct of_device_id *match)
{
int ret;
- struct device_node *np = ofdev->node;
+ struct device_node *np = ofdev->dev.of_node;
struct mpc8xxx_wdt_type *wdt_type = match->data;
u32 freq = fsl_get_sys_freq();
bool enabled;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 300932580ded..ae53662c29bc 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -532,21 +532,22 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
static int __devexit s3c2410wdt_remove(struct platform_device *dev)
{
- s3c2410wdt_cpufreq_deregister();
-
- release_resource(wdt_mem);
- kfree(wdt_mem);
- wdt_mem = NULL;
+ misc_deregister(&s3c2410wdt_miscdev);
- free_irq(wdt_irq->start, dev);
- wdt_irq = NULL;
+ s3c2410wdt_cpufreq_deregister();
clk_disable(wdt_clock);
clk_put(wdt_clock);
wdt_clock = NULL;
+ free_irq(wdt_irq->start, dev);
+ wdt_irq = NULL;
+
iounmap(wdt_base);
- misc_deregister(&s3c2410wdt_miscdev);
+
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
return 0;
}
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c
index 89dd7b035295..b68d928c8f90 100644
--- a/drivers/watchdog/wm8350_wdt.c
+++ b/drivers/watchdog/wm8350_wdt.c
@@ -284,7 +284,7 @@ static int __devinit wm8350_wdt_probe(struct platform_device *pdev)
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
if (!wm8350) {
- dev_err(wm8350->dev, "No driver data supplied\n");
+ pr_err("No driver data supplied\n");
return -ENODEV;
}
diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c
index eab33f1dbdf7..7b547f53f65e 100644
--- a/drivers/xen/xenbus/xenbus_xs.c
+++ b/drivers/xen/xenbus/xenbus_xs.c
@@ -499,7 +499,7 @@ int xenbus_printf(struct xenbus_transaction t,
#define PRINTF_BUFFER_SIZE 4096
char *printf_buffer;
- printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
+ printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_NOIO | __GFP_HIGH);
if (printf_buffer == NULL)
return -ENOMEM;
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 3c7046d79654..4f4ea88fbb71 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -22,8 +22,9 @@ static loff_t
proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
{
loff_t new = -1;
+ struct inode *inode = file->f_path.dentry->d_inode;
- lock_kernel();
+ mutex_lock(&inode->i_mutex);
switch (whence) {
case 0:
new = off;
@@ -35,12 +36,12 @@ proc_bus_zorro_lseek(struct file *file, loff_t off, int whence)
new = sizeof(struct ConfigDev) + off;
break;
}
- if (new < 0 || new > sizeof(struct ConfigDev)) {
- unlock_kernel();
- return -EINVAL;
- }
- unlock_kernel();
- return (file->f_pos = new);
+ if (new < 0 || new > sizeof(struct ConfigDev))
+ new = -EINVAL;
+ else
+ file->f_pos = new;
+ mutex_unlock(&inode->i_mutex);
+ return new;
}
static ssize_t
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 7317b39b2815..5d6cfcbf73e7 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -152,7 +152,8 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
if (access == V9FS_ACCESS_SINGLE)
return ERR_PTR(-EPERM);
- if (v9fs_proto_dotu(v9ses))
+ if (v9fs_proto_dotu(v9ses) ||
+ v9fs_proto_dotl(v9ses))
uname = NULL;
else
uname = v9ses->uname;
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index f8b86e92cd66..3c492011221c 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -278,7 +278,7 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
- if (!v9fs_proto_dotu(v9ses) &&
+ if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
v9ses->flags &= ~V9FS_ACCESS_MASK;
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index d61e3b28ce37..aa1852d7c98e 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -87,29 +87,19 @@ static void p9stat_init(struct p9_wstat *stbuf)
}
/**
- * v9fs_dir_readdir - read a directory
+ * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
* @filp: opened file structure
- * @dirent: directory structure ???
- * @filldir: function to populate directory structure ???
+ * @buflen: Length in bytes of buffer to allocate
*
*/
-static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+static int v9fs_alloc_rdir_buf(struct file *filp, int buflen)
{
- int over;
- struct p9_wstat st;
- int err = 0;
- struct p9_fid *fid;
- int buflen;
- int reclen = 0;
struct p9_rdir *rdir;
+ struct p9_fid *fid;
+ int err = 0;
- P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
fid = filp->private_data;
-
- buflen = fid->clnt->msize - P9_IOHDRSZ;
-
- /* allocate rdir on demand */
if (!fid->rdir) {
rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
@@ -128,6 +118,36 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
spin_unlock(&filp->f_dentry->d_lock);
kfree(rdir);
}
+exit:
+ return err;
+}
+
+/**
+ * v9fs_dir_readdir - read a directory
+ * @filp: opened file structure
+ * @dirent: directory structure ???
+ * @filldir: function to populate directory structure ???
+ *
+ */
+
+static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
+{
+ int over;
+ struct p9_wstat st;
+ int err = 0;
+ struct p9_fid *fid;
+ int buflen;
+ int reclen = 0;
+ struct p9_rdir *rdir;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ fid = filp->private_data;
+
+ buflen = fid->clnt->msize - P9_IOHDRSZ;
+
+ err = v9fs_alloc_rdir_buf(filp, buflen);
+ if (err)
+ goto exit;
rdir = (struct p9_rdir *) fid->rdir;
err = mutex_lock_interruptible(&rdir->mutex);
@@ -176,6 +196,88 @@ exit:
return err;
}
+/**
+ * v9fs_dir_readdir_dotl - read a directory
+ * @filp: opened file structure
+ * @dirent: buffer to fill dirent structures
+ * @filldir: function to populate dirent structures
+ *
+ */
+static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
+ filldir_t filldir)
+{
+ int over;
+ int err = 0;
+ struct p9_fid *fid;
+ int buflen;
+ struct p9_rdir *rdir;
+ struct p9_dirent curdirent;
+ u64 oldoffset = 0;
+
+ P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
+ fid = filp->private_data;
+
+ buflen = fid->clnt->msize - P9_READDIRHDRSZ;
+
+ err = v9fs_alloc_rdir_buf(filp, buflen);
+ if (err)
+ goto exit;
+ rdir = (struct p9_rdir *) fid->rdir;
+
+ err = mutex_lock_interruptible(&rdir->mutex);
+ if (err)
+ return err;
+
+ while (err == 0) {
+ if (rdir->tail == rdir->head) {
+ err = p9_client_readdir(fid, rdir->buf, buflen,
+ filp->f_pos);
+ if (err <= 0)
+ goto unlock_and_exit;
+
+ rdir->head = 0;
+ rdir->tail = err;
+ }
+
+ while (rdir->head < rdir->tail) {
+
+ err = p9dirent_read(rdir->buf + rdir->head,
+ buflen - rdir->head, &curdirent,
+ fid->clnt->proto_version);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
+ err = -EIO;
+ goto unlock_and_exit;
+ }
+
+ /* d_off in dirent structure tracks the offset into
+ * the next dirent in the dir. However, filldir()
+ * expects offset into the current dirent. Hence
+ * while calling filldir send the offset from the
+ * previous dirent structure.
+ */
+ over = filldir(dirent, curdirent.d_name,
+ strlen(curdirent.d_name),
+ oldoffset, v9fs_qid2ino(&curdirent.qid),
+ curdirent.d_type);
+ oldoffset = curdirent.d_off;
+
+ if (over) {
+ err = 0;
+ goto unlock_and_exit;
+ }
+
+ filp->f_pos = curdirent.d_off;
+ rdir->head += err;
+ }
+ }
+
+unlock_and_exit:
+ mutex_unlock(&rdir->mutex);
+exit:
+ return err;
+}
+
/**
* v9fs_dir_release - close a directory
@@ -207,7 +309,7 @@ const struct file_operations v9fs_dir_operations = {
const struct file_operations v9fs_dir_operations_dotl = {
.read = generic_read_dir,
.llseek = generic_file_llseek,
- .readdir = v9fs_dir_readdir,
+ .readdir = v9fs_dir_readdir_dotl,
.open = v9fs_file_open,
.release = v9fs_dir_release,
};
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 2bedc6c94fc2..2d686ec322a0 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -139,7 +139,7 @@ ssize_t
v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
u64 offset)
{
- int n, total;
+ int n, total, size;
struct p9_fid *fid = filp->private_data;
P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid,
@@ -147,6 +147,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
n = 0;
total = 0;
+ size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
do {
n = p9_client_read(fid, data, udata, offset, count);
if (n <= 0)
@@ -160,7 +161,7 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
offset += n;
count -= n;
total += n;
- } while (count > 0 && n == (fid->clnt->msize - P9_IOHDRSZ));
+ } while (count > 0 && n == size);
if (n < 0)
total = n;
@@ -183,11 +184,13 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count,
{
int ret;
struct p9_fid *fid;
+ size_t size;
P9_DPRINTK(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
fid = filp->private_data;
- if (count > (fid->clnt->msize - P9_IOHDRSZ))
+ size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
+ if (count > size)
ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
else
ret = p9_client_read(fid, NULL, udata, *offset, count);
@@ -224,9 +227,7 @@ v9fs_file_write(struct file *filp, const char __user * data,
fid = filp->private_data;
clnt = fid->clnt;
- rsize = fid->iounit;
- if (!rsize || rsize > clnt->msize-P9_IOHDRSZ)
- rsize = clnt->msize - P9_IOHDRSZ;
+ rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
do {
if (count < rsize)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 4331b3b5ee1c..5ffca88653cd 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -236,6 +236,23 @@ void v9fs_destroy_inode(struct inode *inode)
#endif
/**
+ * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
+ * new file system object. This checks the S_ISGID to determine the owning
+ * group of the new file system object.
+ */
+
+gid_t v9fs_get_fsgid_for_create(struct dentry *dir_dentry)
+{
+ BUG_ON(dir_dentry->d_inode == NULL);
+
+ if (dir_dentry->d_inode->i_mode & S_ISGID) {
+ /* set_gid bit is set.*/
+ return dir_dentry->d_inode->i_gid;
+ }
+ return current_fsgid();
+}
+
+/**
* v9fs_get_inode - helper function to setup an inode
* @sb: superblock
* @mode: mode to setup inode with
@@ -532,6 +549,23 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
goto error;
}
+ /* Server grabs uid information from the fid but we need to fix
+ * gid as dotu doesn't support sending gid on the wire with Tcreate.
+ * hardlink is an exception as it inherits all credentials.
+ */
+ if (v9fs_proto_dotu(v9ses) && !(perm & P9_DMLINK)) {
+ struct p9_wstat wstat;
+
+ v9fs_blank_wstat(&wstat);
+ wstat.n_gid = v9fs_get_fsgid_for_create(dentry->d_parent);
+ err = p9_client_wstat(fid, &wstat);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_wstat failed %d\n",
+ err);
+ goto error;
+ }
+ }
+
/* instantiate inode and assign the unopened fid to the dentry */
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
@@ -896,10 +930,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
}
retval = p9_client_wstat(fid, &wstat);
- if (retval >= 0)
- retval = inode_setattr(dentry->d_inode, iattr);
+ if (retval < 0)
+ return retval;
+
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(dentry->d_inode)) {
+ retval = vmtruncate(dentry->d_inode, iattr->ia_size);
+ if (retval)
+ return retval;
+ }
- return retval;
+ setattr_copy(dentry->d_inode, iattr);
+ mark_inode_dirty(dentry->d_inode);
+ return 0;
}
/**
@@ -1186,6 +1229,49 @@ clunk_fid:
}
/**
+ * v9fs_vfs_link_dotl - create a hardlink for dotl
+ * @old_dentry: dentry for file to link to
+ * @dir: inode destination for new link
+ * @dentry: dentry for link
+ *
+ */
+
+static int
+v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ int err;
+ struct p9_fid *dfid;
+ char *name;
+ struct v9fs_session_info *v9ses;
+
+ P9_DPRINTK(P9_DEBUG_VFS,
+ " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
+ old_dentry->d_name.name);
+
+ v9ses = v9fs_inode2v9ses(dir);
+ dfid = v9fs_fid_lookup(dentry->d_parent);
+ if (IS_ERR(dfid))
+ return PTR_ERR(dfid);
+
+ name = (char *) dentry->d_name.name;
+
+ err = p9_client_link(dfid, (char *)old_dentry->d_name.name,
+ (char *)dentry->d_name.name);
+ if (err < 0) {
+ P9_DPRINTK(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
+ return err;
+ }
+
+ dentry->d_op = old_dentry->d_op;
+ /* Hard link, so we can use old_dentry's inode. Just i_count++ */
+ atomic_inc(&old_dentry->d_inode->i_count);
+ d_instantiate(dentry, old_dentry->d_inode);
+
+ return err;
+}
+
+/**
* v9fs_vfs_mknod - create a special file
* @dir: inode destination for new link
* @dentry: dentry for file
@@ -1234,7 +1320,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotu = {
.create = v9fs_vfs_create,
.lookup = v9fs_vfs_lookup,
.symlink = v9fs_vfs_symlink,
- .link = v9fs_vfs_link,
+ .link = v9fs_vfs_link_dotl,
.unlink = v9fs_vfs_unlink,
.mkdir = v9fs_vfs_mkdir,
.rmdir = v9fs_vfs_rmdir,
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 6f850b06ab62..65794b8fe79e 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -50,10 +50,19 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
adfs_get_block,
&ADFS_I(mapping->host)->mmu_private);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t _adfs_bmap(struct address_space *mapping, sector_t block)
@@ -324,10 +333,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr)
/* XXX: this is missing some actual on-disk truncation.. */
if (ia_valid & ATTR_SIZE)
- error = simple_setsize(inode, attr->ia_size);
-
- if (error)
- goto out;
+ truncate_setsize(inode, attr->ia_size);
if (ia_valid & ATTR_MTIME) {
inode->i_mtime = attr->ia_mtime;
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 322710c3eedf..c4a9875bd1a6 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -406,10 +406,19 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
affs_get_block,
&AFFS_I(mapping->host)->mmu_private);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t _affs_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index f4b2a4ee4f91..6883d5fb84cf 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -235,8 +235,17 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
goto out;
}
- error = inode_setattr(inode, attr);
- if (!error && (attr->ia_valid & ATTR_MODE))
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
+ if (attr->ia_valid & ATTR_MODE)
mode_to_prot(inode);
out:
return error;
diff --git a/fs/afs/server.c b/fs/afs/server.c
index f49099516675..9fdc7fe3a7bc 100644
--- a/fs/afs/server.c
+++ b/fs/afs/server.c
@@ -91,9 +91,10 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
memcpy(&server->addr, addr, sizeof(struct in_addr));
server->addr.s_addr = addr->s_addr;
+ _leave(" = %p{%d}", server, atomic_read(&server->usage));
+ } else {
+ _leave(" = NULL [nomem]");
}
-
- _leave(" = %p{%d}", server, atomic_read(&server->usage));
return server;
}
diff --git a/fs/aio.c b/fs/aio.c
index 1ccf25cef1f0..3006b5bc33d6 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1277,7 +1277,7 @@ out:
/* sys_io_destroy:
* Destroy the aio_context specified. May cancel any outstanding
* AIOs and block on completion. Will fail with -ENOSYS if not
- * implemented. May fail with -EFAULT if the context pointed to
+ * implemented. May fail with -EINVAL if the context pointed to
* is invalid.
*/
SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
@@ -1795,15 +1795,16 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb,
/* io_getevents:
* Attempts to read at least min_nr events and up to nr events from
- * the completion queue for the aio_context specified by ctx_id. May
- * fail with -EINVAL if ctx_id is invalid, if min_nr is out of range,
- * if nr is out of range, if when is out of range. May fail with
- * -EFAULT if any of the memory specified to is invalid. May return
- * 0 or < min_nr if no events are available and the timeout specified
- * by when has elapsed, where when == NULL specifies an infinite
- * timeout. Note that the timeout pointed to by when is relative and
- * will be updated if not NULL and the operation blocks. Will fail
- * with -ENOSYS if not implemented.
+ * the completion queue for the aio_context specified by ctx_id. If
+ * it succeeds, the number of read events is returned. May fail with
+ * -EINVAL if ctx_id is invalid, if min_nr is out of range, if nr is
+ * out of range, if timeout is out of range. May fail with -EFAULT
+ * if any of the memory specified is invalid. May return 0 or
+ * < min_nr if the timeout specified by timeout has elapsed
+ * before sufficient events are available, where timeout == NULL
+ * specifies an infinite timeout. Note that the timeout pointed to by
+ * timeout is relative and will be updated if not NULL and the
+ * operation blocks. Will fail with -ENOSYS if not implemented.
*/
SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
long, min_nr,
diff --git a/fs/attr.c b/fs/attr.c
index b4fa3b0aa596..6959666f91a9 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -14,35 +14,53 @@
#include <linux/fcntl.h>
#include <linux/security.h>
-/* Taken over from the old code... */
-
-/* POSIX UID/GID verification for setting inode attributes. */
+/**
+ * inode_change_ok - check if attribute changes to an inode are allowed
+ * @inode: inode to check
+ * @attr: attributes to change
+ *
+ * Check if we are allowed to change the attributes contained in @attr
+ * in the given inode. This includes the normal unix access permission
+ * checks, as well as checks for rlimits and others.
+ *
+ * Should be called as the first thing in ->setattr implementations,
+ * possibly after taking additional locks.
+ */
int inode_change_ok(const struct inode *inode, struct iattr *attr)
{
- int retval = -EPERM;
unsigned int ia_valid = attr->ia_valid;
+ /*
+ * First check size constraints. These can't be overriden using
+ * ATTR_FORCE.
+ */
+ if (attr->ia_mode & ATTR_SIZE) {
+ int error = inode_newsize_ok(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
/* If force is set do it anyway. */
if (ia_valid & ATTR_FORCE)
- goto fine;
+ return 0;
/* Make sure a caller can chown. */
if ((ia_valid & ATTR_UID) &&
(current_fsuid() != inode->i_uid ||
attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN))
- goto error;
+ return -EPERM;
/* Make sure caller can chgrp. */
if ((ia_valid & ATTR_GID) &&
(current_fsuid() != inode->i_uid ||
(!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) &&
!capable(CAP_CHOWN))
- goto error;
+ return -EPERM;
/* Make sure a caller can chmod. */
if (ia_valid & ATTR_MODE) {
if (!is_owner_or_cap(inode))
- goto error;
+ return -EPERM;
/* Also check the setgid bit! */
if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
inode->i_gid) && !capable(CAP_FSETID))
@@ -52,12 +70,10 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr)
/* Check for setting the inode time. */
if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
if (!is_owner_or_cap(inode))
- goto error;
+ return -EPERM;
}
-fine:
- retval = 0;
-error:
- return retval;
+
+ return 0;
}
EXPORT_SYMBOL(inode_change_ok);
@@ -105,21 +121,21 @@ out_big:
EXPORT_SYMBOL(inode_newsize_ok);
/**
- * generic_setattr - copy simple metadata updates into the generic inode
+ * setattr_copy - copy simple metadata updates into the generic inode
* @inode: the inode to be updated
* @attr: the new attributes
*
- * generic_setattr must be called with i_mutex held.
+ * setattr_copy must be called with i_mutex held.
*
- * generic_setattr updates the inode's metadata with that specified
+ * setattr_copy updates the inode's metadata with that specified
* in attr. Noticably missing is inode size update, which is more complex
- * as it requires pagecache updates. See simple_setsize.
+ * as it requires pagecache updates.
*
* The inode is not marked as dirty after this operation. The rationale is
* that for "simple" filesystems, the struct inode is the inode storage.
* The caller is free to mark the inode dirty afterwards if needed.
*/
-void generic_setattr(struct inode *inode, const struct iattr *attr)
+void setattr_copy(struct inode *inode, const struct iattr *attr)
{
unsigned int ia_valid = attr->ia_valid;
@@ -144,32 +160,7 @@ void generic_setattr(struct inode *inode, const struct iattr *attr)
inode->i_mode = mode;
}
}
-EXPORT_SYMBOL(generic_setattr);
-
-/*
- * note this function is deprecated, the new truncate sequence should be
- * used instead -- see eg. simple_setsize, generic_setattr.
- */
-int inode_setattr(struct inode *inode, const struct iattr *attr)
-{
- unsigned int ia_valid = attr->ia_valid;
-
- if (ia_valid & ATTR_SIZE &&
- attr->ia_size != i_size_read(inode)) {
- int error;
-
- error = vmtruncate(inode, attr->ia_size);
- if (error)
- return error;
- }
-
- generic_setattr(inode, attr);
-
- mark_inode_dirty(inode);
-
- return 0;
-}
-EXPORT_SYMBOL(inode_setattr);
+EXPORT_SYMBOL(setattr_copy);
int notify_change(struct dentry * dentry, struct iattr * attr)
{
@@ -237,13 +228,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (ia_valid & ATTR_SIZE)
down_write(&dentry->d_inode->i_alloc_sem);
- if (inode->i_op && inode->i_op->setattr) {
+ if (inode->i_op->setattr)
error = inode->i_op->setattr(dentry, attr);
- } else {
- error = inode_change_ok(inode, attr);
- if (!error)
- error = inode_setattr(inode, attr);
- }
+ else
+ error = simple_setattr(dentry, attr);
if (ia_valid & ATTR_SIZE)
up_write(&dentry->d_inode->i_alloc_sem);
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 88b9a3ff44e4..8fc2e9c9739d 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -168,9 +168,17 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return block_write_begin(file, mapping, pos, len, flags,
- pagep, fsdata, bfs_get_block);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ bfs_get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t bfs_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 2c5f9a0e5d72..63039ed9576f 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -990,10 +990,9 @@ static int elf_fdpic_map_file_constdisp_on_uclinux(
/* clear any space allocated but not loaded */
if (phdr->p_filesz < phdr->p_memsz) {
- ret = clear_user((void *) (seg->addr + phdr->p_filesz),
- phdr->p_memsz - phdr->p_filesz);
- if (ret)
- return ret;
+ if (clear_user((void *) (seg->addr + phdr->p_filesz),
+ phdr->p_memsz - phdr->p_filesz))
+ return -EFAULT;
}
if (mm) {
@@ -1027,7 +1026,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
struct elf32_fdpic_loadseg *seg;
struct elf32_phdr *phdr;
unsigned long load_addr, delta_vaddr;
- int loop, dvset, ret;
+ int loop, dvset;
load_addr = params->load_addr;
delta_vaddr = 0;
@@ -1127,9 +1126,8 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
* PT_LOAD */
if (prot & PROT_WRITE && disp > 0) {
kdebug("clear[%d] ad=%lx sz=%lx", loop, maddr, disp);
- ret = clear_user((void __user *) maddr, disp);
- if (ret)
- return ret;
+ if (clear_user((void __user *) maddr, disp))
+ return -EFAULT;
maddr += disp;
}
@@ -1164,19 +1162,17 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *params,
if (prot & PROT_WRITE && excess1 > 0) {
kdebug("clear[%d] ad=%lx sz=%lx",
loop, maddr + phdr->p_filesz, excess1);
- ret = clear_user((void __user *) maddr + phdr->p_filesz,
- excess1);
- if (ret)
- return ret;
+ if (clear_user((void __user *) maddr + phdr->p_filesz,
+ excess1))
+ return -EFAULT;
}
#else
if (excess > 0) {
kdebug("clear[%d] ad=%lx sz=%lx",
loop, maddr + phdr->p_filesz, excess);
- ret = clear_user((void *) maddr + phdr->p_filesz, excess);
- if (ret)
- return ret;
+ if (clear_user((void *) maddr + phdr->p_filesz, excess))
+ return -EFAULT;
}
#endif
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 49566c1687d8..b6ab27ccf214 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -56,15 +56,22 @@
#endif
/*
- * User data (stack, data section and bss) needs to be aligned
- * for the same reasons as SLAB memory is, and to the same amount.
- * Avoid duplicating architecture specific code by using the same
- * macro as with SLAB allocation:
+ * User data (data section and bss) needs to be aligned.
+ * We pick 0x20 here because it is the max value elf2flt has always
+ * used in producing FLAT files, and because it seems to be large
+ * enough to make all the gcc alignment related tests happy.
+ */
+#define FLAT_DATA_ALIGN (0x20)
+
+/*
+ * User data (stack) also needs to be aligned.
+ * Here we can be a bit looser than the data sections since this
+ * needs to only meet arch ABI requirements.
*/
#ifdef ARCH_SLAB_MINALIGN
-#define FLAT_DATA_ALIGN (ARCH_SLAB_MINALIGN)
+#define FLAT_STACK_ALIGN (ARCH_SLAB_MINALIGN)
#else
-#define FLAT_DATA_ALIGN (sizeof(void *))
+#define FLAT_STACK_ALIGN (sizeof(void *))
#endif
#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
@@ -129,7 +136,7 @@ static unsigned long create_flat_tables(
sp = (unsigned long *)p;
sp -= (envc + argc + 2) + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
- sp = (unsigned long *) ((unsigned long)sp & -FLAT_DATA_ALIGN);
+ sp = (unsigned long *) ((unsigned long)sp & -FLAT_STACK_ALIGN);
argv = sp + 1 + (flat_argvp_envp_on_stack() ? 2 : 0);
envp = argv + (argc + 1);
@@ -589,7 +596,7 @@ static int load_flat_file(struct linux_binprm * bprm,
if (IS_ERR_VALUE(result)) {
printk("Unable to read data+bss, errno %d\n", (int)-result);
do_munmap(current->mm, textpos, text_len);
- do_munmap(current->mm, realdatastart, data_len + extra);
+ do_munmap(current->mm, realdatastart, len);
ret = result;
goto err;
}
@@ -876,7 +883,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs)
stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
stack_len += (bprm->argc + 1) * sizeof(char *); /* the argv array */
stack_len += (bprm->envc + 1) * sizeof(char *); /* the envp array */
- stack_len += FLAT_DATA_ALIGN - 1; /* reserve for upcoming alignment */
+ stack_len += FLAT_STACK_ALIGN - 1; /* reserve for upcoming alignment */
res = load_flat_file(bprm, &libinfo, 0, &stack_len);
if (IS_ERR_VALUE(res))
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 7346c96308a5..be2c7f254b1d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -172,9 +172,8 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
- return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode,
- I_BDEV(inode), iov, offset, nr_segs,
- blkdev_get_blocks, NULL);
+ return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset,
+ nr_segs, blkdev_get_blocks, NULL, NULL, 0);
}
int __sync_blockdev(struct block_device *bdev, int wait)
@@ -309,9 +308,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return block_write_begin_newtrunc(file, mapping, pos, len, flags,
- pagep, fsdata, blkdev_get_block);
+ return block_write_begin(mapping, pos, len, flags, pagep,
+ blkdev_get_block);
}
static int blkdev_write_end(struct file *file, struct address_space *mapping,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index fa6ccc1bfe2a..44d404c7abc6 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3656,13 +3656,15 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
}
- attr->ia_valid &= ~ATTR_SIZE;
- if (attr->ia_valid)
- err = inode_setattr(inode, attr);
+ if (attr->ia_valid) {
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
+ if (attr->ia_valid & ATTR_MODE)
+ err = btrfs_acl_chmod(inode);
+ }
- if (!err && ((attr->ia_valid & ATTR_MODE)))
- err = btrfs_acl_chmod(inode);
return err;
}
diff --git a/fs/buffer.c b/fs/buffer.c
index d54812b198e9..50efa339e051 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to)
}
EXPORT_SYMBOL(page_zero_new_buffers);
-static int __block_prepare_write(struct inode *inode, struct page *page,
- unsigned from, unsigned to, get_block_t *get_block)
+int block_prepare_write(struct page *page, unsigned from, unsigned to,
+ get_block_t *get_block)
{
+ struct inode *inode = page->mapping->host;
unsigned block_start, block_end;
sector_t block;
int err = 0;
@@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
if (!buffer_uptodate(*wait_bh))
err = -EIO;
}
- if (unlikely(err))
+ if (unlikely(err)) {
page_zero_new_buffers(page, from, to);
+ ClearPageUptodate(page);
+ }
return err;
}
+EXPORT_SYMBOL(block_prepare_write);
static int __block_commit_write(struct inode *inode, struct page *page,
unsigned from, unsigned to)
@@ -1948,90 +1952,41 @@ static int __block_commit_write(struct inode *inode, struct page *page,
return 0;
}
-/*
- * Filesystems implementing the new truncate sequence should use the
- * _newtrunc postfix variant which won't incorrectly call vmtruncate.
- * The filesystem needs to handle block truncation upon failure.
- */
-int block_write_begin_newtrunc(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata,
- get_block_t *get_block)
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
+ get_block_t *get_block)
{
- struct inode *inode = mapping->host;
- int status = 0;
- struct page *page;
- pgoff_t index;
- unsigned start, end;
- int ownpage = 0;
-
- index = pos >> PAGE_CACHE_SHIFT;
- start = pos & (PAGE_CACHE_SIZE - 1);
- end = start + len;
-
- page = *pagep;
- if (page == NULL) {
- ownpage = 1;
- page = grab_cache_page_write_begin(mapping, index, flags);
- if (!page) {
- status = -ENOMEM;
- goto out;
- }
- *pagep = page;
- } else
- BUG_ON(!PageLocked(page));
-
- status = __block_prepare_write(inode, page, start, end, get_block);
- if (unlikely(status)) {
- ClearPageUptodate(page);
+ unsigned start = pos & (PAGE_CACHE_SIZE - 1);
- if (ownpage) {
- unlock_page(page);
- page_cache_release(page);
- *pagep = NULL;
- }
- }
-
-out:
- return status;
+ return block_prepare_write(page, start, start + len, get_block);
}
-EXPORT_SYMBOL(block_write_begin_newtrunc);
+EXPORT_SYMBOL(__block_write_begin);
/*
* block_write_begin takes care of the basic task of block allocation and
* bringing partial write blocks uptodate first.
*
- * If *pagep is not NULL, then block_write_begin uses the locked page
- * at *pagep rather than allocating its own. In this case, the page will
- * not be unlocked or deallocated on failure.
+ * The filesystem needs to handle block truncation upon failure.
*/
-int block_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata,
- get_block_t *get_block)
+int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
+ unsigned flags, struct page **pagep, get_block_t *get_block)
{
- int ret;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ struct page *page;
+ int status;
- ret = block_write_begin_newtrunc(file, mapping, pos, len, flags,
- pagep, fsdata, get_block);
+ page = grab_cache_page_write_begin(mapping, index, flags);
+ if (!page)
+ return -ENOMEM;
- /*
- * prepare_write() may have instantiated a few blocks
- * outside i_size. Trim these off again. Don't need
- * i_size_read because we hold i_mutex.
- *
- * Filesystems which pass down their own page also cannot
- * call into vmtruncate here because it would lead to lock
- * inversion problems (*pagep is locked). This is a further
- * example of where the old truncate sequence is inadequate.
- */
- if (unlikely(ret) && *pagep == NULL) {
- loff_t isize = mapping->host->i_size;
- if (pos + len > isize)
- vmtruncate(mapping->host, isize);
+ status = __block_write_begin(page, pos, len, get_block);
+ if (unlikely(status)) {
+ unlock_page(page);
+ page_cache_release(page);
+ page = NULL;
}
- return ret;
+ *pagep = page;
+ return status;
}
EXPORT_SYMBOL(block_write_begin);
@@ -2351,7 +2306,7 @@ out:
* For moronic filesystems that do not allow holes in file.
* We may have to extend the file.
*/
-int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
+int cont_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block, loff_t *bytes)
@@ -2363,7 +2318,7 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
err = cont_expand_zero(file, mapping, pos, bytes);
if (err)
- goto out;
+ return err;
zerofrom = *bytes & ~PAGE_CACHE_MASK;
if (pos+len > *bytes && zerofrom & (blocksize-1)) {
@@ -2371,44 +2326,10 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping,
(*bytes)++;
}
- *pagep = NULL;
- err = block_write_begin_newtrunc(file, mapping, pos, len,
- flags, pagep, fsdata, get_block);
-out:
- return err;
-}
-EXPORT_SYMBOL(cont_write_begin_newtrunc);
-
-int cont_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata,
- get_block_t *get_block, loff_t *bytes)
-{
- int ret;
-
- ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
- pagep, fsdata, get_block, bytes);
- if (unlikely(ret)) {
- loff_t isize = mapping->host->i_size;
- if (pos + len > isize)
- vmtruncate(mapping->host, isize);
- }
-
- return ret;
+ return block_write_begin(mapping, pos, len, flags, pagep, get_block);
}
EXPORT_SYMBOL(cont_write_begin);
-int block_prepare_write(struct page *page, unsigned from, unsigned to,
- get_block_t *get_block)
-{
- struct inode *inode = page->mapping->host;
- int err = __block_prepare_write(inode, page, from, to, get_block);
- if (err)
- ClearPageUptodate(page);
- return err;
-}
-EXPORT_SYMBOL(block_prepare_write);
-
int block_commit_write(struct page *page, unsigned from, unsigned to)
{
struct inode *inode = page->mapping->host;
@@ -2510,11 +2431,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head)
}
/*
- * Filesystems implementing the new truncate sequence should use the
- * _newtrunc postfix variant which won't incorrectly call vmtruncate.
+ * On entry, the page is fully not uptodate.
+ * On exit the page is fully uptodate in the areas outside (from,to)
* The filesystem needs to handle block truncation upon failure.
*/
-int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
+int nobh_write_begin(struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata,
get_block_t *get_block)
@@ -2547,8 +2468,8 @@ int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping,
unlock_page(page);
page_cache_release(page);
*pagep = NULL;
- return block_write_begin_newtrunc(file, mapping, pos, len,
- flags, pagep, fsdata, get_block);
+ return block_write_begin(mapping, pos, len, flags, pagep,
+ get_block);
}
if (PageMappedToDisk(page))
@@ -2654,35 +2575,6 @@ out_release:
return ret;
}
-EXPORT_SYMBOL(nobh_write_begin_newtrunc);
-
-/*
- * On entry, the page is fully not uptodate.
- * On exit the page is fully uptodate in the areas outside (from,to)
- */
-int nobh_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata,
- get_block_t *get_block)
-{
- int ret;
-
- ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags,
- pagep, fsdata, get_block);
-
- /*
- * prepare_write() may have instantiated a few blocks
- * outside i_size. Trim these off again. Don't need
- * i_size_read because we hold i_mutex.
- */
- if (unlikely(ret)) {
- loff_t isize = mapping->host->i_size;
- if (pos + len > isize)
- vmtruncate(mapping->host, isize);
- }
-
- return ret;
-}
EXPORT_SYMBOL(nobh_write_begin);
int nobh_write_end(struct file *file, struct address_space *mapping,
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
index d9c60b84949a..e00797eed29c 100644
--- a/fs/ceph/addr.c
+++ b/fs/ceph/addr.c
@@ -552,7 +552,7 @@ static void writepages_finish(struct ceph_osd_request *req,
* page truncation thread, possibly losing some data that
* raced its way in
*/
- if ((issued & CEPH_CAP_FILE_CACHE) == 0)
+ if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
generic_error_remove_page(inode->i_mapping, page);
unlock_page(page);
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index ae3e3a306445..35036202d9ce 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -331,8 +331,7 @@ static struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds)
}
/*
- * Return id of any MDS with a cap, preferably FILE_WR|WRBUFFER|EXCL, else
- * -1.
+ * Return id of any MDS with a cap, preferably FILE_WR|BUFFER|EXCL, else -1.
*/
static int __ceph_get_cap_mds(struct ceph_inode_info *ci, u32 *mseq)
{
@@ -340,7 +339,7 @@ static int __ceph_get_cap_mds(struct ceph_inode_info *ci, u32 *mseq)
int mds = -1;
struct rb_node *p;
- /* prefer mds with WR|WRBUFFER|EXCL caps */
+ /* prefer mds with WR|BUFFER|EXCL caps */
for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
cap = rb_entry(p, struct ceph_cap, ci_node);
mds = cap->mds;
@@ -477,8 +476,8 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
* Each time we receive FILE_CACHE anew, we increment
* i_rdcache_gen.
*/
- if ((issued & CEPH_CAP_FILE_CACHE) &&
- (had & CEPH_CAP_FILE_CACHE) == 0)
+ if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
+ (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
ci->i_rdcache_gen++;
/*
@@ -825,7 +824,7 @@ int __ceph_caps_file_wanted(struct ceph_inode_info *ci)
{
int want = 0;
int mode;
- for (mode = 0; mode < 4; mode++)
+ for (mode = 0; mode < CEPH_FILE_MODE_NUM; mode++)
if (ci->i_nr_by_mode[mode])
want |= ceph_caps_for_mode(mode);
return want;
@@ -1333,7 +1332,7 @@ void __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
* Add dirty inode to the flushing list. Assigned a seq number so we
* can wait for caps to flush without starving.
*
- * Called under i_lock.
+ * Called under i_lock, s_mutex
*/
static int __mark_caps_flushing(struct inode *inode,
struct ceph_mds_session *session)
@@ -1496,11 +1495,13 @@ retry_locked:
ci->i_wrbuffer_ref == 0 && /* no dirty pages... */
ci->i_rdcache_gen && /* may have cached pages */
(file_wanted == 0 || /* no open files */
- (revoking & CEPH_CAP_FILE_CACHE)) && /* or revoking cache */
+ (revoking & (CEPH_CAP_FILE_CACHE|
+ CEPH_CAP_FILE_LAZYIO))) && /* or revoking cache */
!tried_invalidate) {
dout("check_caps trying to invalidate on %p\n", inode);
if (try_nonblocking_invalidate(inode) < 0) {
- if (revoking & CEPH_CAP_FILE_CACHE) {
+ if (revoking & (CEPH_CAP_FILE_CACHE|
+ CEPH_CAP_FILE_LAZYIO)) {
dout("check_caps queuing invalidate\n");
queue_invalidate = 1;
ci->i_rdcache_revoking = ci->i_rdcache_gen;
@@ -1866,8 +1867,16 @@ static void kick_flushing_capsnaps(struct ceph_mds_client *mdsc,
cap, capsnap);
__ceph_flush_snaps(ci, &session);
} else {
+ struct rb_node *p;
+
pr_err("%p auth cap %p not mds%d ???\n", inode,
cap, session->s_mds);
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ struct ceph_cap *t =
+ rb_entry(p, struct ceph_cap, ci_node);
+ pr_info(" %p cap %p mds%d\n", inode, t,
+ t->session ? t->session->s_mds : -1);
+ }
}
spin_unlock(&inode->i_lock);
}
@@ -1902,8 +1911,15 @@ void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc,
spin_unlock(&inode->i_lock);
}
} else {
+ struct rb_node *p;
pr_err("%p auth cap %p not mds%d ???\n", inode,
cap, session->s_mds);
+ for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
+ struct ceph_cap *t =
+ rb_entry(p, struct ceph_cap, ci_node);
+ pr_info(" %p cap %p mds%d\n", inode, t,
+ t->session ? t->session->s_mds : -1);
+ }
spin_unlock(&inode->i_lock);
}
}
@@ -2263,7 +2279,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
* try to invalidate (once). (If there are dirty buffers, we
* will invalidate _after_ writeback.)
*/
- if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
+ if (((cap->issued & ~newcaps) & (CEPH_CAP_FILE_CACHE|
+ CEPH_CAP_FILE_LAZYIO)) &&
!ci->i_wrbuffer_ref) {
if (try_nonblocking_invalidate(inode) == 0) {
revoked_rdcache = 1;
@@ -2361,7 +2378,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
writeback = 1; /* will delay ack */
else if (dirty & ~newcaps)
check_caps = 1; /* initiate writeback in check_caps */
- else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 ||
+ else if (((used & ~newcaps) & (CEPH_CAP_FILE_CACHE|
+ CEPH_CAP_FILE_LAZYIO)) == 0 ||
revoked_rdcache)
check_caps = 2; /* send revoke ack in check_caps */
cap->issued = newcaps;
diff --git a/fs/ceph/ceph_fs.c b/fs/ceph/ceph_fs.c
index 79d76bc4303f..3ac6cc7c1156 100644
--- a/fs/ceph/ceph_fs.c
+++ b/fs/ceph/ceph_fs.c
@@ -29,46 +29,44 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout)
int ceph_flags_to_mode(int flags)
{
+ int mode;
+
#ifdef O_DIRECTORY /* fixme */
if ((flags & O_DIRECTORY) == O_DIRECTORY)
return CEPH_FILE_MODE_PIN;
#endif
+ if ((flags & O_APPEND) == O_APPEND)
+ flags |= O_WRONLY;
+
+ if ((flags & O_ACCMODE) == O_RDWR)
+ mode = CEPH_FILE_MODE_RDWR;
+ else if ((flags & O_ACCMODE) == O_WRONLY)
+ mode = CEPH_FILE_MODE_WR;
+ else
+ mode = CEPH_FILE_MODE_RD;
+
#ifdef O_LAZY
if (flags & O_LAZY)
- return CEPH_FILE_MODE_LAZY;
+ mode |= CEPH_FILE_MODE_LAZY;
#endif
- if ((flags & O_APPEND) == O_APPEND)
- flags |= O_WRONLY;
- flags &= O_ACCMODE;
- if ((flags & O_RDWR) == O_RDWR)
- return CEPH_FILE_MODE_RDWR;
- if ((flags & O_WRONLY) == O_WRONLY)
- return CEPH_FILE_MODE_WR;
- return CEPH_FILE_MODE_RD;
+ return mode;
}
int ceph_caps_for_mode(int mode)
{
- switch (mode) {
- case CEPH_FILE_MODE_PIN:
- return CEPH_CAP_PIN;
- case CEPH_FILE_MODE_RD:
- return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
+ int caps = CEPH_CAP_PIN;
+
+ if (mode & CEPH_FILE_MODE_RD)
+ caps |= CEPH_CAP_FILE_SHARED |
CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE;
- case CEPH_FILE_MODE_RDWR:
- return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
- CEPH_CAP_FILE_EXCL |
- CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE |
- CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
- CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
- CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
- case CEPH_FILE_MODE_WR:
- return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED |
- CEPH_CAP_FILE_EXCL |
+ if (mode & CEPH_FILE_MODE_WR)
+ caps |= CEPH_CAP_FILE_EXCL |
CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER |
CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL |
CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL;
- }
- return 0;
+ if (mode & CEPH_FILE_MODE_LAZY)
+ caps |= CEPH_CAP_FILE_LAZYIO;
+
+ return caps;
}
diff --git a/fs/ceph/ceph_fs.h b/fs/ceph/ceph_fs.h
index 2fa992eaf7da..c2e4c61a99a3 100644
--- a/fs/ceph/ceph_fs.h
+++ b/fs/ceph/ceph_fs.h
@@ -563,7 +563,8 @@ int ceph_flags_to_mode(int flags);
CEPH_CAP_FILE_EXCL)
#define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR)
#define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \
- CEPH_CAP_ANY_FILE_WR | CEPH_CAP_PIN)
+ CEPH_CAP_ANY_FILE_WR | CEPH_CAP_FILE_LAZYIO | \
+ CEPH_CAP_PIN)
#define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \
CEPH_LOCK_IXATTR)
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 6251a1574b94..2261d52279ed 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -740,28 +740,32 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *filp = iocb->ki_filp;
+ struct ceph_file_info *fi = filp->private_data;
loff_t *ppos = &iocb->ki_pos;
size_t len = iov->iov_len;
struct inode *inode = filp->f_dentry->d_inode;
struct ceph_inode_info *ci = ceph_inode(inode);
void *base = iov->iov_base;
ssize_t ret;
- int got = 0;
+ int want, got = 0;
int checkeof = 0, read = 0;
dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
inode, ceph_vinop(inode), pos, (unsigned)len, inode);
again:
__ceph_do_pending_vmtruncate(inode);
- ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE,
- &got, -1);
+ if (fi->fmode & CEPH_FILE_MODE_LAZY)
+ want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
+ else
+ want = CEPH_CAP_FILE_CACHE;
+ ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
if (ret < 0)
goto out;
dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
inode, ceph_vinop(inode), pos, (unsigned)len,
ceph_cap_string(got));
- if ((got & CEPH_CAP_FILE_CACHE) == 0 ||
+ if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
(iocb->ki_filp->f_flags & O_DIRECT) ||
(inode->i_sb->s_flags & MS_SYNCHRONOUS))
/* hmm, this isn't really async... */
@@ -807,11 +811,12 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
+ struct ceph_file_info *fi = file->private_data;
struct inode *inode = file->f_dentry->d_inode;
struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc;
loff_t endoff = pos + iov->iov_len;
- int got = 0;
+ int want, got = 0;
int ret, err;
if (ceph_snap(inode) != CEPH_NOSNAP)
@@ -824,8 +829,11 @@ retry_snap:
dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n",
inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
inode->i_size);
- ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER,
- &got, endoff);
+ if (fi->fmode & CEPH_FILE_MODE_LAZY)
+ want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
+ else
+ want = CEPH_CAP_FILE_BUFFER;
+ ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff);
if (ret < 0)
goto out;
@@ -833,7 +841,7 @@ retry_snap:
inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len,
ceph_cap_string(got));
- if ((got & CEPH_CAP_FILE_BUFFER) == 0 ||
+ if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
(iocb->ki_filp->f_flags & O_DIRECT) ||
(inode->i_sb->s_flags & MS_SYNCHRONOUS)) {
ret = ceph_sync_write(file, iov->iov_base, iov->iov_len,
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 226f5a50d362..3938ba29369f 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -442,8 +442,9 @@ int ceph_fill_file_size(struct inode *inode, int issued,
* the file is either opened or mmaped
*/
if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
- CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
- CEPH_CAP_FILE_EXCL)) ||
+ CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
+ CEPH_CAP_FILE_EXCL|
+ CEPH_CAP_FILE_LAZYIO)) ||
mapping_mapped(inode->i_mapping) ||
__ceph_caps_file_wanted(ci)) {
ci->i_truncate_pending++;
diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c
index d085f07756b4..76e307d2aba1 100644
--- a/fs/ceph/ioctl.c
+++ b/fs/ceph/ioctl.c
@@ -143,6 +143,27 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
return 0;
}
+static long ceph_ioctl_lazyio(struct file *file)
+{
+ struct ceph_file_info *fi = file->private_data;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ceph_inode_info *ci = ceph_inode(inode);
+
+ if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) {
+ spin_lock(&inode->i_lock);
+ ci->i_nr_by_mode[fi->fmode]--;
+ fi->fmode |= CEPH_FILE_MODE_LAZY;
+ ci->i_nr_by_mode[fi->fmode]++;
+ spin_unlock(&inode->i_lock);
+ dout("ioctl_layzio: file %p marked lazy\n", file);
+
+ ceph_check_caps(ci, 0, NULL);
+ } else {
+ dout("ioctl_layzio: file %p already lazy\n", file);
+ }
+ return 0;
+}
+
long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg);
@@ -155,6 +176,9 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case CEPH_IOC_GET_DATALOC:
return ceph_ioctl_get_dataloc(file, (void __user *)arg);
+
+ case CEPH_IOC_LAZYIO:
+ return ceph_ioctl_lazyio(file);
}
return -ENOTTY;
}
diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h
index 25e4f1a9d059..88451a3b6857 100644
--- a/fs/ceph/ioctl.h
+++ b/fs/ceph/ioctl.h
@@ -37,4 +37,6 @@ struct ceph_ioctl_dataloc {
#define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \
struct ceph_ioctl_dataloc)
+#define CEPH_IOC_LAZYIO _IO(CEPH_IOCTL_MAGIC, 4)
+
#endif
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index f1ff785b2292..75541af4b3db 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1952,6 +1952,7 @@ static void cifs_copy_cache_pages(struct address_space *mapping,
bytes_read -= PAGE_CACHE_SIZE;
continue;
}
+ page_cache_release(page);
target = kmap_atomic(page, KM_USER0);
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 62b324f26a56..8a598c4f1720 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1776,14 +1776,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
xid = GetXid();
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
- /* check if we have permission to change attrs */
- rc = inode_change_ok(inode, attrs);
- if (rc < 0)
- goto out;
- else
- rc = 0;
- }
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ attrs->ia_valid |= ATTR_FORCE;
+
+ rc = inode_change_ok(inode, attrs);
+ if (rc < 0)
+ goto out;
full_path = build_path_from_dentry(direntry);
if (full_path == NULL) {
@@ -1869,18 +1867,27 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
CIFS_MOUNT_MAP_SPECIAL_CHR);
}
- if (!rc) {
- rc = inode_setattr(inode, attrs);
+ if (rc)
+ goto out;
- /* force revalidate when any of these times are set since some
- of the fs types (eg ext3, fat) do not have fine enough
- time granularity to match protocol, and we do not have a
- a way (yet) to query the server fs's time granularity (and
- whether it rounds times down).
- */
- if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)))
- cifsInode->time = 0;
+ if ((attrs->ia_valid & ATTR_SIZE) &&
+ attrs->ia_size != i_size_read(inode)) {
+ rc = vmtruncate(inode, attrs->ia_size);
+ if (rc)
+ goto out;
}
+
+ setattr_copy(inode, attrs);
+ mark_inode_dirty(inode);
+
+ /* force revalidate when any of these times are set since some
+ of the fs types (eg ext3, fat) do not have fine enough
+ time granularity to match protocol, and we do not have a
+ a way (yet) to query the server fs's time granularity (and
+ whether it rounds times down).
+ */
+ if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))
+ cifsInode->time = 0;
out:
kfree(args);
kfree(full_path);
@@ -1905,14 +1912,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
cFYI(1, "setattr on file %s attrs->iavalid 0x%x",
direntry->d_name.name, attrs->ia_valid);
- if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) {
- /* check if we have permission to change attrs */
- rc = inode_change_ok(inode, attrs);
- if (rc < 0) {
- FreeXid(xid);
- return rc;
- } else
- rc = 0;
+ if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM)
+ attrs->ia_valid |= ATTR_FORCE;
+
+ rc = inode_change_ok(inode, attrs);
+ if (rc < 0) {
+ FreeXid(xid);
+ return rc;
}
full_path = build_path_from_dentry(direntry);
@@ -2020,8 +2026,20 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs)
/* do not need local check to inode_check_ok since the server does
that */
- if (!rc)
- rc = inode_setattr(inode, attrs);
+ if (rc)
+ goto cifs_setattr_exit;
+
+ if ((attrs->ia_valid & ATTR_SIZE) &&
+ attrs->ia_size != i_size_read(inode)) {
+ rc = vmtruncate(inode, attrs->ia_size);
+ if (rc)
+ goto cifs_setattr_exit;
+ }
+
+ setattr_copy(inode, attrs);
+ mark_inode_dirty(inode);
+ return 0;
+
cifs_setattr_exit:
kfree(full_path);
FreeXid(xid);
diff --git a/fs/compat.c b/fs/compat.c
index f0b391c50552..ce02278b9c83 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -626,7 +626,7 @@ ssize_t compat_rw_copy_check_uvector(int type,
tot_len += len;
if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
goto out;
- if (!access_ok(vrfy_dir(type), buf, len)) {
+ if (!access_ok(vrfy_dir(type), compat_ptr(buf), len)) {
ret = -EFAULT;
goto out;
}
@@ -1193,11 +1193,10 @@ out:
if (iov != iovstack)
kfree(iov);
if ((ret + (type == READ)) > 0) {
- struct dentry *dentry = file->f_path.dentry;
if (type == READ)
- fsnotify_access(dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 41645142b88b..cf78d44a8d6a 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -72,10 +72,6 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
if (!sd)
return -EINVAL;
- error = simple_setattr(dentry, iattr);
- if (error)
- return error;
-
sd_iattr = sd->s_iattr;
if (!sd_iattr) {
/* setting attributes for the first time, allocate now */
@@ -89,9 +85,12 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
sd->s_iattr = sd_iattr;
}
-
/* attributes were changed atleast once in past */
+ error = simple_setattr(dentry, iattr);
+ if (error)
+ return error;
+
if (ia_valid & ATTR_UID)
sd_iattr->ia_uid = iattr->ia_uid;
if (ia_valid & ATTR_GID)
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 7600aacf531d..88b1ab2354fa 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -1134,8 +1134,27 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode,
return ret;
}
+/*
+ * This is a library function for use by filesystem drivers.
+ *
+ * The locking rules are governed by the flags parameter:
+ * - if the flags value contains DIO_LOCKING we use a fancy locking
+ * scheme for dumb filesystems.
+ * For writes this function is called under i_mutex and returns with
+ * i_mutex held, for reads, i_mutex is not held on entry, but it is
+ * taken and dropped again before returning.
+ * For reads and writes i_alloc_sem is taken in shared mode and released
+ * on I/O completion (which may happen asynchronously after returning to
+ * the caller).
+ *
+ * - if the flags value does NOT contain DIO_LOCKING we don't use any
+ * internal locking but rather rely on the filesystem to synchronize
+ * direct I/O reads/writes versus each other and truncate.
+ * For reads and writes both i_mutex and i_alloc_sem are not held on
+ * entry and are never taken.
+ */
ssize_t
-__blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
+__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
struct block_device *bdev, const struct iovec *iov, loff_t offset,
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
dio_submit_t submit_io, int flags)
@@ -1231,57 +1250,4 @@ __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
out:
return retval;
}
-EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc);
-
-/*
- * This is a library function for use by filesystem drivers.
- *
- * The locking rules are governed by the flags parameter:
- * - if the flags value contains DIO_LOCKING we use a fancy locking
- * scheme for dumb filesystems.
- * For writes this function is called under i_mutex and returns with
- * i_mutex held, for reads, i_mutex is not held on entry, but it is
- * taken and dropped again before returning.
- * For reads and writes i_alloc_sem is taken in shared mode and released
- * on I/O completion (which may happen asynchronously after returning to
- * the caller).
- *
- * - if the flags value does NOT contain DIO_LOCKING we don't use any
- * internal locking but rather rely on the filesystem to synchronize
- * direct I/O reads/writes versus each other and truncate.
- * For reads and writes both i_mutex and i_alloc_sem are not held on
- * entry and are never taken.
- */
-ssize_t
-__blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
- struct block_device *bdev, const struct iovec *iov, loff_t offset,
- unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
- dio_submit_t submit_io, int flags)
-{
- ssize_t retval;
-
- retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov,
- offset, nr_segs, get_block, end_io, submit_io, flags);
- /*
- * In case of error extending write may have instantiated a few
- * blocks outside i_size. Trim these off again for DIO_LOCKING.
- * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in
- * their own manner. This is a further example of where the old
- * truncate sequence is inadequate.
- *
- * NOTE: filesystems with their own locking have to handle this
- * on their own.
- */
- if (flags & DIO_LOCKING) {
- if (unlikely((rw & WRITE) && retval < 0)) {
- loff_t isize = i_size_read(inode);
- loff_t end = offset + iov_length(iov, nr_segs);
-
- if (end > isize)
- vmtruncate(inode, isize);
- }
- }
-
- return retval;
-}
EXPORT_SYMBOL(__blockdev_direct_IO);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 31ef5252f0fe..82900b063b1e 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -804,10 +804,20 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
size_t num_zeros = (PAGE_CACHE_SIZE
- (ia->ia_size & ~PAGE_CACHE_MASK));
+
+ /*
+ * XXX(truncate) this should really happen at the begginning
+ * of ->setattr. But the code is too messy to that as part
+ * of a larger patch. ecryptfs is also totally missing out
+ * on the inode_change_ok check at the beginning of
+ * ->setattr while would include this.
+ */
+ rc = inode_newsize_ok(inode, ia->ia_size);
+ if (rc)
+ goto out;
+
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) {
- rc = simple_setsize(inode, ia->ia_size);
- if (rc)
- goto out;
+ truncate_setsize(inode, ia->ia_size);
lower_ia->ia_size = ia->ia_size;
lower_ia->ia_valid |= ATTR_SIZE;
goto out;
@@ -830,7 +840,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia,
goto out;
}
}
- simple_setsize(inode, ia->ia_size);
+ truncate_setsize(inode, ia->ia_size);
rc = ecryptfs_write_inode_size_to_metadata(inode);
if (rc) {
printk(KERN_ERR "Problem with "
diff --git a/fs/exec.c b/fs/exec.c
index e19de6a80339..f2de04a01a2a 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -129,7 +129,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
error = -ENOEXEC;
if(file->f_op) {
@@ -683,7 +683,7 @@ struct file *open_exec(const char *name)
if (file->f_path.mnt->mnt_flags & MNT_NOEXEC)
goto exit;
- fsnotify_open(file->f_path.dentry);
+ fsnotify_open(file);
err = deny_write_access(file);
if (err)
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 4bb6ef822e46..4bfc1f4fd013 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -887,8 +887,18 @@ int exofs_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
return error;
- error = inode_setattr(inode, iattr);
- return error;
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(inode)) {
+ int error;
+
+ error = vmtruncate(inode, iattr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
+ return 0;
}
static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF(
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index ca7e2a0ed98a..2bcc0431bada 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -200,6 +200,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
return error;
else {
inode->i_mode = mode;
+ inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
if (error == 0)
acl = NULL;
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 7516957273ed..764109886ec0 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -448,6 +448,11 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child)
return res;
}
+static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len)
+{
+ return __block_write_begin(page, pos, len, ext2_get_block);
+}
+
/* Releases the page */
void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
struct page *page, struct inode *inode, int update_times)
@@ -458,8 +463,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de,
int err;
lock_page(page);
- err = __ext2_write_begin(NULL, page->mapping, pos, len,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = ext2_prepare_chunk(page, pos, len);
BUG_ON(err);
de->inode = cpu_to_le32(inode->i_ino);
ext2_set_de_type(de, inode);
@@ -542,8 +546,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
got_it:
pos = page_offset(page) +
(char*)de - (char*)page_address(page);
- err = __ext2_write_begin(NULL, page->mapping, pos, rec_len, 0,
- &page, NULL);
+ err = ext2_prepare_chunk(page, pos, rec_len);
if (err)
goto out_unlock;
if (de->inode) {
@@ -576,8 +579,7 @@ out_unlock:
*/
int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
{
- struct address_space *mapping = page->mapping;
- struct inode *inode = mapping->host;
+ struct inode *inode = page->mapping->host;
char *kaddr = page_address(page);
unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1);
unsigned to = ((char *)dir - kaddr) +
@@ -601,8 +603,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page )
from = (char*)pde - (char*)page_address(page);
pos = page_offset(page) + from;
lock_page(page);
- err = __ext2_write_begin(NULL, page->mapping, pos, to - from, 0,
- &page, NULL);
+ err = ext2_prepare_chunk(page, pos, to - from);
BUG_ON(err);
if (pde)
pde->rec_len = ext2_rec_len_to_disk(to - from);
@@ -621,8 +622,7 @@ out:
*/
int ext2_make_empty(struct inode *inode, struct inode *parent)
{
- struct address_space *mapping = inode->i_mapping;
- struct page *page = grab_cache_page(mapping, 0);
+ struct page *page = grab_cache_page(inode->i_mapping, 0);
unsigned chunk_size = ext2_chunk_size(inode);
struct ext2_dir_entry_2 * de;
int err;
@@ -631,8 +631,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent)
if (!page)
return -ENOMEM;
- err = __ext2_write_begin(NULL, page->mapping, 0, chunk_size, 0,
- &page, NULL);
+ err = ext2_prepare_chunk(page, 0, chunk_size);
if (err) {
unlock_page(page);
goto fail;
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 52b34f1d2738..8f53d11bf957 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -127,9 +127,6 @@ extern void ext2_set_inode_flags(struct inode *inode);
extern void ext2_get_inode_flags(struct ext2_inode_info *);
extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 start, u64 len);
-int __ext2_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata);
/* ioctl.c */
extern long ext2_ioctl(struct file *, unsigned int, unsigned long);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 19214435b752..069620b30d4d 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -765,14 +765,6 @@ ext2_readpages(struct file *file, struct address_space *mapping,
return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
}
-int __ext2_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
-{
- return block_write_begin_newtrunc(file, mapping, pos, len, flags,
- pagep, fsdata, ext2_get_block);
-}
-
static int
ext2_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
@@ -780,8 +772,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping,
{
int ret;
- *pagep = NULL;
- ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ ext2_get_block);
if (ret < 0)
ext2_write_failed(mapping, pos + len);
return ret;
@@ -806,13 +798,8 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping,
{
int ret;
- /*
- * Dir-in-pagecache still uses ext2_write_begin. Would have to rework
- * directory handling code to pass around offsets rather than struct
- * pages in order to make this work easily.
- */
- ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep,
- fsdata, ext2_get_block);
+ ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
+ ext2_get_block);
if (ret < 0)
ext2_write_failed(mapping, pos + len);
return ret;
@@ -838,7 +825,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
struct inode *inode = mapping->host;
ssize_t ret;
- ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
iov, offset, nr_segs, ext2_get_block, NULL);
if (ret < 0 && (rw & WRITE))
ext2_write_failed(mapping, offset + iov_length(iov, nr_segs));
@@ -1169,15 +1156,10 @@ static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
__ext2_truncate_blocks(inode, offset);
}
-int ext2_setsize(struct inode *inode, loff_t newsize)
+static int ext2_setsize(struct inode *inode, loff_t newsize)
{
- loff_t oldsize;
int error;
- error = inode_newsize_ok(inode, newsize);
- if (error)
- return error;
-
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)))
return -EINVAL;
@@ -1197,10 +1179,7 @@ int ext2_setsize(struct inode *inode, loff_t newsize)
if (error)
return error;
- oldsize = inode->i_size;
- i_size_write(inode, newsize);
- truncate_pagecache(inode, oldsize, newsize);
-
+ truncate_setsize(inode, newsize);
__ext2_truncate_blocks(inode, newsize);
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
@@ -1552,12 +1531,12 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
return error;
}
- if (iattr->ia_valid & ATTR_SIZE) {
+ if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) {
error = ext2_setsize(inode, iattr->ia_size);
if (error)
return error;
}
- generic_setattr(inode, iattr);
+ setattr_copy(inode, iattr);
if (iattr->ia_valid & ATTR_MODE)
error = ext2_acl_chmod(inode);
mark_inode_dirty(inode);
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 01552abbca3c..8a11fe212183 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -205,6 +205,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
return error;
else {
inode->i_mode = mode;
+ inode->i_ctime = CURRENT_TIME_SEC;
ext3_mark_inode_dirty(handle, inode);
if (error == 0)
acl = NULL;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 735f0190ec2a..b04d11936683 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1196,8 +1196,7 @@ retry:
ret = PTR_ERR(handle);
goto out;
}
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- ext3_get_block);
+ ret = __block_write_begin(page, pos, len, ext3_get_block);
if (ret)
goto write_begin_failed;
@@ -1785,6 +1784,17 @@ retry:
ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext3_get_block, NULL);
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@@ -3198,9 +3208,17 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
ext3_journal_stop(handle);
}
- rc = inode_setattr(inode, attr);
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ rc = vmtruncate(inode, attr->ia_size);
+ if (rc)
+ goto err_out;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
- if (!rc && (ia_valid & ATTR_MODE))
+ if (ia_valid & ATTR_MODE)
rc = ext3_acl_chmod(inode);
err_out:
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 19df61c321fd..2ca4d8271770 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1578,11 +1578,9 @@ retry:
*pagep = page;
if (ext4_should_dioread_nolock(inode))
- ret = block_write_begin(file, mapping, pos, len, flags, pagep,
- fsdata, ext4_get_block_write);
+ ret = __block_write_begin(page, pos, len, ext4_get_block_write);
else
- ret = block_write_begin(file, mapping, pos, len, flags, pagep,
- fsdata, ext4_get_block);
+ ret = __block_write_begin(page, pos, len, ext4_get_block);
if (!ret && ext4_should_journal_data(inode)) {
ret = walk_page_buffers(handle, page_buffers(page),
@@ -1593,7 +1591,7 @@ retry:
unlock_page(page);
page_cache_release(page);
/*
- * block_write_begin may have instantiated a few blocks
+ * __block_write_begin may have instantiated a few blocks
* outside i_size. Trim these off again. Don't need
* i_size_read because we hold i_mutex.
*
@@ -3185,8 +3183,7 @@ retry:
}
*pagep = page;
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- ext4_da_get_block_prep);
+ ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep);
if (ret < 0) {
unlock_page(page);
ext4_journal_stop(handle);
@@ -3545,15 +3542,24 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb,
retry:
if (rw == READ && ext4_should_dioread_nolock(inode))
- ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
+ ret = __blockdev_direct_IO(rw, iocb, inode,
inode->i_sb->s_bdev, iov,
offset, nr_segs,
- ext4_get_block, NULL);
- else
+ ext4_get_block, NULL, NULL, 0);
+ else {
ret = blockdev_direct_IO(rw, iocb, inode,
inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext4_get_block, NULL);
+
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+ }
if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
goto retry;
@@ -4942,20 +4948,26 @@ void ext4_set_inode_flags(struct inode *inode)
/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */
void ext4_get_inode_flags(struct ext4_inode_info *ei)
{
- unsigned int flags = ei->vfs_inode.i_flags;
-
- ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
- EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL);
- if (flags & S_SYNC)
- ei->i_flags |= EXT4_SYNC_FL;
- if (flags & S_APPEND)
- ei->i_flags |= EXT4_APPEND_FL;
- if (flags & S_IMMUTABLE)
- ei->i_flags |= EXT4_IMMUTABLE_FL;
- if (flags & S_NOATIME)
- ei->i_flags |= EXT4_NOATIME_FL;
- if (flags & S_DIRSYNC)
- ei->i_flags |= EXT4_DIRSYNC_FL;
+ unsigned int vfs_fl;
+ unsigned long old_fl, new_fl;
+
+ do {
+ vfs_fl = ei->vfs_inode.i_flags;
+ old_fl = ei->i_flags;
+ new_fl = old_fl & ~(EXT4_SYNC_FL|EXT4_APPEND_FL|
+ EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|
+ EXT4_DIRSYNC_FL);
+ if (vfs_fl & S_SYNC)
+ new_fl |= EXT4_SYNC_FL;
+ if (vfs_fl & S_APPEND)
+ new_fl |= EXT4_APPEND_FL;
+ if (vfs_fl & S_IMMUTABLE)
+ new_fl |= EXT4_IMMUTABLE_FL;
+ if (vfs_fl & S_NOATIME)
+ new_fl |= EXT4_NOATIME_FL;
+ if (vfs_fl & S_DIRSYNC)
+ new_fl |= EXT4_DIRSYNC_FL;
+ } while (cmpxchg(&ei->i_flags, old_fl, new_fl) != old_fl);
}
static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode,
@@ -5191,7 +5203,7 @@ static int ext4_inode_blocks_set(handle_t *handle,
*/
raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
raw_inode->i_blocks_high = 0;
- ei->i_flags &= ~EXT4_HUGE_FILE_FL;
+ ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
return 0;
}
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE))
@@ -5204,9 +5216,9 @@ static int ext4_inode_blocks_set(handle_t *handle,
*/
raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32);
- ei->i_flags &= ~EXT4_HUGE_FILE_FL;
+ ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE);
} else {
- ei->i_flags |= EXT4_HUGE_FILE_FL;
+ ext4_set_inode_flag(inode, EXT4_INODE_HUGE_FILE);
/* i_block is stored in file system block size */
i_blocks = i_blocks >> (inode->i_blkbits - 9);
raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
@@ -5523,11 +5535,19 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
ext4_truncate(inode);
}
- rc = inode_setattr(inode, attr);
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode))
+ rc = vmtruncate(inode, attr->ia_size);
- /* If inode_setattr's call to ext4_truncate failed to get a
- * transaction handle at all, we need to clean up the in-core
- * orphan list manually. */
+ if (!rc) {
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ }
+
+ /*
+ * If the call to ext4_truncate failed to get a transaction handle at
+ * all, we need to clean up the in-core orphan list manually.
+ */
if (inode->i_nlink)
ext4_orphan_del(NULL, inode);
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 3a6c92ac131c..52abfa12762a 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -960,6 +960,9 @@ mext_check_arguments(struct inode *orig_inode,
return -EINVAL;
}
+ if (IS_IMMUTABLE(donor_inode) || IS_APPEND(donor_inode))
+ return -EPERM;
+
/* Ext4 move extent does not support swapfile */
if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) {
ext4_debug("ext4 move extent: The argument files should "
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 27ac25725954..d75a77f85c28 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -306,7 +306,6 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd,
extern const struct file_operations fat_file_operations;
extern const struct inode_operations fat_file_inode_operations;
extern int fat_setattr(struct dentry * dentry, struct iattr * attr);
-extern int fat_setsize(struct inode *inode, loff_t offset);
extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 990dfae022e5..7257752b6d5d 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -364,18 +364,6 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
return 0;
}
-int fat_setsize(struct inode *inode, loff_t offset)
-{
- int error;
-
- error = simple_setsize(inode, offset);
- if (error)
- return error;
- fat_truncate_blocks(inode, offset);
-
- return error;
-}
-
#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
/* valid file mode bits */
#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO)
@@ -387,21 +375,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
unsigned int ia_valid;
int error;
- /*
- * Expand the file. Since inode_setattr() updates ->i_size
- * before calling the ->truncate(), but FAT needs to fill the
- * hole before it. XXX: this is no longer true with new truncate
- * sequence.
- */
- if (attr->ia_valid & ATTR_SIZE) {
- if (attr->ia_size > inode->i_size) {
- error = fat_cont_expand(inode, attr->ia_size);
- if (error || attr->ia_valid == ATTR_SIZE)
- goto out;
- attr->ia_valid &= ~ATTR_SIZE;
- }
- }
-
/* Check for setting the inode time. */
ia_valid = attr->ia_valid;
if (ia_valid & TIMES_SET_FLAGS) {
@@ -417,6 +390,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
goto out;
}
+ /*
+ * Expand the file. Since inode_setattr() updates ->i_size
+ * before calling the ->truncate(), but FAT needs to fill the
+ * hole before it. XXX: this is no longer true with new truncate
+ * sequence.
+ */
+ if (attr->ia_valid & ATTR_SIZE) {
+ if (attr->ia_size > inode->i_size) {
+ error = fat_cont_expand(inode, attr->ia_size);
+ if (error || attr->ia_valid == ATTR_SIZE)
+ goto out;
+ attr->ia_valid &= ~ATTR_SIZE;
+ }
+ }
+
if (((attr->ia_valid & ATTR_UID) &&
(attr->ia_uid != sbi->options.fs_uid)) ||
((attr->ia_valid & ATTR_GID) &&
@@ -441,12 +429,11 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
}
if (attr->ia_valid & ATTR_SIZE) {
- error = fat_setsize(inode, attr->ia_size);
- if (error)
- goto out;
+ truncate_setsize(inode, attr->ia_size);
+ fat_truncate_blocks(inode, attr->ia_size);
}
- generic_setattr(inode, attr);
+ setattr_copy(inode, attr);
mark_inode_dirty(inode);
out:
return error;
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 7bf45aee56d7..ec6a699a4023 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -159,7 +159,7 @@ static int fat_write_begin(struct file *file, struct address_space *mapping,
int err;
*pagep = NULL;
- err = cont_write_begin_newtrunc(file, mapping, pos, len, flags,
+ err = cont_write_begin(file, mapping, pos, len, flags,
pagep, fsdata, fat_get_block,
&MSDOS_I(mapping->host)->mmu_private);
if (err < 0)
@@ -212,8 +212,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
* FAT need to use the DIO_LOCKING for avoiding the race
* condition of fat_get_block() and ->truncate().
*/
- ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev,
- iov, offset, nr_segs, fat_get_block, NULL);
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
+ iov, offset, nr_segs, fat_get_block, NULL);
if (ret < 0 && (rw & WRITE))
fat_write_failed(mapping, offset + iov_length(iov, nr_segs));
diff --git a/fs/fcntl.c b/fs/fcntl.c
index f74d270ba155..51e11bf5708f 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -274,7 +274,7 @@ static int f_setown_ex(struct file *filp, unsigned long arg)
ret = copy_from_user(&owner, owner_p, sizeof(owner));
if (ret)
- return ret;
+ return -EFAULT;
switch (owner.type) {
case F_OWNER_TID:
@@ -332,8 +332,11 @@ static int f_getown_ex(struct file *filp, unsigned long arg)
}
read_unlock(&filp->f_owner.lock);
- if (!ret)
+ if (!ret) {
ret = copy_to_user(owner_p, &owner, sizeof(owner));
+ if (ret)
+ ret = -EFAULT;
+ }
return ret;
}
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index ea8592b90696..1d1088f48bc2 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -45,7 +45,6 @@ struct wb_writeback_args {
unsigned int for_kupdate:1;
unsigned int range_cyclic:1;
unsigned int for_background:1;
- unsigned int sb_pinned:1;
};
/*
@@ -193,8 +192,7 @@ static void bdi_wait_on_work_clear(struct bdi_work *work)
}
static void bdi_alloc_queue_work(struct backing_dev_info *bdi,
- struct wb_writeback_args *args,
- int wait)
+ struct wb_writeback_args *args)
{
struct bdi_work *work;
@@ -206,8 +204,6 @@ static void bdi_alloc_queue_work(struct backing_dev_info *bdi,
if (work) {
bdi_work_init(work, args);
bdi_queue_work(bdi, work);
- if (wait)
- bdi_wait_on_work_clear(work);
} else {
struct bdi_writeback *wb = &bdi->wb;
@@ -234,11 +230,6 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi,
.sync_mode = WB_SYNC_ALL,
.nr_pages = LONG_MAX,
.range_cyclic = 0,
- /*
- * Setting sb_pinned is not necessary for WB_SYNC_ALL, but
- * lets make it explicitly clear.
- */
- .sb_pinned = 1,
};
struct bdi_work work;
@@ -254,23 +245,21 @@ static void bdi_sync_writeback(struct backing_dev_info *bdi,
* @bdi: the backing device to write from
* @sb: write inodes from this super_block
* @nr_pages: the number of pages to write
- * @sb_locked: caller already holds sb umount sem.
*
* Description:
* This does WB_SYNC_NONE opportunistic writeback. The IO is only
* started when this function returns, we make no guarentees on
- * completion. Caller specifies whether sb umount sem is held already or not.
+ * completion. Caller need not hold sb s_umount semaphore.
*
*/
void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
- long nr_pages, int sb_locked)
+ long nr_pages)
{
struct wb_writeback_args args = {
.sb = sb,
.sync_mode = WB_SYNC_NONE,
.nr_pages = nr_pages,
.range_cyclic = 1,
- .sb_pinned = sb_locked,
};
/*
@@ -282,7 +271,7 @@ void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
args.for_background = 1;
}
- bdi_alloc_queue_work(bdi, &args, sb_locked);
+ bdi_alloc_queue_work(bdi, &args);
}
/*
@@ -595,7 +584,7 @@ static enum sb_pin_state pin_sb_for_writeback(struct writeback_control *wbc,
/*
* Caller must already hold the ref for this
*/
- if (wbc->sync_mode == WB_SYNC_ALL || wbc->sb_pinned) {
+ if (wbc->sync_mode == WB_SYNC_ALL) {
WARN_ON(!rwsem_is_locked(&sb->s_umount));
return SB_NOT_PINNED;
}
@@ -769,7 +758,6 @@ static long wb_writeback(struct bdi_writeback *wb,
.for_kupdate = args->for_kupdate,
.for_background = args->for_background,
.range_cyclic = args->range_cyclic,
- .sb_pinned = args->sb_pinned,
};
unsigned long oldest_jif;
long wrote = 0;
@@ -912,7 +900,6 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
while ((work = get_next_work_item(bdi, wb)) != NULL) {
struct wb_writeback_args args = work->args;
- int post_clear;
/*
* Override sync mode, in case we must wait for completion
@@ -920,13 +907,11 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
if (force_wait)
work->args.sync_mode = args.sync_mode = WB_SYNC_ALL;
- post_clear = WB_SYNC_ALL || args.sb_pinned;
-
/*
* If this isn't a data integrity operation, just notify
* that we have seen this work and we are now starting it.
*/
- if (!post_clear)
+ if (args.sync_mode == WB_SYNC_NONE)
wb_clear_pending(wb, work);
wrote += wb_writeback(wb, &args);
@@ -935,7 +920,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait)
* This is a data integrity writeback, so only do the
* notification when we have completed the work.
*/
- if (post_clear)
+ if (args.sync_mode == WB_SYNC_ALL)
wb_clear_pending(wb, work);
}
@@ -1011,7 +996,7 @@ static void bdi_writeback_all(struct super_block *sb, long nr_pages)
if (!bdi_has_dirty_io(bdi))
continue;
- bdi_alloc_queue_work(bdi, &args, 0);
+ bdi_alloc_queue_work(bdi, &args);
}
rcu_read_unlock();
@@ -1220,18 +1205,6 @@ static void wait_sb_inodes(struct super_block *sb)
iput(old_inode);
}
-static void __writeback_inodes_sb(struct super_block *sb, int sb_locked)
-{
- unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY);
- unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS);
- long nr_to_write;
-
- nr_to_write = nr_dirty + nr_unstable +
- (inodes_stat.nr_inodes - inodes_stat.nr_unused);
-
- bdi_start_writeback(sb->s_bdi, sb, nr_to_write, sb_locked);
-}
-
/**
* writeback_inodes_sb - writeback dirty inodes from given super_block
* @sb: the superblock
@@ -1243,21 +1216,16 @@ static void __writeback_inodes_sb(struct super_block *sb, int sb_locked)
*/
void writeback_inodes_sb(struct super_block *sb)
{
- __writeback_inodes_sb(sb, 0);
-}
-EXPORT_SYMBOL(writeback_inodes_sb);
+ unsigned long nr_dirty = global_page_state(NR_FILE_DIRTY);
+ unsigned long nr_unstable = global_page_state(NR_UNSTABLE_NFS);
+ long nr_to_write;
-/**
- * writeback_inodes_sb_locked - writeback dirty inodes from given super_block
- * @sb: the superblock
- *
- * Like writeback_inodes_sb(), except the caller already holds the
- * sb umount sem.
- */
-void writeback_inodes_sb_locked(struct super_block *sb)
-{
- __writeback_inodes_sb(sb, 1);
+ nr_to_write = nr_dirty + nr_unstable +
+ (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+
+ bdi_start_writeback(sb->s_bdi, sb, nr_to_write);
}
+EXPORT_SYMBOL(writeback_inodes_sb);
/**
* writeback_inodes_sb_if_idle - start writeback if none underway
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 47aefd376e54..723b889fd219 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -710,30 +710,26 @@ static void fscache_write_op(struct fscache_operation *_op)
goto superseded;
}
- if (page) {
- radix_tree_tag_set(&cookie->stores, page->index,
- FSCACHE_COOKIE_STORING_TAG);
- radix_tree_tag_clear(&cookie->stores, page->index,
- FSCACHE_COOKIE_PENDING_TAG);
- }
+ radix_tree_tag_set(&cookie->stores, page->index,
+ FSCACHE_COOKIE_STORING_TAG);
+ radix_tree_tag_clear(&cookie->stores, page->index,
+ FSCACHE_COOKIE_PENDING_TAG);
spin_unlock(&cookie->stores_lock);
spin_unlock(&object->lock);
- if (page) {
- fscache_set_op_state(&op->op, "Store");
- fscache_stat(&fscache_n_store_pages);
- fscache_stat(&fscache_n_cop_write_page);
- ret = object->cache->ops->write_page(op, page);
- fscache_stat_d(&fscache_n_cop_write_page);
- fscache_set_op_state(&op->op, "EndWrite");
- fscache_end_page_write(object, page);
- if (ret < 0) {
- fscache_set_op_state(&op->op, "Abort");
- fscache_abort_object(object);
- } else {
- fscache_enqueue_operation(&op->op);
- }
+ fscache_set_op_state(&op->op, "Store");
+ fscache_stat(&fscache_n_store_pages);
+ fscache_stat(&fscache_n_cop_write_page);
+ ret = object->cache->ops->write_page(op, page);
+ fscache_stat_d(&fscache_n_cop_write_page);
+ fscache_set_op_state(&op->op, "EndWrite");
+ fscache_end_page_write(object, page);
+ if (ret < 0) {
+ fscache_set_op_state(&op->op, "Abort");
+ fscache_abort_object(object);
+ } else {
+ fscache_enqueue_operation(&op->op);
}
_leave("");
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3cdc5f78a406..3978a42d4f04 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1270,21 +1270,18 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
if (!fuse_allow_task(fc, current))
return -EACCES;
- if (fc->flags & FUSE_DEFAULT_PERMISSIONS) {
- err = inode_change_ok(inode, attr);
- if (err)
- return err;
- }
+ if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
+ attr->ia_valid |= ATTR_FORCE;
+
+ err = inode_change_ok(inode, attr);
+ if (err)
+ return err;
if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc)
return 0;
- if (attr->ia_valid & ATTR_SIZE) {
- err = inode_newsize_ok(inode, attr->ia_size);
- if (err)
- return err;
+ if (attr->ia_valid & ATTR_SIZE)
is_truncate = true;
- }
req = fuse_get_req(fc);
if (IS_ERR(req))
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index 9f8b52500d63..54fe087bf54c 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -702,12 +702,12 @@ out:
page_cache_release(page);
/*
- * XXX(hch): the call below should probably be replaced with
+ * XXX(truncate): the call below should probably be replaced with
* a call to the gfs2-specific truncate blocks helper to actually
* release disk blocks..
*/
if (pos + len > ip->i_inode.i_size)
- simple_setsize(&ip->i_inode, ip->i_inode.i_size);
+ truncate_setsize(&ip->i_inode, ip->i_inode.i_size);
out_endtrans:
gfs2_trans_end(sdp);
out_trans_fail:
@@ -1047,9 +1047,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
if (rv != 1)
goto out; /* dio not valid, fall back to buffered i/o */
- rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
- iov, offset, nr_segs,
- gfs2_get_block_direct, NULL);
+ rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ offset, nr_segs, gfs2_get_block_direct,
+ NULL, NULL, 0);
out:
gfs2_glock_dq_m(1, &gh);
gfs2_holder_uninit(&gh);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index b5612cbb62a5..fdf8cfefda45 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -987,18 +987,29 @@ fail:
static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
{
+ struct inode *inode = &ip->i_inode;
struct buffer_head *dibh;
int error;
error = gfs2_meta_inode_buffer(ip, &dibh);
- if (!error) {
- error = inode_setattr(&ip->i_inode, attr);
- gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
- gfs2_dinode_out(ip, dibh->b_data);
- brelse(dibh);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
}
- return error;
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
+ gfs2_assert_warn(GFS2_SB(inode), !error);
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(ip, dibh->b_data);
+ brelse(dibh);
+ return 0;
}
/**
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 98cdd05f3316..1009be2c9737 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -1072,7 +1072,7 @@ int gfs2_permission(struct inode *inode, int mask)
}
/*
- * XXX: should be changed to have proper ordering by opencoding simple_setsize
+ * XXX(truncate): the truncate_setsize calls should be moved to the end.
*/
static int setattr_size(struct inode *inode, struct iattr *attr)
{
@@ -1084,10 +1084,8 @@ static int setattr_size(struct inode *inode, struct iattr *attr)
error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks);
if (error)
return error;
- error = simple_setsize(inode, attr->ia_size);
+ truncate_setsize(inode, attr->ia_size);
gfs2_trans_end(sdp);
- if (error)
- return error;
}
error = gfs2_truncatei(ip, attr->ia_size);
@@ -1136,8 +1134,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr)
if (error)
goto out_end_trans;
- error = inode_setattr(inode, attr);
- gfs2_assert_warn(sdp, !error);
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ int error;
+
+ error = vmtruncate(inode, attr->ia_size);
+ gfs2_assert_warn(sdp, !error);
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
gfs2_trans_add_bh(ip->i_gl, dibh, 1);
gfs2_dinode_out(ip, dibh->b_data);
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 49667d68769e..1ca894daf093 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1457,10 +1457,10 @@ static int gfs2_quota_get_xstate(struct super_block *sb,
switch (sdp->sd_args.ar_quota) {
case GFS2_QUOTA_ON:
- fqs->qs_flags |= (XFS_QUOTA_UDQ_ENFD | XFS_QUOTA_GDQ_ENFD);
+ fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD);
/*FALLTHRU*/
case GFS2_QUOTA_ACCOUNT:
- fqs->qs_flags |= (XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_GDQ_ACCT);
+ fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT);
break;
case GFS2_QUOTA_OFF:
break;
@@ -1506,7 +1506,7 @@ static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id,
qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
fdq->d_version = FS_DQUOT_VERSION;
- fdq->d_flags = (type == QUOTA_USER) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA;
fdq->d_id = id;
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit);
fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn);
@@ -1541,12 +1541,12 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
switch(type) {
case USRQUOTA:
type = QUOTA_USER;
- if (fdq->d_flags != XFS_USER_QUOTA)
+ if (fdq->d_flags != FS_USER_QUOTA)
return -EINVAL;
break;
case GRPQUOTA:
type = QUOTA_GROUP;
- if (fdq->d_flags != XFS_GROUP_QUOTA)
+ if (fdq->d_flags != FS_GROUP_QUOTA)
return -EINVAL;
break;
default:
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index 82f93da00d1b..776af6eb4bcb 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -1296,6 +1296,7 @@ fail:
int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
{
+ struct inode *inode = &ip->i_inode;
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_ea_location el;
struct buffer_head *dibh;
@@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
return error;
error = gfs2_meta_inode_buffer(ip, &dibh);
- if (!error) {
- error = inode_setattr(&ip->i_inode, attr);
- gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
- gfs2_trans_add_bh(ip->i_gl, dibh, 1);
- gfs2_dinode_out(ip, dibh->b_data);
- brelse(dibh);
+ if (error)
+ goto out_trans_end;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ int error;
+
+ error = vmtruncate(inode, attr->ia_size);
+ gfs2_assert_warn(GFS2_SB(inode), !error);
}
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(ip, dibh->b_data);
+ brelse(dibh);
+
+out_trans_end:
gfs2_trans_end(sdp);
return error;
}
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 14f5cb1b9fdc..87de671baa83 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -39,10 +39,19 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hfs_get_block,
&HFS_I(mapping->host)->phys_size);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t hfs_bmap(struct address_space *mapping, sector_t block)
@@ -112,9 +121,24 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfs_get_block, NULL);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+
+ return ret;
}
static int hfs_writepages(struct address_space *mapping,
@@ -588,10 +612,16 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
attr->ia_mode = inode->i_mode & ~S_IWUGO;
attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask;
}
- error = inode_setattr(inode, attr);
- if (error)
- return error;
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
return 0;
}
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 9bbb82924a22..654c5a8ddf1c 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -31,10 +31,19 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hfsplus_get_block,
&HFSPLUS_I(mapping->host).phys_size);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
@@ -105,9 +114,24 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, hfsplus_get_block, NULL);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+
+ return ret;
}
static int hfsplus_writepages(struct address_space *mapping,
@@ -266,9 +290,31 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
return 0;
}
+static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate,
+ .setattr = hfsplus_setattr,
.setxattr = hfsplus_setxattr,
.getxattr = hfsplus_getxattr,
.listxattr = hfsplus_listxattr,
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 87ac1891a185..7943ff11d489 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -849,13 +849,14 @@ int hostfs_permission(struct inode *ino, int desired)
int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
{
+ struct inode *inode = dentry->d_inode;
struct hostfs_iattr attrs;
char *name;
int err;
- int fd = HOSTFS_I(dentry->d_inode)->fd;
+ int fd = HOSTFS_I(inode)->fd;
- err = inode_change_ok(dentry->d_inode, attr);
+ err = inode_change_ok(inode, attr);
if (err)
return err;
@@ -905,7 +906,18 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
return err;
- return inode_setattr(dentry->d_inode, attr);
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ int error;
+
+ error = vmtruncate(inode, attr->ia_size);
+ if (err)
+ return err;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
static const struct inode_operations hostfs_iops = {
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index a9ae9bfa752f..c0340887c7ea 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -97,10 +97,19 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
hpfs_get_block,
&hpfs_i(mapping->host)->mmu_private);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 1042a9bc97f3..3f3b397fd4e6 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr)
if (error)
goto out_unlock;
- error = inode_setattr(inode, attr);
- if (error)
- goto out_unlock;
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
hpfs_write_inode(inode);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index a4e9a7ec3691..d5f019d48b09 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -448,19 +448,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (error)
- goto out;
+ return error;
if (ia_valid & ATTR_SIZE) {
error = -EINVAL;
- if (!(attr->ia_size & ~huge_page_mask(h)))
- error = hugetlb_vmtruncate(inode, attr->ia_size);
+ if (attr->ia_size & ~huge_page_mask(h))
+ return -EINVAL;
+ error = hugetlb_vmtruncate(inode, attr->ia_size);
if (error)
- goto out;
- attr->ia_valid &= ~ATTR_SIZE;
+ return error;
}
- error = inode_setattr(inode, attr);
-out:
- return error;
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
diff --git a/fs/inode.c b/fs/inode.c
index 2bee20ae3d65..1fba60268087 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -20,7 +20,6 @@
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
-#include <linux/inotify.h>
#include <linux/fsnotify.h>
#include <linux/mount.h>
#include <linux/async.h>
@@ -264,12 +263,8 @@ void inode_init_once(struct inode *inode)
INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap);
INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
i_size_ordered_init(inode);
-#ifdef CONFIG_INOTIFY
- INIT_LIST_HEAD(&inode->inotify_watches);
- mutex_init(&inode->inotify_mutex);
-#endif
#ifdef CONFIG_FSNOTIFY
- INIT_HLIST_HEAD(&inode->i_fsnotify_mark_entries);
+ INIT_HLIST_HEAD(&inode->i_fsnotify_marks);
#endif
}
EXPORT_SYMBOL(inode_init_once);
@@ -413,7 +408,6 @@ int invalidate_inodes(struct super_block *sb)
down_write(&iprune_sem);
spin_lock(&inode_lock);
- inotify_unmount_inodes(&sb->s_inodes);
fsnotify_unmount_inodes(&sb->s_inodes);
busy = invalidate_list(&sb->s_inodes, &throw_away);
spin_unlock(&inode_lock);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 7aa4417e085f..166062a68230 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -222,15 +222,18 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode,
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime));
jffs2_free_raw_inode(ri);
- d_instantiate(dentry, inode);
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
inode->i_ino, inode->i_mode, inode->i_nlink,
f->inocache->pino_nlink, inode->i_mapping->nrpages));
+
+ d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
fail:
make_bad_inode(inode);
+ unlock_new_inode(inode);
iput(inode);
jffs2_free_raw_inode(ri);
return ret;
@@ -360,8 +363,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
/* Eeek. Wave bye bye */
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return PTR_ERR(fn);
+ ret = PTR_ERR(fn);
+ goto fail;
}
/* We use f->target field to store the target path. */
@@ -370,8 +373,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
memcpy(f->target, target, targetlen + 1);
@@ -386,30 +389,24 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
+
ret = jffs2_init_acl_post(inode);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
rd = jffs2_alloc_raw_dirent();
if (!rd) {
/* Argh. Now we treat it like a normal delete */
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
dir_f = JFFS2_INODE_INFO(dir_i);
@@ -437,8 +434,8 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
mutex_unlock(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
+ ret = PTR_ERR(fd);
+ goto fail;
}
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
@@ -453,7 +450,14 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
+
+ fail:
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ return ret;
}
@@ -519,8 +523,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
/* Eeek. Wave bye bye */
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return PTR_ERR(fn);
+ ret = PTR_ERR(fn);
+ goto fail;
}
/* No data here. Only a metadata node, which will be
obsoleted by the first data write
@@ -531,30 +535,24 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
+
ret = jffs2_init_acl_post(inode);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
rd = jffs2_alloc_raw_dirent();
if (!rd) {
/* Argh. Now we treat it like a normal delete */
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
dir_f = JFFS2_INODE_INFO(dir_i);
@@ -582,8 +580,8 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
mutex_unlock(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
+ ret = PTR_ERR(fd);
+ goto fail;
}
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
@@ -599,7 +597,14 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
+
+ fail:
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ return ret;
}
static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
@@ -693,8 +698,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
/* Eeek. Wave bye bye */
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return PTR_ERR(fn);
+ ret = PTR_ERR(fn);
+ goto fail;
}
/* No data here. Only a metadata node, which will be
obsoleted by the first data write
@@ -705,30 +710,24 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
jffs2_complete_reservation(c);
ret = jffs2_init_security(inode, dir_i);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
+
ret = jffs2_init_acl_post(inode);
- if (ret) {
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &alloclen,
ALLOC_NORMAL, JFFS2_SUMMARY_DIRENT_SIZE(namelen));
- if (ret) {
- /* Eep. */
- jffs2_clear_inode(inode);
- return ret;
- }
+ if (ret)
+ goto fail;
rd = jffs2_alloc_raw_dirent();
if (!rd) {
/* Argh. Now we treat it like a normal delete */
jffs2_complete_reservation(c);
- jffs2_clear_inode(inode);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto fail;
}
dir_f = JFFS2_INODE_INFO(dir_i);
@@ -759,8 +758,8 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
jffs2_complete_reservation(c);
jffs2_free_raw_dirent(rd);
mutex_unlock(&dir_f->sem);
- jffs2_clear_inode(inode);
- return PTR_ERR(fd);
+ ret = PTR_ERR(fd);
+ goto fail;
}
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
@@ -775,8 +774,14 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de
jffs2_complete_reservation(c);
d_instantiate(dentry, inode);
-
+ unlock_new_inode(inode);
return 0;
+
+ fail:
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ return ret;
}
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 8bc2c80ab159..1b2426604fe3 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -169,13 +169,13 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
mutex_unlock(&f->sem);
jffs2_complete_reservation(c);
- /* We have to do the simple_setsize() without f->sem held, since
+ /* We have to do the truncate_setsize() without f->sem held, since
some pages may be locked and waiting for it in readpage().
We are protected from a simultaneous write() extending i_size
back past iattr->ia_size, because do_truncate() holds the
generic inode semaphore. */
if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) {
- simple_setsize(inode, iattr->ia_size);
+ truncate_setsize(inode, iattr->ia_size);
inode->i_blocks = (inode->i_size + 511) >> 9;
}
@@ -465,7 +465,12 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
inode->i_blocks = 0;
inode->i_size = 0;
- insert_inode_hash(inode);
+ if (insert_inode_locked(inode) < 0) {
+ make_bad_inode(inode);
+ unlock_new_inode(inode);
+ iput(inode);
+ return ERR_PTR(-EINVAL);
+ }
return inode;
}
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index 127263cc8657..c5ce6c1d1ff4 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -17,6 +17,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/quotaops.h>
#include "jfs_incore.h"
@@ -107,11 +108,18 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
return rc;
}
- rc = inode_setattr(inode, iattr);
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(inode)) {
+ rc = vmtruncate(inode, iattr->ia_size);
+ if (rc)
+ return rc;
+ }
- if (!rc && (iattr->ia_valid & ATTR_MODE))
- rc = jfs_acl_chmod(inode);
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
+ if (iattr->ia_valid & ATTR_MODE)
+ rc = jfs_acl_chmod(inode);
return rc;
}
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index ed9ba6fe04f5..c38dc1806281 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -303,8 +303,17 @@ static int jfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ int ret;
+
+ ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata,
jfs_get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t jfs_bmap(struct address_space *mapping, sector_t block)
@@ -317,9 +326,24 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, jfs_get_block, NULL);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+
+ return ret;
}
const struct address_space_operations jfs_aops = {
diff --git a/fs/libfs.c b/fs/libfs.c
index 09e1016eb774..0a9da95317f7 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -327,77 +327,35 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
}
/**
- * simple_setsize - handle core mm and vfs requirements for file size change
- * @inode: inode
- * @newsize: new file size
- *
- * Returns 0 on success, -error on failure.
- *
- * simple_setsize must be called with inode_mutex held.
- *
- * simple_setsize will check that the requested new size is OK (see
- * inode_newsize_ok), and then will perform the necessary i_size update
- * and pagecache truncation (if necessary). It will be typically be called
- * from the filesystem's setattr function when ATTR_SIZE is passed in.
- *
- * The inode itself must have correct permissions and attributes to allow
- * i_size to be changed, this function then just checks that the new size
- * requested is valid.
- *
- * In the case of simple in-memory filesystems with inodes stored solely
- * in the inode cache, and file data in the pagecache, nothing more needs
- * to be done to satisfy a truncate request. Filesystems with on-disk
- * blocks for example will need to free them in the case of truncate, in
- * that case it may be easier not to use simple_setsize (but each of its
- * components will likely be required at some point to update pagecache
- * and inode etc).
- */
-int simple_setsize(struct inode *inode, loff_t newsize)
-{
- loff_t oldsize;
- int error;
-
- error = inode_newsize_ok(inode, newsize);
- if (error)
- return error;
-
- oldsize = inode->i_size;
- i_size_write(inode, newsize);
- truncate_pagecache(inode, oldsize, newsize);
-
- return error;
-}
-EXPORT_SYMBOL(simple_setsize);
-
-/**
- * simple_setattr - setattr for simple in-memory filesystem
+ * simple_setattr - setattr for simple filesystem
* @dentry: dentry
* @iattr: iattr structure
*
* Returns 0 on success, -error on failure.
*
- * simple_setattr implements setattr for an in-memory filesystem which
- * does not store its own file data or metadata (eg. uses the page cache
- * and inode cache as its data store).
+ * simple_setattr is a simple ->setattr implementation without a proper
+ * implementation of size changes.
+ *
+ * It can either be used for in-memory filesystems or special files
+ * on simple regular filesystems. Anything that needs to change on-disk
+ * or wire state on size changes needs its own setattr method.
*/
int simple_setattr(struct dentry *dentry, struct iattr *iattr)
{
struct inode *inode = dentry->d_inode;
int error;
+ WARN_ON_ONCE(inode->i_op->truncate);
+
error = inode_change_ok(inode, iattr);
if (error)
return error;
- if (iattr->ia_valid & ATTR_SIZE) {
- error = simple_setsize(inode, iattr->ia_size);
- if (error)
- return error;
- }
-
- generic_setattr(inode, iattr);
-
- return error;
+ if (iattr->ia_valid & ATTR_SIZE)
+ truncate_setsize(inode, iattr->ia_size);
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
+ return 0;
}
EXPORT_SYMBOL(simple_setattr);
@@ -489,7 +447,8 @@ int simple_write_end(struct file *file, struct address_space *mapping,
* unique inode values later for this filesystem, then you must take care
* to pass it an appropriate max_reserved value to avoid collisions.
*/
-int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files)
+int simple_fill_super(struct super_block *s, unsigned long magic,
+ struct tree_descr *files)
{
struct inode *inode;
struct dentry *root;
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 72d1893ddd36..e780b659b4c5 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -821,7 +821,7 @@ const struct inode_operations logfs_dir_iops = {
};
const struct file_operations logfs_dir_fops = {
.fsync = logfs_fsync,
- .ioctl = logfs_ioctl,
+ .unlocked_ioctl = logfs_ioctl,
.readdir = logfs_readdir,
.read = generic_read_dir,
};
diff --git a/fs/logfs/file.c b/fs/logfs/file.c
index abe1cafbd4c2..e86376b87af1 100644
--- a/fs/logfs/file.c
+++ b/fs/logfs/file.c
@@ -181,9 +181,9 @@ static int logfs_releasepage(struct page *page, gfp_t only_xfs_uses_this)
}
-int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
+long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = file->f_path.dentry->d_inode;
struct logfs_inode *li = logfs_inode(inode);
unsigned int oldflags, flags;
int err;
@@ -232,15 +232,19 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr)
struct inode *inode = dentry->d_inode;
int err = 0;
- if (attr->ia_valid & ATTR_SIZE)
+ err = inode_change_ok(inode, attr);
+ if (err)
+ return err;
+
+ if (attr->ia_valid & ATTR_SIZE) {
err = logfs_truncate(inode, attr->ia_size);
- attr->ia_valid &= ~ATTR_SIZE;
+ if (err)
+ return err;
+ }
- if (!err)
- err = inode_change_ok(inode, attr);
- if (!err)
- err = inode_setattr(inode, attr);
- return err;
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
const struct inode_operations logfs_reg_iops = {
@@ -251,7 +255,7 @@ const struct file_operations logfs_reg_fops = {
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.fsync = logfs_fsync,
- .ioctl = logfs_ioctl,
+ .unlocked_ioctl = logfs_ioctl,
.llseek = generic_file_llseek,
.mmap = generic_file_readonly_mmap,
.open = generic_file_open,
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h
index c838c4d72111..a6e8487e3844 100644
--- a/fs/logfs/logfs.h
+++ b/fs/logfs/logfs.h
@@ -504,8 +504,8 @@ extern const struct inode_operations logfs_reg_iops;
extern const struct file_operations logfs_reg_fops;
extern const struct address_space_operations logfs_reg_aops;
int logfs_readpage(struct file *file, struct page *page);
-int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg);
+long logfs_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg);
int logfs_fsync(struct file *file, int datasync);
/* gc.c */
diff --git a/fs/minix/dir.c b/fs/minix/dir.c
index 91969589131c..085a9262c692 100644
--- a/fs/minix/dir.c
+++ b/fs/minix/dir.c
@@ -75,10 +75,6 @@ static struct page * dir_get_page(struct inode *dir, unsigned long n)
if (!IS_ERR(page))
kmap(page);
return page;
-
-fail:
- dir_put_page(page);
- return ERR_PTR(-EIO);
}
static inline void *minix_next_entry(void *de, struct minix_sb_info *sbi)
@@ -275,8 +271,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode)
got_it:
pos = page_offset(page) + p - (char *)page_address(page);
- err = __minix_write_begin(NULL, page->mapping, pos, sbi->s_dirsize,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
if (err)
goto out_unlock;
memcpy (namx, name, namelen);
@@ -301,8 +296,7 @@ out_unlock:
int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
{
- struct address_space *mapping = page->mapping;
- struct inode *inode = (struct inode*)mapping->host;
+ struct inode *inode = page->mapping->host;
char *kaddr = page_address(page);
loff_t pos = page_offset(page) + (char*)de - kaddr;
struct minix_sb_info *sbi = minix_sb(inode->i_sb);
@@ -310,8 +304,7 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
int err;
lock_page(page);
- err = __minix_write_begin(NULL, mapping, pos, len,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = minix_prepare_chunk(page, pos, len);
if (err == 0) {
if (sbi->s_version == MINIX_V3)
((minix3_dirent *) de)->inode = 0;
@@ -329,16 +322,14 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page)
int minix_make_empty(struct inode *inode, struct inode *dir)
{
- struct address_space *mapping = inode->i_mapping;
- struct page *page = grab_cache_page(mapping, 0);
+ struct page *page = grab_cache_page(inode->i_mapping, 0);
struct minix_sb_info *sbi = minix_sb(inode->i_sb);
char *kaddr;
int err;
if (!page)
return -ENOMEM;
- err = __minix_write_begin(NULL, mapping, 0, 2 * sbi->s_dirsize,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = minix_prepare_chunk(page, 0, 2 * sbi->s_dirsize);
if (err) {
unlock_page(page);
goto fail;
@@ -429,8 +420,7 @@ not_empty:
void minix_set_link(struct minix_dir_entry *de, struct page *page,
struct inode *inode)
{
- struct address_space *mapping = page->mapping;
- struct inode *dir = mapping->host;
+ struct inode *dir = page->mapping->host;
struct minix_sb_info *sbi = minix_sb(dir->i_sb);
loff_t pos = page_offset(page) +
(char *)de-(char*)page_address(page);
@@ -438,8 +428,7 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page,
lock_page(page);
- err = __minix_write_begin(NULL, mapping, pos, sbi->s_dirsize,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = minix_prepare_chunk(page, pos, sbi->s_dirsize);
if (err == 0) {
if (sbi->s_version == MINIX_V3)
((minix3_dirent *) de)->inode = inode->i_ino;
diff --git a/fs/minix/file.c b/fs/minix/file.c
index d5320ff23faf..4493ce695ab8 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -23,7 +23,29 @@ const struct file_operations minix_file_operations = {
.splice_read = generic_file_splice_read,
};
+static int minix_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
const struct inode_operations minix_file_inode_operations = {
.truncate = minix_truncate,
+ .setattr = minix_setattr,
.getattr = minix_getattr,
};
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 756f8c93780c..125062f55ef2 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -357,20 +357,26 @@ static int minix_readpage(struct file *file, struct page *page)
return block_read_full_page(page,minix_get_block);
}
-int __minix_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
+int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- minix_get_block);
+ return __block_write_begin(page, pos, len, minix_get_block);
}
static int minix_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return __minix_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ minix_get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t minix_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/minix/minix.h b/fs/minix/minix.h
index 111f34ee9e3b..407b1c84911e 100644
--- a/fs/minix/minix.h
+++ b/fs/minix/minix.h
@@ -53,9 +53,7 @@ extern int minix_new_block(struct inode * inode);
extern void minix_free_block(struct inode *inode, unsigned long block);
extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi);
extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *);
-extern int __minix_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata);
+extern int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len);
extern void V1_minix_truncate(struct inode *);
extern void V2_minix_truncate(struct inode *);
diff --git a/fs/namei.c b/fs/namei.c
index 868d0cb9d473..0049114958e7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1484,8 +1484,7 @@ static int handle_truncate(struct path *path)
*/
error = locks_verify_locked(inode);
if (!error)
- error = security_path_truncate(path, 0,
- ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+ error = security_path_truncate(path);
if (!error) {
error = do_truncate(path->dentry, 0,
ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
@@ -2635,7 +2634,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
- const char *old_name;
+ const unsigned char *old_name;
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;
diff --git a/fs/namespace.c b/fs/namespace.c
index 88058de59c7c..1969d6b2571e 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -29,6 +29,7 @@
#include <linux/log2.h>
#include <linux/idr.h>
#include <linux/fs_struct.h>
+#include <linux/fsnotify.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "pnode.h"
@@ -150,6 +151,9 @@ struct vfsmount *alloc_vfsmnt(const char *name)
INIT_LIST_HEAD(&mnt->mnt_share);
INIT_LIST_HEAD(&mnt->mnt_slave_list);
INIT_LIST_HEAD(&mnt->mnt_slave);
+#ifdef CONFIG_FSNOTIFY
+ INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks);
+#endif
#ifdef CONFIG_SMP
mnt->mnt_writers = alloc_percpu(int);
if (!mnt->mnt_writers)
@@ -610,6 +614,7 @@ static inline void __mntput(struct vfsmount *mnt)
* provides barriers, so count_mnt_writers() below is safe. AV
*/
WARN_ON(count_mnt_writers(mnt));
+ fsnotify_vfsmount_delete(mnt);
dput(mnt->mnt_root);
free_vfsmnt(mnt);
deactivate_super(sb);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index fa3385154023..b4e8aaae14be 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -924,9 +924,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
tmpattr.ia_valid = ATTR_MODE;
tmpattr.ia_mode = attr->ia_mode;
- result = inode_setattr(inode, &tmpattr);
- if (result)
- goto out;
+ setattr_copy(inode, &tmpattr);
+ mark_inode_dirty(inode);
}
}
#endif
@@ -954,15 +953,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
result = ncp_make_closed(inode);
if (result)
goto out;
- {
- struct iattr tmpattr;
-
- tmpattr.ia_valid = ATTR_SIZE;
- tmpattr.ia_size = attr->ia_size;
-
- result = inode_setattr(inode, &tmpattr);
+
+ if (attr->ia_size != i_size_read(inode)) {
+ result = vmtruncate(inode, attr->ia_size);
if (result)
goto out;
+ mark_inode_dirty(inode);
}
}
if ((attr->ia_valid & ATTR_CTIME) != 0) {
@@ -1002,8 +998,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
NCP_FINFO(inode)->nwattr = info.attributes;
#endif
}
- if (!result)
- result = inode_setattr(inode, attr);
+ if (result)
+ goto out;
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
out:
unlock_kernel();
return result;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 36dfdae95123..e17b49e2eabd 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -45,7 +45,7 @@ unsigned short nfs_callback_tcpport;
unsigned short nfs_callback_tcpport6;
#define NFS_CALLBACK_MAXPORTNR (65535U)
-static int param_set_portnr(const char *val, struct kernel_param *kp)
+static int param_set_portnr(const char *val, const struct kernel_param *kp)
{
unsigned long num;
int ret;
@@ -58,11 +58,10 @@ static int param_set_portnr(const char *val, struct kernel_param *kp)
*((unsigned int *)kp->arg) = num;
return 0;
}
-
-static int param_get_portnr(char *buffer, struct kernel_param *kp)
-{
- return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_portnr = {
+ .set = param_set_portnr,
+ .get = param_get_uint,
+};
#define param_check_portnr(name, p) __param_check(name, p, unsigned int);
module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index eb78e7e22077..c8dd03c3f0fd 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr {
u32 minorversion;
/* res */
int status;
- u32 taglen;
- char *tag;
};
static struct {
@@ -293,13 +291,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
static int
decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
__be32 *p;
+ u32 taglen;
READ_BUF(8);
READ32(hdr->status);
- READ32(hdr->taglen);
- READ_BUF(hdr->taglen + 4);
- hdr->tag = (char *)p;
- p += XDR_QUADLEN(hdr->taglen);
+ /* We've got no use for the tag; ignore it: */
+ READ32(taglen);
+ READ_BUF(taglen + 4);
+ p += XDR_QUADLEN(taglen);
READ32(hdr->nops);
return 0;
}
@@ -667,7 +666,14 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
}
switch (task->tk_status) {
- case -EIO:
+ case 0:
+ return;
+ case -EBADHANDLE:
+ case -NFS4ERR_BAD_STATEID:
+ /* Race: client probably got cb_recall
+ * before open reply granting delegation */
+ break;
+ default:
/* Network partition? */
atomic_set(&clp->cl_cb_set, 0);
warn_no_callback_path(clp, task->tk_status);
@@ -676,14 +682,6 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
nfsd4_cb_recall(dp);
return;
}
- case -EBADHANDLE:
- case -NFS4ERR_BAD_STATEID:
- /* Race: client probably got cb_recall
- * before open reply granting delegation */
- break;
- default:
- /* success, or error we can't handle */
- return;
}
if (dp->dl_retries--) {
rpc_delay(task, 2*HZ);
@@ -752,7 +750,6 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
.rpc_cred = callback_cred
};
- int status;
if (clnt == NULL)
return; /* Client is shutting down; give up. */
@@ -760,10 +757,7 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
args->args_op = dp;
msg.rpc_argp = args;
dp->dl_retries = 1;
- status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
- &nfsd4_cb_recall_ops, dp);
- if (status)
- nfs4_put_delegation(dp);
+ rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
}
void nfsd4_do_callback_rpc(struct work_struct *w)
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 12f7109720c2..117670864af0 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -2255,6 +2255,13 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
return NULL;
}
+int share_access_to_flags(u32 share_access)
+{
+ share_access &= ~NFS4_SHARE_WANT_MASK;
+
+ return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
+}
+
static __be32
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
@@ -2265,8 +2272,7 @@ nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
if (*dp == NULL)
goto out;
- flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
- RD_STATE : WR_STATE;
+ flags = share_access_to_flags(open->op_share_access);
status = nfs4_check_delegmode(*dp, flags);
if (status)
*dp = NULL;
@@ -2358,6 +2364,7 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
struct file *filp = stp->st_vfs_file;
struct inode *inode = filp->f_path.dentry->d_inode;
unsigned int share_access, new_writer;
+ u32 op_share_access;
__be32 status;
set_access(&share_access, stp->st_access_bmap);
@@ -2380,8 +2387,9 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
return status;
}
/* remember the open */
- filp->f_mode |= open->op_share_access;
- __set_bit(open->op_share_access, &stp->st_access_bmap);
+ op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
+ filp->f_mode |= op_share_access;
+ __set_bit(op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
return nfs_ok;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index ebbf3b6b2457..660fa704e04f 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -952,7 +952,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += host_err;
*count = host_err;
err = 0;
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
} else
err = nfserrno(host_err);
out:
@@ -1063,7 +1063,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
goto out_nfserr;
*cnt = host_err;
nfsdstats.io_write += host_err;
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
/* clear setuid/setgid flag after write */
if (inode->i_mode & (S_ISUID | S_ISGID))
diff --git a/fs/nilfs2/btree.h b/fs/nilfs2/btree.h
index af638d59e3bf..43c8c5b541fd 100644
--- a/fs/nilfs2/btree.h
+++ b/fs/nilfs2/btree.h
@@ -75,8 +75,6 @@ struct nilfs_btree_path {
extern struct kmem_cache *nilfs_btree_path_cache;
-int nilfs_btree_path_cache_init(void);
-void nilfs_btree_path_cache_destroy(void);
int nilfs_btree_init(struct nilfs_bmap *);
int nilfs_btree_convert_and_insert(struct nilfs_bmap *, __u64, __u64,
const __u64 *, const __u64 *, int);
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c
index 85c89dfc71f0..d14e3b94d81f 100644
--- a/fs/nilfs2/dir.c
+++ b/fs/nilfs2/dir.c
@@ -80,23 +80,10 @@ static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr)
return last_byte;
}
-static int nilfs_prepare_chunk_uninterruptible(struct page *page,
- struct address_space *mapping,
- unsigned from, unsigned to)
+static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to)
{
loff_t pos = page_offset(page) + from;
- return block_write_begin(NULL, mapping, pos, to - from,
- AOP_FLAG_UNINTERRUPTIBLE, &page,
- NULL, nilfs_get_block);
-}
-
-static int nilfs_prepare_chunk(struct page *page,
- struct address_space *mapping,
- unsigned from, unsigned to)
-{
- loff_t pos = page_offset(page) + from;
- return block_write_begin(NULL, mapping, pos, to - from, 0, &page,
- NULL, nilfs_get_block);
+ return __block_write_begin(page, pos, to - from, nilfs_get_block);
}
static void nilfs_commit_chunk(struct page *page,
@@ -449,7 +436,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
int err;
lock_page(page);
- err = nilfs_prepare_chunk_uninterruptible(page, mapping, from, to);
+ err = nilfs_prepare_chunk(page, from, to);
BUG_ON(err);
de->inode = cpu_to_le64(inode->i_ino);
nilfs_set_de_type(de, inode);
@@ -530,7 +517,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode)
got_it:
from = (char *)de - (char *)page_address(page);
to = from + rec_len;
- err = nilfs_prepare_chunk(page, page->mapping, from, to);
+ err = nilfs_prepare_chunk(page, from, to);
if (err)
goto out_unlock;
if (de->inode) {
@@ -587,7 +574,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page)
if (pde)
from = (char *)pde - (char *)page_address(page);
lock_page(page);
- err = nilfs_prepare_chunk(page, mapping, from, to);
+ err = nilfs_prepare_chunk(page, from, to);
BUG_ON(err);
if (pde)
pde->rec_len = cpu_to_le16(to - from);
@@ -615,7 +602,7 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent)
if (!page)
return -ENOMEM;
- err = nilfs_prepare_chunk(page, mapping, 0, chunk_size);
+ err = nilfs_prepare_chunk(page, 0, chunk_size);
if (unlikely(err)) {
unlock_page(page);
goto fail;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 39e038ac8fcb..051d279abb37 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -197,11 +197,15 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping,
if (unlikely(err))
return err;
- *pagep = NULL;
- err = block_write_begin(file, mapping, pos, len, flags, pagep,
- fsdata, nilfs_get_block);
- if (unlikely(err))
+ err = block_write_begin(mapping, pos, len, flags, pagep,
+ nilfs_get_block);
+ if (unlikely(err)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+
nilfs_transaction_abort(inode->i_sb);
+ }
return err;
}
@@ -237,6 +241,19 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
/* Needs synchronization with the cleaner */
size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs, nilfs_get_block, NULL);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && size < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+
return size;
}
@@ -639,14 +656,27 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr)
err = nilfs_transaction_begin(sb, &ti, 0);
if (unlikely(err))
return err;
- err = inode_setattr(inode, iattr);
- if (!err && (iattr->ia_valid & ATTR_MODE))
+
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(inode)) {
+ err = vmtruncate(inode, iattr->ia_size);
+ if (unlikely(err))
+ goto out_err;
+ }
+
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
+
+ if (iattr->ia_valid & ATTR_MODE) {
err = nilfs_acl_chmod(inode);
- if (likely(!err))
- err = nilfs_transaction_commit(sb);
- else
- nilfs_transaction_abort(sb);
+ if (unlikely(err))
+ goto out_err;
+ }
+
+ return nilfs_transaction_commit(sb);
+out_err:
+ nilfs_transaction_abort(sb);
return err;
}
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c
index bae2a516b4ee..df2c4f01a09b 100644
--- a/fs/nilfs2/recovery.c
+++ b/fs/nilfs2/recovery.c
@@ -91,27 +91,9 @@ static int nilfs_warn_segment_error(int err)
return -EINVAL;
}
-static void store_segsum_info(struct nilfs_segsum_info *ssi,
- struct nilfs_segment_summary *sum,
- unsigned int blocksize)
-{
- ssi->flags = le16_to_cpu(sum->ss_flags);
- ssi->seg_seq = le64_to_cpu(sum->ss_seq);
- ssi->ctime = le64_to_cpu(sum->ss_create);
- ssi->next = le64_to_cpu(sum->ss_next);
- ssi->nblocks = le32_to_cpu(sum->ss_nblocks);
- ssi->nfinfo = le32_to_cpu(sum->ss_nfinfo);
- ssi->sumbytes = le32_to_cpu(sum->ss_sumbytes);
-
- ssi->nsumblk = DIV_ROUND_UP(ssi->sumbytes, blocksize);
- ssi->nfileblk = ssi->nblocks - ssi->nsumblk - !!NILFS_SEG_HAS_SR(ssi);
-
- /* need to verify ->ss_bytes field if read ->ss_cno */
-}
-
/**
- * calc_crc_cont - check CRC of blocks continuously
- * @sbi: nilfs_sb_info
+ * nilfs_compute_checksum - compute checksum of blocks continuously
+ * @nilfs: nilfs object
* @bhs: buffer head of start block
* @sum: place to store result
* @offset: offset bytes in the first block
@@ -119,23 +101,25 @@ static void store_segsum_info(struct nilfs_segsum_info *ssi,
* @start: DBN of start block
* @nblock: number of blocks to be checked
*/
-static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
- u32 *sum, unsigned long offset, u64 check_bytes,
- sector_t start, unsigned long nblock)
+static int nilfs_compute_checksum(struct the_nilfs *nilfs,
+ struct buffer_head *bhs, u32 *sum,
+ unsigned long offset, u64 check_bytes,
+ sector_t start, unsigned long nblock)
{
- unsigned long blocksize = sbi->s_super->s_blocksize;
+ unsigned int blocksize = nilfs->ns_blocksize;
unsigned long size;
u32 crc;
BUG_ON(offset >= blocksize);
check_bytes -= offset;
size = min_t(u64, check_bytes, blocksize - offset);
- crc = crc32_le(sbi->s_nilfs->ns_crc_seed,
+ crc = crc32_le(nilfs->ns_crc_seed,
(unsigned char *)bhs->b_data + offset, size);
if (--nblock > 0) {
do {
- struct buffer_head *bh
- = sb_bread(sbi->s_super, ++start);
+ struct buffer_head *bh;
+
+ bh = __bread(nilfs->ns_bdev, ++start, blocksize);
if (!bh)
return -EIO;
check_bytes -= size;
@@ -150,12 +134,12 @@ static int calc_crc_cont(struct nilfs_sb_info *sbi, struct buffer_head *bhs,
/**
* nilfs_read_super_root_block - read super root block
- * @sb: super_block
+ * @nilfs: nilfs object
* @sr_block: disk block number of the super root block
* @pbh: address of a buffer_head pointer to return super root buffer
* @check: CRC check flag
*/
-int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
+int nilfs_read_super_root_block(struct the_nilfs *nilfs, sector_t sr_block,
struct buffer_head **pbh, int check)
{
struct buffer_head *bh_sr;
@@ -164,7 +148,7 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
int ret;
*pbh = NULL;
- bh_sr = sb_bread(sb, sr_block);
+ bh_sr = __bread(nilfs->ns_bdev, sr_block, nilfs->ns_blocksize);
if (unlikely(!bh_sr)) {
ret = NILFS_SEG_FAIL_IO;
goto failed;
@@ -174,12 +158,13 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
if (check) {
unsigned bytes = le16_to_cpu(sr->sr_bytes);
- if (bytes == 0 || bytes > sb->s_blocksize) {
+ if (bytes == 0 || bytes > nilfs->ns_blocksize) {
ret = NILFS_SEG_FAIL_CHECKSUM_SUPER_ROOT;
goto failed_bh;
}
- if (calc_crc_cont(NILFS_SB(sb), bh_sr, &crc,
- sizeof(sr->sr_sum), bytes, sr_block, 1)) {
+ if (nilfs_compute_checksum(
+ nilfs, bh_sr, &crc, sizeof(sr->sr_sum), bytes,
+ sr_block, 1)) {
ret = NILFS_SEG_FAIL_IO;
goto failed_bh;
}
@@ -199,64 +184,76 @@ int nilfs_read_super_root_block(struct super_block *sb, sector_t sr_block,
}
/**
- * load_segment_summary - read segment summary of the specified partial segment
- * @sbi: nilfs_sb_info
- * @pseg_start: start disk block number of partial segment
- * @seg_seq: sequence number requested
- * @ssi: pointer to nilfs_segsum_info struct to store information
+ * nilfs_read_log_header - read summary header of the specified log
+ * @nilfs: nilfs object
+ * @start_blocknr: start block number of the log
+ * @sum: pointer to return segment summary structure
*/
-static int
-load_segment_summary(struct nilfs_sb_info *sbi, sector_t pseg_start,
- u64 seg_seq, struct nilfs_segsum_info *ssi)
+static struct buffer_head *
+nilfs_read_log_header(struct the_nilfs *nilfs, sector_t start_blocknr,
+ struct nilfs_segment_summary **sum)
{
struct buffer_head *bh_sum;
- struct nilfs_segment_summary *sum;
+
+ bh_sum = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
+ if (bh_sum)
+ *sum = (struct nilfs_segment_summary *)bh_sum->b_data;
+ return bh_sum;
+}
+
+/**
+ * nilfs_validate_log - verify consistency of log
+ * @nilfs: nilfs object
+ * @seg_seq: sequence number of segment
+ * @bh_sum: buffer head of summary block
+ * @sum: segment summary struct
+ */
+static int nilfs_validate_log(struct the_nilfs *nilfs, u64 seg_seq,
+ struct buffer_head *bh_sum,
+ struct nilfs_segment_summary *sum)
+{
unsigned long nblock;
u32 crc;
- int ret = NILFS_SEG_FAIL_IO;
+ int ret;
- bh_sum = sb_bread(sbi->s_super, pseg_start);
- if (!bh_sum)
+ ret = NILFS_SEG_FAIL_MAGIC;
+ if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC)
goto out;
- sum = (struct nilfs_segment_summary *)bh_sum->b_data;
-
- /* Check consistency of segment summary */
- if (le32_to_cpu(sum->ss_magic) != NILFS_SEGSUM_MAGIC) {
- ret = NILFS_SEG_FAIL_MAGIC;
- goto failed;
- }
- store_segsum_info(ssi, sum, sbi->s_super->s_blocksize);
- if (seg_seq != ssi->seg_seq) {
- ret = NILFS_SEG_FAIL_SEQ;
- goto failed;
- }
+ ret = NILFS_SEG_FAIL_SEQ;
+ if (le64_to_cpu(sum->ss_seq) != seg_seq)
+ goto out;
- nblock = ssi->nblocks;
- if (unlikely(nblock == 0 ||
- nblock > sbi->s_nilfs->ns_blocks_per_segment)) {
+ nblock = le32_to_cpu(sum->ss_nblocks);
+ ret = NILFS_SEG_FAIL_CONSISTENCY;
+ if (unlikely(nblock == 0 || nblock > nilfs->ns_blocks_per_segment))
/* This limits the number of blocks read in the CRC check */
- ret = NILFS_SEG_FAIL_CONSISTENCY;
- goto failed;
- }
- if (calc_crc_cont(sbi, bh_sum, &crc, sizeof(sum->ss_datasum),
- ((u64)nblock << sbi->s_super->s_blocksize_bits),
- pseg_start, nblock)) {
- ret = NILFS_SEG_FAIL_IO;
- goto failed;
- }
- if (crc == le32_to_cpu(sum->ss_datasum))
- ret = 0;
- else
- ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
- failed:
- brelse(bh_sum);
- out:
+ goto out;
+
+ ret = NILFS_SEG_FAIL_IO;
+ if (nilfs_compute_checksum(nilfs, bh_sum, &crc, sizeof(sum->ss_datasum),
+ ((u64)nblock << nilfs->ns_blocksize_bits),
+ bh_sum->b_blocknr, nblock))
+ goto out;
+
+ ret = NILFS_SEG_FAIL_CHECKSUM_FULL;
+ if (crc != le32_to_cpu(sum->ss_datasum))
+ goto out;
+ ret = 0;
+out:
return ret;
}
-static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
- unsigned int *offset, unsigned int bytes)
+/**
+ * nilfs_read_summary_info - read an item on summary blocks of a log
+ * @nilfs: nilfs object
+ * @pbh: the current buffer head on summary blocks [in, out]
+ * @offset: the current byte offset on summary blocks [in, out]
+ * @bytes: byte size of the item to be read
+ */
+static void *nilfs_read_summary_info(struct the_nilfs *nilfs,
+ struct buffer_head **pbh,
+ unsigned int *offset, unsigned int bytes)
{
void *ptr;
sector_t blocknr;
@@ -265,7 +262,8 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
if (bytes > (*pbh)->b_size - *offset) {
blocknr = (*pbh)->b_blocknr;
brelse(*pbh);
- *pbh = sb_bread(sb, blocknr + 1);
+ *pbh = __bread(nilfs->ns_bdev, blocknr + 1,
+ nilfs->ns_blocksize);
if (unlikely(!*pbh))
return NULL;
*offset = 0;
@@ -275,9 +273,18 @@ static void *segsum_get(struct super_block *sb, struct buffer_head **pbh,
return ptr;
}
-static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
- unsigned int *offset, unsigned int bytes,
- unsigned long count)
+/**
+ * nilfs_skip_summary_info - skip items on summary blocks of a log
+ * @nilfs: nilfs object
+ * @pbh: the current buffer head on summary blocks [in, out]
+ * @offset: the current byte offset on summary blocks [in, out]
+ * @bytes: byte size of the item to be skipped
+ * @count: number of items to be skipped
+ */
+static void nilfs_skip_summary_info(struct the_nilfs *nilfs,
+ struct buffer_head **pbh,
+ unsigned int *offset, unsigned int bytes,
+ unsigned long count)
{
unsigned int rest_item_in_current_block
= ((*pbh)->b_size - *offset) / bytes;
@@ -294,36 +301,46 @@ static void segsum_skip(struct super_block *sb, struct buffer_head **pbh,
*offset = bytes * (count - (bcnt - 1) * nitem_per_block);
brelse(*pbh);
- *pbh = sb_bread(sb, blocknr + bcnt);
+ *pbh = __bread(nilfs->ns_bdev, blocknr + bcnt,
+ nilfs->ns_blocksize);
}
}
-static int
-collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
- struct nilfs_segsum_info *ssi,
- struct list_head *head)
+/**
+ * nilfs_scan_dsync_log - get block information of a log written for data sync
+ * @nilfs: nilfs object
+ * @start_blocknr: start block number of the log
+ * @sum: log summary information
+ * @head: list head to add nilfs_recovery_block struct
+ */
+static int nilfs_scan_dsync_log(struct the_nilfs *nilfs, sector_t start_blocknr,
+ struct nilfs_segment_summary *sum,
+ struct list_head *head)
{
struct buffer_head *bh;
unsigned int offset;
- unsigned long nfinfo = ssi->nfinfo;
- sector_t blocknr = sum_blocknr + ssi->nsumblk;
+ u32 nfinfo, sumbytes;
+ sector_t blocknr;
ino_t ino;
int err = -EIO;
+ nfinfo = le32_to_cpu(sum->ss_nfinfo);
if (!nfinfo)
return 0;
- bh = sb_bread(sbi->s_super, sum_blocknr);
+ sumbytes = le32_to_cpu(sum->ss_sumbytes);
+ blocknr = start_blocknr + DIV_ROUND_UP(sumbytes, nilfs->ns_blocksize);
+ bh = __bread(nilfs->ns_bdev, start_blocknr, nilfs->ns_blocksize);
if (unlikely(!bh))
goto out;
- offset = le16_to_cpu(
- ((struct nilfs_segment_summary *)bh->b_data)->ss_bytes);
+ offset = le16_to_cpu(sum->ss_bytes);
for (;;) {
unsigned long nblocks, ndatablk, nnodeblk;
struct nilfs_finfo *finfo;
- finfo = segsum_get(sbi->s_super, &bh, &offset, sizeof(*finfo));
+ finfo = nilfs_read_summary_info(nilfs, &bh, &offset,
+ sizeof(*finfo));
if (unlikely(!finfo))
goto out;
@@ -336,8 +353,8 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
struct nilfs_recovery_block *rb;
struct nilfs_binfo_v *binfo;
- binfo = segsum_get(sbi->s_super, &bh, &offset,
- sizeof(*binfo));
+ binfo = nilfs_read_summary_info(nilfs, &bh, &offset,
+ sizeof(*binfo));
if (unlikely(!binfo))
goto out;
@@ -355,9 +372,9 @@ collect_blocks_from_segsum(struct nilfs_sb_info *sbi, sector_t sum_blocknr,
}
if (--nfinfo == 0)
break;
- blocknr += nnodeblk; /* always 0 for the data sync segments */
- segsum_skip(sbi->s_super, &bh, &offset, sizeof(__le64),
- nnodeblk);
+ blocknr += nnodeblk; /* always 0 for data sync logs */
+ nilfs_skip_summary_info(nilfs, &bh, &offset, sizeof(__le64),
+ nnodeblk);
if (unlikely(!bh))
goto out;
}
@@ -467,14 +484,14 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
return err;
}
-static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
+static int nilfs_recovery_copy_block(struct the_nilfs *nilfs,
struct nilfs_recovery_block *rb,
struct page *page)
{
struct buffer_head *bh_org;
void *kaddr;
- bh_org = sb_bread(sbi->s_super, rb->blocknr);
+ bh_org = __bread(nilfs->ns_bdev, rb->blocknr, nilfs->ns_blocksize);
if (unlikely(!bh_org))
return -EIO;
@@ -485,13 +502,14 @@ static int nilfs_recovery_copy_block(struct nilfs_sb_info *sbi,
return 0;
}
-static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
- struct list_head *head,
- unsigned long *nr_salvaged_blocks)
+static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs,
+ struct nilfs_sb_info *sbi,
+ struct list_head *head,
+ unsigned long *nr_salvaged_blocks)
{
struct inode *inode;
struct nilfs_recovery_block *rb, *n;
- unsigned blocksize = sbi->s_super->s_blocksize;
+ unsigned blocksize = nilfs->ns_blocksize;
struct page *page;
loff_t pos;
int err = 0, err2 = 0;
@@ -505,13 +523,16 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
}
pos = rb->blkoff << inode->i_blkbits;
- page = NULL;
- err = block_write_begin(NULL, inode->i_mapping, pos, blocksize,
- 0, &page, NULL, nilfs_get_block);
- if (unlikely(err))
+ err = block_write_begin(inode->i_mapping, pos, blocksize,
+ 0, &page, nilfs_get_block);
+ if (unlikely(err)) {
+ loff_t isize = inode->i_size;
+ if (pos + blocksize > isize)
+ vmtruncate(inode, isize);
goto failed_inode;
+ }
- err = nilfs_recovery_copy_block(sbi, rb, page);
+ err = nilfs_recovery_copy_block(nilfs, rb, page);
if (unlikely(err))
goto failed_page;
@@ -551,18 +572,20 @@ static int recover_dsync_blocks(struct nilfs_sb_info *sbi,
/**
* nilfs_do_roll_forward - salvage logical segments newer than the latest
* checkpoint
+ * @nilfs: nilfs object
* @sbi: nilfs_sb_info
- * @nilfs: the_nilfs
* @ri: pointer to a nilfs_recovery_info
*/
static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
struct nilfs_sb_info *sbi,
struct nilfs_recovery_info *ri)
{
- struct nilfs_segsum_info ssi;
+ struct buffer_head *bh_sum = NULL;
+ struct nilfs_segment_summary *sum;
sector_t pseg_start;
sector_t seg_start, seg_end; /* Starting/ending DBN of full segment */
unsigned long nsalvaged_blocks = 0;
+ unsigned int flags;
u64 seg_seq;
__u64 segnum, nextnum = 0;
int empty_seg = 0;
@@ -581,8 +604,14 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
nilfs_get_segment_range(nilfs, segnum, &seg_start, &seg_end);
while (segnum != ri->ri_segnum || pseg_start <= ri->ri_pseg_start) {
+ brelse(bh_sum);
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
+ if (!bh_sum) {
+ err = -EIO;
+ goto failed;
+ }
- ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
if (ret) {
if (ret == NILFS_SEG_FAIL_IO) {
err = -EIO;
@@ -590,33 +619,38 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
}
goto strayed;
}
- if (unlikely(NILFS_SEG_HAS_SR(&ssi)))
+
+ flags = le16_to_cpu(sum->ss_flags);
+ if (flags & NILFS_SS_SR)
goto confused;
/* Found a valid partial segment; do recovery actions */
- nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
+ nextnum = nilfs_get_segnum_of_block(nilfs,
+ le64_to_cpu(sum->ss_next));
empty_seg = 0;
- nilfs->ns_ctime = ssi.ctime;
- if (!(ssi.flags & NILFS_SS_GC))
- nilfs->ns_nongc_ctime = ssi.ctime;
+ nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
+ if (!(flags & NILFS_SS_GC))
+ nilfs->ns_nongc_ctime = nilfs->ns_ctime;
switch (state) {
case RF_INIT_ST:
- if (!NILFS_SEG_LOGBGN(&ssi) || !NILFS_SEG_DSYNC(&ssi))
+ if (!(flags & NILFS_SS_LOGBGN) ||
+ !(flags & NILFS_SS_SYNDT))
goto try_next_pseg;
state = RF_DSYNC_ST;
/* Fall through */
case RF_DSYNC_ST:
- if (!NILFS_SEG_DSYNC(&ssi))
+ if (!(flags & NILFS_SS_SYNDT))
goto confused;
- err = collect_blocks_from_segsum(
- sbi, pseg_start, &ssi, &dsync_blocks);
+ err = nilfs_scan_dsync_log(nilfs, pseg_start, sum,
+ &dsync_blocks);
if (unlikely(err))
goto failed;
- if (NILFS_SEG_LOGEND(&ssi)) {
- err = recover_dsync_blocks(
- sbi, &dsync_blocks, &nsalvaged_blocks);
+ if (flags & NILFS_SS_LOGEND) {
+ err = nilfs_recover_dsync_blocks(
+ nilfs, sbi, &dsync_blocks,
+ &nsalvaged_blocks);
if (unlikely(err))
goto failed;
state = RF_INIT_ST;
@@ -627,7 +661,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
try_next_pseg:
if (pseg_start == ri->ri_lsegs_end)
break;
- pseg_start += ssi.nblocks;
+ pseg_start += le32_to_cpu(sum->ss_nblocks);
if (pseg_start < seg_end)
continue;
goto feed_segment;
@@ -652,8 +686,9 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
ri->ri_need_recovery = NILFS_RECOVERY_ROLLFORWARD_DONE;
}
out:
+ brelse(bh_sum);
dispose_recovery_list(&dsync_blocks);
- nilfs_detach_writer(sbi->s_nilfs, sbi);
+ nilfs_detach_writer(nilfs, sbi);
return err;
confused:
@@ -667,7 +702,6 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs,
}
static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi,
struct nilfs_recovery_info *ri)
{
struct buffer_head *bh;
@@ -677,7 +711,7 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
nilfs_get_segnum_of_block(nilfs, ri->ri_super_root))
return;
- bh = sb_getblk(sbi->s_super, ri->ri_lsegs_start);
+ bh = __getblk(nilfs->ns_bdev, ri->ri_lsegs_start, nilfs->ns_blocksize);
BUG_ON(!bh);
memset(bh->b_data, 0, bh->b_size);
set_buffer_dirty(bh);
@@ -690,9 +724,8 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
}
/**
- * nilfs_recover_logical_segments - salvage logical segments written after
- * the latest super root
- * @nilfs: the_nilfs
+ * nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
+ * @nilfs: nilfs object
* @sbi: nilfs_sb_info
* @ri: pointer to a nilfs_recovery_info struct to store search results.
*
@@ -709,9 +742,9 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
*
* %-ENOMEM - Insufficient memory available.
*/
-int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi,
- struct nilfs_recovery_info *ri)
+int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
+ struct nilfs_sb_info *sbi,
+ struct nilfs_recovery_info *ri)
{
int err;
@@ -751,7 +784,7 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
goto failed;
}
- nilfs_finish_roll_forward(nilfs, sbi, ri);
+ nilfs_finish_roll_forward(nilfs, ri);
}
failed:
@@ -762,7 +795,6 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
/**
* nilfs_search_super_root - search the latest valid super root
* @nilfs: the_nilfs
- * @sbi: nilfs_sb_info
* @ri: pointer to a nilfs_recovery_info struct to store search results.
*
* nilfs_search_super_root() looks for the latest super-root from a partial
@@ -776,13 +808,16 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
*
* %-EIO - I/O error
*/
-int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
+int nilfs_search_super_root(struct the_nilfs *nilfs,
struct nilfs_recovery_info *ri)
{
- struct nilfs_segsum_info ssi;
+ struct buffer_head *bh_sum = NULL;
+ struct nilfs_segment_summary *sum;
sector_t pseg_start, pseg_end, sr_pseg_start = 0;
sector_t seg_start, seg_end; /* range of full segment (block number) */
sector_t b, end;
+ unsigned long nblocks;
+ unsigned int flags;
u64 seg_seq;
__u64 segnum, nextnum = 0;
__u64 cno;
@@ -801,17 +836,24 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
/* Read ahead segment */
b = seg_start;
while (b <= seg_end)
- sb_breadahead(sbi->s_super, b++);
+ __breadahead(nilfs->ns_bdev, b++, nilfs->ns_blocksize);
for (;;) {
- /* Load segment summary */
- ret = load_segment_summary(sbi, pseg_start, seg_seq, &ssi);
+ brelse(bh_sum);
+ ret = NILFS_SEG_FAIL_IO;
+ bh_sum = nilfs_read_log_header(nilfs, pseg_start, &sum);
+ if (!bh_sum)
+ goto failed;
+
+ ret = nilfs_validate_log(nilfs, seg_seq, bh_sum, sum);
if (ret) {
if (ret == NILFS_SEG_FAIL_IO)
goto failed;
goto strayed;
}
- pseg_end = pseg_start + ssi.nblocks - 1;
+
+ nblocks = le32_to_cpu(sum->ss_nblocks);
+ pseg_end = pseg_start + nblocks - 1;
if (unlikely(pseg_end > seg_end)) {
ret = NILFS_SEG_FAIL_CONSISTENCY;
goto strayed;
@@ -821,11 +863,13 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
ri->ri_pseg_start = pseg_start;
ri->ri_seq = seg_seq;
ri->ri_segnum = segnum;
- nextnum = nilfs_get_segnum_of_block(nilfs, ssi.next);
+ nextnum = nilfs_get_segnum_of_block(nilfs,
+ le64_to_cpu(sum->ss_next));
ri->ri_nextnum = nextnum;
empty_seg = 0;
- if (!NILFS_SEG_HAS_SR(&ssi) && !scan_newer) {
+ flags = le16_to_cpu(sum->ss_flags);
+ if (!(flags & NILFS_SS_SR) && !scan_newer) {
/* This will never happen because a superblock
(last_segment) always points to a pseg
having a super root. */
@@ -836,14 +880,15 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
if (pseg_start == seg_start) {
nilfs_get_segment_range(nilfs, nextnum, &b, &end);
while (b <= end)
- sb_breadahead(sbi->s_super, b++);
+ __breadahead(nilfs->ns_bdev, b++,
+ nilfs->ns_blocksize);
}
- if (!NILFS_SEG_HAS_SR(&ssi)) {
- if (!ri->ri_lsegs_start && NILFS_SEG_LOGBGN(&ssi)) {
+ if (!(flags & NILFS_SS_SR)) {
+ if (!ri->ri_lsegs_start && (flags & NILFS_SS_LOGBGN)) {
ri->ri_lsegs_start = pseg_start;
ri->ri_lsegs_start_seq = seg_seq;
}
- if (NILFS_SEG_LOGEND(&ssi))
+ if (flags & NILFS_SS_LOGEND)
ri->ri_lsegs_end = pseg_start;
goto try_next_pseg;
}
@@ -854,12 +899,12 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
ri->ri_lsegs_start = ri->ri_lsegs_end = 0;
nilfs_dispose_segment_list(&segments);
- nilfs->ns_pseg_offset = (sr_pseg_start = pseg_start)
- + ssi.nblocks - seg_start;
+ sr_pseg_start = pseg_start;
+ nilfs->ns_pseg_offset = pseg_start + nblocks - seg_start;
nilfs->ns_seg_seq = seg_seq;
nilfs->ns_segnum = segnum;
nilfs->ns_cno = cno; /* nilfs->ns_cno = ri->ri_cno + 1 */
- nilfs->ns_ctime = ssi.ctime;
+ nilfs->ns_ctime = le64_to_cpu(sum->ss_create);
nilfs->ns_nextnum = nextnum;
if (scan_newer)
@@ -870,15 +915,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
scan_newer = 1;
}
- /* reset region for roll-forward */
- pseg_start += ssi.nblocks;
- if (pseg_start < seg_end)
- continue;
- goto feed_segment;
-
try_next_pseg:
/* Standing on a course, or met an inconsistent state */
- pseg_start += ssi.nblocks;
+ pseg_start += nblocks;
if (pseg_start < seg_end)
continue;
goto feed_segment;
@@ -909,6 +948,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
super_root_found:
/* Updating pointers relating to the latest checkpoint */
+ brelse(bh_sum);
list_splice_tail(&segments, &ri->ri_used_segments);
nilfs->ns_last_pseg = sr_pseg_start;
nilfs->ns_last_seq = nilfs->ns_seg_seq;
@@ -916,6 +956,7 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
return 0;
failed:
+ brelse(bh_sum);
nilfs_dispose_segment_list(&segments);
return (ret < 0) ? ret : nilfs_warn_segment_error(ret);
}
diff --git a/fs/nilfs2/segbuf.h b/fs/nilfs2/segbuf.h
index fdf1c3b6d673..b04f08cc2397 100644
--- a/fs/nilfs2/segbuf.h
+++ b/fs/nilfs2/segbuf.h
@@ -54,17 +54,6 @@ struct nilfs_segsum_info {
sector_t next;
};
-/* macro for the flags */
-#define NILFS_SEG_HAS_SR(sum) ((sum)->flags & NILFS_SS_SR)
-#define NILFS_SEG_LOGBGN(sum) ((sum)->flags & NILFS_SS_LOGBGN)
-#define NILFS_SEG_LOGEND(sum) ((sum)->flags & NILFS_SS_LOGEND)
-#define NILFS_SEG_DSYNC(sum) ((sum)->flags & NILFS_SS_SYNDT)
-#define NILFS_SEG_SIMPLEX(sum) \
- (((sum)->flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) == \
- (NILFS_SS_LOGBGN | NILFS_SS_LOGEND))
-
-#define NILFS_SEG_EMPTY(sum) ((sum)->nblocks == (sum)->nsumblk)
-
/**
* struct nilfs_segment_buffer - Segment buffer
* @sb_super: back pointer to a superblock struct
@@ -127,8 +116,6 @@ struct nilfs_segment_buffer {
extern struct kmem_cache *nilfs_segbuf_cachep;
-int __init nilfs_init_segbuf_cache(void);
-void nilfs_destroy_segbuf_cache(void);
struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *);
void nilfs_segbuf_free(struct nilfs_segment_buffer *);
void nilfs_segbuf_map(struct nilfs_segment_buffer *, __u64, unsigned long,
@@ -143,6 +130,19 @@ int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *,
struct buffer_head **);
void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *);
+static inline int nilfs_segbuf_simplex(struct nilfs_segment_buffer *segbuf)
+{
+ unsigned int flags = segbuf->sb_sum.flags;
+
+ return (flags & (NILFS_SS_LOGBGN | NILFS_SS_LOGEND)) ==
+ (NILFS_SS_LOGBGN | NILFS_SS_LOGEND);
+}
+
+static inline int nilfs_segbuf_empty(struct nilfs_segment_buffer *segbuf)
+{
+ return segbuf->sb_sum.nblocks == segbuf->sb_sum.nsumblk;
+}
+
static inline void
nilfs_segbuf_add_segsum_buffer(struct nilfs_segment_buffer *segbuf,
struct buffer_head *bh)
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index c9201649cc49..1f7881ca01c4 100644
--- a/fs/nilfs2/segment.c
+++ b/fs/nilfs2/segment.c
@@ -1914,12 +1914,12 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci)
}
}
- if (!NILFS_SEG_SIMPLEX(&segbuf->sb_sum)) {
- if (NILFS_SEG_LOGBGN(&segbuf->sb_sum)) {
+ if (!nilfs_segbuf_simplex(segbuf)) {
+ if (segbuf->sb_sum.flags & NILFS_SS_LOGBGN) {
set_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
sci->sc_lseg_stime = jiffies;
}
- if (NILFS_SEG_LOGEND(&segbuf->sb_sum))
+ if (segbuf->sb_sum.flags & NILFS_SS_LOGEND)
clear_bit(NILFS_SC_UNCLOSED, &sci->sc_flags);
}
}
@@ -2082,7 +2082,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
/* Avoid empty segment */
if (sci->sc_stage.scnt == NILFS_ST_DONE &&
- NILFS_SEG_EMPTY(&sci->sc_curseg->sb_sum)) {
+ nilfs_segbuf_empty(sci->sc_curseg)) {
nilfs_segctor_abort_construction(sci, nilfs, 1);
goto out;
}
diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h
index dca142361ccf..17c487bd8152 100644
--- a/fs/nilfs2/segment.h
+++ b/fs/nilfs2/segment.h
@@ -221,8 +221,6 @@ enum {
extern struct kmem_cache *nilfs_transaction_cachep;
/* segment.c */
-extern int nilfs_init_transaction_cache(void);
-extern void nilfs_destroy_transaction_cache(void);
extern void nilfs_relax_pressure_in_lock(struct super_block *);
extern int nilfs_construct_segment(struct super_block *);
@@ -236,13 +234,13 @@ extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *);
extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *);
/* recovery.c */
-extern int nilfs_read_super_root_block(struct super_block *, sector_t,
+extern int nilfs_read_super_root_block(struct the_nilfs *, sector_t,
struct buffer_head **, int);
-extern int nilfs_search_super_root(struct the_nilfs *, struct nilfs_sb_info *,
+extern int nilfs_search_super_root(struct the_nilfs *,
struct nilfs_recovery_info *);
-extern int nilfs_recover_logical_segments(struct the_nilfs *,
- struct nilfs_sb_info *,
- struct nilfs_recovery_info *);
+extern int nilfs_salvage_orphan_logs(struct the_nilfs *,
+ struct nilfs_sb_info *,
+ struct nilfs_recovery_info *);
extern void nilfs_dispose_segment_list(struct list_head *);
#endif /* _NILFS_SEGMENT_H */
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 03b34b738993..414ef68931cf 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1130,13 +1130,13 @@ static void nilfs_segbuf_init_once(void *obj)
static void nilfs_destroy_cachep(void)
{
- if (nilfs_inode_cachep)
+ if (nilfs_inode_cachep)
kmem_cache_destroy(nilfs_inode_cachep);
- if (nilfs_transaction_cachep)
+ if (nilfs_transaction_cachep)
kmem_cache_destroy(nilfs_transaction_cachep);
- if (nilfs_segbuf_cachep)
+ if (nilfs_segbuf_cachep)
kmem_cache_destroy(nilfs_segbuf_cachep);
- if (nilfs_btree_path_cache)
+ if (nilfs_btree_path_cache)
kmem_cache_destroy(nilfs_btree_path_cache);
}
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 8c1097327abc..9f2cb01994d0 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -159,8 +159,7 @@ void put_nilfs(struct the_nilfs *nilfs)
kfree(nilfs);
}
-static int nilfs_load_super_root(struct the_nilfs *nilfs,
- struct nilfs_sb_info *sbi, sector_t sr_block)
+static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block)
{
struct buffer_head *bh_sr;
struct nilfs_super_root *raw_sr;
@@ -169,7 +168,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs,
unsigned inode_size;
int err;
- err = nilfs_read_super_root_block(sbi->s_super, sr_block, &bh_sr, 1);
+ err = nilfs_read_super_root_block(nilfs, sr_block, &bh_sr, 1);
if (unlikely(err))
return err;
@@ -285,13 +284,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
nilfs_init_recovery_info(&ri);
- err = nilfs_search_super_root(nilfs, sbi, &ri);
+ err = nilfs_search_super_root(nilfs, &ri);
if (unlikely(err)) {
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;
}
- err = nilfs_load_super_root(nilfs, sbi, ri.ri_super_root);
+ err = nilfs_load_super_root(nilfs, ri.ri_super_root);
if (unlikely(err)) {
printk(KERN_ERR "NILFS: error loading super root.\n");
goto failed;
@@ -320,7 +319,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
goto failed_unload;
}
- err = nilfs_recover_logical_segments(nilfs, sbi, &ri);
+ err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri);
if (err)
goto failed_unload;
@@ -604,6 +603,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
when reloading fails. */
}
nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
+ nilfs->ns_blocksize = blocksize;
err = nilfs_store_disk_layout(nilfs, sbp);
if (err)
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index 1ab974533697..85df47f0730f 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -82,6 +82,7 @@ enum {
* @ns_gc_inodes: dummy inodes to keep live blocks
* @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks
* @ns_blocksize_bits: bit length of block size
+ * @ns_blocksize: block size
* @ns_nsegments: number of segments in filesystem
* @ns_blocks_per_segment: number of blocks per segment
* @ns_r_segments_percentage: reserved segments percentage
@@ -168,6 +169,7 @@ struct the_nilfs {
/* Disk layout information (static) */
unsigned int ns_blocksize_bits;
+ unsigned int ns_blocksize;
unsigned long ns_nsegments;
unsigned long ns_blocks_per_segment;
unsigned long ns_r_segments_percentage;
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig
index dffbb0911d02..22c629eedd82 100644
--- a/fs/notify/Kconfig
+++ b/fs/notify/Kconfig
@@ -3,3 +3,4 @@ config FSNOTIFY
source "fs/notify/dnotify/Kconfig"
source "fs/notify/inotify/Kconfig"
+source "fs/notify/fanotify/Kconfig"
diff --git a/fs/notify/Makefile b/fs/notify/Makefile
index 0922cc826c46..ae5f33a6d868 100644
--- a/fs/notify/Makefile
+++ b/fs/notify/Makefile
@@ -1,4 +1,6 @@
-obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o
+obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o \
+ mark.o vfsmount_mark.o
obj-y += dnotify/
obj-y += inotify/
+obj-y += fanotify/
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c
index 7e54e52964dd..6624c2ee8786 100644
--- a/fs/notify/dnotify/dnotify.c
+++ b/fs/notify/dnotify/dnotify.c
@@ -29,17 +29,17 @@
int dir_notify_enable __read_mostly = 1;
static struct kmem_cache *dnotify_struct_cache __read_mostly;
-static struct kmem_cache *dnotify_mark_entry_cache __read_mostly;
+static struct kmem_cache *dnotify_mark_cache __read_mostly;
static struct fsnotify_group *dnotify_group __read_mostly;
static DEFINE_MUTEX(dnotify_mark_mutex);
/*
- * dnotify will attach one of these to each inode (i_fsnotify_mark_entries) which
+ * dnotify will attach one of these to each inode (i_fsnotify_marks) which
* is being watched by dnotify. If multiple userspace applications are watching
* the same directory with dnotify their information is chained in dn
*/
-struct dnotify_mark_entry {
- struct fsnotify_mark_entry fsn_entry;
+struct dnotify_mark {
+ struct fsnotify_mark fsn_mark;
struct dnotify_struct *dn;
};
@@ -51,27 +51,27 @@ struct dnotify_mark_entry {
* it calls the fsnotify function so it can update the set of all events relevant
* to this inode.
*/
-static void dnotify_recalc_inode_mask(struct fsnotify_mark_entry *entry)
+static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
{
__u32 new_mask, old_mask;
struct dnotify_struct *dn;
- struct dnotify_mark_entry *dnentry = container_of(entry,
- struct dnotify_mark_entry,
- fsn_entry);
+ struct dnotify_mark *dn_mark = container_of(fsn_mark,
+ struct dnotify_mark,
+ fsn_mark);
- assert_spin_locked(&entry->lock);
+ assert_spin_locked(&fsn_mark->lock);
- old_mask = entry->mask;
+ old_mask = fsn_mark->mask;
new_mask = 0;
- for (dn = dnentry->dn; dn != NULL; dn = dn->dn_next)
+ for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next)
new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT);
- entry->mask = new_mask;
+ fsnotify_set_mark_mask_locked(fsn_mark, new_mask);
if (old_mask == new_mask)
return;
- if (entry->inode)
- fsnotify_recalc_inode_mask(entry->inode);
+ if (fsn_mark->i.inode)
+ fsnotify_recalc_inode_mask(fsn_mark->i.inode);
}
/*
@@ -85,8 +85,8 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark_entry *entry)
static int dnotify_handle_event(struct fsnotify_group *group,
struct fsnotify_event *event)
{
- struct fsnotify_mark_entry *entry = NULL;
- struct dnotify_mark_entry *dnentry;
+ struct fsnotify_mark *fsn_mark = NULL;
+ struct dnotify_mark *dn_mark;
struct inode *to_tell;
struct dnotify_struct *dn;
struct dnotify_struct **prev;
@@ -95,17 +95,13 @@ static int dnotify_handle_event(struct fsnotify_group *group,
to_tell = event->to_tell;
- spin_lock(&to_tell->i_lock);
- entry = fsnotify_find_mark_entry(group, to_tell);
- spin_unlock(&to_tell->i_lock);
-
- /* unlikely since we alreay passed dnotify_should_send_event() */
- if (unlikely(!entry))
+ fsn_mark = fsnotify_find_inode_mark(group, to_tell);
+ if (unlikely(!fsn_mark))
return 0;
- dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry);
+ dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
- spin_lock(&entry->lock);
- prev = &dnentry->dn;
+ spin_lock(&fsn_mark->lock);
+ prev = &dn_mark->dn;
while ((dn = *prev) != NULL) {
if ((dn->dn_mask & test_mask) == 0) {
prev = &dn->dn_next;
@@ -118,12 +114,12 @@ static int dnotify_handle_event(struct fsnotify_group *group,
else {
*prev = dn->dn_next;
kmem_cache_free(dnotify_struct_cache, dn);
- dnotify_recalc_inode_mask(entry);
+ dnotify_recalc_inode_mask(fsn_mark);
}
}
- spin_unlock(&entry->lock);
- fsnotify_put_mark(entry);
+ spin_unlock(&fsn_mark->lock);
+ fsnotify_put_mark(fsn_mark);
return 0;
}
@@ -133,9 +129,10 @@ static int dnotify_handle_event(struct fsnotify_group *group,
* userspace notification for that pair.
*/
static bool dnotify_should_send_event(struct fsnotify_group *group,
- struct inode *inode, __u32 mask)
+ struct inode *inode, struct vfsmount *mnt,
+ __u32 mask, void *data, int data_type)
{
- struct fsnotify_mark_entry *entry;
+ struct fsnotify_mark *fsn_mark;
bool send;
/* !dir_notify_enable should never get here, don't waste time checking
@@ -146,31 +143,27 @@ static bool dnotify_should_send_event(struct fsnotify_group *group,
if (!S_ISDIR(inode->i_mode))
return false;
- spin_lock(&inode->i_lock);
- entry = fsnotify_find_mark_entry(group, inode);
- spin_unlock(&inode->i_lock);
-
- /* no mark means no dnotify watch */
- if (!entry)
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
return false;
mask = (mask & ~FS_EVENT_ON_CHILD);
- send = (mask & entry->mask);
+ send = (mask & fsn_mark->mask);
- fsnotify_put_mark(entry); /* matches fsnotify_find_mark_entry */
+ fsnotify_put_mark(fsn_mark); /* matches fsnotify_find_inode_mark */
return send;
}
-static void dnotify_free_mark(struct fsnotify_mark_entry *entry)
+static void dnotify_free_mark(struct fsnotify_mark *fsn_mark)
{
- struct dnotify_mark_entry *dnentry = container_of(entry,
- struct dnotify_mark_entry,
- fsn_entry);
+ struct dnotify_mark *dn_mark = container_of(fsn_mark,
+ struct dnotify_mark,
+ fsn_mark);
- BUG_ON(dnentry->dn);
+ BUG_ON(dn_mark->dn);
- kmem_cache_free(dnotify_mark_entry_cache, dnentry);
+ kmem_cache_free(dnotify_mark_cache, dn_mark);
}
static struct fsnotify_ops dnotify_fsnotify_ops = {
@@ -183,15 +176,15 @@ static struct fsnotify_ops dnotify_fsnotify_ops = {
/*
* Called every time a file is closed. Looks first for a dnotify mark on the
- * inode. If one is found run all of the ->dn entries attached to that
+ * inode. If one is found run all of the ->dn structures attached to that
* mark for one relevant to this process closing the file and remove that
* dnotify_struct. If that was the last dnotify_struct also remove the
- * fsnotify_mark_entry.
+ * fsnotify_mark.
*/
void dnotify_flush(struct file *filp, fl_owner_t id)
{
- struct fsnotify_mark_entry *entry;
- struct dnotify_mark_entry *dnentry;
+ struct fsnotify_mark *fsn_mark;
+ struct dnotify_mark *dn_mark;
struct dnotify_struct *dn;
struct dnotify_struct **prev;
struct inode *inode;
@@ -200,38 +193,36 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
if (!S_ISDIR(inode->i_mode))
return;
- spin_lock(&inode->i_lock);
- entry = fsnotify_find_mark_entry(dnotify_group, inode);
- spin_unlock(&inode->i_lock);
- if (!entry)
+ fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
+ if (!fsn_mark)
return;
- dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry);
+ dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
mutex_lock(&dnotify_mark_mutex);
- spin_lock(&entry->lock);
- prev = &dnentry->dn;
+ spin_lock(&fsn_mark->lock);
+ prev = &dn_mark->dn;
while ((dn = *prev) != NULL) {
if ((dn->dn_owner == id) && (dn->dn_filp == filp)) {
*prev = dn->dn_next;
kmem_cache_free(dnotify_struct_cache, dn);
- dnotify_recalc_inode_mask(entry);
+ dnotify_recalc_inode_mask(fsn_mark);
break;
}
prev = &dn->dn_next;
}
- spin_unlock(&entry->lock);
+ spin_unlock(&fsn_mark->lock);
/* nothing else could have found us thanks to the dnotify_mark_mutex */
- if (dnentry->dn == NULL)
- fsnotify_destroy_mark_by_entry(entry);
+ if (dn_mark->dn == NULL)
+ fsnotify_destroy_mark(fsn_mark);
fsnotify_recalc_group_mask(dnotify_group);
mutex_unlock(&dnotify_mark_mutex);
- fsnotify_put_mark(entry);
+ fsnotify_put_mark(fsn_mark);
}
/* this conversion is done only at watch creation */
@@ -259,16 +250,16 @@ static __u32 convert_arg(unsigned long arg)
/*
* If multiple processes watch the same inode with dnotify there is only one
- * dnotify mark in inode->i_fsnotify_mark_entries but we chain a dnotify_struct
+ * dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct
* onto that mark. This function either attaches the new dnotify_struct onto
* that list, or it |= the mask onto an existing dnofiy_struct.
*/
-static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnentry,
+static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark,
fl_owner_t id, int fd, struct file *filp, __u32 mask)
{
struct dnotify_struct *odn;
- odn = dnentry->dn;
+ odn = dn_mark->dn;
while (odn != NULL) {
/* adding more events to existing dnofiy_struct? */
if ((odn->dn_owner == id) && (odn->dn_filp == filp)) {
@@ -283,8 +274,8 @@ static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnent
dn->dn_fd = fd;
dn->dn_filp = filp;
dn->dn_owner = id;
- dn->dn_next = dnentry->dn;
- dnentry->dn = dn;
+ dn->dn_next = dn_mark->dn;
+ dn_mark->dn = dn;
return 0;
}
@@ -296,8 +287,8 @@ static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnent
*/
int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
{
- struct dnotify_mark_entry *new_dnentry, *dnentry;
- struct fsnotify_mark_entry *new_entry, *entry;
+ struct dnotify_mark *new_dn_mark, *dn_mark;
+ struct fsnotify_mark *new_fsn_mark, *fsn_mark;
struct dnotify_struct *dn;
struct inode *inode;
fl_owner_t id = current->files;
@@ -306,7 +297,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
__u32 mask;
/* we use these to tell if we need to kfree */
- new_entry = NULL;
+ new_fsn_mark = NULL;
dn = NULL;
if (!dir_notify_enable) {
@@ -336,8 +327,8 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
}
/* new fsnotify mark, we expect most fcntl calls to add a new mark */
- new_dnentry = kmem_cache_alloc(dnotify_mark_entry_cache, GFP_KERNEL);
- if (!new_dnentry) {
+ new_dn_mark = kmem_cache_alloc(dnotify_mark_cache, GFP_KERNEL);
+ if (!new_dn_mark) {
error = -ENOMEM;
goto out_err;
}
@@ -345,29 +336,27 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
/* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */
mask = convert_arg(arg);
- /* set up the new_entry and new_dnentry */
- new_entry = &new_dnentry->fsn_entry;
- fsnotify_init_mark(new_entry, dnotify_free_mark);
- new_entry->mask = mask;
- new_dnentry->dn = NULL;
+ /* set up the new_fsn_mark and new_dn_mark */
+ new_fsn_mark = &new_dn_mark->fsn_mark;
+ fsnotify_init_mark(new_fsn_mark, dnotify_free_mark);
+ new_fsn_mark->mask = mask;
+ new_dn_mark->dn = NULL;
/* this is needed to prevent the fcntl/close race described below */
mutex_lock(&dnotify_mark_mutex);
- /* add the new_entry or find an old one. */
- spin_lock(&inode->i_lock);
- entry = fsnotify_find_mark_entry(dnotify_group, inode);
- spin_unlock(&inode->i_lock);
- if (entry) {
- dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry);
- spin_lock(&entry->lock);
+ /* add the new_fsn_mark or find an old one. */
+ fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode);
+ if (fsn_mark) {
+ dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
+ spin_lock(&fsn_mark->lock);
} else {
- fsnotify_add_mark(new_entry, dnotify_group, inode);
- spin_lock(&new_entry->lock);
- entry = new_entry;
- dnentry = new_dnentry;
- /* we used new_entry, so don't free it */
- new_entry = NULL;
+ fsnotify_add_mark(new_fsn_mark, dnotify_group, inode, NULL, 0);
+ spin_lock(&new_fsn_mark->lock);
+ fsn_mark = new_fsn_mark;
+ dn_mark = new_dn_mark;
+ /* we used new_fsn_mark, so don't free it */
+ new_fsn_mark = NULL;
}
rcu_read_lock();
@@ -376,17 +365,17 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
/* if (f != filp) means that we lost a race and another task/thread
* actually closed the fd we are still playing with before we grabbed
- * the dnotify_mark_mutex and entry->lock. Since closing the fd is the
- * only time we clean up the mark entries we need to get our mark off
+ * the dnotify_mark_mutex and fsn_mark->lock. Since closing the fd is the
+ * only time we clean up the marks we need to get our mark off
* the list. */
if (f != filp) {
/* if we added ourselves, shoot ourselves, it's possible that
- * the flush actually did shoot this entry. That's fine too
+ * the flush actually did shoot this fsn_mark. That's fine too
* since multiple calls to destroy_mark is perfectly safe, if
- * we found a dnentry already attached to the inode, just sod
+ * we found a dn_mark already attached to the inode, just sod
* off silently as the flush at close time dealt with it.
*/
- if (dnentry == new_dnentry)
+ if (dn_mark == new_dn_mark)
destroy = 1;
goto out;
}
@@ -394,13 +383,13 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
if (error) {
/* if we added, we must shoot */
- if (dnentry == new_dnentry)
+ if (dn_mark == new_dn_mark)
destroy = 1;
goto out;
}
- error = attach_dn(dn, dnentry, id, fd, filp, mask);
- /* !error means that we attached the dn to the dnentry, so don't free it */
+ error = attach_dn(dn, dn_mark, id, fd, filp, mask);
+ /* !error means that we attached the dn to the dn_mark, so don't free it */
if (!error)
dn = NULL;
/* -EEXIST means that we didn't add this new dn and used an old one.
@@ -408,20 +397,20 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
else if (error == -EEXIST)
error = 0;
- dnotify_recalc_inode_mask(entry);
+ dnotify_recalc_inode_mask(fsn_mark);
out:
- spin_unlock(&entry->lock);
+ spin_unlock(&fsn_mark->lock);
if (destroy)
- fsnotify_destroy_mark_by_entry(entry);
+ fsnotify_destroy_mark(fsn_mark);
fsnotify_recalc_group_mask(dnotify_group);
mutex_unlock(&dnotify_mark_mutex);
- fsnotify_put_mark(entry);
+ fsnotify_put_mark(fsn_mark);
out_err:
- if (new_entry)
- fsnotify_put_mark(new_entry);
+ if (new_fsn_mark)
+ fsnotify_put_mark(new_fsn_mark);
if (dn)
kmem_cache_free(dnotify_struct_cache, dn);
return error;
@@ -430,10 +419,9 @@ out_err:
static int __init dnotify_init(void)
{
dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
- dnotify_mark_entry_cache = KMEM_CACHE(dnotify_mark_entry, SLAB_PANIC);
+ dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC);
- dnotify_group = fsnotify_obtain_group(DNOTIFY_GROUP_NUM,
- 0, &dnotify_fsnotify_ops);
+ dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
if (IS_ERR(dnotify_group))
panic("unable to allocate fsnotify group for dnotify\n");
return 0;
diff --git a/fs/notify/fanotify/Kconfig b/fs/notify/fanotify/Kconfig
new file mode 100644
index 000000000000..566de30395c2
--- /dev/null
+++ b/fs/notify/fanotify/Kconfig
@@ -0,0 +1,26 @@
+config FANOTIFY
+ bool "Filesystem wide access notification"
+ select FSNOTIFY
+ select ANON_INODES
+ default y
+ ---help---
+ Say Y here to enable fanotify suport. fanotify is a file access
+ notification system which differs from inotify in that it sends
+ and open file descriptor to the userspace listener along with
+ the event.
+
+ If unsure, say Y.
+
+config FANOTIFY_ACCESS_PERMISSIONS
+ bool "fanotify permissions checking"
+ depends on FANOTIFY
+ depends on SECURITY
+ default n
+ ---help---
+ Say Y here is you want fanotify listeners to be able to make permissions
+ decisions concerning filesystem events. This is used by some fanotify
+ listeners which need to scan files before allowing the system access to
+ use those files. This is used by some anti-malware vendors and by some
+ hierarchical storage managent systems.
+
+ If unsure, say N.
diff --git a/fs/notify/fanotify/Makefile b/fs/notify/fanotify/Makefile
new file mode 100644
index 000000000000..0999213e7e6e
--- /dev/null
+++ b/fs/notify/fanotify/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FANOTIFY) += fanotify.o fanotify_user.o
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c
new file mode 100644
index 000000000000..bbcfccd4a8ea
--- /dev/null
+++ b/fs/notify/fanotify/fanotify.c
@@ -0,0 +1,255 @@
+#include <linux/fanotify.h>
+#include <linux/fdtable.h>
+#include <linux/fsnotify_backend.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h> /* UINT_MAX */
+#include <linux/mount.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+
+static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new)
+{
+ pr_debug("%s: old=%p new=%p\n", __func__, old, new);
+
+ if (old->to_tell == new->to_tell &&
+ old->data_type == new->data_type &&
+ old->tgid == new->tgid) {
+ switch (old->data_type) {
+ case (FSNOTIFY_EVENT_PATH):
+ if ((old->path.mnt == new->path.mnt) &&
+ (old->path.dentry == new->path.dentry))
+ return true;
+ case (FSNOTIFY_EVENT_NONE):
+ return true;
+ default:
+ BUG();
+ };
+ }
+ return false;
+}
+
+/* Note, if we return an event in *arg that a reference is being held... */
+static int fanotify_merge(struct list_head *list,
+ struct fsnotify_event *event,
+ void **arg)
+{
+ struct fsnotify_event_holder *test_holder;
+ struct fsnotify_event *test_event;
+ struct fsnotify_event *new_event;
+ struct fsnotify_event **return_event = (struct fsnotify_event **)arg;
+ int ret = 0;
+
+ pr_debug("%s: list=%p event=%p\n", __func__, list, event);
+
+ *return_event = NULL;
+
+ /* and the list better be locked by something too! */
+
+ list_for_each_entry_reverse(test_holder, list, event_list) {
+ test_event = test_holder->event;
+ if (should_merge(test_event, event)) {
+ fsnotify_get_event(test_event);
+ *return_event = test_event;
+
+ ret = -EEXIST;
+ /* if they are exactly the same we are done */
+ if (test_event->mask == event->mask)
+ goto out;
+
+ /*
+ * if the refcnt == 1 this is the only queue
+ * for this event and so we can update the mask
+ * in place.
+ */
+ if (atomic_read(&test_event->refcnt) == 1) {
+ test_event->mask |= event->mask;
+ goto out;
+ }
+
+ /* can't allocate memory, merge was no possible */
+ new_event = fsnotify_clone_event(test_event);
+ if (unlikely(!new_event)) {
+ ret = 0;
+ goto out;
+ }
+
+ /* we didn't return the test_event, so drop that ref */
+ fsnotify_put_event(test_event);
+ /* the reference we return on new_event is from clone */
+ *return_event = new_event;
+
+ /* build new event and replace it on the list */
+ new_event->mask = (test_event->mask | event->mask);
+ fsnotify_replace_event(test_holder, new_event);
+
+ break;
+ }
+ }
+out:
+ return ret;
+}
+
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+static int fanotify_get_response_from_access(struct fsnotify_group *group,
+ struct fsnotify_event *event)
+{
+ int ret;
+
+ pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
+ wait_event(group->fanotify_data.access_waitq, event->response);
+
+ /* userspace responded, convert to something usable */
+ spin_lock(&event->lock);
+ switch (event->response) {
+ case FAN_ALLOW:
+ ret = 0;
+ break;
+ case FAN_DENY:
+ default:
+ ret = -EPERM;
+ }
+ event->response = 0;
+ spin_unlock(&event->lock);
+
+ pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__,
+ group, event, ret);
+
+ return ret;
+}
+#endif
+
+static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+{
+ int ret;
+ struct fsnotify_event *notify_event = NULL;
+
+ BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
+ BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
+ BUILD_BUG_ON(FAN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
+ BUILD_BUG_ON(FAN_CLOSE_WRITE != FS_CLOSE_WRITE);
+ BUILD_BUG_ON(FAN_OPEN != FS_OPEN);
+ BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD);
+ BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW);
+ BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM);
+ BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
+
+ pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
+ ret = fsnotify_add_notify_event(group, event, NULL, fanotify_merge,
+ (void **)&notify_event);
+ /* -EEXIST means this event was merged with another, not that it was an error */
+ if (ret == -EEXIST)
+ ret = 0;
+ if (ret)
+ goto out;
+
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ if (event->mask & FAN_ALL_PERM_EVENTS) {
+ /* if we merged we need to wait on the new event */
+ if (notify_event)
+ event = notify_event;
+ ret = fanotify_get_response_from_access(group, event);
+ }
+#endif
+
+out:
+ if (notify_event)
+ fsnotify_put_event(notify_event);
+ return ret;
+}
+
+static bool should_send_vfsmount_event(struct fsnotify_group *group, struct vfsmount *mnt,
+ struct inode *inode, __u32 mask)
+{
+ struct fsnotify_mark *mnt_mark;
+ struct fsnotify_mark *inode_mark;
+
+ pr_debug("%s: group=%p vfsmount=%p mask=%x\n",
+ __func__, group, mnt, mask);
+
+ mnt_mark = fsnotify_find_vfsmount_mark(group, mnt);
+ if (!mnt_mark)
+ return false;
+
+ mask &= mnt_mark->mask;
+ mask &= ~mnt_mark->ignored_mask;
+
+ if (mask) {
+ inode_mark = fsnotify_find_inode_mark(group, inode);
+ if (inode_mark) {
+ mask &= ~inode_mark->ignored_mask;
+ fsnotify_put_mark(inode_mark);
+ }
+ }
+
+ /* find took a reference */
+ fsnotify_put_mark(mnt_mark);
+
+ return mask;
+}
+
+static bool should_send_inode_event(struct fsnotify_group *group, struct inode *inode,
+ __u32 mask)
+{
+ struct fsnotify_mark *fsn_mark;
+
+ pr_debug("%s: group=%p inode=%p mask=%x\n",
+ __func__, group, inode, mask);
+
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
+ return false;
+
+ /* if the event is for a child and this inode doesn't care about
+ * events on the child, don't send it! */
+ if ((mask & FS_EVENT_ON_CHILD) &&
+ !(fsn_mark->mask & FS_EVENT_ON_CHILD)) {
+ mask = 0;
+ } else {
+ /*
+ * We care about children, but do we care about this particular
+ * type of event?
+ */
+ mask &= ~FS_EVENT_ON_CHILD;
+ mask &= fsn_mark->mask;
+ mask &= ~fsn_mark->ignored_mask;
+ }
+
+ /* find took a reference */
+ fsnotify_put_mark(fsn_mark);
+
+ return mask;
+}
+
+static bool fanotify_should_send_event(struct fsnotify_group *group, struct inode *to_tell,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
+{
+ pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x data=%p data_type=%d\n",
+ __func__, group, to_tell, mnt, mask, data, data_type);
+
+ /* sorry, fanotify only gives a damn about files and dirs */
+ if (!S_ISREG(to_tell->i_mode) &&
+ !S_ISDIR(to_tell->i_mode))
+ return false;
+
+ /* if we don't have enough info to send an event to userspace say no */
+ if (data_type != FSNOTIFY_EVENT_PATH)
+ return false;
+
+ if (mnt)
+ return should_send_vfsmount_event(group, mnt, to_tell, mask);
+ else
+ return should_send_inode_event(group, to_tell, mask);
+}
+
+const struct fsnotify_ops fanotify_fsnotify_ops = {
+ .handle_event = fanotify_handle_event,
+ .should_send_event = fanotify_should_send_event,
+ .free_group_priv = NULL,
+ .free_event_priv = NULL,
+ .freeing_mark = NULL,
+};
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c
new file mode 100644
index 000000000000..c437bd436e33
--- /dev/null
+++ b/fs/notify/fanotify/fanotify_user.c
@@ -0,0 +1,777 @@
+#include <linux/fanotify.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/anon_inodes.h>
+#include <linux/fsnotify_backend.h>
+#include <linux/init.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include <asm/ioctls.h>
+
+extern const struct fsnotify_ops fanotify_fsnotify_ops;
+
+static struct kmem_cache *fanotify_mark_cache __read_mostly;
+static struct kmem_cache *fanotify_response_event_cache __read_mostly;
+
+struct fanotify_response_event {
+ struct list_head list;
+ __s32 fd;
+ struct fsnotify_event *event;
+};
+
+/*
+ * Get an fsnotify notification event if one exists and is small
+ * enough to fit in "count". Return an error pointer if the count
+ * is not large enough.
+ *
+ * Called with the group->notification_mutex held.
+ */
+static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
+ size_t count)
+{
+ BUG_ON(!mutex_is_locked(&group->notification_mutex));
+
+ pr_debug("%s: group=%p count=%zd\n", __func__, group, count);
+
+ if (fsnotify_notify_queue_is_empty(group))
+ return NULL;
+
+ if (FAN_EVENT_METADATA_LEN > count)
+ return ERR_PTR(-EINVAL);
+
+ /* held the notification_mutex the whole time, so this is the
+ * same event we peeked above */
+ return fsnotify_remove_notify_event(group);
+}
+
+static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event)
+{
+ int client_fd;
+ struct dentry *dentry;
+ struct vfsmount *mnt;
+ struct file *new_file;
+
+ pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
+ client_fd = get_unused_fd();
+ if (client_fd < 0)
+ return client_fd;
+
+ if (event->data_type != FSNOTIFY_EVENT_PATH) {
+ WARN_ON(1);
+ put_unused_fd(client_fd);
+ return -EINVAL;
+ }
+
+ /*
+ * we need a new file handle for the userspace program so it can read even if it was
+ * originally opened O_WRONLY.
+ */
+ dentry = dget(event->path.dentry);
+ mnt = mntget(event->path.mnt);
+ /* it's possible this event was an overflow event. in that case dentry and mnt
+ * are NULL; That's fine, just don't call dentry open */
+ if (dentry && mnt)
+ new_file = dentry_open(dentry, mnt,
+ O_RDONLY | O_LARGEFILE | FMODE_NONOTIFY,
+ current_cred());
+ else
+ new_file = ERR_PTR(-EOVERFLOW);
+ if (IS_ERR(new_file)) {
+ /*
+ * we still send an event even if we can't open the file. this
+ * can happen when say tasks are gone and we try to open their
+ * /proc files or we try to open a WRONLY file like in sysfs
+ * we just send the errno to userspace since there isn't much
+ * else we can do.
+ */
+ put_unused_fd(client_fd);
+ client_fd = PTR_ERR(new_file);
+ } else {
+ fd_install(client_fd, new_file);
+ }
+
+ return client_fd;
+}
+
+static ssize_t fill_event_metadata(struct fsnotify_group *group,
+ struct fanotify_event_metadata *metadata,
+ struct fsnotify_event *event)
+{
+ pr_debug("%s: group=%p metadata=%p event=%p\n", __func__,
+ group, metadata, event);
+
+ metadata->event_len = FAN_EVENT_METADATA_LEN;
+ metadata->vers = FANOTIFY_METADATA_VERSION;
+ metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS;
+ metadata->pid = pid_vnr(event->tgid);
+ metadata->fd = create_fd(group, event);
+
+ return metadata->fd;
+}
+
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group,
+ __s32 fd)
+{
+ struct fanotify_response_event *re, *return_re = NULL;
+
+ mutex_lock(&group->fanotify_data.access_mutex);
+ list_for_each_entry(re, &group->fanotify_data.access_list, list) {
+ if (re->fd != fd)
+ continue;
+
+ list_del_init(&re->list);
+ return_re = re;
+ break;
+ }
+ mutex_unlock(&group->fanotify_data.access_mutex);
+
+ pr_debug("%s: found return_re=%p\n", __func__, return_re);
+
+ return return_re;
+}
+
+static int process_access_response(struct fsnotify_group *group,
+ struct fanotify_response *response_struct)
+{
+ struct fanotify_response_event *re;
+ __s32 fd = response_struct->fd;
+ __u32 response = response_struct->response;
+
+ pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group,
+ fd, response);
+ /*
+ * make sure the response is valid, if invalid we do nothing and either
+ * userspace can send a valid responce or we will clean it up after the
+ * timeout
+ */
+ switch (response) {
+ case FAN_ALLOW:
+ case FAN_DENY:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (fd < 0)
+ return -EINVAL;
+
+ re = dequeue_re(group, fd);
+ if (!re)
+ return -ENOENT;
+
+ re->event->response = response;
+
+ wake_up(&group->fanotify_data.access_waitq);
+
+ kmem_cache_free(fanotify_response_event_cache, re);
+
+ return 0;
+}
+
+static int prepare_for_access_response(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ __s32 fd)
+{
+ struct fanotify_response_event *re;
+
+ if (!(event->mask & FAN_ALL_PERM_EVENTS))
+ return 0;
+
+ re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL);
+ if (!re)
+ return -ENOMEM;
+
+ re->event = event;
+ re->fd = fd;
+
+ mutex_lock(&group->fanotify_data.access_mutex);
+ list_add_tail(&re->list, &group->fanotify_data.access_list);
+ mutex_unlock(&group->fanotify_data.access_mutex);
+
+ return 0;
+}
+
+static void remove_access_response(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ __s32 fd)
+{
+ struct fanotify_response_event *re;
+
+ if (!(event->mask & FAN_ALL_PERM_EVENTS))
+ return;
+
+ re = dequeue_re(group, fd);
+ if (!re)
+ return;
+
+ BUG_ON(re->event != event);
+
+ kmem_cache_free(fanotify_response_event_cache, re);
+
+ return;
+}
+#else
+static int prepare_for_access_response(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ __s32 fd)
+{
+ return 0;
+}
+
+static void remove_access_response(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ __s32 fd)
+{
+ return;
+}
+#endif
+
+static ssize_t copy_event_to_user(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ char __user *buf)
+{
+ struct fanotify_event_metadata fanotify_event_metadata;
+ int fd, ret;
+
+ pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
+ fd = fill_event_metadata(group, &fanotify_event_metadata, event);
+ if (fd < 0)
+ return fd;
+
+ ret = prepare_for_access_response(group, event, fd);
+ if (ret)
+ goto out_close_fd;
+
+ ret = -EFAULT;
+ if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN))
+ goto out_kill_access_response;
+
+ return FAN_EVENT_METADATA_LEN;
+
+out_kill_access_response:
+ remove_access_response(group, event, fd);
+out_close_fd:
+ sys_close(fd);
+ return ret;
+}
+
+/* intofiy userspace file descriptor functions */
+static unsigned int fanotify_poll(struct file *file, poll_table *wait)
+{
+ struct fsnotify_group *group = file->private_data;
+ int ret = 0;
+
+ poll_wait(file, &group->notification_waitq, wait);
+ mutex_lock(&group->notification_mutex);
+ if (!fsnotify_notify_queue_is_empty(group))
+ ret = POLLIN | POLLRDNORM;
+ mutex_unlock(&group->notification_mutex);
+
+ return ret;
+}
+
+static ssize_t fanotify_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct fsnotify_group *group;
+ struct fsnotify_event *kevent;
+ char __user *start;
+ int ret;
+ DEFINE_WAIT(wait);
+
+ start = buf;
+ group = file->private_data;
+
+ pr_debug("%s: group=%p\n", __func__, group);
+
+ while (1) {
+ prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE);
+
+ mutex_lock(&group->notification_mutex);
+ kevent = get_one_event(group, count);
+ mutex_unlock(&group->notification_mutex);
+
+ if (kevent) {
+ ret = PTR_ERR(kevent);
+ if (IS_ERR(kevent))
+ break;
+ ret = copy_event_to_user(group, kevent, buf);
+ fsnotify_put_event(kevent);
+ if (ret < 0)
+ break;
+ buf += ret;
+ count -= ret;
+ continue;
+ }
+
+ ret = -EAGAIN;
+ if (file->f_flags & O_NONBLOCK)
+ break;
+ ret = -EINTR;
+ if (signal_pending(current))
+ break;
+
+ if (start != buf)
+ break;
+
+ schedule();
+ }
+
+ finish_wait(&group->notification_waitq, &wait);
+ if (start != buf && ret != -EFAULT)
+ ret = buf - start;
+ return ret;
+}
+
+static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
+{
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ struct fanotify_response response = { .fd = -1, .response = -1 };
+ struct fsnotify_group *group;
+ int ret;
+
+ group = file->private_data;
+
+ if (count > sizeof(response))
+ count = sizeof(response);
+
+ pr_debug("%s: group=%p count=%zu\n", __func__, group, count);
+
+ if (copy_from_user(&response, buf, count))
+ return -EFAULT;
+
+ ret = process_access_response(group, &response);
+ if (ret < 0)
+ count = ret;
+
+ return count;
+#else
+ return -EINVAL;
+#endif
+}
+
+static int fanotify_release(struct inode *ignored, struct file *file)
+{
+ struct fsnotify_group *group = file->private_data;
+
+ pr_debug("%s: file=%p group=%p\n", __func__, file, group);
+
+ /* matches the fanotify_init->fsnotify_alloc_group */
+ fsnotify_put_group(group);
+
+ return 0;
+}
+
+static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct fsnotify_group *group;
+ struct fsnotify_event_holder *holder;
+ void __user *p;
+ int ret = -ENOTTY;
+ size_t send_len = 0;
+
+ group = file->private_data;
+
+ p = (void __user *) arg;
+
+ switch (cmd) {
+ case FIONREAD:
+ mutex_lock(&group->notification_mutex);
+ list_for_each_entry(holder, &group->notification_list, event_list)
+ send_len += FAN_EVENT_METADATA_LEN;
+ mutex_unlock(&group->notification_mutex);
+ ret = put_user(send_len, (int __user *) p);
+ break;
+ }
+
+ return ret;
+}
+
+static const struct file_operations fanotify_fops = {
+ .poll = fanotify_poll,
+ .read = fanotify_read,
+ .write = fanotify_write,
+ .fasync = NULL,
+ .release = fanotify_release,
+ .unlocked_ioctl = fanotify_ioctl,
+ .compat_ioctl = fanotify_ioctl,
+};
+
+static void fanotify_free_mark(struct fsnotify_mark *fsn_mark)
+{
+ kmem_cache_free(fanotify_mark_cache, fsn_mark);
+}
+
+static int fanotify_find_path(int dfd, const char __user *filename,
+ struct path *path, unsigned int flags)
+{
+ int ret;
+
+ pr_debug("%s: dfd=%d filename=%p flags=%x\n", __func__,
+ dfd, filename, flags);
+
+ if (filename == NULL) {
+ struct file *file;
+ int fput_needed;
+
+ ret = -EBADF;
+ file = fget_light(dfd, &fput_needed);
+ if (!file)
+ goto out;
+
+ ret = -ENOTDIR;
+ if ((flags & FAN_MARK_ONLYDIR) &&
+ !(S_ISDIR(file->f_path.dentry->d_inode->i_mode))) {
+ fput_light(file, fput_needed);
+ goto out;
+ }
+
+ *path = file->f_path;
+ path_get(path);
+ fput_light(file, fput_needed);
+ } else {
+ unsigned int lookup_flags = 0;
+
+ if (!(flags & FAN_MARK_DONT_FOLLOW))
+ lookup_flags |= LOOKUP_FOLLOW;
+ if (flags & FAN_MARK_ONLYDIR)
+ lookup_flags |= LOOKUP_DIRECTORY;
+
+ ret = user_path_at(dfd, filename, lookup_flags, path);
+ if (ret)
+ goto out;
+ }
+
+ /* you can only watch an inode if you have read permissions on it */
+ ret = inode_permission(path->dentry->d_inode, MAY_READ);
+ if (ret)
+ path_put(path);
+out:
+ return ret;
+}
+
+static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
+ __u32 mask,
+ unsigned int flags)
+{
+ __u32 oldmask;
+
+ spin_lock(&fsn_mark->lock);
+ if (!(flags & FAN_MARK_IGNORED_MASK)) {
+ oldmask = fsn_mark->mask;
+ fsnotify_set_mark_mask_locked(fsn_mark, (oldmask & ~mask));
+ } else {
+ oldmask = fsn_mark->ignored_mask;
+ fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask & ~mask));
+ }
+ spin_unlock(&fsn_mark->lock);
+
+ if (!(oldmask & ~mask))
+ fsnotify_destroy_mark(fsn_mark);
+
+ return mask & oldmask;
+}
+
+static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
+ struct vfsmount *mnt, __u32 mask,
+ unsigned int flags)
+{
+ struct fsnotify_mark *fsn_mark = NULL;
+ __u32 removed;
+
+ fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
+ if (!fsn_mark)
+ return -ENOENT;
+
+ removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+ fsnotify_put_mark(fsn_mark);
+ if (removed & group->mask)
+ fsnotify_recalc_group_mask(group);
+ if (removed & mnt->mnt_fsnotify_mask)
+ fsnotify_recalc_vfsmount_mask(mnt);
+
+ return 0;
+}
+
+static int fanotify_remove_inode_mark(struct fsnotify_group *group,
+ struct inode *inode, __u32 mask,
+ unsigned int flags)
+{
+ struct fsnotify_mark *fsn_mark = NULL;
+ __u32 removed;
+
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
+ return -ENOENT;
+
+ removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags);
+ /* matches the fsnotify_find_inode_mark() */
+ fsnotify_put_mark(fsn_mark);
+
+ if (removed & group->mask)
+ fsnotify_recalc_group_mask(group);
+ if (removed & inode->i_fsnotify_mask)
+ fsnotify_recalc_inode_mask(inode);
+
+ return 0;
+}
+
+static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark,
+ __u32 mask,
+ unsigned int flags)
+{
+ __u32 oldmask;
+
+ spin_lock(&fsn_mark->lock);
+ if (!(flags & FAN_MARK_IGNORED_MASK)) {
+ oldmask = fsn_mark->mask;
+ fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask));
+ } else {
+ oldmask = fsn_mark->ignored_mask;
+ fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask | mask));
+ if (flags & FAN_MARK_IGNORED_SURV_MODIFY)
+ fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY;
+ }
+ spin_unlock(&fsn_mark->lock);
+
+ return mask & ~oldmask;
+}
+
+static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
+ struct vfsmount *mnt, __u32 mask,
+ unsigned int flags)
+{
+ struct fsnotify_mark *fsn_mark;
+ __u32 added;
+
+ fsn_mark = fsnotify_find_vfsmount_mark(group, mnt);
+ if (!fsn_mark) {
+ int ret;
+
+ fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
+ if (!fsn_mark)
+ return -ENOMEM;
+
+ fsnotify_init_mark(fsn_mark, fanotify_free_mark);
+ ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0);
+ if (ret) {
+ fanotify_free_mark(fsn_mark);
+ return ret;
+ }
+ }
+ added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
+ fsnotify_put_mark(fsn_mark);
+ if (added) {
+ if (added & ~group->mask)
+ fsnotify_recalc_group_mask(group);
+ if (added & ~mnt->mnt_fsnotify_mask)
+ fsnotify_recalc_vfsmount_mask(mnt);
+ }
+ return 0;
+}
+
+static int fanotify_add_inode_mark(struct fsnotify_group *group,
+ struct inode *inode, __u32 mask,
+ unsigned int flags)
+{
+ struct fsnotify_mark *fsn_mark;
+ __u32 added;
+
+ pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
+
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark) {
+ int ret;
+
+ fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL);
+ if (!fsn_mark)
+ return -ENOMEM;
+
+ fsnotify_init_mark(fsn_mark, fanotify_free_mark);
+ ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0);
+ if (ret) {
+ fanotify_free_mark(fsn_mark);
+ return ret;
+ }
+ }
+ added = fanotify_mark_add_to_mask(fsn_mark, mask, flags);
+ fsnotify_put_mark(fsn_mark);
+ if (added) {
+ if (added & ~group->mask)
+ fsnotify_recalc_group_mask(group);
+ if (added & ~inode->i_fsnotify_mask)
+ fsnotify_recalc_inode_mask(inode);
+ }
+ return 0;
+}
+
+/* fanotify syscalls */
+SYSCALL_DEFINE3(fanotify_init, unsigned int, flags, unsigned int, event_f_flags,
+ unsigned int, priority)
+{
+ struct fsnotify_group *group;
+ int f_flags, fd;
+
+ pr_debug("%s: flags=%d event_f_flags=%d priority=%d\n",
+ __func__, flags, event_f_flags, priority);
+
+ if (event_f_flags)
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (flags & ~FAN_ALL_INIT_FLAGS)
+ return -EINVAL;
+
+ f_flags = O_RDWR | FMODE_NONOTIFY;
+ if (flags & FAN_CLOEXEC)
+ f_flags |= O_CLOEXEC;
+ if (flags & FAN_NONBLOCK)
+ f_flags |= O_NONBLOCK;
+
+ /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
+ group = fsnotify_alloc_group(&fanotify_fsnotify_ops);
+ if (IS_ERR(group))
+ return PTR_ERR(group);
+
+ group->priority = priority;
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ mutex_init(&group->fanotify_data.access_mutex);
+ init_waitqueue_head(&group->fanotify_data.access_waitq);
+ INIT_LIST_HEAD(&group->fanotify_data.access_list);
+#endif
+
+ fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags);
+ if (fd < 0)
+ goto out_put_group;
+
+ return fd;
+
+out_put_group:
+ fsnotify_put_group(group);
+ return fd;
+}
+
+SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags,
+ __u64 mask, int dfd,
+ const char __user * pathname)
+{
+ struct inode *inode = NULL;
+ struct vfsmount *mnt = NULL;
+ struct fsnotify_group *group;
+ struct file *filp;
+ struct path path;
+ int ret, fput_needed;
+
+ pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n",
+ __func__, fanotify_fd, flags, dfd, pathname, mask);
+
+ /* we only use the lower 32 bits as of right now. */
+ if (mask & ((__u64)0xffffffff << 32))
+ return -EINVAL;
+
+ if (flags & ~FAN_ALL_MARK_FLAGS)
+ return -EINVAL;
+ switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
+ case FAN_MARK_ADD:
+ case FAN_MARK_REMOVE:
+ case FAN_MARK_FLUSH:
+ break;
+ default:
+ return -EINVAL;
+ }
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD))
+#else
+ if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD))
+#endif
+ return -EINVAL;
+
+ filp = fget_light(fanotify_fd, &fput_needed);
+ if (unlikely(!filp))
+ return -EBADF;
+
+ /* verify that this is indeed an fanotify instance */
+ ret = -EINVAL;
+ if (unlikely(filp->f_op != &fanotify_fops))
+ goto fput_and_out;
+
+ ret = fanotify_find_path(dfd, pathname, &path, flags);
+ if (ret)
+ goto fput_and_out;
+
+ /* inode held in place by reference to path; group by fget on fd */
+ if (!(flags & FAN_MARK_MOUNT))
+ inode = path.dentry->d_inode;
+ else
+ mnt = path.mnt;
+ group = filp->private_data;
+
+ /* create/update an inode mark */
+ switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) {
+ case FAN_MARK_ADD:
+ if (flags & FAN_MARK_MOUNT)
+ ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags);
+ else
+ ret = fanotify_add_inode_mark(group, inode, mask, flags);
+ break;
+ case FAN_MARK_REMOVE:
+ if (flags & FAN_MARK_MOUNT)
+ ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags);
+ else
+ ret = fanotify_remove_inode_mark(group, inode, mask, flags);
+ break;
+ case FAN_MARK_FLUSH:
+ if (flags & FAN_MARK_MOUNT)
+ fsnotify_clear_vfsmount_marks_by_group(group);
+ else
+ fsnotify_clear_inode_marks_by_group(group);
+ fsnotify_recalc_group_mask(group);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ path_put(&path);
+fput_and_out:
+ fput_light(filp, fput_needed);
+ return ret;
+}
+
+#ifdef CONFIG_HAVE_SYSCALL_WRAPPERS
+asmlinkage long SyS_fanotify_mark(long fanotify_fd, long flags, __u64 mask,
+ long dfd, long pathname)
+{
+ return SYSC_fanotify_mark((int) fanotify_fd, (unsigned int) flags,
+ mask, (int) dfd,
+ (const char __user *) pathname);
+}
+SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark);
+#endif
+
+/*
+ * fanotify_user_setup - Our initialization function. Note that we cannnot return
+ * error because we have compiled-in VFS hooks. So an (unlikely) failure here
+ * must result in panic().
+ */
+static int __init fanotify_user_setup(void)
+{
+ fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
+ fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event,
+ SLAB_PANIC);
+
+ return 0;
+}
+device_initcall(fanotify_user_setup);
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index fcc2f064af83..9810babb1a3b 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -21,6 +21,7 @@
#include <linux/gfp.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mount.h>
#include <linux/srcu.h>
#include <linux/fsnotify_backend.h>
@@ -35,6 +36,11 @@ void __fsnotify_inode_delete(struct inode *inode)
}
EXPORT_SYMBOL_GPL(__fsnotify_inode_delete);
+void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
+{
+ fsnotify_clear_marks_by_mount(mnt);
+}
+
/*
* Given an inode, first check if we care what happens to our children. Inotify
* and dnotify both tell their parents about events. If we care about any event
@@ -78,13 +84,16 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
}
/* Notify this dentry's parent about a child's events. */
-void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{
struct dentry *parent;
struct inode *p_inode;
bool send = false;
bool should_update_children = false;
+ if (!dentry)
+ dentry = path->dentry;
+
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return;
@@ -115,8 +124,12 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
* specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD;
- fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
- dentry->d_name.name, 0);
+ if (path)
+ fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
+ dentry->d_name.name, 0);
+ else
+ fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
+ dentry->d_name.name, 0);
dput(parent);
}
@@ -127,51 +140,127 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
}
EXPORT_SYMBOL_GPL(__fsnotify_parent);
+void __fsnotify_flush_ignored_mask(struct inode *inode, void *data, int data_is)
+{
+ struct fsnotify_mark *mark;
+ struct hlist_node *node;
+
+ if (!hlist_empty(&inode->i_fsnotify_marks)) {
+ spin_lock(&inode->i_lock);
+ hlist_for_each_entry(mark, node, &inode->i_fsnotify_marks, i.i_list) {
+ if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
+ mark->ignored_mask = 0;
+ }
+ spin_unlock(&inode->i_lock);
+ }
+
+ if (data_is == FSNOTIFY_EVENT_PATH) {
+ struct vfsmount *mnt;
+
+ mnt = ((struct path *)data)->mnt;
+ if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) {
+ spin_lock(&mnt->mnt_root->d_lock);
+ hlist_for_each_entry(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
+ if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
+ mark->ignored_mask = 0;
+ }
+ spin_unlock(&mnt->mnt_root->d_lock);
+ }
+ }
+}
+
+static int send_to_group(struct fsnotify_group *group, struct inode *to_tell,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_is, u32 cookie, const unsigned char *file_name,
+ struct fsnotify_event **event)
+{
+ if (!group->ops->should_send_event(group, to_tell, mnt, mask,
+ data, data_is))
+ return 0;
+ if (!*event) {
+ *event = fsnotify_create_event(to_tell, mask, data,
+ data_is, file_name,
+ cookie, GFP_KERNEL);
+ if (!*event)
+ return -ENOMEM;
+ }
+ return group->ops->handle_event(group, *event);
+}
+
+static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt)
+{
+ if (!mnt)
+ return false;
+
+ return (test_mask & mnt->mnt_fsnotify_mask);
+}
+
/*
* This is the main call to fsnotify. The VFS calls into hook specific functions
* in linux/fsnotify.h. Those functions then in turn call here. Here will call
* out to all of the registered fsnotify_group. Those groups can then use the
* notification event in whatever means they feel necessary.
*/
-void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie)
+int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+ const unsigned char *file_name, u32 cookie)
{
struct fsnotify_group *group;
struct fsnotify_event *event = NULL;
- int idx;
+ struct vfsmount *mnt = NULL;
+ int idx, ret = 0;
/* global tests shouldn't care about events on child only the specific event */
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
- if (list_empty(&fsnotify_groups))
- return;
+ /* if no fsnotify listeners, nothing to do */
+ if (list_empty(&fsnotify_inode_groups) &&
+ list_empty(&fsnotify_vfsmount_groups))
+ return 0;
+
+ if (mask & FS_MODIFY)
+ __fsnotify_flush_ignored_mask(to_tell, data, data_is);
- if (!(test_mask & fsnotify_mask))
- return;
+ /* if none of the directed listeners or vfsmount listeners care */
+ if (!(test_mask & fsnotify_inode_mask) &&
+ !(test_mask & fsnotify_vfsmount_mask))
+ return 0;
+
+ if (data_is == FSNOTIFY_EVENT_PATH)
+ mnt = ((struct path *)data)->mnt;
+
+ /* if this inode's directed listeners don't care and nothing on the vfsmount
+ * listeners list cares, nothing to do */
+ if (!(test_mask & to_tell->i_fsnotify_mask) &&
+ !needed_by_vfsmount(test_mask, mnt))
+ return 0;
- if (!(test_mask & to_tell->i_fsnotify_mask))
- return;
/*
* SRCU!! the groups list is very very much read only and the path is
* very hot. The VAST majority of events are not going to need to do
* anything other than walk the list so it's crazy to pre-allocate.
*/
idx = srcu_read_lock(&fsnotify_grp_srcu);
- list_for_each_entry_rcu(group, &fsnotify_groups, group_list) {
- if (test_mask & group->mask) {
- if (!group->ops->should_send_event(group, to_tell, mask))
- continue;
- if (!event) {
- event = fsnotify_create_event(to_tell, mask, data,
- data_is, file_name, cookie,
- GFP_KERNEL);
- /* shit, we OOM'd and now we can't tell, maybe
- * someday someone else will want to do something
- * here */
- if (!event)
- break;
+
+ if (test_mask & to_tell->i_fsnotify_mask) {
+ list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) {
+ if (test_mask & group->mask) {
+ ret = send_to_group(group, to_tell, NULL, mask, data, data_is,
+ cookie, file_name, &event);
+ if (ret)
+ goto out;
}
- group->ops->handle_event(group, event);
}
}
+ if (needed_by_vfsmount(test_mask, mnt)) {
+ list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) {
+ if (test_mask & group->mask) {
+ ret = send_to_group(group, to_tell, mnt, mask, data, data_is,
+ cookie, file_name, &event);
+ if (ret)
+ goto out;
+ }
+ }
+ }
+out:
srcu_read_unlock(&fsnotify_grp_srcu, idx);
/*
* fsnotify_create_event() took a reference so the event can't be cleaned
@@ -179,6 +268,8 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
*/
if (event)
fsnotify_put_event(event);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(fsnotify);
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h
index 4dc240824b2d..1be54f6f9e7d 100644
--- a/fs/notify/fsnotify.h
+++ b/fs/notify/fsnotify.h
@@ -8,19 +8,44 @@
/* protects reads of fsnotify_groups */
extern struct srcu_struct fsnotify_grp_srcu;
-/* all groups which receive fsnotify events */
-extern struct list_head fsnotify_groups;
-/* all bitwise OR of all event types (FS_*) for all fsnotify_groups */
-extern __u32 fsnotify_mask;
+/* all groups which receive inode fsnotify events */
+extern struct list_head fsnotify_inode_groups;
+/* all groups which receive vfsmount fsnotify events */
+extern struct list_head fsnotify_vfsmount_groups;
+/* all bitwise OR of all event types (FS_*) for all fsnotify_inode_groups */
+extern __u32 fsnotify_inode_mask;
+/* all bitwise OR of all event types (FS_*) for all fsnotify_vfsmount_groups */
+extern __u32 fsnotify_vfsmount_mask;
/* destroy all events sitting in this groups notification queue */
extern void fsnotify_flush_notify(struct fsnotify_group *group);
+extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark,
+ __u32 mask);
+/* add a mark to an inode */
+extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
+ struct fsnotify_group *group, struct inode *inode,
+ int allow_dups);
+/* add a mark to a vfsmount */
+extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
+ struct fsnotify_group *group, struct vfsmount *mnt,
+ int allow_dups);
+
+/* add a group to the inode group list */
+extern void fsnotify_add_inode_group(struct fsnotify_group *group);
+/* add a group to the vfsmount group list */
+extern void fsnotify_add_vfsmount_group(struct fsnotify_group *group);
/* final kfree of a group */
extern void fsnotify_final_destroy_group(struct fsnotify_group *group);
+/* vfsmount specific destruction of a mark */
+extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
+/* inode specific destruction of a mark */
+extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
/* run the list of all marks associated with inode and flag them to be freed */
extern void fsnotify_clear_marks_by_inode(struct inode *inode);
+/* run the list of all marks associated with vfsmount and flag them to be freed */
+extern void fsnotify_clear_marks_by_mount(struct vfsmount *mnt);
/*
* update the dentry->d_flags of all of inode's children to indicate if inode cares
* about events that happen to its children.
diff --git a/fs/notify/group.c b/fs/notify/group.c
index 0e1677144bc5..ada913fd4f7f 100644
--- a/fs/notify/group.c
+++ b/fs/notify/group.c
@@ -32,10 +32,14 @@
static DEFINE_MUTEX(fsnotify_grp_mutex);
/* protects reads while running the fsnotify_groups list */
struct srcu_struct fsnotify_grp_srcu;
-/* all groups registered to receive filesystem notifications */
-LIST_HEAD(fsnotify_groups);
+/* all groups registered to receive inode filesystem notifications */
+LIST_HEAD(fsnotify_inode_groups);
+/* all groups registered to receive mount point filesystem notifications */
+LIST_HEAD(fsnotify_vfsmount_groups);
/* bitwise OR of all events (FS_*) interesting to some group on this system */
-__u32 fsnotify_mask;
+__u32 fsnotify_inode_mask;
+/* bitwise OR of all events (FS_*) interesting to some group on this system */
+__u32 fsnotify_vfsmount_mask;
/*
* When a new group registers or changes it's set of interesting events
@@ -44,14 +48,20 @@ __u32 fsnotify_mask;
void fsnotify_recalc_global_mask(void)
{
struct fsnotify_group *group;
- __u32 mask = 0;
+ __u32 inode_mask = 0;
+ __u32 vfsmount_mask = 0;
int idx;
idx = srcu_read_lock(&fsnotify_grp_srcu);
- list_for_each_entry_rcu(group, &fsnotify_groups, group_list)
- mask |= group->mask;
+ list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list)
+ inode_mask |= group->mask;
+ list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list)
+ vfsmount_mask |= group->mask;
+
srcu_read_unlock(&fsnotify_grp_srcu, idx);
- fsnotify_mask = mask;
+
+ fsnotify_inode_mask = inode_mask;
+ fsnotify_vfsmount_mask = vfsmount_mask;
}
/*
@@ -64,11 +74,11 @@ void fsnotify_recalc_group_mask(struct fsnotify_group *group)
{
__u32 mask = 0;
__u32 old_mask = group->mask;
- struct fsnotify_mark_entry *entry;
+ struct fsnotify_mark *mark;
spin_lock(&group->mark_lock);
- list_for_each_entry(entry, &group->mark_entries, g_list)
- mask |= entry->mask;
+ list_for_each_entry(mark, &group->marks_list, g_list)
+ mask |= mark->mask;
spin_unlock(&group->mark_lock);
group->mask = mask;
@@ -77,13 +87,60 @@ void fsnotify_recalc_group_mask(struct fsnotify_group *group)
fsnotify_recalc_global_mask();
}
-/*
- * Take a reference to a group so things found under the fsnotify_grp_mutex
- * can't get freed under us
- */
-static void fsnotify_get_group(struct fsnotify_group *group)
+void fsnotify_add_vfsmount_group(struct fsnotify_group *group)
{
- atomic_inc(&group->refcnt);
+ struct fsnotify_group *group_iter;
+ unsigned int priority = group->priority;
+
+ mutex_lock(&fsnotify_grp_mutex);
+
+ if (!group->on_vfsmount_group_list) {
+ list_for_each_entry(group_iter, &fsnotify_vfsmount_groups,
+ vfsmount_group_list) {
+ /* insert in front of this one? */
+ if (priority < group_iter->priority) {
+ /* list_add_tail() insert in front of group_iter */
+ list_add_tail_rcu(&group->inode_group_list,
+ &group_iter->inode_group_list);
+ goto out;
+ }
+ }
+
+ /* apparently we need to be the last entry */
+ list_add_tail_rcu(&group->vfsmount_group_list, &fsnotify_vfsmount_groups);
+ }
+out:
+ group->on_vfsmount_group_list = 1;
+
+ mutex_unlock(&fsnotify_grp_mutex);
+}
+
+void fsnotify_add_inode_group(struct fsnotify_group *group)
+{
+ struct fsnotify_group *group_iter;
+ unsigned int priority = group->priority;
+
+ mutex_lock(&fsnotify_grp_mutex);
+
+ /* add to global group list, priority 0 first, UINT_MAX last */
+ if (!group->on_inode_group_list) {
+ list_for_each_entry(group_iter, &fsnotify_inode_groups,
+ inode_group_list) {
+ if (priority < group_iter->priority) {
+ /* list_add_tail() insert in front of group_iter */
+ list_add_tail_rcu(&group->inode_group_list,
+ &group_iter->inode_group_list);
+ goto out;
+ }
+ }
+
+ /* apparently we need to be the last entry */
+ list_add_tail_rcu(&group->inode_group_list, &fsnotify_inode_groups);
+ }
+out:
+ group->on_inode_group_list = 1;
+
+ mutex_unlock(&fsnotify_grp_mutex);
}
/*
@@ -110,7 +167,7 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group)
*/
static void fsnotify_destroy_group(struct fsnotify_group *group)
{
- /* clear all inode mark entries for this group */
+ /* clear all inode marks for this group */
fsnotify_clear_marks_by_group(group);
/* past the point of no return, matches the initial value of 1 */
@@ -127,9 +184,12 @@ static void __fsnotify_evict_group(struct fsnotify_group *group)
{
BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
- if (group->on_group_list)
- list_del_rcu(&group->group_list);
- group->on_group_list = 0;
+ if (group->on_inode_group_list)
+ list_del_rcu(&group->inode_group_list);
+ group->on_inode_group_list = 0;
+ if (group->on_vfsmount_group_list)
+ list_del_rcu(&group->vfsmount_group_list);
+ group->on_vfsmount_group_list = 0;
}
/*
@@ -171,84 +231,38 @@ void fsnotify_put_group(struct fsnotify_group *group)
}
/*
- * Simply run the fsnotify_groups list and find a group which matches
- * the given parameters. If a group is found we take a reference to that
- * group.
+ * Create a new fsnotify_group and hold a reference for the group returned.
*/
-static struct fsnotify_group *fsnotify_find_group(unsigned int group_num, __u32 mask,
- const struct fsnotify_ops *ops)
+struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
{
- struct fsnotify_group *group_iter;
- struct fsnotify_group *group = NULL;
-
- BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex));
-
- list_for_each_entry_rcu(group_iter, &fsnotify_groups, group_list) {
- if (group_iter->group_num == group_num) {
- if ((group_iter->mask == mask) &&
- (group_iter->ops == ops)) {
- fsnotify_get_group(group_iter);
- group = group_iter;
- } else
- group = ERR_PTR(-EEXIST);
- }
- }
- return group;
-}
-
-/*
- * Either finds an existing group which matches the group_num, mask, and ops or
- * creates a new group and adds it to the global group list. In either case we
- * take a reference for the group returned.
- */
-struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask,
- const struct fsnotify_ops *ops)
-{
- struct fsnotify_group *group, *tgroup;
+ struct fsnotify_group *group;
- /* very low use, simpler locking if we just always alloc */
- group = kmalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
+ group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
if (!group)
return ERR_PTR(-ENOMEM);
+ /* set to 0 when there a no external references to this group */
atomic_set(&group->refcnt, 1);
-
- group->on_group_list = 0;
- group->group_num = group_num;
- group->mask = mask;
+ /*
+ * hits 0 when there are no external references AND no marks for
+ * this group
+ */
+ atomic_set(&group->num_marks, 1);
mutex_init(&group->notification_mutex);
INIT_LIST_HEAD(&group->notification_list);
init_waitqueue_head(&group->notification_waitq);
- group->q_len = 0;
group->max_events = UINT_MAX;
- spin_lock_init(&group->mark_lock);
- atomic_set(&group->num_marks, 0);
- INIT_LIST_HEAD(&group->mark_entries);
+ INIT_LIST_HEAD(&group->inode_group_list);
+ INIT_LIST_HEAD(&group->vfsmount_group_list);
- group->ops = ops;
-
- mutex_lock(&fsnotify_grp_mutex);
- tgroup = fsnotify_find_group(group_num, mask, ops);
- if (tgroup) {
- /* group already exists */
- mutex_unlock(&fsnotify_grp_mutex);
- /* destroy the new one we made */
- fsnotify_put_group(group);
- return tgroup;
- }
-
- /* group not found, add a new one */
- list_add_rcu(&group->group_list, &fsnotify_groups);
- group->on_group_list = 1;
- /* being on the fsnotify_groups list holds one num_marks */
- atomic_inc(&group->num_marks);
+ spin_lock_init(&group->mark_lock);
+ INIT_LIST_HEAD(&group->marks_list);
- mutex_unlock(&fsnotify_grp_mutex);
+ group->priority = UINT_MAX;
- if (mask)
- fsnotify_recalc_global_mask();
+ group->ops = ops;
return group;
}
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c
index 0399bcbe09c8..0c0a48b1659f 100644
--- a/fs/notify/inode_mark.c
+++ b/fs/notify/inode_mark.c
@@ -16,72 +16,6 @@
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*
- * fsnotify inode mark locking/lifetime/and refcnting
- *
- * REFCNT:
- * The mark->refcnt tells how many "things" in the kernel currently are
- * referencing this object. The object typically will live inside the kernel
- * with a refcnt of 2, one for each list it is on (i_list, g_list). Any task
- * which can find this object holding the appropriete locks, can take a reference
- * and the object itself is guarenteed to survive until the reference is dropped.
- *
- * LOCKING:
- * There are 3 spinlocks involved with fsnotify inode marks and they MUST
- * be taken in order as follows:
- *
- * entry->lock
- * group->mark_lock
- * inode->i_lock
- *
- * entry->lock protects 2 things, entry->group and entry->inode. You must hold
- * that lock to dereference either of these things (they could be NULL even with
- * the lock)
- *
- * group->mark_lock protects the mark_entries list anchored inside a given group
- * and each entry is hooked via the g_list. It also sorta protects the
- * free_g_list, which when used is anchored by a private list on the stack of the
- * task which held the group->mark_lock.
- *
- * inode->i_lock protects the i_fsnotify_mark_entries list anchored inside a
- * given inode and each entry is hooked via the i_list. (and sorta the
- * free_i_list)
- *
- *
- * LIFETIME:
- * Inode marks survive between when they are added to an inode and when their
- * refcnt==0.
- *
- * The inode mark can be cleared for a number of different reasons including:
- * - The inode is unlinked for the last time. (fsnotify_inode_remove)
- * - The inode is being evicted from cache. (fsnotify_inode_delete)
- * - The fs the inode is on is unmounted. (fsnotify_inode_delete/fsnotify_unmount_inodes)
- * - Something explicitly requests that it be removed. (fsnotify_destroy_mark_by_entry)
- * - The fsnotify_group associated with the mark is going away and all such marks
- * need to be cleaned up. (fsnotify_clear_marks_by_group)
- *
- * Worst case we are given an inode and need to clean up all the marks on that
- * inode. We take i_lock and walk the i_fsnotify_mark_entries safely. For each
- * mark on the list we take a reference (so the mark can't disappear under us).
- * We remove that mark form the inode's list of marks and we add this mark to a
- * private list anchored on the stack using i_free_list; At this point we no
- * longer fear anything finding the mark using the inode's list of marks.
- *
- * We can safely and locklessly run the private list on the stack of everything
- * we just unattached from the original inode. For each mark on the private list
- * we grab the mark-> and can thus dereference mark->group and mark->inode. If
- * we see the group and inode are not NULL we take those locks. Now holding all
- * 3 locks we can completely remove the mark from other tasks finding it in the
- * future. Remember, 10 things might already be referencing this mark, but they
- * better be holding a ref. We drop our reference we took before we unhooked it
- * from the inode. When the ref hits 0 we can free the mark.
- *
- * Very similarly for freeing by group, except we use free_g_list.
- *
- * This has the very interesting property of being able to run concurrently with
- * any (or all) other directions.
- */
-
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -95,30 +29,19 @@
#include <linux/fsnotify_backend.h>
#include "fsnotify.h"
-void fsnotify_get_mark(struct fsnotify_mark_entry *entry)
-{
- atomic_inc(&entry->refcnt);
-}
-
-void fsnotify_put_mark(struct fsnotify_mark_entry *entry)
-{
- if (atomic_dec_and_test(&entry->refcnt))
- entry->free_mark(entry);
-}
-
/*
* Recalculate the mask of events relevant to a given inode locked.
*/
static void fsnotify_recalc_inode_mask_locked(struct inode *inode)
{
- struct fsnotify_mark_entry *entry;
+ struct fsnotify_mark *mark;
struct hlist_node *pos;
__u32 new_mask = 0;
assert_spin_locked(&inode->i_lock);
- hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list)
- new_mask |= entry->mask;
+ hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list)
+ new_mask |= mark->mask;
inode->i_fsnotify_mask = new_mask;
}
@@ -135,107 +58,26 @@ void fsnotify_recalc_inode_mask(struct inode *inode)
__fsnotify_update_child_dentry_flags(inode);
}
-/*
- * Any time a mark is getting freed we end up here.
- * The caller had better be holding a reference to this mark so we don't actually
- * do the final put under the entry->lock
- */
-void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry)
+void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
{
- struct fsnotify_group *group;
- struct inode *inode;
-
- spin_lock(&entry->lock);
+ struct inode *inode = mark->i.inode;
- group = entry->group;
- inode = entry->inode;
+ assert_spin_locked(&mark->lock);
+ assert_spin_locked(&mark->group->mark_lock);
- BUG_ON(group && !inode);
- BUG_ON(!group && inode);
-
- /* if !group something else already marked this to die */
- if (!group) {
- spin_unlock(&entry->lock);
- return;
- }
-
- /* 1 from caller and 1 for being on i_list/g_list */
- BUG_ON(atomic_read(&entry->refcnt) < 2);
-
- spin_lock(&group->mark_lock);
spin_lock(&inode->i_lock);
- hlist_del_init(&entry->i_list);
- entry->inode = NULL;
-
- list_del_init(&entry->g_list);
- entry->group = NULL;
-
- fsnotify_put_mark(entry); /* for i_list and g_list */
+ hlist_del_init(&mark->i.i_list);
+ mark->i.inode = NULL;
/*
- * this mark is now off the inode->i_fsnotify_mark_entries list and we
+ * this mark is now off the inode->i_fsnotify_marks list and we
* hold the inode->i_lock, so this is the perfect time to update the
* inode->i_fsnotify_mask
*/
fsnotify_recalc_inode_mask_locked(inode);
spin_unlock(&inode->i_lock);
- spin_unlock(&group->mark_lock);
- spin_unlock(&entry->lock);
-
- /*
- * Some groups like to know that marks are being freed. This is a
- * callback to the group function to let it know that this entry
- * is being freed.
- */
- if (group->ops->freeing_mark)
- group->ops->freeing_mark(entry, group);
-
- /*
- * __fsnotify_update_child_dentry_flags(inode);
- *
- * I really want to call that, but we can't, we have no idea if the inode
- * still exists the second we drop the entry->lock.
- *
- * The next time an event arrive to this inode from one of it's children
- * __fsnotify_parent will see that the inode doesn't care about it's
- * children and will update all of these flags then. So really this
- * is just a lazy update (and could be a perf win...)
- */
-
-
- iput(inode);
-
- /*
- * it's possible that this group tried to destroy itself, but this
- * this mark was simultaneously being freed by inode. If that's the
- * case, we finish freeing the group here.
- */
- if (unlikely(atomic_dec_and_test(&group->num_marks)))
- fsnotify_final_destroy_group(group);
-}
-
-/*
- * Given a group, destroy all of the marks associated with that group.
- */
-void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
-{
- struct fsnotify_mark_entry *lentry, *entry;
- LIST_HEAD(free_list);
-
- spin_lock(&group->mark_lock);
- list_for_each_entry_safe(entry, lentry, &group->mark_entries, g_list) {
- list_add(&entry->free_g_list, &free_list);
- list_del_init(&entry->g_list);
- fsnotify_get_mark(entry);
- }
- spin_unlock(&group->mark_lock);
-
- list_for_each_entry_safe(entry, lentry, &free_list, free_g_list) {
- fsnotify_destroy_mark_by_entry(entry);
- fsnotify_put_mark(entry);
- }
}
/*
@@ -243,112 +85,127 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
*/
void fsnotify_clear_marks_by_inode(struct inode *inode)
{
- struct fsnotify_mark_entry *entry, *lentry;
+ struct fsnotify_mark *mark, *lmark;
struct hlist_node *pos, *n;
LIST_HEAD(free_list);
spin_lock(&inode->i_lock);
- hlist_for_each_entry_safe(entry, pos, n, &inode->i_fsnotify_mark_entries, i_list) {
- list_add(&entry->free_i_list, &free_list);
- hlist_del_init(&entry->i_list);
- fsnotify_get_mark(entry);
+ hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) {
+ list_add(&mark->i.free_i_list, &free_list);
+ hlist_del_init(&mark->i.i_list);
+ fsnotify_get_mark(mark);
}
spin_unlock(&inode->i_lock);
- list_for_each_entry_safe(entry, lentry, &free_list, free_i_list) {
- fsnotify_destroy_mark_by_entry(entry);
- fsnotify_put_mark(entry);
+ list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) {
+ fsnotify_destroy_mark(mark);
+ fsnotify_put_mark(mark);
}
}
/*
+ * Given a group clear all of the inode marks associated with that group.
+ */
+void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group)
+{
+ fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE);
+}
+
+/*
* given a group and inode, find the mark associated with that combination.
* if found take a reference to that mark and return it, else return NULL
*/
-struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group,
- struct inode *inode)
+struct fsnotify_mark *fsnotify_find_inode_mark_locked(struct fsnotify_group *group,
+ struct inode *inode)
{
- struct fsnotify_mark_entry *entry;
+ struct fsnotify_mark *mark;
struct hlist_node *pos;
assert_spin_locked(&inode->i_lock);
- hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list) {
- if (entry->group == group) {
- fsnotify_get_mark(entry);
- return entry;
+ hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) {
+ if (mark->group == group) {
+ fsnotify_get_mark(mark);
+ return mark;
}
}
return NULL;
}
/*
- * Nothing fancy, just initialize lists and locks and counters.
+ * given a group and inode, find the mark associated with that combination.
+ * if found take a reference to that mark and return it, else return NULL
*/
-void fsnotify_init_mark(struct fsnotify_mark_entry *entry,
- void (*free_mark)(struct fsnotify_mark_entry *entry))
+struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group,
+ struct inode *inode)
+{
+ struct fsnotify_mark *mark;
+ spin_lock(&inode->i_lock);
+ mark = fsnotify_find_inode_mark_locked(group, inode);
+ spin_unlock(&inode->i_lock);
+
+ return mark;
+}
+
+/*
+ * If we are setting a mark mask on an inode mark we should pin the inode
+ * in memory.
+ */
+void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark,
+ __u32 mask)
{
- spin_lock_init(&entry->lock);
- atomic_set(&entry->refcnt, 1);
- INIT_HLIST_NODE(&entry->i_list);
- entry->group = NULL;
- entry->mask = 0;
- entry->inode = NULL;
- entry->free_mark = free_mark;
+ struct inode *inode;
+
+ assert_spin_locked(&mark->lock);
+
+ if (mask &&
+ mark->i.inode &&
+ !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) {
+ mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED;
+ inode = igrab(mark->i.inode);
+ /*
+ * we shouldn't be able to get here if the inode wasn't
+ * already safely held in memory. But bug in case it
+ * ever is wrong.
+ */
+ BUG_ON(!inode);
+ }
}
/*
- * Attach an initialized mark entry to a given group and inode.
+ * Attach an initialized mark to a given group and inode.
* These marks may be used for the fsnotify backend to determine which
* event types should be delivered to which group and for which inodes.
*/
-int fsnotify_add_mark(struct fsnotify_mark_entry *entry,
- struct fsnotify_group *group, struct inode *inode)
+int fsnotify_add_inode_mark(struct fsnotify_mark *mark,
+ struct fsnotify_group *group, struct inode *inode,
+ int allow_dups)
{
- struct fsnotify_mark_entry *lentry;
+ struct fsnotify_mark *lmark = NULL;
int ret = 0;
- inode = igrab(inode);
- if (unlikely(!inode))
- return -EINVAL;
-
- /*
- * LOCKING ORDER!!!!
- * entry->lock
- * group->mark_lock
- * inode->i_lock
- */
- spin_lock(&entry->lock);
- spin_lock(&group->mark_lock);
- spin_lock(&inode->i_lock);
+ mark->flags = FSNOTIFY_MARK_FLAG_INODE;
- lentry = fsnotify_find_mark_entry(group, inode);
- if (!lentry) {
- entry->group = group;
- entry->inode = inode;
+ assert_spin_locked(&mark->lock);
+ assert_spin_locked(&group->mark_lock);
- hlist_add_head(&entry->i_list, &inode->i_fsnotify_mark_entries);
- list_add(&entry->g_list, &group->mark_entries);
+ spin_lock(&inode->i_lock);
- fsnotify_get_mark(entry); /* for i_list and g_list */
+ if (!allow_dups)
+ lmark = fsnotify_find_inode_mark_locked(group, inode);
+ if (!lmark) {
+ mark->i.inode = inode;
- atomic_inc(&group->num_marks);
+ hlist_add_head(&mark->i.i_list, &inode->i_fsnotify_marks);
fsnotify_recalc_inode_mask_locked(inode);
}
spin_unlock(&inode->i_lock);
- spin_unlock(&group->mark_lock);
- spin_unlock(&entry->lock);
- if (lentry) {
+ if (lmark)
ret = -EEXIST;
- iput(inode);
- fsnotify_put_mark(lentry);
- } else {
- __fsnotify_update_child_dentry_flags(inode);
- }
return ret;
}
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig
index b3a159b21cfd..b981fc0c8379 100644
--- a/fs/notify/inotify/Kconfig
+++ b/fs/notify/inotify/Kconfig
@@ -1,18 +1,3 @@
-config INOTIFY
- bool "Inotify file change notification support"
- default n
- ---help---
- Say Y here to enable legacy in kernel inotify support. Inotify is a
- file change notification system. It is a replacement for dnotify.
- This option only provides the legacy inotify in kernel API. There
- are no in tree kernel users of this interface since it is deprecated.
- You only need this if you are loading an out of tree kernel module
- that uses inotify.
-
- For more information, see <file:Documentation/filesystems/inotify.txt>
-
- If unsure, say N.
-
config INOTIFY_USER
bool "Inotify support for userspace"
select ANON_INODES
diff --git a/fs/notify/inotify/Makefile b/fs/notify/inotify/Makefile
index 943828171362..a380dabe09de 100644
--- a/fs/notify/inotify/Makefile
+++ b/fs/notify/inotify/Makefile
@@ -1,2 +1 @@
-obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_INOTIFY_USER) += inotify_fsnotify.o inotify_user.o
diff --git a/fs/notify/inotify/inotify.c b/fs/notify/inotify/inotify.c
deleted file mode 100644
index 27b75ebc7460..000000000000
--- a/fs/notify/inotify/inotify.c
+++ /dev/null
@@ -1,873 +0,0 @@
-/*
- * fs/inotify.c - inode-based file event notifications
- *
- * Authors:
- * John McCutchan <ttb@tentacle.dhs.org>
- * Robert Love <rml@novell.com>
- *
- * Kernel API added by: Amy Griffis <amy.griffis@hp.com>
- *
- * Copyright (C) 2005 John McCutchan
- * Copyright 2006 Hewlett-Packard Development Company, L.P.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/idr.h>
-#include <linux/slab.h>
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/list.h>
-#include <linux/writeback.h>
-#include <linux/inotify.h>
-#include <linux/fsnotify_backend.h>
-
-static atomic_t inotify_cookie;
-
-/*
- * Lock ordering:
- *
- * dentry->d_lock (used to keep d_move() away from dentry->d_parent)
- * iprune_mutex (synchronize shrink_icache_memory())
- * inode_lock (protects the super_block->s_inodes list)
- * inode->inotify_mutex (protects inode->inotify_watches and watches->i_list)
- * inotify_handle->mutex (protects inotify_handle and watches->h_list)
- *
- * The inode->inotify_mutex and inotify_handle->mutex and held during execution
- * of a caller's event handler. Thus, the caller must not hold any locks
- * taken in their event handler while calling any of the published inotify
- * interfaces.
- */
-
-/*
- * Lifetimes of the three main data structures--inotify_handle, inode, and
- * inotify_watch--are managed by reference count.
- *
- * inotify_handle: Lifetime is from inotify_init() to inotify_destroy().
- * Additional references can bump the count via get_inotify_handle() and drop
- * the count via put_inotify_handle().
- *
- * inotify_watch: for inotify's purposes, lifetime is from inotify_add_watch()
- * to remove_watch_no_event(). Additional references can bump the count via
- * get_inotify_watch() and drop the count via put_inotify_watch(). The caller
- * is reponsible for the final put after receiving IN_IGNORED, or when using
- * IN_ONESHOT after receiving the first event. Inotify does the final put if
- * inotify_destroy() is called.
- *
- * inode: Pinned so long as the inode is associated with a watch, from
- * inotify_add_watch() to the final put_inotify_watch().
- */
-
-/*
- * struct inotify_handle - represents an inotify instance
- *
- * This structure is protected by the mutex 'mutex'.
- */
-struct inotify_handle {
- struct idr idr; /* idr mapping wd -> watch */
- struct mutex mutex; /* protects this bad boy */
- struct list_head watches; /* list of watches */
- atomic_t count; /* reference count */
- u32 last_wd; /* the last wd allocated */
- const struct inotify_operations *in_ops; /* inotify caller operations */
-};
-
-static inline void get_inotify_handle(struct inotify_handle *ih)
-{
- atomic_inc(&ih->count);
-}
-
-static inline void put_inotify_handle(struct inotify_handle *ih)
-{
- if (atomic_dec_and_test(&ih->count)) {
- idr_destroy(&ih->idr);
- kfree(ih);
- }
-}
-
-/**
- * get_inotify_watch - grab a reference to an inotify_watch
- * @watch: watch to grab
- */
-void get_inotify_watch(struct inotify_watch *watch)
-{
- atomic_inc(&watch->count);
-}
-EXPORT_SYMBOL_GPL(get_inotify_watch);
-
-int pin_inotify_watch(struct inotify_watch *watch)
-{
- struct super_block *sb = watch->inode->i_sb;
- if (atomic_inc_not_zero(&sb->s_active)) {
- atomic_inc(&watch->count);
- return 1;
- }
- return 0;
-}
-
-/**
- * put_inotify_watch - decrements the ref count on a given watch. cleans up
- * watch references if the count reaches zero. inotify_watch is freed by
- * inotify callers via the destroy_watch() op.
- * @watch: watch to release
- */
-void put_inotify_watch(struct inotify_watch *watch)
-{
- if (atomic_dec_and_test(&watch->count)) {
- struct inotify_handle *ih = watch->ih;
-
- iput(watch->inode);
- ih->in_ops->destroy_watch(watch);
- put_inotify_handle(ih);
- }
-}
-EXPORT_SYMBOL_GPL(put_inotify_watch);
-
-void unpin_inotify_watch(struct inotify_watch *watch)
-{
- struct super_block *sb = watch->inode->i_sb;
- put_inotify_watch(watch);
- deactivate_super(sb);
-}
-
-/*
- * inotify_handle_get_wd - returns the next WD for use by the given handle
- *
- * Callers must hold ih->mutex. This function can sleep.
- */
-static int inotify_handle_get_wd(struct inotify_handle *ih,
- struct inotify_watch *watch)
-{
- int ret;
-
- do {
- if (unlikely(!idr_pre_get(&ih->idr, GFP_NOFS)))
- return -ENOSPC;
- ret = idr_get_new_above(&ih->idr, watch, ih->last_wd+1, &watch->wd);
- } while (ret == -EAGAIN);
-
- if (likely(!ret))
- ih->last_wd = watch->wd;
-
- return ret;
-}
-
-/*
- * inotify_inode_watched - returns nonzero if there are watches on this inode
- * and zero otherwise. We call this lockless, we do not care if we race.
- */
-static inline int inotify_inode_watched(struct inode *inode)
-{
- return !list_empty(&inode->inotify_watches);
-}
-
-/*
- * Get child dentry flag into synch with parent inode.
- * Flag should always be clear for negative dentrys.
- */
-static void set_dentry_child_flags(struct inode *inode, int watched)
-{
- struct dentry *alias;
-
- spin_lock(&dcache_lock);
- list_for_each_entry(alias, &inode->i_dentry, d_alias) {
- struct dentry *child;
-
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
- if (!child->d_inode)
- continue;
-
- spin_lock(&child->d_lock);
- if (watched)
- child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
- else
- child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED;
- spin_unlock(&child->d_lock);
- }
- }
- spin_unlock(&dcache_lock);
-}
-
-/*
- * inotify_find_handle - find the watch associated with the given inode and
- * handle
- *
- * Callers must hold inode->inotify_mutex.
- */
-static struct inotify_watch *inode_find_handle(struct inode *inode,
- struct inotify_handle *ih)
-{
- struct inotify_watch *watch;
-
- list_for_each_entry(watch, &inode->inotify_watches, i_list) {
- if (watch->ih == ih)
- return watch;
- }
-
- return NULL;
-}
-
-/*
- * remove_watch_no_event - remove watch without the IN_IGNORED event.
- *
- * Callers must hold both inode->inotify_mutex and ih->mutex.
- */
-static void remove_watch_no_event(struct inotify_watch *watch,
- struct inotify_handle *ih)
-{
- list_del(&watch->i_list);
- list_del(&watch->h_list);
-
- if (!inotify_inode_watched(watch->inode))
- set_dentry_child_flags(watch->inode, 0);
-
- idr_remove(&ih->idr, watch->wd);
-}
-
-/**
- * inotify_remove_watch_locked - Remove a watch from both the handle and the
- * inode. Sends the IN_IGNORED event signifying that the inode is no longer
- * watched. May be invoked from a caller's event handler.
- * @ih: inotify handle associated with watch
- * @watch: watch to remove
- *
- * Callers must hold both inode->inotify_mutex and ih->mutex.
- */
-void inotify_remove_watch_locked(struct inotify_handle *ih,
- struct inotify_watch *watch)
-{
- remove_watch_no_event(watch, ih);
- ih->in_ops->handle_event(watch, watch->wd, IN_IGNORED, 0, NULL, NULL);
-}
-EXPORT_SYMBOL_GPL(inotify_remove_watch_locked);
-
-/* Kernel API for producing events */
-
-/*
- * inotify_d_instantiate - instantiate dcache entry for inode
- */
-void inotify_d_instantiate(struct dentry *entry, struct inode *inode)
-{
- struct dentry *parent;
-
- if (!inode)
- return;
-
- spin_lock(&entry->d_lock);
- parent = entry->d_parent;
- if (parent->d_inode && inotify_inode_watched(parent->d_inode))
- entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
- spin_unlock(&entry->d_lock);
-}
-
-/*
- * inotify_d_move - dcache entry has been moved
- */
-void inotify_d_move(struct dentry *entry)
-{
- struct dentry *parent;
-
- parent = entry->d_parent;
- if (inotify_inode_watched(parent->d_inode))
- entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED;
- else
- entry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED;
-}
-
-/**
- * inotify_inode_queue_event - queue an event to all watches on this inode
- * @inode: inode event is originating from
- * @mask: event mask describing this event
- * @cookie: cookie for synchronization, or zero
- * @name: filename, if any
- * @n_inode: inode associated with name
- */
-void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie,
- const char *name, struct inode *n_inode)
-{
- struct inotify_watch *watch, *next;
-
- if (!inotify_inode_watched(inode))
- return;
-
- mutex_lock(&inode->inotify_mutex);
- list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
- u32 watch_mask = watch->mask;
- if (watch_mask & mask) {
- struct inotify_handle *ih= watch->ih;
- mutex_lock(&ih->mutex);
- if (watch_mask & IN_ONESHOT)
- remove_watch_no_event(watch, ih);
- ih->in_ops->handle_event(watch, watch->wd, mask, cookie,
- name, n_inode);
- mutex_unlock(&ih->mutex);
- }
- }
- mutex_unlock(&inode->inotify_mutex);
-}
-EXPORT_SYMBOL_GPL(inotify_inode_queue_event);
-
-/**
- * inotify_dentry_parent_queue_event - queue an event to a dentry's parent
- * @dentry: the dentry in question, we queue against this dentry's parent
- * @mask: event mask describing this event
- * @cookie: cookie for synchronization, or zero
- * @name: filename, if any
- */
-void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask,
- u32 cookie, const char *name)
-{
- struct dentry *parent;
- struct inode *inode;
-
- if (!(dentry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED))
- return;
-
- spin_lock(&dentry->d_lock);
- parent = dentry->d_parent;
- inode = parent->d_inode;
-
- if (inotify_inode_watched(inode)) {
- dget(parent);
- spin_unlock(&dentry->d_lock);
- inotify_inode_queue_event(inode, mask, cookie, name,
- dentry->d_inode);
- dput(parent);
- } else
- spin_unlock(&dentry->d_lock);
-}
-EXPORT_SYMBOL_GPL(inotify_dentry_parent_queue_event);
-
-/**
- * inotify_get_cookie - return a unique cookie for use in synchronizing events.
- */
-u32 inotify_get_cookie(void)
-{
- return atomic_inc_return(&inotify_cookie);
-}
-EXPORT_SYMBOL_GPL(inotify_get_cookie);
-
-/**
- * inotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
- * @list: list of inodes being unmounted (sb->s_inodes)
- *
- * Called with inode_lock held, protecting the unmounting super block's list
- * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay.
- * We temporarily drop inode_lock, however, and CAN block.
- */
-void inotify_unmount_inodes(struct list_head *list)
-{
- struct inode *inode, *next_i, *need_iput = NULL;
-
- list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
- struct inotify_watch *watch, *next_w;
- struct inode *need_iput_tmp;
- struct list_head *watches;
-
- /*
- * We cannot __iget() an inode in state I_CLEAR, I_FREEING,
- * I_WILL_FREE, or I_NEW which is fine because by that point
- * the inode cannot have any associated watches.
- */
- if (inode->i_state & (I_CLEAR|I_FREEING|I_WILL_FREE|I_NEW))
- continue;
-
- /*
- * If i_count is zero, the inode cannot have any watches and
- * doing an __iget/iput with MS_ACTIVE clear would actually
- * evict all inodes with zero i_count from icache which is
- * unnecessarily violent and may in fact be illegal to do.
- */
- if (!atomic_read(&inode->i_count))
- continue;
-
- need_iput_tmp = need_iput;
- need_iput = NULL;
- /* In case inotify_remove_watch_locked() drops a reference. */
- if (inode != need_iput_tmp)
- __iget(inode);
- else
- need_iput_tmp = NULL;
- /* In case the dropping of a reference would nuke next_i. */
- if ((&next_i->i_sb_list != list) &&
- atomic_read(&next_i->i_count) &&
- !(next_i->i_state & (I_CLEAR | I_FREEING |
- I_WILL_FREE))) {
- __iget(next_i);
- need_iput = next_i;
- }
-
- /*
- * We can safely drop inode_lock here because we hold
- * references on both inode and next_i. Also no new inodes
- * will be added since the umount has begun. Finally,
- * iprune_mutex keeps shrink_icache_memory() away.
- */
- spin_unlock(&inode_lock);
-
- if (need_iput_tmp)
- iput(need_iput_tmp);
-
- /* for each watch, send IN_UNMOUNT and then remove it */
- mutex_lock(&inode->inotify_mutex);
- watches = &inode->inotify_watches;
- list_for_each_entry_safe(watch, next_w, watches, i_list) {
- struct inotify_handle *ih= watch->ih;
- get_inotify_watch(watch);
- mutex_lock(&ih->mutex);
- ih->in_ops->handle_event(watch, watch->wd, IN_UNMOUNT, 0,
- NULL, NULL);
- inotify_remove_watch_locked(ih, watch);
- mutex_unlock(&ih->mutex);
- put_inotify_watch(watch);
- }
- mutex_unlock(&inode->inotify_mutex);
- iput(inode);
-
- spin_lock(&inode_lock);
- }
-}
-EXPORT_SYMBOL_GPL(inotify_unmount_inodes);
-
-/**
- * inotify_inode_is_dead - an inode has been deleted, cleanup any watches
- * @inode: inode that is about to be removed
- */
-void inotify_inode_is_dead(struct inode *inode)
-{
- struct inotify_watch *watch, *next;
-
- mutex_lock(&inode->inotify_mutex);
- list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
- struct inotify_handle *ih = watch->ih;
- mutex_lock(&ih->mutex);
- inotify_remove_watch_locked(ih, watch);
- mutex_unlock(&ih->mutex);
- }
- mutex_unlock(&inode->inotify_mutex);
-}
-EXPORT_SYMBOL_GPL(inotify_inode_is_dead);
-
-/* Kernel Consumer API */
-
-/**
- * inotify_init - allocate and initialize an inotify instance
- * @ops: caller's inotify operations
- */
-struct inotify_handle *inotify_init(const struct inotify_operations *ops)
-{
- struct inotify_handle *ih;
-
- ih = kmalloc(sizeof(struct inotify_handle), GFP_KERNEL);
- if (unlikely(!ih))
- return ERR_PTR(-ENOMEM);
-
- idr_init(&ih->idr);
- INIT_LIST_HEAD(&ih->watches);
- mutex_init(&ih->mutex);
- ih->last_wd = 0;
- ih->in_ops = ops;
- atomic_set(&ih->count, 0);
- get_inotify_handle(ih);
-
- return ih;
-}
-EXPORT_SYMBOL_GPL(inotify_init);
-
-/**
- * inotify_init_watch - initialize an inotify watch
- * @watch: watch to initialize
- */
-void inotify_init_watch(struct inotify_watch *watch)
-{
- INIT_LIST_HEAD(&watch->h_list);
- INIT_LIST_HEAD(&watch->i_list);
- atomic_set(&watch->count, 0);
- get_inotify_watch(watch); /* initial get */
-}
-EXPORT_SYMBOL_GPL(inotify_init_watch);
-
-/*
- * Watch removals suck violently. To kick the watch out we need (in this
- * order) inode->inotify_mutex and ih->mutex. That's fine if we have
- * a hold on inode; however, for all other cases we need to make damn sure
- * we don't race with umount. We can *NOT* just grab a reference to a
- * watch - inotify_unmount_inodes() will happily sail past it and we'll end
- * with reference to inode potentially outliving its superblock. Ideally
- * we just want to grab an active reference to superblock if we can; that
- * will make sure we won't go into inotify_umount_inodes() until we are
- * done. Cleanup is just deactivate_super(). However, that leaves a messy
- * case - what if we *are* racing with umount() and active references to
- * superblock can't be acquired anymore? We can bump ->s_count, grab
- * ->s_umount, which will wait until the superblock is shut down and the
- * watch in question is pining for fjords.
- *
- * And yes, this is far beyond mere "not very pretty"; so's the entire
- * concept of inotify to start with.
- */
-
-/**
- * pin_to_kill - pin the watch down for removal
- * @ih: inotify handle
- * @watch: watch to kill
- *
- * Called with ih->mutex held, drops it. Possible return values:
- * 0 - nothing to do, it has died
- * 1 - remove it, drop the reference and deactivate_super()
- */
-static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch)
-{
- struct super_block *sb = watch->inode->i_sb;
-
- if (atomic_inc_not_zero(&sb->s_active)) {
- get_inotify_watch(watch);
- mutex_unlock(&ih->mutex);
- return 1; /* the best outcome */
- }
- spin_lock(&sb_lock);
- sb->s_count++;
- spin_unlock(&sb_lock);
- mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */
- down_read(&sb->s_umount);
- /* fs is already shut down; the watch is dead */
- drop_super(sb);
- return 0;
-}
-
-static void unpin_and_kill(struct inotify_watch *watch)
-{
- struct super_block *sb = watch->inode->i_sb;
- put_inotify_watch(watch);
- deactivate_super(sb);
-}
-
-/**
- * inotify_destroy - clean up and destroy an inotify instance
- * @ih: inotify handle
- */
-void inotify_destroy(struct inotify_handle *ih)
-{
- /*
- * Destroy all of the watches for this handle. Unfortunately, not very
- * pretty. We cannot do a simple iteration over the list, because we
- * do not know the inode until we iterate to the watch. But we need to
- * hold inode->inotify_mutex before ih->mutex. The following works.
- *
- * AV: it had to become even uglier to start working ;-/
- */
- while (1) {
- struct inotify_watch *watch;
- struct list_head *watches;
- struct super_block *sb;
- struct inode *inode;
-
- mutex_lock(&ih->mutex);
- watches = &ih->watches;
- if (list_empty(watches)) {
- mutex_unlock(&ih->mutex);
- break;
- }
- watch = list_first_entry(watches, struct inotify_watch, h_list);
- sb = watch->inode->i_sb;
- if (!pin_to_kill(ih, watch))
- continue;
-
- inode = watch->inode;
- mutex_lock(&inode->inotify_mutex);
- mutex_lock(&ih->mutex);
-
- /* make sure we didn't race with another list removal */
- if (likely(idr_find(&ih->idr, watch->wd))) {
- remove_watch_no_event(watch, ih);
- put_inotify_watch(watch);
- }
-
- mutex_unlock(&ih->mutex);
- mutex_unlock(&inode->inotify_mutex);
- unpin_and_kill(watch);
- }
-
- /* free this handle: the put matching the get in inotify_init() */
- put_inotify_handle(ih);
-}
-EXPORT_SYMBOL_GPL(inotify_destroy);
-
-/**
- * inotify_find_watch - find an existing watch for an (ih,inode) pair
- * @ih: inotify handle
- * @inode: inode to watch
- * @watchp: pointer to existing inotify_watch
- *
- * Caller must pin given inode (via nameidata).
- */
-s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode,
- struct inotify_watch **watchp)
-{
- struct inotify_watch *old;
- int ret = -ENOENT;
-
- mutex_lock(&inode->inotify_mutex);
- mutex_lock(&ih->mutex);
-
- old = inode_find_handle(inode, ih);
- if (unlikely(old)) {
- get_inotify_watch(old); /* caller must put watch */
- *watchp = old;
- ret = old->wd;
- }
-
- mutex_unlock(&ih->mutex);
- mutex_unlock(&inode->inotify_mutex);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(inotify_find_watch);
-
-/**
- * inotify_find_update_watch - find and update the mask of an existing watch
- * @ih: inotify handle
- * @inode: inode's watch to update
- * @mask: mask of events to watch
- *
- * Caller must pin given inode (via nameidata).
- */
-s32 inotify_find_update_watch(struct inotify_handle *ih, struct inode *inode,
- u32 mask)
-{
- struct inotify_watch *old;
- int mask_add = 0;
- int ret;
-
- if (mask & IN_MASK_ADD)
- mask_add = 1;
-
- /* don't allow invalid bits: we don't want flags set */
- mask &= IN_ALL_EVENTS | IN_ONESHOT;
- if (unlikely(!mask))
- return -EINVAL;
-
- mutex_lock(&inode->inotify_mutex);
- mutex_lock(&ih->mutex);
-
- /*
- * Handle the case of re-adding a watch on an (inode,ih) pair that we
- * are already watching. We just update the mask and return its wd.
- */
- old = inode_find_handle(inode, ih);
- if (unlikely(!old)) {
- ret = -ENOENT;
- goto out;
- }
-
- if (mask_add)
- old->mask |= mask;
- else
- old->mask = mask;
- ret = old->wd;
-out:
- mutex_unlock(&ih->mutex);
- mutex_unlock(&inode->inotify_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(inotify_find_update_watch);
-
-/**
- * inotify_add_watch - add a watch to an inotify instance
- * @ih: inotify handle
- * @watch: caller allocated watch structure
- * @inode: inode to watch
- * @mask: mask of events to watch
- *
- * Caller must pin given inode (via nameidata).
- * Caller must ensure it only calls inotify_add_watch() once per watch.
- * Calls inotify_handle_get_wd() so may sleep.
- */
-s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch,
- struct inode *inode, u32 mask)
-{
- int ret = 0;
- int newly_watched;
-
- /* don't allow invalid bits: we don't want flags set */
- mask &= IN_ALL_EVENTS | IN_ONESHOT;
- if (unlikely(!mask))
- return -EINVAL;
- watch->mask = mask;
-
- mutex_lock(&inode->inotify_mutex);
- mutex_lock(&ih->mutex);
-
- /* Initialize a new watch */
- ret = inotify_handle_get_wd(ih, watch);
- if (unlikely(ret))
- goto out;
- ret = watch->wd;
-
- /* save a reference to handle and bump the count to make it official */
- get_inotify_handle(ih);
- watch->ih = ih;
-
- /*
- * Save a reference to the inode and bump the ref count to make it
- * official. We hold a reference to nameidata, which makes this safe.
- */
- watch->inode = igrab(inode);
-
- /* Add the watch to the handle's and the inode's list */
- newly_watched = !inotify_inode_watched(inode);
- list_add(&watch->h_list, &ih->watches);
- list_add(&watch->i_list, &inode->inotify_watches);
- /*
- * Set child flags _after_ adding the watch, so there is no race
- * windows where newly instantiated children could miss their parent's
- * watched flag.
- */
- if (newly_watched)
- set_dentry_child_flags(inode, 1);
-
-out:
- mutex_unlock(&ih->mutex);
- mutex_unlock(&inode->inotify_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(inotify_add_watch);
-
-/**
- * inotify_clone_watch - put the watch next to existing one
- * @old: already installed watch
- * @new: new watch
- *
- * Caller must hold the inotify_mutex of inode we are dealing with;
- * it is expected to remove the old watch before unlocking the inode.
- */
-s32 inotify_clone_watch(struct inotify_watch *old, struct inotify_watch *new)
-{
- struct inotify_handle *ih = old->ih;
- int ret = 0;
-
- new->mask = old->mask;
- new->ih = ih;
-
- mutex_lock(&ih->mutex);
-
- /* Initialize a new watch */
- ret = inotify_handle_get_wd(ih, new);
- if (unlikely(ret))
- goto out;
- ret = new->wd;
-
- get_inotify_handle(ih);
-
- new->inode = igrab(old->inode);
-
- list_add(&new->h_list, &ih->watches);
- list_add(&new->i_list, &old->inode->inotify_watches);
-out:
- mutex_unlock(&ih->mutex);
- return ret;
-}
-
-void inotify_evict_watch(struct inotify_watch *watch)
-{
- get_inotify_watch(watch);
- mutex_lock(&watch->ih->mutex);
- inotify_remove_watch_locked(watch->ih, watch);
- mutex_unlock(&watch->ih->mutex);
-}
-
-/**
- * inotify_rm_wd - remove a watch from an inotify instance
- * @ih: inotify handle
- * @wd: watch descriptor to remove
- *
- * Can sleep.
- */
-int inotify_rm_wd(struct inotify_handle *ih, u32 wd)
-{
- struct inotify_watch *watch;
- struct super_block *sb;
- struct inode *inode;
-
- mutex_lock(&ih->mutex);
- watch = idr_find(&ih->idr, wd);
- if (unlikely(!watch)) {
- mutex_unlock(&ih->mutex);
- return -EINVAL;
- }
- sb = watch->inode->i_sb;
- if (!pin_to_kill(ih, watch))
- return 0;
-
- inode = watch->inode;
-
- mutex_lock(&inode->inotify_mutex);
- mutex_lock(&ih->mutex);
-
- /* make sure that we did not race */
- if (likely(idr_find(&ih->idr, wd) == watch))
- inotify_remove_watch_locked(ih, watch);
-
- mutex_unlock(&ih->mutex);
- mutex_unlock(&inode->inotify_mutex);
- unpin_and_kill(watch);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(inotify_rm_wd);
-
-/**
- * inotify_rm_watch - remove a watch from an inotify instance
- * @ih: inotify handle
- * @watch: watch to remove
- *
- * Can sleep.
- */
-int inotify_rm_watch(struct inotify_handle *ih,
- struct inotify_watch *watch)
-{
- return inotify_rm_wd(ih, watch->wd);
-}
-EXPORT_SYMBOL_GPL(inotify_rm_watch);
-
-/*
- * inotify_setup - core initialization function
- */
-static int __init inotify_setup(void)
-{
- BUILD_BUG_ON(IN_ACCESS != FS_ACCESS);
- BUILD_BUG_ON(IN_MODIFY != FS_MODIFY);
- BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB);
- BUILD_BUG_ON(IN_CLOSE_WRITE != FS_CLOSE_WRITE);
- BUILD_BUG_ON(IN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
- BUILD_BUG_ON(IN_OPEN != FS_OPEN);
- BUILD_BUG_ON(IN_MOVED_FROM != FS_MOVED_FROM);
- BUILD_BUG_ON(IN_MOVED_TO != FS_MOVED_TO);
- BUILD_BUG_ON(IN_CREATE != FS_CREATE);
- BUILD_BUG_ON(IN_DELETE != FS_DELETE);
- BUILD_BUG_ON(IN_DELETE_SELF != FS_DELETE_SELF);
- BUILD_BUG_ON(IN_MOVE_SELF != FS_MOVE_SELF);
- BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW);
-
- BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT);
- BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR);
- BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED);
- BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
-
- atomic_set(&inotify_cookie, 0);
-
- return 0;
-}
-
-module_init(inotify_setup);
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h
index f234f3a4c8ca..b6642e4de4bf 100644
--- a/fs/notify/inotify/inotify.h
+++ b/fs/notify/inotify/inotify.h
@@ -9,13 +9,12 @@ struct inotify_event_private_data {
int wd;
};
-struct inotify_inode_mark_entry {
- /* fsnotify_mark_entry MUST be the first thing */
- struct fsnotify_mark_entry fsn_entry;
+struct inotify_inode_mark {
+ struct fsnotify_mark fsn_mark;
int wd;
};
-extern void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
+extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
struct fsnotify_group *group);
extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv);
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c
index e27960cd76ab..daa666a6e6c9 100644
--- a/fs/notify/inotify/inotify_fsnotify.c
+++ b/fs/notify/inotify/inotify_fsnotify.c
@@ -32,10 +32,66 @@
#include "inotify.h"
+/*
+ * Check if 2 events contain the same information. We do not compare private data
+ * but at this moment that isn't a problem for any know fsnotify listeners.
+ */
+static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
+{
+ if ((old->mask == new->mask) &&
+ (old->to_tell == new->to_tell) &&
+ (old->data_type == new->data_type) &&
+ (old->name_len == new->name_len)) {
+ switch (old->data_type) {
+ case (FSNOTIFY_EVENT_INODE):
+ /* remember, after old was put on the wait_q we aren't
+ * allowed to look at the inode any more, only thing
+ * left to check was if the file_name is the same */
+ if (!old->name_len ||
+ !strcmp(old->file_name, new->file_name))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_PATH):
+ if ((old->path.mnt == new->path.mnt) &&
+ (old->path.dentry == new->path.dentry))
+ return true;
+ break;
+ case (FSNOTIFY_EVENT_NONE):
+ if (old->mask & FS_Q_OVERFLOW)
+ return true;
+ else if (old->mask & FS_IN_IGNORED)
+ return false;
+ return true;
+ };
+ }
+ return false;
+}
+
+static int inotify_merge(struct list_head *list,
+ struct fsnotify_event *event,
+ void **arg)
+{
+ struct fsnotify_event_holder *last_holder;
+ struct fsnotify_event *last_event;
+ int ret = 0;
+
+ /* and the list better be locked by something too */
+ spin_lock(&event->lock);
+
+ last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
+ last_event = last_holder->event;
+ if (event_compare(last_event, event))
+ ret = -EEXIST;
+
+ spin_unlock(&event->lock);
+
+ return ret;
+}
+
static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
- struct fsnotify_mark_entry *entry;
- struct inotify_inode_mark_entry *ientry;
+ struct fsnotify_mark *fsn_mark;
+ struct inotify_inode_mark *i_mark;
struct inode *to_tell;
struct inotify_event_private_data *event_priv;
struct fsnotify_event_private_data *fsn_event_priv;
@@ -43,15 +99,13 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
to_tell = event->to_tell;
- spin_lock(&to_tell->i_lock);
- entry = fsnotify_find_mark_entry(group, to_tell);
- spin_unlock(&to_tell->i_lock);
+ fsn_mark = fsnotify_find_inode_mark(group, to_tell);
/* race with watch removal? We already passes should_send */
- if (unlikely(!entry))
+ if (unlikely(!fsn_mark))
return 0;
- ientry = container_of(entry, struct inotify_inode_mark_entry,
- fsn_entry);
- wd = ientry->wd;
+ i_mark = container_of(fsn_mark, struct inotify_inode_mark,
+ fsn_mark);
+ wd = i_mark->wd;
event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL);
if (unlikely(!event_priv))
@@ -62,7 +116,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
fsn_event_priv->group = group;
event_priv->wd = wd;
- ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
+ ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge, NULL);
if (ret) {
inotify_free_event_priv(fsn_event_priv);
/* EEXIST says we tail matched, EOVERFLOW isn't something
@@ -73,35 +127,35 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
}
/*
- * If we hold the entry until after the event is on the queue
+ * If we hold the fsn_mark until after the event is on the queue
* IN_IGNORED won't be able to pass this event in the queue
*/
- fsnotify_put_mark(entry);
+ fsnotify_put_mark(fsn_mark);
return ret;
}
-static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
+static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group)
{
- inotify_ignored_and_remove_idr(entry, group);
+ inotify_ignored_and_remove_idr(fsn_mark, group);
}
-static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
- struct fsnotify_mark_entry *entry;
+ struct fsnotify_mark *fsn_mark;
bool send;
- spin_lock(&inode->i_lock);
- entry = fsnotify_find_mark_entry(group, inode);
- spin_unlock(&inode->i_lock);
- if (!entry)
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
return false;
mask = (mask & ~FS_EVENT_ON_CHILD);
- send = (entry->mask & mask);
+ send = (fsn_mark->mask & mask);
/* find took a reference */
- fsnotify_put_mark(entry);
+ fsnotify_put_mark(fsn_mark);
return send;
}
@@ -115,18 +169,18 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode
*/
static int idr_callback(int id, void *p, void *data)
{
- struct fsnotify_mark_entry *entry;
- struct inotify_inode_mark_entry *ientry;
+ struct fsnotify_mark *fsn_mark;
+ struct inotify_inode_mark *i_mark;
static bool warned = false;
if (warned)
return 0;
warned = true;
- entry = p;
- ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
+ fsn_mark = p;
+ i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
- WARN(1, "inotify closing but id=%d for entry=%p in group=%p still in "
+ WARN(1, "inotify closing but id=%d for fsn_mark=%p in group=%p still in "
"idr. Probably leaking memory\n", id, p, data);
/*
@@ -135,9 +189,9 @@ static int idr_callback(int id, void *p, void *data)
* out why we got here and the panic is no worse than the original
* BUG() that was here.
*/
- if (entry)
- printk(KERN_WARNING "entry->group=%p inode=%p wd=%d\n",
- entry->group, entry->inode, ientry->wd);
+ if (fsn_mark)
+ printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n",
+ fsn_mark->group, fsn_mark->i.inode, i_mark->wd);
return 0;
}
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index e46ca685b9be..44aeb0f1b222 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -46,17 +46,11 @@
/* these are configurable via /proc/sys/fs/inotify/ */
static int inotify_max_user_instances __read_mostly;
static int inotify_max_queued_events __read_mostly;
-int inotify_max_user_watches __read_mostly;
+static int inotify_max_user_watches __read_mostly;
static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
struct kmem_cache *event_priv_cachep __read_mostly;
-/*
- * When inotify registers a new group it increments this and uses that
- * value as an offset to set the fsnotify group "name" and priority.
- */
-static atomic_t inotify_grp_num;
-
#ifdef CONFIG_SYSCTL
#include <linux/sysctl.h>
@@ -357,58 +351,158 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
return error;
}
+static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock,
+ int *last_wd,
+ struct inotify_inode_mark *i_mark)
+{
+ int ret;
+
+ do {
+ if (unlikely(!idr_pre_get(idr, GFP_KERNEL)))
+ return -ENOMEM;
+
+ spin_lock(idr_lock);
+ ret = idr_get_new_above(idr, i_mark, *last_wd + 1,
+ &i_mark->wd);
+ /* we added the mark to the idr, take a reference */
+ if (!ret) {
+ *last_wd = i_mark->wd;
+ fsnotify_get_mark(&i_mark->fsn_mark);
+ }
+ spin_unlock(idr_lock);
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+
+static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group,
+ int wd)
+{
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ struct inotify_inode_mark *i_mark;
+
+ assert_spin_locked(idr_lock);
+
+ i_mark = idr_find(idr, wd);
+ if (i_mark) {
+ struct fsnotify_mark *fsn_mark = &i_mark->fsn_mark;
+
+ fsnotify_get_mark(fsn_mark);
+ /* One ref for being in the idr, one ref we just took */
+ BUG_ON(atomic_read(&fsn_mark->refcnt) < 2);
+ }
+
+ return i_mark;
+}
+
+static struct inotify_inode_mark *inotify_idr_find(struct fsnotify_group *group,
+ int wd)
+{
+ struct inotify_inode_mark *i_mark;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+
+ spin_lock(idr_lock);
+ i_mark = inotify_idr_find_locked(group, wd);
+ spin_unlock(idr_lock);
+
+ return i_mark;
+}
+
+static void do_inotify_remove_from_idr(struct fsnotify_group *group,
+ struct inotify_inode_mark *i_mark)
+{
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ int wd = i_mark->wd;
+
+ assert_spin_locked(idr_lock);
+
+ idr_remove(idr, wd);
+
+ /* removed from the idr, drop that ref */
+ fsnotify_put_mark(&i_mark->fsn_mark);
+}
+
/*
* Remove the mark from the idr (if present) and drop the reference
* on the mark because it was in the idr.
*/
static void inotify_remove_from_idr(struct fsnotify_group *group,
- struct inotify_inode_mark_entry *ientry)
+ struct inotify_inode_mark *i_mark)
{
- struct idr *idr;
- struct fsnotify_mark_entry *entry;
- struct inotify_inode_mark_entry *found_ientry;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
+ struct inotify_inode_mark *found_i_mark = NULL;
int wd;
- spin_lock(&group->inotify_data.idr_lock);
- idr = &group->inotify_data.idr;
- wd = ientry->wd;
+ spin_lock(idr_lock);
+ wd = i_mark->wd;
- if (wd == -1)
+ /*
+ * does this i_mark think it is in the idr? we shouldn't get called
+ * if it wasn't....
+ */
+ if (wd == -1) {
+ WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
+ " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
+ i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode);
goto out;
+ }
- entry = idr_find(&group->inotify_data.idr, wd);
- if (unlikely(!entry))
+ /* Lets look in the idr to see if we find it */
+ found_i_mark = inotify_idr_find_locked(group, wd);
+ if (unlikely(!found_i_mark)) {
+ WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
+ " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
+ i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode);
goto out;
+ }
- found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
- if (unlikely(found_ientry != ientry)) {
- /* We found an entry in the idr with the right wd, but it's
- * not the entry we were told to remove. eparis seriously
- * fucked up somewhere. */
- WARN_ON(1);
- ientry->wd = -1;
+ /*
+ * We found an mark in the idr at the right wd, but it's
+ * not the mark we were told to remove. eparis seriously
+ * fucked up somewhere.
+ */
+ if (unlikely(found_i_mark != i_mark)) {
+ WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p "
+ "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d "
+ "found_i_mark->group=%p found_i_mark->inode=%p\n",
+ __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group,
+ i_mark->fsn_mark.i.inode, found_i_mark, found_i_mark->wd,
+ found_i_mark->fsn_mark.group,
+ found_i_mark->fsn_mark.i.inode);
goto out;
}
- /* One ref for being in the idr, one ref held by the caller */
- BUG_ON(atomic_read(&entry->refcnt) < 2);
-
- idr_remove(idr, wd);
- ientry->wd = -1;
+ /*
+ * One ref for being in the idr
+ * one ref held by the caller trying to kill us
+ * one ref grabbed by inotify_idr_find
+ */
+ if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) {
+ printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p"
+ " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd,
+ i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode);
+ /* we can't really recover with bad ref cnting.. */
+ BUG();
+ }
- /* removed from the idr, drop that ref */
- fsnotify_put_mark(entry);
+ do_inotify_remove_from_idr(group, i_mark);
out:
- spin_unlock(&group->inotify_data.idr_lock);
+ /* match the ref taken by inotify_idr_find_locked() */
+ if (found_i_mark)
+ fsnotify_put_mark(&found_i_mark->fsn_mark);
+ i_mark->wd = -1;
+ spin_unlock(idr_lock);
}
/*
* Send IN_IGNORED for this wd, remove this wd from the idr.
*/
-void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
+void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
struct fsnotify_group *group)
{
- struct inotify_inode_mark_entry *ientry;
+ struct inotify_inode_mark *i_mark;
struct fsnotify_event *ignored_event;
struct inotify_event_private_data *event_priv;
struct fsnotify_event_private_data *fsn_event_priv;
@@ -420,7 +514,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
if (!ignored_event)
return;
- ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
+ i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS);
if (unlikely(!event_priv))
@@ -429,9 +523,9 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
fsn_event_priv = &event_priv->fsnotify_event_priv_data;
fsn_event_priv->group = group;
- event_priv->wd = ientry->wd;
+ event_priv->wd = i_mark->wd;
- ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
+ ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL, NULL);
if (ret)
inotify_free_event_priv(fsn_event_priv);
@@ -440,26 +534,28 @@ skip_send_ignore:
/* matches the reference taken when the event was created */
fsnotify_put_event(ignored_event);
- /* remove this entry from the idr */
- inotify_remove_from_idr(group, ientry);
+ /* remove this mark from the idr */
+ inotify_remove_from_idr(group, i_mark);
atomic_dec(&group->inotify_data.user->inotify_watches);
}
/* ding dong the mark is dead */
-static void inotify_free_mark(struct fsnotify_mark_entry *entry)
+static void inotify_free_mark(struct fsnotify_mark *fsn_mark)
{
- struct inotify_inode_mark_entry *ientry = (struct inotify_inode_mark_entry *)entry;
+ struct inotify_inode_mark *i_mark;
+
+ i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
- kmem_cache_free(inotify_inode_mark_cachep, ientry);
+ kmem_cache_free(inotify_inode_mark_cachep, i_mark);
}
static int inotify_update_existing_watch(struct fsnotify_group *group,
struct inode *inode,
u32 arg)
{
- struct fsnotify_mark_entry *entry;
- struct inotify_inode_mark_entry *ientry;
+ struct fsnotify_mark *fsn_mark;
+ struct inotify_inode_mark *i_mark;
__u32 old_mask, new_mask;
__u32 mask;
int add = (arg & IN_MASK_ADD);
@@ -470,36 +566,32 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
if (unlikely(!mask))
return -EINVAL;
- spin_lock(&inode->i_lock);
- entry = fsnotify_find_mark_entry(group, inode);
- spin_unlock(&inode->i_lock);
- if (!entry)
+ fsn_mark = fsnotify_find_inode_mark(group, inode);
+ if (!fsn_mark)
return -ENOENT;
- ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
+ i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
- spin_lock(&entry->lock);
+ spin_lock(&fsn_mark->lock);
- old_mask = entry->mask;
- if (add) {
- entry->mask |= mask;
- new_mask = entry->mask;
- } else {
- entry->mask = mask;
- new_mask = entry->mask;
- }
+ old_mask = fsn_mark->mask;
+ if (add)
+ fsnotify_set_mark_mask_locked(fsn_mark, (fsn_mark->mask | mask));
+ else
+ fsnotify_set_mark_mask_locked(fsn_mark, mask);
+ new_mask = fsn_mark->mask;
- spin_unlock(&entry->lock);
+ spin_unlock(&fsn_mark->lock);
if (old_mask != new_mask) {
/* more bits in old than in new? */
int dropped = (old_mask & ~new_mask);
- /* more bits in this entry than the inode's mask? */
+ /* more bits in this fsn_mark than the inode's mask? */
int do_inode = (new_mask & ~inode->i_fsnotify_mask);
- /* more bits in this entry than the group? */
+ /* more bits in this fsn_mark than the group? */
int do_group = (new_mask & ~group->mask);
- /* update the inode with this new entry */
+ /* update the inode with this new fsn_mark */
if (dropped || do_inode)
fsnotify_recalc_inode_mask(inode);
@@ -509,10 +601,10 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
}
/* return the wd */
- ret = ientry->wd;
+ ret = i_mark->wd;
- /* match the get from fsnotify_find_mark_entry() */
- fsnotify_put_mark(entry);
+ /* match the get from fsnotify_find_mark() */
+ fsnotify_put_mark(fsn_mark);
return ret;
}
@@ -521,73 +613,55 @@ static int inotify_new_watch(struct fsnotify_group *group,
struct inode *inode,
u32 arg)
{
- struct inotify_inode_mark_entry *tmp_ientry;
+ struct inotify_inode_mark *tmp_i_mark;
__u32 mask;
int ret;
+ struct idr *idr = &group->inotify_data.idr;
+ spinlock_t *idr_lock = &group->inotify_data.idr_lock;
/* don't allow invalid bits: we don't want flags set */
mask = inotify_arg_to_mask(arg);
if (unlikely(!mask))
return -EINVAL;
- tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
- if (unlikely(!tmp_ientry))
+ tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
+ if (unlikely(!tmp_i_mark))
return -ENOMEM;
- fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
- tmp_ientry->fsn_entry.mask = mask;
- tmp_ientry->wd = -1;
+ fsnotify_init_mark(&tmp_i_mark->fsn_mark, inotify_free_mark);
+ tmp_i_mark->fsn_mark.mask = mask;
+ tmp_i_mark->wd = -1;
ret = -ENOSPC;
if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
goto out_err;
-retry:
- ret = -ENOMEM;
- if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
- goto out_err;
-
- /* we are putting the mark on the idr, take a reference */
- fsnotify_get_mark(&tmp_ientry->fsn_entry);
-
- spin_lock(&group->inotify_data.idr_lock);
- ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
- group->inotify_data.last_wd+1,
- &tmp_ientry->wd);
- spin_unlock(&group->inotify_data.idr_lock);
- if (ret) {
- /* we didn't get on the idr, drop the idr reference */
- fsnotify_put_mark(&tmp_ientry->fsn_entry);
- /* idr was out of memory allocate and try again */
- if (ret == -EAGAIN)
- goto retry;
+ ret = inotify_add_to_idr(idr, idr_lock, &group->inotify_data.last_wd,
+ tmp_i_mark);
+ if (ret)
goto out_err;
- }
/* we are on the idr, now get on the inode */
- ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
+ ret = fsnotify_add_mark(&tmp_i_mark->fsn_mark, group, inode, NULL, 0);
if (ret) {
/* we failed to get on the inode, get off the idr */
- inotify_remove_from_idr(group, tmp_ientry);
+ inotify_remove_from_idr(group, tmp_i_mark);
goto out_err;
}
- /* update the idr hint, who cares about races, it's just a hint */
- group->inotify_data.last_wd = tmp_ientry->wd;
-
/* increment the number of watches the user has */
atomic_inc(&group->inotify_data.user->inotify_watches);
- /* return the watch descriptor for this new entry */
- ret = tmp_ientry->wd;
+ /* return the watch descriptor for this new mark */
+ ret = tmp_i_mark->wd;
/* if this mark added a new event update the group mask */
if (mask & ~group->mask)
fsnotify_recalc_group_mask(group);
out_err:
- /* match the ref from fsnotify_init_markentry() */
- fsnotify_put_mark(&tmp_ientry->fsn_entry);
+ /* match the ref from fsnotify_init_mark() */
+ fsnotify_put_mark(&tmp_i_mark->fsn_mark);
return ret;
}
@@ -616,11 +690,8 @@ retry:
static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsigned int max_events)
{
struct fsnotify_group *group;
- unsigned int grp_num;
- /* fsnotify_obtain_group took a reference to group, we put this when we kill the file in the end */
- grp_num = (INOTIFY_GROUP_NUM - atomic_inc_return(&inotify_grp_num));
- group = fsnotify_obtain_group(grp_num, 0, &inotify_fsnotify_ops);
+ group = fsnotify_alloc_group(&inotify_fsnotify_ops);
if (IS_ERR(group))
return group;
@@ -726,7 +797,7 @@ fput_and_out:
SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
{
struct fsnotify_group *group;
- struct fsnotify_mark_entry *entry;
+ struct inotify_inode_mark *i_mark;
struct file *filp;
int ret = 0, fput_needed;
@@ -735,25 +806,23 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd)
return -EBADF;
/* verify that this is indeed an inotify instance */
- if (unlikely(filp->f_op != &inotify_fops)) {
- ret = -EINVAL;
+ ret = -EINVAL;
+ if (unlikely(filp->f_op != &inotify_fops))
goto out;
- }
group = filp->private_data;
- spin_lock(&group->inotify_data.idr_lock);
- entry = idr_find(&group->inotify_data.idr, wd);
- if (unlikely(!entry)) {
- spin_unlock(&group->inotify_data.idr_lock);
- ret = -EINVAL;
+ ret = -EINVAL;
+ i_mark = inotify_idr_find(group, wd);
+ if (unlikely(!i_mark))
goto out;
- }
- fsnotify_get_mark(entry);
- spin_unlock(&group->inotify_data.idr_lock);
- fsnotify_destroy_mark_by_entry(entry);
- fsnotify_put_mark(entry);
+ ret = 0;
+
+ fsnotify_destroy_mark(&i_mark->fsn_mark);
+
+ /* match ref taken by inotify_idr_find */
+ fsnotify_put_mark(&i_mark->fsn_mark);
out:
fput_light(filp, fput_needed);
@@ -767,7 +836,7 @@ out:
*/
static int __init inotify_user_setup(void)
{
- inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC);
+ inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);
inotify_max_queued_events = 16384;
diff --git a/fs/notify/mark.c b/fs/notify/mark.c
new file mode 100644
index 000000000000..8f3b0e7a543d
--- /dev/null
+++ b/fs/notify/mark.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * fsnotify inode mark locking/lifetime/and refcnting
+ *
+ * REFCNT:
+ * The mark->refcnt tells how many "things" in the kernel currently are
+ * referencing this object. The object typically will live inside the kernel
+ * with a refcnt of 2, one for each list it is on (i_list, g_list). Any task
+ * which can find this object holding the appropriete locks, can take a reference
+ * and the object itself is guarenteed to survive until the reference is dropped.
+ *
+ * LOCKING:
+ * There are 3 spinlocks involved with fsnotify inode marks and they MUST
+ * be taken in order as follows:
+ *
+ * mark->lock
+ * group->mark_lock
+ * inode->i_lock
+ *
+ * mark->lock protects 2 things, mark->group and mark->inode. You must hold
+ * that lock to dereference either of these things (they could be NULL even with
+ * the lock)
+ *
+ * group->mark_lock protects the marks_list anchored inside a given group
+ * and each mark is hooked via the g_list. It also sorta protects the
+ * free_g_list, which when used is anchored by a private list on the stack of the
+ * task which held the group->mark_lock.
+ *
+ * inode->i_lock protects the i_fsnotify_marks list anchored inside a
+ * given inode and each mark is hooked via the i_list. (and sorta the
+ * free_i_list)
+ *
+ *
+ * LIFETIME:
+ * Inode marks survive between when they are added to an inode and when their
+ * refcnt==0.
+ *
+ * The inode mark can be cleared for a number of different reasons including:
+ * - The inode is unlinked for the last time. (fsnotify_inode_remove)
+ * - The inode is being evicted from cache. (fsnotify_inode_delete)
+ * - The fs the inode is on is unmounted. (fsnotify_inode_delete/fsnotify_unmount_inodes)
+ * - Something explicitly requests that it be removed. (fsnotify_destroy_mark)
+ * - The fsnotify_group associated with the mark is going away and all such marks
+ * need to be cleaned up. (fsnotify_clear_marks_by_group)
+ *
+ * Worst case we are given an inode and need to clean up all the marks on that
+ * inode. We take i_lock and walk the i_fsnotify_marks safely. For each
+ * mark on the list we take a reference (so the mark can't disappear under us).
+ * We remove that mark form the inode's list of marks and we add this mark to a
+ * private list anchored on the stack using i_free_list; At this point we no
+ * longer fear anything finding the mark using the inode's list of marks.
+ *
+ * We can safely and locklessly run the private list on the stack of everything
+ * we just unattached from the original inode. For each mark on the private list
+ * we grab the mark-> and can thus dereference mark->group and mark->inode. If
+ * we see the group and inode are not NULL we take those locks. Now holding all
+ * 3 locks we can completely remove the mark from other tasks finding it in the
+ * future. Remember, 10 things might already be referencing this mark, but they
+ * better be holding a ref. We drop our reference we took before we unhooked it
+ * from the inode. When the ref hits 0 we can free the mark.
+ *
+ * Very similarly for freeing by group, except we use free_g_list.
+ *
+ * This has the very interesting property of being able to run concurrently with
+ * any (or all) other directions.
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/writeback.h> /* for inode_lock */
+
+#include <asm/atomic.h>
+
+#include <linux/fsnotify_backend.h>
+#include "fsnotify.h"
+
+void fsnotify_get_mark(struct fsnotify_mark *mark)
+{
+ atomic_inc(&mark->refcnt);
+}
+
+void fsnotify_put_mark(struct fsnotify_mark *mark)
+{
+ if (atomic_dec_and_test(&mark->refcnt))
+ mark->free_mark(mark);
+}
+
+/*
+ * Any time a mark is getting freed we end up here.
+ * The caller had better be holding a reference to this mark so we don't actually
+ * do the final put under the mark->lock
+ */
+void fsnotify_destroy_mark(struct fsnotify_mark *mark)
+{
+ struct fsnotify_group *group;
+ struct inode *inode = NULL;
+
+ spin_lock(&mark->lock);
+
+ group = mark->group;
+
+ /* if !group something else already marked this to die */
+ if (!group) {
+ spin_unlock(&mark->lock);
+ return;
+ }
+
+ /* 1 from caller and 1 for being on i_list/g_list */
+ BUG_ON(atomic_read(&mark->refcnt) < 2);
+
+ spin_lock(&group->mark_lock);
+
+ if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
+ inode = mark->i.inode;
+ fsnotify_destroy_inode_mark(mark);
+ } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT)
+ fsnotify_destroy_vfsmount_mark(mark);
+ else
+ BUG();
+
+ list_del_init(&mark->g_list);
+ mark->group = NULL;
+
+ fsnotify_put_mark(mark); /* for i_list and g_list */
+
+ spin_unlock(&group->mark_lock);
+ spin_unlock(&mark->lock);
+
+ /*
+ * Some groups like to know that marks are being freed. This is a
+ * callback to the group function to let it know that this mark
+ * is being freed.
+ */
+ if (group->ops->freeing_mark)
+ group->ops->freeing_mark(mark, group);
+
+ /*
+ * __fsnotify_update_child_dentry_flags(inode);
+ *
+ * I really want to call that, but we can't, we have no idea if the inode
+ * still exists the second we drop the mark->lock.
+ *
+ * The next time an event arrive to this inode from one of it's children
+ * __fsnotify_parent will see that the inode doesn't care about it's
+ * children and will update all of these flags then. So really this
+ * is just a lazy update (and could be a perf win...)
+ */
+
+ if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
+ iput(inode);
+
+ /*
+ * it's possible that this group tried to destroy itself, but this
+ * this mark was simultaneously being freed by inode. If that's the
+ * case, we finish freeing the group here.
+ */
+ if (unlikely(atomic_dec_and_test(&group->num_marks)))
+ fsnotify_final_destroy_group(group);
+}
+
+void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
+{
+ assert_spin_locked(&mark->lock);
+
+ mark->mask = mask;
+
+ if (mark->flags & FSNOTIFY_MARK_FLAG_INODE)
+ fsnotify_set_inode_mark_mask_locked(mark, mask);
+}
+
+void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask)
+{
+ assert_spin_locked(&mark->lock);
+
+ mark->ignored_mask = mask;
+}
+
+/*
+ * Attach an initialized mark to a given group and fs object.
+ * These marks may be used for the fsnotify backend to determine which
+ * event types should be delivered to which group.
+ */
+int fsnotify_add_mark(struct fsnotify_mark *mark,
+ struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, int allow_dups)
+{
+ int ret = 0;
+
+ BUG_ON(inode && mnt);
+ BUG_ON(!inode && !mnt);
+
+ /*
+ * if this group isn't being testing for inode type events we need
+ * to start testing
+ */
+ if (inode && unlikely(list_empty(&group->inode_group_list)))
+ fsnotify_add_inode_group(group);
+ else if (mnt && unlikely(list_empty(&group->vfsmount_group_list)))
+ fsnotify_add_vfsmount_group(group);
+
+ /*
+ * LOCKING ORDER!!!!
+ * mark->lock
+ * group->mark_lock
+ * inode->i_lock
+ */
+ spin_lock(&mark->lock);
+ spin_lock(&group->mark_lock);
+
+ mark->group = group;
+ list_add(&mark->g_list, &group->marks_list);
+ atomic_inc(&group->num_marks);
+ fsnotify_get_mark(mark); /* for i_list and g_list */
+
+ if (inode) {
+ ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups);
+ if (ret)
+ goto err;
+ } else if (mnt) {
+ ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups);
+ if (ret)
+ goto err;
+ } else {
+ BUG();
+ }
+
+ spin_unlock(&group->mark_lock);
+
+ /* this will pin the object if appropriate */
+ fsnotify_set_mark_mask_locked(mark, mark->mask);
+
+ spin_unlock(&mark->lock);
+
+ if (inode)
+ __fsnotify_update_child_dentry_flags(inode);
+
+ return ret;
+err:
+ mark->group = NULL;
+ list_del_init(&mark->g_list);
+ atomic_dec(&group->num_marks);
+ fsnotify_put_mark(mark);
+
+ spin_unlock(&group->mark_lock);
+ spin_unlock(&mark->lock);
+
+ return ret;
+}
+
+/*
+ * clear any marks in a group in which mark->flags & flags is true
+ */
+void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group,
+ unsigned int flags)
+{
+ struct fsnotify_mark *lmark, *mark;
+ LIST_HEAD(free_list);
+
+ spin_lock(&group->mark_lock);
+ list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) {
+ if (mark->flags & flags) {
+ list_add(&mark->free_g_list, &free_list);
+ list_del_init(&mark->g_list);
+ fsnotify_get_mark(mark);
+ }
+ }
+ spin_unlock(&group->mark_lock);
+
+ list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) {
+ fsnotify_destroy_mark(mark);
+ fsnotify_put_mark(mark);
+ }
+}
+
+/*
+ * Given a group, destroy all of the marks associated with that group.
+ */
+void fsnotify_clear_marks_by_group(struct fsnotify_group *group)
+{
+ fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1);
+}
+
+void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old)
+{
+ assert_spin_locked(&old->lock);
+ new->i.inode = old->i.inode;
+ new->m.mnt = old->m.mnt;
+ new->group = old->group;
+ new->mask = old->mask;
+ new->free_mark = old->free_mark;
+}
+
+/*
+ * Nothing fancy, just initialize lists and locks and counters.
+ */
+void fsnotify_init_mark(struct fsnotify_mark *mark,
+ void (*free_mark)(struct fsnotify_mark *mark))
+{
+ memset(mark, 0, sizeof(*mark));
+ spin_lock_init(&mark->lock);
+ atomic_set(&mark->refcnt, 1);
+ mark->free_mark = free_mark;
+}
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index b8bf53b4c108..b35faafacd38 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -56,7 +56,7 @@ static struct kmem_cache *fsnotify_event_holder_cachep;
* it is needed. It's refcnt is set 1 at kernel init time and will never
* get set to 0 so it will never get 'freed'
*/
-static struct fsnotify_event q_overflow_event;
+static struct fsnotify_event *q_overflow_event;
static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
/**
@@ -93,6 +93,7 @@ void fsnotify_put_event(struct fsnotify_event *event)
BUG_ON(!list_empty(&event->private_data_list));
kfree(event->file_name);
+ put_pid(event->tgid);
kmem_cache_free(fsnotify_event_cachep, event);
}
}
@@ -104,7 +105,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)
void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
{
- kmem_cache_free(fsnotify_event_holder_cachep, holder);
+ if (holder)
+ kmem_cache_free(fsnotify_event_holder_cachep, holder);
}
/*
@@ -129,53 +131,20 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
}
/*
- * Check if 2 events contain the same information. We do not compare private data
- * but at this moment that isn't a problem for any know fsnotify listeners.
- */
-static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
-{
- if ((old->mask == new->mask) &&
- (old->to_tell == new->to_tell) &&
- (old->data_type == new->data_type) &&
- (old->name_len == new->name_len)) {
- switch (old->data_type) {
- case (FSNOTIFY_EVENT_INODE):
- /* remember, after old was put on the wait_q we aren't
- * allowed to look at the inode any more, only thing
- * left to check was if the file_name is the same */
- if (!old->name_len ||
- !strcmp(old->file_name, new->file_name))
- return true;
- break;
- case (FSNOTIFY_EVENT_PATH):
- if ((old->path.mnt == new->path.mnt) &&
- (old->path.dentry == new->path.dentry))
- return true;
- break;
- case (FSNOTIFY_EVENT_NONE):
- if (old->mask & FS_Q_OVERFLOW)
- return true;
- else if (old->mask & FS_IN_IGNORED)
- return false;
- return false;
- };
- }
- return false;
-}
-
-/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. If the event is successfully added to the
* group's notification queue, a reference is taken on event.
*/
int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv)
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *,
+ struct fsnotify_event *,
+ void **arg),
+ void **arg)
{
struct fsnotify_event_holder *holder = NULL;
struct list_head *list = &group->notification_list;
- struct fsnotify_event_holder *last_holder;
- struct fsnotify_event *last_event;
- int ret = 0;
+ int rc = 0;
/*
* There is one fsnotify_event_holder embedded inside each fsnotify_event.
@@ -195,12 +164,24 @@ alloc_holder:
mutex_lock(&group->notification_mutex);
if (group->q_len >= group->max_events) {
- event = &q_overflow_event;
- ret = -EOVERFLOW;
+ event = q_overflow_event;
+ rc = -EOVERFLOW;
/* sorry, no private data on the overflow event */
priv = NULL;
}
+ if (!list_empty(list) && merge) {
+ int ret;
+
+ ret = merge(list, event, arg);
+ if (ret) {
+ mutex_unlock(&group->notification_mutex);
+ if (holder != &event->holder)
+ fsnotify_destroy_event_holder(holder);
+ return ret;
+ }
+ }
+
spin_lock(&event->lock);
if (list_empty(&event->holder.event_list)) {
@@ -215,18 +196,6 @@ alloc_holder:
goto alloc_holder;
}
- if (!list_empty(list)) {
- last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
- last_event = last_holder->event;
- if (event_compare(last_event, event)) {
- spin_unlock(&event->lock);
- mutex_unlock(&group->notification_mutex);
- if (holder != &event->holder)
- fsnotify_destroy_event_holder(holder);
- return -EEXIST;
- }
- }
-
group->q_len++;
holder->event = event;
@@ -238,7 +207,7 @@ alloc_holder:
mutex_unlock(&group->notification_mutex);
wake_up(&group->notification_waitq);
- return ret;
+ return rc;
}
/*
@@ -314,25 +283,78 @@ void fsnotify_flush_notify(struct fsnotify_group *group)
static void initialize_event(struct fsnotify_event *event)
{
- event->holder.event = NULL;
INIT_LIST_HEAD(&event->holder.event_list);
atomic_set(&event->refcnt, 1);
spin_lock_init(&event->lock);
- event->path.dentry = NULL;
- event->path.mnt = NULL;
- event->inode = NULL;
- event->data_type = FSNOTIFY_EVENT_NONE;
-
INIT_LIST_HEAD(&event->private_data_list);
+}
+
+/*
+ * Caller damn well better be holding whatever mutex is protecting the
+ * old_holder->event_list and the new_event must be a clean event which
+ * cannot be found anywhere else in the kernel.
+ */
+int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event)
+{
+ struct fsnotify_event *old_event = old_holder->event;
+ struct fsnotify_event_holder *new_holder = &new_event->holder;
+
+ enum event_spinlock_class {
+ SPINLOCK_OLD,
+ SPINLOCK_NEW,
+ };
+
+ /*
+ * if the new_event's embedded holder is in use someone
+ * screwed up and didn't give us a clean new event.
+ */
+ BUG_ON(!list_empty(&new_holder->event_list));
+
+ spin_lock_nested(&old_event->lock, SPINLOCK_OLD);
+ spin_lock_nested(&new_event->lock, SPINLOCK_NEW);
+
+ new_holder->event = new_event;
+ list_replace_init(&old_holder->event_list, &new_holder->event_list);
+
+ spin_unlock(&new_event->lock);
+ spin_unlock(&old_event->lock);
+
+ /* event == holder means we are referenced through the in event holder */
+ if (old_holder != &old_event->holder)
+ fsnotify_destroy_event_holder(old_holder);
+
+ fsnotify_get_event(new_event); /* on the list take reference */
+ fsnotify_put_event(old_event); /* off the list, drop reference */
+
+ return 0;
+}
+
+struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
+{
+ struct fsnotify_event *event;
+
+ event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+ if (!event)
+ return NULL;
- event->to_tell = NULL;
+ memcpy(event, old_event, sizeof(*event));
+ initialize_event(event);
- event->file_name = NULL;
- event->name_len = 0;
+ if (event->name_len) {
+ event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
+ if (!event->file_name) {
+ kmem_cache_free(fsnotify_event_cachep, event);
+ return NULL;
+ }
+ }
+ event->tgid = get_pid(old_event->tgid);
+ if (event->data_type == FSNOTIFY_EVENT_PATH)
+ path_get(&event->path);
- event->sync_cookie = 0;
+ return event;
}
/*
@@ -348,12 +370,12 @@ static void initialize_event(struct fsnotify_event *event)
* @name the filename, if available
*/
struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
- int data_type, const char *name, u32 cookie,
- gfp_t gfp)
+ int data_type, const unsigned char *name,
+ u32 cookie, gfp_t gfp)
{
struct fsnotify_event *event;
- event = kmem_cache_alloc(fsnotify_event_cachep, gfp);
+ event = kmem_cache_zalloc(fsnotify_event_cachep, gfp);
if (!event)
return NULL;
@@ -368,30 +390,21 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
event->name_len = strlen(event->file_name);
}
+ event->tgid = get_pid(task_tgid(current));
event->sync_cookie = cookie;
event->to_tell = to_tell;
+ event->data_type = data_type;
switch (data_type) {
- case FSNOTIFY_EVENT_FILE: {
- struct file *file = data;
- struct path *path = &file->f_path;
- event->path.dentry = path->dentry;
- event->path.mnt = path->mnt;
- path_get(&event->path);
- event->data_type = FSNOTIFY_EVENT_PATH;
- break;
- }
case FSNOTIFY_EVENT_PATH: {
struct path *path = data;
event->path.dentry = path->dentry;
event->path.mnt = path->mnt;
path_get(&event->path);
- event->data_type = FSNOTIFY_EVENT_PATH;
break;
}
case FSNOTIFY_EVENT_INODE:
event->inode = data;
- event->data_type = FSNOTIFY_EVENT_INODE;
break;
case FSNOTIFY_EVENT_NONE:
event->inode = NULL;
@@ -412,8 +425,11 @@ __init int fsnotify_notification_init(void)
fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC);
fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC);
- initialize_event(&q_overflow_event);
- q_overflow_event.mask = FS_Q_OVERFLOW;
+ q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL,
+ FSNOTIFY_EVENT_NONE, NULL, 0,
+ GFP_KERNEL);
+ if (!q_overflow_event)
+ panic("unable to allocate fsnotify q_overflow_event\n");
return 0;
}
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c
new file mode 100644
index 000000000000..ec580a25d293
--- /dev/null
+++ b/fs/notify/vfsmount_mark.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mount.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/writeback.h> /* for inode_lock */
+
+#include <asm/atomic.h>
+
+#include <linux/fsnotify_backend.h>
+#include "fsnotify.h"
+
+void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
+{
+ struct fsnotify_mark *mark, *lmark;
+ struct hlist_node *pos, *n;
+ LIST_HEAD(free_list);
+
+ spin_lock(&mnt->mnt_root->d_lock);
+ hlist_for_each_entry_safe(mark, pos, n, &mnt->mnt_fsnotify_marks, m.m_list) {
+ list_add(&mark->m.free_m_list, &free_list);
+ hlist_del_init(&mark->m.m_list);
+ fsnotify_get_mark(mark);
+ }
+ spin_unlock(&mnt->mnt_root->d_lock);
+
+ list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) {
+ fsnotify_destroy_mark(mark);
+ fsnotify_put_mark(mark);
+ }
+}
+
+void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
+{
+ fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_VFSMOUNT);
+}
+
+/*
+ * Recalculate the mask of events relevant to a given vfsmount locked.
+ */
+static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt)
+{
+ struct fsnotify_mark *mark;
+ struct hlist_node *pos;
+ __u32 new_mask = 0;
+
+ assert_spin_locked(&mnt->mnt_root->d_lock);
+
+ hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list)
+ new_mask |= mark->mask;
+ mnt->mnt_fsnotify_mask = new_mask;
+}
+
+/*
+ * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types
+ * any notifier is interested in hearing for this mount point
+ */
+void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt)
+{
+ spin_lock(&mnt->mnt_root->d_lock);
+ fsnotify_recalc_vfsmount_mask_locked(mnt);
+ spin_unlock(&mnt->mnt_root->d_lock);
+}
+
+void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark)
+{
+ struct vfsmount *mnt = mark->m.mnt;
+
+ assert_spin_locked(&mark->lock);
+ assert_spin_locked(&mark->group->mark_lock);
+
+ spin_lock(&mnt->mnt_root->d_lock);
+
+ hlist_del_init(&mark->m.m_list);
+ mark->m.mnt = NULL;
+
+ fsnotify_recalc_vfsmount_mask_locked(mnt);
+
+ spin_unlock(&mnt->mnt_root->d_lock);
+}
+
+static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group,
+ struct vfsmount *mnt)
+{
+ struct fsnotify_mark *mark;
+ struct hlist_node *pos;
+
+ assert_spin_locked(&mnt->mnt_root->d_lock);
+
+ hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) {
+ if (mark->group == group) {
+ fsnotify_get_mark(mark);
+ return mark;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * given a group and vfsmount, find the mark associated with that combination.
+ * if found take a reference to that mark and return it, else return NULL
+ */
+struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group,
+ struct vfsmount *mnt)
+{
+ struct fsnotify_mark *mark;
+
+ spin_lock(&mnt->mnt_root->d_lock);
+ mark = fsnotify_find_vfsmount_mark_locked(group, mnt);
+ spin_unlock(&mnt->mnt_root->d_lock);
+
+ return mark;
+}
+
+/*
+ * Attach an initialized mark to a given group and vfsmount.
+ * These marks may be used for the fsnotify backend to determine which
+ * event types should be delivered to which groups.
+ */
+int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
+ struct fsnotify_group *group, struct vfsmount *mnt,
+ int allow_dups)
+{
+ struct fsnotify_mark *lmark = NULL;
+ int ret = 0;
+
+ mark->flags = FSNOTIFY_MARK_FLAG_VFSMOUNT;
+
+ /*
+ * LOCKING ORDER!!!!
+ * mark->lock
+ * group->mark_lock
+ * mnt->mnt_root->d_lock
+ */
+ assert_spin_locked(&mark->lock);
+ assert_spin_locked(&group->mark_lock);
+
+ spin_lock(&mnt->mnt_root->d_lock);
+
+ if (!allow_dups)
+ lmark = fsnotify_find_vfsmount_mark_locked(group, mnt);
+ if (!lmark) {
+ mark->m.mnt = mnt;
+
+ hlist_add_head(&mark->m.m_list, &mnt->mnt_fsnotify_marks);
+
+ fsnotify_recalc_vfsmount_mask_locked(mnt);
+ } else {
+ ret = -EEXIST;
+ }
+
+ spin_unlock(&mnt->mnt_root->d_lock);
+
+ return ret;
+}
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 4b57fb1eac2a..fdef8f729c3a 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -2879,9 +2879,6 @@ void ntfs_truncate_vfs(struct inode *vi) {
*
* Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also
* called with ->i_alloc_sem held for writing.
- *
- * Basically this is a copy of generic notify_change() and inode_setattr()
- * functionality, except we intercept and abort changes in i_size.
*/
int ntfs_setattr(struct dentry *dentry, struct iattr *attr)
{
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 3623ca20cc18..bf2cef7795e2 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -669,11 +669,10 @@ static ssize_t ocfs2_direct_IO(int rw,
if (i_size_read(inode) <= offset)
return 0;
- ret = blockdev_direct_IO_no_locking(rw, iocb, inode,
- inode->i_sb->s_bdev, iov, offset,
- nr_segs,
- ocfs2_direct_IO_get_blocks,
- ocfs2_dio_end_io);
+ ret = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev,
+ iov, offset, nr_segs,
+ ocfs2_direct_IO_get_blocks,
+ ocfs2_dio_end_io, NULL, 0);
mlog_exit(ret);
return ret;
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index b83d6107a1f5..85e4ccaedd1f 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -214,10 +214,12 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr)
attr->ia_valid &= ~ATTR_SIZE;
error = inode_change_ok(inode, attr);
- if (!error)
- error = inode_setattr(inode, attr);
+ if (error)
+ return error;
- return error;
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 6a13ea64c447..1fb09859bcc8 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1052,18 +1052,26 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
}
/*
- * This will intentionally not wind up calling simple_setsize(),
+ * This will intentionally not wind up calling truncate_setsize(),
* since all the work for a size change has been done above.
* Otherwise, we could get into problems with truncate as
* ip_alloc_sem is used there to protect against i_size
* changes.
+ *
+ * XXX: this means the conditional below can probably be removed.
*/
- status = inode_setattr(inode, attr);
- if (status < 0) {
- mlog_errno(status);
- goto bail_commit;
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ status = vmtruncate(inode, attr->ia_size);
+ if (status) {
+ mlog_errno(status);
+ goto bail_commit;
+ }
}
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+
status = ocfs2_mark_inode_dirty(handle, inode, bh);
if (status < 0)
mlog_errno(status);
@@ -2119,12 +2127,12 @@ relock:
* blocks outside i_size. Trim these off again.
* Don't need i_size_read because we hold i_mutex.
*
- * XXX(hch): this looks buggy because ocfs2 did not
+ * XXX(truncate): this looks buggy because ocfs2 did not
* actually implement ->truncate. Take a look at
* the new truncate sequence and update this accordingly
*/
if (*ppos + count > inode->i_size)
- simple_setsize(inode, inode->i_size);
+ truncate_setsize(inode, inode->i_size);
ret = written;
goto out_dio;
}
diff --git a/fs/ocfs2/reservations.c b/fs/ocfs2/reservations.c
index 40650021fc24..d8b6e4259b80 100644
--- a/fs/ocfs2/reservations.c
+++ b/fs/ocfs2/reservations.c
@@ -26,7 +26,6 @@
#include <linux/fs.h>
#include <linux/types.h>
-#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/bitops.h>
#include <linux/list.h>
diff --git a/fs/omfs/file.c b/fs/omfs/file.c
index 6e7a3291bbe8..5542c284dc1c 100644
--- a/fs/omfs/file.c
+++ b/fs/omfs/file.c
@@ -312,9 +312,17 @@ static int omfs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return block_write_begin(file, mapping, pos, len, flags,
- pagep, fsdata, omfs_get_block);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ omfs_get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t omfs_bmap(struct address_space *mapping, sector_t block)
@@ -333,7 +341,29 @@ const struct file_operations omfs_file_operations = {
.splice_read = generic_file_splice_read,
};
+static int omfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
const struct inode_operations omfs_file_inops = {
+ .setattr = omfs_setattr,
.truncate = omfs_truncate
};
diff --git a/fs/open.c b/fs/open.c
index 5463266db9e6..b25a74cb99b8 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -29,6 +29,7 @@
#include <linux/falloc.h>
#include <linux/fs_struct.h>
#include <linux/ima.h>
+#include <linux/dnotify.h>
#include "internal.h"
@@ -110,7 +111,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
error = locks_verify_truncate(inode, NULL, length);
if (!error)
- error = security_path_truncate(&path, length, 0);
+ error = security_path_truncate(&path);
if (!error)
error = do_truncate(path.dentry, length, 0, NULL);
@@ -165,8 +166,7 @@ static long do_sys_ftruncate(unsigned int fd, loff_t length, int small)
error = locks_verify_truncate(inode, file, length);
if (!error)
- error = security_path_truncate(&file->f_path, length,
- ATTR_MTIME|ATTR_CTIME);
+ error = security_path_truncate(&file->f_path);
if (!error)
error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
@@ -888,7 +888,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_path.dentry);
+ fsnotify_open(f);
fd_install(fd, f);
}
}
diff --git a/fs/pipe.c b/fs/pipe.c
index db6eaaba0dd8..69c4c7c13ea9 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -26,9 +26,14 @@
/*
* The max size that a non-root user is allowed to grow the pipe. Can
- * be set by root in /proc/sys/fs/pipe-max-pages
+ * be set by root in /proc/sys/fs/pipe-max-size
*/
-unsigned int pipe_max_pages = PIPE_DEF_BUFFERS * 16;
+unsigned int pipe_max_size = 1048576;
+
+/*
+ * Minimum pipe size, as required by POSIX
+ */
+unsigned int pipe_min_size = PAGE_SIZE;
/*
* We use a start+len construction, which provides full use of the
@@ -1118,26 +1123,20 @@ SYSCALL_DEFINE1(pipe, int __user *, fildes)
* Allocate a new array of pipe buffers and copy the info over. Returns the
* pipe size if successful, or return -ERROR on error.
*/
-static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
+static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages)
{
struct pipe_buffer *bufs;
/*
- * Must be a power-of-2 currently
- */
- if (!is_power_of_2(arg))
- return -EINVAL;
-
- /*
* We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't
* expect a lot of shrink+grow operations, just free and allocate
* again like we would do for growing. If the pipe currently
* contains more buffers than arg, then return busy.
*/
- if (arg < pipe->nrbufs)
+ if (nr_pages < pipe->nrbufs)
return -EBUSY;
- bufs = kcalloc(arg, sizeof(struct pipe_buffer), GFP_KERNEL);
+ bufs = kcalloc(nr_pages, sizeof(struct pipe_buffer), GFP_KERNEL);
if (unlikely(!bufs))
return -ENOMEM;
@@ -1158,8 +1157,37 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
pipe->curbuf = 0;
kfree(pipe->bufs);
pipe->bufs = bufs;
- pipe->buffers = arg;
- return arg;
+ pipe->buffers = nr_pages;
+ return nr_pages * PAGE_SIZE;
+}
+
+/*
+ * Currently we rely on the pipe array holding a power-of-2 number
+ * of pages.
+ */
+static inline unsigned int round_pipe_size(unsigned int size)
+{
+ unsigned long nr_pages;
+
+ nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
+}
+
+/*
+ * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax
+ * will return an error.
+ */
+int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
+ size_t *lenp, loff_t *ppos)
+{
+ int ret;
+
+ ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
+ if (ret < 0 || !write)
+ return ret;
+
+ pipe_max_size = round_pipe_size(pipe_max_size);
+ return ret;
}
long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -1174,23 +1202,24 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg)
mutex_lock(&pipe->inode->i_mutex);
switch (cmd) {
- case F_SETPIPE_SZ:
- if (!capable(CAP_SYS_ADMIN) && arg > pipe_max_pages) {
- ret = -EINVAL;
+ case F_SETPIPE_SZ: {
+ unsigned int size, nr_pages;
+
+ size = round_pipe_size(arg);
+ nr_pages = size >> PAGE_SHIFT;
+
+ if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
+ ret = -EPERM;
goto out;
- }
- /*
- * The pipe needs to be at least 2 pages large to
- * guarantee POSIX behaviour.
- */
- if (arg < 2) {
+ } else if (nr_pages < PAGE_SIZE) {
ret = -EINVAL;
goto out;
}
- ret = pipe_set_size(pipe, arg);
+ ret = pipe_set_size(pipe, nr_pages);
break;
+ }
case F_GETPIPE_SZ:
- ret = pipe->buffers;
+ ret = pipe->buffers * PAGE_SIZE;
break;
default:
ret = -EINVAL;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index acb7ef80ea4f..a49d9dd06d1d 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -561,9 +561,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
error = inode_change_ok(inode, attr);
- if (!error)
- error = inode_setattr(inode, attr);
- return error;
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
static const struct inode_operations proc_def_inode_operations = {
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 2791907744ed..dd29f0337661 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -12,6 +12,7 @@
#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
+#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mount.h>
@@ -258,17 +259,22 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
error = inode_change_ok(inode, iattr);
if (error)
- goto out;
+ return error;
- error = inode_setattr(inode, iattr);
- if (error)
- goto out;
+ if ((iattr->ia_valid & ATTR_SIZE) &&
+ iattr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, iattr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, iattr);
+ mark_inode_dirty(inode);
de->uid = inode->i_uid;
de->gid = inode->i_gid;
de->mode = inode->i_mode;
-out:
- return error;
+ return 0;
}
static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry,
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 6ff9981f0a18..5be436ea088e 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -329,10 +329,19 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr)
return -EPERM;
error = inode_change_ok(inode, attr);
- if (!error)
- error = inode_setattr(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
- return error;
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 277575ddc05c..16829722be93 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -320,10 +320,19 @@ static int qnx4_write_begin(struct file *file, struct address_space *mapping,
struct page **pagep, void **fsdata)
{
struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host);
+ int ret;
+
*pagep = NULL;
- return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
+ ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
qnx4_get_block,
&qnx4_inode->mmu_private);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t qnx4_bmap(struct address_space *mapping, sector_t block)
{
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 12c233da1b6b..2eebf72d07c8 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -986,6 +986,7 @@ static void remove_dquot_ref(struct super_block *sb, int type,
struct list_head *tofree_head)
{
struct inode *inode;
+ int reserved = 0;
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
@@ -995,10 +996,20 @@ static void remove_dquot_ref(struct super_block *sb, int type,
* only quota pointers and these have separate locking
* (dqptr_sem).
*/
- if (!IS_NOQUOTA(inode))
+ if (!IS_NOQUOTA(inode)) {
+ if (unlikely(inode_get_rsv_space(inode) > 0))
+ reserved = 1;
remove_inode_dquot_ref(inode, type, tofree_head);
+ }
}
spin_unlock(&inode_lock);
+#ifdef CONFIG_QUOTA_DEBUG
+ if (reserved) {
+ printk(KERN_WARNING "VFS (%s): Writes happened after quota"
+ " was disabled thus quota information is probably "
+ "inconsistent. Please run quotacheck(8).\n", sb->s_id);
+ }
+#endif
}
/* Gather all references from inodes and drop them */
@@ -1304,6 +1315,15 @@ static int info_bdq_free(struct dquot *dquot, qsize_t space)
return QUOTA_NL_NOWARN;
}
+static int dquot_active(const struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+
+ if (IS_NOQUOTA(inode))
+ return 0;
+ return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb);
+}
+
/*
* Initialize quota pointers in inode
*
@@ -1323,7 +1343,7 @@ static void __dquot_initialize(struct inode *inode, int type)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return;
/* First get references to structures we might need. */
@@ -1507,7 +1527,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex
*/
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_incr_space(inode, number, reserve);
goto out;
}
@@ -1559,7 +1579,7 @@ int dquot_alloc_inode(const struct inode *inode)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return 0;
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
warntype[cnt] = QUOTA_NL_NOWARN;
@@ -1596,7 +1616,7 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
{
int cnt;
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_claim_rsv_space(inode, number);
return 0;
}
@@ -1629,7 +1649,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode)) {
+ if (!dquot_active(inode)) {
inode_decr_space(inode, number, reserve);
return;
}
@@ -1667,7 +1687,7 @@ void dquot_free_inode(const struct inode *inode)
/* First test before acquiring mutex - solves deadlocks when we
* re-enter the quota code and are already holding the mutex */
- if (!sb_any_quota_active(inode->i_sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return;
down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
@@ -1790,7 +1810,7 @@ int dquot_transfer(struct inode *inode, struct iattr *iattr)
struct super_block *sb = inode->i_sb;
int ret;
- if (!sb_any_quota_active(sb) || IS_NOQUOTA(inode))
+ if (!dquot_active(inode))
return 0;
if (iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid)
@@ -2270,7 +2290,7 @@ static void do_get_dqblk(struct dquot *dquot, struct fs_disk_quota *di)
memset(di, 0, sizeof(*di));
di->d_version = FS_DQUOT_VERSION;
di->d_flags = dquot->dq_type == USRQUOTA ?
- XFS_USER_QUOTA : XFS_GROUP_QUOTA;
+ FS_USER_QUOTA : FS_GROUP_QUOTA;
di->d_id = dquot->dq_id;
spin_lock(&dq_data_lock);
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index d532c20fc179..9eead2c796b7 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -146,9 +146,8 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size)
return ret;
}
- ret = simple_setsize(inode, newsize);
-
- return ret;
+ truncate_setsize(inode, newsize);
+ return 0;
}
/*****************************************************************************/
@@ -183,7 +182,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia)
}
}
- generic_setattr(inode, ia);
+ setattr_copy(inode, ia);
out:
ia->ia_valid = old_ia_valid;
return ret;
diff --git a/fs/read_write.c b/fs/read_write.c
index 9c0485236e68..74e36586e4d3 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -311,7 +311,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
add_rchar(current, ret);
}
inc_syscr(current);
@@ -367,7 +367,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
add_wchar(current, ret);
}
inc_syscw(current);
@@ -675,9 +675,9 @@ out:
kfree(iov);
if ((ret + (type == READ)) > 0) {
if (type == READ)
- fsnotify_access(file->f_path.dentry);
+ fsnotify_access(file);
else
- fsnotify_modify(file->f_path.dentry);
+ fsnotify_modify(file);
}
return ret;
}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 0f22fdaf54ac..bc0c7144449f 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -2587,8 +2587,7 @@ static int reiserfs_write_begin(struct file *file,
old_ref = th->t_refcount;
th->t_refcount++;
}
- ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- reiserfs_get_block);
+ ret = __block_write_begin(page, pos, len, reiserfs_get_block);
if (ret && reiserfs_transaction_running(inode->i_sb)) {
struct reiserfs_transaction_handle *th = current->journal_info;
/* this gets a little ugly. If reiserfs_get_block returned an
@@ -3059,10 +3058,25 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
+ ssize_t ret;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
reiserfs_get_blocks_direct_io, NULL);
+
+ /*
+ * In case of error extending write may have instantiated a few
+ * blocks outside i_size. Trim these off again.
+ */
+ if (unlikely((rw & WRITE) && ret < 0)) {
+ loff_t isize = i_size_read(inode);
+ loff_t end = offset + iov_length(iov, nr_segs);
+
+ if (end > isize)
+ vmtruncate(inode, isize);
+ }
+
+ return ret;
}
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
@@ -3072,6 +3086,10 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
int depth;
int error;
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
/* must be turned off for recursive notify_change calls */
ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID);
@@ -3121,56 +3139,59 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
goto out;
}
- error = inode_change_ok(inode, attr);
- if (!error) {
- if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
- error = reiserfs_chown_xattrs(inode, attr);
+ if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ struct reiserfs_transaction_handle th;
+ int jbegin_count =
+ 2 *
+ (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) +
+ REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) +
+ 2;
- if (!error) {
- struct reiserfs_transaction_handle th;
- int jbegin_count =
- 2 *
- (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) +
- REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) +
- 2;
-
- /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
- error =
- journal_begin(&th, inode->i_sb,
- jbegin_count);
- if (error)
- goto out;
- error = dquot_transfer(inode, attr);
- if (error) {
- journal_end(&th, inode->i_sb,
- jbegin_count);
- goto out;
- }
- /* Update corresponding info in inode so that everything is in
- * one transaction */
- if (attr->ia_valid & ATTR_UID)
- inode->i_uid = attr->ia_uid;
- if (attr->ia_valid & ATTR_GID)
- inode->i_gid = attr->ia_gid;
- mark_inode_dirty(inode);
- error =
- journal_end(&th, inode->i_sb, jbegin_count);
- }
- }
- if (!error) {
- /*
- * Relax the lock here, as it might truncate the
- * inode pages and wait for inode pages locks.
- * To release such page lock, the owner needs the
- * reiserfs lock
- */
- reiserfs_write_unlock_once(inode->i_sb, depth);
- error = inode_setattr(inode, attr);
- depth = reiserfs_write_lock_once(inode->i_sb);
+ error = reiserfs_chown_xattrs(inode, attr);
+
+ if (error)
+ return error;
+
+ /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
+ error = journal_begin(&th, inode->i_sb, jbegin_count);
+ if (error)
+ goto out;
+ error = dquot_transfer(inode, attr);
+ if (error) {
+ journal_end(&th, inode->i_sb, jbegin_count);
+ goto out;
}
+
+ /* Update corresponding info in inode so that everything is in
+ * one transaction */
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ mark_inode_dirty(inode);
+ error = journal_end(&th, inode->i_sb, jbegin_count);
+ if (error)
+ goto out;
}
+ /*
+ * Relax the lock here, as it might truncate the
+ * inode pages and wait for inode pages locks.
+ * To release such page lock, the owner needs the
+ * reiserfs lock
+ */
+ reiserfs_write_unlock_once(inode->i_sb, depth);
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode))
+ error = vmtruncate(inode, attr->ia_size);
+
+ if (!error) {
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ }
+ depth = reiserfs_write_lock_once(inode->i_sb);
+
if (!error && reiserfs_posixacl(inode->i_sb)) {
if (attr->ia_valid & ATTR_MODE)
error = reiserfs_acl_chmod(inode);
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index 9551cb6f7fe4..e338f0a5a70d 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -714,9 +714,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr)
error = server->ops->truncate(inode, attr->ia_size);
if (error)
goto out;
- error = simple_setsize(inode, attr->ia_size);
- if (error)
- goto out;
+ truncate_setsize(inode, attr->ia_size);
refresh = 1;
}
diff --git a/fs/splice.c b/fs/splice.c
index ac22b00d86c3..740e6b9faf7a 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -354,7 +354,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
break;
error = add_to_page_cache_lru(page, mapping, index,
- mapping_gfp_mask(mapping));
+ GFP_KERNEL);
if (unlikely(error)) {
page_cache_release(page);
if (error == -EEXIST)
diff --git a/fs/sync.c b/fs/sync.c
index c9f83f480ec5..15aa6f03b2da 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -42,7 +42,7 @@ static int __sync_filesystem(struct super_block *sb, int wait)
if (wait)
sync_inodes_sb(sb);
else
- writeback_inodes_sb_locked(sb);
+ writeback_inodes_sb(sb);
if (sb->s_op->sync_fs)
sb->s_op->sync_fs(sb, wait);
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index bde1a4c3679a..7e187fbd3d47 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -117,10 +117,12 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr)
if (error)
goto out;
- /* this ignores size changes */
- generic_setattr(inode, iattr);
-
error = sysfs_sd_setattr(sd, iattr);
+ if (error)
+ goto out;
+
+ /* this ignores size changes */
+ setattr_copy(inode, iattr);
out:
mutex_unlock(&sysfs_mutex);
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c
index 79941e4964a4..a77c42157620 100644
--- a/fs/sysv/dir.c
+++ b/fs/sysv/dir.c
@@ -218,8 +218,7 @@ got_it:
pos = page_offset(page) +
(char*)de - (char*)page_address(page);
lock_page(page);
- err = __sysv_write_begin(NULL, page->mapping, pos, SYSV_DIRSIZE,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
if (err)
goto out_unlock;
memcpy (de->name, name, namelen);
@@ -239,15 +238,13 @@ out_unlock:
int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
{
- struct address_space *mapping = page->mapping;
- struct inode *inode = (struct inode*)mapping->host;
+ struct inode *inode = page->mapping->host;
char *kaddr = (char*)page_address(page);
loff_t pos = page_offset(page) + (char *)de - kaddr;
int err;
lock_page(page);
- err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
BUG_ON(err);
de->inode = 0;
err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
@@ -259,16 +256,14 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page)
int sysv_make_empty(struct inode *inode, struct inode *dir)
{
- struct address_space *mapping = inode->i_mapping;
- struct page *page = grab_cache_page(mapping, 0);
+ struct page *page = grab_cache_page(inode->i_mapping, 0);
struct sysv_dir_entry * de;
char *base;
int err;
if (!page)
return -ENOMEM;
- err = __sysv_write_begin(NULL, mapping, 0, 2 * SYSV_DIRSIZE,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = sysv_prepare_chunk(page, 0, 2 * SYSV_DIRSIZE);
if (err) {
unlock_page(page);
goto fail;
@@ -341,15 +336,13 @@ not_empty:
void sysv_set_link(struct sysv_dir_entry *de, struct page *page,
struct inode *inode)
{
- struct address_space *mapping = page->mapping;
- struct inode *dir = mapping->host;
+ struct inode *dir = page->mapping->host;
loff_t pos = page_offset(page) +
(char *)de-(char*)page_address(page);
int err;
lock_page(page);
- err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE);
BUG_ON(err);
de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino);
err = dir_commit_chunk(page, pos, SYSV_DIRSIZE);
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index 750cc22349bd..0a65939508e9 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -30,7 +30,29 @@ const struct file_operations sysv_file_operations = {
.splice_read = generic_file_splice_read,
};
+static int sysv_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
const struct inode_operations sysv_file_inode_operations = {
.truncate = sysv_truncate,
+ .setattr = sysv_setattr,
.getattr = sysv_getattr,
};
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c
index f042eec464c2..9ca66276315e 100644
--- a/fs/sysv/itree.c
+++ b/fs/sysv/itree.c
@@ -459,20 +459,25 @@ static int sysv_readpage(struct file *file, struct page *page)
return block_read_full_page(page,get_block);
}
-int __sysv_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
+int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- get_block);
+ return __block_write_begin(page, pos, len, get_block);
}
static int sysv_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return __sysv_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep, get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t sysv_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 94cb9b4d76c2..bb55cdb394bf 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -136,9 +136,7 @@ extern unsigned long sysv_count_free_blocks(struct super_block *);
/* itree.c */
extern void sysv_truncate(struct inode *);
-extern int __sysv_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata);
+extern int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len);
/* inode.c */
extern struct inode *sysv_iget(struct super_block *, unsigned int);
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index 12f445cee9f7..03ae894c45de 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -967,14 +967,15 @@ static int do_writepage(struct page *page, int len)
* the page locked, and it locks @ui_mutex. However, write-back does take inode
* @i_mutex, which means other VFS operations may be run on this inode at the
* same time. And the problematic one is truncation to smaller size, from where
- * we have to call 'simple_setsize()', which first changes @inode->i_size, then
+ * we have to call 'truncate_setsize()', which first changes @inode->i_size, then
* drops the truncated pages. And while dropping the pages, it takes the page
- * lock. This means that 'do_truncation()' cannot call 'simple_setsize()' with
+ * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with
* @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This
* means that @inode->i_size is changed while @ui_mutex is unlocked.
*
- * XXX: with the new truncate the above is not true anymore, the simple_setsize
- * calls can be replaced with the individual components.
+ * XXX(truncate): with the new truncate sequence this is not true anymore,
+ * and the calls to truncate_setsize can be move around freely. They should
+ * be moved to the very end of the truncate sequence.
*
* But in 'ubifs_writepage()' we have to guarantee that we do not write beyond
* inode size. How do we do this if @inode->i_size may became smaller while we
@@ -1128,9 +1129,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode,
budgeted = 0;
}
- err = simple_setsize(inode, new_size);
- if (err)
- goto out_budg;
+ truncate_setsize(inode, new_size);
if (offset) {
pgoff_t index = new_size >> PAGE_CACHE_SHIFT;
@@ -1217,16 +1216,14 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
if (attr->ia_valid & ATTR_SIZE) {
dbg_gen("size %lld -> %lld", inode->i_size, new_size);
- err = simple_setsize(inode, new_size);
- if (err)
- goto out;
+ truncate_setsize(inode, new_size);
}
mutex_lock(&ui->ui_mutex);
if (attr->ia_valid & ATTR_SIZE) {
/* Truncation changes inode [mc]time */
inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
- /* 'simple_setsize()' changed @i_size, update @ui_size */
+ /* 'truncate_setsize()' changed @i_size, update @ui_size */
ui->ui_size = inode->i_size;
}
@@ -1248,10 +1245,6 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode,
if (IS_SYNC(inode))
err = inode->i_sb->s_op->write_inode(inode, NULL);
return err;
-
-out:
- ubifs_release_budget(c, &req);
- return err;
}
int ubifs_setattr(struct dentry *dentry, struct iattr *attr)
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index 2eef553d50c8..e40a4629e81b 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -379,7 +379,7 @@ struct ubifs_gced_idx_leb {
* The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses
* @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot
* make sure @inode->i_size is always changed under @ui_mutex, because it
- * cannot call 'simple_setsize()' with @ui_mutex locked, because it would deadlock
+ * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock
* with 'ubifs_writepage()' (see file.c). All the other inode fields are
* changed under @ui_mutex, so they do not need "shadow" fields. Note, one
* could consider to rework locking and base it on "shadow" fields.
diff --git a/fs/udf/file.c b/fs/udf/file.c
index 94e06d6bddbd..66b9e7e7e4c5 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -36,7 +36,6 @@
#include <linux/pagemap.h>
#include <linux/buffer_head.h>
#include <linux/aio.h>
-#include <linux/smp_lock.h>
#include "udf_i.h"
#include "udf_sb.h"
@@ -228,6 +227,28 @@ const struct file_operations udf_file_operations = {
.llseek = generic_file_llseek,
};
+static int udf_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((attr->ia_valid & ATTR_SIZE) &&
+ attr->ia_size != i_size_read(inode)) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
+}
+
const struct inode_operations udf_file_inode_operations = {
+ .setattr = udf_setattr,
.truncate = udf_truncate,
};
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 124852bcf6fe..ecddcc2ed746 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -127,9 +127,16 @@ static int udf_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- udf_get_block);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t udf_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c
index ec784756dc65..dbc90994715a 100644
--- a/fs/ufs/dir.c
+++ b/fs/ufs/dir.c
@@ -95,8 +95,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
int err;
lock_page(page);
- err = __ufs_write_begin(NULL, page->mapping, pos, len,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = ufs_prepare_chunk(page, pos, len);
BUG_ON(err);
de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
@@ -381,8 +380,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode)
got_it:
pos = page_offset(page) +
(char*)de - (char*)page_address(page);
- err = __ufs_write_begin(NULL, page->mapping, pos, rec_len,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = ufs_prepare_chunk(page, pos, rec_len);
if (err)
goto out_unlock;
if (de->d_ino) {
@@ -518,7 +516,6 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
struct page * page)
{
struct super_block *sb = inode->i_sb;
- struct address_space *mapping = page->mapping;
char *kaddr = page_address(page);
unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1);
unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen);
@@ -549,8 +546,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir,
pos = page_offset(page) + from;
lock_page(page);
- err = __ufs_write_begin(NULL, mapping, pos, to - from,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = ufs_prepare_chunk(page, pos, to - from);
BUG_ON(err);
if (pde)
pde->d_reclen = cpu_to_fs16(sb, to - from);
@@ -577,8 +573,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir)
if (!page)
return -ENOMEM;
- err = __ufs_write_begin(NULL, mapping, 0, chunk_size,
- AOP_FLAG_UNINTERRUPTIBLE, &page, NULL);
+ err = ufs_prepare_chunk(page, 0, chunk_size);
if (err) {
unlock_page(page);
goto fail;
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 73fe773aa034..45cafa937a4b 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -558,20 +558,26 @@ static int ufs_readpage(struct file *file, struct page *page)
return block_read_full_page(page,ufs_getfrag_block);
}
-int __ufs_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
+int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
{
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- ufs_getfrag_block);
+ return __block_write_begin(page, pos, len, ufs_getfrag_block);
}
static int ufs_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata)
{
- *pagep = NULL;
- return __ufs_write_begin(file, mapping, pos, len, flags, pagep, fsdata);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ ufs_getfrag_block);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 589e01a465ba..34d5cb135320 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -500,11 +500,6 @@ out:
return err;
}
-/*
- * TODO:
- * - truncate case should use proper ordering instead of using
- * simple_setsize
- */
int ufs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
@@ -518,14 +513,17 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr)
if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
loff_t old_i_size = inode->i_size;
- error = simple_setsize(inode, attr->ia_size);
- if (error)
- return error;
+ /* XXX(truncate): truncate_setsize should be called last */
+ truncate_setsize(inode, attr->ia_size);
+
error = ufs_truncate(inode, old_i_size);
if (error)
return error;
}
- return inode_setattr(inode, attr);
+
+ setattr_copy(inode, attr);
+ mark_inode_dirty(inode);
+ return 0;
}
const struct inode_operations ufs_file_inode_operations = {
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 23ceed8c8fb9..0466036912f1 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -257,9 +257,7 @@ ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value)
extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *);
extern void ufs_set_inode_dev(struct super_block *, struct ufs_inode_info *, dev_t);
-extern int __ufs_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata);
+extern int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len);
/*
* These functions manipulate ufs buffers
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 089eaca860b4..3393af5ec80c 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -1333,6 +1333,21 @@ xfs_vm_writepage(
trace_xfs_writepage(inode, page, 0);
/*
+ * Refuse to write the page out if we are called from reclaim context.
+ *
+ * This is primarily to avoid stack overflows when called from deep
+ * used stacks in random callers for direct reclaim, but disabling
+ * reclaim for kswap is a nice side-effect as kswapd causes rather
+ * suboptimal I/O patters, too.
+ *
+ * This should really be done by the core VM, but until that happens
+ * filesystems like XFS, btrfs and ext4 have to take care of this
+ * by themselves.
+ */
+ if (current->flags & PF_MEMALLOC)
+ goto out_fail;
+
+ /*
* We need a transaction if:
* 1. There are delalloc buffers on the page
* 2. The page is uptodate and we have unmapped buffers
@@ -1658,10 +1673,9 @@ xfs_vm_direct_IO(
iocb->private = xfs_alloc_ioend(inode, rw == WRITE ?
IO_UNWRITTEN : IO_READ);
- ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov,
- offset, nr_segs,
- xfs_get_blocks_direct,
- xfs_end_io_direct);
+ ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
+ nr_segs, xfs_get_blocks_direct,
+ xfs_end_io_direct, NULL, 0);
if (unlikely(ret != -EIOCBQUEUED && iocb->private))
xfs_destroy_ioend(iocb->private);
@@ -1678,9 +1692,17 @@ xfs_vm_write_begin(
struct page **pagep,
void **fsdata)
{
- *pagep = NULL;
- return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
- xfs_get_blocks);
+ int ret;
+
+ ret = block_write_begin(mapping, pos, len, flags, pagep,
+ xfs_get_blocks);
+ if (unlikely(ret)) {
+ loff_t isize = mapping->host->i_size;
+ if (pos + len > isize)
+ vmtruncate(mapping->host, isize);
+ }
+
+ return ret;
}
STATIC sector_t
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index 9c8019c78c92..44f0b2de153e 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -585,11 +585,20 @@ xfs_vn_fallocate(
bf.l_len = len;
xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+ /* check the new inode size is valid before allocating */
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ offset + len > i_size_read(inode)) {
+ new_size = offset + len;
+ error = inode_newsize_ok(inode, new_size);
+ if (error)
+ goto out_unlock;
+ }
+
error = -xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf,
0, XFS_ATTR_NOLOCK);
- if (!error && !(mode & FALLOC_FL_KEEP_SIZE) &&
- offset + len > i_size_read(inode))
- new_size = offset + len;
+ if (error)
+ goto out_unlock;
/* Change file size if needed */
if (new_size) {
@@ -600,6 +609,7 @@ xfs_vn_fallocate(
error = -xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
}
+out_unlock:
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
out_error:
return error;
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/linux-2.6/xfs_quotaops.c
index 9ac8aea91529..b9ba7536f4b4 100644
--- a/fs/xfs/linux-2.6/xfs_quotaops.c
+++ b/fs/xfs/linux-2.6/xfs_quotaops.c
@@ -23,7 +23,6 @@
#include "xfs_ag.h"
#include "xfs_mount.h"
#include "xfs_quota.h"
-#include "xfs_log.h"
#include "xfs_trans.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
@@ -70,15 +69,15 @@ xfs_fs_set_xstate(
if (op != Q_XQUOTARM && !XFS_IS_QUOTA_RUNNING(mp))
return -ENOSYS;
- if (uflags & XFS_QUOTA_UDQ_ACCT)
+ if (uflags & FS_QUOTA_UDQ_ACCT)
flags |= XFS_UQUOTA_ACCT;
- if (uflags & XFS_QUOTA_PDQ_ACCT)
+ if (uflags & FS_QUOTA_PDQ_ACCT)
flags |= XFS_PQUOTA_ACCT;
- if (uflags & XFS_QUOTA_GDQ_ACCT)
+ if (uflags & FS_QUOTA_GDQ_ACCT)
flags |= XFS_GQUOTA_ACCT;
- if (uflags & XFS_QUOTA_UDQ_ENFD)
+ if (uflags & FS_QUOTA_UDQ_ENFD)
flags |= XFS_UQUOTA_ENFD;
- if (uflags & (XFS_QUOTA_PDQ_ENFD|XFS_QUOTA_GDQ_ENFD))
+ if (uflags & (FS_QUOTA_PDQ_ENFD|FS_QUOTA_GDQ_ENFD))
flags |= XFS_OQUOTA_ENFD;
switch (op) {
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 3884e20bc14e..ef7f0218bccb 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -164,10 +164,6 @@ xfs_inode_ag_iterator(
struct xfs_perag *pag;
pag = xfs_perag_get(mp, ag);
- if (!pag->pag_ici_init) {
- xfs_perag_put(pag);
- continue;
- }
error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
exclusive, &nr);
xfs_perag_put(pag);
@@ -867,12 +863,7 @@ xfs_reclaim_inode_shrink(
down_read(&xfs_mount_list_lock);
list_for_each_entry(mp, &xfs_mount_list, m_mplist) {
for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
-
pag = xfs_perag_get(mp, ag);
- if (!pag->pag_ici_init) {
- xfs_perag_put(pag);
- continue;
- }
reclaimable += pag->pag_ici_reclaimable;
xfs_perag_put(pag);
}
diff --git a/fs/xfs/linux-2.6/xfs_trace.c b/fs/xfs/linux-2.6/xfs_trace.c
index 207fa77f63ae..d12be8470cba 100644
--- a/fs/xfs/linux-2.6/xfs_trace.c
+++ b/fs/xfs/linux-2.6/xfs_trace.c
@@ -50,7 +50,6 @@
#include "quota/xfs_dquot_item.h"
#include "quota/xfs_dquot.h"
#include "xfs_log_recover.h"
-#include "xfs_buf_item.h"
#include "xfs_inode_item.h"
/*
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h
index ff6bc797baf2..73d5aa117384 100644
--- a/fs/xfs/linux-2.6/xfs_trace.h
+++ b/fs/xfs/linux-2.6/xfs_trace.h
@@ -82,33 +82,6 @@ DECLARE_EVENT_CLASS(xfs_attr_list_class,
)
)
-#define DEFINE_PERAG_REF_EVENT(name) \
-TRACE_EVENT(name, \
- TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \
- unsigned long caller_ip), \
- TP_ARGS(mp, agno, refcount, caller_ip), \
- TP_STRUCT__entry( \
- __field(dev_t, dev) \
- __field(xfs_agnumber_t, agno) \
- __field(int, refcount) \
- __field(unsigned long, caller_ip) \
- ), \
- TP_fast_assign( \
- __entry->dev = mp->m_super->s_dev; \
- __entry->agno = agno; \
- __entry->refcount = refcount; \
- __entry->caller_ip = caller_ip; \
- ), \
- TP_printk("dev %d:%d agno %u refcount %d caller %pf", \
- MAJOR(__entry->dev), MINOR(__entry->dev), \
- __entry->agno, \
- __entry->refcount, \
- (char *)__entry->caller_ip) \
-);
-
-DEFINE_PERAG_REF_EVENT(xfs_perag_get)
-DEFINE_PERAG_REF_EVENT(xfs_perag_put)
-
#define DEFINE_ATTR_LIST_EVENT(name) \
DEFINE_EVENT(xfs_attr_list_class, name, \
TP_PROTO(struct xfs_attr_list_context *ctx), \
@@ -122,6 +95,37 @@ DEFINE_ATTR_LIST_EVENT(xfs_attr_list_add);
DEFINE_ATTR_LIST_EVENT(xfs_attr_list_wrong_blk);
DEFINE_ATTR_LIST_EVENT(xfs_attr_list_notfound);
+DECLARE_EVENT_CLASS(xfs_perag_class,
+ TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount,
+ unsigned long caller_ip),
+ TP_ARGS(mp, agno, refcount, caller_ip),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_agnumber_t, agno)
+ __field(int, refcount)
+ __field(unsigned long, caller_ip)
+ ),
+ TP_fast_assign(
+ __entry->dev = mp->m_super->s_dev;
+ __entry->agno = agno;
+ __entry->refcount = refcount;
+ __entry->caller_ip = caller_ip;
+ ),
+ TP_printk("dev %d:%d agno %u refcount %d caller %pf",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->agno,
+ __entry->refcount,
+ (char *)__entry->caller_ip)
+);
+
+#define DEFINE_PERAG_REF_EVENT(name) \
+DEFINE_EVENT(xfs_perag_class, name, \
+ TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \
+ unsigned long caller_ip), \
+ TP_ARGS(mp, agno, refcount, caller_ip))
+DEFINE_PERAG_REF_EVENT(xfs_perag_get);
+DEFINE_PERAG_REF_EVENT(xfs_perag_put);
+
TRACE_EVENT(xfs_attr_list_node_descend,
TP_PROTO(struct xfs_attr_list_context *ctx,
struct xfs_da_node_entry *btree),
@@ -775,165 +779,181 @@ DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_enter);
DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_exit);
DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_sub);
-#define DEFINE_RW_EVENT(name) \
-TRACE_EVENT(name, \
- TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags), \
- TP_ARGS(ip, count, offset, flags), \
- TP_STRUCT__entry( \
- __field(dev_t, dev) \
- __field(xfs_ino_t, ino) \
- __field(xfs_fsize_t, size) \
- __field(xfs_fsize_t, new_size) \
- __field(loff_t, offset) \
- __field(size_t, count) \
- __field(int, flags) \
- ), \
- TP_fast_assign( \
- __entry->dev = VFS_I(ip)->i_sb->s_dev; \
- __entry->ino = ip->i_ino; \
- __entry->size = ip->i_d.di_size; \
- __entry->new_size = ip->i_new_size; \
- __entry->offset = offset; \
- __entry->count = count; \
- __entry->flags = flags; \
- ), \
- TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \
- "offset 0x%llx count 0x%zx ioflags %s", \
- MAJOR(__entry->dev), MINOR(__entry->dev), \
- __entry->ino, \
- __entry->size, \
- __entry->new_size, \
- __entry->offset, \
- __entry->count, \
- __print_flags(__entry->flags, "|", XFS_IO_FLAGS)) \
+DECLARE_EVENT_CLASS(xfs_file_class,
+ TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags),
+ TP_ARGS(ip, count, offset, flags),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(xfs_fsize_t, size)
+ __field(xfs_fsize_t, new_size)
+ __field(loff_t, offset)
+ __field(size_t, count)
+ __field(int, flags)
+ ),
+ TP_fast_assign(
+ __entry->dev = VFS_I(ip)->i_sb->s_dev;
+ __entry->ino = ip->i_ino;
+ __entry->size = ip->i_d.di_size;
+ __entry->new_size = ip->i_new_size;
+ __entry->offset = offset;
+ __entry->count = count;
+ __entry->flags = flags;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
+ "offset 0x%llx count 0x%zx ioflags %s",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->size,
+ __entry->new_size,
+ __entry->offset,
+ __entry->count,
+ __print_flags(__entry->flags, "|", XFS_IO_FLAGS))
)
+
+#define DEFINE_RW_EVENT(name) \
+DEFINE_EVENT(xfs_file_class, name, \
+ TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset, int flags), \
+ TP_ARGS(ip, count, offset, flags))
DEFINE_RW_EVENT(xfs_file_read);
DEFINE_RW_EVENT(xfs_file_buffered_write);
DEFINE_RW_EVENT(xfs_file_direct_write);
DEFINE_RW_EVENT(xfs_file_splice_read);
DEFINE_RW_EVENT(xfs_file_splice_write);
-
-#define DEFINE_PAGE_EVENT(name) \
-TRACE_EVENT(name, \
- TP_PROTO(struct inode *inode, struct page *page, unsigned long off), \
- TP_ARGS(inode, page, off), \
- TP_STRUCT__entry( \
- __field(dev_t, dev) \
- __field(xfs_ino_t, ino) \
- __field(pgoff_t, pgoff) \
- __field(loff_t, size) \
- __field(unsigned long, offset) \
- __field(int, delalloc) \
- __field(int, unmapped) \
- __field(int, unwritten) \
- ), \
- TP_fast_assign( \
- int delalloc = -1, unmapped = -1, unwritten = -1; \
- \
- if (page_has_buffers(page)) \
- xfs_count_page_state(page, &delalloc, \
- &unmapped, &unwritten); \
- __entry->dev = inode->i_sb->s_dev; \
- __entry->ino = XFS_I(inode)->i_ino; \
- __entry->pgoff = page_offset(page); \
- __entry->size = i_size_read(inode); \
- __entry->offset = off; \
- __entry->delalloc = delalloc; \
- __entry->unmapped = unmapped; \
- __entry->unwritten = unwritten; \
- ), \
- TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx " \
- "delalloc %d unmapped %d unwritten %d", \
- MAJOR(__entry->dev), MINOR(__entry->dev), \
- __entry->ino, \
- __entry->pgoff, \
- __entry->size, \
- __entry->offset, \
- __entry->delalloc, \
- __entry->unmapped, \
- __entry->unwritten) \
+DECLARE_EVENT_CLASS(xfs_page_class,
+ TP_PROTO(struct inode *inode, struct page *page, unsigned long off),
+ TP_ARGS(inode, page, off),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(pgoff_t, pgoff)
+ __field(loff_t, size)
+ __field(unsigned long, offset)
+ __field(int, delalloc)
+ __field(int, unmapped)
+ __field(int, unwritten)
+ ),
+ TP_fast_assign(
+ int delalloc = -1, unmapped = -1, unwritten = -1;
+
+ if (page_has_buffers(page))
+ xfs_count_page_state(page, &delalloc,
+ &unmapped, &unwritten);
+ __entry->dev = inode->i_sb->s_dev;
+ __entry->ino = XFS_I(inode)->i_ino;
+ __entry->pgoff = page_offset(page);
+ __entry->size = i_size_read(inode);
+ __entry->offset = off;
+ __entry->delalloc = delalloc;
+ __entry->unmapped = unmapped;
+ __entry->unwritten = unwritten;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx "
+ "delalloc %d unmapped %d unwritten %d",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->pgoff,
+ __entry->size,
+ __entry->offset,
+ __entry->delalloc,
+ __entry->unmapped,
+ __entry->unwritten)
)
+
+#define DEFINE_PAGE_EVENT(name) \
+DEFINE_EVENT(xfs_page_class, name, \
+ TP_PROTO(struct inode *inode, struct page *page, unsigned long off), \
+ TP_ARGS(inode, page, off))
DEFINE_PAGE_EVENT(xfs_writepage);
DEFINE_PAGE_EVENT(xfs_releasepage);
DEFINE_PAGE_EVENT(xfs_invalidatepage);
-#define DEFINE_IOMAP_EVENT(name) \
-TRACE_EVENT(name, \
- TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, \
- int flags, struct xfs_bmbt_irec *irec), \
- TP_ARGS(ip, offset, count, flags, irec), \
- TP_STRUCT__entry( \
- __field(dev_t, dev) \
- __field(xfs_ino_t, ino) \
- __field(loff_t, size) \
- __field(loff_t, new_size) \
- __field(loff_t, offset) \
- __field(size_t, count) \
- __field(int, flags) \
- __field(xfs_fileoff_t, startoff) \
- __field(xfs_fsblock_t, startblock) \
- __field(xfs_filblks_t, blockcount) \
- ), \
- TP_fast_assign( \
- __entry->dev = VFS_I(ip)->i_sb->s_dev; \
- __entry->ino = ip->i_ino; \
- __entry->size = ip->i_d.di_size; \
- __entry->new_size = ip->i_new_size; \
- __entry->offset = offset; \
- __entry->count = count; \
- __entry->flags = flags; \
- __entry->startoff = irec ? irec->br_startoff : 0; \
- __entry->startblock = irec ? irec->br_startblock : 0; \
- __entry->blockcount = irec ? irec->br_blockcount : 0; \
- ), \
- TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \
- "offset 0x%llx count %zd flags %s " \
- "startoff 0x%llx startblock %lld blockcount 0x%llx", \
- MAJOR(__entry->dev), MINOR(__entry->dev), \
- __entry->ino, \
- __entry->size, \
- __entry->new_size, \
- __entry->offset, \
- __entry->count, \
- __print_flags(__entry->flags, "|", BMAPI_FLAGS), \
- __entry->startoff, \
- (__int64_t)__entry->startblock, \
- __entry->blockcount) \
+DECLARE_EVENT_CLASS(xfs_iomap_class,
+ TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count,
+ int flags, struct xfs_bmbt_irec *irec),
+ TP_ARGS(ip, offset, count, flags, irec),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(loff_t, size)
+ __field(loff_t, new_size)
+ __field(loff_t, offset)
+ __field(size_t, count)
+ __field(int, flags)
+ __field(xfs_fileoff_t, startoff)
+ __field(xfs_fsblock_t, startblock)
+ __field(xfs_filblks_t, blockcount)
+ ),
+ TP_fast_assign(
+ __entry->dev = VFS_I(ip)->i_sb->s_dev;
+ __entry->ino = ip->i_ino;
+ __entry->size = ip->i_d.di_size;
+ __entry->new_size = ip->i_new_size;
+ __entry->offset = offset;
+ __entry->count = count;
+ __entry->flags = flags;
+ __entry->startoff = irec ? irec->br_startoff : 0;
+ __entry->startblock = irec ? irec->br_startblock : 0;
+ __entry->blockcount = irec ? irec->br_blockcount : 0;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
+ "offset 0x%llx count %zd flags %s "
+ "startoff 0x%llx startblock %lld blockcount 0x%llx",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->size,
+ __entry->new_size,
+ __entry->offset,
+ __entry->count,
+ __print_flags(__entry->flags, "|", BMAPI_FLAGS),
+ __entry->startoff,
+ (__int64_t)__entry->startblock,
+ __entry->blockcount)
)
+
+#define DEFINE_IOMAP_EVENT(name) \
+DEFINE_EVENT(xfs_iomap_class, name, \
+ TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, \
+ int flags, struct xfs_bmbt_irec *irec), \
+ TP_ARGS(ip, offset, count, flags, irec))
DEFINE_IOMAP_EVENT(xfs_iomap_enter);
DEFINE_IOMAP_EVENT(xfs_iomap_found);
DEFINE_IOMAP_EVENT(xfs_iomap_alloc);
-#define DEFINE_SIMPLE_IO_EVENT(name) \
-TRACE_EVENT(name, \
- TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), \
- TP_ARGS(ip, offset, count), \
- TP_STRUCT__entry( \
- __field(dev_t, dev) \
- __field(xfs_ino_t, ino) \
- __field(loff_t, size) \
- __field(loff_t, new_size) \
- __field(loff_t, offset) \
- __field(size_t, count) \
- ), \
- TP_fast_assign( \
- __entry->dev = VFS_I(ip)->i_sb->s_dev; \
- __entry->ino = ip->i_ino; \
- __entry->size = ip->i_d.di_size; \
- __entry->new_size = ip->i_new_size; \
- __entry->offset = offset; \
- __entry->count = count; \
- ), \
- TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx " \
- "offset 0x%llx count %zd", \
- MAJOR(__entry->dev), MINOR(__entry->dev), \
- __entry->ino, \
- __entry->size, \
- __entry->new_size, \
- __entry->offset, \
- __entry->count) \
+DECLARE_EVENT_CLASS(xfs_simple_io_class,
+ TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count),
+ TP_ARGS(ip, offset, count),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(xfs_ino_t, ino)
+ __field(loff_t, size)
+ __field(loff_t, new_size)
+ __field(loff_t, offset)
+ __field(size_t, count)
+ ),
+ TP_fast_assign(
+ __entry->dev = VFS_I(ip)->i_sb->s_dev;
+ __entry->ino = ip->i_ino;
+ __entry->size = ip->i_d.di_size;
+ __entry->new_size = ip->i_new_size;
+ __entry->offset = offset;
+ __entry->count = count;
+ ),
+ TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx "
+ "offset 0x%llx count %zd",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __entry->ino,
+ __entry->size,
+ __entry->new_size,
+ __entry->offset,
+ __entry->count)
);
+
+#define DEFINE_SIMPLE_IO_EVENT(name) \
+DEFINE_EVENT(xfs_simple_io_class, name, \
+ TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), \
+ TP_ARGS(ip, offset, count))
DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc);
DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert);
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 38e764146644..2d8b7bc792c9 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -249,8 +249,10 @@ xfs_qm_hold_quotafs_ref(
if (!xfs_Gqm) {
xfs_Gqm = xfs_Gqm_init();
- if (!xfs_Gqm)
+ if (!xfs_Gqm) {
+ mutex_unlock(&xfs_Gqm_lock);
return ENOMEM;
+ }
}
/*
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 92b002f1805f..c9a43a149d58 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -786,9 +786,9 @@ xfs_qm_export_dquot(
}
#ifdef DEBUG
- if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == XFS_USER_QUOTA) ||
+ if (((XFS_IS_UQUOTA_ENFORCED(mp) && dst->d_flags == FS_USER_QUOTA) ||
(XFS_IS_OQUOTA_ENFORCED(mp) &&
- (dst->d_flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)))) &&
+ (dst->d_flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)))) &&
dst->d_id != 0) {
if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) &&
(dst->d_blk_softlimit > 0)) {
@@ -809,17 +809,17 @@ xfs_qm_export_qtype_flags(
/*
* Can't be more than one, or none.
*/
- ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) !=
- (XFS_PROJ_QUOTA | XFS_USER_QUOTA));
- ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) !=
- (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA));
- ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) !=
- (XFS_USER_QUOTA | XFS_GROUP_QUOTA));
- ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0);
+ ASSERT((flags & (FS_PROJ_QUOTA | FS_USER_QUOTA)) !=
+ (FS_PROJ_QUOTA | FS_USER_QUOTA));
+ ASSERT((flags & (FS_PROJ_QUOTA | FS_GROUP_QUOTA)) !=
+ (FS_PROJ_QUOTA | FS_GROUP_QUOTA));
+ ASSERT((flags & (FS_USER_QUOTA | FS_GROUP_QUOTA)) !=
+ (FS_USER_QUOTA | FS_GROUP_QUOTA));
+ ASSERT((flags & (FS_PROJ_QUOTA|FS_USER_QUOTA|FS_GROUP_QUOTA)) != 0);
return (flags & XFS_DQ_USER) ?
- XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
- XFS_PROJ_QUOTA : XFS_GROUP_QUOTA;
+ FS_USER_QUOTA : (flags & XFS_DQ_PROJ) ?
+ FS_PROJ_QUOTA : FS_GROUP_QUOTA;
}
STATIC uint
@@ -830,16 +830,16 @@ xfs_qm_export_flags(
uflags = 0;
if (flags & XFS_UQUOTA_ACCT)
- uflags |= XFS_QUOTA_UDQ_ACCT;
+ uflags |= FS_QUOTA_UDQ_ACCT;
if (flags & XFS_PQUOTA_ACCT)
- uflags |= XFS_QUOTA_PDQ_ACCT;
+ uflags |= FS_QUOTA_PDQ_ACCT;
if (flags & XFS_GQUOTA_ACCT)
- uflags |= XFS_QUOTA_GDQ_ACCT;
+ uflags |= FS_QUOTA_GDQ_ACCT;
if (flags & XFS_UQUOTA_ENFD)
- uflags |= XFS_QUOTA_UDQ_ENFD;
+ uflags |= FS_QUOTA_UDQ_ENFD;
if (flags & (XFS_OQUOTA_ENFD)) {
uflags |= (flags & XFS_GQUOTA_ACCT) ?
- XFS_QUOTA_GDQ_ENFD : XFS_QUOTA_PDQ_ENFD;
+ FS_QUOTA_GDQ_ENFD : FS_QUOTA_PDQ_ENFD;
}
return (uflags);
}
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index 401f364ad36c..4917d4eed4ed 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -227,7 +227,6 @@ typedef struct xfs_perag {
atomic_t pagf_fstrms; /* # of filestreams active in this AG */
- int pag_ici_init; /* incore inode cache initialised */
rwlock_t pag_ici_lock; /* incore inode lock */
struct radix_tree_root pag_ici_root; /* incore inode cache root */
int pag_ici_reclaimable; /* reclaimable inodes */
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 6845db90818f..75df75f43d48 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -382,9 +382,6 @@ xfs_iget(
/* get the perag structure and ensure that it's inode capable */
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
- if (!pag->pagi_inodeok)
- return EINVAL;
- ASSERT(pag->pag_ici_init);
agino = XFS_INO_TO_AGINO(mp, ino);
again:
@@ -744,30 +741,24 @@ xfs_ilock_demote(
}
#ifdef DEBUG
-/*
- * Debug-only routine, without additional rw_semaphore APIs, we can
- * now only answer requests regarding whether we hold the lock for write
- * (reader state is outside our visibility, we only track writer state).
- *
- * Note: this means !xfs_isilocked would give false positives, so don't do that.
- */
int
xfs_isilocked(
xfs_inode_t *ip,
uint lock_flags)
{
- if ((lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) ==
- XFS_ILOCK_EXCL) {
- if (!ip->i_lock.mr_writer)
- return 0;
+ if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) {
+ if (!(lock_flags & XFS_ILOCK_SHARED))
+ return !!ip->i_lock.mr_writer;
+ return rwsem_is_locked(&ip->i_lock.mr_lock);
}
- if ((lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) ==
- XFS_IOLOCK_EXCL) {
- if (!ip->i_iolock.mr_writer)
- return 0;
+ if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) {
+ if (!(lock_flags & XFS_IOLOCK_SHARED))
+ return !!ip->i_iolock.mr_writer;
+ return rwsem_is_locked(&ip->i_iolock.mr_lock);
}
- return 1;
+ ASSERT(0);
+ return 0;
}
#endif
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 8cd6e8d8fe9c..d53c39de7d05 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1940,10 +1940,10 @@ xfs_ifree_cluster(
int blks_per_cluster;
int nbufs;
int ninodes;
- int i, j, found, pre_flushed;
+ int i, j;
xfs_daddr_t blkno;
xfs_buf_t *bp;
- xfs_inode_t *ip, **ip_found;
+ xfs_inode_t *ip;
xfs_inode_log_item_t *iip;
xfs_log_item_t *lip;
struct xfs_perag *pag;
@@ -1960,114 +1960,97 @@ xfs_ifree_cluster(
nbufs = XFS_IALLOC_BLOCKS(mp) / blks_per_cluster;
}
- ip_found = kmem_alloc(ninodes * sizeof(xfs_inode_t *), KM_NOFS);
-
for (j = 0; j < nbufs; j++, inum += ninodes) {
+ int found = 0;
+
blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum),
XFS_INO_TO_AGBNO(mp, inum));
+ /*
+ * We obtain and lock the backing buffer first in the process
+ * here, as we have to ensure that any dirty inode that we
+ * can't get the flush lock on is attached to the buffer.
+ * If we scan the in-memory inodes first, then buffer IO can
+ * complete before we get a lock on it, and hence we may fail
+ * to mark all the active inodes on the buffer stale.
+ */
+ bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
+ mp->m_bsize * blks_per_cluster,
+ XBF_LOCK);
+
+ /*
+ * Walk the inodes already attached to the buffer and mark them
+ * stale. These will all have the flush locks held, so an
+ * in-memory inode walk can't lock them.
+ */
+ lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
+ while (lip) {
+ if (lip->li_type == XFS_LI_INODE) {
+ iip = (xfs_inode_log_item_t *)lip;
+ ASSERT(iip->ili_logged == 1);
+ lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
+ xfs_trans_ail_copy_lsn(mp->m_ail,
+ &iip->ili_flush_lsn,
+ &iip->ili_item.li_lsn);
+ xfs_iflags_set(iip->ili_inode, XFS_ISTALE);
+ found++;
+ }
+ lip = lip->li_bio_list;
+ }
/*
- * Look for each inode in memory and attempt to lock it,
- * we can be racing with flush and tail pushing here.
- * any inode we get the locks on, add to an array of
- * inode items to process later.
+ * For each inode in memory attempt to add it to the inode
+ * buffer and set it up for being staled on buffer IO
+ * completion. This is safe as we've locked out tail pushing
+ * and flushing by locking the buffer.
*
- * The get the buffer lock, we could beat a flush
- * or tail pushing thread to the lock here, in which
- * case they will go looking for the inode buffer
- * and fail, we need some other form of interlock
- * here.
+ * We have already marked every inode that was part of a
+ * transaction stale above, which means there is no point in
+ * even trying to lock them.
*/
- found = 0;
for (i = 0; i < ninodes; i++) {
read_lock(&pag->pag_ici_lock);
ip = radix_tree_lookup(&pag->pag_ici_root,
XFS_INO_TO_AGINO(mp, (inum + i)));
- /* Inode not in memory or we found it already,
- * nothing to do
- */
+ /* Inode not in memory or stale, nothing to do */
if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) {
read_unlock(&pag->pag_ici_lock);
continue;
}
- if (xfs_inode_clean(ip)) {
- read_unlock(&pag->pag_ici_lock);
- continue;
- }
-
- /* If we can get the locks then add it to the
- * list, otherwise by the time we get the bp lock
- * below it will already be attached to the
- * inode buffer.
- */
-
- /* This inode will already be locked - by us, lets
- * keep it that way.
- */
-
- if (ip == free_ip) {
- if (xfs_iflock_nowait(ip)) {
- xfs_iflags_set(ip, XFS_ISTALE);
- if (xfs_inode_clean(ip)) {
- xfs_ifunlock(ip);
- } else {
- ip_found[found++] = ip;
- }
- }
+ /* don't try to lock/unlock the current inode */
+ if (ip != free_ip &&
+ !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
read_unlock(&pag->pag_ici_lock);
continue;
}
+ read_unlock(&pag->pag_ici_lock);
- if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
- if (xfs_iflock_nowait(ip)) {
- xfs_iflags_set(ip, XFS_ISTALE);
-
- if (xfs_inode_clean(ip)) {
- xfs_ifunlock(ip);
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
- } else {
- ip_found[found++] = ip;
- }
- } else {
+ if (!xfs_iflock_nowait(ip)) {
+ if (ip != free_ip)
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- }
+ continue;
}
- read_unlock(&pag->pag_ici_lock);
- }
- bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno,
- mp->m_bsize * blks_per_cluster,
- XBF_LOCK);
-
- pre_flushed = 0;
- lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *);
- while (lip) {
- if (lip->li_type == XFS_LI_INODE) {
- iip = (xfs_inode_log_item_t *)lip;
- ASSERT(iip->ili_logged == 1);
- lip->li_cb = (void(*)(xfs_buf_t*,xfs_log_item_t*)) xfs_istale_done;
- xfs_trans_ail_copy_lsn(mp->m_ail,
- &iip->ili_flush_lsn,
- &iip->ili_item.li_lsn);
- xfs_iflags_set(iip->ili_inode, XFS_ISTALE);
- pre_flushed++;
+ xfs_iflags_set(ip, XFS_ISTALE);
+ if (xfs_inode_clean(ip)) {
+ ASSERT(ip != free_ip);
+ xfs_ifunlock(ip);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ continue;
}
- lip = lip->li_bio_list;
- }
- for (i = 0; i < found; i++) {
- ip = ip_found[i];
iip = ip->i_itemp;
-
if (!iip) {
+ /* inode with unlogged changes only */
+ ASSERT(ip != free_ip);
ip->i_update_core = 0;
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
continue;
}
+ found++;
iip->ili_last_fields = iip->ili_format.ilf_fields;
iip->ili_format.ilf_fields = 0;
@@ -2078,17 +2061,16 @@ xfs_ifree_cluster(
xfs_buf_attach_iodone(bp,
(void(*)(xfs_buf_t*,xfs_log_item_t*))
xfs_istale_done, (xfs_log_item_t *)iip);
- if (ip != free_ip) {
+
+ if (ip != free_ip)
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- }
}
- if (found || pre_flushed)
+ if (found)
xfs_trans_stale_inode_buf(tp, bp);
xfs_trans_binval(tp, bp);
}
- kmem_free(ip_found);
xfs_perag_put(pag);
}
@@ -2649,8 +2631,6 @@ xfs_iflush_cluster(
int i;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
- ASSERT(pag->pagi_inodeok);
- ASSERT(pag->pag_ici_init);
inodes_per_cluster = XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog;
ilist_size = inodes_per_cluster * sizeof(xfs_inode_t *);
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 14a69aec2c0b..ed0684cc50ee 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -132,15 +132,10 @@ xlog_align(
int nbblks,
xfs_buf_t *bp)
{
- xfs_daddr_t offset;
- xfs_caddr_t ptr;
+ xfs_daddr_t offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1);
- offset = blk_no & ((xfs_daddr_t) log->l_sectBBsize - 1);
- ptr = XFS_BUF_PTR(bp) + BBTOB(offset);
-
- ASSERT(ptr + BBTOB(nbblks) <= XFS_BUF_PTR(bp) + XFS_BUF_SIZE(bp));
-
- return ptr;
+ ASSERT(BBTOB(offset + nbblks) <= XFS_BUF_SIZE(bp));
+ return XFS_BUF_PTR(bp) + BBTOB(offset);
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index d7bf38c8cd1c..d59f4e8bedcf 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -268,10 +268,10 @@ xfs_sb_validate_fsb_count(
#if XFS_BIG_BLKNOS /* Limited by ULONG_MAX of page cache index */
if (nblocks >> (PAGE_CACHE_SHIFT - sbp->sb_blocklog) > ULONG_MAX)
- return E2BIG;
+ return EFBIG;
#else /* Limited by UINT_MAX of sectors */
if (nblocks << (sbp->sb_blocklog - BBSHIFT) > UINT_MAX)
- return E2BIG;
+ return EFBIG;
#endif
return 0;
}
@@ -393,7 +393,7 @@ xfs_mount_validate_sb(
xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
xfs_fs_mount_cmn_err(flags,
"file system too large to be mounted on this system.");
- return XFS_ERROR(E2BIG);
+ return XFS_ERROR(EFBIG);
}
if (unlikely(sbp->sb_inprogress)) {
@@ -413,17 +413,6 @@ xfs_mount_validate_sb(
return 0;
}
-STATIC void
-xfs_initialize_perag_icache(
- xfs_perag_t *pag)
-{
- if (!pag->pag_ici_init) {
- rwlock_init(&pag->pag_ici_lock);
- INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
- pag->pag_ici_init = 1;
- }
-}
-
int
xfs_initialize_perag(
xfs_mount_t *mp,
@@ -436,13 +425,8 @@ xfs_initialize_perag(
xfs_agino_t agino;
xfs_ino_t ino;
xfs_sb_t *sbp = &mp->m_sb;
- xfs_ino_t max_inum = XFS_MAXINUMBER_32;
int error = -ENOMEM;
- /* Check to see if the filesystem can overflow 32 bit inodes */
- agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
- ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
-
/*
* Walk the current per-ag tree so we don't try to initialise AGs
* that already exist (growfs case). Allocate and insert all the
@@ -456,11 +440,18 @@ xfs_initialize_perag(
}
if (!first_initialised)
first_initialised = index;
+
pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
if (!pag)
goto out_unwind;
+ pag->pag_agno = index;
+ pag->pag_mount = mp;
+ rwlock_init(&pag->pag_ici_lock);
+ INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
+
if (radix_tree_preload(GFP_NOFS))
goto out_unwind;
+
spin_lock(&mp->m_perag_lock);
if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
BUG();
@@ -469,25 +460,26 @@ xfs_initialize_perag(
error = -EEXIST;
goto out_unwind;
}
- pag->pag_agno = index;
- pag->pag_mount = mp;
spin_unlock(&mp->m_perag_lock);
radix_tree_preload_end();
}
- /* Clear the mount flag if no inode can overflow 32 bits
- * on this filesystem, or if specifically requested..
+ /*
+ * If we mount with the inode64 option, or no inode overflows
+ * the legacy 32-bit address space clear the inode32 option.
*/
- if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > max_inum) {
+ agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0);
+ ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino);
+
+ if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32)
mp->m_flags |= XFS_MOUNT_32BITINODES;
- } else {
+ else
mp->m_flags &= ~XFS_MOUNT_32BITINODES;
- }
- /* If we can overflow then setup the ag headers accordingly */
if (mp->m_flags & XFS_MOUNT_32BITINODES) {
- /* Calculate how much should be reserved for inodes to
- * meet the max inode percentage.
+ /*
+ * Calculate how much should be reserved for inodes to meet
+ * the max inode percentage.
*/
if (mp->m_maxicount) {
__uint64_t icount;
@@ -500,30 +492,28 @@ xfs_initialize_perag(
} else {
max_metadata = agcount;
}
+
for (index = 0; index < agcount; index++) {
ino = XFS_AGINO_TO_INO(mp, index, agino);
- if (ino > max_inum) {
+ if (ino > XFS_MAXINUMBER_32) {
index++;
break;
}
- /* This ag is preferred for inodes */
pag = xfs_perag_get(mp, index);
pag->pagi_inodeok = 1;
if (index < max_metadata)
pag->pagf_metadata = 1;
- xfs_initialize_perag_icache(pag);
xfs_perag_put(pag);
}
} else {
- /* Setup default behavior for smaller filesystems */
for (index = 0; index < agcount; index++) {
pag = xfs_perag_get(mp, index);
pag->pagi_inodeok = 1;
- xfs_initialize_perag_icache(pag);
xfs_perag_put(pag);
}
}
+
if (maxagi)
*maxagi = index;
return 0;
@@ -1009,7 +999,7 @@ xfs_check_sizes(xfs_mount_t *mp)
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks);
if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) {
cmn_err(CE_WARN, "XFS: size check 1 failed");
- return XFS_ERROR(E2BIG);
+ return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_ddev_targp,
d - XFS_FSS_TO_BB(mp, 1),
@@ -1019,7 +1009,7 @@ xfs_check_sizes(xfs_mount_t *mp)
} else {
cmn_err(CE_WARN, "XFS: size check 2 failed");
if (error == ENOSPC)
- error = XFS_ERROR(E2BIG);
+ error = XFS_ERROR(EFBIG);
return error;
}
@@ -1027,7 +1017,7 @@ xfs_check_sizes(xfs_mount_t *mp)
d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks);
if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) {
cmn_err(CE_WARN, "XFS: size check 3 failed");
- return XFS_ERROR(E2BIG);
+ return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_logdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
@@ -1037,7 +1027,7 @@ xfs_check_sizes(xfs_mount_t *mp)
} else {
cmn_err(CE_WARN, "XFS: size check 3 failed");
if (error == ENOSPC)
- error = XFS_ERROR(E2BIG);
+ error = XFS_ERROR(EFBIG);
return error;
}
}
@@ -1254,7 +1244,7 @@ xfs_mountfs(
* Allocate and initialize the per-ag data.
*/
spin_lock_init(&mp->m_perag_lock);
- INIT_RADIX_TREE(&mp->m_perag_tree, GFP_NOFS);
+ INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC);
error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi);
if (error) {
cmn_err(CE_WARN, "XFS: Failed per-ag init: %d", error);
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 6be05f756d59..16445518506d 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -2247,7 +2247,7 @@ xfs_rtmount_init(
cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu",
(unsigned long long) XFS_BB_TO_FSB(mp, d),
(unsigned long long) mp->m_sb.sb_rblocks);
- return XFS_ERROR(E2BIG);
+ return XFS_ERROR(EFBIG);
}
error = xfs_read_buf(mp, mp->m_rtdev_targp,
d - XFS_FSB_TO_BB(mp, 1),
@@ -2256,7 +2256,7 @@ xfs_rtmount_init(
cmn_err(CE_WARN,
"XFS: realtime mount -- xfs_read_buf failed, returned %d", error);
if (error == ENOSPC)
- return XFS_ERROR(E2BIG);
+ return XFS_ERROR(EFBIG);
return error;
}
xfs_buf_relse(bp);
diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h
index b2d67adb6a08..ff614c29b441 100644
--- a/fs/xfs/xfs_rtalloc.h
+++ b/fs/xfs/xfs_rtalloc.h
@@ -147,7 +147,16 @@ xfs_growfs_rt(
# define xfs_rtfree_extent(t,b,l) (ENOSYS)
# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS)
# define xfs_growfs_rt(mp,in) (ENOSYS)
-# define xfs_rtmount_init(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
+static inline int /* error */
+xfs_rtmount_init(
+ xfs_mount_t *mp) /* file system mount structure */
+{
+ if (mp->m_sb.sb_rblocks == 0)
+ return 0;
+
+ cmn_err(CE_WARN, "XFS: Not built with CONFIG_XFS_RT");
+ return ENOSYS;
+}
# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS))
# define xfs_rtunmount_inodes(m)
#endif /* CONFIG_XFS_RT */
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index ce558efa2ea0..28547dfce037 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -48,134 +48,489 @@
kmem_zone_t *xfs_trans_zone;
+
/*
- * Reservation functions here avoid a huge stack in xfs_trans_init
- * due to register overflow from temporaries in the calculations.
+ * Various log reservation values.
+ *
+ * These are based on the size of the file system block because that is what
+ * most transactions manipulate. Each adds in an additional 128 bytes per
+ * item logged to try to account for the overhead of the transaction mechanism.
+ *
+ * Note: Most of the reservations underestimate the number of allocation
+ * groups into which they could free extents in the xfs_bmap_finish() call.
+ * This is because the number in the worst case is quite high and quite
+ * unusual. In order to fix this we need to change xfs_bmap_finish() to free
+ * extents in only a single AG at a time. This will require changes to the
+ * EFI code as well, however, so that the EFI for the extents not freed is
+ * logged again in each transaction. See SGI PV #261917.
+ *
+ * Reservation functions here avoid a huge stack in xfs_trans_init due to
+ * register overflow from temporaries in the calculations.
+ */
+
+
+/*
+ * In a write transaction we can allocate a maximum of 2
+ * extents. This gives:
+ * the inode getting the new extents: inode size
+ * the inode's bmap btree: max depth * block size
+ * the agfs of the ags from which the extents are allocated: 2 * sector
+ * the superblock free block counter: sector size
+ * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ * And the bmap_finish transaction can free bmap blocks in a join:
+ * the agfs of the ags containing the blocks: 2 * sector size
+ * the agfls of the ags containing the blocks: 2 * sector size
+ * the super block free block counter: sector size
+ * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
*/
STATIC uint
-xfs_calc_write_reservation(xfs_mount_t *mp)
+xfs_calc_write_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_WRITE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) +
+ 2 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 2) +
+ 128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 2))),
+ (2 * mp->m_sb.sb_sectsize +
+ 2 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 2) +
+ 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))));
}
+/*
+ * In truncating a file we free up to two extents at once. We can modify:
+ * the inode being truncated: inode size
+ * the inode's bmap btree: (max depth + 1) * block size
+ * And the bmap_finish transaction can free the blocks and bmap blocks:
+ * the agf for each of the ags: 4 * sector size
+ * the agfl for each of the ags: 4 * sector size
+ * the super block to reflect the freed blocks: sector size
+ * worst case split in allocation btrees per extent assuming 4 extents:
+ * 4 exts * 2 trees * (2 * max depth - 1) * block size
+ * the inode btree: max depth * blocksize
+ * the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_itruncate_reservation(xfs_mount_t *mp)
+xfs_calc_itruncate_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ITRUNCATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) +
+ 128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK))),
+ (4 * mp->m_sb.sb_sectsize +
+ 4 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 4) +
+ 128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4)) +
+ 128 * 5 +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1))));
}
+/*
+ * In renaming a files we can modify:
+ * the four inodes involved: 4 * inode size
+ * the two directory btrees: 2 * (max depth + v2) * dir block size
+ * the two directory bmap btrees: 2 * max depth * block size
+ * And the bmap_finish transaction can free dir and bmap blocks (two sets
+ * of bmap blocks) giving:
+ * the agf for the ags in which the blocks live: 3 * sector size
+ * the agfl for the ags in which the blocks live: 3 * sector size
+ * the superblock for the free block count: sector size
+ * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_rename_reservation(xfs_mount_t *mp)
+xfs_calc_rename_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_RENAME_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((4 * mp->m_sb.sb_inodesize +
+ 2 * XFS_DIROP_LOG_RES(mp) +
+ 128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp))),
+ (3 * mp->m_sb.sb_sectsize +
+ 3 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 3) +
+ 128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3))));
}
+/*
+ * For creating a link to an inode:
+ * the parent directory inode: inode size
+ * the linked inode: inode size
+ * the directory btree could split: (max depth + v2) * dir block size
+ * the directory bmap btree could join or split: (max depth + v2) * blocksize
+ * And the bmap_finish transaction can free some bmap blocks giving:
+ * the agf for the ag in which the blocks live: sector size
+ * the agfl for the ag in which the blocks live: sector size
+ * the superblock for the free block count: sector size
+ * the allocation btrees: 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_link_reservation(xfs_mount_t *mp)
+xfs_calc_link_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_LINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_inodesize +
+ XFS_DIROP_LOG_RES(mp) +
+ 128 * (2 + XFS_DIROP_LOG_COUNT(mp))),
+ (mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1))));
}
+/*
+ * For removing a directory entry we can modify:
+ * the parent directory inode: inode size
+ * the removed inode: inode size
+ * the directory btree could join: (max depth + v2) * dir block size
+ * the directory bmap btree could join or split: (max depth + v2) * blocksize
+ * And the bmap_finish transaction can free the dir and bmap blocks giving:
+ * the agf for the ag in which the blocks live: 2 * sector size
+ * the agfl for the ag in which the blocks live: 2 * sector size
+ * the superblock for the free block count: sector size
+ * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_remove_reservation(xfs_mount_t *mp)
+xfs_calc_remove_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_REMOVE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_inodesize +
+ XFS_DIROP_LOG_RES(mp) +
+ 128 * (2 + XFS_DIROP_LOG_COUNT(mp))),
+ (2 * mp->m_sb.sb_sectsize +
+ 2 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 2) +
+ 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))));
}
+/*
+ * For symlink we can modify:
+ * the parent directory inode: inode size
+ * the new inode: inode size
+ * the inode btree entry: 1 block
+ * the directory btree: (max depth + v2) * dir block size
+ * the directory inode's bmap btree: (max depth + v2) * block size
+ * the blocks for the symlink: 1 kB
+ * Or in the first xact we allocate some inodes giving:
+ * the agi and agf of the ag getting the new inodes: 2 * sectorsize
+ * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
+ * the inode btree: max depth * blocksize
+ * the allocation btrees: 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_symlink_reservation(xfs_mount_t *mp)
+xfs_calc_symlink_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_SYMLINK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_inodesize +
+ XFS_FSB_TO_B(mp, 1) +
+ XFS_DIROP_LOG_RES(mp) +
+ 1024 +
+ 128 * (4 + XFS_DIROP_LOG_COUNT(mp))),
+ (2 * mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, XFS_IALLOC_BLOCKS(mp)) +
+ XFS_FSB_TO_B(mp, mp->m_in_maxlevels) +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1))));
}
+/*
+ * For create we can modify:
+ * the parent directory inode: inode size
+ * the new inode: inode size
+ * the inode btree entry: block size
+ * the superblock for the nlink flag: sector size
+ * the directory btree: (max depth + v2) * dir block size
+ * the directory inode's bmap btree: (max depth + v2) * block size
+ * Or in the first xact we allocate some inodes giving:
+ * the agi and agf of the ag getting the new inodes: 2 * sectorsize
+ * the superblock for the nlink flag: sector size
+ * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
+ * the inode btree: max depth * blocksize
+ * the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_create_reservation(xfs_mount_t *mp)
+xfs_calc_create_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_CREATE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, 1) +
+ XFS_DIROP_LOG_RES(mp) +
+ 128 * (3 + XFS_DIROP_LOG_COUNT(mp))),
+ (3 * mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, XFS_IALLOC_BLOCKS(mp)) +
+ XFS_FSB_TO_B(mp, mp->m_in_maxlevels) +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1))));
}
+/*
+ * Making a new directory is the same as creating a new file.
+ */
STATIC uint
-xfs_calc_mkdir_reservation(xfs_mount_t *mp)
+xfs_calc_mkdir_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_MKDIR_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return xfs_calc_create_reservation(mp);
}
+/*
+ * In freeing an inode we can modify:
+ * the inode being freed: inode size
+ * the super block free inode counter: sector size
+ * the agi hash list and counters: sector size
+ * the inode btree entry: block size
+ * the on disk inode before ours in the agi hash list: inode cluster size
+ * the inode btree: max depth * blocksize
+ * the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_ifree_reservation(xfs_mount_t *mp)
+xfs_calc_ifree_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_IFREE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, 1) +
+ MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
+ XFS_INODE_CLUSTER_SIZE(mp)) +
+ 128 * 5 +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (2 + XFS_IALLOC_BLOCKS(mp) + mp->m_in_maxlevels +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1));
}
+/*
+ * When only changing the inode we log the inode and possibly the superblock
+ * We also add a bit of slop for the transaction stuff.
+ */
STATIC uint
-xfs_calc_ichange_reservation(xfs_mount_t *mp)
+xfs_calc_ichange_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ICHANGE_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_sectsize +
+ 512;
+
}
+/*
+ * Growing the data section of the filesystem.
+ * superblock
+ * agi and agf
+ * allocation btrees
+ */
STATIC uint
-xfs_calc_growdata_reservation(xfs_mount_t *mp)
+xfs_calc_growdata_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_GROWDATA_LOG_RES(mp);
+ return mp->m_sb.sb_sectsize * 3 +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1));
}
+/*
+ * Growing the rt section of the filesystem.
+ * In the first set of transactions (ALLOC) we allocate space to the
+ * bitmap or summary files.
+ * superblock: sector size
+ * agf of the ag from which the extent is allocated: sector size
+ * bmap btree for bitmap/summary inode: max depth * blocksize
+ * bitmap/summary inode: inode size
+ * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize
+ */
STATIC uint
-xfs_calc_growrtalloc_reservation(xfs_mount_t *mp)
+xfs_calc_growrtalloc_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_GROWRTALLOC_LOG_RES(mp);
+ return 2 * mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) +
+ mp->m_sb.sb_inodesize +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1));
}
+/*
+ * Growing the rt section of the filesystem.
+ * In the second set of transactions (ZERO) we zero the new metadata blocks.
+ * one bitmap/summary block: blocksize
+ */
STATIC uint
-xfs_calc_growrtzero_reservation(xfs_mount_t *mp)
+xfs_calc_growrtzero_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_GROWRTZERO_LOG_RES(mp);
+ return mp->m_sb.sb_blocksize + 128;
}
+/*
+ * Growing the rt section of the filesystem.
+ * In the third set of transactions (FREE) we update metadata without
+ * allocating any new blocks.
+ * superblock: sector size
+ * bitmap inode: inode size
+ * summary inode: inode size
+ * one bitmap block: blocksize
+ * summary blocks: new summary size
+ */
STATIC uint
-xfs_calc_growrtfree_reservation(xfs_mount_t *mp)
+xfs_calc_growrtfree_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_GROWRTFREE_LOG_RES(mp);
+ return mp->m_sb.sb_sectsize +
+ 2 * mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_blocksize +
+ mp->m_rsumsize +
+ 128 * 5;
}
+/*
+ * Logging the inode modification timestamp on a synchronous write.
+ * inode
+ */
STATIC uint
-xfs_calc_swrite_reservation(xfs_mount_t *mp)
+xfs_calc_swrite_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_SWRITE_LOG_RES(mp);
+ return mp->m_sb.sb_inodesize + 128;
}
+/*
+ * Logging the inode mode bits when writing a setuid/setgid file
+ * inode
+ */
STATIC uint
xfs_calc_writeid_reservation(xfs_mount_t *mp)
{
- return XFS_CALC_WRITEID_LOG_RES(mp);
+ return mp->m_sb.sb_inodesize + 128;
}
+/*
+ * Converting the inode from non-attributed to attributed.
+ * the inode being converted: inode size
+ * agf block and superblock (for block allocation)
+ * the new block (directory sized)
+ * bmap blocks for the new directory block
+ * allocation btrees
+ */
STATIC uint
-xfs_calc_addafork_reservation(xfs_mount_t *mp)
+xfs_calc_addafork_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ADDAFORK_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_sectsize * 2 +
+ mp->m_dirblksize +
+ XFS_FSB_TO_B(mp, XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) +
+ XFS_ALLOCFREE_LOG_RES(mp, 1) +
+ 128 * (4 + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1 +
+ XFS_ALLOCFREE_LOG_COUNT(mp, 1));
}
+/*
+ * Removing the attribute fork of a file
+ * the inode being truncated: inode size
+ * the inode's bmap btree: max depth * block size
+ * And the bmap_finish transaction can free the blocks and bmap blocks:
+ * the agf for each of the ags: 4 * sector size
+ * the agfl for each of the ags: 4 * sector size
+ * the super block to reflect the freed blocks: sector size
+ * worst case split in allocation btrees per extent assuming 4 extents:
+ * 4 exts * 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_attrinval_reservation(xfs_mount_t *mp)
+xfs_calc_attrinval_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ATTRINVAL_LOG_RES(mp);
+ return MAX((mp->m_sb.sb_inodesize +
+ XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
+ 128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))),
+ (4 * mp->m_sb.sb_sectsize +
+ 4 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 4) +
+ 128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))));
}
+/*
+ * Setting an attribute.
+ * the inode getting the attribute
+ * the superblock for allocations
+ * the agfs extents are allocated from
+ * the attribute btree * max depth
+ * the inode allocation btree
+ * Since attribute transaction space is dependent on the size of the attribute,
+ * the calculation is done partially at mount time and partially at runtime.
+ */
STATIC uint
-xfs_calc_attrset_reservation(xfs_mount_t *mp)
+xfs_calc_attrset_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ATTRSET_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ mp->m_sb.sb_inodesize +
+ mp->m_sb.sb_sectsize +
+ XFS_FSB_TO_B(mp, XFS_DA_NODE_MAXDEPTH) +
+ 128 * (2 + XFS_DA_NODE_MAXDEPTH);
}
+/*
+ * Removing an attribute.
+ * the inode: inode size
+ * the attribute btree could join: max depth * block size
+ * the inode bmap btree could join or split: max depth * block size
+ * And the bmap_finish transaction can free the attr blocks freed giving:
+ * the agf for the ag in which the blocks live: 2 * sector size
+ * the agfl for the ag in which the blocks live: 2 * sector size
+ * the superblock for the free block count: sector size
+ * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ */
STATIC uint
-xfs_calc_attrrm_reservation(xfs_mount_t *mp)
+xfs_calc_attrrm_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_ATTRRM_LOG_RES(mp) + XFS_DQUOT_LOGRES(mp);
+ return XFS_DQUOT_LOGRES(mp) +
+ MAX((mp->m_sb.sb_inodesize +
+ XFS_FSB_TO_B(mp, XFS_DA_NODE_MAXDEPTH) +
+ XFS_FSB_TO_B(mp, XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
+ 128 * (1 + XFS_DA_NODE_MAXDEPTH +
+ XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK))),
+ (2 * mp->m_sb.sb_sectsize +
+ 2 * mp->m_sb.sb_sectsize +
+ mp->m_sb.sb_sectsize +
+ XFS_ALLOCFREE_LOG_RES(mp, 2) +
+ 128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))));
}
+/*
+ * Clearing a bad agino number in an agi hash bucket.
+ */
STATIC uint
-xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp)
+xfs_calc_clear_agi_bucket_reservation(
+ struct xfs_mount *mp)
{
- return XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp);
+ return mp->m_sb.sb_sectsize + 128;
}
/*
@@ -184,11 +539,10 @@ xfs_calc_clear_agi_bucket_reservation(xfs_mount_t *mp)
*/
void
xfs_trans_init(
- xfs_mount_t *mp)
+ struct xfs_mount *mp)
{
- xfs_trans_reservations_t *resp;
+ struct xfs_trans_reservations *resp = &mp->m_reservations;
- resp = &(mp->m_reservations);
resp->tr_write = xfs_calc_write_reservation(mp);
resp->tr_itruncate = xfs_calc_itruncate_reservation(mp);
resp->tr_rename = xfs_calc_rename_reservation(mp);
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 8c69e7824f68..e639e8e9a2a9 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -300,24 +300,6 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
/*
- * Various log reservation values.
- * These are based on the size of the file system block
- * because that is what most transactions manipulate.
- * Each adds in an additional 128 bytes per item logged to
- * try to account for the overhead of the transaction mechanism.
- *
- * Note:
- * Most of the reservations underestimate the number of allocation
- * groups into which they could free extents in the xfs_bmap_finish()
- * call. This is because the number in the worst case is quite high
- * and quite unusual. In order to fix this we need to change
- * xfs_bmap_finish() to free extents in only a single AG at a time.
- * This will require changes to the EFI code as well, however, so that
- * the EFI for the extents not freed is logged again in each transaction.
- * See bug 261917.
- */
-
-/*
* Per-extent log reservation for the allocation btree changes
* involved in freeing or allocating an extent.
* 2 trees * (2 blocks/level * max depth - 1) * block size
@@ -341,429 +323,36 @@ xfs_lic_desc_to_chunk(xfs_log_item_desc_t *dp)
(XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \
XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1)
-/*
- * In a write transaction we can allocate a maximum of 2
- * extents. This gives:
- * the inode getting the new extents: inode size
- * the inode's bmap btree: max depth * block size
- * the agfs of the ags from which the extents are allocated: 2 * sector
- * the superblock free block counter: sector size
- * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- * And the bmap_finish transaction can free bmap blocks in a join:
- * the agfs of the ags containing the blocks: 2 * sector size
- * the agfls of the ags containing the blocks: 2 * sector size
- * the super block free block counter: sector size
- * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_WRITE_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \
- (2 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 2) + \
- (128 * (4 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + XFS_ALLOCFREE_LOG_COUNT(mp, 2)))),\
- ((2 * (mp)->m_sb.sb_sectsize) + \
- (2 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 2) + \
- (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))))))
#define XFS_WRITE_LOG_RES(mp) ((mp)->m_reservations.tr_write)
-
-/*
- * In truncating a file we free up to two extents at once. We can modify:
- * the inode being truncated: inode size
- * the inode's bmap btree: (max depth + 1) * block size
- * And the bmap_finish transaction can free the blocks and bmap blocks:
- * the agf for each of the ags: 4 * sector size
- * the agfl for each of the ags: 4 * sector size
- * the super block to reflect the freed blocks: sector size
- * worst case split in allocation btrees per extent assuming 4 extents:
- * 4 exts * 2 trees * (2 * max depth - 1) * block size
- * the inode btree: max depth * blocksize
- * the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-#define XFS_CALC_ITRUNCATE_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1) + \
- (128 * (2 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \
- ((4 * (mp)->m_sb.sb_sectsize) + \
- (4 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 4) + \
- (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))) + \
- (128 * 5) + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
-
#define XFS_ITRUNCATE_LOG_RES(mp) ((mp)->m_reservations.tr_itruncate)
-
-/*
- * In renaming a files we can modify:
- * the four inodes involved: 4 * inode size
- * the two directory btrees: 2 * (max depth + v2) * dir block size
- * the two directory bmap btrees: 2 * max depth * block size
- * And the bmap_finish transaction can free dir and bmap blocks (two sets
- * of bmap blocks) giving:
- * the agf for the ags in which the blocks live: 3 * sector size
- * the agfl for the ags in which the blocks live: 3 * sector size
- * the superblock for the free block count: sector size
- * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_RENAME_LOG_RES(mp) \
- (MAX( \
- ((4 * (mp)->m_sb.sb_inodesize) + \
- (2 * XFS_DIROP_LOG_RES(mp)) + \
- (128 * (4 + 2 * XFS_DIROP_LOG_COUNT(mp)))), \
- ((3 * (mp)->m_sb.sb_sectsize) + \
- (3 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 3) + \
- (128 * (7 + XFS_ALLOCFREE_LOG_COUNT(mp, 3))))))
-
#define XFS_RENAME_LOG_RES(mp) ((mp)->m_reservations.tr_rename)
-
-/*
- * For creating a link to an inode:
- * the parent directory inode: inode size
- * the linked inode: inode size
- * the directory btree could split: (max depth + v2) * dir block size
- * the directory bmap btree could join or split: (max depth + v2) * blocksize
- * And the bmap_finish transaction can free some bmap blocks giving:
- * the agf for the ag in which the blocks live: sector size
- * the agfl for the ag in which the blocks live: sector size
- * the superblock for the free block count: sector size
- * the allocation btrees: 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_LINK_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_inodesize + \
- XFS_DIROP_LOG_RES(mp) + \
- (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \
- ((mp)->m_sb.sb_sectsize + \
- (mp)->m_sb.sb_sectsize + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
-
#define XFS_LINK_LOG_RES(mp) ((mp)->m_reservations.tr_link)
-
-/*
- * For removing a directory entry we can modify:
- * the parent directory inode: inode size
- * the removed inode: inode size
- * the directory btree could join: (max depth + v2) * dir block size
- * the directory bmap btree could join or split: (max depth + v2) * blocksize
- * And the bmap_finish transaction can free the dir and bmap blocks giving:
- * the agf for the ag in which the blocks live: 2 * sector size
- * the agfl for the ag in which the blocks live: 2 * sector size
- * the superblock for the free block count: sector size
- * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_REMOVE_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_inodesize + \
- XFS_DIROP_LOG_RES(mp) + \
- (128 * (2 + XFS_DIROP_LOG_COUNT(mp)))), \
- ((2 * (mp)->m_sb.sb_sectsize) + \
- (2 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 2) + \
- (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))))))
-
#define XFS_REMOVE_LOG_RES(mp) ((mp)->m_reservations.tr_remove)
-
-/*
- * For symlink we can modify:
- * the parent directory inode: inode size
- * the new inode: inode size
- * the inode btree entry: 1 block
- * the directory btree: (max depth + v2) * dir block size
- * the directory inode's bmap btree: (max depth + v2) * block size
- * the blocks for the symlink: 1 kB
- * Or in the first xact we allocate some inodes giving:
- * the agi and agf of the ag getting the new inodes: 2 * sectorsize
- * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
- * the inode btree: max depth * blocksize
- * the allocation btrees: 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_SYMLINK_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_inodesize + \
- XFS_FSB_TO_B(mp, 1) + \
- XFS_DIROP_LOG_RES(mp) + \
- 1024 + \
- (128 * (4 + XFS_DIROP_LOG_COUNT(mp)))), \
- (2 * (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \
- XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
-
#define XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink)
-
-/*
- * For create we can modify:
- * the parent directory inode: inode size
- * the new inode: inode size
- * the inode btree entry: block size
- * the superblock for the nlink flag: sector size
- * the directory btree: (max depth + v2) * dir block size
- * the directory inode's bmap btree: (max depth + v2) * block size
- * Or in the first xact we allocate some inodes giving:
- * the agi and agf of the ag getting the new inodes: 2 * sectorsize
- * the superblock for the nlink flag: sector size
- * the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
- * the inode btree: max depth * blocksize
- * the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-#define XFS_CALC_CREATE_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B(mp, 1) + \
- XFS_DIROP_LOG_RES(mp) + \
- (128 * (3 + XFS_DIROP_LOG_COUNT(mp)))), \
- (3 * (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B((mp), XFS_IALLOC_BLOCKS((mp))) + \
- XFS_FSB_TO_B((mp), (mp)->m_in_maxlevels) + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))))
-
#define XFS_CREATE_LOG_RES(mp) ((mp)->m_reservations.tr_create)
-
-/*
- * Making a new directory is the same as creating a new file.
- */
-#define XFS_CALC_MKDIR_LOG_RES(mp) XFS_CALC_CREATE_LOG_RES(mp)
-
#define XFS_MKDIR_LOG_RES(mp) ((mp)->m_reservations.tr_mkdir)
-
-/*
- * In freeing an inode we can modify:
- * the inode being freed: inode size
- * the super block free inode counter: sector size
- * the agi hash list and counters: sector size
- * the inode btree entry: block size
- * the on disk inode before ours in the agi hash list: inode cluster size
- * the inode btree: max depth * blocksize
- * the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-#define XFS_CALC_IFREE_LOG_RES(mp) \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_sectsize + \
- (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B((mp), 1) + \
- MAX((__uint16_t)XFS_FSB_TO_B((mp), 1), XFS_INODE_CLUSTER_SIZE(mp)) + \
- (128 * 5) + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (2 + XFS_IALLOC_BLOCKS(mp) + (mp)->m_in_maxlevels + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
-
-
#define XFS_IFREE_LOG_RES(mp) ((mp)->m_reservations.tr_ifree)
-
-/*
- * When only changing the inode we log the inode and possibly the superblock
- * We also add a bit of slop for the transaction stuff.
- */
-#define XFS_CALC_ICHANGE_LOG_RES(mp) ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_sectsize + 512)
-
#define XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange)
-
-/*
- * Growing the data section of the filesystem.
- * superblock
- * agi and agf
- * allocation btrees
- */
-#define XFS_CALC_GROWDATA_LOG_RES(mp) \
- ((mp)->m_sb.sb_sectsize * 3 + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (3 + XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
-
#define XFS_GROWDATA_LOG_RES(mp) ((mp)->m_reservations.tr_growdata)
-
-/*
- * Growing the rt section of the filesystem.
- * In the first set of transactions (ALLOC) we allocate space to the
- * bitmap or summary files.
- * superblock: sector size
- * agf of the ag from which the extent is allocated: sector size
- * bmap btree for bitmap/summary inode: max depth * blocksize
- * bitmap/summary inode: inode size
- * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize
- */
-#define XFS_CALC_GROWRTALLOC_LOG_RES(mp) \
- (2 * (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)) + \
- (mp)->m_sb.sb_inodesize + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * \
- (3 + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
-
#define XFS_GROWRTALLOC_LOG_RES(mp) ((mp)->m_reservations.tr_growrtalloc)
-
-/*
- * Growing the rt section of the filesystem.
- * In the second set of transactions (ZERO) we zero the new metadata blocks.
- * one bitmap/summary block: blocksize
- */
-#define XFS_CALC_GROWRTZERO_LOG_RES(mp) \
- ((mp)->m_sb.sb_blocksize + 128)
-
#define XFS_GROWRTZERO_LOG_RES(mp) ((mp)->m_reservations.tr_growrtzero)
-
-/*
- * Growing the rt section of the filesystem.
- * In the third set of transactions (FREE) we update metadata without
- * allocating any new blocks.
- * superblock: sector size
- * bitmap inode: inode size
- * summary inode: inode size
- * one bitmap block: blocksize
- * summary blocks: new summary size
- */
-#define XFS_CALC_GROWRTFREE_LOG_RES(mp) \
- ((mp)->m_sb.sb_sectsize + \
- 2 * (mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_blocksize + \
- (mp)->m_rsumsize + \
- (128 * 5))
-
#define XFS_GROWRTFREE_LOG_RES(mp) ((mp)->m_reservations.tr_growrtfree)
-
-/*
- * Logging the inode modification timestamp on a synchronous write.
- * inode
- */
-#define XFS_CALC_SWRITE_LOG_RES(mp) \
- ((mp)->m_sb.sb_inodesize + 128)
-
#define XFS_SWRITE_LOG_RES(mp) ((mp)->m_reservations.tr_swrite)
-
/*
* Logging the inode timestamps on an fsync -- same as SWRITE
* as long as SWRITE logs the entire inode core
*/
#define XFS_FSYNC_TS_LOG_RES(mp) ((mp)->m_reservations.tr_swrite)
-
-/*
- * Logging the inode mode bits when writing a setuid/setgid file
- * inode
- */
-#define XFS_CALC_WRITEID_LOG_RES(mp) \
- ((mp)->m_sb.sb_inodesize + 128)
-
#define XFS_WRITEID_LOG_RES(mp) ((mp)->m_reservations.tr_swrite)
-
-/*
- * Converting the inode from non-attributed to attributed.
- * the inode being converted: inode size
- * agf block and superblock (for block allocation)
- * the new block (directory sized)
- * bmap blocks for the new directory block
- * allocation btrees
- */
-#define XFS_CALC_ADDAFORK_LOG_RES(mp) \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_sectsize * 2 + \
- (mp)->m_dirblksize + \
- XFS_FSB_TO_B(mp, (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1)) + \
- XFS_ALLOCFREE_LOG_RES(mp, 1) + \
- (128 * (4 + (XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1) + \
- XFS_ALLOCFREE_LOG_COUNT(mp, 1))))
-
#define XFS_ADDAFORK_LOG_RES(mp) ((mp)->m_reservations.tr_addafork)
-
-/*
- * Removing the attribute fork of a file
- * the inode being truncated: inode size
- * the inode's bmap btree: max depth * block size
- * And the bmap_finish transaction can free the blocks and bmap blocks:
- * the agf for each of the ags: 4 * sector size
- * the agfl for each of the ags: 4 * sector size
- * the super block to reflect the freed blocks: sector size
- * worst case split in allocation btrees per extent assuming 4 extents:
- * 4 exts * 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_ATTRINVAL_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \
- (128 * (1 + XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))), \
- ((4 * (mp)->m_sb.sb_sectsize) + \
- (4 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 4) + \
- (128 * (9 + XFS_ALLOCFREE_LOG_COUNT(mp, 4))))))
-
#define XFS_ATTRINVAL_LOG_RES(mp) ((mp)->m_reservations.tr_attrinval)
-
-/*
- * Setting an attribute.
- * the inode getting the attribute
- * the superblock for allocations
- * the agfs extents are allocated from
- * the attribute btree * max depth
- * the inode allocation btree
- * Since attribute transaction space is dependent on the size of the attribute,
- * the calculation is done partially at mount time and partially at runtime.
- */
-#define XFS_CALC_ATTRSET_LOG_RES(mp) \
- ((mp)->m_sb.sb_inodesize + \
- (mp)->m_sb.sb_sectsize + \
- XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \
- (128 * (2 + XFS_DA_NODE_MAXDEPTH)))
-
#define XFS_ATTRSET_LOG_RES(mp, ext) \
((mp)->m_reservations.tr_attrset + \
(ext * (mp)->m_sb.sb_sectsize) + \
(ext * XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK))) + \
(128 * (ext + (ext * XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)))))
-
-/*
- * Removing an attribute.
- * the inode: inode size
- * the attribute btree could join: max depth * block size
- * the inode bmap btree could join or split: max depth * block size
- * And the bmap_finish transaction can free the attr blocks freed giving:
- * the agf for the ag in which the blocks live: 2 * sector size
- * the agfl for the ag in which the blocks live: 2 * sector size
- * the superblock for the free block count: sector size
- * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-#define XFS_CALC_ATTRRM_LOG_RES(mp) \
- (MAX( \
- ((mp)->m_sb.sb_inodesize + \
- XFS_FSB_TO_B((mp), XFS_DA_NODE_MAXDEPTH) + \
- XFS_FSB_TO_B((mp), XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + \
- (128 * (1 + XFS_DA_NODE_MAXDEPTH + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK)))), \
- ((2 * (mp)->m_sb.sb_sectsize) + \
- (2 * (mp)->m_sb.sb_sectsize) + \
- (mp)->m_sb.sb_sectsize + \
- XFS_ALLOCFREE_LOG_RES(mp, 2) + \
- (128 * (5 + XFS_ALLOCFREE_LOG_COUNT(mp, 2))))))
-
#define XFS_ATTRRM_LOG_RES(mp) ((mp)->m_reservations.tr_attrrm)
-
-/*
- * Clearing a bad agino number in an agi hash bucket.
- */
-#define XFS_CALC_CLEAR_AGI_BUCKET_LOG_RES(mp) \
- ((mp)->m_sb.sb_sectsize + 128)
-
#define XFS_CLEAR_AGI_BUCKET_LOG_RES(mp) ((mp)->m_reservations.tr_clearagi)
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 9d376be0ea38..a06bd62504fc 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -267,7 +267,7 @@ xfs_setattr(
if (code) {
ASSERT(tp == NULL);
lock_flags &= ~XFS_ILOCK_EXCL;
- ASSERT(lock_flags == XFS_IOLOCK_EXCL);
+ ASSERT(lock_flags == XFS_IOLOCK_EXCL || !need_iolock);
goto error_return;
}
tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 5958d7845bd5..17714beb868e 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -212,7 +212,7 @@ char const *acpi_gbl_exception_names_env[] = {
"AE_NO_GLOBAL_LOCK",
"AE_ABORT_METHOD",
"AE_SAME_HANDLER",
- "AE_WAKE_ONLY_GPE",
+ "AE_NO_HANDLER",
"AE_OWNER_ID_LIMIT"
};
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 0e4ab1fe5966..8aaa596e1208 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -47,7 +47,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20100428
+#define ACPI_CA_VERSION 0x20100528
#include "actypes.h"
#include "actbl.h"
@@ -69,6 +69,7 @@ extern acpi_name acpi_gbl_trace_method_name;
extern u32 acpi_gbl_trace_flags;
extern u8 acpi_gbl_enable_aml_debug_object;
extern u8 acpi_gbl_copy_dsdt_locally;
+extern u8 acpi_gbl_truncate_io_addresses;
extern u32 acpi_current_gpe_count;
extern struct acpi_table_fadt acpi_gbl_FADT;
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
index 95f4d0ef4819..0a600b8e53f4 100644
--- a/include/acpi/actbl2.h
+++ b/include/acpi/actbl2.h
@@ -79,6 +79,15 @@
#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */
#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
+#ifdef ACPI_UNDEFINED_TABLES
+/*
+ * These tables have been seen in the field, but no definition has been found
+ */
+#define ACPI_SIG_ATKG "ATKG"
+#define ACPI_SIG_GSCI "GSCI" /* GMCH SCI table */
+#define ACPI_SIG_IEIT "IEIT"
+#endif
+
/*
* All tables must be byte-packed to match the ACPI specification, since
* the tables are provided by the system BIOS.
diff --git a/include/asm-generic/fcntl.h b/include/asm-generic/fcntl.h
index fcd268ce0674..e3cbc38bdcc2 100644
--- a/include/asm-generic/fcntl.h
+++ b/include/asm-generic/fcntl.h
@@ -3,6 +3,14 @@
#include <linux/types.h>
+/*
+ * FMODE_EXEC is 0x20
+ * FMODE_NONOTIFY is 0x1000000
+ * These cannot be used by userspace O_* until internal and external open
+ * flags are split.
+ * -Eric Paris
+ */
+
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 04f91c2d3f7b..b5043a9890d8 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -80,7 +80,7 @@ extern void setup_per_cpu_areas(void);
#ifndef PER_CPU_BASE_SECTION
#ifdef CONFIG_SMP
-#define PER_CPU_BASE_SECTION ".data.percpu"
+#define PER_CPU_BASE_SECTION ".data..percpu"
#else
#define PER_CPU_BASE_SECTION ".data"
#endif
@@ -92,15 +92,15 @@ extern void setup_per_cpu_areas(void);
#define PER_CPU_SHARED_ALIGNED_SECTION ""
#define PER_CPU_ALIGNED_SECTION ""
#else
-#define PER_CPU_SHARED_ALIGNED_SECTION ".shared_aligned"
-#define PER_CPU_ALIGNED_SECTION ".shared_aligned"
+#define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned"
+#define PER_CPU_ALIGNED_SECTION "..shared_aligned"
#endif
-#define PER_CPU_FIRST_SECTION ".first"
+#define PER_CPU_FIRST_SECTION "..first"
#else
#define PER_CPU_SHARED_ALIGNED_SECTION ""
-#define PER_CPU_ALIGNED_SECTION ".shared_aligned"
+#define PER_CPU_ALIGNED_SECTION "..shared_aligned"
#define PER_CPU_FIRST_SECTION ""
#endif
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 6a0b30f78a62..30218b4fa4e0 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -18,7 +18,7 @@
#define __SYSCALL(x, y)
#endif
-#if __BITS_PER_LONG == 32
+#if __BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT)
#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32)
#else
#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64)
@@ -241,8 +241,13 @@ __SYSCALL(__NR_sync, sys_sync)
__SYSCALL(__NR_fsync, sys_fsync)
#define __NR_fdatasync 83
__SYSCALL(__NR_fdatasync, sys_fdatasync)
+#ifdef __ARCH_WANT_SYNC_FILE_RANGE2
+#define __NR_sync_file_range2 84
+__SYSCALL(__NR_sync_file_range2, sys_sync_file_range2)
+#else
#define __NR_sync_file_range 84
-__SYSCALL(__NR_sync_file_range, sys_sync_file_range) /* .long sys_sync_file_range2, */
+__SYSCALL(__NR_sync_file_range, sys_sync_file_range)
+#endif
/* fs/timerfd.c */
#define __NR_timerfd_create 85
@@ -580,7 +585,7 @@ __SYSCALL(__NR_execve, sys_execve) /* .long sys_execve_wrapper */
__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap)
/* mm/fadvise.c */
#define __NR3264_fadvise64 223
-__SC_3264(__NR3264_fadvise64, sys_fadvise64_64, sys_fadvise64)
+__SYSCALL(__NR3264_fadvise64, sys_fadvise64_64)
/* mm/, CONFIG_MMU only */
#ifndef __ARCH_NOMMU
@@ -627,8 +632,14 @@ __SYSCALL(__NR_accept4, sys_accept4)
#define __NR_recvmmsg 243
__SYSCALL(__NR_recvmmsg, sys_recvmmsg)
+/*
+ * Architectures may provide up to 16 syscalls of their own
+ * starting with this value.
+ */
+#define __NR_arch_specific_syscall 244
+
#undef __NR_syscalls
-#define __NR_syscalls 244
+#define __NR_syscalls 260
/*
* All syscalls below here should go away really,
@@ -694,7 +705,8 @@ __SYSCALL(__NR_signalfd, sys_signalfd)
#define __NR_syscalls (__NR_signalfd+1)
#endif /* __ARCH_WANT_SYSCALL_NO_FLAGS */
-#if __BITS_PER_LONG == 32 && defined(__ARCH_WANT_SYSCALL_OFF_T)
+#if (__BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT)) && \
+ defined(__ARCH_WANT_SYSCALL_OFF_T)
#define __NR_sendfile 1046
__SYSCALL(__NR_sendfile, sys_sendfile)
#define __NR_ftruncate 1047
@@ -740,6 +752,7 @@ __SYSCALL(__NR_getpgrp, sys_getpgrp)
__SYSCALL(__NR_pause, sys_pause)
#define __NR_time 1062
#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_TIME
__SYSCALL(__NR_time, sys_time)
#define __NR_utime 1063
#define __ARCH_WANT_SYS_UTIME
@@ -801,7 +814,7 @@ __SYSCALL(__NR_fork, sys_ni_syscall)
* Here we map the numbers so that both versions
* use the same syscall table layout.
*/
-#if __BITS_PER_LONG == 64
+#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT)
#define __NR_fcntl __NR3264_fcntl
#define __NR_statfs __NR3264_statfs
#define __NR_fstatfs __NR3264_fstatfs
@@ -848,6 +861,7 @@ __SYSCALL(__NR_fork, sys_ni_syscall)
#endif
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
/*
* "Conditional" syscalls
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index ef779c6fc3d7..48c5299cbf26 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -175,25 +175,25 @@
#define NOSAVE_DATA \
. = ALIGN(PAGE_SIZE); \
VMLINUX_SYMBOL(__nosave_begin) = .; \
- *(.data.nosave) \
+ *(.data..nosave) \
. = ALIGN(PAGE_SIZE); \
VMLINUX_SYMBOL(__nosave_end) = .;
#define PAGE_ALIGNED_DATA(page_align) \
. = ALIGN(page_align); \
- *(.data.page_aligned)
+ *(.data..page_aligned)
#define READ_MOSTLY_DATA(align) \
. = ALIGN(align); \
- *(.data.read_mostly)
+ *(.data..read_mostly)
#define CACHELINE_ALIGNED_DATA(align) \
. = ALIGN(align); \
- *(.data.cacheline_aligned)
+ *(.data..cacheline_aligned)
#define INIT_TASK_DATA(align) \
. = ALIGN(align); \
- *(.data.init_task)
+ *(.data..init_task)
/*
* Read only Data
@@ -435,7 +435,7 @@
*/
#define INIT_TASK_DATA_SECTION(align) \
. = ALIGN(align); \
- .data.init_task : { \
+ .data..init_task : { \
INIT_TASK_DATA(align) \
}
@@ -499,7 +499,7 @@
#define BSS(bss_align) \
. = ALIGN(bss_align); \
.bss : AT(ADDR(.bss) - LOAD_OFFSET) { \
- *(.bss.page_aligned) \
+ *(.bss..page_aligned) \
*(.dynbss) \
*(.bss) \
*(COMMON) \
@@ -666,16 +666,16 @@
*/
#define PERCPU_VADDR(vaddr, phdr) \
VMLINUX_SYMBOL(__per_cpu_load) = .; \
- .data.percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \
+ .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \
- LOAD_OFFSET) { \
VMLINUX_SYMBOL(__per_cpu_start) = .; \
- *(.data.percpu.first) \
- *(.data.percpu.page_aligned) \
- *(.data.percpu) \
- *(.data.percpu.shared_aligned) \
+ *(.data..percpu..first) \
+ *(.data..percpu..page_aligned) \
+ *(.data..percpu) \
+ *(.data..percpu..shared_aligned) \
VMLINUX_SYMBOL(__per_cpu_end) = .; \
} phdr \
- . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data.percpu);
+ . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu);
/**
* PERCPU - define output section for percpu area, simple version
@@ -687,18 +687,18 @@
*
* This macro is equivalent to ALIGN(align); PERCPU_VADDR( , ) except
* that __per_cpu_load is defined as a relative symbol against
- * .data.percpu which is required for relocatable x86_32
+ * .data..percpu which is required for relocatable x86_32
* configuration.
*/
#define PERCPU(align) \
. = ALIGN(align); \
- .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { \
+ .data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__per_cpu_load) = .; \
VMLINUX_SYMBOL(__per_cpu_start) = .; \
- *(.data.percpu.first) \
- *(.data.percpu.page_aligned) \
- *(.data.percpu) \
- *(.data.percpu.shared_aligned) \
+ *(.data..percpu..first) \
+ *(.data..percpu..page_aligned) \
+ *(.data..percpu) \
+ *(.data..percpu..shared_aligned) \
VMLINUX_SYMBOL(__per_cpu_end) = .; \
}
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index dc5873c21e45..1121f7799c6f 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -130,4 +130,7 @@ extern int drm_helper_resume_force_mode(struct drm_device *dev);
extern void drm_kms_helper_poll_init(struct drm_device *dev);
extern void drm_kms_helper_poll_fini(struct drm_device *dev);
extern void drm_helper_hpd_irq_event(struct drm_device *dev);
+
+extern void drm_kms_helper_poll_disable(struct drm_device *dev);
+extern void drm_kms_helper_poll_enable(struct drm_device *dev);
#endif
diff --git a/include/drm/i915_drm.h b/include/drm/i915_drm.h
index b64a8d7cdf6d..7f0028e1010b 100644
--- a/include/drm/i915_drm.h
+++ b/include/drm/i915_drm.h
@@ -275,6 +275,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_HAS_OVERLAY 7
#define I915_PARAM_HAS_PAGEFLIPPING 8
#define I915_PARAM_HAS_EXECBUF2 9
+#define I915_PARAM_HAS_BSD 10
typedef struct drm_i915_getparam {
int param;
@@ -616,7 +617,9 @@ struct drm_i915_gem_execbuffer2 {
__u32 num_cliprects;
/** This is a struct drm_clip_rect *cliprects */
__u64 cliprects_ptr;
- __u64 flags; /* currently unused */
+#define I915_EXEC_RENDER (1<<0)
+#define I915_EXEC_BSD (1<<1)
+ __u64 flags;
__u64 rsvd1;
__u64 rsvd2;
};
diff --git a/include/drm/nouveau_drm.h b/include/drm/nouveau_drm.h
index a6a9f4af5ebd..fe917dee723a 100644
--- a/include/drm/nouveau_drm.h
+++ b/include/drm/nouveau_drm.h
@@ -79,6 +79,7 @@ struct drm_nouveau_gpuobj_free {
#define NOUVEAU_GETPARAM_CHIPSET_ID 11
#define NOUVEAU_GETPARAM_VM_VRAM_BASE 12
#define NOUVEAU_GETPARAM_GRAPH_UNITS 13
+#define NOUVEAU_GETPARAM_PTIMER_TIME 14
struct drm_nouveau_getparam {
uint64_t param;
uint64_t value;
diff --git a/include/drm/vmwgfx_drm.h b/include/drm/vmwgfx_drm.h
index c7645f480d12..4d0842391edc 100644
--- a/include/drm/vmwgfx_drm.h
+++ b/include/drm/vmwgfx_drm.h
@@ -50,6 +50,8 @@
#define DRM_VMW_EXECBUF 12
#define DRM_VMW_FIFO_DEBUG 13
#define DRM_VMW_FENCE_WAIT 14
+/* guarded by minor version >= 2 */
+#define DRM_VMW_UPDATE_LAYOUT 15
/*************************************************************************/
@@ -585,4 +587,28 @@ struct drm_vmw_stream_arg {
* sure that the stream has been stopped.
*/
+/*************************************************************************/
+/**
+ * DRM_VMW_UPDATE_LAYOUT - Update layout
+ *
+ * Updates the prefered modes and connection status for connectors. The
+ * command conisits of one drm_vmw_update_layout_arg pointing out a array
+ * of num_outputs drm_vmw_rect's.
+ */
+
+/**
+ * struct drm_vmw_update_layout_arg
+ *
+ * @num_outputs: number of active
+ * @rects: pointer to array of drm_vmw_rect
+ *
+ * Input argument to the DRM_VMW_UPDATE_LAYOUT Ioctl.
+ */
+
+struct drm_vmw_update_layout_arg {
+ uint32_t num_outputs;
+ uint32_t pad64;
+ uint64_t rects;
+};
+
#endif
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 2fc8e14cc24a..6af77937aed0 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -210,6 +210,7 @@ unifdef-y += ethtool.h
unifdef-y += eventpoll.h
unifdef-y += signalfd.h
unifdef-y += ext2_fs.h
+unifdef-y += fanotify.h
unifdef-y += fb.h
unifdef-y += fcntl.h
unifdef-y += filter.h
@@ -251,6 +252,7 @@ unifdef-y += in.h
unifdef-y += in6.h
unifdef-y += inotify.h
unifdef-y += input.h
+unifdef-y += ioq.h
unifdef-y += ip.h
unifdef-y += ipc.h
unifdef-y += ipmi.h
@@ -340,6 +342,7 @@ unifdef-y += serial_core.h
unifdef-y += serial.h
unifdef-y += serio.h
unifdef-y += shm.h
+unifdef-y += shm_signal.h
unifdef-y += signal.h
unifdef-y += smb_fs.h
unifdef-y += smb.h
@@ -366,6 +369,8 @@ unifdef-y += unistd.h
unifdef-y += usbdevice_fs.h
unifdef-y += utsname.h
unifdef-y += vhost.h
+unifdef-y += vbus_pci.h
+unifdef-y += venet.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += virtio_config.h
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index e6e0cb5437e6..aee5f6ce166e 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -106,7 +106,7 @@ int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
void bdi_unregister(struct backing_dev_info *bdi);
int bdi_setup_and_register(struct backing_dev_info *, char *, unsigned int);
void bdi_start_writeback(struct backing_dev_info *bdi, struct super_block *sb,
- long nr_pages, int sb_locked);
+ long nr_pages);
int bdi_writeback_task(struct bdi_writeback *wb);
int bdi_has_dirty_io(struct backing_dev_info *bdi);
void bdi_arm_supers_timer(void);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 8b7f5e0914ad..09a840264d6f 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1211,14 +1211,23 @@ struct work_struct;
int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
#ifdef CONFIG_BLK_CGROUP
+/*
+ * This should not be using sched_clock(). A real patch is in progress
+ * to fix this up, until that is in place we need to disable preemption
+ * around sched_clock() in this function and set_io_start_time_ns().
+ */
static inline void set_start_time_ns(struct request *req)
{
+ preempt_disable();
req->start_time_ns = sched_clock();
+ preempt_enable();
}
static inline void set_io_start_time_ns(struct request *req)
{
+ preempt_disable();
req->io_start_time_ns = sched_clock();
+ preempt_enable();
}
static inline uint64_t rq_start_time_ns(struct request *req)
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 1b9ba193b789..3f69054f86d9 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -203,12 +203,10 @@ int block_write_full_page_endio(struct page *page, get_block_t *get_block,
int block_read_full_page(struct page*, get_block_t*);
int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc,
unsigned long from);
-int block_write_begin_newtrunc(struct file *, struct address_space *,
- loff_t, unsigned, unsigned,
- struct page **, void **, get_block_t*);
-int block_write_begin(struct file *, struct address_space *,
- loff_t, unsigned, unsigned,
- struct page **, void **, get_block_t*);
+int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
+ unsigned flags, struct page **pagep, get_block_t *get_block);
+int __block_write_begin(struct page *page, loff_t pos, unsigned len,
+ get_block_t *get_block);
int block_write_end(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
struct page *, void *);
@@ -217,9 +215,6 @@ int generic_write_end(struct file *, struct address_space *,
struct page *, void *);
void page_zero_new_buffers(struct page *page, unsigned from, unsigned to);
int block_prepare_write(struct page*, unsigned, unsigned, get_block_t*);
-int cont_write_begin_newtrunc(struct file *, struct address_space *, loff_t,
- unsigned, unsigned, struct page **, void **,
- get_block_t *, loff_t *);
int cont_write_begin(struct file *, struct address_space *, loff_t,
unsigned, unsigned, struct page **, void **,
get_block_t *, loff_t *);
@@ -231,11 +226,7 @@ void block_sync_page(struct page *);
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
int block_truncate_page(struct address_space *, loff_t, get_block_t *);
int file_fsync(struct file *, int);
-int nobh_write_begin_newtrunc(struct file *, struct address_space *,
- loff_t, unsigned, unsigned,
- struct page **, void **, get_block_t*);
-int nobh_write_begin(struct file *, struct address_space *,
- loff_t, unsigned, unsigned,
+int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned,
struct page **, void **, get_block_t*);
int nobh_write_end(struct file *, struct address_space *,
loff_t, unsigned, unsigned,
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 97e24881c4c6..4c570653ab84 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -31,7 +31,7 @@
#ifndef __cacheline_aligned
#define __cacheline_aligned \
__attribute__((__aligned__(SMP_CACHE_BYTES), \
- __section__(".data.cacheline_aligned")))
+ __section__(".data..cacheline_aligned")))
#endif /* __cacheline_aligned */
#ifndef __cacheline_aligned_in_smp
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 9f15150ce8d6..c3e9de8321c6 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -196,11 +196,6 @@ extern int __cpufreq_driver_getavg(struct cpufreq_policy *policy,
int cpufreq_register_governor(struct cpufreq_governor *governor);
void cpufreq_unregister_governor(struct cpufreq_governor *governor);
-int lock_policy_rwsem_read(int cpu);
-int lock_policy_rwsem_write(int cpu);
-void unlock_policy_rwsem_read(int cpu);
-void unlock_policy_rwsem_write(int cpu);
-
/*********************************************************************
* CPUFREQ DRIVER INTERFACE *
diff --git a/include/linux/dnotify.h b/include/linux/dnotify.h
index ecc06286226d..3290555a52ee 100644
--- a/include/linux/dnotify.h
+++ b/include/linux/dnotify.h
@@ -28,6 +28,7 @@ struct dnotify_struct {
FS_CREATE | FS_DN_RENAME |\
FS_MOVED_FROM | FS_MOVED_TO)
+extern int dir_notify_enable;
extern void dnotify_flush(struct file *, fl_owner_t);
extern int fcntl_dirnotify(int, struct file *, unsigned long);
diff --git a/include/linux/dqblk_xfs.h b/include/linux/dqblk_xfs.h
index 4389ae72024e..86552807aed9 100644
--- a/include/linux/dqblk_xfs.h
+++ b/include/linux/dqblk_xfs.h
@@ -49,7 +49,7 @@
#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */
typedef struct fs_disk_quota {
__s8 d_version; /* version of this structure */
- __s8 d_flags; /* XFS_{USER,PROJ,GROUP}_QUOTA */
+ __s8 d_flags; /* FS_{USER,PROJ,GROUP}_QUOTA */
__u16 d_fieldmask; /* field specifier */
__u32 d_id; /* user, project, or group ID */
__u64 d_blk_hardlimit;/* absolute limit on disk blks */
@@ -119,18 +119,18 @@ typedef struct fs_disk_quota {
#define FS_DQ_ACCT_MASK (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT)
/*
- * Various flags related to quotactl(2). Only relevant to XFS filesystems.
+ * Various flags related to quotactl(2).
*/
-#define XFS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */
-#define XFS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */
-#define XFS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */
-#define XFS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */
-#define XFS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */
-#define XFS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */
+#define FS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */
+#define FS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */
+#define FS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */
+#define FS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */
+#define FS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */
+#define FS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */
-#define XFS_USER_QUOTA (1<<0) /* user quota type */
-#define XFS_PROJ_QUOTA (1<<1) /* project quota type */
-#define XFS_GROUP_QUOTA (1<<2) /* group quota type */
+#define FS_USER_QUOTA (1<<0) /* user quota type */
+#define FS_PROJ_QUOTA (1<<1) /* project quota type */
+#define FS_GROUP_QUOTA (1<<2) /* group quota type */
/*
* fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system.
@@ -151,7 +151,7 @@ typedef struct fs_qfilestat {
typedef struct fs_quota_stat {
__s8 qs_version; /* version number for future changes */
- __u16 qs_flags; /* XFS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
+ __u16 qs_flags; /* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */
__s8 qs_pad; /* unused */
fs_qfilestat_t qs_uquota; /* user quota storage information */
fs_qfilestat_t qs_gquota; /* group quota storage information */
diff --git a/include/linux/drbd.h b/include/linux/drbd.h
index 68530521ad00..30da4ae48972 100644
--- a/include/linux/drbd.h
+++ b/include/linux/drbd.h
@@ -53,7 +53,7 @@
extern const char *drbd_buildtag(void);
-#define REL_VERSION "8.3.8rc1"
+#define REL_VERSION "8.3.8rc2"
#define API_VERSION 88
#define PRO_VERSION_MIN 86
#define PRO_VERSION_MAX 94
diff --git a/include/linux/edac_mce.h b/include/linux/edac_mce.h
new file mode 100644
index 000000000000..f974fc035363
--- /dev/null
+++ b/include/linux/edac_mce.h
@@ -0,0 +1,31 @@
+/* Provides edac interface to mcelog events
+ *
+ * This file may be distributed under the terms of the
+ * GNU General Public License version 2.
+ *
+ * Copyright (c) 2009 by:
+ * Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Red Hat Inc. http://www.redhat.com
+ */
+
+#if defined(CONFIG_EDAC_MCE) || \
+ (defined(CONFIG_EDAC_MCE_MODULE) && defined(MODULE))
+
+#include <asm/mce.h>
+#include <linux/list.h>
+
+struct edac_mce {
+ struct list_head list;
+
+ void *priv;
+ int (*check_error)(void *priv, struct mce *mce);
+};
+
+int edac_mce_register(struct edac_mce *edac_mce);
+void edac_mce_unregister(struct edac_mce *edac_mce);
+int edac_mce_parse(struct mce *mce);
+
+#else
+#define edac_mce_parse(mce) (0)
+#endif
diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h
new file mode 100644
index 000000000000..f0949a57ca9d
--- /dev/null
+++ b/include/linux/fanotify.h
@@ -0,0 +1,105 @@
+#ifndef _LINUX_FANOTIFY_H
+#define _LINUX_FANOTIFY_H
+
+#include <linux/types.h>
+
+/* the following events that user-space can register for */
+#define FAN_ACCESS 0x00000001 /* File was accessed */
+#define FAN_MODIFY 0x00000002 /* File was modified */
+#define FAN_CLOSE_WRITE 0x00000008 /* Unwrittable file closed */
+#define FAN_CLOSE_NOWRITE 0x00000010 /* Writtable file closed */
+#define FAN_OPEN 0x00000020 /* File was opened */
+
+#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */
+
+/* FIXME currently Q's have no limit.... */
+#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
+
+#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
+#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
+
+/* helper events */
+#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
+
+/* flags used for fanotify_init() */
+#define FAN_CLOEXEC 0x00000001
+#define FAN_NONBLOCK 0x00000002
+
+#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK)
+
+/* flags used for fanotify_modify_mark() */
+#define FAN_MARK_ADD 0x00000001
+#define FAN_MARK_REMOVE 0x00000002
+#define FAN_MARK_DONT_FOLLOW 0x00000004
+#define FAN_MARK_ONLYDIR 0x00000008
+#define FAN_MARK_MOUNT 0x00000010
+#define FAN_MARK_IGNORED_MASK 0x00000020
+#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
+#define FAN_MARK_FLUSH 0x00000080
+
+#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
+ FAN_MARK_REMOVE |\
+ FAN_MARK_DONT_FOLLOW |\
+ FAN_MARK_ONLYDIR |\
+ FAN_MARK_MOUNT |\
+ FAN_MARK_IGNORED_MASK |\
+ FAN_MARK_IGNORED_SURV_MODIFY)
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility. Apps will get only the
+ * events that they originally wanted. Be sure to add new events here!
+ */
+#define FAN_ALL_EVENTS (FAN_ACCESS |\
+ FAN_MODIFY |\
+ FAN_CLOSE |\
+ FAN_OPEN)
+
+/*
+ * All events which require a permission response from userspace
+ */
+#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
+ FAN_ACCESS_PERM)
+
+#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\
+ FAN_ALL_PERM_EVENTS |\
+ FAN_Q_OVERFLOW)
+
+#define FANOTIFY_METADATA_VERSION 1
+
+struct fanotify_event_metadata {
+ __u32 event_len;
+ __u32 vers;
+ __s32 fd;
+ __u64 mask;
+ __s64 pid;
+} __attribute__ ((packed));
+
+struct fanotify_response {
+ __s32 fd;
+ __u32 response;
+} __attribute__ ((packed));
+
+/* Legit userspace responses to a _PERM event */
+#define FAN_ALLOW 0x01
+#define FAN_DENY 0x02
+
+/* Helper functions to deal with fanotify_event_metadata buffers */
+#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
+
+#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
+ (struct fanotify_event_metadata*)(((char *)(meta)) + \
+ (meta)->event_len))
+
+#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
+ (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
+ (long)(meta)->event_len <= (long)(len))
+
+#ifdef __KERNEL__
+
+struct fanotify_wait {
+ struct fsnotify_event *event;
+ __s32 fd;
+};
+#endif /* __KERNEL__ */
+#endif /* _LINUX_FANOTIFY_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 3428393942a6..9464c75dbcee 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -90,6 +90,9 @@ struct inodes_stat_t {
/* Expect random access pattern */
#define FMODE_RANDOM ((__force fmode_t)0x1000)
+/* File was opened by fanotify and shouldn't generate fanotify events */
+#define FMODE_NONOTIFY ((__force fmode_t)16777216) /* 0x1000000 */
+
/*
* The below are the various read and write types that we support. Some of
* them include behavioral modifiers that send information down to the
@@ -407,9 +410,6 @@ extern int get_max_files(void);
extern int sysctl_nr_open;
extern struct inodes_stat_t inodes_stat;
extern int leases_enable, lease_break_time;
-#ifdef CONFIG_DNOTIFY
-extern int dir_notify_enable;
-#endif
struct buffer_head;
typedef int (get_block_t)(struct inode *inode, sector_t iblock,
@@ -768,12 +768,7 @@ struct inode {
#ifdef CONFIG_FSNOTIFY
__u32 i_fsnotify_mask; /* all events this inode cares about */
- struct hlist_head i_fsnotify_mark_entries; /* fsnotify mark entries */
-#endif
-
-#ifdef CONFIG_INOTIFY
- struct list_head inotify_watches; /* watches on this inode */
- struct mutex inotify_mutex; /* protects the watches list */
+ struct hlist_head i_fsnotify_marks;
#endif
unsigned long i_state;
@@ -2255,16 +2250,6 @@ static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
struct bio;
typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode,
loff_t file_offset);
-void dio_end_io(struct bio *bio, int error);
-
-ssize_t __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode,
- struct block_device *bdev, const struct iovec *iov, loff_t offset,
- unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
- dio_submit_t submit_io, int lock_type);
-ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
- struct block_device *bdev, const struct iovec *iov, loff_t offset,
- unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
- dio_submit_t submit_io, int lock_type);
enum {
/* need locking between buffered and direct access */
@@ -2274,24 +2259,13 @@ enum {
DIO_SKIP_HOLES = 0x02,
};
-static inline ssize_t blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb,
- struct inode *inode, struct block_device *bdev, const struct iovec *iov,
- loff_t offset, unsigned long nr_segs, get_block_t get_block,
- dio_iodone_t end_io)
-{
- return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
- nr_segs, get_block, end_io, NULL,
- DIO_LOCKING | DIO_SKIP_HOLES);
-}
+void dio_end_io(struct bio *bio, int error);
+
+ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
+ struct block_device *bdev, const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
+ dio_submit_t submit_io, int flags);
-static inline ssize_t blockdev_direct_IO_no_locking_newtrunc(int rw, struct kiocb *iocb,
- struct inode *inode, struct block_device *bdev, const struct iovec *iov,
- loff_t offset, unsigned long nr_segs, get_block_t get_block,
- dio_iodone_t end_io)
-{
- return __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, offset,
- nr_segs, get_block, end_io, NULL, 0);
-}
static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
struct inode *inode, struct block_device *bdev, const struct iovec *iov,
loff_t offset, unsigned long nr_segs, get_block_t get_block,
@@ -2301,15 +2275,6 @@ static inline ssize_t blockdev_direct_IO(int rw, struct kiocb *iocb,
nr_segs, get_block, end_io, NULL,
DIO_LOCKING | DIO_SKIP_HOLES);
}
-
-static inline ssize_t blockdev_direct_IO_no_locking(int rw, struct kiocb *iocb,
- struct inode *inode, struct block_device *bdev, const struct iovec *iov,
- loff_t offset, unsigned long nr_segs, get_block_t get_block,
- dio_iodone_t end_io)
-{
- return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
- nr_segs, get_block, end_io, NULL, 0);
-}
#endif
extern const struct file_operations generic_ro_fops;
@@ -2371,7 +2336,6 @@ extern int simple_link(struct dentry *, struct inode *, struct dentry *);
extern int simple_unlink(struct inode *, struct dentry *);
extern int simple_rmdir(struct inode *, struct dentry *);
extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
-extern int simple_setsize(struct inode *, loff_t);
extern int noop_fsync(struct file *, int);
extern int simple_empty(struct dentry *);
extern int simple_readpage(struct file *file, struct page *page);
@@ -2388,7 +2352,7 @@ extern const struct file_operations simple_dir_operations;
extern const struct inode_operations simple_dir_inode_operations;
struct tree_descr { char *name; const struct file_operations *ops; int mode; };
struct dentry *d_alloc_name(struct dentry *, const char *);
-extern int simple_fill_super(struct super_block *, int, struct tree_descr *);
+extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *);
extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count);
extern void simple_release_fs(struct vfsmount **mount, int *count);
@@ -2408,8 +2372,7 @@ extern int buffer_migrate_page(struct address_space *,
extern int inode_change_ok(const struct inode *, struct iattr *);
extern int inode_newsize_ok(const struct inode *, loff_t offset);
-extern int __must_check inode_setattr(struct inode *, const struct iattr *);
-extern void generic_setattr(struct inode *inode, const struct iattr *attr);
+extern void setattr_copy(struct inode *inode, const struct iattr *attr);
extern void file_update_time(struct file *file);
@@ -2500,7 +2463,8 @@ int proc_nr_files(struct ctl_table *table, int write,
int __init get_filesystem_list(char *buf);
#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE])
-#define OPEN_FMODE(flag) ((__force fmode_t)((flag + 1) & O_ACCMODE))
+#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
+ (flag & FMODE_NONOTIFY)))
#endif /* __KERNEL__ */
#endif /* _LINUX_FS_H */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 01755909ce81..59d0df43ff9d 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -11,8 +11,6 @@
* (C) Copyright 2005 Robert Love
*/
-#include <linux/dnotify.h>
-#include <linux/inotify.h>
#include <linux/fsnotify_backend.h>
#include <linux/audit.h>
#include <linux/slab.h>
@@ -21,35 +19,53 @@
* fsnotify_d_instantiate - instantiate a dentry for inode
* Called with dcache_lock held.
*/
-static inline void fsnotify_d_instantiate(struct dentry *entry,
- struct inode *inode)
+static inline void fsnotify_d_instantiate(struct dentry *dentry,
+ struct inode *inode)
{
- __fsnotify_d_instantiate(entry, inode);
-
- inotify_d_instantiate(entry, inode);
+ __fsnotify_d_instantiate(dentry, inode);
}
/* Notify this dentry's parent about a child's events. */
-static inline void fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{
- __fsnotify_parent(dentry, mask);
+ if (!dentry)
+ dentry = path->dentry;
+
+ __fsnotify_parent(path, dentry, mask);
+}
- inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
+/* simple call site for access decisions */
+static inline int fsnotify_perm(struct file *file, int mask)
+{
+ struct path *path = &file->f_path;
+ struct inode *inode = path->dentry->d_inode;
+ __u32 fsnotify_mask = 0;
+
+ if (file->f_mode & FMODE_NONOTIFY)
+ return 0;
+ if (!(mask & (MAY_READ | MAY_OPEN)))
+ return 0;
+ if (mask & MAY_OPEN)
+ fsnotify_mask = FS_OPEN_PERM;
+ else if (mask & MAY_READ)
+ fsnotify_mask = FS_ACCESS_PERM;
+ else
+ BUG();
+
+ return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
}
/*
- * fsnotify_d_move - entry has been moved
- * Called with dcache_lock and entry->d_lock held.
+ * fsnotify_d_move - dentry has been moved
+ * Called with dcache_lock and dentry->d_lock held.
*/
-static inline void fsnotify_d_move(struct dentry *entry)
+static inline void fsnotify_d_move(struct dentry *dentry)
{
/*
- * On move we need to update entry->d_flags to indicate if the new parent
- * cares about events from this entry.
+ * On move we need to update dentry->d_flags to indicate if the new parent
+ * cares about events from this dentry.
*/
- __fsnotify_update_dcache_flags(entry);
-
- inotify_d_move(entry);
+ __fsnotify_update_dcache_flags(dentry);
}
/*
@@ -57,8 +73,6 @@ static inline void fsnotify_d_move(struct dentry *entry)
*/
static inline void fsnotify_link_count(struct inode *inode)
{
- inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
-
fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
@@ -66,45 +80,31 @@ static inline void fsnotify_link_count(struct inode *inode)
* fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
*/
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
- const char *old_name,
+ const unsigned char *old_name,
int isdir, struct inode *target, struct dentry *moved)
{
struct inode *source = moved->d_inode;
- u32 in_cookie = inotify_get_cookie();
u32 fs_cookie = fsnotify_get_cookie();
__u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM);
__u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO);
- const char *new_name = moved->d_name.name;
+ const unsigned char *new_name = moved->d_name.name;
if (old_dir == new_dir)
old_dir_mask |= FS_DN_RENAME;
if (isdir) {
- isdir = IN_ISDIR;
old_dir_mask |= FS_IN_ISDIR;
new_dir_mask |= FS_IN_ISDIR;
}
- inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, in_cookie, old_name,
- source);
- inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, in_cookie, new_name,
- source);
-
fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name, fs_cookie);
- if (target) {
- inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
- inotify_inode_is_dead(target);
-
- /* this is really a link_count change not a removal */
+ if (target)
fsnotify_link_count(target);
- }
- if (source) {
- inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
+ if (source)
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
- }
audit_inode_child(moved, new_dir);
}
@@ -117,6 +117,14 @@ static inline void fsnotify_inode_delete(struct inode *inode)
}
/*
+ * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed
+ */
+static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt)
+{
+ __fsnotify_vfsmount_delete(mnt);
+}
+
+/*
* fsnotify_nameremove - a filename was removed from a directory
*/
static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
@@ -126,7 +134,7 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
if (isdir)
mask |= FS_IN_ISDIR;
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
}
/*
@@ -134,9 +142,6 @@ static inline void fsnotify_nameremove(struct dentry *dentry, int isdir)
*/
static inline void fsnotify_inoderemove(struct inode *inode)
{
- inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
- inotify_inode_is_dead(inode);
-
fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
__fsnotify_inode_delete(inode);
}
@@ -146,8 +151,6 @@ static inline void fsnotify_inoderemove(struct inode *inode)
*/
static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{
- inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
- dentry->d_inode);
audit_inode_child(dentry, inode);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
@@ -160,8 +163,6 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
*/
static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry)
{
- inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
- inode);
fsnotify_link_count(inode);
audit_inode_child(new_dentry, dir);
@@ -176,7 +177,6 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
__u32 mask = (FS_CREATE | FS_IN_ISDIR);
struct inode *d_inode = dentry->d_inode;
- inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
audit_inode_child(dentry, inode);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
@@ -185,52 +185,55 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
/*
* fsnotify_access - file was read
*/
-static inline void fsnotify_access(struct dentry *dentry)
+static inline void fsnotify_access(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct path *path = &file->f_path;
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_ACCESS;
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
-
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ if (!(file->f_mode & FMODE_NONOTIFY)) {
+ fsnotify_parent(path, NULL, mask);
+ fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
+ }
}
/*
* fsnotify_modify - file was modified
*/
-static inline void fsnotify_modify(struct dentry *dentry)
+static inline void fsnotify_modify(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct path *path = &file->f_path;
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_MODIFY;
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
-
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ if (!(file->f_mode & FMODE_NONOTIFY)) {
+ fsnotify_parent(path, NULL, mask);
+ fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
+ }
}
/*
* fsnotify_open - file was opened
*/
-static inline void fsnotify_open(struct dentry *dentry)
+static inline void fsnotify_open(struct file *file)
{
- struct inode *inode = dentry->d_inode;
+ struct path *path = &file->f_path;
+ struct inode *inode = path->dentry->d_inode;
__u32 mask = FS_OPEN;
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
-
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
+ if (!(file->f_mode & FMODE_NONOTIFY)) {
+ fsnotify_parent(path, NULL, mask);
+ fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
+ }
}
/*
@@ -238,18 +241,18 @@ static inline void fsnotify_open(struct dentry *dentry)
*/
static inline void fsnotify_close(struct file *file)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct path *path = &file->f_path;
+ struct inode *inode = file->f_path.dentry->d_inode;
fmode_t mode = file->f_mode;
__u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE;
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
-
- fsnotify_parent(dentry, mask);
- fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
+ if (!(file->f_mode & FMODE_NONOTIFY)) {
+ fsnotify_parent(path, NULL, mask);
+ fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0);
+ }
}
/*
@@ -263,9 +266,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
-
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
@@ -299,19 +300,18 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
if (mask) {
if (S_ISDIR(inode->i_mode))
mask |= FS_IN_ISDIR;
- inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
- fsnotify_parent(dentry, mask);
+ fsnotify_parent(NULL, dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
}
-#if defined(CONFIG_INOTIFY) || defined(CONFIG_FSNOTIFY) /* notify helpers */
+#if defined(CONFIG_FSNOTIFY) /* notify helpers */
/*
* fsnotify_oldname_init - save off the old filename before we change it
*/
-static inline const char *fsnotify_oldname_init(const char *name)
+static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name)
{
return kstrdup(name, GFP_KERNEL);
}
@@ -319,22 +319,22 @@ static inline const char *fsnotify_oldname_init(const char *name)
/*
* fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
*/
-static inline void fsnotify_oldname_free(const char *old_name)
+static inline void fsnotify_oldname_free(const unsigned char *old_name)
{
kfree(old_name);
}
-#else /* CONFIG_INOTIFY || CONFIG_FSNOTIFY */
+#else /* CONFIG_FSNOTIFY */
-static inline const char *fsnotify_oldname_init(const char *name)
+static inline const char *fsnotify_oldname_init(const unsigned char *name)
{
return NULL;
}
-static inline void fsnotify_oldname_free(const char *old_name)
+static inline void fsnotify_oldname_free(const unsigned char *old_name)
{
}
-#endif /* ! CONFIG_INOTIFY */
+#endif /* CONFIG_FSNOTIFY */
#endif /* _LINUX_FS_NOTIFY_H */
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 4d6f47b51189..b0d00fd6bfad 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -41,6 +41,9 @@
#define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
#define FS_IN_IGNORED 0x00008000 /* last inotify event here */
+#define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */
+#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */
+
#define FS_IN_ISDIR 0x40000000 /* event occurred against dir */
#define FS_IN_ONESHOT 0x80000000 /* only send event once */
@@ -58,13 +61,11 @@
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
FS_DELETE)
-/* listeners that hard code group numbers near the top */
-#define DNOTIFY_GROUP_NUM UINT_MAX
-#define INOTIFY_GROUP_NUM (DNOTIFY_GROUP_NUM-1)
+#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
struct fsnotify_group;
struct fsnotify_event;
-struct fsnotify_mark_entry;
+struct fsnotify_mark;
struct fsnotify_event_private_data;
/*
@@ -80,10 +81,12 @@ struct fsnotify_event_private_data;
* valid group and inode to use to clean up.
*/
struct fsnotify_ops {
- bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode, __u32 mask);
+ bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type);
int (*handle_event)(struct fsnotify_group *group, struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group);
- void (*freeing_mark)(struct fsnotify_mark_entry *entry, struct fsnotify_group *group);
+ void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
void (*free_event_priv)(struct fsnotify_event_private_data *priv);
};
@@ -96,10 +99,14 @@ struct fsnotify_ops {
struct fsnotify_group {
/*
* global list of all groups receiving events from fsnotify.
- * anchored by fsnotify_groups and protected by either fsnotify_grp_mutex
+ * anchored by fsnotify_inode_groups and protected by either fsnotify_grp_mutex
* or fsnotify_grp_srcu depending on write vs read.
*/
- struct list_head group_list;
+ struct list_head inode_group_list;
+ /*
+ * same as above except anchored by fsnotify_vfsmount_groups
+ */
+ struct list_head vfsmount_group_list;
/*
* Defines all of the event types in which this group is interested.
@@ -119,7 +126,6 @@ struct fsnotify_group {
* closed.
*/
atomic_t refcnt; /* things with interest in this group */
- unsigned int group_num; /* simply prevents accidental group collision */
const struct fsnotify_ops *ops; /* how this group handles things */
@@ -130,15 +136,17 @@ struct fsnotify_group {
unsigned int q_len; /* events on the queue */
unsigned int max_events; /* maximum events allowed on the list */
- /* stores all fastapth entries assoc with this group so they can be cleaned on unregister */
- spinlock_t mark_lock; /* protect mark_entries list */
- atomic_t num_marks; /* 1 for each mark entry and 1 for not being
+ /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */
+ spinlock_t mark_lock; /* protect marks_list */
+ atomic_t num_marks; /* 1 for each mark and 1 for not being
* past the point of no return when freeing
* a group */
- struct list_head mark_entries; /* all inode mark entries for this group */
+ struct list_head marks_list; /* all inode marks for this group */
+ unsigned int priority; /* order of this group compared to others */
/* prevents double list_del of group_list. protected by global fsnotify_grp_mutex */
- bool on_group_list;
+ bool on_inode_group_list;
+ bool on_vfsmount_group_list;
/* groups can define private fields here or use the void *private */
union {
@@ -152,6 +160,14 @@ struct fsnotify_group {
struct user_struct *user;
} inotify_data;
#endif
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ struct fanotify_group_private_data {
+ /* allows a group to block waiting for a userspace response */
+ struct mutex access_mutex;
+ struct list_head access_list;
+ wait_queue_head_t access_waitq;
+ } fanotify_data;
+#endif
};
};
@@ -210,20 +226,42 @@ struct fsnotify_event {
#define FSNOTIFY_EVENT_NONE 0
#define FSNOTIFY_EVENT_PATH 1
#define FSNOTIFY_EVENT_INODE 2
-#define FSNOTIFY_EVENT_FILE 3
int data_type; /* which of the above union we have */
atomic_t refcnt; /* how many groups still are using/need to send this event */
__u32 mask; /* the type of access, bitwise OR for FS_* event types */
u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
- char *file_name;
+ const unsigned char *file_name;
size_t name_len;
+ struct pid *tgid;
+
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+ __u32 response; /* userspace answer to question */
+#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */
struct list_head private_data_list; /* groups can store private data here */
};
/*
- * a mark is simply an entry attached to an in core inode which allows an
+ * Inode specific fields in an fsnotify_mark
+ */
+struct fsnotify_inode_mark {
+ struct inode *inode; /* inode this mark is associated with */
+ struct hlist_node i_list; /* list of marks by inode->i_fsnotify_marks */
+ struct list_head free_i_list; /* tmp list used when freeing this mark */
+};
+
+/*
+ * Mount point specific fields in an fsnotify_mark
+ */
+struct fsnotify_vfsmount_mark {
+ struct vfsmount *mnt; /* vfsmount this mark is associated with */
+ struct hlist_node m_list; /* list of marks by inode->i_fsnotify_marks */
+ struct list_head free_m_list; /* tmp list used when freeing this mark */
+};
+
+/*
+ * a mark is simply an object attached to an in core inode which allows an
* fsnotify listener to indicate they are either no longer interested in events
* of a type matching mask or only interested in those events.
*
@@ -232,19 +270,26 @@ struct fsnotify_event {
* (such as dnotify) will flush these when the open fd is closed and not at
* inode eviction or modification.
*/
-struct fsnotify_mark_entry {
- __u32 mask; /* mask this mark entry is for */
+struct fsnotify_mark {
+ __u32 mask; /* mask this mark is for */
/* we hold ref for each i_list and g_list. also one ref for each 'thing'
* in kernel that found and may be using this mark. */
atomic_t refcnt; /* active things looking at this mark */
- struct inode *inode; /* inode this entry is associated with */
- struct fsnotify_group *group; /* group this mark entry is for */
- struct hlist_node i_list; /* list of mark_entries by inode->i_fsnotify_mark_entries */
- struct list_head g_list; /* list of mark_entries by group->i_fsnotify_mark_entries */
- spinlock_t lock; /* protect group, inode, and killme */
- struct list_head free_i_list; /* tmp list used when freeing this mark */
+ struct fsnotify_group *group; /* group this mark is for */
+ struct list_head g_list; /* list of marks by group->i_fsnotify_marks */
+ spinlock_t lock; /* protect group and inode */
+ union {
+ struct fsnotify_inode_mark i;
+ struct fsnotify_vfsmount_mark m;
+ };
+ __u32 ignored_mask; /* events types to ignore */
struct list_head free_g_list; /* tmp list used when freeing this mark */
- void (*free_mark)(struct fsnotify_mark_entry *entry); /* called on final put+free */
+#define FSNOTIFY_MARK_FLAG_INODE 0x01
+#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
+#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04
+#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08
+ unsigned int flags; /* vfsmount or inode mark? */
+ void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */
};
#ifdef CONFIG_FSNOTIFY
@@ -252,10 +297,11 @@ struct fsnotify_mark_entry {
/* called from the vfs helpers */
/* main fsnotify call to send events */
-extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
- const char *name, u32 cookie);
-extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
+extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+ const unsigned char *name, u32 cookie);
+extern void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
+extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
extern u32 fsnotify_get_cookie(void);
static inline int fsnotify_inode_watches_children(struct inode *inode)
@@ -307,12 +353,10 @@ static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode
/* must call when a group changes its ->mask */
extern void fsnotify_recalc_global_mask(void);
/* get a reference to an existing or create a new group */
-extern struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num,
- __u32 mask,
- const struct fsnotify_ops *ops);
+extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
/* run all marks associated with this group and update group->mask */
extern void fsnotify_recalc_group_mask(struct fsnotify_group *group);
-/* drop reference on a group from fsnotify_obtain_group */
+/* drop reference on a group from fsnotify_alloc_group */
extern void fsnotify_put_group(struct fsnotify_group *group);
/* take a reference to an event */
@@ -323,8 +367,13 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
struct fsnotify_event *event);
/* attach the event to the group notification queue */
-extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
- struct fsnotify_event_private_data *priv);
+extern int fsnotify_add_notify_event(struct fsnotify_group *group,
+ struct fsnotify_event *event,
+ struct fsnotify_event_private_data *priv,
+ int (*merge)(struct list_head *,
+ struct fsnotify_event *,
+ void **),
+ void **arg);
/* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */
@@ -334,38 +383,66 @@ extern struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group
/* functions used to manipulate the marks attached to inodes */
+/* run all marks associated with a vfsmount and update mnt->mnt_fsnotify_mask */
+extern void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt);
/* run all marks associated with an inode and update inode->i_fsnotify_mask */
extern void fsnotify_recalc_inode_mask(struct inode *inode);
-extern void fsnotify_init_mark(struct fsnotify_mark_entry *entry, void (*free_mark)(struct fsnotify_mark_entry *entry));
+extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));
/* find (and take a reference) to a mark associated with group and inode */
-extern struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group, struct inode *inode);
+extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, struct inode *inode);
+/* find (and take a reference) to a mark associated with group and vfsmount */
+extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt);
+/* copy the values from old into new */
+extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old);
+/* set the ignored_mask of a mark */
+extern void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask);
+/* set the mask of a mark (might pin the object into memory */
+extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask);
/* attach the mark to both the group and the inode */
-extern int fsnotify_add_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group, struct inode *inode);
+extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
+ struct inode *inode, struct vfsmount *mnt, int allow_dups);
/* given a mark, flag it to be freed when all references are dropped */
-extern void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry);
+extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
+/* run all the marks in a group, and clear all of the vfsmount marks */
+extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
+/* run all the marks in a group, and clear all of the inode marks */
+extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group);
+/* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/
+extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags);
/* run all the marks in a group, and flag them to be freed */
extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
-extern void fsnotify_get_mark(struct fsnotify_mark_entry *entry);
-extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);
+extern void fsnotify_get_mark(struct fsnotify_mark *mark);
+extern void fsnotify_put_mark(struct fsnotify_mark *mark);
extern void fsnotify_unmount_inodes(struct list_head *list);
/* put here because inotify does some weird stuff when destroying watches */
extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
- void *data, int data_is, const char *name,
+ void *data, int data_is,
+ const unsigned char *name,
u32 cookie, gfp_t gfp);
+/* fanotify likes to change events after they are on lists... */
+extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
+extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
+ struct fsnotify_event *new_event);
+
#else
-static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
- const char *name, u32 cookie)
-{}
+static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+ const unsigned char *name, u32 cookie)
+{
+ return 0;
+}
-static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
+static inline void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{}
static inline void __fsnotify_inode_delete(struct inode *inode)
{}
+static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
+{}
+
static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
{}
diff --git a/include/linux/i2c/ltc4245.h b/include/linux/i2c/ltc4245.h
new file mode 100644
index 000000000000..56bda4be0016
--- /dev/null
+++ b/include/linux/i2c/ltc4245.h
@@ -0,0 +1,21 @@
+/*
+ * Platform Data for LTC4245 hardware monitor chip
+ *
+ * Copyright (c) 2010 Ira W. Snyder <iws@ovro.caltech.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef LINUX_LTC4245_H
+#define LINUX_LTC4245_H
+
+#include <linux/types.h>
+
+struct ltc4245_platform_data {
+ bool use_extra_gpios;
+};
+
+#endif /* LINUX_LTC4245_H */
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
index cd525fae3c98..2c7994372bde 100644
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -83,6 +83,7 @@
#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
+#define BOND_DEFAULT_TX_QUEUES 16 /* Default number of tx queues per device */
/* hashing types */
#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */
#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */
diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 938b7e81df95..0d241a5c4909 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -102,8 +102,6 @@ struct __fdb_entry {
#include <linux/netdevice.h>
extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *));
-extern struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
- struct sk_buff *skb);
extern int (*br_should_route_hook)(struct sk_buff *skb);
#endif
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index bed7a4682b90..c831467774d0 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -119,7 +119,7 @@ struct ethhdr {
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_proto; /* packet type ID field */
-} __attribute__((packed));
+} __packed;
#ifdef __KERNEL__
#include <linux/skbuff.h>
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index 5459c5c09930..9947c39e62f6 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -67,7 +67,7 @@ struct fddi_8022_1_hdr {
__u8 dsap; /* destination service access point */
__u8 ssap; /* source service access point */
__u8 ctrl; /* control byte #1 */
-} __attribute__ ((packed));
+} __packed;
/* Define 802.2 Type 2 header */
struct fddi_8022_2_hdr {
@@ -75,7 +75,7 @@ struct fddi_8022_2_hdr {
__u8 ssap; /* source service access point */
__u8 ctrl_1; /* control byte #1 */
__u8 ctrl_2; /* control byte #2 */
-} __attribute__ ((packed));
+} __packed;
/* Define 802.2 SNAP header */
#define FDDI_K_OUI_LEN 3
@@ -85,7 +85,7 @@ struct fddi_snap_hdr {
__u8 ctrl; /* always 0x03 */
__u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */
__be16 ethertype; /* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
/* Define FDDI LLC frame header */
struct fddihdr {
@@ -98,7 +98,7 @@ struct fddihdr {
struct fddi_8022_2_hdr llc_8022_2;
struct fddi_snap_hdr llc_snap;
} hdr;
-} __attribute__ ((packed));
+} __packed;
#ifdef __KERNEL__
#include <linux/netdevice.h>
diff --git a/include/linux/if_frad.h b/include/linux/if_frad.h
index 80b3a1056a5f..191ee0869bc1 100644
--- a/include/linux/if_frad.h
+++ b/include/linux/if_frad.h
@@ -135,7 +135,7 @@ struct frhdr
__be16 PID;
#define IP_NLPID pad
-} __attribute__((packed));
+} __packed;
/* see RFC 1490 for the definition of the following */
#define FRAD_I_UI 0x03
diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h
index 8d038eb8db5c..5fe5f307c6f5 100644
--- a/include/linux/if_hippi.h
+++ b/include/linux/if_hippi.h
@@ -104,7 +104,7 @@ struct hippi_fp_hdr {
__be32 fixed;
#endif
__be32 d2_size;
-} __attribute__ ((packed));
+} __packed;
struct hippi_le_hdr {
#if defined (__BIG_ENDIAN_BITFIELD)
@@ -129,7 +129,7 @@ struct hippi_le_hdr {
__u8 daddr[HIPPI_ALEN];
__u16 locally_administered;
__u8 saddr[HIPPI_ALEN];
-} __attribute__ ((packed));
+} __packed;
#define HIPPI_OUI_LEN 3
/*
@@ -142,12 +142,12 @@ struct hippi_snap_hdr {
__u8 ctrl; /* always 0x03 */
__u8 oui[HIPPI_OUI_LEN]; /* organizational universal id (zero)*/
__be16 ethertype; /* packet type ID field */
-} __attribute__ ((packed));
+} __packed;
struct hippi_hdr {
struct hippi_fp_hdr fp;
struct hippi_le_hdr le;
struct hippi_snap_hdr snap;
-} __attribute__ ((packed));
+} __packed;
#endif /* _LINUX_IF_HIPPI_H */
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 9ea047aca795..c26a0e4f0ce8 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -84,8 +84,4 @@ extern int macvlan_link_register(struct rtnl_link_ops *ops);
extern netdev_tx_t macvlan_start_xmit(struct sk_buff *skb,
struct net_device *dev);
-
-extern struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *,
- struct sk_buff *);
-
#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h
index 6ac23ef1801a..72bfa5a034dd 100644
--- a/include/linux/if_packet.h
+++ b/include/linux/if_packet.h
@@ -48,6 +48,7 @@ struct sockaddr_ll {
#define PACKET_LOSS 14
#define PACKET_VNET_HDR 15
#define PACKET_TX_TIMESTAMP 16
+#define PACKET_TIMESTAMP 17
struct tpacket_stats {
unsigned int tp_packets;
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index a6577af0c4e6..1925e0c3f162 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -59,7 +59,7 @@ struct sockaddr_pppox {
union{
struct pppoe_addr pppoe;
}sa_addr;
-}__attribute__ ((packed));
+} __packed;
/* The use of the above union isn't viable because the size of this
* struct must stay fixed over time -- applications use sizeof(struct
@@ -70,7 +70,7 @@ struct sockaddr_pppol2tp {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tp_addr pppol2tp;
-}__attribute__ ((packed));
+} __packed;
/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32
* bits. So we need a different sockaddr structure.
@@ -79,7 +79,7 @@ struct sockaddr_pppol2tpv3 {
sa_family_t sa_family; /* address family, AF_PPPOX */
unsigned int sa_protocol; /* protocol identifier */
struct pppol2tpv3_addr pppol2tp;
-} __attribute__ ((packed));
+} __packed;
/*********************************************************************
*
@@ -129,7 +129,7 @@ struct pppoe_hdr {
__be16 sid;
__be16 length;
struct pppoe_tag tag[0];
-} __attribute__ ((packed));
+} __packed;
/* Length of entire PPPoE + PPP header */
#define PPPOE_SES_HLEN 8
diff --git a/include/linux/init.h b/include/linux/init.h
index ab1d31f9352b..de994304e0bb 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -301,7 +301,7 @@ void __init parse_early_options(char *cmdline);
#endif
/* Data marked not to be saved by software suspend */
-#define __nosavedata __section(.data.nosave)
+#define __nosavedata __section(.data..nosave)
/* This means "can be init if no module support, otherwise module load
may call it." */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 2beaa13492be..1f43fa56f600 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -183,7 +183,7 @@ extern struct cred init_cred;
}
/* Attach to the init_task data structure for proper alignment */
-#define __init_task_data __attribute__((__section__(".data.init_task")))
+#define __init_task_data __attribute__((__section__(".data..init_task")))
#endif
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
index 37ea2894b3c0..94d209a1b689 100644
--- a/include/linux/inotify.h
+++ b/include/linux/inotify.h
@@ -70,177 +70,8 @@ struct inotify_event {
#define IN_NONBLOCK O_NONBLOCK
#ifdef __KERNEL__
-
-#include <linux/dcache.h>
-#include <linux/fs.h>
-
-/*
- * struct inotify_watch - represents a watch request on a specific inode
- *
- * h_list is protected by ih->mutex of the associated inotify_handle.
- * i_list, mask are protected by inode->inotify_mutex of the associated inode.
- * ih, inode, and wd are never written to once the watch is created.
- *
- * Callers must use the established inotify interfaces to access inotify_watch
- * contents. The content of this structure is private to the inotify
- * implementation.
- */
-struct inotify_watch {
- struct list_head h_list; /* entry in inotify_handle's list */
- struct list_head i_list; /* entry in inode's list */
- atomic_t count; /* reference count */
- struct inotify_handle *ih; /* associated inotify handle */
- struct inode *inode; /* associated inode */
- __s32 wd; /* watch descriptor */
- __u32 mask; /* event mask for this watch */
-};
-
-struct inotify_operations {
- void (*handle_event)(struct inotify_watch *, u32, u32, u32,
- const char *, struct inode *);
- void (*destroy_watch)(struct inotify_watch *);
-};
-
-#ifdef CONFIG_INOTIFY
-
-/* Kernel API for producing events */
-
-extern void inotify_d_instantiate(struct dentry *, struct inode *);
-extern void inotify_d_move(struct dentry *);
-extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
- const char *, struct inode *);
-extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
- const char *);
-extern void inotify_unmount_inodes(struct list_head *);
-extern void inotify_inode_is_dead(struct inode *);
-extern u32 inotify_get_cookie(void);
-
-/* Kernel Consumer API */
-
-extern struct inotify_handle *inotify_init(const struct inotify_operations *);
-extern void inotify_init_watch(struct inotify_watch *);
-extern void inotify_destroy(struct inotify_handle *);
-extern __s32 inotify_find_watch(struct inotify_handle *, struct inode *,
- struct inotify_watch **);
-extern __s32 inotify_find_update_watch(struct inotify_handle *, struct inode *,
- u32);
-extern __s32 inotify_add_watch(struct inotify_handle *, struct inotify_watch *,
- struct inode *, __u32);
-extern __s32 inotify_clone_watch(struct inotify_watch *, struct inotify_watch *);
-extern void inotify_evict_watch(struct inotify_watch *);
-extern int inotify_rm_watch(struct inotify_handle *, struct inotify_watch *);
-extern int inotify_rm_wd(struct inotify_handle *, __u32);
-extern void inotify_remove_watch_locked(struct inotify_handle *,
- struct inotify_watch *);
-extern void get_inotify_watch(struct inotify_watch *);
-extern void put_inotify_watch(struct inotify_watch *);
-extern int pin_inotify_watch(struct inotify_watch *);
-extern void unpin_inotify_watch(struct inotify_watch *);
-
-#else
-
-static inline void inotify_d_instantiate(struct dentry *dentry,
- struct inode *inode)
-{
-}
-
-static inline void inotify_d_move(struct dentry *dentry)
-{
-}
-
-static inline void inotify_inode_queue_event(struct inode *inode,
- __u32 mask, __u32 cookie,
- const char *filename,
- struct inode *n_inode)
-{
-}
-
-static inline void inotify_dentry_parent_queue_event(struct dentry *dentry,
- __u32 mask, __u32 cookie,
- const char *filename)
-{
-}
-
-static inline void inotify_unmount_inodes(struct list_head *list)
-{
-}
-
-static inline void inotify_inode_is_dead(struct inode *inode)
-{
-}
-
-static inline u32 inotify_get_cookie(void)
-{
- return 0;
-}
-
-static inline struct inotify_handle *inotify_init(const struct inotify_operations *ops)
-{
- return ERR_PTR(-EOPNOTSUPP);
-}
-
-static inline void inotify_init_watch(struct inotify_watch *watch)
-{
-}
-
-static inline void inotify_destroy(struct inotify_handle *ih)
-{
-}
-
-static inline __s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode,
- struct inotify_watch **watchp)
-{
- return -EOPNOTSUPP;
-}
-
-static inline __s32 inotify_find_update_watch(struct inotify_handle *ih,
- struct inode *inode, u32 mask)
-{
- return -EOPNOTSUPP;
-}
-
-static inline __s32 inotify_add_watch(struct inotify_handle *ih,
- struct inotify_watch *watch,
- struct inode *inode, __u32 mask)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int inotify_rm_watch(struct inotify_handle *ih,
- struct inotify_watch *watch)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int inotify_rm_wd(struct inotify_handle *ih, __u32 wd)
-{
- return -EOPNOTSUPP;
-}
-
-static inline void inotify_remove_watch_locked(struct inotify_handle *ih,
- struct inotify_watch *watch)
-{
-}
-
-static inline void get_inotify_watch(struct inotify_watch *watch)
-{
-}
-
-static inline void put_inotify_watch(struct inotify_watch *watch)
-{
-}
-
-extern inline int pin_inotify_watch(struct inotify_watch *watch)
-{
- return 0;
-}
-
-extern inline void unpin_inotify_watch(struct inotify_watch *watch)
-{
-}
-
-#endif /* CONFIG_INOTIFY */
-
-#endif /* __KERNEL __ */
+#include <linux/sysctl.h>
+extern struct ctl_table inotify_table[]; /* for sysctl */
+#endif
#endif /* _LINUX_INOTIFY_H */
diff --git a/include/linux/iocontext.h b/include/linux/iocontext.h
index a0bb301afac0..64d529133031 100644
--- a/include/linux/iocontext.h
+++ b/include/linux/iocontext.h
@@ -7,7 +7,6 @@
struct cfq_queue;
struct cfq_io_context {
void *key;
- unsigned long dead_key;
struct cfq_queue *cfqq[2];
diff --git a/include/linux/ioq.h b/include/linux/ioq.h
new file mode 100644
index 000000000000..7c6d6cad83c7
--- /dev/null
+++ b/include/linux/ioq.h
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * IOQ is a generic shared-memory, lockless queue mechanism. It can be used
+ * in a variety of ways, though its intended purpose is to become the
+ * asynchronous communication path for virtual-bus drivers.
+ *
+ * The following are a list of key design points:
+ *
+ * #) All shared-memory is always allocated on explicitly one side of the
+ * link. This typically would be the guest side in a VM/VMM scenario.
+ * #) Each IOQ has the concept of "north" and "south" locales, where
+ * north denotes the memory-owner side (e.g. guest).
+ * #) An IOQ is manipulated using an iterator idiom.
+ * #) Provides a bi-directional signaling/notification infrastructure on
+ * a per-queue basis, which includes an event mitigation strategy
+ * to reduce boundary switching.
+ * #) The signaling path is abstracted so that various technologies and
+ * topologies can define their own specific implementation while sharing
+ * the basic structures and code.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_IOQ_H
+#define _LINUX_IOQ_H
+
+#include <linux/types.h>
+#include <linux/shm_signal.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc). Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+struct ioq_ring_desc {
+ __u64 cookie; /* for arbitrary use by north-side */
+ __le64 ptr;
+ __le64 len;
+ __u8 valid;
+ __u8 sown; /* South owned = 1, North owned = 0 */
+};
+
+#define IOQ_RING_MAGIC cpu_to_le32(0x47fa2fe4)
+#define IOQ_RING_VER cpu_to_le32(4)
+
+struct ioq_ring_idx {
+ __le32 head; /* 0 based index to head of ptr array */
+ __le32 tail; /* 0 based index to tail of ptr array */
+ __u8 full;
+};
+
+enum ioq_locality {
+ ioq_locality_north,
+ ioq_locality_south,
+};
+
+struct ioq_ring_head {
+ __le32 magic;
+ __le32 ver;
+ struct shm_signal_desc signal;
+ struct ioq_ring_idx idx[2];
+ __le32 count;
+ struct ioq_ring_desc ring[1]; /* "count" elements will be allocated */
+};
+
+#define IOQ_HEAD_DESC_SIZE(count) \
+ (sizeof(struct ioq_ring_head) + sizeof(struct ioq_ring_desc) * (count - 1))
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/kref.h>
+
+enum ioq_idx_type {
+ ioq_idxtype_valid,
+ ioq_idxtype_inuse,
+ ioq_idxtype_both,
+ ioq_idxtype_invalid,
+};
+
+enum ioq_seek_type {
+ ioq_seek_tail,
+ ioq_seek_next,
+ ioq_seek_head,
+ ioq_seek_set
+};
+
+struct ioq_iterator {
+ struct ioq *ioq;
+ struct ioq_ring_idx *idx;
+ u32 pos;
+ struct ioq_ring_desc *desc;
+ bool update;
+ bool dualidx;
+ bool flipowner;
+};
+
+struct ioq_notifier {
+ void (*signal)(struct ioq_notifier *);
+};
+
+struct ioq_ops {
+ void (*release)(struct ioq *ioq);
+};
+
+struct ioq {
+ struct ioq_ops *ops;
+
+ struct kref kref;
+ enum ioq_locality locale;
+ struct ioq_ring_head *head_desc;
+ struct ioq_ring_desc *ring;
+ struct shm_signal *signal;
+ wait_queue_head_t wq;
+ struct ioq_notifier *notifier;
+ size_t count;
+ struct shm_signal_notifier shm_notifier;
+};
+
+#define IOQ_ITER_AUTOUPDATE (1 << 0)
+#define IOQ_ITER_NOFLIPOWNER (1 << 1)
+
+/**
+ * ioq_init() - initialize an IOQ
+ * @ioq: IOQ context
+ *
+ * Initializes IOQ context before first use
+ *
+ **/
+void ioq_init(struct ioq *ioq,
+ struct ioq_ops *ops,
+ enum ioq_locality locale,
+ struct ioq_ring_head *head,
+ struct shm_signal *signal,
+ size_t count);
+
+/**
+ * ioq_get() - acquire an IOQ context reference
+ * @ioq: IOQ context
+ *
+ **/
+static inline struct ioq *ioq_get(struct ioq *ioq)
+{
+ kref_get(&ioq->kref);
+
+ return ioq;
+}
+
+static inline void _ioq_kref_release(struct kref *kref)
+{
+ struct ioq *ioq = container_of(kref, struct ioq, kref);
+
+ shm_signal_put(ioq->signal);
+ ioq->ops->release(ioq);
+}
+
+/**
+ * ioq_put() - release an IOQ context reference
+ * @ioq: IOQ context
+ *
+ **/
+static inline void ioq_put(struct ioq *ioq)
+{
+ kref_put(&ioq->kref, _ioq_kref_release);
+}
+
+/**
+ * ioq_notify_enable() - enables local notifications on an IOQ
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered ioq_notifier (if applicable) and waitq to
+ * receive wakeups whenever the remote side performs an ioq_signal() operation.
+ * A notification will be dispatched immediately if any pending signals have
+ * already been issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_enable(struct ioq *ioq, int flags)
+{
+ return shm_signal_enable(ioq->signal, 0);
+}
+
+/**
+ * ioq_notify_disable() - disable local notifications on an IOQ
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Disables/masks the registered ioq_notifier (if applicable) and waitq
+ * from receiving any further notifications. Any subsequent calls to
+ * ioq_signal() by the remote side will update the ring as dirty, but
+ * will not traverse the locale boundary and will not invoke the notifier
+ * callback or wakeup the waitq. Signals delivered while masked will
+ * be deferred until ioq_notify_enable() is invoked
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_notify_disable(struct ioq *ioq, int flags)
+{
+ return shm_signal_disable(ioq->signal, 0);
+}
+
+/**
+ * ioq_signal() - notify the remote side about ring changes
+ * @ioq: IOQ context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Marks the ring state as "dirty" and, if enabled, will traverse
+ * a locale boundary to invoke a remote notification. The remote
+ * side controls whether the notification should be delivered via
+ * the ioq_notify_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the ioq_ops->signal() interface and provided by a particular
+ * implementation. However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+static inline int ioq_signal(struct ioq *ioq, int flags)
+{
+ return shm_signal_inject(ioq->signal, 0);
+}
+
+/**
+ * ioq_count() - counts the number of outstanding descriptors in an index
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) >=0: # of descriptors outstanding in the index
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_count(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_remain() - counts the number of remaining descriptors in an index
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * This is the converse of ioq_count(). This function returns the number
+ * of "free" descriptors left in a particular index
+ *
+ * Returns:
+ * (*) >=0: # of descriptors remaining in the index
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_remain(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_size() - counts the maximum number of descriptors in an ring
+ * @ioq: IOQ context
+ *
+ * This function returns the maximum number of descriptors supported in
+ * a ring, regardless of their current state (free or inuse).
+ *
+ * Returns:
+ * (*) >=0: total # of descriptors in the ring
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_size(struct ioq *ioq);
+
+/**
+ * ioq_full() - determines if a specific index is "full"
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) 0: index is not full
+ * (*) 1: index is full
+ * (*) <0 = ERRNO
+ *
+ **/
+int ioq_full(struct ioq *ioq, enum ioq_idx_type type);
+
+/**
+ * ioq_empty() - determines if a specific index is "empty"
+ * @ioq: IOQ context
+ * @type: Specifies the index type
+ * (*) valid: the descriptor is valid. This is usually
+ * used to keep track of descriptors that may not
+ * be carrying a useful payload, but still need to
+ * be tracked carefully.
+ * (*) inuse: Descriptors that carry useful payload
+ *
+ * Returns:
+ * (*) 0: index is not empty
+ * (*) 1: index is empty
+ * (*) <0 = ERRNO
+ *
+ **/
+static inline int ioq_empty(struct ioq *ioq, enum ioq_idx_type type)
+{
+ return !ioq_count(ioq, type);
+}
+
+/**
+ * ioq_iter_init() - initialize an iterator for IOQ descriptor traversal
+ * @ioq: IOQ context to iterate on
+ * @iter: Iterator context to init (usually from stack)
+ * @type: Specifies the index type to iterate against
+ * (*) valid: iterate against the "valid" index
+ * (*) inuse: iterate against the "inuse" index
+ * (*) both: iterate against both indexes simultaneously
+ * @flags: Bitfield with 0 or more bits set to alter behavior
+ * (*) autoupdate: automatically signal the remote side
+ * whenever the iterator pushes/pops to a new desc
+ * (*) noflipowner: do not flip the ownership bit during
+ * a push/pop operation
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
+ enum ioq_idx_type type, int flags);
+
+/**
+ * ioq_iter_seek() - seek to a specific location in the IOQ ring
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @type: Specifies the type of seek operation
+ * (*) tail: seek to the absolute tail, offset is ignored
+ * (*) next: seek to the relative next, offset is ignored
+ * (*) head: seek to the absolute head, offset is ignored
+ * (*) set: seek to the absolute offset
+ * @offset: Offset for ioq_seek_set operations
+ * @flags: Reserved for future use, must be 0
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
+ long offset, int flags);
+
+/**
+ * ioq_iter_push() - push the tail pointer forward
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @flags: Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the tail ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation. This effectively "pushes" a new pointer
+ * onto the tail of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_push(struct ioq_iterator *iter, int flags);
+
+/**
+ * ioq_iter_pop() - pop the head pointer from the ring
+ * @iter: Iterator context (must be initialized with ioq_iter_init)
+ * @flags: Reserved for future use, must be 0
+ *
+ * This function will simultaneously advance the head ptr in the current
+ * index (valid/inuse, as specified in the ioq_iter_init) as well as
+ * perform a seek(next) operation. This effectively "pops" a pointer
+ * from the head of the index.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int ioq_iter_pop(struct ioq_iterator *iter, int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_IOQ_H */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 99e1ab7e3eec..940e21595351 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -58,7 +58,7 @@ struct ipv6_opt_hdr {
/*
* TLV encoded option data follows.
*/
-} __attribute__ ((packed)); /* required for some archs */
+} __packed; /* required for some archs */
#define ipv6_destopt_hdr ipv6_opt_hdr
#define ipv6_hopopt_hdr ipv6_opt_hdr
@@ -99,7 +99,7 @@ struct ipv6_destopt_hao {
__u8 type;
__u8 length;
struct in6_addr addr;
-} __attribute__ ((__packed__));
+} __packed;
/*
* IPv6 fixed header
diff --git a/include/linux/iscsi_boot_sysfs.h b/include/linux/iscsi_boot_sysfs.h
new file mode 100644
index 000000000000..f1e6c184f14f
--- /dev/null
+++ b/include/linux/iscsi_boot_sysfs.h
@@ -0,0 +1,123 @@
+/*
+ * Export the iSCSI boot info to userland via sysfs.
+ *
+ * Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010 Mike Christie
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _ISCSI_BOOT_SYSFS_
+#define _ISCSI_BOOT_SYSFS_
+
+/*
+ * The text attributes names for each of the kobjects.
+*/
+enum iscsi_boot_eth_properties_enum {
+ ISCSI_BOOT_ETH_INDEX,
+ ISCSI_BOOT_ETH_FLAGS,
+ ISCSI_BOOT_ETH_IP_ADDR,
+ ISCSI_BOOT_ETH_SUBNET_MASK,
+ ISCSI_BOOT_ETH_ORIGIN,
+ ISCSI_BOOT_ETH_GATEWAY,
+ ISCSI_BOOT_ETH_PRIMARY_DNS,
+ ISCSI_BOOT_ETH_SECONDARY_DNS,
+ ISCSI_BOOT_ETH_DHCP,
+ ISCSI_BOOT_ETH_VLAN,
+ ISCSI_BOOT_ETH_MAC,
+ /* eth_pci_bdf - this is replaced by link to the device itself. */
+ ISCSI_BOOT_ETH_HOSTNAME,
+ ISCSI_BOOT_ETH_END_MARKER,
+};
+
+enum iscsi_boot_tgt_properties_enum {
+ ISCSI_BOOT_TGT_INDEX,
+ ISCSI_BOOT_TGT_FLAGS,
+ ISCSI_BOOT_TGT_IP_ADDR,
+ ISCSI_BOOT_TGT_PORT,
+ ISCSI_BOOT_TGT_LUN,
+ ISCSI_BOOT_TGT_CHAP_TYPE,
+ ISCSI_BOOT_TGT_NIC_ASSOC,
+ ISCSI_BOOT_TGT_NAME,
+ ISCSI_BOOT_TGT_CHAP_NAME,
+ ISCSI_BOOT_TGT_CHAP_SECRET,
+ ISCSI_BOOT_TGT_REV_CHAP_NAME,
+ ISCSI_BOOT_TGT_REV_CHAP_SECRET,
+ ISCSI_BOOT_TGT_END_MARKER,
+};
+
+enum iscsi_boot_initiator_properties_enum {
+ ISCSI_BOOT_INI_INDEX,
+ ISCSI_BOOT_INI_FLAGS,
+ ISCSI_BOOT_INI_ISNS_SERVER,
+ ISCSI_BOOT_INI_SLP_SERVER,
+ ISCSI_BOOT_INI_PRI_RADIUS_SERVER,
+ ISCSI_BOOT_INI_SEC_RADIUS_SERVER,
+ ISCSI_BOOT_INI_INITIATOR_NAME,
+ ISCSI_BOOT_INI_END_MARKER,
+};
+
+struct attribute_group;
+
+struct iscsi_boot_kobj {
+ struct kobject kobj;
+ struct attribute_group *attr_group;
+ struct list_head list;
+
+ /*
+ * Pointer to store driver specific info. If set this will
+ * be freed for the LLD when the kobj release function is called.
+ */
+ void *data;
+ /*
+ * Driver specific show function.
+ *
+ * The enum of the type. This can be any value of the above
+ * properties.
+ */
+ ssize_t (*show) (void *data, int type, char *buf);
+
+ /*
+ * Drivers specific visibility function.
+ * The function should return if they the attr should be readable
+ * writable or should not be shown.
+ *
+ * The enum of the type. This can be any value of the above
+ * properties.
+ */
+ mode_t (*is_visible) (void *data, int type);
+};
+
+struct iscsi_boot_kset {
+ struct list_head kobj_list;
+ struct kset *kset;
+};
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kobj *
+iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+struct iscsi_boot_kobj *
+iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index,
+ void *data,
+ ssize_t (*show) (void *data, int type, char *buf),
+ mode_t (*is_visible) (void *data, int type));
+
+struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name);
+struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno);
+void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset);
+
+#endif
diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h
index d2e4042f8f5e..8ba7e5b9d62c 100644
--- a/include/linux/iscsi_ibft.h
+++ b/include/linux/iscsi_ibft.h
@@ -21,21 +21,13 @@
#ifndef ISCSI_IBFT_H
#define ISCSI_IBFT_H
-struct ibft_table_header {
- char signature[4];
- u32 length;
- u8 revision;
- u8 checksum;
- char oem_id[6];
- char oem_table_id[8];
- char reserved[24];
-} __attribute__((__packed__));
+#include <acpi/acpi.h>
/*
* Logical location of iSCSI Boot Format Table.
* If the value is NULL there is no iBFT on the machine.
*/
-extern struct ibft_table_header *ibft_addr;
+extern struct acpi_table_ibft *ibft_addr;
/*
* Routine used to find and reserve the iSCSI Boot Format Table. The
diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h
index b9b5a684ed69..b8c23f88dd54 100644
--- a/include/linux/isdnif.h
+++ b/include/linux/isdnif.h
@@ -317,7 +317,7 @@ typedef struct T30_s {
__u8 r_scantime;
__u8 r_id[FAXIDLEN];
__u8 r_code;
-} __attribute__((packed)) T30_s;
+} __packed T30_s;
#define ISDN_TTY_FAX_CONN_IN 0
#define ISDN_TTY_FAX_CONN_OUT 1
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 3bad2701bfa6..b85f3ff34d7d 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1023,6 +1023,7 @@ extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
extern int ata_std_bios_param(struct scsi_device *sdev,
struct block_device *bdev,
sector_t capacity, int geom[]);
+extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev);
extern int ata_scsi_slave_config(struct scsi_device *sdev);
extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
@@ -1174,6 +1175,7 @@ extern struct device_attribute *ata_common_sdev_attrs[];
.slave_configure = ata_scsi_slave_config, \
.slave_destroy = ata_scsi_slave_destroy, \
.bios_param = ata_std_bios_param, \
+ .unlock_native_capacity = ata_scsi_unlock_native_capacity, \
.sdev_attrs = ata_common_sdev_attrs
#define ATA_NCQ_SHT(drv_name) \
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index 5126cceb6ae9..7135ebc8428c 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -18,8 +18,8 @@
# define asmregparm
#endif
-#define __page_aligned_data __section(.data.page_aligned) __aligned(PAGE_SIZE)
-#define __page_aligned_bss __section(.bss.page_aligned) __aligned(PAGE_SIZE)
+#define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE)
+#define __page_aligned_bss __section(.bss..page_aligned) __aligned(PAGE_SIZE)
/*
* For assembly routines.
@@ -27,8 +27,8 @@
* Note when using these that you must specify the appropriate
* alignment directives yourself
*/
-#define __PAGE_ALIGNED_DATA .section ".data.page_aligned", "aw"
-#define __PAGE_ALIGNED_BSS .section ".bss.page_aligned", "aw"
+#define __PAGE_ALIGNED_DATA .section ".data..page_aligned", "aw"
+#define __PAGE_ALIGNED_BSS .section ".bss..page_aligned", "aw"
/*
* This is used by architectures to keep arguments on the stack
diff --git a/include/linux/mISDNif.h b/include/linux/mISDNif.h
index 78c3bed1c3f5..b5e7f2202484 100644
--- a/include/linux/mISDNif.h
+++ b/include/linux/mISDNif.h
@@ -251,7 +251,7 @@
struct mISDNhead {
unsigned int prim;
unsigned int id;
-} __attribute__((packed));
+} __packed;
#define MISDN_HEADER_LEN sizeof(struct mISDNhead)
#define MAX_DATA_SIZE 2048
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b969efb03787..c34e35e2ecce 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -815,6 +815,7 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
}
extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
+extern void truncate_setsize(struct inode *inode, loff_t newsize);
extern int vmtruncate(struct inode *inode, loff_t offset);
extern int vmtruncate_range(struct inode *inode, loff_t offset, loff_t end);
diff --git a/include/linux/mmc/sh_mmcif.h b/include/linux/mmc/sh_mmcif.h
index aafe832f18aa..d4a2ebbdab4b 100644
--- a/include/linux/mmc/sh_mmcif.h
+++ b/include/linux/mmc/sh_mmcif.h
@@ -14,6 +14,9 @@
#ifndef __SH_MMCIF_H__
#define __SH_MMCIF_H__
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
/*
* MMCIF : CE_CLK_CTRL [19:16]
* 1000 : Peripheral clock / 512
@@ -36,4 +39,162 @@ struct sh_mmcif_plat_data {
u32 ocr;
};
+#define MMCIF_CE_CMD_SET 0x00000000
+#define MMCIF_CE_ARG 0x00000008
+#define MMCIF_CE_ARG_CMD12 0x0000000C
+#define MMCIF_CE_CMD_CTRL 0x00000010
+#define MMCIF_CE_BLOCK_SET 0x00000014
+#define MMCIF_CE_CLK_CTRL 0x00000018
+#define MMCIF_CE_BUF_ACC 0x0000001C
+#define MMCIF_CE_RESP3 0x00000020
+#define MMCIF_CE_RESP2 0x00000024
+#define MMCIF_CE_RESP1 0x00000028
+#define MMCIF_CE_RESP0 0x0000002C
+#define MMCIF_CE_RESP_CMD12 0x00000030
+#define MMCIF_CE_DATA 0x00000034
+#define MMCIF_CE_INT 0x00000040
+#define MMCIF_CE_INT_MASK 0x00000044
+#define MMCIF_CE_HOST_STS1 0x00000048
+#define MMCIF_CE_HOST_STS2 0x0000004C
+#define MMCIF_CE_VERSION 0x0000007C
+
+extern inline u32 sh_mmcif_readl(void __iomem *addr, int reg)
+{
+ return readl(addr + reg);
+}
+
+extern inline void sh_mmcif_writel(void __iomem *addr, int reg, u32 val)
+{
+ writel(val, addr + reg);
+}
+
+#define SH_MMCIF_BBS 512 /* boot block size */
+
+extern inline void sh_mmcif_boot_cmd_send(void __iomem *base,
+ unsigned long cmd, unsigned long arg)
+{
+ sh_mmcif_writel(base, MMCIF_CE_INT, 0);
+ sh_mmcif_writel(base, MMCIF_CE_ARG, arg);
+ sh_mmcif_writel(base, MMCIF_CE_CMD_SET, cmd);
+}
+
+extern inline int sh_mmcif_boot_cmd_poll(void __iomem *base, unsigned long mask)
+{
+ unsigned long tmp;
+ int cnt;
+
+ for (cnt = 0; cnt < 1000000; cnt++) {
+ tmp = sh_mmcif_readl(base, MMCIF_CE_INT);
+ if (tmp & mask) {
+ sh_mmcif_writel(base, MMCIF_CE_INT, tmp & ~mask);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+extern inline int sh_mmcif_boot_cmd(void __iomem *base,
+ unsigned long cmd, unsigned long arg)
+{
+ sh_mmcif_boot_cmd_send(base, cmd, arg);
+ return sh_mmcif_boot_cmd_poll(base, 0x00010000);
+}
+
+extern inline int sh_mmcif_boot_do_read_single(void __iomem *base,
+ unsigned int block_nr,
+ unsigned long *buf)
+{
+ int k;
+
+ /* CMD13 - Status */
+ sh_mmcif_boot_cmd(base, 0x0d400000, 0x00010000);
+
+ if (sh_mmcif_readl(base, MMCIF_CE_RESP0) != 0x0900)
+ return -1;
+
+ /* CMD17 - Read */
+ sh_mmcif_boot_cmd(base, 0x11480000, block_nr * SH_MMCIF_BBS);
+ if (sh_mmcif_boot_cmd_poll(base, 0x00100000) < 0)
+ return -1;
+
+ for (k = 0; k < (SH_MMCIF_BBS / 4); k++)
+ buf[k] = sh_mmcif_readl(base, MMCIF_CE_DATA);
+
+ return 0;
+}
+
+extern inline int sh_mmcif_boot_do_read(void __iomem *base,
+ unsigned long first_block,
+ unsigned long nr_blocks,
+ void *buf)
+{
+ unsigned long k;
+ int ret = 0;
+
+ /* CMD16 - Set the block size */
+ sh_mmcif_boot_cmd(base, 0x10400000, SH_MMCIF_BBS);
+
+ for (k = 0; !ret && k < nr_blocks; k++)
+ ret = sh_mmcif_boot_do_read_single(base, first_block + k,
+ buf + (k * SH_MMCIF_BBS));
+
+ return ret;
+}
+
+extern inline void sh_mmcif_boot_init(void __iomem *base)
+{
+ unsigned long tmp;
+
+ /* reset */
+ tmp = sh_mmcif_readl(base, MMCIF_CE_VERSION);
+ sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp | 0x80000000);
+ sh_mmcif_writel(base, MMCIF_CE_VERSION, tmp & ~0x80000000);
+
+ /* byte swap */
+ sh_mmcif_writel(base, MMCIF_CE_BUF_ACC, 0x00010000);
+
+ /* Set block size in MMCIF hardware */
+ sh_mmcif_writel(base, MMCIF_CE_BLOCK_SET, SH_MMCIF_BBS);
+
+ /* Enable the clock, set it to Bus clock/256 (about 325Khz)*/
+ sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01072fff);
+
+ /* CMD0 */
+ sh_mmcif_boot_cmd(base, 0x00000040, 0);
+
+ /* CMD1 - Get OCR */
+ do {
+ sh_mmcif_boot_cmd(base, 0x01405040, 0x40300000); /* CMD1 */
+ } while ((sh_mmcif_readl(base, MMCIF_CE_RESP0) & 0x80000000)
+ != 0x80000000);
+
+ /* CMD2 - Get CID */
+ sh_mmcif_boot_cmd(base, 0x02806040, 0);
+
+ /* CMD3 - Set card relative address */
+ sh_mmcif_boot_cmd(base, 0x03400040, 0x00010000);
+}
+
+extern inline void sh_mmcif_boot_slurp(void __iomem *base,
+ unsigned char *buf,
+ unsigned long no_bytes)
+{
+ unsigned long tmp;
+
+ /* In data transfer mode: Set clock to Bus clock/4 (about 20Mhz) */
+ sh_mmcif_writel(base, MMCIF_CE_CLK_CTRL, 0x01012fff);
+
+ /* CMD9 - Get CSD */
+ sh_mmcif_boot_cmd(base, 0x09806000, 0x00010000);
+
+ /* CMD7 - Select the card */
+ sh_mmcif_boot_cmd(base, 0x07400000, 0x00010000);
+
+ tmp = no_bytes / SH_MMCIF_BBS;
+ tmp += (no_bytes % SH_MMCIF_BBS) ? 1 : 0;
+
+ sh_mmcif_boot_do_read(base, 512, tmp, buf);
+}
+
#endif /* __SH_MMCIF_H__ */
diff --git a/include/linux/module.h b/include/linux/module.h
index 6914fcad4673..8a6b9fdc7ffa 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -181,6 +181,13 @@ void *__symbol_get(const char *symbol);
void *__symbol_get_gpl(const char *symbol);
#define symbol_get(x) ((typeof(&x))(__symbol_get(MODULE_SYMBOL_PREFIX #x)))
+/* modules using other modules: kdb wants to see this. */
+struct module_use {
+ struct list_head source_list;
+ struct list_head target_list;
+ struct module *source, *target;
+};
+
#ifndef __GENKSYMS__
#ifdef CONFIG_MODVERSIONS
/* Mark the CRC weak since genksyms apparently decides not to
@@ -359,7 +366,9 @@ struct module
#ifdef CONFIG_MODULE_UNLOAD
/* What modules depend on me? */
- struct list_head modules_which_use_me;
+ struct list_head source_list;
+ /* What modules do I depend on? */
+ struct list_head target_list;
/* Who is waiting for us to be unloaded */
struct task_struct *waiter;
@@ -663,43 +672,10 @@ static inline int module_get_iter_tracepoints(struct tracepoint_iter *iter)
#endif /* CONFIG_MODULES */
-struct device_driver;
#ifdef CONFIG_SYSFS
-struct module;
-
extern struct kset *module_kset;
extern struct kobj_type module_ktype;
extern int module_sysfs_initialized;
-
-int mod_sysfs_init(struct module *mod);
-int mod_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
- unsigned int num_params);
-int module_add_modinfo_attrs(struct module *mod);
-void module_remove_modinfo_attrs(struct module *mod);
-
-#else /* !CONFIG_SYSFS */
-
-static inline int mod_sysfs_init(struct module *mod)
-{
- return 0;
-}
-
-static inline int mod_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
- unsigned int num_params)
-{
- return 0;
-}
-
-static inline int module_add_modinfo_attrs(struct module *mod)
-{
- return 0;
-}
-
-static inline void module_remove_modinfo_attrs(struct module *mod)
-{ }
-
#endif /* CONFIG_SYSFS */
#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 82a9124f7d75..893549c04265 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -31,20 +31,23 @@ static const char __module_cat(name,__LINE__)[] \
struct kernel_param;
-/* Returns 0, or -errno. arg is in kp->arg. */
-typedef int (*param_set_fn)(const char *val, struct kernel_param *kp);
-/* Returns length written or -errno. Buffer is 4k (ie. be short!) */
-typedef int (*param_get_fn)(char *buffer, struct kernel_param *kp);
+struct kernel_param_ops {
+ /* Returns 0, or -errno. arg is in kp->arg. */
+ int (*set)(const char *val, const struct kernel_param *kp);
+ /* Returns length written or -errno. Buffer is 4k (ie. be short!) */
+ int (*get)(char *buffer, const struct kernel_param *kp);
+ /* Optional function to free kp->arg when module unloaded. */
+ void (*free)(void *arg);
+};
/* Flag bits for kernel_param.flags */
#define KPARAM_ISBOOL 2
struct kernel_param {
const char *name;
+ const struct kernel_param_ops *ops;
u16 perm;
u16 flags;
- param_set_fn set;
- param_get_fn get;
union {
void *arg;
const struct kparam_string *str;
@@ -63,12 +66,67 @@ struct kparam_array
{
unsigned int max;
unsigned int *num;
- param_set_fn set;
- param_get_fn get;
+ const struct kernel_param_ops *ops;
unsigned int elemsize;
void *elem;
};
+/**
+ * module_param - typesafe helper for a module/cmdline parameter
+ * @value: the variable to alter, and exposed parameter name.
+ * @type: the type of the parameter
+ * @perm: visibility in sysfs.
+ *
+ * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a
+ * ".") the kernel commandline parameter. Note that - is changed to _, so
+ * the user can use "foo-bar=1" even for variable "foo_bar".
+ *
+ * @perm is 0 if the the variable is not to appear in sysfs, or 0444
+ * for world-readable, 0644 for root-writable, etc. Note that if it
+ * is writable, you may need to use kparam_block_sysfs_write() around
+ * accesses (esp. charp, which can be kfreed when it changes).
+ *
+ * The @type is simply pasted to refer to a param_ops_##type and a
+ * param_check_##type: for convenience many standard types are provided but
+ * you can create your own by defining those variables.
+ *
+ * Standard types are:
+ * byte, short, ushort, int, uint, long, ulong
+ * charp: a character pointer
+ * bool: a bool, values 0/1, y/n, Y/N.
+ * invbool: the above, only sense-reversed (N = true).
+ */
+#define module_param(name, type, perm) \
+ module_param_named(name, name, type, perm)
+
+/**
+ * module_param_named - typesafe helper for a renamed module/cmdline parameter
+ * @name: a valid C identifier which is the parameter name.
+ * @value: the actual lvalue to alter.
+ * @type: the type of the parameter
+ * @perm: visibility in sysfs.
+ *
+ * Usually it's a good idea to have variable names and user-exposed names the
+ * same, but that's harder if the variable must be non-static or is inside a
+ * structure. This allows exposure under a different name.
+ */
+#define module_param_named(name, value, type, perm) \
+ param_check_##type(name, &(value)); \
+ module_param_cb(name, &param_ops_##type, &value, perm); \
+ __MODULE_PARM_TYPE(name, #type)
+
+/**
+ * module_param_cb - general callback for a module/cmdline parameter
+ * @name: a valid C identifier which is the parameter name.
+ * @ops: the set & get operations for this parameter.
+ * @perm: visibility in sysfs.
+ *
+ * The ops can have NULL set or get functions.
+ */
+#define module_param_cb(name, ops, arg, perm) \
+ __module_param_call(MODULE_PARAM_PREFIX, \
+ name, ops, arg, __same_type(*(arg), bool), perm)
+
/* On alpha, ia64 and ppc64 relocations to global data cannot go into
read-only sections (which is part of respective UNIX ABI on these
platforms). So 'const' makes no sense and even causes compile failures
@@ -80,10 +138,8 @@ struct kparam_array
#endif
/* This is the fundamental function for registering boot/module
- parameters. perm sets the visibility in sysfs: 000 means it's
- not there, read bits mean it's readable, write bits mean it's
- writable. */
-#define __module_param_call(prefix, name, set, get, arg, isbool, perm) \
+ parameters. */
+#define __module_param_call(prefix, name, ops, arg, isbool, perm) \
/* Default value instead of permissions? */ \
static int __param_perm_check_##name __attribute__((unused)) = \
BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)) \
@@ -92,31 +148,87 @@ struct kparam_array
static struct kernel_param __moduleparam_const __param_##name \
__used \
__attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
- = { __param_str_##name, perm, isbool ? KPARAM_ISBOOL : 0, \
- set, get, { arg } }
+ = { __param_str_##name, ops, perm, isbool ? KPARAM_ISBOOL : 0, \
+ { arg } }
+
+/* Obsolete - use module_param_cb() */
+#define module_param_call(name, set, get, arg, perm) \
+ static struct kernel_param_ops __param_ops_##name = \
+ { (void *)set, (void *)get }; \
+ __module_param_call(MODULE_PARAM_PREFIX, \
+ name, &__param_ops_##name, arg, \
+ __same_type(*(arg), bool), \
+ (perm) + sizeof(__check_old_set_param(set))*0)
+
+/* We don't get oldget: it's often a new-style param_get_uint, etc. */
+static inline int
+__check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
+{
+ return 0;
+}
-#define module_param_call(name, set, get, arg, perm) \
- __module_param_call(MODULE_PARAM_PREFIX, \
- name, set, get, arg, \
- __same_type(*(arg), bool), perm)
+/**
+ * kparam_block_sysfs_write - make sure a parameter isn't written via sysfs.
+ * @name: the name of the parameter
+ *
+ * There's no point blocking write on a paramter that isn't writable via sysfs!
+ */
+#define kparam_block_sysfs_write(name) \
+ do { \
+ BUG_ON(!(__param_##name.perm & 0222)); \
+ __kernel_param_lock(); \
+ } while (0)
-/* Helper functions: type is byte, short, ushort, int, uint, long,
- ulong, charp, bool or invbool, or XXX if you define param_get_XXX,
- param_set_XXX and param_check_XXX. */
-#define module_param_named(name, value, type, perm) \
- param_check_##type(name, &(value)); \
- module_param_call(name, param_set_##type, param_get_##type, &value, perm); \
- __MODULE_PARM_TYPE(name, #type)
+/**
+ * kparam_unblock_sysfs_write - allows sysfs to write to a parameter again.
+ * @name: the name of the parameter
+ */
+#define kparam_unblock_sysfs_write(name) \
+ do { \
+ BUG_ON(!(__param_##name.perm & 0222)); \
+ __kernel_param_unlock(); \
+ } while (0)
-#define module_param(name, type, perm) \
- module_param_named(name, name, type, perm)
+/**
+ * kparam_block_sysfs_read - make sure a parameter isn't read via sysfs.
+ * @name: the name of the parameter
+ *
+ * This also blocks sysfs writes.
+ */
+#define kparam_block_sysfs_read(name) \
+ do { \
+ BUG_ON(!(__param_##name.perm & 0444)); \
+ __kernel_param_lock(); \
+ } while (0)
+
+/**
+ * kparam_unblock_sysfs_read - allows sysfs to read a parameter again.
+ * @name: the name of the parameter
+ */
+#define kparam_unblock_sysfs_read(name) \
+ do { \
+ BUG_ON(!(__param_##name.perm & 0444)); \
+ __kernel_param_unlock(); \
+ } while (0)
+
+#ifdef CONFIG_SYSFS
+extern void __kernel_param_lock(void);
+extern void __kernel_param_unlock(void);
+#else
+static inline void __kernel_param_lock(void)
+{
+}
+static inline void __kernel_param_unlock(void)
+{
+}
+#endif
#ifndef MODULE
/**
* core_param - define a historical core kernel parameter.
* @name: the name of the cmdline and sysfs parameter (often the same as var)
* @var: the variable
- * @type: the type (for param_set_##type and param_get_##type)
+ * @type: the type of the parameter
* @perm: visibility in sysfs
*
* core_param is just like module_param(), but cannot be modular and
@@ -126,23 +238,32 @@ struct kparam_array
*/
#define core_param(name, var, type, perm) \
param_check_##type(name, &(var)); \
- __module_param_call("", name, param_set_##type, param_get_##type, \
+ __module_param_call("", name, &param_ops_##type, \
&var, __same_type(var, bool), perm)
#endif /* !MODULE */
-/* Actually copy string: maxlen param is usually sizeof(string). */
+/**
+ * module_param_string - a char array parameter
+ * @name: the name of the parameter
+ * @string: the string variable
+ * @len: the maximum length of the string, incl. terminator
+ * @perm: visibility in sysfs.
+ *
+ * This actually copies the string when it's set (unlike type charp).
+ * @len is usually just sizeof(string).
+ */
#define module_param_string(name, string, len, perm) \
static const struct kparam_string __param_string_##name \
= { len, string }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \
- param_set_copystring, param_get_string, \
+ &param_ops_string, \
.str = &__param_string_##name, 0, perm); \
__MODULE_PARM_TYPE(name, "string")
/* Called on module insert or kernel boot */
extern int parse_args(const char *name,
char *args,
- struct kernel_param *params,
+ const struct kernel_param *params,
unsigned num,
int (*unknown)(char *param, char *val));
@@ -162,41 +283,50 @@ static inline void destroy_params(const struct kernel_param *params,
#define __param_check(name, p, type) \
static inline type *__check_##name(void) { return(p); }
-extern int param_set_byte(const char *val, struct kernel_param *kp);
-extern int param_get_byte(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_byte;
+extern int param_set_byte(const char *val, const struct kernel_param *kp);
+extern int param_get_byte(char *buffer, const struct kernel_param *kp);
#define param_check_byte(name, p) __param_check(name, p, unsigned char)
-extern int param_set_short(const char *val, struct kernel_param *kp);
-extern int param_get_short(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_short;
+extern int param_set_short(const char *val, const struct kernel_param *kp);
+extern int param_get_short(char *buffer, const struct kernel_param *kp);
#define param_check_short(name, p) __param_check(name, p, short)
-extern int param_set_ushort(const char *val, struct kernel_param *kp);
-extern int param_get_ushort(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_ushort;
+extern int param_set_ushort(const char *val, const struct kernel_param *kp);
+extern int param_get_ushort(char *buffer, const struct kernel_param *kp);
#define param_check_ushort(name, p) __param_check(name, p, unsigned short)
-extern int param_set_int(const char *val, struct kernel_param *kp);
-extern int param_get_int(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_int;
+extern int param_set_int(const char *val, const struct kernel_param *kp);
+extern int param_get_int(char *buffer, const struct kernel_param *kp);
#define param_check_int(name, p) __param_check(name, p, int)
-extern int param_set_uint(const char *val, struct kernel_param *kp);
-extern int param_get_uint(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_uint;
+extern int param_set_uint(const char *val, const struct kernel_param *kp);
+extern int param_get_uint(char *buffer, const struct kernel_param *kp);
#define param_check_uint(name, p) __param_check(name, p, unsigned int)
-extern int param_set_long(const char *val, struct kernel_param *kp);
-extern int param_get_long(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_long;
+extern int param_set_long(const char *val, const struct kernel_param *kp);
+extern int param_get_long(char *buffer, const struct kernel_param *kp);
#define param_check_long(name, p) __param_check(name, p, long)
-extern int param_set_ulong(const char *val, struct kernel_param *kp);
-extern int param_get_ulong(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_ulong;
+extern int param_set_ulong(const char *val, const struct kernel_param *kp);
+extern int param_get_ulong(char *buffer, const struct kernel_param *kp);
#define param_check_ulong(name, p) __param_check(name, p, unsigned long)
-extern int param_set_charp(const char *val, struct kernel_param *kp);
-extern int param_get_charp(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_charp;
+extern int param_set_charp(const char *val, const struct kernel_param *kp);
+extern int param_get_charp(char *buffer, const struct kernel_param *kp);
#define param_check_charp(name, p) __param_check(name, p, char *)
/* For historical reasons "bool" parameters can be (unsigned) "int". */
-extern int param_set_bool(const char *val, struct kernel_param *kp);
-extern int param_get_bool(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_bool;
+extern int param_set_bool(const char *val, const struct kernel_param *kp);
+extern int param_get_bool(char *buffer, const struct kernel_param *kp);
#define param_check_bool(name, p) \
static inline void __check_##name(void) \
{ \
@@ -205,29 +335,53 @@ extern int param_get_bool(char *buffer, struct kernel_param *kp);
!__same_type(*(p), int)); \
}
-extern int param_set_invbool(const char *val, struct kernel_param *kp);
-extern int param_get_invbool(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_invbool;
+extern int param_set_invbool(const char *val, const struct kernel_param *kp);
+extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
#define param_check_invbool(name, p) __param_check(name, p, bool)
-/* Comma-separated array: *nump is set to number they actually specified. */
+/**
+ * module_param_array - a parameter which is an array of some type
+ * @name: the name of the array variable
+ * @type: the type, as per module_param()
+ * @nump: optional pointer filled in with the number written
+ * @perm: visibility in sysfs
+ *
+ * Input and output are as comma-separated values. Commas inside values
+ * don't work properly (eg. an array of charp).
+ *
+ * ARRAY_SIZE(@name) is used to determine the number of elements in the
+ * array, so the definition must be visible.
+ */
+#define module_param_array(name, type, nump, perm) \
+ module_param_array_named(name, name, type, nump, perm)
+
+/**
+ * module_param_array_named - renamed parameter which is an array of some type
+ * @name: a valid C identifier which is the parameter name
+ * @array: the name of the array variable
+ * @type: the type, as per module_param()
+ * @nump: optional pointer filled in with the number written
+ * @perm: visibility in sysfs
+ *
+ * This exposes a different name than the actual variable name. See
+ * module_param_named() for why this might be necessary.
+ */
#define module_param_array_named(name, array, type, nump, perm) \
static const struct kparam_array __param_arr_##name \
- = { ARRAY_SIZE(array), nump, param_set_##type, param_get_##type,\
+ = { ARRAY_SIZE(array), nump, &param_ops_##type, \
sizeof(array[0]), array }; \
__module_param_call(MODULE_PARAM_PREFIX, name, \
- param_array_set, param_array_get, \
+ &param_array_ops, \
.arr = &__param_arr_##name, \
__same_type(array[0], bool), perm); \
__MODULE_PARM_TYPE(name, "array of " #type)
-#define module_param_array(name, type, nump, perm) \
- module_param_array_named(name, name, type, nump, perm)
-
-extern int param_array_set(const char *val, struct kernel_param *kp);
-extern int param_array_get(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_array_ops;
-extern int param_set_copystring(const char *val, struct kernel_param *kp);
-extern int param_get_string(char *buffer, struct kernel_param *kp);
+extern struct kernel_param_ops param_ops_string;
+extern int param_set_copystring(const char *val, const struct kernel_param *);
+extern int param_get_string(char *buffer, const struct kernel_param *kp);
/* for exporting parameters in /sys/parameters */
@@ -235,13 +389,13 @@ struct module;
#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES)
extern int module_param_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
+ const struct kernel_param *kparam,
unsigned int num_params);
extern void module_param_sysfs_remove(struct module *mod);
#else
static inline int module_param_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
+ const struct kernel_param *kparam,
unsigned int num_params)
{
return 0;
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 4bd05474d11d..907210bd9f9c 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -56,7 +56,11 @@ struct vfsmount {
struct list_head mnt_mounts; /* list of children, anchored here */
struct list_head mnt_child; /* and going through their mnt_child */
int mnt_flags;
- /* 4 bytes hole on 64bits arches */
+ /* 4 bytes hole on 64bits arches without fsnotify */
+#ifdef CONFIG_FSNOTIFY
+ __u32 mnt_fsnotify_mask;
+ struct hlist_head mnt_fsnotify_marks;
+#endif
const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
struct list_head mnt_list;
struct list_head mnt_expire; /* link in fs-specific expiry list */
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 155719dab813..bb58854a8061 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -88,7 +88,7 @@ struct nbd_request {
char handle[8];
__be64 from;
__be32 len;
-} __attribute__ ((packed));
+} __packed;
/*
* This is the reply packet that nbd-server sends back to the client after
diff --git a/include/linux/ncp.h b/include/linux/ncp.h
index 99f0adeeb3f3..3ace8370e61e 100644
--- a/include/linux/ncp.h
+++ b/include/linux/ncp.h
@@ -27,7 +27,7 @@ struct ncp_request_header {
__u8 conn_high;
__u8 function;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
#define NCP_REPLY (0x3333)
#define NCP_WATCHDOG (0x3E3E)
@@ -42,7 +42,7 @@ struct ncp_reply_header {
__u8 completion_code;
__u8 connection_state;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
#define NCP_VOLNAME_LEN (16)
#define NCP_NUMBER_OF_VOLUMES (256)
@@ -158,7 +158,7 @@ struct nw_info_struct {
#ifdef __KERNEL__
struct nw_nfs_info nfs;
#endif
-} __attribute__((packed));
+} __packed;
/* modify mask - use with MODIFY_DOS_INFO structure */
#define DM_ATTRIBUTES (cpu_to_le32(0x02))
@@ -190,12 +190,12 @@ struct nw_modify_dos_info {
__u16 inheritanceGrantMask;
__u16 inheritanceRevokeMask;
__u32 maximumSpace;
-} __attribute__((packed));
+} __packed;
struct nw_search_sequence {
__u8 volNumber;
__u32 dirBase;
__u32 sequence;
-} __attribute__((packed));
+} __packed;
#endif /* _LINUX_NCP_H */
diff --git a/include/linux/ncp_fs_sb.h b/include/linux/ncp_fs_sb.h
index 5ec9ca671687..8da05bc098ca 100644
--- a/include/linux/ncp_fs_sb.h
+++ b/include/linux/ncp_fs_sb.h
@@ -104,13 +104,13 @@ struct ncp_server {
unsigned int state; /* STREAM only: receiver state */
struct {
- __u32 magic __attribute__((packed));
- __u32 len __attribute__((packed));
- __u16 type __attribute__((packed));
- __u16 p1 __attribute__((packed));
- __u16 p2 __attribute__((packed));
- __u16 p3 __attribute__((packed));
- __u16 type2 __attribute__((packed));
+ __u32 magic __packed;
+ __u32 len __packed;
+ __u16 type __packed;
+ __u16 p1 __packed;
+ __u16 p2 __packed;
+ __u16 p3 __packed;
+ __u16 type2 __packed;
} buf; /* STREAM only: temporary buffer */
unsigned char* ptr; /* STREAM only: pointer to data */
size_t len; /* STREAM only: length of data to receive */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 40291f375024..6edb72c982cc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -381,6 +381,8 @@ enum gro_result {
};
typedef enum gro_result gro_result_t;
+typedef struct sk_buff *rx_handler_func_t(struct sk_buff *skb);
+
extern void __napi_schedule(struct napi_struct *n);
static inline int napi_disable_pending(struct napi_struct *n)
@@ -775,7 +777,7 @@ struct net_device {
/*
* This is the first field of the "visible" part of this structure
* (i.e. as seen by users in the "Space.c" file). It is the name
- * the interface.
+ * of the interface.
*/
char name[IFNAMSIZ];
@@ -957,6 +959,7 @@ struct net_device {
#endif
struct netdev_queue rx_queue;
+ rx_handler_func_t *rx_handler;
struct netdev_queue *_tx ____cacheline_aligned_in_smp;
@@ -1087,11 +1090,7 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev,
static inline
struct net *dev_net(const struct net_device *dev)
{
-#ifdef CONFIG_NET_NS
- return dev->nd_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&dev->nd_net);
}
static inline
@@ -1693,6 +1692,10 @@ static inline void napi_free_frags(struct napi_struct *napi)
napi->skb = NULL;
}
+extern int netdev_rx_handler_register(struct net_device *dev,
+ rx_handler_func_t *rx_handler);
+extern void netdev_rx_handler_unregister(struct net_device *dev);
+
extern void netif_nit_deliver(struct sk_buff *skb);
extern int dev_valid_name(const char *name);
extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *);
@@ -1772,6 +1775,8 @@ extern void netif_carrier_on(struct net_device *dev);
extern void netif_carrier_off(struct net_device *dev);
+extern void netif_notify_peers(struct net_device *dev);
+
/**
* netif_dormant_on - mark device as dormant.
* @dev: network device
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index c00cc0c4d0b7..24e5d01d27d0 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -397,7 +397,7 @@ struct xt_table_info {
* @stacksize jumps (number of user chains) can possibly be made.
*/
unsigned int stacksize;
- unsigned int *stackptr;
+ unsigned int __percpu *stackptr;
void ***jumpstack;
/* ipt_entry tables: one per CPU */
/* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index b7c77f9712f4..64fb32b93a28 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -132,7 +132,7 @@
* %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
* %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
* @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
- * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * to the specified ISO/IEC 3166-1 alpha2 country code. The core will
* store this as a valid request and then query userspace for it.
*
* @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index b752e807adde..06aab5eee134 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -20,10 +20,14 @@ extern void touch_nmi_watchdog(void);
extern void acpi_nmi_disable(void);
extern void acpi_nmi_enable(void);
#else
+#ifndef CONFIG_HARDLOCKUP_DETECTOR
static inline void touch_nmi_watchdog(void)
{
touch_softlockup_watchdog();
}
+#else
+extern void touch_nmi_watchdog(void);
+#endif
static inline void acpi_nmi_disable(void) { }
static inline void acpi_nmi_enable(void) { }
#endif
@@ -47,4 +51,13 @@ static inline bool trigger_all_cpu_backtrace(void)
}
#endif
+#ifdef CONFIG_LOCKUP_DETECTOR
+int hw_nmi_is_cpu_stuck(struct pt_regs *);
+u64 hw_nmi_get_sample_period(void);
+extern int watchdog_enabled;
+struct ctl_table;
+extern int proc_dowatchdog_enabled(struct ctl_table *, int ,
+ void __user *, size_t *, loff_t *);
+#endif
+
#endif
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 540703b555cb..b2f1a4d83550 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -210,6 +210,7 @@ static inline int notifier_to_errno(int ret)
#define NETDEV_POST_INIT 0x0010
#define NETDEV_UNREGISTER_BATCH 0x0011
#define NETDEV_BONDING_DESLAVE 0x0012
+#define NETDEV_NOTIFY_PEERS 0x0013
#define SYS_DOWN 0x0001 /* Notify of system down */
#define SYS_RESTART SYS_DOWN
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 6a471aba3b07..7cb00845f150 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -632,6 +632,7 @@ void pci_fixup_cardbus(struct pci_bus *);
/* Generic PCI functions used internally */
+void pcibios_scan_specific_bus(int busn);
extern struct pci_bus *pci_find_bus(int domain, int busnr);
void pci_bus_add_devices(const struct pci_bus *bus);
struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus,
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index ae66851870be..4eb467910a45 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -2321,6 +2321,7 @@
#define PCI_VENDOR_ID_JMICRON 0x197B
#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360
#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361
+#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362
#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363
#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365
#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366
@@ -2532,11 +2533,63 @@
#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930
#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916
#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918
+#define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18
+#define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19
+#define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a
+#define PCI_DEVICE_ID_INTEL_I7_MC_TEST 0x2c1c
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL 0x2c20
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR 0x2c21
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK 0x2c22
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC 0x2c23
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL 0x2c28
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR 0x2c29
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK 0x2c2a
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC 0x2c2b
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL 0x2c30
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32
+#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33
+#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41
+#define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR 0x2c98
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD 0x2c99
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST 0x2c9C
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL 0x2ca0
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR 0x2ca1
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK 0x2ca2
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC 0x2ca3
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL 0x2ca8
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR 0x2ca9
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK 0x2caa
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC 0x2cab
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2 0x2d98
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2 0x2d99
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2 0x2d9a
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2 0x2d9c
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2 0x2da0
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2 0x2da1
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2 0x2da2
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2 0x2da3
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2 0x2da8
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2 0x2da9
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2 0x2daa
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2 0x2dab
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2 0x2db0
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2
+#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3
#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340
#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429
#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a
#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b
#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c
+#define PCI_DEVICE_ID_INTEL_X58_HUB_MGMT 0x342e
#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430
#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431
#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432
diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h
index 68567c0b3a5d..ce2dc655cd1d 100644
--- a/include/linux/percpu-defs.h
+++ b/include/linux/percpu-defs.h
@@ -131,11 +131,11 @@
* Declaration/definition used for per-CPU variables that must be page aligned.
*/
#define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \
- DECLARE_PER_CPU_SECTION(type, name, ".page_aligned") \
+ DECLARE_PER_CPU_SECTION(type, name, "..page_aligned") \
__aligned(PAGE_SIZE)
#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name) \
- DEFINE_PER_CPU_SECTION(type, name, ".page_aligned") \
+ DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \
__aligned(PAGE_SIZE)
/*
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index fb6c91eac7e3..5d0266d94985 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -585,6 +585,7 @@ enum perf_event_active_state {
struct file;
struct perf_mmap_data {
+ atomic_t refcount;
struct rcu_head rcu_head;
#ifdef CONFIG_PERF_USE_VMALLOC
struct work_struct work;
@@ -592,7 +593,6 @@ struct perf_mmap_data {
#endif
int nr_pages; /* nr of data pages */
int writable; /* are we writable */
- int nr_locked; /* nr pages mlocked */
atomic_t poll; /* POLL_ for wakeups */
@@ -631,6 +631,9 @@ struct swevent_hlist {
struct rcu_head rcu_head;
};
+#define PERF_ATTACH_CONTEXT 0x01
+#define PERF_ATTACH_GROUP 0x02
+
/**
* struct perf_event - performance event kernel representation:
*/
@@ -643,10 +646,10 @@ struct perf_event {
int nr_siblings;
int group_flags;
struct perf_event *group_leader;
- struct perf_event *output;
const struct pmu *pmu;
enum perf_event_active_state state;
+ unsigned int attach_state;
atomic64_t count;
/*
@@ -704,6 +707,8 @@ struct perf_event {
/* mmap bits */
struct mutex mmap_mutex;
atomic_t mmap_count;
+ int mmap_locked;
+ struct user_struct *mmap_user;
struct perf_mmap_data *data;
/* poll related */
diff --git a/include/linux/personality.h b/include/linux/personality.h
index 126120819a0d..eec3bae164d4 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -12,7 +12,7 @@ struct pt_regs;
extern int register_exec_domain(struct exec_domain *);
extern int unregister_exec_domain(struct exec_domain *);
-extern int __set_personality(unsigned long);
+extern int __set_personality(unsigned int);
#endif /* __KERNEL__ */
diff --git a/include/linux/phonet.h b/include/linux/phonet.h
index e5126cff9b2a..24426c3d6b5a 100644
--- a/include/linux/phonet.h
+++ b/include/linux/phonet.h
@@ -56,7 +56,7 @@ struct phonethdr {
__be16 pn_length;
__u8 pn_robj;
__u8 pn_sobj;
-} __attribute__((packed));
+} __packed;
/* Common Phonet payload header */
struct phonetmsg {
@@ -98,7 +98,7 @@ struct sockaddr_pn {
__u8 spn_dev;
__u8 spn_resource;
__u8 spn_zero[sizeof(struct sockaddr) - sizeof(sa_family_t) - 3];
-} __attribute__ ((packed));
+} __packed;
/* Well known address */
#define PN_DEV_PC 0x10
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index 16de3933c45e..445796945ac9 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -139,7 +139,9 @@ void pipe_lock(struct pipe_inode_info *);
void pipe_unlock(struct pipe_inode_info *);
void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *);
-extern unsigned int pipe_max_pages;
+extern unsigned int pipe_max_size, pipe_min_size;
+int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *);
+
/* Drop the inode semaphore and wait for a pipe event, atomically */
void pipe_wait(struct pipe_inode_info *pipe);
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index aa36793b48bd..126193c1a5ce 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -145,11 +145,6 @@ static inline bool sb_has_quota_active(struct super_block *sb, int type)
!sb_has_quota_suspended(sb, type);
}
-static inline unsigned sb_any_quota_active(struct super_block *sb)
-{
- return sb_any_quota_loaded(sb) & ~sb_any_quota_suspended(sb);
-}
-
/*
* Operations supported for diskquotas.
*/
@@ -194,11 +189,6 @@ static inline int sb_has_quota_active(struct super_block *sb, int type)
return 0;
}
-static inline int sb_any_quota_active(struct super_block *sb)
-{
- return 0;
-}
-
static inline void dquot_initialize(struct inode *inode)
{
}
diff --git a/include/linux/rds.h b/include/linux/rds.h
index cab4994c2f63..24bce3ded9ea 100644
--- a/include/linux/rds.h
+++ b/include/linux/rds.h
@@ -100,7 +100,7 @@
struct rds_info_counter {
u_int8_t name[32];
u_int64_t value;
-} __attribute__((packed));
+} __packed;
#define RDS_INFO_CONNECTION_FLAG_SENDING 0x01
#define RDS_INFO_CONNECTION_FLAG_CONNECTING 0x02
@@ -115,7 +115,7 @@ struct rds_info_connection {
__be32 faddr;
u_int8_t transport[TRANSNAMSIZ]; /* null term ascii */
u_int8_t flags;
-} __attribute__((packed));
+} __packed;
struct rds_info_flow {
__be32 laddr;
@@ -123,7 +123,7 @@ struct rds_info_flow {
u_int32_t bytes;
__be16 lport;
__be16 fport;
-} __attribute__((packed));
+} __packed;
#define RDS_INFO_MESSAGE_FLAG_ACK 0x01
#define RDS_INFO_MESSAGE_FLAG_FAST_ACK 0x02
@@ -136,7 +136,7 @@ struct rds_info_message {
__be16 lport;
__be16 fport;
u_int8_t flags;
-} __attribute__((packed));
+} __packed;
struct rds_info_socket {
u_int32_t sndbuf;
@@ -146,7 +146,7 @@ struct rds_info_socket {
__be16 connected_port;
u_int32_t rcvbuf;
u_int64_t inum;
-} __attribute__((packed));
+} __packed;
struct rds_info_tcp_socket {
__be32 local_addr;
@@ -158,7 +158,7 @@ struct rds_info_tcp_socket {
u_int32_t last_sent_nxt;
u_int32_t last_expected_una;
u_int32_t last_seen_una;
-} __attribute__((packed));
+} __packed;
#define RDS_IB_GID_LEN 16
struct rds_info_rdma_connection {
diff --git a/include/linux/sched.h b/include/linux/sched.h
index f118809c953f..8485aa2d8db5 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -315,20 +315,16 @@ extern void scheduler_tick(void);
extern void sched_show_task(struct task_struct *p);
-#ifdef CONFIG_DETECT_SOFTLOCKUP
-extern void softlockup_tick(void);
+#ifdef CONFIG_LOCKUP_DETECTOR
extern void touch_softlockup_watchdog(void);
extern void touch_softlockup_watchdog_sync(void);
extern void touch_all_softlockup_watchdogs(void);
-extern int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos);
+extern int proc_dowatchdog_thresh(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos);
extern unsigned int softlockup_panic;
extern int softlockup_thresh;
#else
-static inline void softlockup_tick(void)
-{
-}
static inline void touch_softlockup_watchdog(void)
{
}
diff --git a/include/linux/sctp.h b/include/linux/sctp.h
index c20d3ce673c0..c11a28706fa4 100644
--- a/include/linux/sctp.h
+++ b/include/linux/sctp.h
@@ -61,7 +61,7 @@ typedef struct sctphdr {
__be16 dest;
__be32 vtag;
__le32 checksum;
-} __attribute__((packed)) sctp_sctphdr_t;
+} __packed sctp_sctphdr_t;
#ifdef __KERNEL__
#include <linux/skbuff.h>
@@ -77,7 +77,7 @@ typedef struct sctp_chunkhdr {
__u8 type;
__u8 flags;
__be16 length;
-} __attribute__((packed)) sctp_chunkhdr_t;
+} __packed sctp_chunkhdr_t;
/* Section 3.2. Chunk Type Values.
@@ -167,7 +167,7 @@ enum { SCTP_CHUNK_FLAG_T = 0x01 };
typedef struct sctp_paramhdr {
__be16 type;
__be16 length;
-} __attribute__((packed)) sctp_paramhdr_t;
+} __packed sctp_paramhdr_t;
typedef enum {
@@ -228,12 +228,12 @@ typedef struct sctp_datahdr {
__be16 ssn;
__be32 ppid;
__u8 payload[0];
-} __attribute__((packed)) sctp_datahdr_t;
+} __packed sctp_datahdr_t;
typedef struct sctp_data_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_datahdr_t data_hdr;
-} __attribute__((packed)) sctp_data_chunk_t;
+} __packed sctp_data_chunk_t;
/* DATA Chuck Specific Flags */
enum {
@@ -259,78 +259,78 @@ typedef struct sctp_inithdr {
__be16 num_inbound_streams;
__be32 initial_tsn;
__u8 params[0];
-} __attribute__((packed)) sctp_inithdr_t;
+} __packed sctp_inithdr_t;
typedef struct sctp_init_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_inithdr_t init_hdr;
-} __attribute__((packed)) sctp_init_chunk_t;
+} __packed sctp_init_chunk_t;
/* Section 3.3.2.1. IPv4 Address Parameter (5) */
typedef struct sctp_ipv4addr_param {
sctp_paramhdr_t param_hdr;
struct in_addr addr;
-} __attribute__((packed)) sctp_ipv4addr_param_t;
+} __packed sctp_ipv4addr_param_t;
/* Section 3.3.2.1. IPv6 Address Parameter (6) */
typedef struct sctp_ipv6addr_param {
sctp_paramhdr_t param_hdr;
struct in6_addr addr;
-} __attribute__((packed)) sctp_ipv6addr_param_t;
+} __packed sctp_ipv6addr_param_t;
/* Section 3.3.2.1 Cookie Preservative (9) */
typedef struct sctp_cookie_preserve_param {
sctp_paramhdr_t param_hdr;
__be32 lifespan_increment;
-} __attribute__((packed)) sctp_cookie_preserve_param_t;
+} __packed sctp_cookie_preserve_param_t;
/* Section 3.3.2.1 Host Name Address (11) */
typedef struct sctp_hostname_param {
sctp_paramhdr_t param_hdr;
uint8_t hostname[0];
-} __attribute__((packed)) sctp_hostname_param_t;
+} __packed sctp_hostname_param_t;
/* Section 3.3.2.1 Supported Address Types (12) */
typedef struct sctp_supported_addrs_param {
sctp_paramhdr_t param_hdr;
__be16 types[0];
-} __attribute__((packed)) sctp_supported_addrs_param_t;
+} __packed sctp_supported_addrs_param_t;
/* Appendix A. ECN Capable (32768) */
typedef struct sctp_ecn_capable_param {
sctp_paramhdr_t param_hdr;
-} __attribute__((packed)) sctp_ecn_capable_param_t;
+} __packed sctp_ecn_capable_param_t;
/* ADDIP Section 3.2.6 Adaptation Layer Indication */
typedef struct sctp_adaptation_ind_param {
struct sctp_paramhdr param_hdr;
__be32 adaptation_ind;
-} __attribute__((packed)) sctp_adaptation_ind_param_t;
+} __packed sctp_adaptation_ind_param_t;
/* ADDIP Section 4.2.7 Supported Extensions Parameter */
typedef struct sctp_supported_ext_param {
struct sctp_paramhdr param_hdr;
__u8 chunks[0];
-} __attribute__((packed)) sctp_supported_ext_param_t;
+} __packed sctp_supported_ext_param_t;
/* AUTH Section 3.1 Random */
typedef struct sctp_random_param {
sctp_paramhdr_t param_hdr;
__u8 random_val[0];
-} __attribute__((packed)) sctp_random_param_t;
+} __packed sctp_random_param_t;
/* AUTH Section 3.2 Chunk List */
typedef struct sctp_chunks_param {
sctp_paramhdr_t param_hdr;
__u8 chunks[0];
-} __attribute__((packed)) sctp_chunks_param_t;
+} __packed sctp_chunks_param_t;
/* AUTH Section 3.3 HMAC Algorithm */
typedef struct sctp_hmac_algo_param {
sctp_paramhdr_t param_hdr;
__be16 hmac_ids[0];
-} __attribute__((packed)) sctp_hmac_algo_param_t;
+} __packed sctp_hmac_algo_param_t;
/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2):
* The INIT ACK chunk is used to acknowledge the initiation of an SCTP
@@ -342,13 +342,13 @@ typedef sctp_init_chunk_t sctp_initack_chunk_t;
typedef struct sctp_cookie_param {
sctp_paramhdr_t p;
__u8 body[0];
-} __attribute__((packed)) sctp_cookie_param_t;
+} __packed sctp_cookie_param_t;
/* Section 3.3.3.1 Unrecognized Parameters (8) */
typedef struct sctp_unrecognized_param {
sctp_paramhdr_t param_hdr;
sctp_paramhdr_t unrecognized;
-} __attribute__((packed)) sctp_unrecognized_param_t;
+} __packed sctp_unrecognized_param_t;
@@ -363,7 +363,7 @@ typedef struct sctp_unrecognized_param {
typedef struct sctp_gap_ack_block {
__be16 start;
__be16 end;
-} __attribute__((packed)) sctp_gap_ack_block_t;
+} __packed sctp_gap_ack_block_t;
typedef __be32 sctp_dup_tsn_t;
@@ -378,12 +378,12 @@ typedef struct sctp_sackhdr {
__be16 num_gap_ack_blocks;
__be16 num_dup_tsns;
sctp_sack_variable_t variable[0];
-} __attribute__((packed)) sctp_sackhdr_t;
+} __packed sctp_sackhdr_t;
typedef struct sctp_sack_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_sackhdr_t sack_hdr;
-} __attribute__((packed)) sctp_sack_chunk_t;
+} __packed sctp_sack_chunk_t;
/* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4):
@@ -395,12 +395,12 @@ typedef struct sctp_sack_chunk {
typedef struct sctp_heartbeathdr {
sctp_paramhdr_t info;
-} __attribute__((packed)) sctp_heartbeathdr_t;
+} __packed sctp_heartbeathdr_t;
typedef struct sctp_heartbeat_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_heartbeathdr_t hb_hdr;
-} __attribute__((packed)) sctp_heartbeat_chunk_t;
+} __packed sctp_heartbeat_chunk_t;
/* For the abort and shutdown ACK we must carry the init tag in the
@@ -409,7 +409,7 @@ typedef struct sctp_heartbeat_chunk {
*/
typedef struct sctp_abort_chunk {
sctp_chunkhdr_t uh;
-} __attribute__((packed)) sctp_abort_chunk_t;
+} __packed sctp_abort_chunk_t;
/* For the graceful shutdown we must carry the tag (in common header)
@@ -417,12 +417,12 @@ typedef struct sctp_abort_chunk {
*/
typedef struct sctp_shutdownhdr {
__be32 cum_tsn_ack;
-} __attribute__((packed)) sctp_shutdownhdr_t;
+} __packed sctp_shutdownhdr_t;
struct sctp_shutdown_chunk_t {
sctp_chunkhdr_t chunk_hdr;
sctp_shutdownhdr_t shutdown_hdr;
-} __attribute__ ((packed));
+} __packed;
/* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */
@@ -430,12 +430,12 @@ typedef struct sctp_errhdr {
__be16 cause;
__be16 length;
__u8 variable[0];
-} __attribute__((packed)) sctp_errhdr_t;
+} __packed sctp_errhdr_t;
typedef struct sctp_operr_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_errhdr_t err_hdr;
-} __attribute__((packed)) sctp_operr_chunk_t;
+} __packed sctp_operr_chunk_t;
/* RFC 2960 3.3.10 - Operation Error
*
@@ -525,7 +525,7 @@ typedef struct sctp_ecnehdr {
typedef struct sctp_ecne_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_ecnehdr_t ence_hdr;
-} __attribute__((packed)) sctp_ecne_chunk_t;
+} __packed sctp_ecne_chunk_t;
/* RFC 2960. Appendix A. Explicit Congestion Notification.
* Congestion Window Reduced (CWR) (13)
@@ -537,7 +537,7 @@ typedef struct sctp_cwrhdr {
typedef struct sctp_cwr_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_cwrhdr_t cwr_hdr;
-} __attribute__((packed)) sctp_cwr_chunk_t;
+} __packed sctp_cwr_chunk_t;
/* PR-SCTP
* 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN)
@@ -588,17 +588,17 @@ typedef struct sctp_cwr_chunk {
struct sctp_fwdtsn_skip {
__be16 stream;
__be16 ssn;
-} __attribute__((packed));
+} __packed;
struct sctp_fwdtsn_hdr {
__be32 new_cum_tsn;
struct sctp_fwdtsn_skip skip[0];
-} __attribute((packed));
+} __packed;
struct sctp_fwdtsn_chunk {
struct sctp_chunkhdr chunk_hdr;
struct sctp_fwdtsn_hdr fwdtsn_hdr;
-} __attribute((packed));
+} __packed;
/* ADDIP
@@ -636,17 +636,17 @@ struct sctp_fwdtsn_chunk {
typedef struct sctp_addip_param {
sctp_paramhdr_t param_hdr;
__be32 crr_id;
-} __attribute__((packed)) sctp_addip_param_t;
+} __packed sctp_addip_param_t;
typedef struct sctp_addiphdr {
__be32 serial;
__u8 params[0];
-} __attribute__((packed)) sctp_addiphdr_t;
+} __packed sctp_addiphdr_t;
typedef struct sctp_addip_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_addiphdr_t addip_hdr;
-} __attribute__((packed)) sctp_addip_chunk_t;
+} __packed sctp_addip_chunk_t;
/* AUTH
* Section 4.1 Authentication Chunk (AUTH)
@@ -701,11 +701,11 @@ typedef struct sctp_authhdr {
__be16 shkey_id;
__be16 hmac_id;
__u8 hmac[0];
-} __attribute__((packed)) sctp_authhdr_t;
+} __packed sctp_authhdr_t;
typedef struct sctp_auth_chunk {
sctp_chunkhdr_t chunk_hdr;
sctp_authhdr_t auth_hdr;
-} __attribute__((packed)) sctp_auth_chunk_t;
+} __packed sctp_auth_chunk_t;
#endif /* __LINUX_SCTP_H__ */
diff --git a/include/linux/security.h b/include/linux/security.h
index 0c8819170463..5bcb395a49d4 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -23,6 +23,7 @@
#define __LINUX_SECURITY_H
#include <linux/fs.h>
+#include <linux/fsnotify.h>
#include <linux/binfmts.h>
#include <linux/signal.h>
#include <linux/resource.h>
@@ -470,8 +471,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
* @path_truncate:
* Check permission before truncating a file.
* @path contains the path structure for the file.
- * @length is the new length of the file.
- * @time_attrs is the flags passed to do_truncate().
* Return 0 if permission is granted.
* @inode_getattr:
* Check permission before obtaining file attributes.
@@ -1412,8 +1411,7 @@ struct security_operations {
int (*path_rmdir) (struct path *dir, struct dentry *dentry);
int (*path_mknod) (struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
- int (*path_truncate) (struct path *path, loff_t length,
- unsigned int time_attrs);
+ int (*path_truncate) (struct path *path);
int (*path_symlink) (struct path *dir, struct dentry *dentry,
const char *old_name);
int (*path_link) (struct dentry *old_dentry, struct path *new_dir,
@@ -2806,8 +2804,7 @@ int security_path_mkdir(struct path *dir, struct dentry *dentry, int mode);
int security_path_rmdir(struct path *dir, struct dentry *dentry);
int security_path_mknod(struct path *dir, struct dentry *dentry, int mode,
unsigned int dev);
-int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs);
+int security_path_truncate(struct path *path);
int security_path_symlink(struct path *dir, struct dentry *dentry,
const char *old_name);
int security_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -2841,8 +2838,7 @@ static inline int security_path_mknod(struct path *dir, struct dentry *dentry,
return 0;
}
-static inline int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static inline int security_path_truncate(struct path *path)
{
return 0;
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index f10db6e5f3b5..522832023a69 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -186,6 +186,9 @@
#define PORT_ALTERA_JTAGUART 91
#define PORT_ALTERA_UART 92
+/* SH-SCI */
+#define PORT_SCIFB 93
+
#ifdef __KERNEL__
#include <linux/compiler.h>
diff --git a/include/linux/serial_sci.h b/include/linux/serial_sci.h
index f5364a1de68b..baed2122c5a6 100644
--- a/include/linux/serial_sci.h
+++ b/include/linux/serial_sci.h
@@ -2,9 +2,7 @@
#define __LINUX_SERIAL_SCI_H
#include <linux/serial_core.h>
-#ifdef CONFIG_SERIAL_SH_SCI_DMA
-#include <asm/dmaengine.h>
-#endif
+#include <linux/sh_dma.h>
/*
* Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts)
diff --git a/include/linux/shm_signal.h b/include/linux/shm_signal.h
new file mode 100644
index 000000000000..b2efd72669fb
--- /dev/null
+++ b/include/linux/shm_signal.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_SHM_SIGNAL_H
+#define _LINUX_SHM_SIGNAL_H
+
+#include <linux/types.h>
+
+/*
+ *---------
+ * The following structures represent data that is shared across boundaries
+ * which may be quite disparate from one another (e.g. Windows vs Linux,
+ * 32 vs 64 bit, etc). Therefore, care has been taken to make sure they
+ * present data in a manner that is independent of the environment.
+ *-----------
+ */
+
+#define SHM_SIGNAL_MAGIC cpu_to_le32(0x58fa39df)
+#define SHM_SIGNAL_VER cpu_to_le32(1)
+
+struct shm_signal_irq {
+ __u8 enabled;
+ __u8 pending;
+ __u8 dirty;
+};
+
+enum shm_signal_locality {
+ shm_locality_north,
+ shm_locality_south,
+};
+
+struct shm_signal_desc {
+ __le32 magic;
+ __le32 ver;
+ struct shm_signal_irq irq[2];
+};
+
+/* --- END SHARED STRUCTURES --- */
+
+#ifdef __KERNEL__
+
+#include <linux/kref.h>
+#include <linux/interrupt.h>
+
+struct shm_signal_notifier {
+ void (*signal)(struct shm_signal_notifier *);
+};
+
+struct shm_signal;
+
+struct shm_signal_ops {
+ int (*inject)(struct shm_signal *s);
+ void (*fault)(struct shm_signal *s, const char *fmt, ...);
+ void (*release)(struct shm_signal *s);
+};
+
+enum {
+ shm_signal_in_wakeup,
+};
+
+struct shm_signal {
+ struct kref kref;
+ spinlock_t lock;
+ enum shm_signal_locality locale;
+ unsigned long flags;
+ struct shm_signal_ops *ops;
+ struct shm_signal_desc *desc;
+ struct shm_signal_notifier *notifier;
+ struct tasklet_struct deferred_notify;
+};
+
+#define SHM_SIGNAL_FAULT(s, fmt, args...) \
+ ((s)->ops->fault ? (s)->ops->fault((s), fmt, ## args) : panic(fmt, ## args))
+
+ /*
+ * These functions should only be used internally
+ */
+void _shm_signal_release(struct kref *kref);
+void _shm_signal_wakeup(struct shm_signal *s);
+
+/**
+ * shm_signal_init() - initialize an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ *
+ * Initializes SHM_SIGNAL context before first use
+ *
+ **/
+void shm_signal_init(struct shm_signal *s, enum shm_signal_locality locale,
+ struct shm_signal_ops *ops, struct shm_signal_desc *desc);
+
+/**
+ * shm_signal_get() - acquire an SHM_SIGNAL context reference
+ * @s: SHM_SIGNAL context
+ *
+ **/
+static inline struct shm_signal *shm_signal_get(struct shm_signal *s)
+{
+ kref_get(&s->kref);
+
+ return s;
+}
+
+/**
+ * shm_signal_put() - release an SHM_SIGNAL context reference
+ * @s: SHM_SIGNAL context
+ *
+ **/
+static inline void shm_signal_put(struct shm_signal *s)
+{
+ kref_put(&s->kref, _shm_signal_release);
+}
+
+/**
+ * shm_signal_enable() - enables local notifications on an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Enables/unmasks the registered notifier (if applicable) to receive wakeups
+ * whenever the remote side performs an shm_signal() operation. A notification
+ * will be dispatched immediately if any pending signals have already been
+ * issued prior to invoking this call.
+ *
+ * This is synonymous with unmasking an interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_enable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_disable() - disable local notifications on an SHM_SIGNAL
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Disables/masks the registered shm_signal_notifier (if applicable) from
+ * receiving any further notifications. Any subsequent calls to shm_signal()
+ * by the remote side will update the shm as dirty, but will not traverse the
+ * locale boundary and will not invoke the notifier callback. Signals
+ * delivered while masked will be deferred until shm_signal_enable() is
+ * invoked.
+ *
+ * This is synonymous with masking an interrupt
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_disable(struct shm_signal *s, int flags);
+
+/**
+ * shm_signal_inject() - notify the remote side about shm changes
+ * @s: SHM_SIGNAL context
+ * @flags: Reserved for future use, must be 0
+ *
+ * Marks the shm state as "dirty" and, if enabled, will traverse
+ * a locale boundary to inject a remote notification. The remote
+ * side controls whether the notification should be delivered via
+ * the shm_signal_enable/disable() interface.
+ *
+ * The specifics of how to traverse a locale boundary are abstracted
+ * by the shm_signal_ops->signal() interface and provided by a particular
+ * implementation. However, typically going north to south would be
+ * something like a syscall/hypercall, and going south to north would be
+ * something like a posix-signal/guest-interrupt.
+ *
+ * Returns: success = 0, <0 = ERRNO
+ *
+ **/
+int shm_signal_inject(struct shm_signal *s, int flags);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_SHM_SIGNAL_H */
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 7cdfb4d52847..645e78d395fd 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -501,7 +501,7 @@ static inline struct sk_buff *alloc_skb_fclone(unsigned int size,
return __alloc_skb(size, priority, 1, -1);
}
-extern int skb_recycle_check(struct sk_buff *skb, int skb_size);
+extern bool skb_recycle_check(struct sk_buff *skb, int skb_size);
extern struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src);
extern struct sk_buff *skb_clone(struct sk_buff *skb,
@@ -2129,7 +2129,8 @@ static inline bool skb_warn_if_lro(const struct sk_buff *skb)
/* LRO sets gso_size but not gso_type, whereas if GSO is really
* wanted then gso_type will be set. */
struct skb_shared_info *shinfo = skb_shinfo(skb);
- if (shinfo->gso_size != 0 && unlikely(shinfo->gso_type == 0)) {
+ if (skb_is_nonlinear(skb) && shinfo->gso_size != 0 &&
+ unlikely(shinfo->gso_type == 0)) {
__skb_warn_lro_forwarding(skb);
return true;
}
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 52797714ade7..ebb0c80ffd6e 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -229,6 +229,7 @@ enum
LINUX_MIB_TCPBACKLOGDROP,
LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
LINUX_MIB_TCPDEFERACCEPTDROP,
+ LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
__LINUX_MIB_MAX
};
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 89fac6a3f78b..f8854655860e 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -60,7 +60,7 @@
/*
* Must define these before including other files, inline functions need them
*/
-#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME
+#define LOCK_SECTION_NAME ".text..lock."KBUILD_BASENAME
#define LOCK_SECTION_START(extra) \
".subsection 1\n\t" \
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index a2608bff9c78..623b704fdc42 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -167,7 +167,7 @@ struct ssb_device {
* is an optimization. */
const struct ssb_bus_ops *ops;
- struct device *dev;
+ struct device *dev, *dma_dev;
struct ssb_bus *bus;
struct ssb_device_id id;
@@ -470,14 +470,6 @@ extern u32 ssb_dma_translation(struct ssb_device *dev);
#define SSB_DMA_TRANSLATION_MASK 0xC0000000
#define SSB_DMA_TRANSLATION_SHIFT 30
-extern int ssb_dma_set_mask(struct ssb_device *dev, u64 mask);
-
-extern void * ssb_dma_alloc_consistent(struct ssb_device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp_flags);
-extern void ssb_dma_free_consistent(struct ssb_device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle,
- gfp_t gfp_flags);
-
static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
{
#ifdef CONFIG_SSB_DEBUG
@@ -486,155 +478,6 @@ static inline void __cold __ssb_dma_not_implemented(struct ssb_device *dev)
#endif /* DEBUG */
}
-static inline int ssb_dma_mapping_error(struct ssb_device *dev, dma_addr_t addr)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- return pci_dma_mapping_error(dev->bus->host_pci, addr);
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- return dma_mapping_error(dev->dev, addr);
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
- return -ENOSYS;
-}
-
-static inline dma_addr_t ssb_dma_map_single(struct ssb_device *dev, void *p,
- size_t size, enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- return pci_map_single(dev->bus->host_pci, p, size, dir);
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- return dma_map_single(dev->dev, p, size, dir);
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
- return 0;
-}
-
-static inline void ssb_dma_unmap_single(struct ssb_device *dev, dma_addr_t dma_addr,
- size_t size, enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_unmap_single(dev->bus->host_pci, dma_addr, size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_unmap_single(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_cpu(struct ssb_device *dev,
- dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
- size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_for_cpu(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_for_device(struct ssb_device *dev,
- dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
- size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_for_device(dev->dev, dma_addr, size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_cpu(struct ssb_device *dev,
- dma_addr_t dma_addr,
- unsigned long offset,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- /* Just sync everything. That's all the PCI API can do. */
- pci_dma_sync_single_for_cpu(dev->bus->host_pci, dma_addr,
- offset + size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_range_for_cpu(dev->dev, dma_addr, offset,
- size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-static inline void ssb_dma_sync_single_range_for_device(struct ssb_device *dev,
- dma_addr_t dma_addr,
- unsigned long offset,
- size_t size,
- enum dma_data_direction dir)
-{
- switch (dev->bus->bustype) {
- case SSB_BUSTYPE_PCI:
-#ifdef CONFIG_SSB_PCIHOST
- /* Just sync everything. That's all the PCI API can do. */
- pci_dma_sync_single_for_device(dev->bus->host_pci, dma_addr,
- offset + size, dir);
- return;
-#endif
- break;
- case SSB_BUSTYPE_SSB:
- dma_sync_single_range_for_device(dev->dev, dma_addr, offset,
- size, dir);
- return;
- default:
- break;
- }
- __ssb_dma_not_implemented(dev);
-}
-
-
#ifdef CONFIG_SSB_PCIHOST
/* PCI-host wrapper driver */
extern int ssb_pcihost_register(struct pci_driver *driver);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 5e781d824e6d..bc7d6bb4cd8e 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -256,22 +256,22 @@ static inline int hibernate(void) { return -ENOSYS; }
static inline bool system_entering_hibernation(void) { return false; }
#endif /* CONFIG_HIBERNATION */
-#ifdef CONFIG_HIBERNATION_NVS
-extern int hibernate_nvs_register(unsigned long start, unsigned long size);
-extern int hibernate_nvs_alloc(void);
-extern void hibernate_nvs_free(void);
-extern void hibernate_nvs_save(void);
-extern void hibernate_nvs_restore(void);
-#else /* CONFIG_HIBERNATION_NVS */
-static inline int hibernate_nvs_register(unsigned long a, unsigned long b)
+#ifdef CONFIG_SUSPEND_NVS
+extern int suspend_nvs_register(unsigned long start, unsigned long size);
+extern int suspend_nvs_alloc(void);
+extern void suspend_nvs_free(void);
+extern void suspend_nvs_save(void);
+extern void suspend_nvs_restore(void);
+#else /* CONFIG_SUSPEND_NVS */
+static inline int suspend_nvs_register(unsigned long a, unsigned long b)
{
return 0;
}
-static inline int hibernate_nvs_alloc(void) { return 0; }
-static inline void hibernate_nvs_free(void) {}
-static inline void hibernate_nvs_save(void) {}
-static inline void hibernate_nvs_restore(void) {}
-#endif /* CONFIG_HIBERNATION_NVS */
+static inline int suspend_nvs_alloc(void) { return 0; }
+static inline void suspend_nvs_free(void) {}
+static inline void suspend_nvs_save(void) {}
+static inline void suspend_nvs_restore(void) {}
+#endif /* CONFIG_SUSPEND_NVS */
#ifdef CONFIG_PM_SLEEP
void save_processor_state(void);
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
index 81a4e213c6cf..8c0e349f4a6c 100644
--- a/include/linux/swiotlb.h
+++ b/include/linux/swiotlb.h
@@ -23,6 +23,29 @@ extern int swiotlb_force;
#define IO_TLB_SHIFT 11
extern void swiotlb_init(int verbose);
+extern void swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose);
+
+/*
+ * Enumeration for sync targets
+ */
+enum dma_sync_target {
+ SYNC_FOR_CPU = 0,
+ SYNC_FOR_DEVICE = 1,
+};
+extern void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+ phys_addr_t phys, size_t size,
+ enum dma_data_direction dir);
+
+extern void swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr,
+ size_t size, enum dma_data_direction dir);
+
+extern void swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr,
+ size_t size, enum dma_data_direction dir,
+ enum dma_sync_target target);
+
+/* Accessory functions. */
+extern void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+ enum dma_data_direction dir);
extern void
*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -42,11 +65,11 @@ extern void swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
extern int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
- int direction);
+ enum dma_data_direction dir);
extern void
swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
- int direction);
+ enum dma_data_direction dir);
extern int
swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a1a86a53bc73..3c7620c26201 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -289,7 +289,7 @@ asmlinkage long sys_capget(cap_user_header_t header,
cap_user_data_t dataptr);
asmlinkage long sys_capset(cap_user_header_t header,
const cap_user_data_t data);
-asmlinkage long sys_personality(u_long personality);
+asmlinkage long sys_personality(unsigned int personality);
asmlinkage long sys_sigpending(old_sigset_t __user *set);
asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set,
@@ -811,6 +811,11 @@ asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *,
asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int,
struct timespec __user *, const sigset_t __user *,
size_t);
+asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags,
+ unsigned int priority);
+asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags,
+ u64 mask, int fd,
+ const char __user *pathname);
int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h
index 92f1d99f0f17..383b94ba8c20 100644
--- a/include/linux/usb/audio-v2.h
+++ b/include/linux/usb/audio-v2.h
@@ -18,6 +18,16 @@
/* v1.0 and v2.0 of this standard have many things in common. For the rest
* of the definitions, please refer to audio.h */
+static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
+{
+ return (bmControls >> (control * 2)) & 0x1;
+}
+
+static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
+{
+ return (bmControls >> (control * 2)) & 0x2;
+}
+
/* 4.7.2.1 Clock Source Descriptor */
struct uac_clock_source_descriptor {
@@ -31,6 +41,13 @@ struct uac_clock_source_descriptor {
__u8 iClockSource;
} __attribute__((packed));
+/* bmAttribute fields */
+#define UAC_CLOCK_SOURCE_TYPE_EXT 0x0
+#define UAC_CLOCK_SOURCE_TYPE_INT_FIXED 0x1
+#define UAC_CLOCK_SOURCE_TYPE_INT_VAR 0x2
+#define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3
+#define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2)
+
/* 4.7.2.2 Clock Source Descriptor */
struct uac_clock_selector_descriptor {
@@ -39,8 +56,20 @@ struct uac_clock_selector_descriptor {
__u8 bDescriptorSubtype;
__u8 bClockID;
__u8 bNrInPins;
- __u8 bmControls;
__u8 baCSourceID[];
+ /* bmControls, bAssocTerminal and iClockSource omitted */
+} __attribute__((packed));
+
+/* 4.7.2.3 Clock Multiplier Descriptor */
+
+struct uac_clock_multiplier_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __u8 bClockID;
+ __u8 bCSourceID;
+ __u8 bmControls;
+ __u8 iClockMultiplier;
} __attribute__((packed));
/* 4.7.2.4 Input terminal descriptor */
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
index 5d646c388752..c51200c715e5 100644
--- a/include/linux/usb/audio.h
+++ b/include/linux/usb/audio.h
@@ -47,6 +47,15 @@
#define UAC_FORMAT_TYPE 0x02
#define UAC_FORMAT_SPECIFIC 0x03
+/* A.7 Processing Unit Process Types */
+#define UAC_PROCESS_UNDEFINED 0x00
+#define UAC_PROCESS_UP_DOWNMIX 0x01
+#define UAC_PROCESS_DOLBY_PROLOGIC 0x02
+#define UAC_PROCESS_STEREO_EXTENDER 0x03
+#define UAC_PROCESS_REVERB 0x04
+#define UAC_PROCESS_CHORUS 0x05
+#define UAC_PROCESS_DYN_RANGE_COMP 0x06
+
/* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */
#define UAC_EP_GENERAL 0x01
@@ -73,6 +82,60 @@
#define UAC_GET_STAT 0xff
+/* A.10 Control Selector Codes */
+
+/* A.10.1 Terminal Control Selectors */
+#define UAC_TERM_COPY_PROTECT 0x01
+
+/* A.10.2 Feature Unit Control Selectors */
+#define UAC_FU_MUTE 0x01
+#define UAC_FU_VOLUME 0x02
+#define UAC_FU_BASS 0x03
+#define UAC_FU_MID 0x04
+#define UAC_FU_TREBLE 0x05
+#define UAC_FU_GRAPHIC_EQUALIZER 0x06
+#define UAC_FU_AUTOMATIC_GAIN 0x07
+#define UAC_FU_DELAY 0x08
+#define UAC_FU_BASS_BOOST 0x09
+#define UAC_FU_LOUDNESS 0x0a
+
+#define UAC_CONTROL_BIT(CS) (1 << ((CS) - 1))
+
+/* A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */
+#define UAC_UD_ENABLE 0x01
+#define UAC_UD_MODE_SELECT 0x02
+
+/* A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */
+#define UAC_DP_ENABLE 0x01
+#define UAC_DP_MODE_SELECT 0x02
+
+/* A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */
+#define UAC_3D_ENABLE 0x01
+#define UAC_3D_SPACE 0x02
+
+/* A.10.3.4 Reverberation Processing Unit Control Selectors */
+#define UAC_REVERB_ENABLE 0x01
+#define UAC_REVERB_LEVEL 0x02
+#define UAC_REVERB_TIME 0x03
+#define UAC_REVERB_FEEDBACK 0x04
+
+/* A.10.3.5 Chorus Processing Unit Control Selectors */
+#define UAC_CHORUS_ENABLE 0x01
+#define UAC_CHORUS_LEVEL 0x02
+#define UAC_CHORUS_RATE 0x03
+#define UAC_CHORUS_DEPTH 0x04
+
+/* A.10.3.6 Dynamic Range Compressor Unit Control Selectors */
+#define UAC_DCR_ENABLE 0x01
+#define UAC_DCR_RATE 0x02
+#define UAC_DCR_MAXAMPL 0x03
+#define UAC_DCR_THRESHOLD 0x04
+#define UAC_DCR_ATTACK_TIME 0x05
+#define UAC_DCR_RELEASE_TIME 0x06
+
+/* A.10.4 Extension Unit Control Selectors */
+#define UAC_XU_ENABLE 0x01
+
/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
#define UAC_MS_HEADER 0x01
#define UAC_MIDI_IN_JACK 0x02
@@ -244,7 +307,7 @@ struct uac_selector_unit_descriptor {
static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
{
__u8 *raw = (__u8 *) desc;
- return raw[9 + desc->bLength - 1];
+ return raw[desc->bLength - 1];
}
/* 4.3.2.5 Feature Unit Descriptor */
@@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor {
#define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02
#define UAC_EP_CS_ATTR_FILL_MAX 0x80
-/* A.10.2 Feature Unit Control Selectors */
-
-#define UAC_FU_CONTROL_UNDEFINED 0x00
-#define UAC_MUTE_CONTROL 0x01
-#define UAC_VOLUME_CONTROL 0x02
-#define UAC_BASS_CONTROL 0x03
-#define UAC_MID_CONTROL 0x04
-#define UAC_TREBLE_CONTROL 0x05
-#define UAC_GRAPHIC_EQUALIZER_CONTROL 0x06
-#define UAC_AUTOMATIC_GAIN_CONTROL 0x07
-#define UAC_DELAY_CONTROL 0x08
-#define UAC_BASS_BOOST_CONTROL 0x09
-#define UAC_LOUDNESS_CONTROL 0x0a
-
-#define UAC_FU_MUTE (1 << (UAC_MUTE_CONTROL - 1))
-#define UAC_FU_VOLUME (1 << (UAC_VOLUME_CONTROL - 1))
-#define UAC_FU_BASS (1 << (UAC_BASS_CONTROL - 1))
-#define UAC_FU_MID (1 << (UAC_MID_CONTROL - 1))
-#define UAC_FU_TREBLE (1 << (UAC_TREBLE_CONTROL - 1))
-#define UAC_FU_GRAPHIC_EQ (1 << (UAC_GRAPHIC_EQUALIZER_CONTROL - 1))
-#define UAC_FU_AUTO_GAIN (1 << (UAC_AUTOMATIC_GAIN_CONTROL - 1))
-#define UAC_FU_DELAY (1 << (UAC_DELAY_CONTROL - 1))
-#define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1))
-#define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1))
-
/* status word format (3.7.1.1) */
#define UAC1_STATUS_TYPE_ORIG_MASK 0x0f
diff --git a/include/linux/vbus_driver.h b/include/linux/vbus_driver.h
new file mode 100644
index 000000000000..8a7acb1a7a05
--- /dev/null
+++ b/include/linux/vbus_driver.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Mediates access to a host VBUS from a guest kernel by providing a
+ * global view of all VBUS devices
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_DRIVER_H
+#define _LINUX_VBUS_DRIVER_H
+
+#include <linux/device.h>
+#include <linux/shm_signal.h>
+#include <linux/ioq.h>
+
+struct vbus_device_proxy;
+struct vbus_driver;
+
+struct vbus_device_proxy_ops {
+ int (*open)(struct vbus_device_proxy *dev, int version, int flags);
+ int (*close)(struct vbus_device_proxy *dev, int flags);
+ int (*shm)(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio,
+ void *ptr, size_t len,
+ struct shm_signal_desc *sigdesc, struct shm_signal **signal,
+ int flags);
+ int (*call)(struct vbus_device_proxy *dev, u32 func,
+ void *data, size_t len, int flags);
+ void (*release)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_device_proxy {
+ char *type;
+ u64 id;
+ void *priv; /* Used by drivers */
+ struct vbus_device_proxy_ops *ops;
+ struct device dev;
+};
+
+int vbus_device_proxy_register(struct vbus_device_proxy *dev);
+void vbus_device_proxy_unregister(struct vbus_device_proxy *dev);
+
+struct vbus_device_proxy *vbus_device_proxy_find(u64 id);
+
+struct vbus_driver_ops {
+ int (*probe)(struct vbus_device_proxy *dev);
+ int (*remove)(struct vbus_device_proxy *dev);
+};
+
+struct vbus_driver {
+ char *type;
+ struct module *owner;
+ struct vbus_driver_ops *ops;
+ struct device_driver drv;
+};
+
+int vbus_driver_register(struct vbus_driver *drv);
+void vbus_driver_unregister(struct vbus_driver *drv);
+
+/*
+ * driver-side IOQ helper - allocates device-shm and maps an IOQ on it
+ */
+int vbus_driver_ioq_alloc(struct vbus_device_proxy *dev, const char *name,
+ int id, int prio, size_t ringsize, struct ioq **ioq);
+
+#define VBUS_DRIVER_AUTOPROBE(name) MODULE_ALIAS("vbus-proxy:" name)
+
+#endif /* _LINUX_VBUS_DRIVER_H */
diff --git a/include/linux/vbus_pci.h b/include/linux/vbus_pci.h
new file mode 100644
index 000000000000..fe337590e644
--- /dev/null
+++ b/include/linux/vbus_pci.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * PCI to Virtual-Bus Bridge
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VBUS_PCI_H
+#define _LINUX_VBUS_PCI_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define VBUS_PCI_ABI_MAGIC 0xbf53eef5
+#define VBUS_PCI_ABI_VERSION 2
+#define VBUS_PCI_HC_VERSION 1
+
+enum {
+ VBUS_PCI_BRIDGE_NEGOTIATE,
+ VBUS_PCI_BRIDGE_QREG,
+ VBUS_PCI_BRIDGE_SLOWCALL,
+ VBUS_PCI_BRIDGE_FASTCALL_ADD,
+ VBUS_PCI_BRIDGE_FASTCALL_DROP,
+
+ VBUS_PCI_BRIDGE_MAX, /* must be last */
+};
+
+enum {
+ VBUS_PCI_HC_DEVOPEN,
+ VBUS_PCI_HC_DEVCLOSE,
+ VBUS_PCI_HC_DEVCALL,
+ VBUS_PCI_HC_DEVSHM,
+
+ VBUS_PCI_HC_MAX, /* must be last */
+};
+
+struct vbus_pci_bridge_negotiate {
+ __u32 magic;
+ __u32 version;
+ __u64 capabilities;
+};
+
+struct vbus_pci_deviceopen {
+ __u32 devid;
+ __u32 version; /* device ABI version */
+ __u64 handle; /* return value for devh */
+};
+
+struct vbus_pci_devicecall {
+ __u64 devh; /* device-handle (returned from DEVICEOPEN */
+ __u32 func;
+ __u32 len;
+ __u32 flags;
+ __u64 datap;
+};
+
+struct vbus_pci_deviceshm {
+ __u64 devh; /* device-handle (returned from DEVICEOPEN */
+ __u32 id;
+ __u32 len;
+ __u32 flags;
+ struct {
+ __u32 offset;
+ __u32 prio;
+ __u64 cookie; /* token to pass back when signaling client */
+ } signal;
+ __u64 datap;
+};
+
+struct vbus_pci_call_desc {
+ __u32 vector;
+ __u32 len;
+ __u64 datap;
+};
+
+struct vbus_pci_fastcall_desc {
+ struct vbus_pci_call_desc call;
+ __u32 result;
+};
+
+struct vbus_pci_regs {
+ struct vbus_pci_call_desc bridgecall;
+ __u8 pad[48];
+};
+
+struct vbus_pci_signals {
+ __u32 eventq;
+ __u32 fastcall;
+ __u32 shmsignal;
+ __u8 pad[20];
+};
+
+struct vbus_pci_eventqreg {
+ __u32 count;
+ __u64 ring;
+ __u64 data;
+};
+
+struct vbus_pci_busreg {
+ __u32 count; /* supporting multiple queues allows for prio, etc */
+ struct vbus_pci_eventqreg eventq[1];
+};
+
+enum vbus_pci_eventid {
+ VBUS_PCI_EVENT_DEVADD,
+ VBUS_PCI_EVENT_DEVDROP,
+ VBUS_PCI_EVENT_SHMSIGNAL,
+ VBUS_PCI_EVENT_SHMCLOSE,
+};
+
+#define VBUS_MAX_DEVTYPE_LEN 128
+
+struct vbus_pci_add_event {
+ __u64 id;
+ char type[VBUS_MAX_DEVTYPE_LEN];
+};
+
+struct vbus_pci_handle_event {
+ __u64 handle;
+};
+
+struct vbus_pci_event {
+ __u32 eventid;
+ union {
+ struct vbus_pci_add_event add;
+ struct vbus_pci_handle_event handle;
+ } data;
+};
+
+#endif /* _LINUX_VBUS_PCI_H */
diff --git a/include/linux/venet.h b/include/linux/venet.h
new file mode 100644
index 000000000000..0578d797c973
--- /dev/null
+++ b/include/linux/venet.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * Virtual-Ethernet adapter
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _LINUX_VENET_H
+#define _LINUX_VENET_H
+
+#include <linux/types.h>
+
+#define VENET_VERSION 1
+
+#define VENET_TYPE "virtual-ethernet"
+
+#define VENET_QUEUE_RX 0
+#define VENET_QUEUE_TX 1
+
+struct venet_capabilities {
+ __u32 gid;
+ __u32 bits;
+};
+
+#define VENET_CAP_GROUP_SG 0
+#define VENET_CAP_GROUP_EVENTQ 1
+#define VENET_CAP_GROUP_L4RO 2 /* layer-4 reassem offloading */
+
+/* CAPABILITIES-GROUP SG */
+#define VENET_CAP_SG (1 << 0)
+#define VENET_CAP_TSO4 (1 << 1)
+#define VENET_CAP_TSO6 (1 << 2)
+#define VENET_CAP_ECN (1 << 3)
+#define VENET_CAP_UFO (1 << 4)
+#define VENET_CAP_PMTD (1 << 5) /* pre-mapped tx desc */
+
+/* CAPABILITIES-GROUP EVENTQ */
+#define VENET_CAP_EVQ_LINKSTATE (1 << 0)
+#define VENET_CAP_EVQ_TXC (1 << 1) /* tx-complete */
+
+struct venet_iov {
+ __u32 len;
+ __u64 ptr;
+};
+
+#define VENET_SG_FLAG_NEEDS_CSUM (1 << 0)
+#define VENET_SG_FLAG_GSO (1 << 1)
+#define VENET_SG_FLAG_ECN (1 << 2)
+
+struct venet_sg {
+ __u64 cookie;
+ __u32 flags;
+ __u32 len; /* total length of all iovs */
+ struct {
+ __u16 start; /* csum starting position */
+ __u16 offset; /* offset to place csum */
+ } csum;
+ struct {
+#define VENET_GSO_TYPE_TCPV4 0 /* IPv4 TCP (TSO) */
+#define VENET_GSO_TYPE_UDP 1 /* IPv4 UDP (UFO) */
+#define VENET_GSO_TYPE_TCPV6 2 /* IPv6 TCP */
+ __u8 type;
+ __u16 hdrlen;
+ __u16 size;
+ } gso;
+ __u32 count; /* nr of iovs */
+ struct venet_iov iov[1];
+};
+
+struct venet_eventq_query {
+ __u32 flags;
+ __u32 evsize; /* size of each event */
+ __u32 dpid; /* descriptor pool-id */
+ __u32 qid;
+ __u8 pad[16];
+};
+
+#define VENET_EVENT_LINKSTATE 0
+#define VENET_EVENT_TXC 1
+
+struct venet_event_header {
+ __u32 flags;
+ __u32 size;
+ __u32 id;
+};
+
+struct venet_event_linkstate {
+ struct venet_event_header header;
+ __u8 state; /* 0 = down, 1 = up */
+};
+
+struct venet_event_txc {
+ struct venet_event_header header;
+ __u32 txqid;
+ __u64 cookie;
+};
+
+struct venet_l4ro_query {
+ __u32 flags;
+ __u32 dpid; /* descriptor pool-id */
+ __u32 pqid; /* page queue-id */
+ __u8 pad[20];
+};
+
+
+#define VSG_DESC_SIZE(count) (sizeof(struct venet_sg) + \
+ sizeof(struct venet_iov) * ((count) - 1))
+
+#define VENET_FUNC_LINKUP 0
+#define VENET_FUNC_LINKDOWN 1
+#define VENET_FUNC_MACQUERY 2
+#define VENET_FUNC_NEGCAP 3 /* negotiate capabilities */
+#define VENET_FUNC_FLUSHRX 4
+#define VENET_FUNC_PMTDQUERY 5
+#define VENET_FUNC_EVQQUERY 6
+#define VENET_FUNC_L4ROQUERY 7
+
+#endif /* _LINUX_VENET_H */
diff --git a/include/linux/vgaarb.h b/include/linux/vgaarb.h
index 2dfaa293ae8c..c9a975976995 100644
--- a/include/linux/vgaarb.h
+++ b/include/linux/vgaarb.h
@@ -5,6 +5,27 @@
* (C) Copyright 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
* (C) Copyright 2007 Paulo R. Zanoni <przanoni@gmail.com>
* (C) Copyright 2007, 2009 Tiago Vignatti <vignatti@freedesktop.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS
+ * IN THE SOFTWARE.
+ *
*/
#ifndef LINUX_VGA_H
diff --git a/include/linux/via-core.h b/include/linux/via-core.h
index 7ffb521e1a7a..38bffd8ccca5 100644
--- a/include/linux/via-core.h
+++ b/include/linux/via-core.h
@@ -81,7 +81,7 @@ struct viafb_dev {
unsigned long fbmem_start;
long fbmem_len;
void __iomem *fbmem;
-#if defined(CONFIG_FB_VIA_CAMERA) || defined(CONFIG_FB_VIA_CAMERA_MODULE)
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
long camera_fbmem_offset;
long camera_fbmem_size;
#endif
@@ -138,6 +138,7 @@ void viafb_irq_disable(u32 mask);
#define VDE_I_LVDSSIEN 0x40000000 /* LVDS Sense enable */
#define VDE_I_ENABLE 0x80000000 /* Global interrupt enable */
+#if defined(CONFIG_VIDEO_VIA_CAMERA) || defined(CONFIG_VIDEO_VIA_CAMERA_MODULE)
/*
* DMA management.
*/
@@ -172,6 +173,7 @@ int viafb_dma_copy_out_sg(unsigned int offset, struct scatterlist *sg, int nsg);
*/
#define VGA_WIDTH 640
#define VGA_HEIGHT 480
+#endif /* CONFIG_VIDEO_VIA_CAMERA */
/*
* Indexed port operations. Note that these are all multi-op
diff --git a/include/linux/virtio_9p.h b/include/linux/virtio_9p.h
index 5cf11765146b..395c38a47adb 100644
--- a/include/linux/virtio_9p.h
+++ b/include/linux/virtio_9p.h
@@ -4,6 +4,7 @@
* compatible drivers/servers. */
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/types.h>
/* The feature bitmap for virtio 9P */
diff --git a/include/linux/wlp.h b/include/linux/wlp.h
index ac95ce6606ac..b709ceff53f2 100644
--- a/include/linux/wlp.h
+++ b/include/linux/wlp.h
@@ -300,7 +300,7 @@ struct wlp_ie {
__le16 cycle_param;
__le16 acw_anchor_addr;
u8 wssid_hash_list[];
-} __attribute__((packed));
+} __packed;
static inline int wlp_ie_hash_length(struct wlp_ie *ie)
{
@@ -324,7 +324,7 @@ static inline void wlp_ie_set_hash_length(struct wlp_ie *ie, int hash_length)
*/
struct wlp_nonce {
u8 data[16];
-} __attribute__((packed));
+} __packed;
/**
* WLP UUID
@@ -336,7 +336,7 @@ struct wlp_nonce {
*/
struct wlp_uuid {
u8 data[16];
-} __attribute__((packed));
+} __packed;
/**
@@ -348,7 +348,7 @@ struct wlp_dev_type {
u8 OUI[3];
u8 OUIsubdiv;
__le16 subID;
-} __attribute__((packed));
+} __packed;
/**
* WLP frame header
@@ -357,7 +357,7 @@ struct wlp_dev_type {
struct wlp_frame_hdr {
__le16 mux_hdr; /* WLP_PROTOCOL_ID */
enum wlp_frame_type type:8;
-} __attribute__((packed));
+} __packed;
/**
* WLP attribute field header
@@ -368,7 +368,7 @@ struct wlp_frame_hdr {
struct wlp_attr_hdr {
__le16 type;
__le16 length;
-} __attribute__((packed));
+} __packed;
/**
* Device information commonly used together
@@ -401,13 +401,13 @@ struct wlp_device_info {
struct wlp_attr_##name { \
struct wlp_attr_hdr hdr; \
type name; \
-} __attribute__((packed));
+} __packed;
#define wlp_attr_array(type, name) \
struct wlp_attr_##name { \
struct wlp_attr_hdr hdr; \
type name[]; \
-} __attribute__((packed));
+} __packed;
/**
* WLP association attribute fields
@@ -483,7 +483,7 @@ struct wlp_wss_info {
struct wlp_attr_accept_enrl accept;
struct wlp_attr_wss_sec_status sec_stat;
struct wlp_attr_wss_bcast bcast;
-} __attribute__((packed));
+} __packed;
/* WLP WSS Information */
wlp_attr_array(struct wlp_wss_info, wss_info)
@@ -520,7 +520,7 @@ wlp_attr(u8, wlp_assc_err)
struct wlp_frame_std_abbrv_hdr {
struct wlp_frame_hdr hdr;
u8 tag;
-} __attribute__((packed));
+} __packed;
/**
* WLP association frames
@@ -533,7 +533,7 @@ struct wlp_frame_assoc {
struct wlp_attr_version version;
struct wlp_attr_msg_type msg_type;
u8 attr[];
-} __attribute__((packed));
+} __packed;
/* Ethernet to dev address mapping */
struct wlp_eda {
@@ -655,7 +655,7 @@ struct wlp {
struct mutex nbmutex; /* Neighbor mutex protects neighbors list */
struct list_head neighbors; /* Elements are wlp_neighbor_e */
struct uwb_notifs_handler uwb_notifs_handler;
- struct wlp_device_info *dev_info;
+ struct wlp_device_info *wdi;
void (*fill_device_info)(struct wlp *wlp, struct wlp_device_info *info);
int (*xmit_frame)(struct wlp *, struct sk_buff *,
struct uwb_dev_addr *);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index cc97d6caf2b3..f64134653a8c 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -65,15 +65,6 @@ struct writeback_control {
* so we use a single control to update them
*/
unsigned no_nrwrite_index_update:1;
-
- /*
- * For WB_SYNC_ALL, the sb must always be pinned. For WB_SYNC_NONE,
- * the writeback code will pin the sb for the caller. However,
- * for eg umount, the caller does WB_SYNC_NONE but already has
- * the sb pinned. If the below is set, caller already has the
- * sb pinned.
- */
- unsigned sb_pinned:1;
};
/*
@@ -82,7 +73,6 @@ struct writeback_control {
struct bdi_writeback;
int inode_wait(void *);
void writeback_inodes_sb(struct super_block *);
-void writeback_inodes_sb_locked(struct super_block *);
int writeback_inodes_sb_if_idle(struct super_block *);
void sync_inodes_sb(struct super_block *);
void writeback_inodes_wbc(struct writeback_control *wbc);
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 5833966a7100..c78e99a435b6 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -55,7 +55,8 @@ void rc_map_init(void);
#define RC_MAP_AVERMEDIA_A16D "rc-avermedia-a16d"
#define RC_MAP_AVERMEDIA_CARDBUS "rc-avermedia-cardbus"
#define RC_MAP_AVERMEDIA_DVBT "rc-avermedia-dvbt"
-#define RC_MAP_AVERMEDIA_M135A_RM_JX "rc-avermedia-m135a-rm-jx"
+#define RC_MAP_AVERMEDIA_M135A "rc-avermedia-m135a"
+#define RC_MAP_AVERMEDIA_M733A_RM_K6 "rc-avermedia-m733a-rm-k6"
#define RC_MAP_AVERMEDIA "rc-avermedia"
#define RC_MAP_AVERTV_303 "rc-avertv-303"
#define RC_MAP_BEHOLD_COLUMBUS "rc-behold-columbus"
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index c9a5bbfa6ab5..b8289c2f609b 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -66,7 +66,7 @@ struct soc_camera_host_ops {
* .get_formats() fail, .put_formats() will not be called at all, the
* failing .get_formats() must then clean up internally.
*/
- int (*get_formats)(struct soc_camera_device *, int,
+ int (*get_formats)(struct soc_camera_device *, unsigned int,
struct soc_camera_format_xlate *);
void (*put_formats)(struct soc_camera_device *);
int (*cropcap)(struct soc_camera_device *, struct v4l2_cropcap *);
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 21b4428c12ab..6400c7c9d1ed 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -111,6 +111,10 @@ enum {
V4L2_IDENT_VPX3216B = 3216,
V4L2_IDENT_VPX3220A = 3220,
+ /* VX855 just ident 3409 */
+ /* Other via devs could use 3314, 3324, 3327, 3336, 3364, 3353 */
+ V4L2_IDENT_VIA_VX855 = 3409,
+
/* module tvp5150 */
V4L2_IDENT_TVP5150 = 5150,
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 0dbe02ada259..865cda7cd611 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -40,6 +40,7 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ V4L2_MBUS_FMT_SGRBG8_1X8,
};
/**
@@ -58,4 +59,24 @@ struct v4l2_mbus_framefmt {
enum v4l2_colorspace colorspace;
};
+static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
+ const struct v4l2_mbus_framefmt *mbus_fmt)
+{
+ pix_fmt->width = mbus_fmt->width;
+ pix_fmt->height = mbus_fmt->height;
+ pix_fmt->field = mbus_fmt->field;
+ pix_fmt->colorspace = mbus_fmt->colorspace;
+}
+
+static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt,
+ const struct v4l2_pix_format *pix_fmt,
+ enum v4l2_mbus_pixelcode code)
+{
+ mbus_fmt->width = pix_fmt->width;
+ mbus_fmt->height = pix_fmt->height;
+ mbus_fmt->field = pix_fmt->field;
+ mbus_fmt->colorspace = pix_fmt->colorspace;
+ mbus_fmt->code = code;
+}
+
#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index a88889355ae0..02c6f4d11ed3 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -246,7 +246,7 @@ struct v4l2_subdev_video_ops {
struct v4l2_dv_timings *timings);
int (*g_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
- int (*enum_mbus_fmt)(struct v4l2_subdev *sd, int index,
+ int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code);
int (*g_mbus_fmt)(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *fmt);
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 156c26bb8bd7..6df324ef278c 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -133,6 +133,10 @@ enum p9_msg_t {
P9_RSTATFS,
P9_TRENAME = 20,
P9_RRENAME,
+ P9_TREADDIR = 40,
+ P9_RREADDIR,
+ P9_TLINK = 70,
+ P9_RLINK,
P9_TVERSION = 100,
P9_RVERSION,
P9_TAUTH = 102,
@@ -275,6 +279,9 @@ enum p9_qid_t {
/* ample room for Twrite/Rread header */
#define P9_IOHDRSZ 24
+/* Room for readdir header */
+#define P9_READDIRHDRSZ 24
+
/**
* struct p9_str - length prefixed string type
* @len: length of the string
@@ -485,6 +492,18 @@ struct p9_rwrite {
u32 count;
};
+struct p9_treaddir {
+ u32 fid;
+ u64 offset;
+ u32 count;
+};
+
+struct p9_rreaddir {
+ u32 count;
+ u8 *data;
+};
+
+
struct p9_tclunk {
u32 fid;
};
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 7dd3ed85c782..180a07ed07d7 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -195,6 +195,21 @@ struct p9_fid {
struct list_head dlist; /* list of all fids attached to a dentry */
};
+/**
+ * struct p9_dirent - directory entry structure
+ * @qid: The p9 server qid for this dirent
+ * @d_off: offset to the next dirent
+ * @d_type: type of file
+ * @d_name: file name
+ */
+
+struct p9_dirent {
+ struct p9_qid qid;
+ u64 d_off;
+ unsigned char d_type;
+ char d_name[256];
+};
+
int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
int p9_client_version(struct p9_client *);
@@ -211,12 +226,16 @@ struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames,
int p9_client_open(struct p9_fid *fid, int mode);
int p9_client_fcreate(struct p9_fid *fid, char *name, u32 perm, int mode,
char *extension);
+int p9_client_link(struct p9_fid *fid, char *name, char *linkname);
int p9_client_clunk(struct p9_fid *fid);
int p9_client_remove(struct p9_fid *fid);
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
u64 offset, u32 count);
int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
u64 offset, u32 count);
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+ int proto_version);
struct p9_wstat *p9_client_stat(struct p9_fid *fid);
int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index b44a2e5321a3..bd057b6007da 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -89,7 +89,7 @@ enum ieee80211_channel_flags {
* @max_power: maximum transmission power (in dBm)
* @beacon_found: helper to regulatory code to indicate when a beacon
* has been found on this channel. Use regulatory_hint_found_beacon()
- * to enable this, this is is useful only on 5 GHz band.
+ * to enable this, this is useful only on 5 GHz band.
* @orig_mag: internal use
* @orig_mpwr: internal use
*/
@@ -1168,6 +1168,7 @@ struct cfg80211_ops {
int (*action)(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie);
int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
@@ -1330,26 +1331,15 @@ struct wiphy {
char priv[0] __attribute__((__aligned__(NETDEV_ALIGN)));
};
-#ifdef CONFIG_NET_NS
-static inline struct net *wiphy_net(struct wiphy *wiphy)
-{
- return wiphy->_net;
-}
-
-static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
-{
- wiphy->_net = net;
-}
-#else
static inline struct net *wiphy_net(struct wiphy *wiphy)
{
- return &init_net;
+ return read_pnet(&wiphy->_net);
}
static inline void wiphy_net_set(struct wiphy *wiphy, struct net *net)
{
+ write_pnet(&wiphy->_net, net);
}
-#endif
/**
* wiphy_priv - return priv from wiphy
diff --git a/include/net/dn_dev.h b/include/net/dn_dev.h
index 511a459ec10f..0916bbf3bdff 100644
--- a/include/net/dn_dev.h
+++ b/include/net/dn_dev.h
@@ -101,7 +101,7 @@ struct dn_short_packet {
__le16 dstnode;
__le16 srcnode;
__u8 forward;
-} __attribute__((packed));
+} __packed;
struct dn_long_packet {
__u8 msgflg;
@@ -115,7 +115,7 @@ struct dn_long_packet {
__u8 visit_ct;
__u8 s_class;
__u8 pt;
-} __attribute__((packed));
+} __packed;
/*------------------------- DRP - Routing messages ---------------------*/
@@ -132,7 +132,7 @@ struct endnode_hello_message {
__u8 mpd;
__u8 datalen;
__u8 data[2];
-} __attribute__((packed));
+} __packed;
struct rtnode_hello_message {
__u8 msgflg;
@@ -144,7 +144,7 @@ struct rtnode_hello_message {
__u8 area;
__le16 timer;
__u8 mpd;
-} __attribute__((packed));
+} __packed;
extern void dn_dev_init(void);
diff --git a/include/net/dn_nsp.h b/include/net/dn_nsp.h
index 17d43d2db5ec..e43a2893f132 100644
--- a/include/net/dn_nsp.h
+++ b/include/net/dn_nsp.h
@@ -74,18 +74,18 @@ struct nsp_data_seg_msg {
__u8 msgflg;
__le16 dstaddr;
__le16 srcaddr;
-} __attribute__((packed));
+} __packed;
struct nsp_data_opt_msg {
__le16 acknum;
__le16 segnum;
__le16 lsflgs;
-} __attribute__((packed));
+} __packed;
struct nsp_data_opt_msg1 {
__le16 acknum;
__le16 segnum;
-} __attribute__((packed));
+} __packed;
/* Acknowledgment Message (data/other data) */
@@ -94,13 +94,13 @@ struct nsp_data_ack_msg {
__le16 dstaddr;
__le16 srcaddr;
__le16 acknum;
-} __attribute__((packed));
+} __packed;
/* Connect Acknowledgment Message */
struct nsp_conn_ack_msg {
__u8 msgflg;
__le16 dstaddr;
-} __attribute__((packed));
+} __packed;
/* Connect Initiate/Retransmit Initiate/Connect Confirm */
@@ -117,7 +117,7 @@ struct nsp_conn_init_msg {
#define NSP_FC_MASK 0x0c /* FC type mask */
__u8 info;
__le16 segsize;
-} __attribute__((packed));
+} __packed;
/* Disconnect Initiate/Disconnect Confirm */
struct nsp_disconn_init_msg {
@@ -125,7 +125,7 @@ struct nsp_disconn_init_msg {
__le16 dstaddr;
__le16 srcaddr;
__le16 reason;
-} __attribute__((packed));
+} __packed;
@@ -135,7 +135,7 @@ struct srcobj_fmt {
__le16 grpcode;
__le16 usrcode;
__u8 dlen;
-} __attribute__((packed));
+} __packed;
/*
* A collection of functions for manipulating the sequence
diff --git a/include/net/dst.h b/include/net/dst.h
index 612069beda73..81d1413a8701 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -250,11 +250,11 @@ static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev)
* Linux networking. Thus, destinations are stackable.
*/
-static inline struct dst_entry *dst_pop(struct dst_entry *dst)
+static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb)
{
- struct dst_entry *child = dst_clone(dst->child);
+ struct dst_entry *child = skb_dst(skb)->child;
- dst_release(dst);
+ skb_dst_drop(skb);
return child;
}
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index eb551baafc04..f7dcd2c70412 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -68,26 +68,15 @@ struct genl_info {
#endif
};
-#ifdef CONFIG_NET_NS
static inline struct net *genl_info_net(struct genl_info *info)
{
- return info->_net;
+ return read_pnet(&info->_net);
}
static inline void genl_info_net_set(struct genl_info *info, struct net *net)
{
- info->_net = net;
+ write_pnet(&info->_net, net);
}
-#else
-static inline struct net *genl_info_net(struct genl_info *info)
-{
- return &init_net;
-}
-
-static inline void genl_info_net_set(struct genl_info *info, struct net *net)
-{
-}
-#endif
/**
* struct genl_ops - generic netlink operations
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index fbf9d1cda27b..fc94ec568a50 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -27,6 +27,6 @@ struct ipv6_tlv_tnl_enc_lim {
__u8 type; /* type-code for option */
__u8 length; /* option length */
__u8 encap_limit; /* tunnel encapsulation limit */
-} __attribute__ ((packed));
+} __packed;
#endif
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 2600b69757b8..f5808d596aab 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -551,6 +551,10 @@ extern int ipv6_ext_hdr(u8 nexthdr);
extern int ipv6_find_tlv(struct sk_buff *skb, int offset, int type);
+extern struct in6_addr *fl6_update_dst(struct flowi *fl,
+ const struct ipv6_txoptions *opt,
+ struct in6_addr *orig);
+
/*
* socket options (ipv6_sockglue.c)
*/
diff --git a/include/net/ipx.h b/include/net/ipx.h
index ef51a668ba19..05d7e4a88b49 100644
--- a/include/net/ipx.h
+++ b/include/net/ipx.h
@@ -27,9 +27,9 @@ struct ipx_address {
#define IPX_MAX_PPROP_HOPS 8
struct ipxhdr {
- __be16 ipx_checksum __attribute__ ((packed));
+ __be16 ipx_checksum __packed;
#define IPX_NO_CHECKSUM cpu_to_be16(0xFFFF)
- __be16 ipx_pktsize __attribute__ ((packed));
+ __be16 ipx_pktsize __packed;
__u8 ipx_tctrl;
__u8 ipx_type;
#define IPX_TYPE_UNKNOWN 0x00
@@ -38,8 +38,8 @@ struct ipxhdr {
#define IPX_TYPE_SPX 0x05 /* SPX protocol */
#define IPX_TYPE_NCP 0x11 /* $lots for docs on this (SPIT) */
#define IPX_TYPE_PPROP 0x14 /* complicated flood fill brdcast */
- struct ipx_address ipx_dest __attribute__ ((packed));
- struct ipx_address ipx_source __attribute__ ((packed));
+ struct ipx_address ipx_dest __packed;
+ struct ipx_address ipx_source __packed;
};
static __inline__ struct ipxhdr *ipx_hdr(struct sk_buff *skb)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index de22cbfef232..e3c1d4794003 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -19,6 +19,7 @@
#include <linux/wireless.h>
#include <linux/device.h>
#include <linux/ieee80211.h>
+#include <linux/inetdevice.h>
#include <net/cfg80211.h>
/**
@@ -412,8 +413,6 @@ struct ieee80211_tx_rate {
* @driver_data: array of driver_data pointers
* @ampdu_ack_len: number of acked aggregated frames.
* relevant only if IEEE80211_TX_STAT_AMPDU was set.
- * @ampdu_ack_map: block ack bit map for the aggregation.
- * relevant only if IEEE80211_TX_STAT_AMPDU was set.
* @ampdu_len: number of aggregated frames.
* relevant only if IEEE80211_TX_STAT_AMPDU was set.
* @ack_signal: signal strength of the ACK frame
@@ -448,10 +447,9 @@ struct ieee80211_tx_info {
struct {
struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES];
u8 ampdu_ack_len;
- u64 ampdu_ack_map;
int ack_signal;
u8 ampdu_len;
- /* 7 bytes free */
+ /* 15 bytes free */
} status;
struct {
struct ieee80211_tx_rate driver_rates[
@@ -881,16 +879,12 @@ struct ieee80211_sta {
* enum sta_notify_cmd - sta notify command
*
* Used with the sta_notify() callback in &struct ieee80211_ops, this
- * indicates addition and removal of a station to station table,
- * or if a associated station made a power state transition.
+ * indicates if an associated station made a power state transition.
*
- * @STA_NOTIFY_ADD: (DEPRECATED) a station was added to the station table
- * @STA_NOTIFY_REMOVE: (DEPRECATED) a station being removed from the station table
* @STA_NOTIFY_SLEEP: a station is now sleeping
* @STA_NOTIFY_AWAKE: a sleeping station woke up
*/
enum sta_notify_cmd {
- STA_NOTIFY_ADD, STA_NOTIFY_REMOVE,
STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE,
};
@@ -1535,6 +1529,16 @@ enum ieee80211_ampdu_mlme_action {
* of the bss parameters has changed when a call is made. The callback
* can sleep.
*
+ * @configure_arp_filter: Configuration function for hardware ARP query filter.
+ * This function is called with all the IP addresses configured to the
+ * interface as argument - all ARP queries targeted to any of these
+ * addresses must pass through. If the hardware filter does not support
+ * enought addresses, hardware filtering must be disabled. The ifa_list
+ * argument may be NULL, indicating that filtering must be disabled.
+ * This function is called upon association complete with current
+ * address(es), and while associated whenever the IP address(es) change.
+ * The callback can sleep.
+ *
* @prepare_multicast: Prepare for multicast filter configuration.
* This callback is optional, and its return value is passed
* to configure_filter(). This callback must be atomic.
@@ -1674,6 +1678,9 @@ struct ieee80211_ops {
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed);
+ int (*configure_arp_filter)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct in_ifaddr *ifa_list);
u64 (*prepare_multicast)(struct ieee80211_hw *hw,
struct netdev_hw_addr_list *mc_list);
void (*configure_filter)(struct ieee80211_hw *hw,
@@ -2334,16 +2341,14 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, const u8 *ra,
* ieee80211_stop_tx_ba_session - Stop a Block Ack session.
* @sta: the station whose BA session to stop
* @tid: the TID to stop BA.
- * @initiator: if indicates initiator DELBA frame will be sent.
*
- * Return: error if no sta with matching da found, success otherwise
+ * Return: negative error if the TID is invalid, or no aggregation active
*
* Although mac80211/low level driver/user space application can estimate
* the need to stop aggregation on a certain RA/TID, the session level
* will be managed by the mac80211.
*/
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid,
- enum ieee80211_back_parties initiator);
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *sta, u16 tid);
/**
* ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate.
diff --git a/include/net/mip6.h b/include/net/mip6.h
index a83ad1982a90..26ba99b5a4b1 100644
--- a/include/net/mip6.h
+++ b/include/net/mip6.h
@@ -39,7 +39,7 @@ struct ip6_mh {
__u16 ip6mh_cksum;
/* Followed by type specific messages */
__u8 data[0];
-} __attribute__ ((__packed__));
+} __packed;
#define IP6_MH_TYPE_BRR 0 /* Binding Refresh Request */
#define IP6_MH_TYPE_HOTI 1 /* HOTI Message */
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index f76f22d05721..895997bc2ead 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -82,7 +82,7 @@ struct ra_msg {
struct nd_opt_hdr {
__u8 nd_opt_type;
__u8 nd_opt_len;
-} __attribute__((__packed__));
+} __packed;
extern int ndisc_init(void);
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index bde095f7e845..bbfdd9453087 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -152,11 +152,7 @@ extern struct net init_net;
static inline struct net *nf_ct_net(const struct nf_conn *ct)
{
-#ifdef CONFIG_NET_NS
- return ct->ct_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&ct->ct_net);
}
/* Alter reply tuple (maybe alter helper). */
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index 9d4d87cc970e..d9549af6929a 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -95,7 +95,7 @@ extern void __qdisc_run(struct Qdisc *q);
static inline void qdisc_run(struct Qdisc *q)
{
- if (!test_and_set_bit(__QDISC_STATE_RUNNING, &q->state))
+ if (qdisc_run_begin(q))
__qdisc_run(q);
}
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 03ca5d826757..b35301b0c7b6 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -23,11 +23,17 @@ struct qdisc_rate_table {
};
enum qdisc_state_t {
- __QDISC_STATE_RUNNING,
__QDISC_STATE_SCHED,
__QDISC_STATE_DEACTIVATED,
};
+/*
+ * following bits are only changed while qdisc lock is held
+ */
+enum qdisc___state_t {
+ __QDISC___STATE_RUNNING,
+};
+
struct qdisc_size_table {
struct list_head list;
struct tc_sizespec szopts;
@@ -72,10 +78,27 @@ struct Qdisc {
unsigned long state;
struct sk_buff_head q;
struct gnet_stats_basic_packed bstats;
+ unsigned long __state;
struct gnet_stats_queue qstats;
- struct rcu_head rcu_head;
+ struct rcu_head rcu_head;
+ spinlock_t busylock;
};
+static inline bool qdisc_is_running(struct Qdisc *qdisc)
+{
+ return test_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline bool qdisc_run_begin(struct Qdisc *qdisc)
+{
+ return !__test_and_set_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
+static inline void qdisc_run_end(struct Qdisc *qdisc)
+{
+ __clear_bit(__QDISC___STATE_RUNNING, &qdisc->__state);
+}
+
struct Qdisc_class_ops {
/* Child qdisc manipulation */
struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 4b860116e096..f9e7473613bd 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -443,7 +443,7 @@ struct sctp_signed_cookie {
__u8 signature[SCTP_SECRET_SIZE];
__u32 __pad; /* force sctp_cookie alignment to 64 bits */
struct sctp_cookie c;
-} __attribute__((packed));
+} __packed;
/* This is another convenience type to allocate memory for address
* params for the maximum size and pass such structures around
@@ -488,7 +488,7 @@ typedef struct sctp_sender_hb_info {
union sctp_addr daddr;
unsigned long sent_at;
__u64 hb_nonce;
-} __attribute__((packed)) sctp_sender_hb_info_t;
+} __packed sctp_sender_hb_info_t;
/*
* RFC 2960 1.3.2 Sequenced Delivery within Streams
diff --git a/include/net/sock.h b/include/net/sock.h
index ca241ea14875..f8acf38f092f 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1524,20 +1524,7 @@ extern void sk_stop_timer(struct sock *sk, struct timer_list* timer);
extern int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
-static inline int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
-{
- /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces
- number of warnings when compiling with -W --ANK
- */
- if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
- (unsigned)sk->sk_rcvbuf)
- return -ENOMEM;
- skb_set_owner_r(skb, sk);
- skb_queue_tail(&sk->sk_error_queue, skb);
- if (!sock_flag(sk, SOCK_DEAD))
- sk->sk_data_ready(sk, skb->len);
- return 0;
-}
+extern int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
/*
* Recover an error report and clear atomically
@@ -1724,19 +1711,13 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e
static inline
struct net *sock_net(const struct sock *sk)
{
-#ifdef CONFIG_NET_NS
- return sk->sk_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&sk->sk_net);
}
static inline
void sock_net_set(struct sock *sk, struct net *net)
{
-#ifdef CONFIG_NET_NS
- sk->sk_net = net;
-#endif
+ write_pnet(&sk->sk_net, net);
}
/*
diff --git a/include/rxrpc/packet.h b/include/rxrpc/packet.h
index b69e6e173ea1..9b2c30897e50 100644
--- a/include/rxrpc/packet.h
+++ b/include/rxrpc/packet.h
@@ -65,7 +65,7 @@ struct rxrpc_header {
};
__be16 serviceId; /* service ID */
-} __attribute__((packed));
+} __packed;
#define __rxrpc_header_off(X) offsetof(struct rxrpc_header,X)
@@ -120,7 +120,7 @@ struct rxrpc_ackpacket {
#define RXRPC_ACK_TYPE_NACK 0
#define RXRPC_ACK_TYPE_ACK 1
-} __attribute__((packed));
+} __packed;
/*
* ACK packets can have a further piece of information tagged on the end
@@ -141,7 +141,7 @@ struct rxkad_challenge {
__be32 nonce; /* encrypted random number */
__be32 min_level; /* minimum security level */
__be32 __padding; /* padding to 8-byte boundary */
-} __attribute__((packed));
+} __packed;
/*****************************************************************************/
/*
@@ -164,7 +164,7 @@ struct rxkad_response {
__be32 kvno; /* Kerberos key version number */
__be32 ticket_len; /* Kerberos ticket length */
-} __attribute__((packed));
+} __packed;
/*****************************************************************************/
/*
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index c50a97fc76f9..b7bdecb7b76e 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -327,6 +327,14 @@ struct scsi_host_template {
sector_t, int []);
/*
+ * This function is called when one or more partitions on the
+ * device reach beyond the end of the device.
+ *
+ * Status: OPTIONAL
+ */
+ void (*unlock_native_capacity)(struct scsi_device *);
+
+ /*
* Can be used to export driver statistics and other infos to the
* world outside the kernel ie. userspace and it also provides an
* interface to feed the driver with information.
diff --git a/include/sound/asound.h b/include/sound/asound.h
index 9f1eecf99e6b..a1803ecea34d 100644
--- a/include/sound/asound.h
+++ b/include/sound/asound.h
@@ -212,7 +212,11 @@ typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41) /* in three bytes */
#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42) /* in three bytes */
#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43) /* in three bytes */
-#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_U18_3BE
+#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44) /* 8 samples in 3 bytes */
+#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45) /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46) /* 8 Samples in 5 bytes */
+#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47) /* 1 sample in 1 byte */
+#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index dd76cdede64d..07fd630db88d 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -174,6 +174,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_FMTBIT_U18_3LE (1ULL << SNDRV_PCM_FORMAT_U18_3LE)
#define SNDRV_PCM_FMTBIT_S18_3BE (1ULL << SNDRV_PCM_FORMAT_S18_3BE)
#define SNDRV_PCM_FMTBIT_U18_3BE (1ULL << SNDRV_PCM_FORMAT_U18_3BE)
+#define SNDRV_PCM_FMTBIT_G723_24 (1ULL << SNDRV_PCM_FORMAT_G723_24)
+#define SNDRV_PCM_FMTBIT_G723_24_1B (1ULL << SNDRV_PCM_FORMAT_G723_24_1B)
+#define SNDRV_PCM_FMTBIT_G723_40 (1ULL << SNDRV_PCM_FORMAT_G723_40)
+#define SNDRV_PCM_FMTBIT_G723_40_1B (1ULL << SNDRV_PCM_FORMAT_G723_40_1B)
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 66ff4c124dbd..c5d9987bc897 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -273,6 +273,8 @@
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
+#define SND_SOC_DAPM_PRE_POST_PMD \
+ (SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
/* convenience event type detection */
#define SND_SOC_DAPM_EVENT_ON(e) \
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 697e7ffe39d7..65e9d03ed4f5 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -170,6 +170,21 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
+#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
+ xmin, xmax, tlv_array) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = snd_soc_info_volsw_2r_sx, \
+ .get = snd_soc_get_volsw_2r_sx, \
+ .put = snd_soc_put_volsw_2r_sx, \
+ .private_value = (unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg_left, \
+ .rreg = xreg_right, .shift = xshift, \
+ .min = xmin, .max = xmax} }
+
+
/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
@@ -329,6 +344,12 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
+int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo);
+int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
+int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol);
/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 4f733ecea46e..b9e1dd6c6208 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -115,6 +115,23 @@ DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new,
TP_PROTO(struct task_struct *p, int success),
TP_ARGS(p, success));
+#ifdef CREATE_TRACE_POINTS
+static inline long __trace_sched_switch_state(struct task_struct *p)
+{
+ long state = p->state;
+
+#ifdef CONFIG_PREEMPT
+ /*
+ * For all intents and purposes a preempted task is a running task.
+ */
+ if (task_thread_info(p)->preempt_count & PREEMPT_ACTIVE)
+ state = TASK_RUNNING;
+#endif
+
+ return state;
+}
+#endif
+
/*
* Tracepoint for task switches, performed by the scheduler:
*/
@@ -139,7 +156,7 @@ TRACE_EVENT(sched_switch,
memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN);
__entry->prev_pid = prev->pid;
__entry->prev_prio = prev->prio;
- __entry->prev_state = prev->state;
+ __entry->prev_state = __trace_sched_switch_state(prev);
memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN);
__entry->next_pid = next->pid;
__entry->next_prio = next->prio;
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 3d685d1f2a03..5a64905d7278 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -725,7 +725,7 @@ perf_trace_##call(void *__data, proto) \
\
{ assign; } \
\
- head = per_cpu_ptr(event_call->perf_events, smp_processor_id());\
+ head = this_cpu_ptr(event_call->perf_events); \
perf_trace_buf_submit(entry, __entry_size, rctx, __addr, \
__count, &__regs, head); \
}
diff --git a/include/video/mipi_display.h b/include/video/mipi_display.h
new file mode 100644
index 000000000000..ddcc8ca7316b
--- /dev/null
+++ b/include/video/mipi_display.h
@@ -0,0 +1,130 @@
+/*
+ * Defines for Mobile Industry Processor Interface (MIPI(R))
+ * Display Working Group standards: DSI, DCS, DBI, DPI
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2006 Nokia Corporation
+ * Author: Imre Deak <imre.deak@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef MIPI_DISPLAY_H
+#define MIPI_DISPLAY_H
+
+/* MIPI DSI Processor-to-Peripheral transaction types */
+enum {
+ MIPI_DSI_V_SYNC_START = 0x01,
+ MIPI_DSI_V_SYNC_END = 0x11,
+ MIPI_DSI_H_SYNC_START = 0x21,
+ MIPI_DSI_H_SYNC_END = 0x31,
+
+ MIPI_DSI_COLOR_MODE_OFF = 0x02,
+ MIPI_DSI_COLOR_MODE_ON = 0x12,
+ MIPI_DSI_SHUTDOWN_PERIPHERAL = 0x22,
+ MIPI_DSI_TURN_ON_PERIPHERAL = 0x32,
+
+ MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM = 0x03,
+ MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM = 0x13,
+ MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM = 0x23,
+
+ MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM = 0x04,
+ MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM = 0x14,
+ MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM = 0x24,
+
+ MIPI_DSI_DCS_SHORT_WRITE = 0x05,
+ MIPI_DSI_DCS_SHORT_WRITE_PARAM = 0x15,
+
+ MIPI_DSI_DCS_READ = 0x06,
+
+ MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE = 0x37,
+
+ MIPI_DSI_END_OF_TRANSMISSION = 0x08,
+
+ MIPI_DSI_NULL_PACKET = 0x09,
+ MIPI_DSI_BLANKING_PACKET = 0x19,
+ MIPI_DSI_GENERIC_LONG_WRITE = 0x29,
+ MIPI_DSI_DCS_LONG_WRITE = 0x39,
+
+ MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20 = 0x0c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24 = 0x1c,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16 = 0x2c,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_30 = 0x0d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_36 = 0x1d,
+ MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12 = 0x3d,
+
+ MIPI_DSI_PACKED_PIXEL_STREAM_16 = 0x0e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_18 = 0x1e,
+ MIPI_DSI_PIXEL_STREAM_3BYTE_18 = 0x2e,
+ MIPI_DSI_PACKED_PIXEL_STREAM_24 = 0x3e,
+};
+
+/* MIPI DSI Peripheral-to-Processor transaction types */
+enum {
+ MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT = 0x02,
+ MIPI_DSI_RX_END_OF_TRANSMISSION = 0x08,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE = 0x11,
+ MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE = 0x12,
+ MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE = 0x1a,
+ MIPI_DSI_RX_DCS_LONG_READ_RESPONSE = 0x1c,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE = 0x21,
+ MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE = 0x22,
+};
+
+/* MIPI DCS commands */
+enum {
+ MIPI_DCS_NOP = 0x00,
+ MIPI_DCS_SOFT_RESET = 0x01,
+ MIPI_DCS_GET_DISPLAY_ID = 0x04,
+ MIPI_DCS_GET_RED_CHANNEL = 0x06,
+ MIPI_DCS_GET_GREEN_CHANNEL = 0x07,
+ MIPI_DCS_GET_BLUE_CHANNEL = 0x08,
+ MIPI_DCS_GET_DISPLAY_STATUS = 0x09,
+ MIPI_DCS_GET_POWER_MODE = 0x0A,
+ MIPI_DCS_GET_ADDRESS_MODE = 0x0B,
+ MIPI_DCS_GET_PIXEL_FORMAT = 0x0C,
+ MIPI_DCS_GET_DISPLAY_MODE = 0x0D,
+ MIPI_DCS_GET_SIGNAL_MODE = 0x0E,
+ MIPI_DCS_GET_DIAGNOSTIC_RESULT = 0x0F,
+ MIPI_DCS_ENTER_SLEEP_MODE = 0x10,
+ MIPI_DCS_EXIT_SLEEP_MODE = 0x11,
+ MIPI_DCS_ENTER_PARTIAL_MODE = 0x12,
+ MIPI_DCS_ENTER_NORMAL_MODE = 0x13,
+ MIPI_DCS_EXIT_INVERT_MODE = 0x20,
+ MIPI_DCS_ENTER_INVERT_MODE = 0x21,
+ MIPI_DCS_SET_GAMMA_CURVE = 0x26,
+ MIPI_DCS_SET_DISPLAY_OFF = 0x28,
+ MIPI_DCS_SET_DISPLAY_ON = 0x29,
+ MIPI_DCS_SET_COLUMN_ADDRESS = 0x2A,
+ MIPI_DCS_SET_PAGE_ADDRESS = 0x2B,
+ MIPI_DCS_WRITE_MEMORY_START = 0x2C,
+ MIPI_DCS_WRITE_LUT = 0x2D,
+ MIPI_DCS_READ_MEMORY_START = 0x2E,
+ MIPI_DCS_SET_PARTIAL_AREA = 0x30,
+ MIPI_DCS_SET_SCROLL_AREA = 0x33,
+ MIPI_DCS_SET_TEAR_OFF = 0x34,
+ MIPI_DCS_SET_TEAR_ON = 0x35,
+ MIPI_DCS_SET_ADDRESS_MODE = 0x36,
+ MIPI_DCS_SET_SCROLL_START = 0x37,
+ MIPI_DCS_EXIT_IDLE_MODE = 0x38,
+ MIPI_DCS_ENTER_IDLE_MODE = 0x39,
+ MIPI_DCS_SET_PIXEL_FORMAT = 0x3A,
+ MIPI_DCS_WRITE_MEMORY_CONTINUE = 0x3C,
+ MIPI_DCS_READ_MEMORY_CONTINUE = 0x3E,
+ MIPI_DCS_SET_TEAR_SCANLINE = 0x44,
+ MIPI_DCS_GET_SCANLINE = 0x45,
+ MIPI_DCS_READ_DDB_START = 0xA1,
+ MIPI_DCS_READ_DDB_CONTINUE = 0xA8,
+};
+
+/* MIPI DCS pixel formats */
+#define MIPI_DCS_PIXEL_FMT_24BIT 7
+#define MIPI_DCS_PIXEL_FMT_18BIT 6
+#define MIPI_DCS_PIXEL_FMT_16BIT 5
+#define MIPI_DCS_PIXEL_FMT_12BIT 3
+#define MIPI_DCS_PIXEL_FMT_8BIT 2
+#define MIPI_DCS_PIXEL_FMT_3BIT 1
+
+#endif
diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h
new file mode 100644
index 000000000000..18bca08f9f59
--- /dev/null
+++ b/include/video/sh_mipi_dsi.h
@@ -0,0 +1,35 @@
+/*
+ * Public SH-mobile MIPI DSI header
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef VIDEO_SH_MIPI_DSI_H
+#define VIDEO_SH_MIPI_DSI_H
+
+enum sh_mipi_dsi_data_fmt {
+ MIPI_RGB888,
+ MIPI_RGB565,
+ MIPI_RGB666_LP,
+ MIPI_RGB666,
+ MIPI_BGR888,
+ MIPI_BGR565,
+ MIPI_BGR666_LP,
+ MIPI_BGR666,
+ MIPI_YUYV,
+ MIPI_UYVY,
+ MIPI_YUV420_L,
+ MIPI_YUV420,
+};
+
+struct sh_mobile_lcdc_chan_cfg;
+
+struct sh_mipi_dsi_info {
+ enum sh_mipi_dsi_data_fmt data_format;
+ struct sh_mobile_lcdc_chan_cfg *lcd_chan;
+};
+
+#endif
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h
index 288205457713..24393449960f 100644
--- a/include/video/sh_mobile_lcdc.h
+++ b/include/video/sh_mobile_lcdc.h
@@ -3,24 +3,27 @@
#include <linux/fb.h>
-enum { RGB8, /* 24bpp, 8:8:8 */
- RGB9, /* 18bpp, 9:9 */
- RGB12A, /* 24bpp, 12:12 */
- RGB12B, /* 12bpp */
- RGB16, /* 16bpp */
- RGB18, /* 18bpp */
- RGB24, /* 24bpp */
- SYS8A, /* 24bpp, 8:8:8 */
- SYS8B, /* 18bpp, 8:8:2 */
- SYS8C, /* 18bpp, 2:8:8 */
- SYS8D, /* 16bpp, 8:8 */
- SYS9, /* 18bpp, 9:9 */
- SYS12, /* 24bpp, 12:12 */
- SYS16A, /* 16bpp */
- SYS16B, /* 18bpp, 16:2 */
- SYS16C, /* 18bpp, 2:16 */
- SYS18, /* 18bpp */
- SYS24 };/* 24bpp */
+enum {
+ RGB8, /* 24bpp, 8:8:8 */
+ RGB9, /* 18bpp, 9:9 */
+ RGB12A, /* 24bpp, 12:12 */
+ RGB12B, /* 12bpp */
+ RGB16, /* 16bpp */
+ RGB18, /* 18bpp */
+ RGB24, /* 24bpp */
+ YUV422, /* 16bpp */
+ SYS8A, /* 24bpp, 8:8:8 */
+ SYS8B, /* 18bpp, 8:8:2 */
+ SYS8C, /* 18bpp, 2:8:8 */
+ SYS8D, /* 16bpp, 8:8 */
+ SYS9, /* 18bpp, 9:9 */
+ SYS12, /* 24bpp, 12:12 */
+ SYS16A, /* 16bpp */
+ SYS16B, /* 18bpp, 16:2 */
+ SYS16C, /* 18bpp, 2:16 */
+ SYS18, /* 18bpp */
+ SYS24, /* 24bpp */
+};
enum { LCDC_CHAN_DISABLED = 0,
LCDC_CHAN_MAINLCD,
diff --git a/init/Kconfig b/init/Kconfig
index 2cce9f343ad0..05e932ef5169 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -76,6 +76,14 @@ config INIT_ENV_ARG_LIMIT
variables passed to init from the kernel command line.
+config CROSS_COMPILE
+ string "Cross-compiler tool prefix"
+ help
+ Same as running 'make CROSS_COMPILE=prefix-' but stored for
+ default make runs in this kernel build directory. You don't
+ need to set this unless you want the configured kernel build
+ directory to select the cross-compiler automatically.
+
config LOCALVERSION
string "Local version - append to kernel release"
help
@@ -312,13 +320,17 @@ config AUDITSYSCALL
help
Enable low-overhead system-call auditing infrastructure that
can be used independently or with another kernel subsystem,
- such as SELinux. To use audit's filesystem watch feature, please
- ensure that INOTIFY is configured.
+ such as SELinux.
+
+config AUDIT_WATCH
+ def_bool y
+ depends on AUDITSYSCALL
+ select FSNOTIFY
config AUDIT_TREE
def_bool y
depends on AUDITSYSCALL
- select INOTIFY
+ select FSNOTIFY
menu "RCU Subsystem"
diff --git a/init/main.c b/init/main.c
index 3bdb152f412f..25c8b2fa68bc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -202,11 +202,11 @@ static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
static const char *panic_later, *panic_param;
-extern struct obs_kernel_param __setup_start[], __setup_end[];
+extern const struct obs_kernel_param __setup_start[], __setup_end[];
static int __init obsolete_checksetup(char *line)
{
- struct obs_kernel_param *p;
+ const struct obs_kernel_param *p;
int had_early_param = 0;
p = __setup_start;
@@ -452,7 +452,7 @@ static noinline void __init_refok rest_init(void)
/* Check for early params. */
static int __init do_early_param(char *param, char *val)
{
- struct obs_kernel_param *p;
+ const struct obs_kernel_param *p;
for (p = __setup_start; p < __setup_end; p++) {
if ((p->early && strcmp(param, p->str) == 0) ||
@@ -529,7 +529,7 @@ static void __init mm_init(void)
asmlinkage void __init start_kernel(void)
{
char * command_line;
- extern struct kernel_param __start___param[], __stop___param[];
+ extern const struct kernel_param __start___param[], __stop___param[];
smp_setup_processor_id();
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 5108232f93d4..c93fd3faac2d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -176,7 +176,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
}
return inode;
out_inode:
- make_bad_inode(inode);
iput(inode);
return NULL;
}
diff --git a/kernel/Makefile b/kernel/Makefile
index 057472fbc272..a10a24788ffb 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -70,14 +70,15 @@ obj-$(CONFIG_IKCONFIG) += configs.o
obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
obj-$(CONFIG_SMP) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
-obj-$(CONFIG_AUDIT) += audit.o auditfilter.o audit_watch.o
+obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
-obj-$(CONFIG_GCOV_KERNEL) += gcov/
+obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o
obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
+obj-$(CONFIG_GCOV_KERNEL) += gcov/
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KGDB) += debug/
-obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
+obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
diff --git a/kernel/audit.c b/kernel/audit.c
index c71bd26631a2..05a32f0d87dc 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -56,7 +56,6 @@
#include <net/netlink.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
-#include <linux/inotify.h>
#include <linux/freezer.h>
#include <linux/tty.h>
diff --git a/kernel/audit.h b/kernel/audit.h
index 208687be4f30..f7206db4e13d 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -103,21 +103,27 @@ extern struct mutex audit_filter_mutex;
extern void audit_free_rule_rcu(struct rcu_head *);
extern struct list_head audit_filter_list[];
+extern struct audit_entry *audit_dupe_rule(struct audit_krule *old);
+
/* audit watch functions */
-extern unsigned long audit_watch_inode(struct audit_watch *watch);
-extern dev_t audit_watch_dev(struct audit_watch *watch);
+#ifdef CONFIG_AUDIT_WATCH
extern void audit_put_watch(struct audit_watch *watch);
extern void audit_get_watch(struct audit_watch *watch);
extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op);
-extern int audit_add_watch(struct audit_krule *krule);
-extern void audit_remove_watch(struct audit_watch *watch);
-extern void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list);
-extern void audit_inotify_unregister(struct list_head *in_list);
+extern int audit_add_watch(struct audit_krule *krule, struct list_head **list);
+extern void audit_remove_watch_rule(struct audit_krule *krule);
extern char *audit_watch_path(struct audit_watch *watch);
-extern struct list_head *audit_watch_rules(struct audit_watch *watch);
-
-extern struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch);
+extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev);
+#else
+#define audit_put_watch(w) {}
+#define audit_get_watch(w) {}
+#define audit_to_watch(k, p, l, o) (-EINVAL)
+#define audit_add_watch(k, l) (-EINVAL)
+#define audit_remove_watch_rule(k) BUG()
+#define audit_watch_path(w) ""
+#define audit_watch_compare(w, i, d) 0
+
+#endif /* CONFIG_AUDIT_WATCH */
#ifdef CONFIG_AUDIT_TREE
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
index 46a57b57a335..cfb97d752a61 100644
--- a/kernel/audit_tree.c
+++ b/kernel/audit_tree.c
@@ -1,5 +1,5 @@
#include "audit.h"
-#include <linux/inotify.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/kthread.h>
@@ -22,7 +22,7 @@ struct audit_tree {
struct audit_chunk {
struct list_head hash;
- struct inotify_watch watch;
+ struct fsnotify_mark mark;
struct list_head trees; /* with root here */
int dead;
int count;
@@ -59,7 +59,7 @@ static LIST_HEAD(prune_list);
* tree is refcounted; one reference for "some rules on rules_list refer to
* it", one for each chunk with pointer to it.
*
- * chunk is refcounted by embedded inotify_watch + .refs (non-zero refcount
+ * chunk is refcounted by embedded fsnotify_mark + .refs (non-zero refcount
* of watch contributes 1 to .refs).
*
* node.index allows to get from node.list to containing chunk.
@@ -68,7 +68,7 @@ static LIST_HEAD(prune_list);
* that makes a difference. Some.
*/
-static struct inotify_handle *rtree_ih;
+static struct fsnotify_group *audit_tree_group;
static struct audit_tree *alloc_tree(const char *s)
{
@@ -111,29 +111,6 @@ const char *audit_tree_path(struct audit_tree *tree)
return tree->pathname;
}
-static struct audit_chunk *alloc_chunk(int count)
-{
- struct audit_chunk *chunk;
- size_t size;
- int i;
-
- size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
- chunk = kzalloc(size, GFP_KERNEL);
- if (!chunk)
- return NULL;
-
- INIT_LIST_HEAD(&chunk->hash);
- INIT_LIST_HEAD(&chunk->trees);
- chunk->count = count;
- atomic_long_set(&chunk->refs, 1);
- for (i = 0; i < count; i++) {
- INIT_LIST_HEAD(&chunk->owners[i].list);
- chunk->owners[i].index = i;
- }
- inotify_init_watch(&chunk->watch);
- return chunk;
-}
-
static void free_chunk(struct audit_chunk *chunk)
{
int i;
@@ -157,6 +134,35 @@ static void __put_chunk(struct rcu_head *rcu)
audit_put_chunk(chunk);
}
+static void audit_tree_destroy_watch(struct fsnotify_mark *entry)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+ call_rcu(&chunk->head, __put_chunk);
+}
+
+static struct audit_chunk *alloc_chunk(int count)
+{
+ struct audit_chunk *chunk;
+ size_t size;
+ int i;
+
+ size = offsetof(struct audit_chunk, owners) + count * sizeof(struct node);
+ chunk = kzalloc(size, GFP_KERNEL);
+ if (!chunk)
+ return NULL;
+
+ INIT_LIST_HEAD(&chunk->hash);
+ INIT_LIST_HEAD(&chunk->trees);
+ chunk->count = count;
+ atomic_long_set(&chunk->refs, 1);
+ for (i = 0; i < count; i++) {
+ INIT_LIST_HEAD(&chunk->owners[i].list);
+ chunk->owners[i].index = i;
+ }
+ fsnotify_init_mark(&chunk->mark, audit_tree_destroy_watch);
+ return chunk;
+}
+
enum {HASH_SIZE = 128};
static struct list_head chunk_hash_heads[HASH_SIZE];
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(hash_lock);
@@ -167,10 +173,15 @@ static inline struct list_head *chunk_hash(const struct inode *inode)
return chunk_hash_heads + n % HASH_SIZE;
}
-/* hash_lock is held by caller */
+/* hash_lock & entry->lock is held by caller */
static void insert_hash(struct audit_chunk *chunk)
{
- struct list_head *list = chunk_hash(chunk->watch.inode);
+ struct fsnotify_mark *entry = &chunk->mark;
+ struct list_head *list;
+
+ if (!entry->i.inode)
+ return;
+ list = chunk_hash(entry->i.inode);
list_add_rcu(&chunk->hash, list);
}
@@ -181,7 +192,8 @@ struct audit_chunk *audit_tree_lookup(const struct inode *inode)
struct audit_chunk *p;
list_for_each_entry_rcu(p, list, hash) {
- if (p->watch.inode == inode) {
+ /* mark.inode may have gone NULL, but who cares? */
+ if (p->mark.i.inode == inode) {
atomic_long_inc(&p->refs);
return p;
}
@@ -210,38 +222,19 @@ static struct audit_chunk *find_chunk(struct node *p)
static void untag_chunk(struct node *p)
{
struct audit_chunk *chunk = find_chunk(p);
+ struct fsnotify_mark *entry = &chunk->mark;
struct audit_chunk *new;
struct audit_tree *owner;
int size = chunk->count - 1;
int i, j;
- if (!pin_inotify_watch(&chunk->watch)) {
- /*
- * Filesystem is shutting down; all watches are getting
- * evicted, just take it off the node list for this
- * tree and let the eviction logics take care of the
- * rest.
- */
- owner = p->owner;
- if (owner->root == chunk) {
- list_del_init(&owner->same_root);
- owner->root = NULL;
- }
- list_del_init(&p->list);
- p->owner = NULL;
- put_tree(owner);
- return;
- }
+ fsnotify_get_mark(entry);
spin_unlock(&hash_lock);
- /*
- * pin_inotify_watch() succeeded, so the watch won't go away
- * from under us.
- */
- mutex_lock(&chunk->watch.inode->inotify_mutex);
- if (chunk->dead) {
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_lock(&entry->lock);
+ if (chunk->dead || !entry->i.inode) {
+ spin_unlock(&entry->lock);
goto out;
}
@@ -256,16 +249,17 @@ static void untag_chunk(struct node *p)
list_del_init(&p->list);
list_del_rcu(&chunk->hash);
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark(entry);
+ fsnotify_put_mark(entry);
goto out;
}
new = alloc_chunk(size);
if (!new)
goto Fallback;
- if (inotify_clone_watch(&chunk->watch, &new->watch) < 0) {
+ fsnotify_duplicate_mark(&new->mark, entry);
+ if (fsnotify_add_mark(&new->mark, new->mark.group, new->mark.i.inode, NULL, 1)) {
free_chunk(new);
goto Fallback;
}
@@ -298,9 +292,9 @@ static void untag_chunk(struct node *p)
list_for_each_entry(owner, &new->trees, same_root)
owner->root = new;
spin_unlock(&hash_lock);
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark(entry);
+ fsnotify_put_mark(entry);
goto out;
Fallback:
@@ -314,31 +308,33 @@ Fallback:
p->owner = NULL;
put_tree(owner);
spin_unlock(&hash_lock);
- mutex_unlock(&chunk->watch.inode->inotify_mutex);
+ spin_unlock(&entry->lock);
out:
- unpin_inotify_watch(&chunk->watch);
+ fsnotify_put_mark(entry);
spin_lock(&hash_lock);
}
static int create_chunk(struct inode *inode, struct audit_tree *tree)
{
+ struct fsnotify_mark *entry;
struct audit_chunk *chunk = alloc_chunk(1);
if (!chunk)
return -ENOMEM;
- if (inotify_add_watch(rtree_ih, &chunk->watch, inode, IN_IGNORED | IN_DELETE_SELF) < 0) {
+ entry = &chunk->mark;
+ if (fsnotify_add_mark(entry, audit_tree_group, inode, NULL, 0)) {
free_chunk(chunk);
return -ENOSPC;
}
- mutex_lock(&inode->inotify_mutex);
+ spin_lock(&entry->lock);
spin_lock(&hash_lock);
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&entry->lock);
+ fsnotify_destroy_mark(entry);
+ fsnotify_put_mark(entry);
return 0;
}
chunk->owners[0].index = (1U << 31);
@@ -351,30 +347,31 @@ static int create_chunk(struct inode *inode, struct audit_tree *tree)
}
insert_hash(chunk);
spin_unlock(&hash_lock);
- mutex_unlock(&inode->inotify_mutex);
+ spin_unlock(&entry->lock);
return 0;
}
/* the first tagged inode becomes root of tree */
static int tag_chunk(struct inode *inode, struct audit_tree *tree)
{
- struct inotify_watch *watch;
+ struct fsnotify_mark *old_entry, *chunk_entry;
struct audit_tree *owner;
struct audit_chunk *chunk, *old;
struct node *p;
int n;
- if (inotify_find_watch(rtree_ih, inode, &watch) < 0)
+ old_entry = fsnotify_find_inode_mark(audit_tree_group, inode);
+ if (!old_entry)
return create_chunk(inode, tree);
- old = container_of(watch, struct audit_chunk, watch);
+ old = container_of(old_entry, struct audit_chunk, mark);
/* are we already there? */
spin_lock(&hash_lock);
for (n = 0; n < old->count; n++) {
if (old->owners[n].owner == tree) {
spin_unlock(&hash_lock);
- put_inotify_watch(&old->watch);
+ fsnotify_put_mark(old_entry);
return 0;
}
}
@@ -382,25 +379,44 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
chunk = alloc_chunk(old->count + 1);
if (!chunk) {
- put_inotify_watch(&old->watch);
+ fsnotify_put_mark(old_entry);
return -ENOMEM;
}
- mutex_lock(&inode->inotify_mutex);
- if (inotify_clone_watch(&old->watch, &chunk->watch) < 0) {
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
+ chunk_entry = &chunk->mark;
+
+ spin_lock(&old_entry->lock);
+ if (!old_entry->i.inode) {
+ /* old_entry is being shot, lets just lie */
+ spin_unlock(&old_entry->lock);
+ fsnotify_put_mark(old_entry);
free_chunk(chunk);
+ return -ENOENT;
+ }
+
+ fsnotify_duplicate_mark(chunk_entry, old_entry);
+ if (fsnotify_add_mark(chunk_entry, chunk_entry->group, chunk_entry->i.inode, NULL, 1)) {
+ spin_unlock(&old_entry->lock);
+ free_chunk(chunk);
+ fsnotify_put_mark(old_entry);
return -ENOSPC;
}
+
+ /* even though we hold old_entry->lock, this is safe since chunk_entry->lock could NEVER have been grabbed before */
+ spin_lock(&chunk_entry->lock);
spin_lock(&hash_lock);
+
+ /* we now hold old_entry->lock, chunk_entry->lock, and hash_lock */
if (tree->goner) {
spin_unlock(&hash_lock);
chunk->dead = 1;
- inotify_evict_watch(&chunk->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch);
- put_inotify_watch(&chunk->watch);
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+
+ fsnotify_destroy_mark(chunk_entry);
+
+ fsnotify_put_mark(chunk_entry);
+ fsnotify_put_mark(old_entry);
return 0;
}
list_replace_init(&old->trees, &chunk->trees);
@@ -426,10 +442,11 @@ static int tag_chunk(struct inode *inode, struct audit_tree *tree)
list_add(&tree->same_root, &chunk->trees);
}
spin_unlock(&hash_lock);
- inotify_evict_watch(&old->watch);
- mutex_unlock(&inode->inotify_mutex);
- put_inotify_watch(&old->watch); /* pair to inotify_find_watch */
- put_inotify_watch(&old->watch); /* and kill it */
+ spin_unlock(&chunk_entry->lock);
+ spin_unlock(&old_entry->lock);
+ fsnotify_destroy_mark(old_entry);
+ fsnotify_put_mark(old_entry); /* pair to fsnotify_find mark_entry */
+ fsnotify_put_mark(old_entry); /* and kill it */
return 0;
}
@@ -584,7 +601,9 @@ void audit_trim_trees(void)
spin_lock(&hash_lock);
list_for_each_entry(node, &tree->chunks, list) {
- struct inode *inode = find_chunk(node)->watch.inode;
+ struct audit_chunk *chunk = find_chunk(node);
+ /* this could be NULL if the watch is dieing else where... */
+ struct inode *inode = chunk->mark.i.inode;
node->index |= 1U<<31;
if (iterate_mounts(compare_root, inode, root_mnt))
node->index &= ~(1U<<31);
@@ -846,7 +865,6 @@ void audit_kill_trees(struct list_head *list)
* Here comes the stuff asynchronous to auditctl operations
*/
-/* inode->inotify_mutex is locked */
static void evict_chunk(struct audit_chunk *chunk)
{
struct audit_tree *owner;
@@ -885,35 +903,42 @@ static void evict_chunk(struct audit_chunk *chunk)
mutex_unlock(&audit_filter_mutex);
}
-static void handle_event(struct inotify_watch *watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static int audit_tree_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
+ BUG();
+ return -EOPNOTSUPP;
+}
- if (mask & IN_IGNORED) {
- evict_chunk(chunk);
- put_inotify_watch(watch);
- }
+static void audit_tree_freeing_mark(struct fsnotify_mark *entry, struct fsnotify_group *group)
+{
+ struct audit_chunk *chunk = container_of(entry, struct audit_chunk, mark);
+
+ evict_chunk(chunk);
+ fsnotify_put_mark(entry);
}
-static void destroy_watch(struct inotify_watch *watch)
+static bool audit_tree_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
- struct audit_chunk *chunk = container_of(watch, struct audit_chunk, watch);
- call_rcu(&chunk->head, __put_chunk);
+ return 0;
}
-static const struct inotify_operations rtree_inotify_ops = {
- .handle_event = handle_event,
- .destroy_watch = destroy_watch,
+static const struct fsnotify_ops audit_tree_ops = {
+ .handle_event = audit_tree_handle_event,
+ .should_send_event = audit_tree_send_event,
+ .free_group_priv = NULL,
+ .free_event_priv = NULL,
+ .freeing_mark = audit_tree_freeing_mark,
};
static int __init audit_tree_init(void)
{
int i;
- rtree_ih = inotify_init(&rtree_inotify_ops);
- if (IS_ERR(rtree_ih))
- audit_panic("cannot initialize inotify handle for rectree watches");
+ audit_tree_group = fsnotify_alloc_group(&audit_tree_ops);
+ if (IS_ERR(audit_tree_group))
+ audit_panic("cannot initialize fsnotify group for rectree watches");
for (i = 0; i < HASH_SIZE; i++)
INIT_LIST_HEAD(&chunk_hash_heads[i]);
diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
index 8df43696f4ba..7499397a6100 100644
--- a/kernel/audit_watch.c
+++ b/kernel/audit_watch.c
@@ -24,18 +24,18 @@
#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/fs.h>
+#include <linux/fsnotify_backend.h>
#include <linux/namei.h>
#include <linux/netlink.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/inotify.h>
#include <linux/security.h>
#include "audit.h"
/*
* Reference counting:
*
- * audit_parent: lifetime is from audit_init_parent() to receipt of an IN_IGNORED
+ * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED
* event. Each audit_watch holds a reference to its associated parent.
*
* audit_watch: if added to lists, lifetime is from audit_init_watch() to
@@ -51,40 +51,61 @@ struct audit_watch {
unsigned long ino; /* associated inode number */
struct audit_parent *parent; /* associated parent */
struct list_head wlist; /* entry in parent->watches list */
- struct list_head rules; /* associated rules */
+ struct list_head rules; /* anchor for krule->rlist */
};
struct audit_parent {
- struct list_head ilist; /* entry in inotify registration list */
- struct list_head watches; /* associated watches */
- struct inotify_watch wdata; /* inotify watch data */
- unsigned flags; /* status flags */
+ struct list_head watches; /* anchor for audit_watch->wlist */
+ struct fsnotify_mark mark; /* fsnotify mark on the inode */
};
-/* Inotify handle. */
-struct inotify_handle *audit_ih;
+/* fsnotify handle. */
+struct fsnotify_group *audit_watch_group;
-/*
- * audit_parent status flags:
- *
- * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
- * a filesystem event to ensure we're adding audit watches to a valid parent.
- * Technically not needed for IN_DELETE_SELF or IN_UNMOUNT events, as we cannot
- * receive them while we have nameidata, but must be used for IN_MOVE_SELF which
- * we can receive while holding nameidata.
- */
-#define AUDIT_PARENT_INVALID 0x001
+/* fsnotify events we care about. */
+#define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
+ FS_MOVE_SELF | FS_EVENT_ON_CHILD)
-/* Inotify events we care about. */
-#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
+static void audit_free_parent(struct audit_parent *parent)
+{
+ WARN_ON(!list_empty(&parent->watches));
+ kfree(parent);
+}
-static void audit_free_parent(struct inotify_watch *i_watch)
+static void audit_watch_free_mark(struct fsnotify_mark *entry)
{
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
- WARN_ON(!list_empty(&parent->watches));
- kfree(parent);
+ parent = container_of(entry, struct audit_parent, mark);
+ audit_free_parent(parent);
+}
+
+static void audit_get_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_get_mark(&parent->mark);
+}
+
+static void audit_put_parent(struct audit_parent *parent)
+{
+ if (likely(parent))
+ fsnotify_put_mark(&parent->mark);
+}
+
+/*
+ * Find and return the audit_parent on the given inode. If found a reference
+ * is taken on this parent.
+ */
+static inline struct audit_parent *audit_find_parent(struct inode *inode)
+{
+ struct audit_parent *parent = NULL;
+ struct fsnotify_mark *entry;
+
+ entry = fsnotify_find_inode_mark(audit_watch_group, inode);
+ if (entry)
+ parent = container_of(entry, struct audit_parent, mark);
+
+ return parent;
}
void audit_get_watch(struct audit_watch *watch)
@@ -105,7 +126,7 @@ void audit_put_watch(struct audit_watch *watch)
void audit_remove_watch(struct audit_watch *watch)
{
list_del(&watch->wlist);
- put_inotify_watch(&watch->parent->wdata);
+ audit_put_parent(watch->parent);
watch->parent = NULL;
audit_put_watch(watch); /* match initial get */
}
@@ -115,44 +136,36 @@ char *audit_watch_path(struct audit_watch *watch)
return watch->path;
}
-struct list_head *audit_watch_rules(struct audit_watch *watch)
+int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
{
- return &watch->rules;
-}
-
-unsigned long audit_watch_inode(struct audit_watch *watch)
-{
- return watch->ino;
-}
-
-dev_t audit_watch_dev(struct audit_watch *watch)
-{
- return watch->dev;
+ return (watch->ino != (unsigned long)-1) &&
+ (watch->ino == ino) &&
+ (watch->dev == dev);
}
/* Initialize a parent watch entry. */
static struct audit_parent *audit_init_parent(struct nameidata *ndp)
{
+ struct inode *inode = ndp->path.dentry->d_inode;
struct audit_parent *parent;
- s32 wd;
+ int ret;
parent = kzalloc(sizeof(*parent), GFP_KERNEL);
if (unlikely(!parent))
return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&parent->watches);
- parent->flags = 0;
-
- inotify_init_watch(&parent->wdata);
- /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */
- get_inotify_watch(&parent->wdata);
- wd = inotify_add_watch(audit_ih, &parent->wdata,
- ndp->path.dentry->d_inode, AUDIT_IN_WATCH);
- if (wd < 0) {
- audit_free_parent(&parent->wdata);
- return ERR_PTR(wd);
+
+ fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
+ parent->mark.mask = AUDIT_FS_WATCH;
+ ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
+ if (ret < 0) {
+ audit_free_parent(parent);
+ return ERR_PTR(ret);
}
+ fsnotify_recalc_group_mask(audit_watch_group);
+
return parent;
}
@@ -179,7 +192,7 @@ int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op)
{
struct audit_watch *watch;
- if (!audit_ih)
+ if (!audit_watch_group)
return -EOPNOTSUPP;
if (path[0] != '/' || path[len-1] == '/' ||
@@ -217,7 +230,7 @@ static struct audit_watch *audit_dupe_watch(struct audit_watch *old)
new->dev = old->dev;
new->ino = old->ino;
- get_inotify_watch(&old->parent->wdata);
+ audit_get_parent(old->parent);
new->parent = old->parent;
out:
@@ -251,15 +264,19 @@ static void audit_update_watch(struct audit_parent *parent,
struct audit_entry *oentry, *nentry;
mutex_lock(&audit_filter_mutex);
+ /* Run all of the watches on this parent looking for the one that
+ * matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) {
if (audit_compare_dname_path(dname, owatch->path, NULL))
continue;
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */
- if (invalidating && current->audit_context)
+ if (invalidating && !audit_dummy_context())
audit_filter_inodes(current, current->audit_context);
+ /* updating ino will likely change which audit_hash_list we
+ * are on so we need a new watch for the new list */
nwatch = audit_dupe_watch(owatch);
if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
@@ -275,12 +292,21 @@ static void audit_update_watch(struct audit_parent *parent,
list_del(&oentry->rule.rlist);
list_del_rcu(&oentry->list);
- nentry = audit_dupe_rule(&oentry->rule, nwatch);
+ nentry = audit_dupe_rule(&oentry->rule);
if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing");
} else {
int h = audit_hash_ino((u32)ino);
+
+ /*
+ * nentry->rule.watch == oentry->rule.watch so
+ * we must drop that reference and set it to our
+ * new watch.
+ */
+ audit_put_watch(nentry->rule.watch);
+ audit_get_watch(nwatch);
+ nentry->rule.watch = nwatch;
list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
@@ -312,7 +338,6 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
struct audit_entry *e;
mutex_lock(&audit_filter_mutex);
- parent->flags |= AUDIT_PARENT_INVALID;
list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
e = container_of(r, struct audit_entry, rule);
@@ -325,20 +350,11 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
audit_remove_watch(w);
}
mutex_unlock(&audit_filter_mutex);
-}
-/* Unregister inotify watches for parents on in_list.
- * Generates an IN_IGNORED event. */
-void audit_inotify_unregister(struct list_head *in_list)
-{
- struct audit_parent *p, *n;
+ fsnotify_destroy_mark(&parent->mark);
+
+ fsnotify_recalc_group_mask(audit_watch_group);
- list_for_each_entry_safe(p, n, in_list, ilist) {
- list_del(&p->ilist);
- inotify_rm_watch(audit_ih, &p->wdata);
- /* the unpin matching the pin in audit_do_del_rule() */
- unpin_inotify_watch(&p->wdata);
- }
}
/* Get path information necessary for adding watches. */
@@ -389,7 +405,7 @@ static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
}
}
-/* Associate the given rule with an existing parent inotify_watch.
+/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
struct audit_parent *parent)
@@ -397,6 +413,8 @@ static void audit_add_to_parent(struct audit_krule *krule,
struct audit_watch *w, *watch = krule->watch;
int watch_found = 0;
+ BUG_ON(!mutex_is_locked(&audit_filter_mutex));
+
list_for_each_entry(w, &parent->watches, wlist) {
if (strcmp(watch->path, w->path))
continue;
@@ -413,7 +431,7 @@ static void audit_add_to_parent(struct audit_krule *krule,
}
if (!watch_found) {
- get_inotify_watch(&parent->wdata);
+ audit_get_parent(parent);
watch->parent = parent;
list_add(&watch->wlist, &parent->watches);
@@ -423,13 +441,12 @@ static void audit_add_to_parent(struct audit_krule *krule,
/* Find a matching watch entry, or add this one.
* Caller must hold audit_filter_mutex. */
-int audit_add_watch(struct audit_krule *krule)
+int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{
struct audit_watch *watch = krule->watch;
- struct inotify_watch *i_watch;
struct audit_parent *parent;
struct nameidata *ndp = NULL, *ndw = NULL;
- int ret = 0;
+ int h, ret = 0;
mutex_unlock(&audit_filter_mutex);
@@ -441,47 +458,38 @@ int audit_add_watch(struct audit_krule *krule)
goto error;
}
+ mutex_lock(&audit_filter_mutex);
+
/* update watch filter fields */
if (ndw) {
watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
watch->ino = ndw->path.dentry->d_inode->i_ino;
}
- /* The audit_filter_mutex must not be held during inotify calls because
- * we hold it during inotify event callback processing. If an existing
- * inotify watch is found, inotify_find_watch() grabs a reference before
- * returning.
- */
- if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode,
- &i_watch) < 0) {
+ /* either find an old parent or attach a new one */
+ parent = audit_find_parent(ndp->path.dentry->d_inode);
+ if (!parent) {
parent = audit_init_parent(ndp);
if (IS_ERR(parent)) {
- /* caller expects mutex locked */
- mutex_lock(&audit_filter_mutex);
ret = PTR_ERR(parent);
goto error;
}
- } else
- parent = container_of(i_watch, struct audit_parent, wdata);
-
- mutex_lock(&audit_filter_mutex);
+ }
- /* parent was moved before we took audit_filter_mutex */
- if (parent->flags & AUDIT_PARENT_INVALID)
- ret = -ENOENT;
- else
- audit_add_to_parent(krule, parent);
+ audit_add_to_parent(krule, parent);
- /* match get in audit_init_parent or inotify_find_watch */
- put_inotify_watch(&parent->wdata);
+ /* match get in audit_find_parent or audit_init_parent */
+ audit_put_parent(parent);
+ h = audit_hash_ino((u32)watch->ino);
+ *list = &audit_inode_hash[h];
error:
audit_put_nd(ndp, ndw); /* NULL args OK */
return ret;
}
-void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
+void audit_remove_watch_rule(struct audit_krule *krule)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent = watch->parent;
@@ -492,53 +500,92 @@ void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
audit_remove_watch(watch);
if (list_empty(&parent->watches)) {
- /* Put parent on the inotify un-registration
- * list. Grab a reference before releasing
- * audit_filter_mutex, to be released in
- * audit_inotify_unregister().
- * If filesystem is going away, just leave
- * the sucker alone, eviction will take
- * care of it. */
- if (pin_inotify_watch(&parent->wdata))
- list_add(&parent->ilist, list);
+ audit_get_parent(parent);
+ fsnotify_destroy_mark(&parent->mark);
+ audit_put_parent(parent);
}
}
+
+ fsnotify_recalc_group_mask(audit_watch_group);
+
}
-/* Update watch data in audit rules based on inotify events. */
-static void audit_handle_ievent(struct inotify_watch *i_watch, u32 wd, u32 mask,
- u32 cookie, const char *dname, struct inode *inode)
+static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_type)
{
+ struct fsnotify_mark *entry;
+ bool send;
+
+ entry = fsnotify_find_inode_mark(group, inode);
+ if (!entry)
+ return false;
+
+ mask = (mask & ~FS_EVENT_ON_CHILD);
+ send = (entry->mask & mask);
+
+ /* find took a reference */
+ fsnotify_put_mark(entry);
+
+ return send;
+}
+
+/* Update watch data in audit rules based on fsnotify events. */
+static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+{
+ struct inode *inode;
+ __u32 mask = event->mask;
+ const char *dname = event->file_name;
struct audit_parent *parent;
- parent = container_of(i_watch, struct audit_parent, wdata);
+ BUG_ON(group != audit_watch_group);
- if (mask & (IN_CREATE|IN_MOVED_TO) && inode)
- audit_update_watch(parent, dname, inode->i_sb->s_dev,
- inode->i_ino, 0);
- else if (mask & (IN_DELETE|IN_MOVED_FROM))
+ parent = audit_find_parent(event->to_tell);
+ if (unlikely(!parent))
+ return 0;
+
+ switch (event->data_type) {
+ case (FSNOTIFY_EVENT_PATH):
+ inode = event->path.dentry->d_inode;
+ break;
+ case (FSNOTIFY_EVENT_INODE):
+ inode = event->inode;
+ break;
+ default:
+ BUG();
+ inode = NULL;
+ break;
+ };
+
+ if (mask & (FS_CREATE|FS_MOVED_TO) && inode)
+ audit_update_watch(parent, dname, inode->i_sb->s_dev, inode->i_ino, 0);
+ else if (mask & (FS_DELETE|FS_MOVED_FROM))
audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
- /* inotify automatically removes the watch and sends IN_IGNORED */
- else if (mask & (IN_DELETE_SELF|IN_UNMOUNT))
+ else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
audit_remove_parent_watches(parent);
- /* inotify does not remove the watch, so remove it manually */
- else if(mask & IN_MOVE_SELF) {
- audit_remove_parent_watches(parent);
- inotify_remove_watch_locked(audit_ih, i_watch);
- } else if (mask & IN_IGNORED)
- put_inotify_watch(i_watch);
+ /* moved put_inotify_watch to freeing mark */
+
+ /* matched the ref taken by audit_find_parent */
+ audit_put_parent(parent);
+
+ return 0;
}
-static const struct inotify_operations audit_inotify_ops = {
- .handle_event = audit_handle_ievent,
- .destroy_watch = audit_free_parent,
+static const struct fsnotify_ops audit_watch_fsnotify_ops = {
+ .should_send_event = audit_watch_should_send_event,
+ .handle_event = audit_watch_handle_event,
+ .free_group_priv = NULL,
+ .freeing_mark = NULL,
+ .free_event_priv = NULL,
};
static int __init audit_watch_init(void)
{
- audit_ih = inotify_init(&audit_inotify_ops);
- if (IS_ERR(audit_ih))
- audit_panic("cannot initialize inotify handle");
+ audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
+ if (IS_ERR(audit_watch_group)) {
+ audit_watch_group = NULL;
+ audit_panic("cannot create audit fsnotify group");
+ }
return 0;
}
-subsys_initcall(audit_watch_init);
+device_initcall(audit_watch_init);
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index ce08041f578d..eb7675499fb5 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -71,6 +71,7 @@ static inline void audit_free_rule(struct audit_entry *e)
{
int i;
struct audit_krule *erule = &e->rule;
+
/* some rules don't have associated watches */
if (erule->watch)
audit_put_watch(erule->watch);
@@ -746,8 +747,7 @@ static inline int audit_dupe_lsm_field(struct audit_field *df,
* rule with the new rule in the filterlist, then free the old rule.
* The rlist element is undefined; list manipulations are handled apart from
* the initial copy. */
-struct audit_entry *audit_dupe_rule(struct audit_krule *old,
- struct audit_watch *watch)
+struct audit_entry *audit_dupe_rule(struct audit_krule *old)
{
u32 fcount = old->field_count;
struct audit_entry *entry;
@@ -769,8 +769,8 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
new->prio = old->prio;
new->buflen = old->buflen;
new->inode_f = old->inode_f;
- new->watch = NULL;
new->field_count = old->field_count;
+
/*
* note that we are OK with not refcounting here; audit_match_tree()
* never dereferences tree and we can't get false positives there
@@ -811,9 +811,9 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old,
}
}
- if (watch) {
- audit_get_watch(watch);
- new->watch = watch;
+ if (old->watch) {
+ audit_get_watch(old->watch);
+ new->watch = old->watch;
}
return entry;
@@ -866,7 +866,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- int h, err;
+ int err;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -889,15 +889,11 @@ static inline int audit_add_rule(struct audit_entry *entry)
if (watch) {
/* audit_filter_mutex is dropped and re-taken during this call */
- err = audit_add_watch(&entry->rule);
+ err = audit_add_watch(&entry->rule, &list);
if (err) {
mutex_unlock(&audit_filter_mutex);
goto error;
}
- /* entry->rule.watch may have changed during audit_add_watch() */
- watch = entry->rule.watch;
- h = audit_hash_ino((u32)audit_watch_inode(watch));
- list = &audit_inode_hash[h];
}
if (tree) {
err = audit_add_tree_rule(&entry->rule);
@@ -949,7 +945,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
struct audit_watch *watch = entry->rule.watch;
struct audit_tree *tree = entry->rule.tree;
struct list_head *list;
- LIST_HEAD(inotify_list);
int ret = 0;
#ifdef CONFIG_AUDITSYSCALL
int dont_count = 0;
@@ -969,7 +964,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
}
if (e->rule.watch)
- audit_remove_watch_rule(&e->rule, &inotify_list);
+ audit_remove_watch_rule(&e->rule);
if (e->rule.tree)
audit_remove_tree_rule(&e->rule);
@@ -987,9 +982,6 @@ static inline int audit_del_rule(struct audit_entry *entry)
#endif
mutex_unlock(&audit_filter_mutex);
- if (!list_empty(&inotify_list))
- audit_inotify_unregister(&inotify_list);
-
out:
if (watch)
audit_put_watch(watch); /* match initial get */
@@ -1323,30 +1315,23 @@ static int update_lsm_rule(struct audit_krule *r)
{
struct audit_entry *entry = container_of(r, struct audit_entry, rule);
struct audit_entry *nentry;
- struct audit_watch *watch;
- struct audit_tree *tree;
int err = 0;
if (!security_audit_rule_known(r))
return 0;
- watch = r->watch;
- tree = r->tree;
- nentry = audit_dupe_rule(r, watch);
+ nentry = audit_dupe_rule(r);
if (IS_ERR(nentry)) {
/* save the first error encountered for the
* return value */
err = PTR_ERR(nentry);
audit_panic("error updating LSM filters");
- if (watch)
+ if (r->watch)
list_del(&r->rlist);
list_del_rcu(&entry->list);
list_del(&r->list);
} else {
- if (watch) {
- list_add(&nentry->rule.rlist, audit_watch_rules(watch));
- list_del(&r->rlist);
- } else if (tree)
+ if (r->watch || r->tree)
list_replace_init(&r->rlist, &nentry->rule.rlist);
list_replace_rcu(&entry->list, &nentry->list);
list_replace(&r->list, &nentry->rule.list);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 3828ad5fb8f1..b87a63beb66c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -65,7 +65,6 @@
#include <linux/binfmts.h>
#include <linux/highmem.h>
#include <linux/syscalls.h>
-#include <linux/inotify.h>
#include <linux/capability.h>
#include <linux/fs_struct.h>
@@ -549,9 +548,8 @@ static int audit_filter_rules(struct task_struct *tsk,
}
break;
case AUDIT_WATCH:
- if (name && audit_watch_inode(rule->watch) != (unsigned long)-1)
- result = (name->dev == audit_watch_dev(rule->watch) &&
- name->ino == audit_watch_inode(rule->watch));
+ if (name)
+ result = audit_watch_compare(rule->watch, name->ino, name->dev);
break;
case AUDIT_DIR:
if (ctx)
@@ -1726,7 +1724,7 @@ static inline void handle_one(const struct inode *inode)
struct audit_tree_refs *p;
struct audit_chunk *chunk;
int count;
- if (likely(list_empty(&inode->inotify_watches)))
+ if (likely(hlist_empty(&inode->i_fsnotify_marks)))
return;
context = current->audit_context;
p = context->trees;
@@ -1769,7 +1767,7 @@ retry:
seq = read_seqbegin(&rename_lock);
for(;;) {
struct inode *inode = d->d_inode;
- if (inode && unlikely(!list_empty(&inode->inotify_watches))) {
+ if (inode && unlikely(!hlist_empty(&inode->i_fsnotify_marks))) {
struct audit_chunk *chunk;
chunk = audit_tree_lookup(inode);
if (chunk) {
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 422cb19f156e..3ac6f5b0a64b 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4598,7 +4598,7 @@ static int alloc_css_id(struct cgroup_subsys *ss, struct cgroup *parent,
parent_css = parent->subsys[subsys_id];
child_css = child->subsys[subsys_id];
parent_id = parent_css->id;
- depth = parent_id->depth;
+ depth = parent_id->depth + 1;
child_id = get_new_cssid(ss, depth);
if (IS_ERR(child_id))
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 8b92539b4754..97d1b426a4ac 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -34,7 +34,7 @@ void cpu_maps_update_done(void)
mutex_unlock(&cpu_add_remove_lock);
}
-static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
+static RAW_NOTIFIER_HEAD(cpu_chain);
/* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
* Should always be manipulated under cpu_add_remove_lock
diff --git a/kernel/debug/kdb/kdb_main.c b/kernel/debug/kdb/kdb_main.c
index b724c791b6d4..5f24758810aa 100644
--- a/kernel/debug/kdb/kdb_main.c
+++ b/kernel/debug/kdb/kdb_main.c
@@ -1818,13 +1818,17 @@ static int kdb_rm(int argc, const char **argv)
*/
static int kdb_sr(int argc, const char **argv)
{
+ int toggle_save;
+
if (argc != 1)
return KDB_ARGCOUNT;
- sysrq_toggle_support(1);
+ toggle_save = sysrq_toggle_support(1);
kdb_trap_printk++;
handle_sysrq(*argv[1], NULL);
kdb_trap_printk--;
+ sysrq_toggle_support(toggle_save);
+
return 0;
}
#endif /* CONFIG_MAGIC_SYSRQ */
@@ -1857,12 +1861,6 @@ static int kdb_ef(int argc, const char **argv)
}
#if defined(CONFIG_MODULES)
-/* modules using other modules */
-struct module_use {
- struct list_head list;
- struct module *module_which_uses;
-};
-
/*
* kdb_lsmod - This function implements the 'lsmod' command. Lists
* currently loaded kernel modules.
@@ -1894,9 +1892,9 @@ static int kdb_lsmod(int argc, const char **argv)
{
struct module_use *use;
kdb_printf(" [ ");
- list_for_each_entry(use, &mod->modules_which_use_me,
- list)
- kdb_printf("%s ", use->module_which_uses->name);
+ list_for_each_entry(use, &mod->source_list,
+ source_list)
+ kdb_printf("%s ", use->target->name);
kdb_printf("]\n");
}
#endif
@@ -2297,6 +2295,9 @@ static int kdb_ll(int argc, const char **argv)
while (va) {
char buf[80];
+ if (KDB_FLAG(CMD_INTERRUPT))
+ return 0;
+
sprintf(buf, "%s " kdb_machreg_fmt "\n", command, va);
diag = kdb_parse(buf);
if (diag)
diff --git a/kernel/exec_domain.c b/kernel/exec_domain.c
index c35452cadded..dd62f8e714ca 100644
--- a/kernel/exec_domain.c
+++ b/kernel/exec_domain.c
@@ -27,7 +27,7 @@ static struct exec_domain *exec_domains = &default_exec_domain;
static DEFINE_RWLOCK(exec_domains_lock);
-static u_long ident_map[32] = {
+static unsigned long ident_map[32] = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
@@ -56,10 +56,10 @@ default_handler(int segment, struct pt_regs *regp)
}
static struct exec_domain *
-lookup_exec_domain(u_long personality)
+lookup_exec_domain(unsigned int personality)
{
- struct exec_domain * ep;
- u_long pers = personality(personality);
+ unsigned int pers = personality(personality);
+ struct exec_domain *ep;
read_lock(&exec_domains_lock);
for (ep = exec_domains; ep; ep = ep->next) {
@@ -70,7 +70,7 @@ lookup_exec_domain(u_long personality)
#ifdef CONFIG_MODULES
read_unlock(&exec_domains_lock);
- request_module("personality-%ld", pers);
+ request_module("personality-%d", pers);
read_lock(&exec_domains_lock);
for (ep = exec_domains; ep; ep = ep->next) {
@@ -135,7 +135,7 @@ unregister:
}
int
-__set_personality(u_long personality)
+__set_personality(unsigned int personality)
{
struct exec_domain *ep, *oep;
@@ -188,9 +188,9 @@ static int __init proc_execdomains_init(void)
module_init(proc_execdomains_init);
#endif
-SYSCALL_DEFINE1(personality, u_long, personality)
+SYSCALL_DEFINE1(personality, unsigned int, personality)
{
- u_long old = current->personality;
+ unsigned int old = current->personality;
if (personality != 0xffffffff) {
set_personality(personality);
@@ -198,7 +198,7 @@ SYSCALL_DEFINE1(personality, u_long, personality)
return -EINVAL;
}
- return (long)old;
+ return old;
}
diff --git a/kernel/module.c b/kernel/module.c
index 333fbcc96978..48c065c92691 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1,6 +1,6 @@
/*
Copyright (C) 2002 Richard Henderson
- Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
+ Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -72,7 +72,11 @@
/* If this is set, the section belongs in the init part of the module */
#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
-/* List of modules, protected by module_mutex or preempt_disable
+/*
+ * Mutex protects:
+ * 1) List of modules (also safely readable with preempt_disable),
+ * 2) module_use links,
+ * 3) module_addr_min/module_addr_max.
* (delete uses stop_machine/add uses RCU list operations). */
DEFINE_MUTEX(module_mutex);
EXPORT_SYMBOL_GPL(module_mutex);
@@ -90,7 +94,8 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq);
static BLOCKING_NOTIFIER_HEAD(module_notify_list);
-/* Bounds of module allocation, for speeding __module_address */
+/* Bounds of module allocation, for speeding __module_address.
+ * Protected by module_mutex. */
static unsigned long module_addr_min = -1UL, module_addr_max = 0;
int register_module_notifier(struct notifier_block * nb)
@@ -105,6 +110,18 @@ int unregister_module_notifier(struct notifier_block * nb)
}
EXPORT_SYMBOL(unregister_module_notifier);
+struct load_info {
+ Elf_Ehdr *hdr;
+ unsigned long len;
+ Elf_Shdr *sechdrs;
+ char *secstrings, *strtab;
+ unsigned long *strmap;
+ unsigned long symoffs, stroffs;
+ struct {
+ unsigned int sym, str, mod, vers, info, pcpu;
+ } index;
+};
+
/* We require a truly strong try_module_get(): 0 means failure due to
ongoing or failed initialization etc. */
static inline int strong_try_module_get(struct module *mod)
@@ -135,42 +152,38 @@ void __module_put_and_exit(struct module *mod, long code)
EXPORT_SYMBOL(__module_put_and_exit);
/* Find a module section: 0 means not found. */
-static unsigned int find_sec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings,
- const char *name)
+static unsigned int find_sec(const struct load_info *info, const char *name)
{
unsigned int i;
- for (i = 1; i < hdr->e_shnum; i++)
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
/* Alloc bit cleared means "ignore it." */
- if ((sechdrs[i].sh_flags & SHF_ALLOC)
- && strcmp(secstrings+sechdrs[i].sh_name, name) == 0)
+ if ((shdr->sh_flags & SHF_ALLOC)
+ && strcmp(info->secstrings + shdr->sh_name, name) == 0)
return i;
+ }
return 0;
}
/* Find a module section, or NULL. */
-static void *section_addr(Elf_Ehdr *hdr, Elf_Shdr *shdrs,
- const char *secstrings, const char *name)
+static void *section_addr(const struct load_info *info, const char *name)
{
/* Section 0 has sh_addr 0. */
- return (void *)shdrs[find_sec(hdr, shdrs, secstrings, name)].sh_addr;
+ return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
}
/* Find a module section, or NULL. Fill in number of "objects" in section. */
-static void *section_objs(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings,
+static void *section_objs(const struct load_info *info,
const char *name,
size_t object_size,
unsigned int *num)
{
- unsigned int sec = find_sec(hdr, sechdrs, secstrings, name);
+ unsigned int sec = find_sec(info, name);
/* Section 0 has sh_addr 0 and sh_size 0. */
- *num = sechdrs[sec].sh_size / object_size;
- return (void *)sechdrs[sec].sh_addr;
+ *num = info->sechdrs[sec].sh_size / object_size;
+ return (void *)info->sechdrs[sec].sh_addr;
}
/* Provided by the linker */
@@ -222,7 +235,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
unsigned int symnum, void *data), void *data)
{
struct module *mod;
- const struct symsearch arr[] = {
+ static const struct symsearch arr[] = {
{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
NOT_GPL_ONLY, false },
{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
@@ -329,7 +342,7 @@ static bool find_symbol_in_section(const struct symsearch *syms,
}
/* Find a symbol and return it, along with, (optional) crc and
- * (optional) module which owns it */
+ * (optional) module which owns it. Needs preempt disabled or module_mutex. */
const struct kernel_symbol *find_symbol(const char *name,
struct module **owner,
const unsigned long **crc,
@@ -387,7 +400,8 @@ static int percpu_modalloc(struct module *mod,
mod->percpu = __alloc_reserved_percpu(size, align);
if (!mod->percpu) {
printk(KERN_WARNING
- "Could not allocate %lu bytes percpu data\n", size);
+ "%s: Could not allocate %lu bytes percpu data\n",
+ mod->name, size);
return -ENOMEM;
}
mod->percpu_size = size;
@@ -399,11 +413,9 @@ static void percpu_modfree(struct module *mod)
free_percpu(mod->percpu);
}
-static unsigned int find_pcpusec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static unsigned int find_pcpusec(struct load_info *info)
{
- return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
+ return find_sec(info, ".data..percpu");
}
static void percpu_modcopy(struct module *mod,
@@ -463,9 +475,7 @@ static inline int percpu_modalloc(struct module *mod,
static inline void percpu_modfree(struct module *mod)
{
}
-static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static unsigned int find_pcpusec(struct load_info *info)
{
return 0;
}
@@ -519,36 +529,30 @@ static char last_unloaded_module[MODULE_NAME_LEN+1];
EXPORT_TRACEPOINT_SYMBOL(module_get);
/* Init the unload section of the module. */
-static void module_unload_init(struct module *mod)
+static int module_unload_init(struct module *mod)
{
- int cpu;
+ mod->refptr = alloc_percpu(struct module_ref);
+ if (!mod->refptr)
+ return -ENOMEM;
- INIT_LIST_HEAD(&mod->modules_which_use_me);
- for_each_possible_cpu(cpu) {
- per_cpu_ptr(mod->refptr, cpu)->incs = 0;
- per_cpu_ptr(mod->refptr, cpu)->decs = 0;
- }
+ INIT_LIST_HEAD(&mod->source_list);
+ INIT_LIST_HEAD(&mod->target_list);
/* Hold reference count during initialization. */
__this_cpu_write(mod->refptr->incs, 1);
/* Backwards compatibility macros put refcount during init. */
mod->waiter = current;
-}
-/* modules using other modules */
-struct module_use
-{
- struct list_head list;
- struct module *module_which_uses;
-};
+ return 0;
+}
/* Does a already use b? */
static int already_uses(struct module *a, struct module *b)
{
struct module_use *use;
- list_for_each_entry(use, &b->modules_which_use_me, list) {
- if (use->module_which_uses == a) {
+ list_for_each_entry(use, &b->source_list, source_list) {
+ if (use->source == a) {
DEBUGP("%s uses %s!\n", a->name, b->name);
return 1;
}
@@ -557,62 +561,70 @@ static int already_uses(struct module *a, struct module *b)
return 0;
}
-/* Module a uses b */
-int use_module(struct module *a, struct module *b)
+/*
+ * Module a uses b
+ * - we add 'a' as a "source", 'b' as a "target" of module use
+ * - the module_use is added to the list of 'b' sources (so
+ * 'b' can walk the list to see who sourced them), and of 'a'
+ * targets (so 'a' can see what modules it targets).
+ */
+static int add_module_usage(struct module *a, struct module *b)
{
struct module_use *use;
- int no_warn, err;
- if (b == NULL || already_uses(a, b)) return 1;
+ DEBUGP("Allocating new usage for %s.\n", a->name);
+ use = kmalloc(sizeof(*use), GFP_ATOMIC);
+ if (!use) {
+ printk(KERN_WARNING "%s: out of memory loading\n", a->name);
+ return -ENOMEM;
+ }
+
+ use->source = a;
+ use->target = b;
+ list_add(&use->source_list, &b->source_list);
+ list_add(&use->target_list, &a->target_list);
+ return 0;
+}
+
+/* Module a uses b: caller needs module_mutex() */
+int ref_module(struct module *a, struct module *b)
+{
+ int err;
- /* If we're interrupted or time out, we fail. */
- if (wait_event_interruptible_timeout(
- module_wq, (err = strong_try_module_get(b)) != -EBUSY,
- 30 * HZ) <= 0) {
- printk("%s: gave up waiting for init of module %s.\n",
- a->name, b->name);
+ if (b == NULL || already_uses(a, b))
return 0;
- }
- /* If strong_try_module_get() returned a different error, we fail. */
+ /* If module isn't available, we fail. */
+ err = strong_try_module_get(b);
if (err)
- return 0;
+ return err;
- DEBUGP("Allocating new usage for %s.\n", a->name);
- use = kmalloc(sizeof(*use), GFP_ATOMIC);
- if (!use) {
- printk("%s: out of memory loading\n", a->name);
+ err = add_module_usage(a, b);
+ if (err) {
module_put(b);
- return 0;
+ return err;
}
-
- use->module_which_uses = a;
- list_add(&use->list, &b->modules_which_use_me);
- no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
- return 1;
+ return 0;
}
-EXPORT_SYMBOL_GPL(use_module);
+EXPORT_SYMBOL_GPL(ref_module);
/* Clear the unload stuff of the module. */
static void module_unload_free(struct module *mod)
{
- struct module *i;
+ struct module_use *use, *tmp;
- list_for_each_entry(i, &modules, list) {
- struct module_use *use;
-
- list_for_each_entry(use, &i->modules_which_use_me, list) {
- if (use->module_which_uses == mod) {
- DEBUGP("%s unusing %s\n", mod->name, i->name);
- module_put(i);
- list_del(&use->list);
- kfree(use);
- sysfs_remove_link(i->holders_dir, mod->name);
- /* There can be at most one match. */
- break;
- }
- }
+ mutex_lock(&module_mutex);
+ list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
+ struct module *i = use->target;
+ DEBUGP("%s unusing %s\n", mod->name, i->name);
+ module_put(i);
+ list_del(&use->source_list);
+ list_del(&use->target_list);
+ kfree(use);
}
+ mutex_unlock(&module_mutex);
+
+ free_percpu(mod->refptr);
}
#ifdef CONFIG_MODULE_FORCE_UNLOAD
@@ -735,7 +747,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
goto out;
}
- if (!list_empty(&mod->modules_which_use_me)) {
+ if (!list_empty(&mod->source_list)) {
/* Other modules depend on us: get rid of them first. */
ret = -EWOULDBLOCK;
goto out;
@@ -779,13 +791,14 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
async_synchronize_full();
- mutex_lock(&module_mutex);
+
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
ddebug_remove_module(mod->name);
- free_module(mod);
- out:
+ free_module(mod);
+ return 0;
+out:
mutex_unlock(&module_mutex);
return ret;
}
@@ -799,9 +812,9 @@ static inline void print_unload_info(struct seq_file *m, struct module *mod)
/* Always include a trailing , so userspace can differentiate
between this and the old multi-field proc format. */
- list_for_each_entry(use, &mod->modules_which_use_me, list) {
+ list_for_each_entry(use, &mod->source_list, source_list) {
printed_something = 1;
- seq_printf(m, "%s,", use->module_which_uses->name);
+ seq_printf(m, "%s,", use->source->name);
}
if (mod->init != NULL && mod->exit == NULL) {
@@ -880,14 +893,15 @@ static inline void module_unload_free(struct module *mod)
{
}
-int use_module(struct module *a, struct module *b)
+int ref_module(struct module *a, struct module *b)
{
- return strong_try_module_get(b) == 0;
+ return strong_try_module_get(b);
}
-EXPORT_SYMBOL_GPL(use_module);
+EXPORT_SYMBOL_GPL(ref_module);
-static inline void module_unload_init(struct module *mod)
+static inline int module_unload_init(struct module *mod)
{
+ return 0;
}
#endif /* CONFIG_MODULE_UNLOAD */
@@ -1001,6 +1015,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
{
const unsigned long *crc;
+ /* Since this should be found in kernel (which can't be removed),
+ * no locking is necessary. */
if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL,
&crc, true, false))
BUG();
@@ -1043,35 +1059,68 @@ static inline int same_magic(const char *amagic, const char *bmagic,
}
#endif /* CONFIG_MODVERSIONS */
-/* Resolve a symbol for this module. I.e. if we find one, record usage.
- Must be holding module_mutex. */
-static const struct kernel_symbol *resolve_symbol(Elf_Shdr *sechdrs,
- unsigned int versindex,
+/* Resolve a symbol for this module. I.e. if we find one, record usage. */
+static const struct kernel_symbol *resolve_symbol(struct module *mod,
+ const struct load_info *info,
const char *name,
- struct module *mod)
+ char ownername[])
{
struct module *owner;
const struct kernel_symbol *sym;
const unsigned long *crc;
+ int err;
+ mutex_lock(&module_mutex);
sym = find_symbol(name, &owner, &crc,
!(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
- /* use_module can fail due to OOM,
- or module initialization or unloading */
- if (sym) {
- if (!check_version(sechdrs, versindex, name, mod, crc, owner)
- || !use_module(mod, owner))
- sym = NULL;
+ if (!sym)
+ goto unlock;
+
+ if (!check_version(info->sechdrs, info->index.vers, name, mod, crc,
+ owner)) {
+ sym = ERR_PTR(-EINVAL);
+ goto getname;
}
+
+ err = ref_module(mod, owner);
+ if (err) {
+ sym = ERR_PTR(err);
+ goto getname;
+ }
+
+getname:
+ /* We must make copy under the lock if we failed to get ref. */
+ strncpy(ownername, module_name(owner), MODULE_NAME_LEN);
+unlock:
+ mutex_unlock(&module_mutex);
return sym;
}
+static const struct kernel_symbol *
+resolve_symbol_wait(struct module *mod,
+ const struct load_info *info,
+ const char *name)
+{
+ const struct kernel_symbol *ksym;
+ char owner[MODULE_NAME_LEN];
+
+ if (wait_event_interruptible_timeout(module_wq,
+ !IS_ERR(ksym = resolve_symbol(mod, info, name, owner))
+ || PTR_ERR(ksym) != -EBUSY,
+ 30 * HZ) <= 0) {
+ printk(KERN_WARNING "%s: gave up waiting for init of module %s.\n",
+ mod->name, owner);
+ }
+ return ksym;
+}
+
/*
* /sys/module/foo/sections stuff
* J. Corbet <corbet@lwn.net>
*/
-#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+#ifdef CONFIG_SYSFS
+#ifdef CONFIG_KALLSYMS
static inline bool sect_empty(const Elf_Shdr *sect)
{
return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
@@ -1108,8 +1157,7 @@ static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
kfree(sect_attrs);
}
-static void add_sect_attrs(struct module *mod, unsigned int nsect,
- char *secstrings, Elf_Shdr *sechdrs)
+static void add_sect_attrs(struct module *mod, const struct load_info *info)
{
unsigned int nloaded = 0, i, size[2];
struct module_sect_attrs *sect_attrs;
@@ -1117,8 +1165,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
struct attribute **gattr;
/* Count loaded sections and allocate structures */
- for (i = 0; i < nsect; i++)
- if (!sect_empty(&sechdrs[i]))
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ if (!sect_empty(&info->sechdrs[i]))
nloaded++;
size[0] = ALIGN(sizeof(*sect_attrs)
+ nloaded * sizeof(sect_attrs->attrs[0]),
@@ -1135,11 +1183,12 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
sect_attrs->nsections = 0;
sattr = &sect_attrs->attrs[0];
gattr = &sect_attrs->grp.attrs[0];
- for (i = 0; i < nsect; i++) {
- if (sect_empty(&sechdrs[i]))
+ for (i = 0; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *sec = &info->sechdrs[i];
+ if (sect_empty(sec))
continue;
- sattr->address = sechdrs[i].sh_addr;
- sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+ sattr->address = sec->sh_addr;
+ sattr->name = kstrdup(info->secstrings + sec->sh_name,
GFP_KERNEL);
if (sattr->name == NULL)
goto out;
@@ -1207,8 +1256,7 @@ static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
kfree(notes_attrs);
}
-static void add_notes_attrs(struct module *mod, unsigned int nsect,
- char *secstrings, Elf_Shdr *sechdrs)
+static void add_notes_attrs(struct module *mod, const struct load_info *info)
{
unsigned int notes, loaded, i;
struct module_notes_attrs *notes_attrs;
@@ -1220,9 +1268,9 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
/* Count notes sections and allocate structures. */
notes = 0;
- for (i = 0; i < nsect; i++)
- if (!sect_empty(&sechdrs[i]) &&
- (sechdrs[i].sh_type == SHT_NOTE))
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ if (!sect_empty(&info->sechdrs[i]) &&
+ (info->sechdrs[i].sh_type == SHT_NOTE))
++notes;
if (notes == 0)
@@ -1236,15 +1284,15 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
notes_attrs->notes = notes;
nattr = &notes_attrs->attrs[0];
- for (loaded = i = 0; i < nsect; ++i) {
- if (sect_empty(&sechdrs[i]))
+ for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
+ if (sect_empty(&info->sechdrs[i]))
continue;
- if (sechdrs[i].sh_type == SHT_NOTE) {
+ if (info->sechdrs[i].sh_type == SHT_NOTE) {
sysfs_bin_attr_init(nattr);
nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
nattr->attr.mode = S_IRUGO;
- nattr->size = sechdrs[i].sh_size;
- nattr->private = (void *) sechdrs[i].sh_addr;
+ nattr->size = info->sechdrs[i].sh_size;
+ nattr->private = (void *) info->sechdrs[i].sh_addr;
nattr->read = module_notes_read;
++nattr;
}
@@ -1275,8 +1323,8 @@ static void remove_notes_attrs(struct module *mod)
#else
-static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
- char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_sect_attrs(struct module *mod,
+ const struct load_info *info)
{
}
@@ -1284,18 +1332,44 @@ static inline void remove_sect_attrs(struct module *mod)
{
}
-static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
- char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_notes_attrs(struct module *mod,
+ const struct load_info *info)
{
}
static inline void remove_notes_attrs(struct module *mod)
{
}
+#endif /* CONFIG_KALLSYMS */
+
+static void add_usage_links(struct module *mod)
+{
+#ifdef CONFIG_MODULE_UNLOAD
+ struct module_use *use;
+ int nowarn;
+
+ mutex_lock(&module_mutex);
+ list_for_each_entry(use, &mod->target_list, target_list) {
+ nowarn = sysfs_create_link(use->target->holders_dir,
+ &mod->mkobj.kobj, mod->name);
+ }
+ mutex_unlock(&module_mutex);
#endif
+}
-#ifdef CONFIG_SYSFS
-int module_add_modinfo_attrs(struct module *mod)
+static void del_usage_links(struct module *mod)
+{
+#ifdef CONFIG_MODULE_UNLOAD
+ struct module_use *use;
+
+ mutex_lock(&module_mutex);
+ list_for_each_entry(use, &mod->target_list, target_list)
+ sysfs_remove_link(use->target->holders_dir, mod->name);
+ mutex_unlock(&module_mutex);
+#endif
+}
+
+static int module_add_modinfo_attrs(struct module *mod)
{
struct module_attribute *attr;
struct module_attribute *temp_attr;
@@ -1321,7 +1395,7 @@ int module_add_modinfo_attrs(struct module *mod)
return error;
}
-void module_remove_modinfo_attrs(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod)
{
struct module_attribute *attr;
int i;
@@ -1337,7 +1411,7 @@ void module_remove_modinfo_attrs(struct module *mod)
kfree(mod->modinfo_attrs);
}
-int mod_sysfs_init(struct module *mod)
+static int mod_sysfs_init(struct module *mod)
{
int err;
struct kobject *kobj;
@@ -1371,12 +1445,17 @@ out:
return err;
}
-int mod_sysfs_setup(struct module *mod,
+static int mod_sysfs_setup(struct module *mod,
+ const struct load_info *info,
struct kernel_param *kparam,
unsigned int num_params)
{
int err;
+ err = mod_sysfs_init(mod);
+ if (err)
+ goto out;
+
mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
if (!mod->holders_dir) {
err = -ENOMEM;
@@ -1391,6 +1470,10 @@ int mod_sysfs_setup(struct module *mod,
if (err)
goto out_unreg_param;
+ add_usage_links(mod);
+ add_sect_attrs(mod, info);
+ add_notes_attrs(mod, info);
+
kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
return 0;
@@ -1400,24 +1483,44 @@ out_unreg_holders:
kobject_put(mod->holders_dir);
out_unreg:
kobject_put(&mod->mkobj.kobj);
+out:
return err;
}
static void mod_sysfs_fini(struct module *mod)
{
+ remove_notes_attrs(mod);
+ remove_sect_attrs(mod);
kobject_put(&mod->mkobj.kobj);
}
-#else /* CONFIG_SYSFS */
+#else /* !CONFIG_SYSFS */
+
+static int mod_sysfs_setup(struct module *mod,
+ const struct load_info *info,
+ struct kernel_param *kparam,
+ unsigned int num_params)
+{
+ return 0;
+}
static void mod_sysfs_fini(struct module *mod)
{
}
+static void module_remove_modinfo_attrs(struct module *mod)
+{
+}
+
+static void del_usage_links(struct module *mod)
+{
+}
+
#endif /* CONFIG_SYSFS */
-static void mod_kobject_remove(struct module *mod)
+static void mod_sysfs_teardown(struct module *mod)
{
+ del_usage_links(mod);
module_remove_modinfo_attrs(mod);
module_param_sysfs_remove(mod);
kobject_put(mod->mkobj.drivers_dir);
@@ -1436,16 +1539,16 @@ static int __unlink_module(void *_mod)
return 0;
}
-/* Free a module, remove from lists, etc (must hold module_mutex). */
+/* Free a module, remove from lists, etc. */
static void free_module(struct module *mod)
{
trace_module_free(mod);
/* Delete from various lists */
+ mutex_lock(&module_mutex);
stop_machine(__unlink_module, mod, NULL);
- remove_notes_attrs(mod);
- remove_sect_attrs(mod);
- mod_kobject_remove(mod);
+ mutex_unlock(&module_mutex);
+ mod_sysfs_teardown(mod);
/* Arch-specific cleanup. */
module_arch_cleanup(mod);
@@ -1460,10 +1563,7 @@ static void free_module(struct module *mod)
module_free(mod, mod->module_init);
kfree(mod->args);
percpu_modfree(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
- if (mod->refptr)
- free_percpu(mod->refptr);
-#endif
+
/* Free lock-classes: */
lockdep_free_key_range(mod->module_core, mod->core_size);
@@ -1493,6 +1593,8 @@ EXPORT_SYMBOL_GPL(__symbol_get);
/*
* Ensure that an exported symbol [global namespace] does not already exist
* in the kernel or in some other module's exported symbol table.
+ *
+ * You must hold the module_mutex.
*/
static int verify_export_symbols(struct module *mod)
{
@@ -1527,25 +1629,23 @@ static int verify_export_symbols(struct module *mod)
}
/* Change all symbols so that st_value encodes the pointer directly. */
-static int simplify_symbols(Elf_Shdr *sechdrs,
- unsigned int symindex,
- const char *strtab,
- unsigned int versindex,
- unsigned int pcpuindex,
- struct module *mod)
-{
- Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
+static int simplify_symbols(struct module *mod, const struct load_info *info)
+{
+ Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
+ Elf_Sym *sym = (void *)symsec->sh_addr;
unsigned long secbase;
- unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
+ unsigned int i;
int ret = 0;
const struct kernel_symbol *ksym;
- for (i = 1; i < n; i++) {
+ for (i = 1; i < symsec->sh_size / sizeof(Elf_Sym); i++) {
+ const char *name = info->strtab + sym[i].st_name;
+
switch (sym[i].st_shndx) {
case SHN_COMMON:
/* We compiled with -fno-common. These are not
supposed to happen. */
- DEBUGP("Common symbol: %s\n", strtab + sym[i].st_name);
+ DEBUGP("Common symbol: %s\n", name);
printk("%s: please compile with -fno-common\n",
mod->name);
ret = -ENOEXEC;
@@ -1558,29 +1658,28 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
break;
case SHN_UNDEF:
- ksym = resolve_symbol(sechdrs, versindex,
- strtab + sym[i].st_name, mod);
+ ksym = resolve_symbol_wait(mod, info, name);
/* Ok if resolved. */
- if (ksym) {
+ if (ksym && !IS_ERR(ksym)) {
sym[i].st_value = ksym->value;
break;
}
/* Ok if weak. */
- if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
+ if (!ksym && ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
break;
- printk(KERN_WARNING "%s: Unknown symbol %s\n",
- mod->name, strtab + sym[i].st_name);
- ret = -ENOENT;
+ printk(KERN_WARNING "%s: Unknown symbol %s (err %li)\n",
+ mod->name, name, PTR_ERR(ksym));
+ ret = PTR_ERR(ksym) ?: -ENOENT;
break;
default:
/* Divert to percpu allocation if a percpu var. */
- if (sym[i].st_shndx == pcpuindex)
+ if (sym[i].st_shndx == info->index.pcpu)
secbase = (unsigned long)mod_percpu(mod);
else
- secbase = sechdrs[sym[i].st_shndx].sh_addr;
+ secbase = info->sechdrs[sym[i].st_shndx].sh_addr;
sym[i].st_value += secbase;
break;
}
@@ -1589,6 +1688,35 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
return ret;
}
+static int apply_relocations(struct module *mod, const struct load_info *info)
+{
+ unsigned int i;
+ int err = 0;
+
+ /* Now do relocations. */
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ unsigned int infosec = info->sechdrs[i].sh_info;
+
+ /* Not a valid relocation section? */
+ if (infosec >= info->hdr->e_shnum)
+ continue;
+
+ /* Don't bother with non-allocated sections */
+ if (!(info->sechdrs[infosec].sh_flags & SHF_ALLOC))
+ continue;
+
+ if (info->sechdrs[i].sh_type == SHT_REL)
+ err = apply_relocate(info->sechdrs, info->strtab,
+ info->index.sym, i, mod);
+ else if (info->sechdrs[i].sh_type == SHT_RELA)
+ err = apply_relocate_add(info->sechdrs, info->strtab,
+ info->index.sym, i, mod);
+ if (err < 0)
+ break;
+ }
+ return err;
+}
+
/* Additional bytes needed by arch in front of individual sections */
unsigned int __weak arch_mod_section_prepend(struct module *mod,
unsigned int section)
@@ -1613,10 +1741,7 @@ static long get_offset(struct module *mod, unsigned int *size,
might -- code, read-only data, read-write data, small data. Tally
sizes, and place the offsets into sh_entsize fields: high bit means it
belongs in init. */
-static void layout_sections(struct module *mod,
- const Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs,
- const char *secstrings)
+static void layout_sections(struct module *mod, struct load_info *info)
{
static unsigned long const masks[][2] = {
/* NOTE: all executable code must be the first section
@@ -1629,21 +1754,22 @@ static void layout_sections(struct module *mod,
};
unsigned int m, i;
- for (i = 0; i < hdr->e_shnum; i++)
- sechdrs[i].sh_entsize = ~0UL;
+ for (i = 0; i < info->hdr->e_shnum; i++)
+ info->sechdrs[i].sh_entsize = ~0UL;
DEBUGP("Core section allocation order:\n");
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
- for (i = 0; i < hdr->e_shnum; ++i) {
- Elf_Shdr *s = &sechdrs[i];
+ for (i = 0; i < info->hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &info->sechdrs[i];
+ const char *sname = info->secstrings + s->sh_name;
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL
- || strstarts(secstrings + s->sh_name, ".init"))
+ || strstarts(sname, ".init"))
continue;
s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
- DEBUGP("\t%s\n", secstrings + s->sh_name);
+ DEBUGP("\t%s\n", name);
}
if (m == 0)
mod->core_text_size = mod->core_size;
@@ -1651,17 +1777,18 @@ static void layout_sections(struct module *mod,
DEBUGP("Init section allocation order:\n");
for (m = 0; m < ARRAY_SIZE(masks); ++m) {
- for (i = 0; i < hdr->e_shnum; ++i) {
- Elf_Shdr *s = &sechdrs[i];
+ for (i = 0; i < info->hdr->e_shnum; ++i) {
+ Elf_Shdr *s = &info->sechdrs[i];
+ const char *sname = info->secstrings + s->sh_name;
if ((s->sh_flags & masks[m][0]) != masks[m][0]
|| (s->sh_flags & masks[m][1])
|| s->sh_entsize != ~0UL
- || !strstarts(secstrings + s->sh_name, ".init"))
+ || !strstarts(sname, ".init"))
continue;
s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
| INIT_OFFSET_MASK);
- DEBUGP("\t%s\n", secstrings + s->sh_name);
+ DEBUGP("\t%s\n", sname);
}
if (m == 0)
mod->init_text_size = mod->init_size;
@@ -1700,33 +1827,28 @@ static char *next_string(char *string, unsigned long *secsize)
return string;
}
-static char *get_modinfo(Elf_Shdr *sechdrs,
- unsigned int info,
- const char *tag)
+static char *get_modinfo(struct load_info *info, const char *tag)
{
char *p;
unsigned int taglen = strlen(tag);
- unsigned long size = sechdrs[info].sh_size;
+ Elf_Shdr *infosec = &info->sechdrs[info->index.info];
+ unsigned long size = infosec->sh_size;
- for (p = (char *)sechdrs[info].sh_addr; p; p = next_string(p, &size)) {
+ for (p = (char *)infosec->sh_addr; p; p = next_string(p, &size)) {
if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=')
return p + taglen + 1;
}
return NULL;
}
-static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
- unsigned int infoindex)
+static void setup_modinfo(struct module *mod, struct load_info *info)
{
struct module_attribute *attr;
int i;
for (i = 0; (attr = modinfo_attrs[i]); i++) {
if (attr->setup)
- attr->setup(mod,
- get_modinfo(sechdrs,
- infoindex,
- attr->attr.name));
+ attr->setup(mod, get_modinfo(info, attr->attr.name));
}
}
@@ -1767,11 +1889,10 @@ static int is_exported(const char *name, unsigned long value,
}
/* As per nm */
-static char elf_type(const Elf_Sym *sym,
- Elf_Shdr *sechdrs,
- const char *secstrings,
- struct module *mod)
+static char elf_type(const Elf_Sym *sym, const struct load_info *info)
{
+ const Elf_Shdr *sechdrs = info->sechdrs;
+
if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
return 'v';
@@ -1801,8 +1922,10 @@ static char elf_type(const Elf_Sym *sym,
else
return 'b';
}
- if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))
+ if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
+ ".debug")) {
return 'n';
+ }
return '?';
}
@@ -1827,205 +1950,149 @@ static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
return true;
}
-static unsigned long layout_symtab(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int symindex,
- unsigned int strindex,
- const Elf_Ehdr *hdr,
- const char *secstrings,
- unsigned long *pstroffs,
- unsigned long *strmap)
+static void layout_symtab(struct module *mod, struct load_info *info)
{
- unsigned long symoffs;
- Elf_Shdr *symsect = sechdrs + symindex;
- Elf_Shdr *strsect = sechdrs + strindex;
+ Elf_Shdr *symsect = info->sechdrs + info->index.sym;
+ Elf_Shdr *strsect = info->sechdrs + info->index.str;
const Elf_Sym *src;
- const char *strtab;
unsigned int i, nsrc, ndst;
/* Put symbol section at end of init part of module. */
symsect->sh_flags |= SHF_ALLOC;
symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
- symindex) | INIT_OFFSET_MASK;
- DEBUGP("\t%s\n", secstrings + symsect->sh_name);
+ info->index.sym) | INIT_OFFSET_MASK;
+ DEBUGP("\t%s\n", info->secstrings + symsect->sh_name);
- src = (void *)hdr + symsect->sh_offset;
+ src = (void *)info->hdr + symsect->sh_offset;
nsrc = symsect->sh_size / sizeof(*src);
- strtab = (void *)hdr + strsect->sh_offset;
for (ndst = i = 1; i < nsrc; ++i, ++src)
- if (is_core_symbol(src, sechdrs, hdr->e_shnum)) {
+ if (is_core_symbol(src, info->sechdrs, info->hdr->e_shnum)) {
unsigned int j = src->st_name;
- while(!__test_and_set_bit(j, strmap) && strtab[j])
+ while (!__test_and_set_bit(j, info->strmap)
+ && info->strtab[j])
++j;
++ndst;
}
/* Append room for core symbols at end of core part. */
- symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
- mod->core_size = symoffs + ndst * sizeof(Elf_Sym);
+ info->symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
+ mod->core_size = info->symoffs + ndst * sizeof(Elf_Sym);
/* Put string table section at end of init part of module. */
strsect->sh_flags |= SHF_ALLOC;
strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
- strindex) | INIT_OFFSET_MASK;
- DEBUGP("\t%s\n", secstrings + strsect->sh_name);
+ info->index.str) | INIT_OFFSET_MASK;
+ DEBUGP("\t%s\n", info->secstrings + strsect->sh_name);
/* Append room for core symbols' strings at end of core part. */
- *pstroffs = mod->core_size;
- __set_bit(0, strmap);
- mod->core_size += bitmap_weight(strmap, strsect->sh_size);
-
- return symoffs;
+ info->stroffs = mod->core_size;
+ __set_bit(0, info->strmap);
+ mod->core_size += bitmap_weight(info->strmap, strsect->sh_size);
}
-static void add_kallsyms(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int shnum,
- unsigned int symindex,
- unsigned int strindex,
- unsigned long symoffs,
- unsigned long stroffs,
- const char *secstrings,
- unsigned long *strmap)
+static void add_kallsyms(struct module *mod, const struct load_info *info)
{
unsigned int i, ndst;
const Elf_Sym *src;
Elf_Sym *dst;
char *s;
+ Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
- mod->symtab = (void *)sechdrs[symindex].sh_addr;
- mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
- mod->strtab = (void *)sechdrs[strindex].sh_addr;
+ mod->symtab = (void *)symsec->sh_addr;
+ mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+ mod->strtab = info->strtab;
/* Set types up while we still have access to sections. */
for (i = 0; i < mod->num_symtab; i++)
- mod->symtab[i].st_info
- = elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
+ mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
- mod->core_symtab = dst = mod->module_core + symoffs;
+ mod->core_symtab = dst = mod->module_core + info->symoffs;
src = mod->symtab;
*dst = *src;
for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
- if (!is_core_symbol(src, sechdrs, shnum))
+ if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
continue;
dst[ndst] = *src;
- dst[ndst].st_name = bitmap_weight(strmap, dst[ndst].st_name);
+ dst[ndst].st_name = bitmap_weight(info->strmap,
+ dst[ndst].st_name);
++ndst;
}
mod->core_num_syms = ndst;
- mod->core_strtab = s = mod->module_core + stroffs;
- for (*s = 0, i = 1; i < sechdrs[strindex].sh_size; ++i)
- if (test_bit(i, strmap))
+ mod->core_strtab = s = mod->module_core + info->stroffs;
+ for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i)
+ if (test_bit(i, info->strmap))
*++s = mod->strtab[i];
}
#else
-static inline unsigned long layout_symtab(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int symindex,
- unsigned int strindex,
- const Elf_Ehdr *hdr,
- const char *secstrings,
- unsigned long *pstroffs,
- unsigned long *strmap)
+static inline void layout_symtab(struct module *mod, struct load_info *info)
{
- return 0;
}
-static inline void add_kallsyms(struct module *mod,
- Elf_Shdr *sechdrs,
- unsigned int shnum,
- unsigned int symindex,
- unsigned int strindex,
- unsigned long symoffs,
- unsigned long stroffs,
- const char *secstrings,
- const unsigned long *strmap)
+static void add_kallsyms(struct module *mod, const struct load_info *info)
{
}
#endif /* CONFIG_KALLSYMS */
-static void dynamic_debug_setup(struct _ddebug *debug, unsigned int num)
-{
-#ifdef CONFIG_DYNAMIC_DEBUG
- if (ddebug_add_module(debug, num, debug->modname))
- printk(KERN_ERR "dynamic debug error adding module: %s\n",
- debug->modname);
-#endif
-}
-
static void *module_alloc_update_bounds(unsigned long size)
{
void *ret = module_alloc(size);
if (ret) {
+ mutex_lock(&module_mutex);
/* Update module bounds. */
if ((unsigned long)ret < module_addr_min)
module_addr_min = (unsigned long)ret;
if ((unsigned long)ret + size > module_addr_max)
module_addr_max = (unsigned long)ret + size;
+ mutex_unlock(&module_mutex);
}
return ret;
}
#ifdef CONFIG_DEBUG_KMEMLEAK
-static void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs, char *secstrings)
+static void kmemleak_load_module(const struct module *mod,
+ const struct load_info *info)
{
unsigned int i;
/* only scan the sections containing data */
kmemleak_scan_area(mod, sizeof(struct module), GFP_KERNEL);
- for (i = 1; i < hdr->e_shnum; i++) {
- if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ const char *name = info->secstrings + info->sechdrs[i].sh_name;
+ if (!(info->sechdrs[i].sh_flags & SHF_ALLOC))
continue;
- if (strncmp(secstrings + sechdrs[i].sh_name, ".data", 5) != 0
- && strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) != 0)
+ if (!strstarts(name, ".data") && !strstarts(name, ".bss"))
continue;
- kmemleak_scan_area((void *)sechdrs[i].sh_addr,
- sechdrs[i].sh_size, GFP_KERNEL);
+ kmemleak_scan_area((void *)info->sechdrs[i].sh_addr,
+ info->sechdrs[i].sh_size, GFP_KERNEL);
}
}
#else
-static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
- Elf_Shdr *sechdrs, char *secstrings)
+static inline void kmemleak_load_module(const struct module *mod,
+ const struct load_info *info)
{
}
#endif
-/* Allocate and load the module: note that size of section 0 is always
- zero, and we rely on this for optional sections. */
-static noinline struct module *load_module(void __user *umod,
- unsigned long len,
- const char __user *uargs)
+/* Sets info->hdr and info->len. */
+static int copy_and_check(struct load_info *info,
+ const void __user *umod, unsigned long len,
+ const char __user *uargs)
{
+ int err;
Elf_Ehdr *hdr;
- Elf_Shdr *sechdrs;
- char *secstrings, *args, *modmagic, *strtab = NULL;
- char *staging;
- unsigned int i;
- unsigned int symindex = 0;
- unsigned int strindex = 0;
- unsigned int modindex, versindex, infoindex, pcpuindex;
- struct module *mod;
- long err = 0;
- void *ptr = NULL; /* Stops spurious gcc warning */
- unsigned long symoffs, stroffs, *strmap;
-
- mm_segment_t old_fs;
- DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
- umod, len, uargs);
if (len < sizeof(*hdr))
- return ERR_PTR(-ENOEXEC);
+ return -ENOEXEC;
/* Suck in entire file: we'll want most of it. */
/* vmalloc barfs on "unusual" numbers. Check here */
if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
if (copy_from_user(hdr, umod, len) != 0) {
err = -EFAULT;
@@ -2033,138 +2100,223 @@ static noinline struct module *load_module(void __user *umod,
}
/* Sanity checks against insmoding binaries or wrong arch,
- weird elf version */
+ weird elf version */
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|| hdr->e_type != ET_REL
|| !elf_check_arch(hdr)
- || hdr->e_shentsize != sizeof(*sechdrs)) {
+ || hdr->e_shentsize != sizeof(Elf_Shdr)) {
+ err = -ENOEXEC;
+ goto free_hdr;
+ }
+
+ if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
err = -ENOEXEC;
goto free_hdr;
}
- if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr))
- goto truncated;
+ info->hdr = hdr;
+ info->len = len;
+ return 0;
+
+free_hdr:
+ vfree(hdr);
+ return err;
+}
- /* Convenience variables */
- sechdrs = (void *)hdr + hdr->e_shoff;
- secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
- sechdrs[0].sh_addr = 0;
+static void free_copy(struct load_info *info)
+{
+ vfree(info->hdr);
+}
- for (i = 1; i < hdr->e_shnum; i++) {
- if (sechdrs[i].sh_type != SHT_NOBITS
- && len < sechdrs[i].sh_offset + sechdrs[i].sh_size)
- goto truncated;
+static int rewrite_section_headers(struct load_info *info)
+{
+ unsigned int i;
+
+ /* This should always be true, but let's be sure. */
+ info->sechdrs[0].sh_addr = 0;
+
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ Elf_Shdr *shdr = &info->sechdrs[i];
+ if (shdr->sh_type != SHT_NOBITS
+ && info->len < shdr->sh_offset + shdr->sh_size) {
+ printk(KERN_ERR "Module len %lu truncated\n",
+ info->len);
+ return -ENOEXEC;
+ }
/* Mark all sections sh_addr with their address in the
temporary image. */
- sechdrs[i].sh_addr = (size_t)hdr + sechdrs[i].sh_offset;
+ shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
- /* Internal symbols and strings. */
- if (sechdrs[i].sh_type == SHT_SYMTAB) {
- symindex = i;
- strindex = sechdrs[i].sh_link;
- strtab = (char *)hdr + sechdrs[strindex].sh_offset;
- }
#ifndef CONFIG_MODULE_UNLOAD
/* Don't load .exit sections */
- if (strstarts(secstrings+sechdrs[i].sh_name, ".exit"))
- sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+ shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
#endif
}
- modindex = find_sec(hdr, sechdrs, secstrings,
- ".gnu.linkonce.this_module");
- if (!modindex) {
+ /* Track but don't keep modinfo and version sections. */
+ info->index.vers = find_sec(info, "__versions");
+ info->index.info = find_sec(info, ".modinfo");
+ info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ return 0;
+}
+
+/*
+ * Set up our basic convenience variables (pointers to section headers,
+ * search for module section index etc), and do some basic section
+ * verification.
+ *
+ * Return the temporary module pointer (we'll replace it with the final
+ * one when we move the module sections around).
+ */
+static struct module *setup_load_info(struct load_info *info)
+{
+ unsigned int i;
+ int err;
+ struct module *mod;
+
+ /* Set up the convenience variables */
+ info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
+ info->secstrings = (void *)info->hdr
+ + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
+
+ err = rewrite_section_headers(info);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Find internal symbols and strings. */
+ for (i = 1; i < info->hdr->e_shnum; i++) {
+ if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
+ info->index.sym = i;
+ info->index.str = info->sechdrs[i].sh_link;
+ info->strtab = (char *)info->hdr
+ + info->sechdrs[info->index.str].sh_offset;
+ break;
+ }
+ }
+
+ info->index.mod = find_sec(info, ".gnu.linkonce.this_module");
+ if (!info->index.mod) {
printk(KERN_WARNING "No module found in object\n");
- err = -ENOEXEC;
- goto free_hdr;
+ return ERR_PTR(-ENOEXEC);
}
/* This is temporary: point mod into copy of data. */
- mod = (void *)sechdrs[modindex].sh_addr;
+ mod = (void *)info->sechdrs[info->index.mod].sh_addr;
- if (symindex == 0) {
+ if (info->index.sym == 0) {
printk(KERN_WARNING "%s: module has no symbols (stripped?)\n",
mod->name);
- err = -ENOEXEC;
- goto free_hdr;
+ return ERR_PTR(-ENOEXEC);
}
- versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
- infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
- pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
-
- /* Don't keep modinfo and version sections. */
- sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
- sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ info->index.pcpu = find_pcpusec(info);
/* Check module struct version now, before we try to use module. */
- if (!check_modstruct_version(sechdrs, versindex, mod)) {
- err = -ENOEXEC;
- goto free_hdr;
- }
+ if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
+ return ERR_PTR(-ENOEXEC);
+
+ return mod;
+}
+
+static int check_modinfo(struct module *mod, struct load_info *info)
+{
+ const char *modmagic = get_modinfo(info, "vermagic");
+ int err;
- modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
/* This is allowed: modprobe --force will invalidate it. */
if (!modmagic) {
err = try_to_force_load(mod, "bad vermagic");
if (err)
- goto free_hdr;
- } else if (!same_magic(modmagic, vermagic, versindex)) {
+ return err;
+ } else if (!same_magic(modmagic, vermagic, info->index.vers)) {
printk(KERN_ERR "%s: version magic '%s' should be '%s'\n",
mod->name, modmagic, vermagic);
- err = -ENOEXEC;
- goto free_hdr;
+ return -ENOEXEC;
}
- staging = get_modinfo(sechdrs, infoindex, "staging");
- if (staging) {
+ if (get_modinfo(info, "staging")) {
add_taint_module(mod, TAINT_CRAP);
printk(KERN_WARNING "%s: module is from the staging directory,"
" the quality is unknown, you have been warned.\n",
mod->name);
}
- /* Now copy in args */
- args = strndup_user(uargs, ~0UL >> 1);
- if (IS_ERR(args)) {
- err = PTR_ERR(args);
- goto free_hdr;
- }
+ /* Set up license info based on the info section */
+ set_license(mod, get_modinfo(info, "license"));
- strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
- * sizeof(long), GFP_KERNEL);
- if (!strmap) {
- err = -ENOMEM;
- goto free_mod;
- }
+ return 0;
+}
- if (find_module(mod->name)) {
- err = -EEXIST;
- goto free_mod;
- }
+static void find_module_sections(struct module *mod,
+ const struct load_info *info)
+{
+ mod->kp = section_objs(info, "__param",
+ sizeof(*mod->kp), &mod->num_kp);
+ mod->syms = section_objs(info, "__ksymtab",
+ sizeof(*mod->syms), &mod->num_syms);
+ mod->crcs = section_addr(info, "__kcrctab");
+ mod->gpl_syms = section_objs(info, "__ksymtab_gpl",
+ sizeof(*mod->gpl_syms),
+ &mod->num_gpl_syms);
+ mod->gpl_crcs = section_addr(info, "__kcrctab_gpl");
+ mod->gpl_future_syms = section_objs(info,
+ "__ksymtab_gpl_future",
+ sizeof(*mod->gpl_future_syms),
+ &mod->num_gpl_future_syms);
+ mod->gpl_future_crcs = section_addr(info, "__kcrctab_gpl_future");
- mod->state = MODULE_STATE_COMING;
+#ifdef CONFIG_UNUSED_SYMBOLS
+ mod->unused_syms = section_objs(info, "__ksymtab_unused",
+ sizeof(*mod->unused_syms),
+ &mod->num_unused_syms);
+ mod->unused_crcs = section_addr(info, "__kcrctab_unused");
+ mod->unused_gpl_syms = section_objs(info, "__ksymtab_unused_gpl",
+ sizeof(*mod->unused_gpl_syms),
+ &mod->num_unused_gpl_syms);
+ mod->unused_gpl_crcs = section_addr(info, "__kcrctab_unused_gpl");
+#endif
+#ifdef CONFIG_CONSTRUCTORS
+ mod->ctors = section_objs(info, ".ctors",
+ sizeof(*mod->ctors), &mod->num_ctors);
+#endif
- /* Allow arches to frob section contents and sizes. */
- err = module_frob_arch_sections(hdr, sechdrs, secstrings, mod);
- if (err < 0)
- goto free_mod;
+#ifdef CONFIG_TRACEPOINTS
+ mod->tracepoints = section_objs(info, "__tracepoints",
+ sizeof(*mod->tracepoints),
+ &mod->num_tracepoints);
+#endif
+#ifdef CONFIG_EVENT_TRACING
+ mod->trace_events = section_objs(info, "_ftrace_events",
+ sizeof(*mod->trace_events),
+ &mod->num_trace_events);
+ /*
+ * This section contains pointers to allocated objects in the trace
+ * code and not scanning it leads to false positives.
+ */
+ kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
+ mod->num_trace_events, GFP_KERNEL);
+#endif
+#ifdef CONFIG_FTRACE_MCOUNT_RECORD
+ /* sechdrs[0].sh_size is always zero */
+ mod->ftrace_callsites = section_objs(info, "__mcount_loc",
+ sizeof(*mod->ftrace_callsites),
+ &mod->num_ftrace_callsites);
+#endif
- if (pcpuindex) {
- /* We have a special allocation for this section. */
- err = percpu_modalloc(mod, sechdrs[pcpuindex].sh_size,
- sechdrs[pcpuindex].sh_addralign);
- if (err)
- goto free_mod;
- sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
- }
+ mod->extable = section_objs(info, "__ex_table",
+ sizeof(*mod->extable), &mod->num_exentries);
- /* Determine total sizes, and put offsets in sh_entsize. For now
- this is done generically; there doesn't appear to be any
- special cases for the architectures. */
- layout_sections(mod, hdr, sechdrs, secstrings);
- symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
- secstrings, &stroffs, strmap);
+ if (section_addr(info, "__obsparm"))
+ printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
+ mod->name);
+}
+
+static int move_module(struct module *mod, struct load_info *info)
+{
+ int i;
+ void *ptr;
/* Do the allocs. */
ptr = module_alloc_update_bounds(mod->core_size);
@@ -2174,10 +2326,9 @@ static noinline struct module *load_module(void __user *umod,
* leak.
*/
kmemleak_not_leak(ptr);
- if (!ptr) {
- err = -ENOMEM;
- goto free_percpu;
- }
+ if (!ptr)
+ return -ENOMEM;
+
memset(ptr, 0, mod->core_size);
mod->module_core = ptr;
@@ -2190,55 +2341,40 @@ static noinline struct module *load_module(void __user *umod,
*/
kmemleak_ignore(ptr);
if (!ptr && mod->init_size) {
- err = -ENOMEM;
- goto free_core;
+ module_free(mod, mod->module_core);
+ return -ENOMEM;
}
memset(ptr, 0, mod->init_size);
mod->module_init = ptr;
/* Transfer each section which specifies SHF_ALLOC */
DEBUGP("final section addresses:\n");
- for (i = 0; i < hdr->e_shnum; i++) {
+ for (i = 0; i < info->hdr->e_shnum; i++) {
void *dest;
+ Elf_Shdr *shdr = &info->sechdrs[i];
- if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+ if (!(shdr->sh_flags & SHF_ALLOC))
continue;
- if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK)
+ if (shdr->sh_entsize & INIT_OFFSET_MASK)
dest = mod->module_init
- + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK);
+ + (shdr->sh_entsize & ~INIT_OFFSET_MASK);
else
- dest = mod->module_core + sechdrs[i].sh_entsize;
+ dest = mod->module_core + shdr->sh_entsize;
- if (sechdrs[i].sh_type != SHT_NOBITS)
- memcpy(dest, (void *)sechdrs[i].sh_addr,
- sechdrs[i].sh_size);
+ if (shdr->sh_type != SHT_NOBITS)
+ memcpy(dest, (void *)shdr->sh_addr, shdr->sh_size);
/* Update sh_addr to point to copy in image. */
- sechdrs[i].sh_addr = (unsigned long)dest;
- DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
- }
- /* Module has been moved. */
- mod = (void *)sechdrs[modindex].sh_addr;
- kmemleak_load_module(mod, hdr, sechdrs, secstrings);
-
-#if defined(CONFIG_MODULE_UNLOAD)
- mod->refptr = alloc_percpu(struct module_ref);
- if (!mod->refptr) {
- err = -ENOMEM;
- goto free_init;
+ shdr->sh_addr = (unsigned long)dest;
+ DEBUGP("\t0x%lx %s\n",
+ shdr->sh_addr, info->secstrings + shdr->sh_name);
}
-#endif
- /* Now we've moved module, initialize linked lists, etc. */
- module_unload_init(mod);
-
- /* add kobject, so we can reference it. */
- err = mod_sysfs_init(mod);
- if (err)
- goto free_unload;
- /* Set up license info based on the info section */
- set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
+ return 0;
+}
+static int check_module_license_and_versions(struct module *mod)
+{
/*
* ndiswrapper is under GPL by itself, but loads proprietary modules.
* Don't use add_taint_module(), as it would prevent ndiswrapper from
@@ -2251,77 +2387,6 @@ static noinline struct module *load_module(void __user *umod,
if (strcmp(mod->name, "driverloader") == 0)
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
- /* Set up MODINFO_ATTR fields */
- setup_modinfo(mod, sechdrs, infoindex);
-
- /* Fix up syms, so that st_value is a pointer to location. */
- err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
- mod);
- if (err < 0)
- goto cleanup;
-
- /* Now we've got everything in the final locations, we can
- * find optional sections. */
- mod->kp = section_objs(hdr, sechdrs, secstrings, "__param",
- sizeof(*mod->kp), &mod->num_kp);
- mod->syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab",
- sizeof(*mod->syms), &mod->num_syms);
- mod->crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab");
- mod->gpl_syms = section_objs(hdr, sechdrs, secstrings, "__ksymtab_gpl",
- sizeof(*mod->gpl_syms),
- &mod->num_gpl_syms);
- mod->gpl_crcs = section_addr(hdr, sechdrs, secstrings, "__kcrctab_gpl");
- mod->gpl_future_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_gpl_future",
- sizeof(*mod->gpl_future_syms),
- &mod->num_gpl_future_syms);
- mod->gpl_future_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_gpl_future");
-
-#ifdef CONFIG_UNUSED_SYMBOLS
- mod->unused_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_unused",
- sizeof(*mod->unused_syms),
- &mod->num_unused_syms);
- mod->unused_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_unused");
- mod->unused_gpl_syms = section_objs(hdr, sechdrs, secstrings,
- "__ksymtab_unused_gpl",
- sizeof(*mod->unused_gpl_syms),
- &mod->num_unused_gpl_syms);
- mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
- "__kcrctab_unused_gpl");
-#endif
-#ifdef CONFIG_CONSTRUCTORS
- mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors",
- sizeof(*mod->ctors), &mod->num_ctors);
-#endif
-
-#ifdef CONFIG_TRACEPOINTS
- mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
- "__tracepoints",
- sizeof(*mod->tracepoints),
- &mod->num_tracepoints);
-#endif
-#ifdef CONFIG_EVENT_TRACING
- mod->trace_events = section_objs(hdr, sechdrs, secstrings,
- "_ftrace_events",
- sizeof(*mod->trace_events),
- &mod->num_trace_events);
- /*
- * This section contains pointers to allocated objects in the trace
- * code and not scanning it leads to false positives.
- */
- kmemleak_scan_area(mod->trace_events, sizeof(*mod->trace_events) *
- mod->num_trace_events, GFP_KERNEL);
-#endif
-#ifdef CONFIG_FTRACE_MCOUNT_RECORD
- /* sechdrs[0].sh_size is always zero */
- mod->ftrace_callsites = section_objs(hdr, sechdrs, secstrings,
- "__mcount_loc",
- sizeof(*mod->ftrace_callsites),
- &mod->num_ftrace_callsites);
-#endif
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !mod->crcs)
|| (mod->num_gpl_syms && !mod->gpl_crcs)
@@ -2331,67 +2396,16 @@ static noinline struct module *load_module(void __user *umod,
|| (mod->num_unused_gpl_syms && !mod->unused_gpl_crcs)
#endif
) {
- err = try_to_force_load(mod,
- "no versions for exported symbols");
- if (err)
- goto cleanup;
+ return try_to_force_load(mod,
+ "no versions for exported symbols");
}
#endif
+ return 0;
+}
- /* Now do relocations. */
- for (i = 1; i < hdr->e_shnum; i++) {
- const char *strtab = (char *)sechdrs[strindex].sh_addr;
- unsigned int info = sechdrs[i].sh_info;
-
- /* Not a valid relocation section? */
- if (info >= hdr->e_shnum)
- continue;
-
- /* Don't bother with non-allocated sections */
- if (!(sechdrs[info].sh_flags & SHF_ALLOC))
- continue;
-
- if (sechdrs[i].sh_type == SHT_REL)
- err = apply_relocate(sechdrs, strtab, symindex, i,mod);
- else if (sechdrs[i].sh_type == SHT_RELA)
- err = apply_relocate_add(sechdrs, strtab, symindex, i,
- mod);
- if (err < 0)
- goto cleanup;
- }
-
- /* Find duplicate symbols */
- err = verify_export_symbols(mod);
- if (err < 0)
- goto cleanup;
-
- /* Set up and sort exception table */
- mod->extable = section_objs(hdr, sechdrs, secstrings, "__ex_table",
- sizeof(*mod->extable), &mod->num_exentries);
- sort_extable(mod->extable, mod->extable + mod->num_exentries);
-
- /* Finally, copy percpu area over. */
- percpu_modcopy(mod, (void *)sechdrs[pcpuindex].sh_addr,
- sechdrs[pcpuindex].sh_size);
-
- add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
- symoffs, stroffs, secstrings, strmap);
- kfree(strmap);
- strmap = NULL;
-
- if (!mod->taints) {
- struct _ddebug *debug;
- unsigned int num_debug;
-
- debug = section_objs(hdr, sechdrs, secstrings, "__verbose",
- sizeof(*debug), &num_debug);
- if (debug)
- dynamic_debug_setup(debug, num_debug);
- }
-
- err = module_finalize(hdr, sechdrs, mod);
- if (err < 0)
- goto cleanup;
+static void flush_module_icache(const struct module *mod)
+{
+ mm_segment_t old_fs;
/* flush the icache in correct context */
old_fs = get_fs();
@@ -2410,11 +2424,182 @@ static noinline struct module *load_module(void __user *umod,
(unsigned long)mod->module_core + mod->core_size);
set_fs(old_fs);
+}
- mod->args = args;
- if (section_addr(hdr, sechdrs, secstrings, "__obsparm"))
- printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
- mod->name);
+static struct module *layout_and_allocate(struct load_info *info)
+{
+ /* Module within temporary copy. */
+ struct module *mod;
+ Elf_Shdr *pcpusec;
+ int err;
+
+ mod = setup_load_info(info);
+ if (IS_ERR(mod))
+ return mod;
+
+ err = check_modinfo(mod, info);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Allow arches to frob section contents and sizes. */
+ err = module_frob_arch_sections(info->hdr, info->sechdrs,
+ info->secstrings, mod);
+ if (err < 0)
+ goto out;
+
+ pcpusec = &info->sechdrs[info->index.pcpu];
+ if (pcpusec->sh_size) {
+ /* We have a special allocation for this section. */
+ err = percpu_modalloc(mod,
+ pcpusec->sh_size, pcpusec->sh_addralign);
+ if (err)
+ goto out;
+ pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC;
+ }
+
+ /* Determine total sizes, and put offsets in sh_entsize. For now
+ this is done generically; there doesn't appear to be any
+ special cases for the architectures. */
+ layout_sections(mod, info);
+
+ info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size)
+ * sizeof(long), GFP_KERNEL);
+ if (!info->strmap) {
+ err = -ENOMEM;
+ goto free_percpu;
+ }
+ layout_symtab(mod, info);
+
+ /* Allocate and move to the final place */
+ err = move_module(mod, info);
+ if (err)
+ goto free_strmap;
+
+ /* Module has been copied to its final place now: return it. */
+ mod = (void *)info->sechdrs[info->index.mod].sh_addr;
+ kmemleak_load_module(mod, info);
+ return mod;
+
+free_strmap:
+ kfree(info->strmap);
+free_percpu:
+ percpu_modfree(mod);
+out:
+ return ERR_PTR(err);
+}
+
+/* mod is no longer valid after this! */
+static void module_deallocate(struct module *mod, struct load_info *info)
+{
+ kfree(info->strmap);
+ percpu_modfree(mod);
+ module_free(mod, mod->module_init);
+ module_free(mod, mod->module_core);
+}
+
+static void setup_dynamic_debugging(struct module *mod,
+ const struct load_info *info)
+{
+#ifdef CONFIG_DYNAMIC_DEBUG
+ struct _ddebug *debug;
+ unsigned int num_debug;
+
+ if (mod->taints)
+ return;
+
+ debug = section_objs(info, "__verbose", sizeof(*debug), &num_debug);
+ if (!debug)
+ return;
+
+ if (ddebug_add_module(debug, num_debug, debug->modname))
+ printk(KERN_ERR "dynamic debug error adding module: %s\n",
+ debug->modname);
+#endif
+}
+
+static int post_relocation(struct module *mod, const struct load_info *info)
+{
+ /* Sort exception table now relocations are done. */
+ sort_extable(mod->extable, mod->extable + mod->num_exentries);
+
+ /* Copy relocated percpu area over. */
+ percpu_modcopy(mod, (void *)info->sechdrs[info->index.pcpu].sh_addr,
+ info->sechdrs[info->index.pcpu].sh_size);
+
+ /* Setup kallsyms-specific fields. */
+ add_kallsyms(mod, info);
+
+ setup_dynamic_debugging(mod, info);
+
+ /* Arch-specific module finalizing. */
+ return module_finalize(info->hdr, info->sechdrs, mod);
+}
+
+/* Allocate and load the module: note that size of section 0 is always
+ zero, and we rely on this for optional sections. */
+static struct module *load_module(void __user *umod,
+ unsigned long len,
+ const char __user *uargs)
+{
+ struct load_info info = { NULL, };
+ struct module *mod;
+ long err;
+
+ DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
+ umod, len, uargs);
+
+ /* Copy in the blobs from userspace, check they are vaguely sane. */
+ err = copy_and_check(&info, umod, len, uargs);
+ if (err)
+ return ERR_PTR(err);
+
+ /* Figure out module layout, and allocate all the memory. */
+ mod = layout_and_allocate(&info);
+ if (IS_ERR(mod)) {
+ err = PTR_ERR(mod);
+ goto free_copy;
+ }
+
+ /* Now module is in final location, initialize linked lists, etc. */
+ err = module_unload_init(mod);
+ if (err)
+ goto free_module;
+
+ /* Now we've got everything in the final locations, we can
+ * find optional sections. */
+ find_module_sections(mod, &info);
+
+ err = check_module_license_and_versions(mod);
+ if (err)
+ goto free_unload;
+
+ /* Set up MODINFO_ATTR fields */
+ setup_modinfo(mod, &info);
+
+ /* Fix up syms, so that st_value is a pointer to location. */
+ err = simplify_symbols(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ err = apply_relocations(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ err = post_relocation(mod, &info);
+ if (err < 0)
+ goto free_modinfo;
+
+ flush_module_icache(mod);
+
+ /* Now copy in args */
+ mod->args = strndup_user(uargs, ~0UL >> 1);
+ if (IS_ERR(mod->args)) {
+ err = PTR_ERR(mod->args);
+ goto free_arch_cleanup;
+ }
+
+ /* Mark state as coming so strong_try_module_get() ignores us. */
+ mod->state = MODULE_STATE_COMING;
/* Now sew it into the lists so we can get lockdep and oops
* info during argument parsing. Noone should access us, since
@@ -2423,58 +2608,57 @@ static noinline struct module *load_module(void __user *umod,
* function to insert in a way safe to concurrent readers.
* The mutex protects against concurrent writers.
*/
+ mutex_lock(&module_mutex);
+ if (find_module(mod->name)) {
+ err = -EEXIST;
+ goto unlock;
+ }
+
+ /* Find duplicate symbols */
+ err = verify_export_symbols(mod);
+ if (err < 0)
+ goto unlock;
+
list_add_rcu(&mod->list, &modules);
+ mutex_unlock(&module_mutex);
+ /* Module is ready to execute: parsing args may do that. */
err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, NULL);
if (err < 0)
goto unlink;
- err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
+ /* Link in to syfs. */
+ err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
if (err < 0)
goto unlink;
- add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
- add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
-
- /* Get rid of temporary copy */
- vfree(hdr);
- trace_module_load(mod);
+ /* Get rid of temporary copy and strmap. */
+ kfree(info.strmap);
+ free_copy(&info);
/* Done! */
+ trace_module_load(mod);
return mod;
unlink:
+ mutex_lock(&module_mutex);
/* Unlink carefully: kallsyms could be walking list. */
list_del_rcu(&mod->list);
+ unlock:
+ mutex_unlock(&module_mutex);
synchronize_sched();
+ kfree(mod->args);
+ free_arch_cleanup:
module_arch_cleanup(mod);
- cleanup:
+ free_modinfo:
free_modinfo(mod);
- kobject_del(&mod->mkobj.kobj);
- kobject_put(&mod->mkobj.kobj);
free_unload:
module_unload_free(mod);
-#if defined(CONFIG_MODULE_UNLOAD)
- free_percpu(mod->refptr);
- free_init:
-#endif
- module_free(mod, mod->module_init);
- free_core:
- module_free(mod, mod->module_core);
- /* mod will be freed with core. Don't access it beyond this line! */
- free_percpu:
- percpu_modfree(mod);
- free_mod:
- kfree(args);
- kfree(strmap);
- free_hdr:
- vfree(hdr);
+ free_module:
+ module_deallocate(mod, &info);
+ free_copy:
+ free_copy(&info);
return ERR_PTR(err);
-
- truncated:
- printk(KERN_ERR "Module len %lu truncated\n", len);
- err = -ENOEXEC;
- goto free_hdr;
}
/* Call module constructors. */
@@ -2499,19 +2683,10 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
if (!capable(CAP_SYS_MODULE) || modules_disabled)
return -EPERM;
- /* Only one module load at a time, please */
- if (mutex_lock_interruptible(&module_mutex) != 0)
- return -EINTR;
-
/* Do all the hard work */
mod = load_module(umod, len, uargs);
- if (IS_ERR(mod)) {
- mutex_unlock(&module_mutex);
+ if (IS_ERR(mod))
return PTR_ERR(mod);
- }
-
- /* Drop lock so they can recurse */
- mutex_unlock(&module_mutex);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_COMING, mod);
@@ -2528,9 +2703,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
module_put(mod);
blocking_notifier_call_chain(&module_notify_list,
MODULE_STATE_GOING, mod);
- mutex_lock(&module_mutex);
free_module(mod);
- mutex_unlock(&module_mutex);
wake_up(&module_wq);
return ret;
}
diff --git a/kernel/padata.c b/kernel/padata.c
index fdd8ae609ce3..060884a98b07 100644
--- a/kernel/padata.c
+++ b/kernel/padata.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/rcupdate.h>
-#define MAX_SEQ_NR INT_MAX - NR_CPUS
+#define MAX_SEQ_NR (INT_MAX - NR_CPUS)
#define MAX_OBJ_NUM 1000
static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index)
diff --git a/kernel/params.c b/kernel/params.c
index 0b30ecd53a52..08107d181758 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -31,6 +31,42 @@
#define DEBUGP(fmt, a...)
#endif
+/* Protects all parameters, and incidentally kmalloced_param list. */
+static DEFINE_MUTEX(param_lock);
+
+/* This just allows us to keep track of which parameters are kmalloced. */
+struct kmalloced_param {
+ struct list_head list;
+ char val[];
+};
+static LIST_HEAD(kmalloced_params);
+
+static void *kmalloc_parameter(unsigned int size)
+{
+ struct kmalloced_param *p;
+
+ p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
+ if (!p)
+ return NULL;
+
+ list_add(&p->list, &kmalloced_params);
+ return p->val;
+}
+
+/* Does nothing if parameter wasn't kmalloced above. */
+static void maybe_kfree_parameter(void *param)
+{
+ struct kmalloced_param *p;
+
+ list_for_each_entry(p, &kmalloced_params, list) {
+ if (p->val == param) {
+ list_del(&p->list);
+ kfree(p);
+ break;
+ }
+ }
+}
+
static inline char dash2underscore(char c)
{
if (c == '-')
@@ -49,18 +85,25 @@ static inline int parameq(const char *input, const char *paramname)
static int parse_one(char *param,
char *val,
- struct kernel_param *params,
+ const struct kernel_param *params,
unsigned num_params,
int (*handle_unknown)(char *param, char *val))
{
unsigned int i;
+ int err;
/* Find parameter */
for (i = 0; i < num_params; i++) {
if (parameq(param, params[i].name)) {
+ /* Noone handled NULL, so do it here. */
+ if (!val && params[i].ops->set != param_set_bool)
+ return -EINVAL;
DEBUGP("They are equal! Calling %p\n",
- params[i].set);
- return params[i].set(val, &params[i]);
+ params[i].ops->set);
+ mutex_lock(&param_lock);
+ err = params[i].ops->set(val, &params[i]);
+ mutex_unlock(&param_lock);
+ return err;
}
}
@@ -128,7 +171,7 @@ static char *next_arg(char *args, char **param, char **val)
/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
int parse_args(const char *name,
char *args,
- struct kernel_param *params,
+ const struct kernel_param *params,
unsigned num,
int (*unknown)(char *param, char *val))
{
@@ -176,22 +219,29 @@ int parse_args(const char *name,
/* Lazy bastard, eh? */
#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn) \
- int param_set_##name(const char *val, struct kernel_param *kp) \
+ int param_set_##name(const char *val, const struct kernel_param *kp) \
{ \
tmptype l; \
int ret; \
\
- if (!val) return -EINVAL; \
ret = strtolfn(val, 0, &l); \
if (ret == -EINVAL || ((type)l != l)) \
return -EINVAL; \
*((type *)kp->arg) = l; \
return 0; \
} \
- int param_get_##name(char *buffer, struct kernel_param *kp) \
+ int param_get_##name(char *buffer, const struct kernel_param *kp) \
{ \
return sprintf(buffer, format, *((type *)kp->arg)); \
- }
+ } \
+ struct kernel_param_ops param_ops_##name = { \
+ .set = param_set_##name, \
+ .get = param_get_##name, \
+ }; \
+ EXPORT_SYMBOL(param_set_##name); \
+ EXPORT_SYMBOL(param_get_##name); \
+ EXPORT_SYMBOL(param_ops_##name)
+
STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
@@ -201,39 +251,50 @@ STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
-int param_set_charp(const char *val, struct kernel_param *kp)
+int param_set_charp(const char *val, const struct kernel_param *kp)
{
- if (!val) {
- printk(KERN_ERR "%s: string parameter expected\n",
- kp->name);
- return -EINVAL;
- }
-
if (strlen(val) > 1024) {
printk(KERN_ERR "%s: string parameter too long\n",
kp->name);
return -ENOSPC;
}
- /* This is a hack. We can't need to strdup in early boot, and we
+ maybe_kfree_parameter(*(char **)kp->arg);
+
+ /* This is a hack. We can't kmalloc in early boot, and we
* don't need to; this mangled commandline is preserved. */
if (slab_is_available()) {
- *(char **)kp->arg = kstrdup(val, GFP_KERNEL);
+ *(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
if (!*(char **)kp->arg)
return -ENOMEM;
+ strcpy(*(char **)kp->arg, val);
} else
*(const char **)kp->arg = val;
return 0;
}
+EXPORT_SYMBOL(param_set_charp);
-int param_get_charp(char *buffer, struct kernel_param *kp)
+int param_get_charp(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%s", *((char **)kp->arg));
}
+EXPORT_SYMBOL(param_get_charp);
+
+static void param_free_charp(void *arg)
+{
+ maybe_kfree_parameter(*((char **)arg));
+}
+
+struct kernel_param_ops param_ops_charp = {
+ .set = param_set_charp,
+ .get = param_get_charp,
+ .free = param_free_charp,
+};
+EXPORT_SYMBOL(param_ops_charp);
/* Actually could be a bool or an int, for historical reasons. */
-int param_set_bool(const char *val, struct kernel_param *kp)
+int param_set_bool(const char *val, const struct kernel_param *kp)
{
bool v;
@@ -258,8 +319,9 @@ int param_set_bool(const char *val, struct kernel_param *kp)
*(int *)kp->arg = v;
return 0;
}
+EXPORT_SYMBOL(param_set_bool);
-int param_get_bool(char *buffer, struct kernel_param *kp)
+int param_get_bool(char *buffer, const struct kernel_param *kp)
{
bool val;
if (kp->flags & KPARAM_ISBOOL)
@@ -270,9 +332,16 @@ int param_get_bool(char *buffer, struct kernel_param *kp)
/* Y and N chosen as being relatively non-coder friendly */
return sprintf(buffer, "%c", val ? 'Y' : 'N');
}
+EXPORT_SYMBOL(param_get_bool);
+
+struct kernel_param_ops param_ops_bool = {
+ .set = param_set_bool,
+ .get = param_get_bool,
+};
+EXPORT_SYMBOL(param_ops_bool);
/* This one must be bool. */
-int param_set_invbool(const char *val, struct kernel_param *kp)
+int param_set_invbool(const char *val, const struct kernel_param *kp)
{
int ret;
bool boolval;
@@ -285,18 +354,26 @@ int param_set_invbool(const char *val, struct kernel_param *kp)
*(bool *)kp->arg = !boolval;
return ret;
}
+EXPORT_SYMBOL(param_set_invbool);
-int param_get_invbool(char *buffer, struct kernel_param *kp)
+int param_get_invbool(char *buffer, const struct kernel_param *kp)
{
return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
}
+EXPORT_SYMBOL(param_get_invbool);
+
+struct kernel_param_ops param_ops_invbool = {
+ .set = param_set_invbool,
+ .get = param_get_invbool,
+};
+EXPORT_SYMBOL(param_ops_invbool);
/* We break the rule and mangle the string. */
static int param_array(const char *name,
const char *val,
unsigned int min, unsigned int max,
void *elem, int elemsize,
- int (*set)(const char *, struct kernel_param *kp),
+ int (*set)(const char *, const struct kernel_param *kp),
u16 flags,
unsigned int *num)
{
@@ -309,12 +386,6 @@ static int param_array(const char *name,
kp.arg = elem;
kp.flags = flags;
- /* No equals sign? */
- if (!val) {
- printk(KERN_ERR "%s: expects arguments\n", name);
- return -EINVAL;
- }
-
*num = 0;
/* We expect a comma-separated list of values. */
do {
@@ -330,6 +401,7 @@ static int param_array(const char *name,
/* nul-terminate and parse */
save = val[len];
((char *)val)[len] = '\0';
+ BUG_ON(!mutex_is_locked(&param_lock));
ret = set(val, &kp);
if (ret != 0)
@@ -347,17 +419,17 @@ static int param_array(const char *name,
return 0;
}
-int param_array_set(const char *val, struct kernel_param *kp)
+static int param_array_set(const char *val, const struct kernel_param *kp)
{
const struct kparam_array *arr = kp->arr;
unsigned int temp_num;
return param_array(kp->name, val, 1, arr->max, arr->elem,
- arr->elemsize, arr->set, kp->flags,
+ arr->elemsize, arr->ops->set, kp->flags,
arr->num ?: &temp_num);
}
-int param_array_get(char *buffer, struct kernel_param *kp)
+static int param_array_get(char *buffer, const struct kernel_param *kp)
{
int i, off, ret;
const struct kparam_array *arr = kp->arr;
@@ -368,7 +440,8 @@ int param_array_get(char *buffer, struct kernel_param *kp)
if (i)
buffer[off++] = ',';
p.arg = arr->elem + arr->elemsize * i;
- ret = arr->get(buffer + off, &p);
+ BUG_ON(!mutex_is_locked(&param_lock));
+ ret = arr->ops->get(buffer + off, &p);
if (ret < 0)
return ret;
off += ret;
@@ -377,14 +450,27 @@ int param_array_get(char *buffer, struct kernel_param *kp)
return off;
}
-int param_set_copystring(const char *val, struct kernel_param *kp)
+static void param_array_free(void *arg)
+{
+ unsigned int i;
+ const struct kparam_array *arr = arg;
+
+ if (arr->ops->free)
+ for (i = 0; i < (arr->num ? *arr->num : arr->max); i++)
+ arr->ops->free(arr->elem + arr->elemsize * i);
+}
+
+struct kernel_param_ops param_array_ops = {
+ .set = param_array_set,
+ .get = param_array_get,
+ .free = param_array_free,
+};
+EXPORT_SYMBOL(param_array_ops);
+
+int param_set_copystring(const char *val, const struct kernel_param *kp)
{
const struct kparam_string *kps = kp->str;
- if (!val) {
- printk(KERN_ERR "%s: missing param set value\n", kp->name);
- return -EINVAL;
- }
if (strlen(val)+1 > kps->maxlen) {
printk(KERN_ERR "%s: string doesn't fit in %u chars.\n",
kp->name, kps->maxlen-1);
@@ -393,12 +479,20 @@ int param_set_copystring(const char *val, struct kernel_param *kp)
strcpy(kps->string, val);
return 0;
}
+EXPORT_SYMBOL(param_set_copystring);
-int param_get_string(char *buffer, struct kernel_param *kp)
+int param_get_string(char *buffer, const struct kernel_param *kp)
{
const struct kparam_string *kps = kp->str;
return strlcpy(buffer, kps->string, kps->maxlen);
}
+EXPORT_SYMBOL(param_get_string);
+
+struct kernel_param_ops param_ops_string = {
+ .set = param_set_copystring,
+ .get = param_get_string,
+};
+EXPORT_SYMBOL(param_ops_string);
/* sysfs output in /sys/modules/XYZ/parameters/ */
#define to_module_attr(n) container_of(n, struct module_attribute, attr)
@@ -409,7 +503,7 @@ extern struct kernel_param __start___param[], __stop___param[];
struct param_attribute
{
struct module_attribute mattr;
- struct kernel_param *param;
+ const struct kernel_param *param;
};
struct module_param_attrs
@@ -428,10 +522,12 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
int count;
struct param_attribute *attribute = to_param_attr(mattr);
- if (!attribute->param->get)
+ if (!attribute->param->ops->get)
return -EPERM;
- count = attribute->param->get(buf, attribute->param);
+ mutex_lock(&param_lock);
+ count = attribute->param->ops->get(buf, attribute->param);
+ mutex_unlock(&param_lock);
if (count > 0) {
strcat(buf, "\n");
++count;
@@ -447,10 +543,12 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
int err;
struct param_attribute *attribute = to_param_attr(mattr);
- if (!attribute->param->set)
+ if (!attribute->param->ops->set)
return -EPERM;
- err = attribute->param->set(buf, attribute->param);
+ mutex_lock(&param_lock);
+ err = attribute->param->ops->set(buf, attribute->param);
+ mutex_unlock(&param_lock);
if (!err)
return len;
return err;
@@ -464,6 +562,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
#endif
#ifdef CONFIG_SYSFS
+void __kernel_param_lock(void)
+{
+ mutex_lock(&param_lock);
+}
+EXPORT_SYMBOL(__kernel_param_lock);
+
+void __kernel_param_unlock(void)
+{
+ mutex_unlock(&param_lock);
+}
+EXPORT_SYMBOL(__kernel_param_unlock);
+
/*
* add_sysfs_param - add a parameter to sysfs
* @mk: struct module_kobject
@@ -475,7 +585,7 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
* if there's an error.
*/
static __modinit int add_sysfs_param(struct module_kobject *mk,
- struct kernel_param *kp,
+ const struct kernel_param *kp,
const char *name)
{
struct module_param_attrs *new;
@@ -557,7 +667,7 @@ static void free_module_param_attrs(struct module_kobject *mk)
* /sys/module/[mod->name]/parameters/
*/
int module_param_sysfs_setup(struct module *mod,
- struct kernel_param *kparam,
+ const struct kernel_param *kparam,
unsigned int num_params)
{
int i, err;
@@ -602,7 +712,11 @@ void module_param_sysfs_remove(struct module *mod)
void destroy_params(const struct kernel_param *params, unsigned num)
{
- /* FIXME: This should free kmalloced charp parameters. It doesn't. */
+ unsigned int i;
+
+ for (i = 0; i < num; i++)
+ if (params[i].ops->free)
+ params[i].ops->free(params[i].arg);
}
static void __init kernel_add_sysfs_param(const char *name,
@@ -768,28 +882,3 @@ static int __init param_sysfs_init(void)
subsys_initcall(param_sysfs_init);
#endif /* CONFIG_SYSFS */
-
-EXPORT_SYMBOL(param_set_byte);
-EXPORT_SYMBOL(param_get_byte);
-EXPORT_SYMBOL(param_set_short);
-EXPORT_SYMBOL(param_get_short);
-EXPORT_SYMBOL(param_set_ushort);
-EXPORT_SYMBOL(param_get_ushort);
-EXPORT_SYMBOL(param_set_int);
-EXPORT_SYMBOL(param_get_int);
-EXPORT_SYMBOL(param_set_uint);
-EXPORT_SYMBOL(param_get_uint);
-EXPORT_SYMBOL(param_set_long);
-EXPORT_SYMBOL(param_get_long);
-EXPORT_SYMBOL(param_set_ulong);
-EXPORT_SYMBOL(param_get_ulong);
-EXPORT_SYMBOL(param_set_charp);
-EXPORT_SYMBOL(param_get_charp);
-EXPORT_SYMBOL(param_set_bool);
-EXPORT_SYMBOL(param_get_bool);
-EXPORT_SYMBOL(param_set_invbool);
-EXPORT_SYMBOL(param_get_invbool);
-EXPORT_SYMBOL(param_array_set);
-EXPORT_SYMBOL(param_array_get);
-EXPORT_SYMBOL(param_set_copystring);
-EXPORT_SYMBOL(param_get_string);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index bd7ce8ca5bb9..31d6afe92594 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -283,14 +283,15 @@ ctx_group_list(struct perf_event *event, struct perf_event_context *ctx)
static void
list_add_event(struct perf_event *event, struct perf_event_context *ctx)
{
- struct perf_event *group_leader = event->group_leader;
+ WARN_ON_ONCE(event->attach_state & PERF_ATTACH_CONTEXT);
+ event->attach_state |= PERF_ATTACH_CONTEXT;
/*
- * Depending on whether it is a standalone or sibling event,
- * add it straight to the context's event list, or to the group
- * leader's sibling list:
+ * If we're a stand alone event or group leader, we go to the context
+ * list, group events are kept attached to the group so that
+ * perf_group_detach can, at all times, locate all siblings.
*/
- if (group_leader == event) {
+ if (event->group_leader == event) {
struct list_head *list;
if (is_software_event(event))
@@ -298,13 +299,6 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
list = ctx_group_list(event, ctx);
list_add_tail(&event->group_entry, list);
- } else {
- if (group_leader->group_flags & PERF_GROUP_SOFTWARE &&
- !is_software_event(event))
- group_leader->group_flags &= ~PERF_GROUP_SOFTWARE;
-
- list_add_tail(&event->group_entry, &group_leader->sibling_list);
- group_leader->nr_siblings++;
}
list_add_rcu(&event->event_entry, &ctx->event_list);
@@ -313,6 +307,24 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
ctx->nr_stat++;
}
+static void perf_group_attach(struct perf_event *event)
+{
+ struct perf_event *group_leader = event->group_leader;
+
+ WARN_ON_ONCE(event->attach_state & PERF_ATTACH_GROUP);
+ event->attach_state |= PERF_ATTACH_GROUP;
+
+ if (group_leader == event)
+ return;
+
+ if (group_leader->group_flags & PERF_GROUP_SOFTWARE &&
+ !is_software_event(event))
+ group_leader->group_flags &= ~PERF_GROUP_SOFTWARE;
+
+ list_add_tail(&event->group_entry, &group_leader->sibling_list);
+ group_leader->nr_siblings++;
+}
+
/*
* Remove a event from the lists for its context.
* Must be called with ctx->mutex and ctx->lock held.
@@ -320,17 +332,22 @@ list_add_event(struct perf_event *event, struct perf_event_context *ctx)
static void
list_del_event(struct perf_event *event, struct perf_event_context *ctx)
{
- if (list_empty(&event->group_entry))
+ /*
+ * We can have double detach due to exit/hot-unplug + close.
+ */
+ if (!(event->attach_state & PERF_ATTACH_CONTEXT))
return;
+
+ event->attach_state &= ~PERF_ATTACH_CONTEXT;
+
ctx->nr_events--;
if (event->attr.inherit_stat)
ctx->nr_stat--;
- list_del_init(&event->group_entry);
list_del_rcu(&event->event_entry);
- if (event->group_leader != event)
- event->group_leader->nr_siblings--;
+ if (event->group_leader == event)
+ list_del_init(&event->group_entry);
update_group_times(event);
@@ -345,21 +362,39 @@ list_del_event(struct perf_event *event, struct perf_event_context *ctx)
event->state = PERF_EVENT_STATE_OFF;
}
-static void
-perf_destroy_group(struct perf_event *event, struct perf_event_context *ctx)
+static void perf_group_detach(struct perf_event *event)
{
struct perf_event *sibling, *tmp;
+ struct list_head *list = NULL;
+
+ /*
+ * We can have double detach due to exit/hot-unplug + close.
+ */
+ if (!(event->attach_state & PERF_ATTACH_GROUP))
+ return;
+
+ event->attach_state &= ~PERF_ATTACH_GROUP;
+
+ /*
+ * If this is a sibling, remove it from its group.
+ */
+ if (event->group_leader != event) {
+ list_del_init(&event->group_entry);
+ event->group_leader->nr_siblings--;
+ return;
+ }
+
+ if (!list_empty(&event->group_entry))
+ list = &event->group_entry;
/*
* If this was a group event with sibling events then
* upgrade the siblings to singleton events by adding them
- * to the context list directly:
+ * to whatever list we are on.
*/
list_for_each_entry_safe(sibling, tmp, &event->sibling_list, group_entry) {
- struct list_head *list;
-
- list = ctx_group_list(event, ctx);
- list_move_tail(&sibling->group_entry, list);
+ if (list)
+ list_move_tail(&sibling->group_entry, list);
sibling->group_leader = sibling;
/* Inherit group flags from the previous leader */
@@ -652,8 +687,11 @@ group_sched_in(struct perf_event *group_event,
if (txn)
pmu->start_txn(pmu);
- if (event_sched_in(group_event, cpuctx, ctx))
+ if (event_sched_in(group_event, cpuctx, ctx)) {
+ if (txn)
+ pmu->cancel_txn(pmu);
return -EAGAIN;
+ }
/*
* Schedule in siblings as one group (if any):
@@ -675,9 +713,6 @@ group_sched_in(struct perf_event *group_event,
}
group_error:
- if (txn)
- pmu->cancel_txn(pmu);
-
/*
* Groups can be scheduled in as one unit only, so undo any
* partial group before returning:
@@ -689,6 +724,9 @@ group_error:
}
event_sched_out(group_event, cpuctx, ctx);
+ if (txn)
+ pmu->cancel_txn(pmu);
+
return -EAGAIN;
}
@@ -727,6 +765,7 @@ static void add_event_to_ctx(struct perf_event *event,
struct perf_event_context *ctx)
{
list_add_event(event, ctx);
+ perf_group_attach(event);
event->tstamp_enabled = ctx->time;
event->tstamp_running = ctx->time;
event->tstamp_stopped = ctx->time;
@@ -1841,6 +1880,7 @@ static void free_event_rcu(struct rcu_head *head)
}
static void perf_pending_sync(struct perf_event *event);
+static void perf_mmap_data_put(struct perf_mmap_data *data);
static void free_event(struct perf_event *event)
{
@@ -1856,9 +1896,9 @@ static void free_event(struct perf_event *event)
atomic_dec(&nr_task_events);
}
- if (event->output) {
- fput(event->output->filp);
- event->output = NULL;
+ if (event->data) {
+ perf_mmap_data_put(event->data);
+ event->data = NULL;
}
if (event->destroy)
@@ -1893,8 +1933,8 @@ int perf_event_release_kernel(struct perf_event *event)
*/
mutex_lock_nested(&ctx->mutex, SINGLE_DEPTH_NESTING);
raw_spin_lock_irq(&ctx->lock);
+ perf_group_detach(event);
list_del_event(event, ctx);
- perf_destroy_group(event, ctx);
raw_spin_unlock_irq(&ctx->lock);
mutex_unlock(&ctx->mutex);
@@ -2175,7 +2215,27 @@ unlock:
return ret;
}
-static int perf_event_set_output(struct perf_event *event, int output_fd);
+static const struct file_operations perf_fops;
+
+static struct perf_event *perf_fget_light(int fd, int *fput_needed)
+{
+ struct file *file;
+
+ file = fget_light(fd, fput_needed);
+ if (!file)
+ return ERR_PTR(-EBADF);
+
+ if (file->f_op != &perf_fops) {
+ fput_light(file, *fput_needed);
+ *fput_needed = 0;
+ return ERR_PTR(-EBADF);
+ }
+
+ return file->private_data;
+}
+
+static int perf_event_set_output(struct perf_event *event,
+ struct perf_event *output_event);
static int perf_event_set_filter(struct perf_event *event, void __user *arg);
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -2202,7 +2262,23 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return perf_event_period(event, (u64 __user *)arg);
case PERF_EVENT_IOC_SET_OUTPUT:
- return perf_event_set_output(event, arg);
+ {
+ struct perf_event *output_event = NULL;
+ int fput_needed = 0;
+ int ret;
+
+ if (arg != -1) {
+ output_event = perf_fget_light(arg, &fput_needed);
+ if (IS_ERR(output_event))
+ return PTR_ERR(output_event);
+ }
+
+ ret = perf_event_set_output(event, output_event);
+ if (output_event)
+ fput_light(output_event->filp, fput_needed);
+
+ return ret;
+ }
case PERF_EVENT_IOC_SET_FILTER:
return perf_event_set_filter(event, (void __user *)arg);
@@ -2335,8 +2411,6 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
unsigned long size;
int i;
- WARN_ON(atomic_read(&event->mmap_count));
-
size = sizeof(struct perf_mmap_data);
size += nr_pages * sizeof(void *);
@@ -2452,8 +2526,6 @@ perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
unsigned long size;
void *all_buf;
- WARN_ON(atomic_read(&event->mmap_count));
-
size = sizeof(struct perf_mmap_data);
size += sizeof(void *);
@@ -2536,7 +2608,7 @@ perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data)
if (!data->watermark)
data->watermark = max_size / 2;
-
+ atomic_set(&data->refcount, 1);
rcu_assign_pointer(event->data, data);
}
@@ -2548,13 +2620,26 @@ static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head)
perf_mmap_data_free(data);
}
-static void perf_mmap_data_release(struct perf_event *event)
+static struct perf_mmap_data *perf_mmap_data_get(struct perf_event *event)
{
- struct perf_mmap_data *data = event->data;
+ struct perf_mmap_data *data;
- WARN_ON(atomic_read(&event->mmap_count));
+ rcu_read_lock();
+ data = rcu_dereference(event->data);
+ if (data) {
+ if (!atomic_inc_not_zero(&data->refcount))
+ data = NULL;
+ }
+ rcu_read_unlock();
+
+ return data;
+}
+
+static void perf_mmap_data_put(struct perf_mmap_data *data)
+{
+ if (!atomic_dec_and_test(&data->refcount))
+ return;
- rcu_assign_pointer(event->data, NULL);
call_rcu(&data->rcu_head, perf_mmap_data_free_rcu);
}
@@ -2569,15 +2654,18 @@ static void perf_mmap_close(struct vm_area_struct *vma)
{
struct perf_event *event = vma->vm_file->private_data;
- WARN_ON_ONCE(event->ctx->parent_ctx);
if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) {
unsigned long size = perf_data_size(event->data);
- struct user_struct *user = current_user();
+ struct user_struct *user = event->mmap_user;
+ struct perf_mmap_data *data = event->data;
atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm);
- vma->vm_mm->locked_vm -= event->data->nr_locked;
- perf_mmap_data_release(event);
+ vma->vm_mm->locked_vm -= event->mmap_locked;
+ rcu_assign_pointer(event->data, NULL);
mutex_unlock(&event->mmap_mutex);
+
+ perf_mmap_data_put(data);
+ free_uid(user);
}
}
@@ -2629,13 +2717,10 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
WARN_ON_ONCE(event->ctx->parent_ctx);
mutex_lock(&event->mmap_mutex);
- if (event->output) {
- ret = -EINVAL;
- goto unlock;
- }
-
- if (atomic_inc_not_zero(&event->mmap_count)) {
- if (nr_pages != event->data->nr_pages)
+ if (event->data) {
+ if (event->data->nr_pages == nr_pages)
+ atomic_inc(&event->data->refcount);
+ else
ret = -EINVAL;
goto unlock;
}
@@ -2667,21 +2752,23 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
WARN_ON(event->data);
data = perf_mmap_data_alloc(event, nr_pages);
- ret = -ENOMEM;
- if (!data)
+ if (!data) {
+ ret = -ENOMEM;
goto unlock;
+ }
- ret = 0;
perf_mmap_data_init(event, data);
-
- atomic_set(&event->mmap_count, 1);
- atomic_long_add(user_extra, &user->locked_vm);
- vma->vm_mm->locked_vm += extra;
- event->data->nr_locked = extra;
if (vma->vm_flags & VM_WRITE)
event->data->writable = 1;
+ atomic_long_add(user_extra, &user->locked_vm);
+ event->mmap_locked = extra;
+ event->mmap_user = get_current_user();
+ vma->vm_mm->locked_vm += event->mmap_locked;
+
unlock:
+ if (!ret)
+ atomic_inc(&event->mmap_count);
mutex_unlock(&event->mmap_mutex);
vma->vm_flags |= VM_RESERVED;
@@ -2977,6 +3064,7 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle,
len -= size;
handle->addr += size;
+ buf += size;
handle->size -= size;
if (!handle->size) {
struct perf_mmap_data *data = handle->data;
@@ -2993,7 +3081,6 @@ int perf_output_begin(struct perf_output_handle *handle,
struct perf_event *event, unsigned int size,
int nmi, int sample)
{
- struct perf_event *output_event;
struct perf_mmap_data *data;
unsigned long tail, offset, head;
int have_lost;
@@ -3010,10 +3097,6 @@ int perf_output_begin(struct perf_output_handle *handle,
if (event->parent)
event = event->parent;
- output_event = rcu_dereference(event->output);
- if (output_event)
- event = output_event;
-
data = rcu_dereference(event->data);
if (!data)
goto out;
@@ -3972,13 +4055,6 @@ static void perf_swevent_overflow(struct perf_event *event, u64 overflow,
}
}
-static void perf_swevent_unthrottle(struct perf_event *event)
-{
- /*
- * Nothing to do, we already reset hwc->interrupts.
- */
-}
-
static void perf_swevent_add(struct perf_event *event, u64 nr,
int nmi, struct perf_sample_data *data,
struct pt_regs *regs)
@@ -4193,11 +4269,22 @@ static void perf_swevent_disable(struct perf_event *event)
hlist_del_rcu(&event->hlist_entry);
}
+static void perf_swevent_void(struct perf_event *event)
+{
+}
+
+static int perf_swevent_int(struct perf_event *event)
+{
+ return 0;
+}
+
static const struct pmu perf_ops_generic = {
.enable = perf_swevent_enable,
.disable = perf_swevent_disable,
+ .start = perf_swevent_int,
+ .stop = perf_swevent_void,
.read = perf_swevent_read,
- .unthrottle = perf_swevent_unthrottle,
+ .unthrottle = perf_swevent_void, /* hwc->interrupts already reset */
};
/*
@@ -4478,8 +4565,10 @@ static int swevent_hlist_get(struct perf_event *event)
static const struct pmu perf_ops_tracepoint = {
.enable = perf_trace_enable,
.disable = perf_trace_disable,
+ .start = perf_swevent_int,
+ .stop = perf_swevent_void,
.read = perf_swevent_read,
- .unthrottle = perf_swevent_unthrottle,
+ .unthrottle = perf_swevent_void,
};
static int perf_tp_filter_match(struct perf_event *event,
@@ -4912,39 +5001,17 @@ err_size:
goto out;
}
-static int perf_event_set_output(struct perf_event *event, int output_fd)
+static int
+perf_event_set_output(struct perf_event *event, struct perf_event *output_event)
{
- struct perf_event *output_event = NULL;
- struct file *output_file = NULL;
- struct perf_event *old_output;
- int fput_needed = 0;
+ struct perf_mmap_data *data = NULL, *old_data = NULL;
int ret = -EINVAL;
- /*
- * Don't allow output of inherited per-task events. This would
- * create performance issues due to cross cpu access.
- */
- if (event->cpu == -1 && event->attr.inherit)
- return -EINVAL;
-
- if (!output_fd)
+ if (!output_event)
goto set;
- output_file = fget_light(output_fd, &fput_needed);
- if (!output_file)
- return -EBADF;
-
- if (output_file->f_op != &perf_fops)
- goto out;
-
- output_event = output_file->private_data;
-
- /* Don't chain output fds */
- if (output_event->output)
- goto out;
-
- /* Don't set an output fd when we already have an output channel */
- if (event->data)
+ /* don't allow circular references */
+ if (event == output_event)
goto out;
/*
@@ -4959,26 +5026,28 @@ static int perf_event_set_output(struct perf_event *event, int output_fd)
if (output_event->cpu == -1 && output_event->ctx != event->ctx)
goto out;
- atomic_long_inc(&output_file->f_count);
-
set:
mutex_lock(&event->mmap_mutex);
- old_output = event->output;
- rcu_assign_pointer(event->output, output_event);
- mutex_unlock(&event->mmap_mutex);
+ /* Can't redirect output if we've got an active mmap() */
+ if (atomic_read(&event->mmap_count))
+ goto unlock;
- if (old_output) {
- /*
- * we need to make sure no existing perf_output_*()
- * is still referencing this event.
- */
- synchronize_rcu();
- fput(old_output->filp);
+ if (output_event) {
+ /* get the buffer we want to redirect to */
+ data = perf_mmap_data_get(output_event);
+ if (!data)
+ goto unlock;
}
+ old_data = event->data;
+ rcu_assign_pointer(event->data, data);
ret = 0;
+unlock:
+ mutex_unlock(&event->mmap_mutex);
+
+ if (old_data)
+ perf_mmap_data_put(old_data);
out:
- fput_light(output_file, fput_needed);
return ret;
}
@@ -4994,7 +5063,7 @@ SYSCALL_DEFINE5(perf_event_open,
struct perf_event_attr __user *, attr_uptr,
pid_t, pid, int, cpu, int, group_fd, unsigned long, flags)
{
- struct perf_event *event, *group_leader;
+ struct perf_event *event, *group_leader = NULL, *output_event = NULL;
struct perf_event_attr attr;
struct perf_event_context *ctx;
struct file *event_file = NULL;
@@ -5034,19 +5103,25 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_fd;
}
+ if (group_fd != -1) {
+ group_leader = perf_fget_light(group_fd, &fput_needed);
+ if (IS_ERR(group_leader)) {
+ err = PTR_ERR(group_leader);
+ goto err_put_context;
+ }
+ group_file = group_leader->filp;
+ if (flags & PERF_FLAG_FD_OUTPUT)
+ output_event = group_leader;
+ if (flags & PERF_FLAG_FD_NO_GROUP)
+ group_leader = NULL;
+ }
+
/*
* Look up the group leader (we will attach this event to it):
*/
- group_leader = NULL;
- if (group_fd != -1 && !(flags & PERF_FLAG_FD_NO_GROUP)) {
+ if (group_leader) {
err = -EINVAL;
- group_file = fget_light(group_fd, &fput_needed);
- if (!group_file)
- goto err_put_context;
- if (group_file->f_op != &perf_fops)
- goto err_put_context;
- group_leader = group_file->private_data;
/*
* Do not allow a recursive hierarchy (this new sibling
* becoming part of another group-sibling):
@@ -5068,9 +5143,16 @@ SYSCALL_DEFINE5(perf_event_open,
event = perf_event_alloc(&attr, cpu, ctx, group_leader,
NULL, NULL, GFP_KERNEL);
- err = PTR_ERR(event);
- if (IS_ERR(event))
+ if (IS_ERR(event)) {
+ err = PTR_ERR(event);
goto err_put_context;
+ }
+
+ if (output_event) {
+ err = perf_event_set_output(event, output_event);
+ if (err)
+ goto err_free_put_context;
+ }
event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
if (IS_ERR(event_file)) {
@@ -5078,12 +5160,6 @@ SYSCALL_DEFINE5(perf_event_open,
goto err_free_put_context;
}
- if (flags & PERF_FLAG_FD_OUTPUT) {
- err = perf_event_set_output(event, group_fd);
- if (err)
- goto err_fput_free_put_context;
- }
-
event->filp = event_file;
WARN_ON_ONCE(ctx->parent_ctx);
mutex_lock(&ctx->mutex);
@@ -5097,12 +5173,16 @@ SYSCALL_DEFINE5(perf_event_open,
list_add_tail(&event->owner_entry, &current->perf_event_list);
mutex_unlock(&current->perf_event_mutex);
+ /*
+ * Drop the reference on the group_event after placing the
+ * new event on the sibling_list. This ensures destruction
+ * of the group leader will find the pointer to itself in
+ * perf_group_detach().
+ */
fput_light(group_file, fput_needed);
fd_install(event_fd, event_file);
return event_fd;
-err_fput_free_put_context:
- fput(event_file);
err_free_put_context:
free_event(event);
err_put_context:
@@ -5420,6 +5500,7 @@ static void perf_free_event(struct perf_event *event,
fput(parent->filp);
+ perf_group_detach(event);
list_del_event(event, ctx);
free_event(event);
}
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 5c36ea9d55d2..ca6066a6952e 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -99,9 +99,13 @@ config PM_SLEEP_ADVANCED_DEBUG
depends on PM_ADVANCED_DEBUG
default n
+config SUSPEND_NVS
+ bool
+
config SUSPEND
bool "Suspend to RAM and standby"
depends on PM && ARCH_SUSPEND_POSSIBLE
+ select SUSPEND_NVS if HAS_IOMEM
default y
---help---
Allow the system to enter sleep states in which main memory is
@@ -130,13 +134,10 @@ config SUSPEND_FREEZER
Turning OFF this setting is NOT recommended! If in doubt, say Y.
-config HIBERNATION_NVS
- bool
-
config HIBERNATION
bool "Hibernation (aka 'suspend to disk')"
depends on PM && SWAP && ARCH_HIBERNATION_POSSIBLE
- select HIBERNATION_NVS if HAS_IOMEM
+ select SUSPEND_NVS if HAS_IOMEM
---help---
Enable the suspend to disk (STD) functionality, which is usually
called "hibernation" in user interfaces. STD checkpoints the
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index 524e058dcf06..f9063c6b185d 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -10,6 +10,6 @@ obj-$(CONFIG_SUSPEND) += suspend.o
obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o
obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o \
block_io.o
-obj-$(CONFIG_HIBERNATION_NVS) += hibernate_nvs.o
+obj-$(CONFIG_SUSPEND_NVS) += nvs.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/hibernate_nvs.c b/kernel/power/nvs.c
index fdcad9ed5a7b..1836db60bbb6 100644
--- a/kernel/power/hibernate_nvs.c
+++ b/kernel/power/nvs.c
@@ -15,7 +15,7 @@
/*
* Platforms, like ACPI, may want us to save some memory used by them during
- * hibernation and to restore the contents of this memory during the subsequent
+ * suspend and to restore the contents of this memory during the subsequent
* resume. The code below implements a mechanism allowing us to do that.
*/
@@ -30,7 +30,7 @@ struct nvs_page {
static LIST_HEAD(nvs_list);
/**
- * hibernate_nvs_register - register platform NVS memory region to save
+ * suspend_nvs_register - register platform NVS memory region to save
* @start - physical address of the region
* @size - size of the region
*
@@ -38,7 +38,7 @@ static LIST_HEAD(nvs_list);
* things so that the data from page-aligned addresses in this region will
* be copied into separate RAM pages.
*/
-int hibernate_nvs_register(unsigned long start, unsigned long size)
+int suspend_nvs_register(unsigned long start, unsigned long size)
{
struct nvs_page *entry, *next;
@@ -68,9 +68,9 @@ int hibernate_nvs_register(unsigned long start, unsigned long size)
}
/**
- * hibernate_nvs_free - free data pages allocated for saving NVS regions
+ * suspend_nvs_free - free data pages allocated for saving NVS regions
*/
-void hibernate_nvs_free(void)
+void suspend_nvs_free(void)
{
struct nvs_page *entry;
@@ -86,16 +86,16 @@ void hibernate_nvs_free(void)
}
/**
- * hibernate_nvs_alloc - allocate memory necessary for saving NVS regions
+ * suspend_nvs_alloc - allocate memory necessary for saving NVS regions
*/
-int hibernate_nvs_alloc(void)
+int suspend_nvs_alloc(void)
{
struct nvs_page *entry;
list_for_each_entry(entry, &nvs_list, node) {
entry->data = (void *)__get_free_page(GFP_KERNEL);
if (!entry->data) {
- hibernate_nvs_free();
+ suspend_nvs_free();
return -ENOMEM;
}
}
@@ -103,9 +103,9 @@ int hibernate_nvs_alloc(void)
}
/**
- * hibernate_nvs_save - save NVS memory regions
+ * suspend_nvs_save - save NVS memory regions
*/
-void hibernate_nvs_save(void)
+void suspend_nvs_save(void)
{
struct nvs_page *entry;
@@ -119,12 +119,12 @@ void hibernate_nvs_save(void)
}
/**
- * hibernate_nvs_restore - restore NVS memory regions
+ * suspend_nvs_restore - restore NVS memory regions
*
* This function is going to be called with interrupts disabled, so it
* cannot iounmap the virtual addresses used to access the NVS region.
*/
-void hibernate_nvs_restore(void)
+void suspend_nvs_restore(void)
{
struct nvs_page *entry;
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c
index 56e7dbb8b996..f37cb7dd4402 100644
--- a/kernel/power/suspend.c
+++ b/kernel/power/suspend.c
@@ -16,6 +16,12 @@
#include <linux/cpu.h>
#include <linux/syscalls.h>
#include <linux/gfp.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
#include "power.h"
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index b0bb21778391..7c3ae83e41d7 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -32,7 +32,7 @@
/*
* The swap map is a data structure used for keeping track of each page
* written to a swap partition. It consists of many swap_map_page
- * structures that contain each an array of MAP_PAGE_SIZE swap entries.
+ * structures that contain each an array of MAP_PAGE_ENTRIES swap entries.
* These structures are stored on the swap and linked together with the
* help of the .next_swap member.
*
@@ -148,7 +148,7 @@ sector_t alloc_swapdev_block(int swap)
/**
* free_all_swap_pages - free swap pages allocated for saving image data.
- * It also frees the extents used to register which swap entres had been
+ * It also frees the extents used to register which swap entries had been
* allocated.
*/
diff --git a/kernel/printk.c b/kernel/printk.c
index 444b770c9595..569a7c2489b1 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -37,6 +37,8 @@
#include <linux/ratelimit.h>
#include <linux/kmsg_dump.h>
#include <linux/syslog.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
#include <asm/uaccess.h>
@@ -985,6 +987,29 @@ void resume_console(void)
}
/**
+ * console_cpu_notify - print deferred console messages after CPU hotplug
+ * @self: notifier struct
+ * @action: CPU hotplug event
+ * @hcpu: unused
+ *
+ * If printk() is called from a CPU that is not online yet, the messages
+ * will be spooled but will not show up on the console. This function is
+ * called when a new CPU comes online (or fails to come up), and ensures
+ * that any such output gets printed.
+ */
+static int __cpuinit console_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_UP_CANCELED:
+ acquire_console_sem();
+ release_console_sem();
+ }
+ return NOTIFY_OK;
+}
+
+/**
* acquire_console_sem - lock the console system for exclusive use.
*
* Acquires a semaphore which guarantees that the caller has
@@ -1371,7 +1396,7 @@ int unregister_console(struct console *console)
}
EXPORT_SYMBOL(unregister_console);
-static int __init disable_boot_consoles(void)
+static int __init printk_late_init(void)
{
struct console *con;
@@ -1382,9 +1407,10 @@ static int __init disable_boot_consoles(void)
unregister_console(con);
}
}
+ hotcpu_notifier(console_cpu_notify, 0);
return 0;
}
-late_initcall(disable_boot_consoles);
+late_initcall(printk_late_init);
#if defined CONFIG_PRINTK
diff --git a/kernel/sched.c b/kernel/sched.c
index d48408142503..f8b8996228dd 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -544,6 +544,8 @@ struct rq {
struct root_domain *rd;
struct sched_domain *sd;
+ unsigned long cpu_power;
+
unsigned char idle_at_tick;
/* For active balancing */
int post_schedule;
@@ -1499,24 +1501,9 @@ static unsigned long target_load(int cpu, int type)
return max(rq->cpu_load[type-1], total);
}
-static struct sched_group *group_of(int cpu)
-{
- struct sched_domain *sd = rcu_dereference_sched(cpu_rq(cpu)->sd);
-
- if (!sd)
- return NULL;
-
- return sd->groups;
-}
-
static unsigned long power_of(int cpu)
{
- struct sched_group *group = group_of(cpu);
-
- if (!group)
- return SCHED_LOAD_SCALE;
-
- return group->cpu_power;
+ return cpu_rq(cpu)->cpu_power;
}
static int task_hot(struct task_struct *p, u64 now, struct sched_domain *sd);
@@ -1854,8 +1841,8 @@ static void dec_nr_running(struct rq *rq)
static void set_load_weight(struct task_struct *p)
{
if (task_has_rt_policy(p)) {
- p->se.load.weight = prio_to_weight[0] * 2;
- p->se.load.inv_weight = prio_to_wmult[0] >> 1;
+ p->se.load.weight = 0;
+ p->se.load.inv_weight = WMULT_CONST;
return;
}
@@ -7605,6 +7592,7 @@ void __init sched_init(void)
#ifdef CONFIG_SMP
rq->sd = NULL;
rq->rd = NULL;
+ rq->cpu_power = SCHED_LOAD_SCALE;
rq->post_schedule = 0;
rq->active_balance = 0;
rq->next_balance = jiffies;
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 217e4a9393e4..eed35eded602 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -1225,7 +1225,6 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
unsigned long this_load, load;
int idx, this_cpu, prev_cpu;
unsigned long tl_per_task;
- unsigned int imbalance;
struct task_group *tg;
unsigned long weight;
int balanced;
@@ -1252,8 +1251,6 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
tg = task_group(p);
weight = p->se.load.weight;
- imbalance = 100 + (sd->imbalance_pct - 100) / 2;
-
/*
* In low-load situations, where prev_cpu is idle and this_cpu is idle
* due to the sync cause above having dropped this_load to 0, we'll
@@ -1263,9 +1260,21 @@ static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
* Otherwise check if either cpus are near enough in load to allow this
* task to be woken on this_cpu.
*/
- balanced = !this_load ||
- 100*(this_load + effective_load(tg, this_cpu, weight, weight)) <=
- imbalance*(load + effective_load(tg, prev_cpu, 0, weight));
+ if (this_load) {
+ unsigned long this_eff_load, prev_eff_load;
+
+ this_eff_load = 100;
+ this_eff_load *= power_of(prev_cpu);
+ this_eff_load *= this_load +
+ effective_load(tg, this_cpu, weight, weight);
+
+ prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2;
+ prev_eff_load *= power_of(this_cpu);
+ prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight);
+
+ balanced = this_eff_load <= prev_eff_load;
+ } else
+ balanced = true;
/*
* If the currently running task will sleep within
@@ -2298,6 +2307,7 @@ static void update_cpu_power(struct sched_domain *sd, int cpu)
if (!power)
power = 1;
+ cpu_rq(cpu)->cpu_power = power;
sdg->cpu_power = power;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 825e1126008f..07b4f1b1a73a 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -850,7 +850,7 @@ static __init int spawn_ksoftirqd(void)
void *cpu = (void *)(long)smp_processor_id();
int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
- BUG_ON(err == NOTIFY_BAD);
+ BUG_ON(err != NOTIFY_OK);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
register_cpu_notifier(&cpu_nfb);
return 0;
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
deleted file mode 100644
index 4b493f67dcb5..000000000000
--- a/kernel/softlockup.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * Detect Soft Lockups
- *
- * started by Ingo Molnar, Copyright (C) 2005, 2006 Red Hat, Inc.
- *
- * this code detects soft lockups: incidents in where on a CPU
- * the kernel does not reschedule for 10 seconds or more.
- */
-#include <linux/mm.h>
-#include <linux/cpu.h>
-#include <linux/nmi.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
-#include <linux/lockdep.h>
-#include <linux/notifier.h>
-#include <linux/module.h>
-#include <linux/sysctl.h>
-
-#include <asm/irq_regs.h>
-
-static DEFINE_SPINLOCK(print_lock);
-
-static DEFINE_PER_CPU(unsigned long, softlockup_touch_ts); /* touch timestamp */
-static DEFINE_PER_CPU(unsigned long, softlockup_print_ts); /* print timestamp */
-static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
-static DEFINE_PER_CPU(bool, softlock_touch_sync);
-
-static int __read_mostly did_panic;
-int __read_mostly softlockup_thresh = 60;
-
-/*
- * Should we panic (and reboot, if panic_timeout= is set) when a
- * soft-lockup occurs:
- */
-unsigned int __read_mostly softlockup_panic =
- CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
-
-static int __init softlockup_panic_setup(char *str)
-{
- softlockup_panic = simple_strtoul(str, NULL, 0);
-
- return 1;
-}
-__setup("softlockup_panic=", softlockup_panic_setup);
-
-static int
-softlock_panic(struct notifier_block *this, unsigned long event, void *ptr)
-{
- did_panic = 1;
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
- .notifier_call = softlock_panic,
-};
-
-/*
- * Returns seconds, approximately. We don't need nanosecond
- * resolution, and we don't need to waste time with a big divide when
- * 2^30ns == 1.074s.
- */
-static unsigned long get_timestamp(int this_cpu)
-{
- return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
-}
-
-static void __touch_softlockup_watchdog(void)
-{
- int this_cpu = raw_smp_processor_id();
-
- __raw_get_cpu_var(softlockup_touch_ts) = get_timestamp(this_cpu);
-}
-
-void touch_softlockup_watchdog(void)
-{
- __raw_get_cpu_var(softlockup_touch_ts) = 0;
-}
-EXPORT_SYMBOL(touch_softlockup_watchdog);
-
-void touch_softlockup_watchdog_sync(void)
-{
- __raw_get_cpu_var(softlock_touch_sync) = true;
- __raw_get_cpu_var(softlockup_touch_ts) = 0;
-}
-
-void touch_all_softlockup_watchdogs(void)
-{
- int cpu;
-
- /* Cause each CPU to re-update its timestamp rather than complain */
- for_each_online_cpu(cpu)
- per_cpu(softlockup_touch_ts, cpu) = 0;
-}
-EXPORT_SYMBOL(touch_all_softlockup_watchdogs);
-
-int proc_dosoftlockup_thresh(struct ctl_table *table, int write,
- void __user *buffer,
- size_t *lenp, loff_t *ppos)
-{
- touch_all_softlockup_watchdogs();
- return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-}
-
-/*
- * This callback runs from the timer interrupt, and checks
- * whether the watchdog thread has hung or not:
- */
-void softlockup_tick(void)
-{
- int this_cpu = smp_processor_id();
- unsigned long touch_ts = per_cpu(softlockup_touch_ts, this_cpu);
- unsigned long print_ts;
- struct pt_regs *regs = get_irq_regs();
- unsigned long now;
-
- /* Is detection switched off? */
- if (!per_cpu(softlockup_watchdog, this_cpu) || softlockup_thresh <= 0) {
- /* Be sure we don't false trigger if switched back on */
- if (touch_ts)
- per_cpu(softlockup_touch_ts, this_cpu) = 0;
- return;
- }
-
- if (touch_ts == 0) {
- if (unlikely(per_cpu(softlock_touch_sync, this_cpu))) {
- /*
- * If the time stamp was touched atomically
- * make sure the scheduler tick is up to date.
- */
- per_cpu(softlock_touch_sync, this_cpu) = false;
- sched_clock_tick();
- }
- __touch_softlockup_watchdog();
- return;
- }
-
- print_ts = per_cpu(softlockup_print_ts, this_cpu);
-
- /* report at most once a second */
- if (print_ts == touch_ts || did_panic)
- return;
-
- /* do not print during early bootup: */
- if (unlikely(system_state != SYSTEM_RUNNING)) {
- __touch_softlockup_watchdog();
- return;
- }
-
- now = get_timestamp(this_cpu);
-
- /*
- * Wake up the high-prio watchdog task twice per
- * threshold timespan.
- */
- if (time_after(now - softlockup_thresh/2, touch_ts))
- wake_up_process(per_cpu(softlockup_watchdog, this_cpu));
-
- /* Warn about unreasonable delays: */
- if (time_before_eq(now - softlockup_thresh, touch_ts))
- return;
-
- per_cpu(softlockup_print_ts, this_cpu) = touch_ts;
-
- spin_lock(&print_lock);
- printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %lus! [%s:%d]\n",
- this_cpu, now - touch_ts,
- current->comm, task_pid_nr(current));
- print_modules();
- print_irqtrace_events(current);
- if (regs)
- show_regs(regs);
- else
- dump_stack();
- spin_unlock(&print_lock);
-
- if (softlockup_panic)
- panic("softlockup: hung tasks");
-}
-
-/*
- * The watchdog thread - runs every second and touches the timestamp.
- */
-static int watchdog(void *__bind_cpu)
-{
- struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
-
- sched_setscheduler(current, SCHED_FIFO, &param);
-
- /* initialize timestamp */
- __touch_softlockup_watchdog();
-
- set_current_state(TASK_INTERRUPTIBLE);
- /*
- * Run briefly once per second to reset the softlockup timestamp.
- * If this gets delayed for more than 60 seconds then the
- * debug-printout triggers in softlockup_tick().
- */
- while (!kthread_should_stop()) {
- __touch_softlockup_watchdog();
- schedule();
-
- if (kthread_should_stop())
- break;
-
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
-
- return 0;
-}
-
-/*
- * Create/destroy watchdog threads as CPUs come and go:
- */
-static int __cpuinit
-cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
- int hotcpu = (unsigned long)hcpu;
- struct task_struct *p;
-
- switch (action) {
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
- BUG_ON(per_cpu(softlockup_watchdog, hotcpu));
- p = kthread_create(watchdog, hcpu, "watchdog/%d", hotcpu);
- if (IS_ERR(p)) {
- printk(KERN_ERR "watchdog for %i failed\n", hotcpu);
- return NOTIFY_BAD;
- }
- per_cpu(softlockup_touch_ts, hotcpu) = 0;
- per_cpu(softlockup_watchdog, hotcpu) = p;
- kthread_bind(p, hotcpu);
- break;
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- wake_up_process(per_cpu(softlockup_watchdog, hotcpu));
- break;
-#ifdef CONFIG_HOTPLUG_CPU
- case CPU_UP_CANCELED:
- case CPU_UP_CANCELED_FROZEN:
- if (!per_cpu(softlockup_watchdog, hotcpu))
- break;
- /* Unbind so it can run. Fall thru. */
- kthread_bind(per_cpu(softlockup_watchdog, hotcpu),
- cpumask_any(cpu_online_mask));
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
- p = per_cpu(softlockup_watchdog, hotcpu);
- per_cpu(softlockup_watchdog, hotcpu) = NULL;
- kthread_stop(p);
- break;
-#endif /* CONFIG_HOTPLUG_CPU */
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata cpu_nfb = {
- .notifier_call = cpu_callback
-};
-
-static int __initdata nosoftlockup;
-
-static int __init nosoftlockup_setup(char *str)
-{
- nosoftlockup = 1;
- return 1;
-}
-__setup("nosoftlockup", nosoftlockup_setup);
-
-static int __init spawn_softlockup_task(void)
-{
- void *cpu = (void *)(long)smp_processor_id();
- int err;
-
- if (nosoftlockup)
- return 0;
-
- err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
- if (err == NOTIFY_BAD) {
- BUG();
- return 1;
- }
- cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
- register_cpu_notifier(&cpu_nfb);
-
- atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
-
- return 0;
-}
-early_initcall(spawn_softlockup_task);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index b4e7431e7c78..70f8d90331e9 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -321,7 +321,7 @@ static int __cpuinit cpu_stop_cpu_callback(struct notifier_block *nfb,
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
- case CPU_DEAD:
+ case CPU_POST_DEAD:
{
struct cpu_stop_work *work;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 70f2ea758ffe..bad369ec5403 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -181,3 +181,7 @@ cond_syscall(sys_eventfd2);
/* performance counters: */
cond_syscall(sys_perf_event_open);
+
+/* fanotify! */
+cond_syscall(sys_fanotify_init);
+cond_syscall(sys_fanotify_mark);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 997080f00e0b..702709bca8c4 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -44,6 +44,7 @@
#include <linux/times.h>
#include <linux/limits.h>
#include <linux/dcache.h>
+#include <linux/dnotify.h>
#include <linux/syscalls.h>
#include <linux/vmstat.h>
#include <linux/nfs_fs.h>
@@ -76,6 +77,10 @@
#include <scsi/sg.h>
#endif
+#ifdef CONFIG_LOCKUP_DETECTOR
+#include <linux/nmi.h>
+#endif
+
#if defined(CONFIG_SYSCTL)
@@ -106,7 +111,7 @@ extern int blk_iopoll_enabled;
#endif
/* Constants used for minimum and maximum */
-#ifdef CONFIG_DETECT_SOFTLOCKUP
+#ifdef CONFIG_LOCKUP_DETECTOR
static int sixty = 60;
static int neg_one = -1;
#endif
@@ -130,6 +135,9 @@ static int min_percpu_pagelist_fract = 8;
static int ngroups_max = NGROUPS_MAX;
+#ifdef CONFIG_INOTIFY_USER
+#include <linux/inotify.h>
+#endif
#ifdef CONFIG_SPARC
#include <asm/system.h>
#endif
@@ -206,9 +214,6 @@ static struct ctl_table fs_table[];
static struct ctl_table debug_table[];
static struct ctl_table dev_table[];
extern struct ctl_table random_table[];
-#ifdef CONFIG_INOTIFY_USER
-extern struct ctl_table inotify_table[];
-#endif
#ifdef CONFIG_EPOLL
extern struct ctl_table epoll_table[];
#endif
@@ -710,7 +715,34 @@ static struct ctl_table kern_table[] = {
.mode = 0444,
.proc_handler = proc_dointvec,
},
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
+#if defined(CONFIG_LOCKUP_DETECTOR)
+ {
+ .procname = "watchdog",
+ .data = &watchdog_enabled,
+ .maxlen = sizeof (int),
+ .mode = 0644,
+ .proc_handler = proc_dowatchdog_enabled,
+ },
+ {
+ .procname = "watchdog_thresh",
+ .data = &softlockup_thresh,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dowatchdog_thresh,
+ .extra1 = &neg_one,
+ .extra2 = &sixty,
+ },
+ {
+ .procname = "softlockup_panic",
+ .data = &softlockup_panic,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
+#endif
+#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) && !defined(CONFIG_LOCKUP_DETECTOR)
{
.procname = "unknown_nmi_panic",
.data = &unknown_nmi_panic,
@@ -813,26 +845,6 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
-#ifdef CONFIG_DETECT_SOFTLOCKUP
- {
- .procname = "softlockup_panic",
- .data = &softlockup_panic,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_minmax,
- .extra1 = &zero,
- .extra2 = &one,
- },
- {
- .procname = "softlockup_thresh",
- .data = &softlockup_thresh,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dosoftlockup_thresh,
- .extra1 = &neg_one,
- .extra2 = &sixty,
- },
-#endif
#ifdef CONFIG_DETECT_HUNG_TASK
{
.procname = "hung_task_panic",
@@ -1471,12 +1483,12 @@ static struct ctl_table fs_table[] = {
},
#endif
{
- .procname = "pipe-max-pages",
- .data = &pipe_max_pages,
+ .procname = "pipe-max-size",
+ .data = &pipe_max_size,
.maxlen = sizeof(int),
.mode = 0644,
- .proc_handler = &proc_dointvec_minmax,
- .extra1 = &two,
+ .proc_handler = &pipe_proc_fn,
+ .extra1 = &pipe_min_size,
},
/*
* NOTE: do not add new entries to this table unless you have read
diff --git a/kernel/timer.c b/kernel/timer.c
index 2454172a80d3..c29e2d4d2a66 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1289,7 +1289,6 @@ void run_local_timers(void)
{
hrtimer_run_queues();
raise_softirq(TIMER_SOFTIRQ);
- softlockup_tick();
}
/*
@@ -1717,7 +1716,7 @@ void __init init_timers(void)
init_timer_stats();
- BUG_ON(err == NOTIFY_BAD);
+ BUG_ON(err != NOTIFY_OK);
register_cpu_notifier(&timers_nb);
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index 36ea2b65dcdc..638711c17504 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -842,6 +842,7 @@ static void blk_add_trace_split(void *ignore,
/**
* blk_add_trace_remap - Add a trace for a remap operation
+ * @ignore: trace callback data parameter (not used)
* @q: queue the io is for
* @bio: the source bio
* @dev: target device
@@ -873,6 +874,7 @@ static void blk_add_trace_remap(void *ignore,
/**
* blk_add_trace_rq_remap - Add a trace for a request-remap operation
+ * @ignore: trace callback data parameter (not used)
* @q: queue the io is for
* @rq: the source request
* @dev: target device
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index cb6f365016e4..e6f65887842c 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -116,7 +116,7 @@ int perf_trace_enable(struct perf_event *p_event)
if (WARN_ON_ONCE(!list))
return -EINVAL;
- list = per_cpu_ptr(list, smp_processor_id());
+ list = this_cpu_ptr(list);
hlist_add_head_rcu(&p_event->hlist_entry, list);
return 0;
@@ -132,8 +132,9 @@ void perf_trace_destroy(struct perf_event *p_event)
struct ftrace_event_call *tp_event = p_event->tp_event;
int i;
+ mutex_lock(&event_mutex);
if (--tp_event->perf_refcount > 0)
- return;
+ goto out;
if (tp_event->class->reg)
tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER);
@@ -142,6 +143,12 @@ void perf_trace_destroy(struct perf_event *p_event)
tp_event->class->perf_probe,
tp_event);
+ /*
+ * Ensure our callback won't be called anymore. See
+ * tracepoint_probe_unregister() and __DO_TRACE().
+ */
+ synchronize_sched();
+
free_percpu(tp_event->perf_events);
tp_event->perf_events = NULL;
@@ -151,6 +158,8 @@ void perf_trace_destroy(struct perf_event *p_event)
perf_trace_buf[i] = NULL;
}
}
+out:
+ mutex_unlock(&event_mutex);
}
__kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
@@ -169,7 +178,7 @@ __kprobes void *perf_trace_buf_prepare(int size, unsigned short type,
if (*rctxp < 0)
return NULL;
- raw_data = per_cpu_ptr(perf_trace_buf[*rctxp], smp_processor_id());
+ raw_data = this_cpu_ptr(perf_trace_buf[*rctxp]);
/* zero the dead bytes from align to not leak stack to user */
memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64));
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index faf7cefd15da..f52b5f50299d 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1359,7 +1359,7 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
for (i = 0; i < tp->nr_args; i++)
call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
- head = per_cpu_ptr(call->perf_events, smp_processor_id());
+ head = this_cpu_ptr(call->perf_events);
perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
}
@@ -1392,7 +1392,7 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
for (i = 0; i < tp->nr_args; i++)
call_fetch(&tp->args[i].fetch, regs, data + tp->args[i].offset);
- head = per_cpu_ptr(call->perf_events, smp_processor_id());
+ head = this_cpu_ptr(call->perf_events);
perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
}
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index d2c859cec9ea..34e35804304b 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -519,7 +519,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
syscall_get_arguments(current, regs, 0, sys_data->nb_args,
(unsigned long *)&rec->args);
- head = per_cpu_ptr(sys_data->enter_event->perf_events, smp_processor_id());
+ head = this_cpu_ptr(sys_data->enter_event->perf_events);
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
}
@@ -595,7 +595,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
rec->nr = syscall_nr;
rec->ret = syscall_get_return_value(current, regs);
- head = per_cpu_ptr(sys_data->exit_event->perf_events, smp_processor_id());
+ head = this_cpu_ptr(sys_data->exit_event->perf_events);
perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
new file mode 100644
index 000000000000..91b0b26adc67
--- /dev/null
+++ b/kernel/watchdog.c
@@ -0,0 +1,567 @@
+/*
+ * Detect hard and soft lockups on a system
+ *
+ * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc.
+ *
+ * this code detects hard lockups: incidents in where on a CPU
+ * the kernel does not respond to anything except NMI.
+ *
+ * Note: Most of this code is borrowed heavily from softlockup.c,
+ * so thanks to Ingo for the initial implementation.
+ * Some chunks also taken from arch/x86/kernel/apic/nmi.c, thanks
+ * to those contributors as well.
+ */
+
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/nmi.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
+#include <linux/lockdep.h>
+#include <linux/notifier.h>
+#include <linux/module.h>
+#include <linux/sysctl.h>
+
+#include <asm/irq_regs.h>
+#include <linux/perf_event.h>
+
+int watchdog_enabled;
+int __read_mostly softlockup_thresh = 60;
+
+static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
+static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
+static DEFINE_PER_CPU(struct hrtimer, watchdog_hrtimer);
+static DEFINE_PER_CPU(bool, softlockup_touch_sync);
+static DEFINE_PER_CPU(bool, soft_watchdog_warn);
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static DEFINE_PER_CPU(bool, hard_watchdog_warn);
+static DEFINE_PER_CPU(bool, watchdog_nmi_touch);
+static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts);
+static DEFINE_PER_CPU(unsigned long, hrtimer_interrupts_saved);
+static DEFINE_PER_CPU(struct perf_event *, watchdog_ev);
+#endif
+
+static int __read_mostly did_panic;
+static int __initdata no_watchdog;
+
+
+/* boot commands */
+/*
+ * Should we panic when a soft-lockup or hard-lockup occurs:
+ */
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static int hardlockup_panic;
+
+static int __init hardlockup_panic_setup(char *str)
+{
+ if (!strncmp(str, "panic", 5))
+ hardlockup_panic = 1;
+ return 1;
+}
+__setup("nmi_watchdog=", hardlockup_panic_setup);
+#endif
+
+unsigned int __read_mostly softlockup_panic =
+ CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE;
+
+static int __init softlockup_panic_setup(char *str)
+{
+ softlockup_panic = simple_strtoul(str, NULL, 0);
+
+ return 1;
+}
+__setup("softlockup_panic=", softlockup_panic_setup);
+
+static int __init nowatchdog_setup(char *str)
+{
+ no_watchdog = 1;
+ return 1;
+}
+__setup("nowatchdog", nowatchdog_setup);
+
+/* deprecated */
+static int __init nosoftlockup_setup(char *str)
+{
+ no_watchdog = 1;
+ return 1;
+}
+__setup("nosoftlockup", nosoftlockup_setup);
+/* */
+
+
+/*
+ * Returns seconds, approximately. We don't need nanosecond
+ * resolution, and we don't need to waste time with a big divide when
+ * 2^30ns == 1.074s.
+ */
+static unsigned long get_timestamp(int this_cpu)
+{
+ return cpu_clock(this_cpu) >> 30LL; /* 2^30 ~= 10^9 */
+}
+
+static unsigned long get_sample_period(void)
+{
+ /*
+ * convert softlockup_thresh from seconds to ns
+ * the divide by 5 is to give hrtimer 5 chances to
+ * increment before the hardlockup detector generates
+ * a warning
+ */
+ return softlockup_thresh / 5 * NSEC_PER_SEC;
+}
+
+/* Commands for resetting the watchdog */
+static void __touch_watchdog(void)
+{
+ int this_cpu = smp_processor_id();
+
+ __get_cpu_var(watchdog_touch_ts) = get_timestamp(this_cpu);
+}
+
+void touch_softlockup_watchdog(void)
+{
+ __get_cpu_var(watchdog_touch_ts) = 0;
+}
+EXPORT_SYMBOL(touch_softlockup_watchdog);
+
+void touch_all_softlockup_watchdogs(void)
+{
+ int cpu;
+
+ /*
+ * this is done lockless
+ * do we care if a 0 races with a timestamp?
+ * all it means is the softlock check starts one cycle later
+ */
+ for_each_online_cpu(cpu)
+ per_cpu(watchdog_touch_ts, cpu) = 0;
+}
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+void touch_nmi_watchdog(void)
+{
+ __get_cpu_var(watchdog_nmi_touch) = true;
+ touch_softlockup_watchdog();
+}
+EXPORT_SYMBOL(touch_nmi_watchdog);
+
+#endif
+
+void touch_softlockup_watchdog_sync(void)
+{
+ __raw_get_cpu_var(softlockup_touch_sync) = true;
+ __raw_get_cpu_var(watchdog_touch_ts) = 0;
+}
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+/* watchdog detector functions */
+static int is_hardlockup(void)
+{
+ unsigned long hrint = __get_cpu_var(hrtimer_interrupts);
+
+ if (__get_cpu_var(hrtimer_interrupts_saved) == hrint)
+ return 1;
+
+ __get_cpu_var(hrtimer_interrupts_saved) = hrint;
+ return 0;
+}
+#endif
+
+static int is_softlockup(unsigned long touch_ts)
+{
+ unsigned long now = get_timestamp(smp_processor_id());
+
+ /* Warn about unreasonable delays: */
+ if (time_after(now, touch_ts + softlockup_thresh))
+ return now - touch_ts;
+
+ return 0;
+}
+
+static int
+watchdog_panic(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ did_panic = 1;
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_block = {
+ .notifier_call = watchdog_panic,
+};
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static struct perf_event_attr wd_hw_attr = {
+ .type = PERF_TYPE_HARDWARE,
+ .config = PERF_COUNT_HW_CPU_CYCLES,
+ .size = sizeof(struct perf_event_attr),
+ .pinned = 1,
+ .disabled = 1,
+};
+
+/* Callback function for perf event subsystem */
+void watchdog_overflow_callback(struct perf_event *event, int nmi,
+ struct perf_sample_data *data,
+ struct pt_regs *regs)
+{
+ if (__get_cpu_var(watchdog_nmi_touch) == true) {
+ __get_cpu_var(watchdog_nmi_touch) = false;
+ return;
+ }
+
+ /* check for a hardlockup
+ * This is done by making sure our timer interrupt
+ * is incrementing. The timer interrupt should have
+ * fired multiple times before we overflow'd. If it hasn't
+ * then this is a good indication the cpu is stuck
+ */
+ if (is_hardlockup()) {
+ int this_cpu = smp_processor_id();
+
+ /* only print hardlockups once */
+ if (__get_cpu_var(hard_watchdog_warn) == true)
+ return;
+
+ if (hardlockup_panic)
+ panic("Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+ else
+ WARN(1, "Watchdog detected hard LOCKUP on cpu %d", this_cpu);
+
+ __get_cpu_var(hard_watchdog_warn) = true;
+ return;
+ }
+
+ __get_cpu_var(hard_watchdog_warn) = false;
+ return;
+}
+static void watchdog_interrupt_count(void)
+{
+ __get_cpu_var(hrtimer_interrupts)++;
+}
+#else
+static inline void watchdog_interrupt_count(void) { return; }
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
+/* watchdog kicker functions */
+static enum hrtimer_restart watchdog_timer_fn(struct hrtimer *hrtimer)
+{
+ unsigned long touch_ts = __get_cpu_var(watchdog_touch_ts);
+ struct pt_regs *regs = get_irq_regs();
+ int duration;
+
+ /* kick the hardlockup detector */
+ watchdog_interrupt_count();
+
+ /* kick the softlockup detector */
+ wake_up_process(__get_cpu_var(softlockup_watchdog));
+
+ /* .. and repeat */
+ hrtimer_forward_now(hrtimer, ns_to_ktime(get_sample_period()));
+
+ if (touch_ts == 0) {
+ if (unlikely(__get_cpu_var(softlockup_touch_sync))) {
+ /*
+ * If the time stamp was touched atomically
+ * make sure the scheduler tick is up to date.
+ */
+ __get_cpu_var(softlockup_touch_sync) = false;
+ sched_clock_tick();
+ }
+ __touch_watchdog();
+ return HRTIMER_RESTART;
+ }
+
+ /* check for a softlockup
+ * This is done by making sure a high priority task is
+ * being scheduled. The task touches the watchdog to
+ * indicate it is getting cpu time. If it hasn't then
+ * this is a good indication some task is hogging the cpu
+ */
+ duration = is_softlockup(touch_ts);
+ if (unlikely(duration)) {
+ /* only warn once */
+ if (__get_cpu_var(soft_watchdog_warn) == true)
+ return HRTIMER_RESTART;
+
+ printk(KERN_ERR "BUG: soft lockup - CPU#%d stuck for %us! [%s:%d]\n",
+ smp_processor_id(), duration,
+ current->comm, task_pid_nr(current));
+ print_modules();
+ print_irqtrace_events(current);
+ if (regs)
+ show_regs(regs);
+ else
+ dump_stack();
+
+ if (softlockup_panic)
+ panic("softlockup: hung tasks");
+ __get_cpu_var(soft_watchdog_warn) = true;
+ } else
+ __get_cpu_var(soft_watchdog_warn) = false;
+
+ return HRTIMER_RESTART;
+}
+
+
+/*
+ * The watchdog thread - touches the timestamp.
+ */
+static int watchdog(void *unused)
+{
+ struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+ struct hrtimer *hrtimer = &__raw_get_cpu_var(watchdog_hrtimer);
+
+ sched_setscheduler(current, SCHED_FIFO, &param);
+
+ /* initialize timestamp */
+ __touch_watchdog();
+
+ /* kick off the timer for the hardlockup detector */
+ /* done here because hrtimer_start can only pin to smp_processor_id() */
+ hrtimer_start(hrtimer, ns_to_ktime(get_sample_period()),
+ HRTIMER_MODE_REL_PINNED);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ /*
+ * Run briefly once per second to reset the softlockup timestamp.
+ * If this gets delayed for more than 60 seconds then the
+ * debug-printout triggers in watchdog_timer_fn().
+ */
+ while (!kthread_should_stop()) {
+ __touch_watchdog();
+ schedule();
+
+ if (kthread_should_stop())
+ break;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+
+#ifdef CONFIG_HARDLOCKUP_DETECTOR
+static int watchdog_nmi_enable(int cpu)
+{
+ struct perf_event_attr *wd_attr;
+ struct perf_event *event = per_cpu(watchdog_ev, cpu);
+
+ /* is it already setup and enabled? */
+ if (event && event->state > PERF_EVENT_STATE_OFF)
+ goto out;
+
+ /* it is setup but not enabled */
+ if (event != NULL)
+ goto out_enable;
+
+ /* Try to register using hardware perf events */
+ wd_attr = &wd_hw_attr;
+ wd_attr->sample_period = hw_nmi_get_sample_period();
+ event = perf_event_create_kernel_counter(wd_attr, cpu, -1, watchdog_overflow_callback);
+ if (!IS_ERR(event)) {
+ printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
+ goto out_save;
+ }
+
+ printk(KERN_ERR "NMI watchdog failed to create perf event on cpu%i: %p\n", cpu, event);
+ return -1;
+
+ /* success path */
+out_save:
+ per_cpu(watchdog_ev, cpu) = event;
+out_enable:
+ perf_event_enable(per_cpu(watchdog_ev, cpu));
+out:
+ return 0;
+}
+
+static void watchdog_nmi_disable(int cpu)
+{
+ struct perf_event *event = per_cpu(watchdog_ev, cpu);
+
+ if (event) {
+ perf_event_disable(event);
+ per_cpu(watchdog_ev, cpu) = NULL;
+
+ /* should be in cleanup, but blocks oprofile */
+ perf_event_release_kernel(event);
+ }
+ return;
+}
+#else
+static int watchdog_nmi_enable(int cpu) { return 0; }
+static void watchdog_nmi_disable(int cpu) { return; }
+#endif /* CONFIG_HARDLOCKUP_DETECTOR */
+
+/* prepare/enable/disable routines */
+static int watchdog_prepare_cpu(int cpu)
+{
+ struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
+
+ WARN_ON(per_cpu(softlockup_watchdog, cpu));
+ hrtimer_init(hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ hrtimer->function = watchdog_timer_fn;
+
+ return 0;
+}
+
+static int watchdog_enable(int cpu)
+{
+ struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
+
+ /* enable the perf event */
+ if (watchdog_nmi_enable(cpu) != 0)
+ return -1;
+
+ /* create the watchdog thread */
+ if (!p) {
+ p = kthread_create(watchdog, (void *)(unsigned long)cpu, "watchdog/%d", cpu);
+ if (IS_ERR(p)) {
+ printk(KERN_ERR "softlockup watchdog for %i failed\n", cpu);
+ return -1;
+ }
+ kthread_bind(p, cpu);
+ per_cpu(watchdog_touch_ts, cpu) = 0;
+ per_cpu(softlockup_watchdog, cpu) = p;
+ wake_up_process(p);
+ }
+
+ return 0;
+}
+
+static void watchdog_disable(int cpu)
+{
+ struct task_struct *p = per_cpu(softlockup_watchdog, cpu);
+ struct hrtimer *hrtimer = &per_cpu(watchdog_hrtimer, cpu);
+
+ /*
+ * cancel the timer first to stop incrementing the stats
+ * and waking up the kthread
+ */
+ hrtimer_cancel(hrtimer);
+
+ /* disable the perf event */
+ watchdog_nmi_disable(cpu);
+
+ /* stop the watchdog thread */
+ if (p) {
+ per_cpu(softlockup_watchdog, cpu) = NULL;
+ kthread_stop(p);
+ }
+
+ /* if any cpu succeeds, watchdog is considered enabled for the system */
+ watchdog_enabled = 1;
+}
+
+static void watchdog_enable_all_cpus(void)
+{
+ int cpu;
+ int result;
+
+ for_each_online_cpu(cpu)
+ result += watchdog_enable(cpu);
+
+ if (result)
+ printk(KERN_ERR "watchdog: failed to be enabled on some cpus\n");
+
+}
+
+static void watchdog_disable_all_cpus(void)
+{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ watchdog_disable(cpu);
+
+ /* if all watchdogs are disabled, then they are disabled for the system */
+ watchdog_enabled = 0;
+}
+
+
+/* sysctl functions */
+#ifdef CONFIG_SYSCTL
+/*
+ * proc handler for /proc/sys/kernel/nmi_watchdog
+ */
+
+int proc_dowatchdog_enabled(struct ctl_table *table, int write,
+ void __user *buffer, size_t *length, loff_t *ppos)
+{
+ proc_dointvec(table, write, buffer, length, ppos);
+
+ if (watchdog_enabled)
+ watchdog_enable_all_cpus();
+ else
+ watchdog_disable_all_cpus();
+ return 0;
+}
+
+int proc_dowatchdog_thresh(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+}
+#endif /* CONFIG_SYSCTL */
+
+
+/*
+ * Create/destroy watchdog threads as CPUs come and go:
+ */
+static int __cpuinit
+cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ int hotcpu = (unsigned long)hcpu;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ if (watchdog_prepare_cpu(hotcpu))
+ return NOTIFY_BAD;
+ break;
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ if (watchdog_enable(hotcpu))
+ return NOTIFY_BAD;
+ break;
+#ifdef CONFIG_HOTPLUG_CPU
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
+ watchdog_disable(hotcpu);
+ break;
+ case CPU_DEAD:
+ case CPU_DEAD_FROZEN:
+ watchdog_disable(hotcpu);
+ break;
+#endif /* CONFIG_HOTPLUG_CPU */
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_nfb = {
+ .notifier_call = cpu_callback
+};
+
+static int __init spawn_watchdog_task(void)
+{
+ void *cpu = (void *)(long)smp_processor_id();
+ int err;
+
+ if (no_watchdog)
+ return 0;
+
+ err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+ WARN_ON(err == NOTIFY_BAD);
+
+ cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
+ register_cpu_notifier(&cpu_nfb);
+
+ atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
+
+ return 0;
+}
+early_initcall(spawn_watchdog_task);
diff --git a/lib/Kconfig b/lib/Kconfig
index 170d8ca901d8..af12831f2eea 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -210,4 +210,25 @@ config GENERIC_ATOMIC64
config LRU_CACHE
tristate
+config SHM_SIGNAL
+ tristate "SHM Signal - Generic shared-memory signaling mechanism"
+ default n
+ help
+ Provides a shared-memory based signaling mechanism to indicate
+ memory-dirty notifications between two end-points.
+
+ If unsure, say N
+
+config IOQ
+ tristate "IO-Queue library - Generic shared-memory queue"
+ select SHM_SIGNAL
+ default n
+ help
+ IOQ is a generic shared-memory-queue mechanism that happens to be
+ friendly to virtualization boundaries. It can be used in a variety
+ of ways, though its intended purpose is to become a low-level
+ communication path for paravirtualized drivers.
+
+ If unsure, say N
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index e722e9d62221..e2cd7fbf31c0 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -152,28 +152,33 @@ config DEBUG_SHIRQ
Drivers ought to be able to handle interrupts coming in at those
points; some don't and need to be caught.
-config DETECT_SOFTLOCKUP
- bool "Detect Soft Lockups"
+config LOCKUP_DETECTOR
+ bool "Detect Hard and Soft Lockups"
depends on DEBUG_KERNEL && !S390
- default y
help
- Say Y here to enable the kernel to detect "soft lockups",
- which are bugs that cause the kernel to loop in kernel
+ Say Y here to enable the kernel to act as a watchdog to detect
+ hard and soft lockups.
+
+ Softlockups are bugs that cause the kernel to loop in kernel
mode for more than 60 seconds, without giving other tasks a
- chance to run.
+ chance to run. The current stack trace is displayed upon
+ detection and the system will stay locked up.
- When a soft-lockup is detected, the kernel will print the
- current stack trace (which you should report), but the
- system will stay locked up. This feature has negligible
- overhead.
+ Hardlockups are bugs that cause the CPU to loop in kernel mode
+ for more than 60 seconds, without letting other interrupts have a
+ chance to run. The current stack trace is displayed upon detection
+ and the system will stay locked up.
+
+ The overhead should be minimal. A periodic hrtimer runs to
+ generate interrupts and kick the watchdog task every 10-12 seconds.
+ An NMI is generated every 60 seconds or so to check for hardlockups.
- (Note that "hard lockups" are separate type of bugs that
- can be detected via the NMI-watchdog, on platforms that
- support it.)
+config HARDLOCKUP_DETECTOR
+ def_bool LOCKUP_DETECTOR && PERF_EVENTS && HAVE_PERF_EVENTS_NMI
config BOOTPARAM_SOFTLOCKUP_PANIC
bool "Panic (Reboot) On Soft Lockups"
- depends on DETECT_SOFTLOCKUP
+ depends on LOCKUP_DETECTOR
help
Say Y here to enable the kernel to panic on "soft lockups",
which are bugs that cause the kernel to loop in kernel
@@ -190,7 +195,7 @@ config BOOTPARAM_SOFTLOCKUP_PANIC
config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE
int
- depends on DETECT_SOFTLOCKUP
+ depends on LOCKUP_DETECTOR
range 0 1
default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC
default 1 if BOOTPARAM_SOFTLOCKUP_PANIC
diff --git a/lib/Makefile b/lib/Makefile
index 3f1062cbbff4..e18f1a6b2c14 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -81,6 +81,8 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o
obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
obj-$(CONFIG_SMP) += percpu_counter.o
obj-$(CONFIG_AUDIT_GENERIC) += audit.o
+obj-$(CONFIG_SHM_SIGNAL) += shm_signal.o
+obj-$(CONFIG_IOQ) += ioq.o
obj-$(CONFIG_SWIOTLB) += swiotlb.o
obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index 9087d71537dd..250ed11d3ed2 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -113,7 +113,8 @@ static __init int test_atomic64(void)
r += one;
BUG_ON(v.counter != r);
-#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(_ASM_GENERIC_ATOMIC64_H)
+#if defined(CONFIG_X86) || defined(CONFIG_MIPS) || defined(CONFIG_PPC) || \
+ defined(CONFIG_S390) || defined(_ASM_GENERIC_ATOMIC64_H)
INIT(onestwos);
BUG_ON(atomic64_dec_if_positive(&v) != (onestwos - 1));
r -= one;
diff --git a/lib/ioq.c b/lib/ioq.c
new file mode 100644
index 000000000000..4027848d7436
--- /dev/null
+++ b/lib/ioq.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * See include/linux/ioq.h for documentation
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/sched.h>
+#include <linux/ioq.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+static int ioq_iter_setpos(struct ioq_iterator *iter, u32 pos)
+{
+ struct ioq *ioq = iter->ioq;
+
+ BUG_ON(pos >= ioq->count);
+
+ iter->pos = pos;
+ iter->desc = &ioq->ring[pos];
+
+ return 0;
+}
+
+static inline u32 modulo_inc(u32 val, u32 mod)
+{
+ BUG_ON(val >= mod);
+
+ if (val == (mod - 1))
+ return 0;
+
+ return val + 1;
+}
+
+static inline int idx_full(struct ioq_ring_idx *idx)
+{
+ return idx->full && (idx->head == idx->tail);
+}
+
+int ioq_iter_seek(struct ioq_iterator *iter, enum ioq_seek_type type,
+ long offset, int flags)
+{
+ struct ioq_ring_idx *idx = iter->idx;
+ u32 pos;
+
+ switch (type) {
+ case ioq_seek_next:
+ pos = modulo_inc(iter->pos, iter->ioq->count);
+ break;
+ case ioq_seek_tail:
+ pos = le32_to_cpu(idx->tail);
+ break;
+ case ioq_seek_head:
+ pos = le32_to_cpu(idx->head);
+ break;
+ case ioq_seek_set:
+ if (offset >= iter->ioq->count)
+ return -1;
+ pos = offset;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ioq_iter_setpos(iter, pos);
+}
+EXPORT_SYMBOL_GPL(ioq_iter_seek);
+
+static int ioq_ring_count(struct ioq_ring_idx *idx, int count)
+{
+ u32 head = le32_to_cpu(idx->head);
+ u32 tail = le32_to_cpu(idx->tail);
+
+ if (idx->full && (head == tail))
+ return count;
+ else if (tail >= head)
+ return tail - head;
+ else
+ return (tail + count) - head;
+}
+
+static void idx_tail_push(struct ioq_ring_idx *idx, int count)
+{
+ u32 tail = modulo_inc(le32_to_cpu(idx->tail), count);
+ u32 head = le32_to_cpu(idx->head);
+
+ if (head == tail) {
+ rmb();
+
+ /*
+ * Setting full here may look racy, but note that we havent
+ * flipped the owner bit yet. So it is impossible for the
+ * remote locale to move head in such a way that this operation
+ * becomes invalid
+ */
+ idx->full = 1;
+ wmb();
+ }
+
+ idx->tail = cpu_to_le32(tail);
+}
+
+int ioq_iter_push(struct ioq_iterator *iter, int flags)
+{
+ struct ioq_ring_head *head_desc = iter->ioq->head_desc;
+ struct ioq_ring_idx *idx = iter->idx;
+ int ret;
+
+ /*
+ * Its only valid to push if we are currently pointed at the tail
+ */
+ if (iter->pos != le32_to_cpu(idx->tail) || iter->desc->sown != iter->ioq->locale)
+ return -EINVAL;
+
+ idx_tail_push(idx, iter->ioq->count);
+ if (iter->dualidx) {
+ idx_tail_push(&head_desc->idx[ioq_idxtype_inuse],
+ iter->ioq->count);
+ if (head_desc->idx[ioq_idxtype_inuse].tail !=
+ head_desc->idx[ioq_idxtype_valid].tail) {
+ SHM_SIGNAL_FAULT(iter->ioq->signal,
+ "Tails not synchronized");
+ return -EINVAL;
+ }
+ }
+
+ wmb(); /* the index must be visible before the sown, or signal */
+
+ if (iter->flipowner) {
+ iter->desc->sown = !iter->ioq->locale;
+ wmb(); /* sown must be visible before we signal */
+ }
+
+ ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
+
+ if (iter->update)
+ ioq_signal(iter->ioq, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_push);
+
+int ioq_iter_pop(struct ioq_iterator *iter, int flags)
+{
+ struct ioq_ring_idx *idx = iter->idx;
+ int ret;
+
+ /*
+ * Its only valid to pop if we are currently pointed at the head
+ */
+ if (iter->pos != le32_to_cpu(idx->head) || iter->desc->sown != iter->ioq->locale)
+ return -EINVAL;
+
+ idx->head = cpu_to_le32(modulo_inc(le32_to_cpu(idx->head), iter->ioq->count));
+ wmb(); /* head must be visible before full */
+
+ if (idx->full) {
+ idx->full = 0;
+ wmb(); /* full must be visible before sown */
+ }
+
+ if (iter->flipowner) {
+ iter->desc->sown = !iter->ioq->locale;
+ wmb(); /* sown must be visible before we signal */
+ }
+
+ ret = ioq_iter_seek(iter, ioq_seek_next, 0, flags);
+
+ if (iter->update)
+ ioq_signal(iter->ioq, 0);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_pop);
+
+static struct ioq_ring_idx *idxtype_to_idx(struct ioq *ioq,
+ enum ioq_idx_type type)
+{
+ struct ioq_ring_idx *idx;
+
+ switch (type) {
+ case ioq_idxtype_valid:
+ case ioq_idxtype_inuse:
+ idx = &ioq->head_desc->idx[type];
+ break;
+ default:
+ panic("IOQ: illegal index type: %d", type);
+ break;
+ }
+
+ return idx;
+}
+
+int ioq_iter_init(struct ioq *ioq, struct ioq_iterator *iter,
+ enum ioq_idx_type type, int flags)
+{
+ iter->ioq = ioq;
+ iter->update = (flags & IOQ_ITER_AUTOUPDATE);
+ iter->flipowner = !(flags & IOQ_ITER_NOFLIPOWNER);
+ iter->pos = -1;
+ iter->desc = NULL;
+ iter->dualidx = 0;
+
+ if (type == ioq_idxtype_both) {
+ /*
+ * "both" is a special case, so we set the dualidx flag.
+ *
+ * However, we also just want to use the valid-index
+ * for normal processing, so override that here
+ */
+ type = ioq_idxtype_valid;
+ iter->dualidx = 1;
+ }
+
+ iter->idx = idxtype_to_idx(ioq, type);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ioq_iter_init);
+
+int ioq_count(struct ioq *ioq, enum ioq_idx_type type)
+{
+ return ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
+}
+EXPORT_SYMBOL_GPL(ioq_count);
+
+int ioq_remain(struct ioq *ioq, enum ioq_idx_type type)
+{
+ int count = ioq_ring_count(idxtype_to_idx(ioq, type), ioq->count);
+
+ return ioq->count - count;
+}
+EXPORT_SYMBOL_GPL(ioq_remain);
+
+int ioq_size(struct ioq *ioq)
+{
+ return ioq->count;
+}
+EXPORT_SYMBOL_GPL(ioq_size);
+
+int ioq_full(struct ioq *ioq, enum ioq_idx_type type)
+{
+ struct ioq_ring_idx *idx = idxtype_to_idx(ioq, type);
+
+ return idx_full(idx);
+}
+EXPORT_SYMBOL_GPL(ioq_full);
+
+static void ioq_shm_signal(struct shm_signal_notifier *notifier)
+{
+ struct ioq *ioq = container_of(notifier, struct ioq, shm_notifier);
+
+ if (waitqueue_active(&ioq->wq))
+ wake_up(&ioq->wq);
+
+ if (ioq->notifier)
+ ioq->notifier->signal(ioq->notifier);
+}
+
+void ioq_init(struct ioq *ioq,
+ struct ioq_ops *ops,
+ enum ioq_locality locale,
+ struct ioq_ring_head *head,
+ struct shm_signal *signal,
+ size_t count)
+{
+ memset(ioq, 0, sizeof(*ioq));
+ kref_init(&ioq->kref);
+ init_waitqueue_head(&ioq->wq);
+
+ ioq->ops = ops;
+ ioq->locale = locale;
+ ioq->head_desc = head;
+ ioq->ring = &head->ring[0];
+ ioq->count = count;
+ ioq->signal = signal;
+
+ ioq->shm_notifier.signal = &ioq_shm_signal;
+ signal->notifier = &ioq->shm_notifier;
+}
+EXPORT_SYMBOL_GPL(ioq_init);
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 59c15511d58a..b93579504dfa 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -83,6 +83,7 @@ out:
return ret;
}
+#ifdef CONFIG_NET
static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
{
struct kobject *kobj = data;
@@ -98,6 +99,7 @@ static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data)
return 0;
}
+#endif
static int kobj_usermode_filter(struct kobject *kobj)
{
@@ -378,6 +380,7 @@ static int uevent_net_init(struct net *net)
if (!ue_sk->sk) {
printk(KERN_ERR
"kobject_uevent: unable to create netlink socket!\n");
+ kfree(ue_sk);
return -ENODEV;
}
mutex_lock(&uevent_sock_mutex);
diff --git a/lib/shm_signal.c b/lib/shm_signal.c
new file mode 100644
index 000000000000..8d3e9b418a27
--- /dev/null
+++ b/lib/shm_signal.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright 2009 Novell. All Rights Reserved.
+ *
+ * See include/linux/shm_signal.h for documentation
+ *
+ * Author:
+ * Gregory Haskins <ghaskins@novell.com>
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/shm_signal.h>
+
+MODULE_AUTHOR("Gregory Haskins");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1");
+
+int shm_signal_enable(struct shm_signal *s, int flags)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+ unsigned long iflags;
+
+ spin_lock_irqsave(&s->lock, iflags);
+
+ irq->enabled = 1;
+ wmb();
+
+ if ((irq->dirty || irq->pending)
+ && !test_bit(shm_signal_in_wakeup, &s->flags)) {
+ rmb();
+ tasklet_schedule(&s->deferred_notify);
+ }
+
+ spin_unlock_irqrestore(&s->lock, iflags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_enable);
+
+int shm_signal_disable(struct shm_signal *s, int flags)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+
+ irq->enabled = 0;
+ wmb();
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_disable);
+
+/*
+ * signaling protocol:
+ *
+ * each side of the shm_signal has an "irq" structure with the following
+ * fields:
+ *
+ * - enabled: controlled by shm_signal_enable/disable() to mask/unmask
+ * the notification locally
+ * - dirty: indicates if the shared-memory is dirty or clean. This
+ * is updated regardless of the enabled/pending state so that
+ * the state is always accurately tracked.
+ * - pending: indicates if a signal is pending to the remote locale.
+ * This allows us to determine if a remote-notification is
+ * already in flight to optimize spurious notifications away.
+ */
+int shm_signal_inject(struct shm_signal *s, int flags)
+{
+ /* Load the irq structure from the other locale */
+ struct shm_signal_irq *irq = &s->desc->irq[!s->locale];
+
+ /*
+ * We always mark the remote side as dirty regardless of whether
+ * they need to be notified.
+ */
+ irq->dirty = 1;
+ wmb(); /* dirty must be visible before we test the pending state */
+
+ if (irq->enabled && !irq->pending) {
+ rmb();
+
+ /*
+ * If the remote side has enabled notifications, and we do
+ * not see a notification pending, we must inject a new one.
+ */
+ irq->pending = 1;
+ wmb(); /* make it visible before we do the injection */
+
+ s->ops->inject(s);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(shm_signal_inject);
+
+void _shm_signal_wakeup(struct shm_signal *s)
+{
+ struct shm_signal_irq *irq = &s->desc->irq[s->locale];
+ int dirty;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->lock, flags);
+
+ __set_bit(shm_signal_in_wakeup, &s->flags);
+
+ /*
+ * The outer loop protects against race conditions between
+ * irq->dirty and irq->pending updates
+ */
+ while (irq->enabled && (irq->dirty || irq->pending)) {
+
+ /*
+ * Run until we completely exhaust irq->dirty (it may
+ * be re-dirtied by the remote side while we are in the
+ * callback). We let "pending" remain untouched until we have
+ * processed them all so that the remote side knows we do not
+ * need a new notification (yet).
+ */
+ do {
+ irq->dirty = 0;
+ /* the unlock is an implicit wmb() for dirty = 0 */
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ if (s->notifier)
+ s->notifier->signal(s->notifier);
+
+ spin_lock_irqsave(&s->lock, flags);
+ dirty = irq->dirty;
+ rmb();
+
+ } while (irq->enabled && dirty);
+
+ barrier();
+
+ /*
+ * We can finally acknowledge the notification by clearing
+ * "pending" after all of the dirty memory has been processed
+ * Races against this clearing are handled by the outer loop.
+ * Subsequent iterations of this loop will execute with
+ * pending=0 potentially leading to future spurious
+ * notifications, but this is an acceptable tradeoff as this
+ * will be rare and harmless.
+ */
+ irq->pending = 0;
+ wmb();
+
+ }
+
+ __clear_bit(shm_signal_in_wakeup, &s->flags);
+ spin_unlock_irqrestore(&s->lock, flags);
+
+}
+EXPORT_SYMBOL_GPL(_shm_signal_wakeup);
+
+void _shm_signal_release(struct kref *kref)
+{
+ struct shm_signal *s = container_of(kref, struct shm_signal, kref);
+
+ s->ops->release(s);
+}
+EXPORT_SYMBOL_GPL(_shm_signal_release);
+
+static void
+deferred_notify(unsigned long data)
+{
+ struct shm_signal *s = (struct shm_signal *)data;
+
+ _shm_signal_wakeup(s);
+}
+
+void shm_signal_init(struct shm_signal *s, enum shm_signal_locality locale,
+ struct shm_signal_ops *ops, struct shm_signal_desc *desc)
+{
+ memset(s, 0, sizeof(*s));
+ kref_init(&s->kref);
+ spin_lock_init(&s->lock);
+ tasklet_init(&s->deferred_notify,
+ deferred_notify,
+ (unsigned long)s);
+ s->locale = locale;
+ s->ops = ops;
+ s->desc = desc;
+}
+EXPORT_SYMBOL_GPL(shm_signal_init);
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index a009055140ec..34e3082632d8 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -50,19 +50,11 @@
*/
#define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT)
-/*
- * Enumeration for sync targets
- */
-enum dma_sync_target {
- SYNC_FOR_CPU = 0,
- SYNC_FOR_DEVICE = 1,
-};
-
int swiotlb_force;
/*
- * Used to do a quick range check in unmap_single and
- * sync_single_*, to see if the memory was in fact allocated by this
+ * Used to do a quick range check in swiotlb_tbl_unmap_single and
+ * swiotlb_tbl_sync_single_*, to see if the memory was in fact allocated by this
* API.
*/
static char *io_tlb_start, *io_tlb_end;
@@ -140,28 +132,14 @@ void swiotlb_print_info(void)
(unsigned long long)pend);
}
-/*
- * Statically reserve bounce buffer space and initialize bounce buffer data
- * structures for the software IO TLB used to implement the DMA API.
- */
-void __init
-swiotlb_init_with_default_size(size_t default_size, int verbose)
+void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
{
unsigned long i, bytes;
- if (!io_tlb_nslabs) {
- io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
- io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
- }
-
- bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+ bytes = nslabs << IO_TLB_SHIFT;
- /*
- * Get IO TLB memory from the low pages
- */
- io_tlb_start = alloc_bootmem_low_pages(bytes);
- if (!io_tlb_start)
- panic("Cannot allocate SWIOTLB buffer");
+ io_tlb_nslabs = nslabs;
+ io_tlb_start = tlb;
io_tlb_end = io_tlb_start + bytes;
/*
@@ -185,6 +163,32 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
swiotlb_print_info();
}
+/*
+ * Statically reserve bounce buffer space and initialize bounce buffer data
+ * structures for the software IO TLB used to implement the DMA API.
+ */
+void __init
+swiotlb_init_with_default_size(size_t default_size, int verbose)
+{
+ unsigned long bytes;
+
+ if (!io_tlb_nslabs) {
+ io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
+ io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
+ }
+
+ bytes = io_tlb_nslabs << IO_TLB_SHIFT;
+
+ /*
+ * Get IO TLB memory from the low pages
+ */
+ io_tlb_start = alloc_bootmem_low_pages(bytes);
+ if (!io_tlb_start)
+ panic("Cannot allocate SWIOTLB buffer");
+
+ swiotlb_init_with_tbl(io_tlb_start, io_tlb_nslabs, verbose);
+}
+
void __init
swiotlb_init(int verbose)
{
@@ -323,8 +327,8 @@ static int is_swiotlb_buffer(phys_addr_t paddr)
/*
* Bounce: copy the swiotlb buffer back to the original dma location
*/
-static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
- enum dma_data_direction dir)
+void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
+ enum dma_data_direction dir)
{
unsigned long pfn = PFN_DOWN(phys);
@@ -360,26 +364,25 @@ static void swiotlb_bounce(phys_addr_t phys, char *dma_addr, size_t size,
memcpy(phys_to_virt(phys), dma_addr, size);
}
}
+EXPORT_SYMBOL_GPL(swiotlb_bounce);
-/*
- * Allocates bounce buffer and returns its kernel virtual address.
- */
-static void *
-map_single(struct device *hwdev, phys_addr_t phys, size_t size, int dir)
+void *swiotlb_tbl_map_single(struct device *hwdev, dma_addr_t tbl_dma_addr,
+ phys_addr_t phys, size_t size,
+ enum dma_data_direction dir)
{
unsigned long flags;
char *dma_addr;
unsigned int nslots, stride, index, wrap;
int i;
- unsigned long start_dma_addr;
unsigned long mask;
unsigned long offset_slots;
unsigned long max_slots;
mask = dma_get_seg_boundary(hwdev);
- start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start) & mask;
- offset_slots = ALIGN(start_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+ tbl_dma_addr &= mask;
+
+ offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
/*
* Carefully handle integer overflow which can occur when mask == ~0UL.
@@ -466,12 +469,27 @@ found:
return dma_addr;
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_map_single);
+
+/*
+ * Allocates bounce buffer and returns its kernel virtual address.
+ */
+
+static void *
+map_single(struct device *hwdev, phys_addr_t phys, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t start_dma_addr = swiotlb_virt_to_bus(hwdev, io_tlb_start);
+
+ return swiotlb_tbl_map_single(hwdev, start_dma_addr, phys, size, dir);
+}
/*
* dma_addr is the kernel virtual address of the bounce buffer to unmap.
*/
-static void
-do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
+void
+swiotlb_tbl_unmap_single(struct device *hwdev, char *dma_addr, size_t size,
+ enum dma_data_direction dir)
{
unsigned long flags;
int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -509,10 +527,12 @@ do_unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
}
spin_unlock_irqrestore(&io_tlb_lock, flags);
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_unmap_single);
-static void
-sync_single(struct device *hwdev, char *dma_addr, size_t size,
- int dir, int target)
+void
+swiotlb_tbl_sync_single(struct device *hwdev, char *dma_addr, size_t size,
+ enum dma_data_direction dir,
+ enum dma_sync_target target)
{
int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
phys_addr_t phys = io_tlb_orig_addr[index];
@@ -536,6 +556,7 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
BUG();
}
}
+EXPORT_SYMBOL_GPL(swiotlb_tbl_sync_single);
void *
swiotlb_alloc_coherent(struct device *hwdev, size_t size,
@@ -559,8 +580,8 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
}
if (!ret) {
/*
- * We are either out of memory or the device can't DMA
- * to GFP_DMA memory; fall back on map_single(), which
+ * We are either out of memory or the device can't DMA to
+ * GFP_DMA memory; fall back on map_single(), which
* will grab memory from the lowest available address range.
*/
ret = map_single(hwdev, 0, size, DMA_FROM_DEVICE);
@@ -578,7 +599,7 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
(unsigned long long)dev_addr);
/* DMA_TO_DEVICE to avoid memcpy in unmap_single */
- do_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
+ swiotlb_tbl_unmap_single(hwdev, ret, size, DMA_TO_DEVICE);
return NULL;
}
*dma_handle = dev_addr;
@@ -596,13 +617,14 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
if (!is_swiotlb_buffer(paddr))
free_pages((unsigned long)vaddr, get_order(size));
else
- /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
- do_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
+ /* DMA_TO_DEVICE to avoid memcpy in swiotlb_tbl_unmap_single */
+ swiotlb_tbl_unmap_single(hwdev, vaddr, size, DMA_TO_DEVICE);
}
EXPORT_SYMBOL(swiotlb_free_coherent);
static void
-swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
+swiotlb_full(struct device *dev, size_t size, enum dma_data_direction dir,
+ int do_panic)
{
/*
* Ran out of IOMMU space for this operation. This is very bad.
@@ -680,14 +702,14 @@ EXPORT_SYMBOL_GPL(swiotlb_map_page);
* whatever the device wrote there.
*/
static void unmap_single(struct device *hwdev, dma_addr_t dev_addr,
- size_t size, int dir)
+ size_t size, enum dma_data_direction dir)
{
phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
BUG_ON(dir == DMA_NONE);
if (is_swiotlb_buffer(paddr)) {
- do_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
+ swiotlb_tbl_unmap_single(hwdev, phys_to_virt(paddr), size, dir);
return;
}
@@ -723,14 +745,16 @@ EXPORT_SYMBOL_GPL(swiotlb_unmap_page);
*/
static void
swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
- size_t size, int dir, int target)
+ size_t size, enum dma_data_direction dir,
+ enum dma_sync_target target)
{
phys_addr_t paddr = dma_to_phys(hwdev, dev_addr);
BUG_ON(dir == DMA_NONE);
if (is_swiotlb_buffer(paddr)) {
- sync_single(hwdev, phys_to_virt(paddr), size, dir, target);
+ swiotlb_tbl_sync_single(hwdev, phys_to_virt(paddr), size, dir,
+ target);
return;
}
@@ -809,7 +833,7 @@ EXPORT_SYMBOL(swiotlb_map_sg_attrs);
int
swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+ enum dma_data_direction dir)
{
return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
}
@@ -836,7 +860,7 @@ EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
void
swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+ enum dma_data_direction dir)
{
return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
}
@@ -851,7 +875,8 @@ EXPORT_SYMBOL(swiotlb_unmap_sg);
*/
static void
swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sgl,
- int nelems, int dir, int target)
+ int nelems, enum dma_data_direction dir,
+ enum dma_sync_target target)
{
struct scatterlist *sg;
int i;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index b289310e2c89..5fa63bdf52e4 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -597,7 +597,7 @@ static void balance_dirty_pages(struct address_space *mapping,
(!laptop_mode && ((global_page_state(NR_FILE_DIRTY)
+ global_page_state(NR_UNSTABLE_NFS))
> background_thresh)))
- bdi_start_writeback(bdi, NULL, 0, 0);
+ bdi_start_writeback(bdi, NULL, 0);
}
void set_page_dirty_balance(struct page *page, int page_mkwrite)
@@ -707,7 +707,7 @@ void laptop_mode_timer_fn(unsigned long data)
*/
if (bdi_has_dirty_io(&q->backing_dev_info))
- bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages, 0);
+ bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages);
}
/*
diff --git a/mm/shmem.c b/mm/shmem.c
index 7e5030ae18ff..33222ba256fb 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -764,10 +764,15 @@ done2:
static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
+ loff_t newsize = attr->ia_size;
int error;
- if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
- loff_t newsize = attr->ia_size;
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)
+ && newsize != inode->i_size) {
struct page *page = NULL;
if (newsize < inode->i_size) {
@@ -800,19 +805,16 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
}
}
- error = simple_setsize(inode, newsize);
+ /* XXX(truncate): truncate_setsize should be called last */
+ truncate_setsize(inode, newsize);
if (page)
page_cache_release(page);
- if (error)
- return error;
shmem_truncate_range(inode, newsize, (loff_t)-1);
}
- error = inode_change_ok(inode, attr);
- if (!error)
- generic_setattr(inode, attr);
+ setattr_copy(inode, attr);
#ifdef CONFIG_TMPFS_POSIX_ACL
- if (!error && (attr->ia_valid & ATTR_MODE))
+ if (attr->ia_valid & ATTR_MODE)
error = generic_acl_chmod(inode);
#endif
return error;
diff --git a/mm/truncate.c b/mm/truncate.c
index 937571b8b233..ba887bff48c5 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -541,28 +541,48 @@ void truncate_pagecache(struct inode *inode, loff_t old, loff_t new)
EXPORT_SYMBOL(truncate_pagecache);
/**
+ * truncate_setsize - update inode and pagecache for a new file size
+ * @inode: inode
+ * @newsize: new file size
+ *
+ * truncate_setsize updastes i_size update and performs pagecache
+ * truncation (if necessary) for a file size updates. It will be
+ * typically be called from the filesystem's setattr function when
+ * ATTR_SIZE is passed in.
+ *
+ * Must be called with inode_mutex held and after all filesystem
+ * specific block truncation has been performed.
+ */
+void truncate_setsize(struct inode *inode, loff_t newsize)
+{
+ loff_t oldsize;
+
+ oldsize = inode->i_size;
+ i_size_write(inode, newsize);
+
+ truncate_pagecache(inode, oldsize, newsize);
+}
+EXPORT_SYMBOL(truncate_setsize);
+
+/**
* vmtruncate - unmap mappings "freed" by truncate() syscall
* @inode: inode of the file used
* @offset: file offset to start truncating
*
- * NOTE! We have to be ready to update the memory sharing
- * between the file and the memory map for a potential last
- * incomplete page. Ugly, but necessary.
- *
- * This function is deprecated and simple_setsize or truncate_pagecache
- * should be used instead.
+ * This function is deprecated and truncate_setsize or truncate_pagecache
+ * should be used instead, together with filesystem specific block truncation.
*/
int vmtruncate(struct inode *inode, loff_t offset)
{
int error;
- error = simple_setsize(inode, offset);
+ error = inode_newsize_ok(inode, offset);
if (error)
return error;
+ truncate_setsize(inode, offset);
if (inode->i_op->truncate)
inode->i_op->truncate(inode);
-
- return error;
+ return 0;
}
EXPORT_SYMBOL(vmtruncate);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 915dceb487c1..9c7e57cc63a3 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -1724,13 +1724,13 @@ static void shrink_zone(int priority, struct zone *zone,
* If a zone is deemed to be full of pinned pages then just give it a light
* scan then give up on it.
*/
-static int shrink_zones(int priority, struct zonelist *zonelist,
+static bool shrink_zones(int priority, struct zonelist *zonelist,
struct scan_control *sc)
{
enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask);
struct zoneref *z;
struct zone *zone;
- int progress = 0;
+ bool all_unreclaimable = true;
for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
sc->nodemask) {
@@ -1757,9 +1757,9 @@ static int shrink_zones(int priority, struct zonelist *zonelist,
}
shrink_zone(priority, zone, sc);
- progress = 1;
+ all_unreclaimable = false;
}
- return progress;
+ return all_unreclaimable;
}
/*
@@ -1782,7 +1782,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
struct scan_control *sc)
{
int priority;
- unsigned long ret = 0;
+ bool all_unreclaimable;
unsigned long total_scanned = 0;
struct reclaim_state *reclaim_state = current->reclaim_state;
unsigned long lru_pages = 0;
@@ -1813,7 +1813,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
sc->nr_scanned = 0;
if (!priority)
disable_swap_token();
- ret = shrink_zones(priority, zonelist, sc);
+ all_unreclaimable = shrink_zones(priority, zonelist, sc);
/*
* Don't shrink slabs when reclaiming memory from
* over limit cgroups
@@ -1826,10 +1826,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
}
}
total_scanned += sc->nr_scanned;
- if (sc->nr_reclaimed >= sc->nr_to_reclaim) {
- ret = sc->nr_reclaimed;
+ if (sc->nr_reclaimed >= sc->nr_to_reclaim)
goto out;
- }
/*
* Try to write back as many pages as we just scanned. This
@@ -1849,9 +1847,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
priority < DEF_PRIORITY - 2)
congestion_wait(BLK_RW_ASYNC, HZ/10);
}
- /* top priority shrink_zones still had more to do? don't OOM, then */
- if (ret && scanning_global_lru(sc))
- ret = sc->nr_reclaimed;
+
out:
/*
* Now that we've scanned all the zones at this priority level, note
@@ -1877,7 +1873,14 @@ out:
delayacct_freepages_end();
put_mems_allowed();
- return ret;
+ if (sc->nr_reclaimed)
+ return sc->nr_reclaimed;
+
+ /* top priority shrink_zones still had more to do? don't OOM, then */
+ if (scanning_global_lru(sc) && !all_unreclaimable)
+ return 1;
+
+ return 0;
}
unsigned long try_to_free_pages(struct zonelist *zonelist, int order,
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 55be90826f5f..529842677817 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -708,7 +708,8 @@ static int vlan_dev_init(struct net_device *dev)
netif_carrier_off(dev);
/* IFF_BROADCAST|IFF_MULTICAST; ??? */
- dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI);
+ dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
+ IFF_MASTER | IFF_SLAVE);
dev->iflink = real_dev->ifindex;
dev->state = (real_dev->state & ((1<<__LINK_STATE_NOCARRIER) |
(1<<__LINK_STATE_DORMANT))) |
diff --git a/net/9p/client.c b/net/9p/client.c
index 37c8da07a80b..01000a84a006 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -460,7 +460,8 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
return err;
}
- if (p9_is_proto_dotu(c))
+ if (p9_is_proto_dotu(c) ||
+ p9_is_proto_dotl(c))
err = -ecode;
if (!err || !IS_ERR_VALUE(err))
@@ -1094,6 +1095,27 @@ error:
}
EXPORT_SYMBOL(p9_client_fcreate);
+int p9_client_link(struct p9_fid *dfid, char *oldname, char *newname)
+{
+ int err = 0;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TLINK fid %d oldname %s newname %s\n",
+ dfid->fid, oldname, newname);
+ clnt = dfid->clnt;
+ req = p9_client_rpc(clnt, P9_TLINK, "dss", dfid->fid, oldname, newname);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RLINK\n");
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_link);
+
int p9_client_clunk(struct p9_fid *fid)
{
int err;
@@ -1432,3 +1454,50 @@ error:
}
EXPORT_SYMBOL(p9_client_rename);
+int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
+{
+ int err, rsize, total;
+ struct p9_client *clnt;
+ struct p9_req_t *req;
+ char *dataptr;
+
+ P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
+ fid->fid, (long long unsigned) offset, count);
+
+ err = 0;
+ clnt = fid->clnt;
+ total = 0;
+
+ rsize = fid->iounit;
+ if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
+ rsize = clnt->msize - P9_READDIRHDRSZ;
+
+ if (count < rsize)
+ rsize = count;
+
+ req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ goto error;
+ }
+
+ err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
+ if (err) {
+ p9pdu_dump(1, req->rc);
+ goto free_and_error;
+ }
+
+ P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
+
+ if (data)
+ memmove(data, dataptr, count);
+
+ p9_free_req(clnt, req);
+ return count;
+
+free_and_error:
+ p9_free_req(clnt, req);
+error:
+ return err;
+}
+EXPORT_SYMBOL(p9_client_readdir);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 149f82160130..b645c8263538 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -580,3 +580,30 @@ void p9pdu_reset(struct p9_fcall *pdu)
pdu->offset = 0;
pdu->size = 0;
}
+
+int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
+ int proto_version)
+{
+ struct p9_fcall fake_pdu;
+ int ret;
+ char *nameptr;
+
+ fake_pdu.size = len;
+ fake_pdu.capacity = len;
+ fake_pdu.sdata = buf;
+ fake_pdu.offset = 0;
+
+ ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
+ &dirent->d_off, &dirent->d_type, &nameptr);
+ if (ret) {
+ P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
+ p9pdu_dump(1, &fake_pdu);
+ goto out;
+ }
+
+ strcpy(dirent->d_name, nameptr);
+
+out:
+ return fake_pdu.offset;
+}
+EXPORT_SYMBOL(p9dirent_read);
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 0d9e506f5d5a..70672544db86 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -86,26 +86,26 @@ struct bnep_setup_conn_req {
__u8 ctrl;
__u8 uuid_size;
__u8 service[0];
-} __attribute__((packed));
+} __packed;
struct bnep_set_filter_req {
__u8 type;
__u8 ctrl;
__be16 len;
__u8 list[0];
-} __attribute__((packed));
+} __packed;
struct bnep_control_rsp {
__u8 type;
__u8 ctrl;
__be16 resp;
-} __attribute__((packed));
+} __packed;
struct bnep_ext_hdr {
__u8 type;
__u8 len;
__u8 data[0];
-} __attribute__((packed));
+} __packed;
/* BNEP ioctl defines */
#define BNEPCONNADD _IOW('B', 200, int)
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 76357b547752..c8436fa31344 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -63,7 +63,6 @@ static int __init br_init(void)
goto err_out4;
brioctl_set(br_ioctl_deviceless_stub);
- br_handle_frame_hook = br_handle_frame;
#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
br_fdb_test_addr_hook = br_fdb_test_addr;
@@ -100,7 +99,6 @@ static void __exit br_deinit(void)
br_fdb_test_addr_hook = NULL;
#endif
- br_handle_frame_hook = NULL;
br_fdb_fini();
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 18b245e2c00e..d9242342837e 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -147,6 +147,7 @@ static void del_nbp(struct net_bridge_port *p)
list_del_rcu(&p->list);
+ netdev_rx_handler_unregister(dev);
rcu_assign_pointer(dev->br_port, NULL);
br_multicast_del_port(p);
@@ -429,6 +430,11 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
goto err2;
rcu_assign_pointer(dev->br_port, p);
+
+ err = netdev_rx_handler_register(dev, br_handle_frame);
+ if (err)
+ goto err3;
+
dev_disable_lro(dev);
list_add_rcu(&p->list, &br->port_list);
@@ -451,6 +457,8 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
br_netpoll_enable(br, dev);
return 0;
+err3:
+ rcu_assign_pointer(dev->br_port, NULL);
err2:
br_fdb_delete_by_port(br, p, 1);
err1:
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index d36e700f7a26..99647d8f95c8 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -131,15 +131,19 @@ static inline int is_link_local(const unsigned char *dest)
}
/*
- * Called via br_handle_frame_hook.
* Return NULL if skb is handled
- * note: already called with rcu_read_lock (preempt_disabled)
+ * note: already called with rcu_read_lock (preempt_disabled) from
+ * netif_receive_skb
*/
-struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
+struct sk_buff *br_handle_frame(struct sk_buff *skb)
{
+ struct net_bridge_port *p;
const unsigned char *dest = eth_hdr(skb)->h_dest;
int (*rhook)(struct sk_buff *skb);
+ if (skb->pkt_type == PACKET_LOOPBACK)
+ return skb;
+
if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
goto drop;
@@ -147,6 +151,8 @@ struct sk_buff *br_handle_frame(struct net_bridge_port *p, struct sk_buff *skb)
if (!skb)
return NULL;
+ p = rcu_dereference(skb->dev->br_port);
+
if (unlikely(is_link_local(dest))) {
/* Pause frames shouldn't be passed up by driver anyway */
if (skb->protocol == htons(ETH_P_PAUSE))
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 0f4a74bc6a9b..c83519b555bb 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -331,8 +331,7 @@ extern void br_features_recompute(struct net_bridge *br);
/* br_input.c */
extern int br_handle_frame_finish(struct sk_buff *skb);
-extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
- struct sk_buff *skb);
+extern struct sk_buff *br_handle_frame(struct sk_buff *skb);
/* br_ioctl.c */
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index 3d0e09584fae..791249316ef3 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -874,8 +874,7 @@ static int caif_connect(struct socket *sock, struct sockaddr *uaddr,
sk_stream_kill_queues(&cf_sk->sk);
err = -EINVAL;
- if (addr_len != sizeof(struct sockaddr_caif) ||
- !uaddr)
+ if (addr_len != sizeof(struct sockaddr_caif))
goto out;
memcpy(&cf_sk->conn_req.sockaddr, uaddr,
diff --git a/net/caif/cfcnfg.c b/net/caif/cfcnfg.c
index df43f264d9fb..7c81974a45c4 100644
--- a/net/caif/cfcnfg.c
+++ b/net/caif/cfcnfg.c
@@ -308,19 +308,15 @@ cfcnfg_linkup_rsp(struct cflayer *layer, u8 channel_id, enum cfctrl_srv serv,
caif_assert(cnfg != NULL);
caif_assert(phyid != 0);
phyinfo = &cnfg->phy_layers[phyid];
- caif_assert(phyinfo != NULL);
caif_assert(phyinfo->id == phyid);
caif_assert(phyinfo->phy_layer != NULL);
caif_assert(phyinfo->phy_layer->id == phyid);
- if (phyinfo != NULL &&
- phyinfo->phy_ref_count++ == 0 &&
- phyinfo->phy_layer != NULL &&
+ phyinfo->phy_ref_count++;
+ if (phyinfo->phy_ref_count == 1 &&
phyinfo->phy_layer->modemcmd != NULL) {
- caif_assert(phyinfo->phy_layer->id == phyid);
phyinfo->phy_layer->modemcmd(phyinfo->phy_layer,
_CAIF_MODEMCMD_PHYIF_USEFULL);
-
}
adapt_layer->id = channel_id;
diff --git a/net/caif/cfserl.c b/net/caif/cfserl.c
index cb4325a3dc83..965c5baace40 100644
--- a/net/caif/cfserl.c
+++ b/net/caif/cfserl.c
@@ -59,16 +59,18 @@ static int cfserl_receive(struct cflayer *l, struct cfpkt *newpkt)
u8 stx = CFSERL_STX;
int ret;
u16 expectlen = 0;
+
caif_assert(newpkt != NULL);
spin_lock(&layr->sync);
if (layr->incomplete_frm != NULL) {
-
layr->incomplete_frm =
cfpkt_append(layr->incomplete_frm, newpkt, expectlen);
pkt = layr->incomplete_frm;
- if (pkt == NULL)
+ if (pkt == NULL) {
+ spin_unlock(&layr->sync);
return -ENOMEM;
+ }
} else {
pkt = newpkt;
}
diff --git a/net/can/raw.c b/net/can/raw.c
index da99cf153b33..ccfe633eec8e 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -436,14 +436,9 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
if (count > 1) {
/* filter does not fit into dfilter => alloc space */
- filter = kmalloc(optlen, GFP_KERNEL);
- if (!filter)
- return -ENOMEM;
-
- if (copy_from_user(filter, optval, optlen)) {
- kfree(filter);
- return -EFAULT;
- }
+ filter = memdup_user(optval, optlen);
+ if (IS_ERR(filter))
+ return PTR_ERR(filter);
} else if (count == 1) {
if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
return -EFAULT;
diff --git a/net/compat.c b/net/compat.c
index ec24d9edb025..63d260e81472 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -81,7 +81,7 @@ int verify_compat_iovec(struct msghdr *kern_msg, struct iovec *kern_iov,
int tot_len;
if (kern_msg->msg_namelen) {
- if (mode==VERIFY_READ) {
+ if (mode == VERIFY_READ) {
int err = move_addr_to_kernel(kern_msg->msg_name,
kern_msg->msg_namelen,
kern_address);
@@ -354,7 +354,7 @@ static int do_set_attach_filter(struct socket *sock, int level, int optname,
static int do_set_sock_timeout(struct socket *sock, int level,
int optname, char __user *optval, unsigned int optlen)
{
- struct compat_timeval __user *up = (struct compat_timeval __user *) optval;
+ struct compat_timeval __user *up = (struct compat_timeval __user *)optval;
struct timeval ktime;
mm_segment_t old_fs;
int err;
@@ -367,7 +367,7 @@ static int do_set_sock_timeout(struct socket *sock, int level,
return -EFAULT;
old_fs = get_fs();
set_fs(KERNEL_DS);
- err = sock_setsockopt(sock, level, optname, (char *) &ktime, sizeof(ktime));
+ err = sock_setsockopt(sock, level, optname, (char *)&ktime, sizeof(ktime));
set_fs(old_fs);
return err;
@@ -389,11 +389,10 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
char __user *optval, unsigned int optlen)
{
int err;
- struct socket *sock;
+ struct socket *sock = sockfd_lookup(fd, &err);
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
- err = security_socket_setsockopt(sock,level,optname);
+ if (sock) {
+ err = security_socket_setsockopt(sock, level, optname);
if (err) {
sockfd_put(sock);
return err;
@@ -453,7 +452,7 @@ static int compat_sock_getsockopt(struct socket *sock, int level, int optname,
int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
{
struct compat_timeval __user *ctv =
- (struct compat_timeval __user*) userstamp;
+ (struct compat_timeval __user *) userstamp;
int err = -ENOENT;
struct timeval tv;
@@ -477,7 +476,7 @@ EXPORT_SYMBOL(compat_sock_get_timestamp);
int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
{
struct compat_timespec __user *ctv =
- (struct compat_timespec __user*) userstamp;
+ (struct compat_timespec __user *) userstamp;
int err = -ENOENT;
struct timespec ts;
@@ -502,12 +501,10 @@ asmlinkage long compat_sys_getsockopt(int fd, int level, int optname,
char __user *optval, int __user *optlen)
{
int err;
- struct socket *sock;
+ struct socket *sock = sockfd_lookup(fd, &err);
- if ((sock = sockfd_lookup(fd, &err))!=NULL)
- {
- err = security_socket_getsockopt(sock, level,
- optname);
+ if (sock) {
+ err = security_socket_getsockopt(sock, level, optname);
if (err) {
sockfd_put(sock);
return err;
@@ -531,7 +528,7 @@ struct compat_group_req {
__u32 gr_interface;
struct __kernel_sockaddr_storage gr_group
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
struct compat_group_source_req {
__u32 gsr_interface;
@@ -539,7 +536,7 @@ struct compat_group_source_req {
__attribute__ ((aligned(4)));
struct __kernel_sockaddr_storage gsr_source
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
struct compat_group_filter {
__u32 gf_interface;
@@ -549,7 +546,7 @@ struct compat_group_filter {
__u32 gf_numsrc;
struct __kernel_sockaddr_storage gf_slist[1]
__attribute__ ((aligned(4)));
-} __attribute__ ((packed));
+} __packed;
#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
sizeof(struct __kernel_sockaddr_storage))
@@ -557,7 +554,7 @@ struct compat_group_filter {
int compat_mc_setsockopt(struct sock *sock, int level, int optname,
char __user *optval, unsigned int optlen,
- int (*setsockopt)(struct sock *,int,int,char __user *,unsigned int))
+ int (*setsockopt)(struct sock *, int, int, char __user *, unsigned int))
{
char __user *koptval = optval;
int koptlen = optlen;
@@ -640,12 +637,11 @@ int compat_mc_setsockopt(struct sock *sock, int level, int optname,
}
return setsockopt(sock, level, optname, koptval, koptlen);
}
-
EXPORT_SYMBOL(compat_mc_setsockopt);
int compat_mc_getsockopt(struct sock *sock, int level, int optname,
char __user *optval, int __user *optlen,
- int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
+ int (*getsockopt)(struct sock *, int, int, char __user *, int __user *))
{
struct compat_group_filter __user *gf32 = (void *)optval;
struct group_filter __user *kgf;
@@ -681,7 +677,7 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname,
__put_user(interface, &kgf->gf_interface) ||
__put_user(fmode, &kgf->gf_fmode) ||
__put_user(numsrc, &kgf->gf_numsrc) ||
- copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
+ copy_in_user(&kgf->gf_group, &gf32->gf_group, sizeof(kgf->gf_group)))
return -EFAULT;
err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
@@ -714,21 +710,22 @@ int compat_mc_getsockopt(struct sock *sock, int level, int optname,
copylen = numsrc * sizeof(gf32->gf_slist[0]);
if (copylen > klen)
copylen = klen;
- if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
+ if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
return -EFAULT;
}
return err;
}
-
EXPORT_SYMBOL(compat_mc_getsockopt);
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
-static unsigned char nas[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4),AL(5)};
+static unsigned char nas[20] = {
+ AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+ AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+ AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+ AL(4), AL(5)
+};
#undef AL
asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, unsigned flags)
@@ -827,7 +824,7 @@ asmlinkage long compat_sys_socketcall(int call, u32 __user *args)
compat_ptr(a[4]), compat_ptr(a[5]));
break;
case SYS_SHUTDOWN:
- ret = sys_shutdown(a0,a1);
+ ret = sys_shutdown(a0, a1);
break;
case SYS_SETSOCKOPT:
ret = compat_sys_setsockopt(a0, a1, a[2],
diff --git a/net/core/dev.c b/net/core/dev.c
index 1845b08c624e..b65347c2cf2a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1577,7 +1577,9 @@ EXPORT_SYMBOL(__netif_schedule);
void dev_kfree_skb_irq(struct sk_buff *skb)
{
- if (atomic_dec_and_test(&skb->users)) {
+ if (!skb->destructor)
+ dev_kfree_skb(skb);
+ else if (atomic_dec_and_test(&skb->users)) {
struct softnet_data *sd;
unsigned long flags;
@@ -2038,14 +2040,24 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
struct netdev_queue *txq)
{
spinlock_t *root_lock = qdisc_lock(q);
+ bool contended = qdisc_is_running(q);
int rc;
+ /*
+ * Heuristic to force contended enqueues to serialize on a
+ * separate lock before trying to get qdisc main lock.
+ * This permits __QDISC_STATE_RUNNING owner to get the lock more often
+ * and dequeue packets faster.
+ */
+ if (unlikely(contended))
+ spin_lock(&q->busylock);
+
spin_lock(root_lock);
if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) {
kfree_skb(skb);
rc = NET_XMIT_DROP;
} else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&
- !test_and_set_bit(__QDISC_STATE_RUNNING, &q->state)) {
+ qdisc_run_begin(q)) {
/*
* This is a work-conserving queue; there are no old skbs
* waiting to be sent out; and the qdisc is not running -
@@ -2054,19 +2066,30 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))
skb_dst_force(skb);
__qdisc_update_bstats(q, skb->len);
- if (sch_direct_xmit(skb, q, dev, txq, root_lock))
+ if (sch_direct_xmit(skb, q, dev, txq, root_lock)) {
+ if (unlikely(contended)) {
+ spin_unlock(&q->busylock);
+ contended = false;
+ }
__qdisc_run(q);
- else
- clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ } else
+ qdisc_run_end(q);
rc = NET_XMIT_SUCCESS;
} else {
skb_dst_force(skb);
rc = qdisc_enqueue_root(skb, q);
- qdisc_run(q);
+ if (qdisc_run_begin(q)) {
+ if (unlikely(contended)) {
+ spin_unlock(&q->busylock);
+ contended = false;
+ }
+ __qdisc_run(q);
+ }
}
spin_unlock(root_lock);
-
+ if (unlikely(contended))
+ spin_unlock(&q->busylock);
return rc;
}
@@ -2080,9 +2103,10 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
static inline int skb_needs_linearize(struct sk_buff *skb,
struct net_device *dev)
{
- return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
- (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
- illegal_highdma(dev, skb)));
+ return skb_is_nonlinear(skb) &&
+ ((skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
+ (skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
+ illegal_highdma(dev, skb))));
}
/**
@@ -2581,70 +2605,14 @@ static inline int deliver_skb(struct sk_buff *skb,
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}
-#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-
-#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
+#if (defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)) && \
+ (defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE))
/* This hook is defined here for ATM LANE */
int (*br_fdb_test_addr_hook)(struct net_device *dev,
unsigned char *addr) __read_mostly;
EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook);
#endif
-/*
- * If bridge module is loaded call bridging hook.
- * returns NULL if packet was consumed.
- */
-struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
- struct sk_buff *skb) __read_mostly;
-EXPORT_SYMBOL_GPL(br_handle_frame_hook);
-
-static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
- struct packet_type **pt_prev, int *ret,
- struct net_device *orig_dev)
-{
- struct net_bridge_port *port;
-
- if (skb->pkt_type == PACKET_LOOPBACK ||
- (port = rcu_dereference(skb->dev->br_port)) == NULL)
- return skb;
-
- if (*pt_prev) {
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
- *pt_prev = NULL;
- }
-
- return br_handle_frame_hook(port, skb);
-}
-#else
-#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb)
-#endif
-
-#if defined(CONFIG_MACVLAN) || defined(CONFIG_MACVLAN_MODULE)
-struct sk_buff *(*macvlan_handle_frame_hook)(struct macvlan_port *p,
- struct sk_buff *skb) __read_mostly;
-EXPORT_SYMBOL_GPL(macvlan_handle_frame_hook);
-
-static inline struct sk_buff *handle_macvlan(struct sk_buff *skb,
- struct packet_type **pt_prev,
- int *ret,
- struct net_device *orig_dev)
-{
- struct macvlan_port *port;
-
- port = rcu_dereference(skb->dev->macvlan_port);
- if (!port)
- return skb;
-
- if (*pt_prev) {
- *ret = deliver_skb(skb, *pt_prev, orig_dev);
- *pt_prev = NULL;
- }
- return macvlan_handle_frame_hook(port, skb);
-}
-#else
-#define handle_macvlan(skb, pt_prev, ret, orig_dev) (skb)
-#endif
-
#ifdef CONFIG_NET_CLS_ACT
/* TODO: Maybe we should just force sch_ingress to be compiled in
* when CONFIG_NET_CLS_ACT is? otherwise some useless instructions
@@ -2740,6 +2708,47 @@ void netif_nit_deliver(struct sk_buff *skb)
rcu_read_unlock();
}
+/**
+ * netdev_rx_handler_register - register receive handler
+ * @dev: device to register a handler for
+ * @rx_handler: receive handler to register
+ *
+ * Register a receive hander for a device. This handler will then be
+ * called from __netif_receive_skb. A negative errno code is returned
+ * on a failure.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+int netdev_rx_handler_register(struct net_device *dev,
+ rx_handler_func_t *rx_handler)
+{
+ ASSERT_RTNL();
+
+ if (dev->rx_handler)
+ return -EBUSY;
+
+ rcu_assign_pointer(dev->rx_handler, rx_handler);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_register);
+
+/**
+ * netdev_rx_handler_unregister - unregister receive handler
+ * @dev: device to unregister a handler from
+ *
+ * Unregister a receive hander from a device.
+ *
+ * The caller must hold the rtnl_mutex.
+ */
+void netdev_rx_handler_unregister(struct net_device *dev)
+{
+
+ ASSERT_RTNL();
+ rcu_assign_pointer(dev->rx_handler, NULL);
+}
+EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister);
+
static inline void skb_bond_set_mac_by_master(struct sk_buff *skb,
struct net_device *master)
{
@@ -2792,10 +2801,11 @@ EXPORT_SYMBOL(__skb_bond_should_drop);
static int __netif_receive_skb(struct sk_buff *skb)
{
struct packet_type *ptype, *pt_prev;
+ rx_handler_func_t *rx_handler;
struct net_device *orig_dev;
struct net_device *master;
struct net_device *null_or_orig;
- struct net_device *null_or_bond;
+ struct net_device *orig_or_bond;
int ret = NET_RX_DROP;
__be16 type;
@@ -2822,8 +2832,7 @@ static int __netif_receive_skb(struct sk_buff *skb)
skb->dev = master;
}
- __get_cpu_var(softnet_data).processed++;
-
+ __this_cpu_inc(softnet_data.processed);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
skb->mac_len = skb->network_header - skb->mac_header;
@@ -2855,12 +2864,17 @@ static int __netif_receive_skb(struct sk_buff *skb)
ncls:
#endif
- skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
- if (!skb)
- goto out;
- skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
- if (!skb)
- goto out;
+ /* Handle special case of bridge or macvlan */
+ rx_handler = rcu_dereference(skb->dev->rx_handler);
+ if (rx_handler) {
+ if (pt_prev) {
+ ret = deliver_skb(skb, pt_prev, orig_dev);
+ pt_prev = NULL;
+ }
+ skb = rx_handler(skb);
+ if (!skb)
+ goto out;
+ }
/*
* Make sure frames received on VLAN interfaces stacked on
@@ -2868,10 +2882,10 @@ ncls:
* device that may have registered for a specific ptype. The
* handler may have to adjust skb->dev and orig_dev.
*/
- null_or_bond = NULL;
+ orig_or_bond = orig_dev;
if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
(vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
- null_or_bond = vlan_dev_real_dev(skb->dev);
+ orig_or_bond = vlan_dev_real_dev(skb->dev);
}
type = skb->protocol;
@@ -2879,7 +2893,7 @@ ncls:
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
if (ptype->type == type && (ptype->dev == null_or_orig ||
ptype->dev == skb->dev || ptype->dev == orig_dev ||
- ptype->dev == null_or_bond)) {
+ ptype->dev == orig_or_bond)) {
if (pt_prev)
ret = deliver_skb(skb, pt_prev, orig_dev);
pt_prev = ptype;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 94825b109551..e034342c819c 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -49,7 +49,6 @@ static atomic_t trapped;
(MAX_UDP_CHUNK + sizeof(struct udphdr) + \
sizeof(struct iphdr) + sizeof(struct ethhdr))
-static void zap_completion_queue(void);
static void arp_reply(struct sk_buff *skb);
static unsigned int carrier_timeout = 4;
@@ -197,7 +196,6 @@ void netpoll_poll_dev(struct net_device *dev)
service_arp_queue(dev->npinfo);
- zap_completion_queue();
}
void netpoll_poll(struct netpoll *np)
@@ -221,40 +219,11 @@ static void refill_skbs(void)
spin_unlock_irqrestore(&skb_pool.lock, flags);
}
-static void zap_completion_queue(void)
-{
- unsigned long flags;
- struct softnet_data *sd = &get_cpu_var(softnet_data);
-
- if (sd->completion_queue) {
- struct sk_buff *clist;
-
- local_irq_save(flags);
- clist = sd->completion_queue;
- sd->completion_queue = NULL;
- local_irq_restore(flags);
-
- while (clist != NULL) {
- struct sk_buff *skb = clist;
- clist = clist->next;
- if (skb->destructor) {
- atomic_inc(&skb->users);
- dev_kfree_skb_any(skb); /* put this one back */
- } else {
- __kfree_skb(skb);
- }
- }
- }
-
- put_cpu_var(softnet_data);
-}
-
static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
{
int count = 0;
struct sk_buff *skb;
- zap_completion_queue();
refill_skbs();
repeat:
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index f8abf68e3988..9f07e749d7b1 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -482,22 +482,22 @@ EXPORT_SYMBOL(consume_skb);
* reference count dropping and cleans up the skbuff as if it
* just came from __alloc_skb().
*/
-int skb_recycle_check(struct sk_buff *skb, int skb_size)
+bool skb_recycle_check(struct sk_buff *skb, int skb_size)
{
struct skb_shared_info *shinfo;
if (irqs_disabled())
- return 0;
+ return false;
if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE)
- return 0;
+ return false;
skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);
if (skb_end_pointer(skb) - skb->head < skb_size)
- return 0;
+ return false;
if (skb_shared(skb) || skb_cloned(skb))
- return 0;
+ return false;
skb_release_head_state(skb);
@@ -509,7 +509,7 @@ int skb_recycle_check(struct sk_buff *skb, int skb_size)
skb->data = skb->head + NET_SKB_PAD;
skb_reset_tail_pointer(skb);
- return 1;
+ return true;
}
EXPORT_SYMBOL(skb_recycle_check);
@@ -2965,6 +2965,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
}
EXPORT_SYMBOL_GPL(skb_cow_data);
+static void sock_rmem_free(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+
+ atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
+}
+
+/*
+ * Note: We dont mem charge error packets (no sk_forward_alloc changes)
+ */
+int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
+{
+ if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >=
+ (unsigned)sk->sk_rcvbuf)
+ return -ENOMEM;
+
+ skb_orphan(skb);
+ skb->sk = sk;
+ skb->destructor = sock_rmem_free;
+ atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+
+ skb_queue_tail(&sk->sk_error_queue, skb);
+ if (!sock_flag(sk, SOCK_DEAD))
+ sk->sk_data_ready(sk, skb->len);
+ return 0;
+}
+EXPORT_SYMBOL(sock_queue_err_skb);
+
void skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps)
{
@@ -2996,7 +3024,9 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
+
err = sock_queue_err_skb(sk, skb);
+
if (err)
kfree_skb(skb);
}
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 091698899594..6e3f32575df7 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -248,7 +248,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff *skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
int err = -1;
struct dst_entry *dst;
@@ -265,13 +265,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req,
opt = np->opt;
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -545,19 +539,13 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_DCCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (opt != NULL && opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.fl_ip_dport = inet_rsk(req)->rmt_port;
@@ -885,7 +873,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -988,13 +976,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt != NULL && np->opt->srcrt != NULL) {
- const struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
-
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b03ecf6b2bb0..f79bcef5088f 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -473,14 +473,9 @@ static int dccp_setsockopt_ccid(struct sock *sk, int type,
if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS)
return -EINVAL;
- val = kmalloc(optlen, GFP_KERNEL);
- if (val == NULL)
- return -ENOMEM;
-
- if (copy_from_user(val, optval, optlen)) {
- kfree(val);
- return -EFAULT;
- }
+ val = memdup_user(optval, optlen);
+ if (IS_ERR(val))
+ return PTR_ERR(val);
lock_sock(sk);
if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID)
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 8e3a1fd938ab..7c3a7d191249 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -303,7 +303,7 @@ config ARPD
If unsure, say N.
config SYN_COOKIES
- bool "IP: TCP syncookie support (disabled per default)"
+ bool "IP: TCP syncookie support"
---help---
Normal TCP/IP networking is open to an attack known as "SYN
flooding". This denial-of-service attack prevents legitimate remote
@@ -328,13 +328,13 @@ config SYN_COOKIES
server is really overloaded. If this happens frequently better turn
them off.
- If you say Y here, note that SYN cookies aren't enabled by default;
- you can enable them by saying Y to "/proc file system support" and
+ If you say Y here, you can disable SYN cookies at run time by
+ saying Y to "/proc file system support" and
"Sysctl support" below and executing the command
- echo 1 >/proc/sys/net/ipv4/tcp_syncookies
+ echo 0 > /proc/sys/net/ipv4/tcp_syncookies
- at boot time after the /proc file system has been mounted.
+ after the /proc file system has been mounted.
If unsure, say N.
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index f094b75810db..917d2d66162e 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -545,10 +545,10 @@ static inline int arp_fwd_proxy(struct in_device *in_dev,
/* place to check for proxy_arp for routes */
- if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
+ out_dev = __in_dev_get_rcu(rt->u.dst.dev);
+ if (out_dev)
omi = IN_DEV_MEDIUM_ID(out_dev);
- in_dev_put(out_dev);
- }
+
return (omi != imi && omi != -1);
}
@@ -741,7 +741,7 @@ void arp_send(int type, int ptype, __be32 dest_ip,
static int arp_process(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
struct arphdr *arp;
unsigned char *arp_ptr;
struct rtable *rt;
@@ -890,7 +890,6 @@ static int arp_process(struct sk_buff *skb)
arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
} else {
pneigh_enqueue(&arp_tbl, in_dev->arp_parms, skb);
- in_dev_put(in_dev);
return 0;
}
goto out;
@@ -936,8 +935,6 @@ static int arp_process(struct sk_buff *skb)
}
out:
- if (in_dev)
- in_dev_put(in_dev);
consume_skb(skb);
return 0;
}
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 382bc768ed56..da14c49284f4 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1081,6 +1081,7 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
}
ip_mc_up(in_dev);
/* fall through */
+ case NETDEV_NOTIFY_PEERS:
case NETDEV_CHANGEADDR:
/* Send gratuitous ARP to notify of link change */
if (IN_DEV_ARP_NOTIFY(in_dev)) {
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 4f0ed458c883..e830f7a123bd 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -284,7 +284,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
if (no_addr)
goto last_resort;
if (rpf == 1)
- goto e_inval;
+ goto e_rpf;
fl.oif = dev->ifindex;
ret = 0;
@@ -299,7 +299,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
last_resort:
if (rpf)
- goto e_inval;
+ goto e_rpf;
*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
*itag = 0;
return 0;
@@ -308,6 +308,8 @@ e_inval_res:
fib_res_put(&res);
e_inval:
return -EINVAL;
+e_rpf:
+ return -EXDEV;
}
static inline __be32 sk_extract_addr(struct sockaddr *addr)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 5fff865a4fa7..250cb5e1af48 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1646,8 +1646,7 @@ static int sf_setstate(struct ip_mc_list *pmc)
if (dpsf->sf_inaddr == psf->sf_inaddr)
break;
if (!dpsf) {
- dpsf = (struct ip_sf_list *)
- kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+ dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
if (!dpsf)
continue;
*dpsf = *psf;
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index d930dc5e4d85..d52c9da644cf 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -340,6 +340,9 @@ static int ip_rcv_finish(struct sk_buff *skb)
else if (err == -ENETUNREACH)
IP_INC_STATS_BH(dev_net(skb->dev),
IPSTATS_MIB_INNOROUTES);
+ else if (err == -EXDEV)
+ NET_INC_STATS_BH(dev_net(skb->dev),
+ LINUX_MIB_IPRPFILTER);
goto drop;
}
}
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index b9d84e800cf4..3a6e1ec5e9ae 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -665,6 +665,13 @@ ic_dhcp_init_options(u8 *options)
memcpy(e, ic_req_params, sizeof(ic_req_params));
e += sizeof(ic_req_params);
+ if (ic_host_name_set) {
+ *e++ = 12; /* host-name */
+ len = strlen(utsname()->nodename);
+ *e++ = len;
+ memcpy(e, utsname()->nodename, len);
+ e += len;
+ }
if (*vendor_class_identifier) {
printk(KERN_INFO "DHCP: sending class identifier \"%s\"\n",
vendor_class_identifier);
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 63958f3394a5..4b6c5ca610fc 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -336,7 +336,7 @@ ipt_do_table(struct sk_buff *skb,
cpu = smp_processor_id();
table_base = private->entries[cpu];
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
- stackptr = &private->stackptr[cpu];
+ stackptr = per_cpu_ptr(private->stackptr, cpu);
origptr = *stackptr;
e = get_entry(table_base, private->hook_entry[hook]);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 3dc9914c1dce..e320ca6b3ef3 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -252,6 +252,7 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPBacklogDrop", LINUX_MIB_TCPBACKLOGDROP),
SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
+ SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
SNMP_MIB_SENTINEL
};
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 560acc677ce4..7b8eacd5ac26 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -253,8 +253,7 @@ static unsigned rt_hash_mask __read_mostly;
static unsigned int rt_hash_log __read_mostly;
static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
-#define RT_CACHE_STAT_INC(field) \
- (__raw_get_cpu_var(rt_cache_stat).field++)
+#define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx,
int genid)
@@ -1844,14 +1843,16 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
rt->rt_type = res->type;
}
+/* called in rcu_read_lock() section */
static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev, int our)
{
- unsigned hash;
+ unsigned int hash;
struct rtable *rth;
__be32 spec_dst;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
u32 itag = 0;
+ int err;
/* Primary sanity checks. */
@@ -1866,10 +1867,12 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
if (!ipv4_is_local_multicast(daddr))
goto e_inval;
spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
- } else if (fib_validate_source(saddr, 0, tos, 0,
- dev, &spec_dst, &itag, 0) < 0)
- goto e_inval;
-
+ } else {
+ err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
+ &itag, 0);
+ if (err < 0)
+ goto e_err;
+ }
rth = dst_alloc(&ipv4_dst_ops);
if (!rth)
goto e_nobufs;
@@ -1912,17 +1915,15 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
#endif
RT_CACHE_STAT_INC(in_slow_mc);
- in_dev_put(in_dev);
hash = rt_hash(daddr, saddr, dev->ifindex, rt_genid(dev_net(dev)));
return rt_intern_hash(hash, rth, NULL, skb, dev->ifindex);
e_nobufs:
- in_dev_put(in_dev);
return -ENOBUFS;
-
e_inval:
- in_dev_put(in_dev);
return -EINVAL;
+e_err:
+ return err;
}
@@ -1956,22 +1957,22 @@ static void ip_handle_martian_source(struct net_device *dev,
#endif
}
+/* called in rcu_read_lock() section */
static int __mkroute_input(struct sk_buff *skb,
struct fib_result *res,
struct in_device *in_dev,
__be32 daddr, __be32 saddr, u32 tos,
struct rtable **result)
{
-
struct rtable *rth;
int err;
struct in_device *out_dev;
- unsigned flags = 0;
+ unsigned int flags = 0;
__be32 spec_dst;
u32 itag;
/* get a working reference to the output device */
- out_dev = in_dev_get(FIB_RES_DEV(*res));
+ out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res));
if (out_dev == NULL) {
if (net_ratelimit())
printk(KERN_CRIT "Bug in ip_route_input" \
@@ -1986,7 +1987,6 @@ static int __mkroute_input(struct sk_buff *skb,
ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
saddr);
- err = -EINVAL;
goto cleanup;
}
@@ -2053,8 +2053,6 @@ static int __mkroute_input(struct sk_buff *skb,
*result = rth;
err = 0;
cleanup:
- /* release the working reference to the output device */
- in_dev_put(out_dev);
return err;
}
@@ -2098,7 +2096,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct fib_result res;
- struct in_device *in_dev = in_dev_get(dev);
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = daddr,
.saddr = saddr,
@@ -2158,13 +2156,12 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
goto brd_input;
if (res.type == RTN_LOCAL) {
- int result;
- result = fib_validate_source(saddr, daddr, tos,
+ err = fib_validate_source(saddr, daddr, tos,
net->loopback_dev->ifindex,
dev, &spec_dst, &itag, skb->mark);
- if (result < 0)
- goto martian_source;
- if (result)
+ if (err < 0)
+ goto martian_source_keep_err;
+ if (err)
flags |= RTCF_DIRECTSRC;
spec_dst = daddr;
goto local_input;
@@ -2177,7 +2174,6 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
err = ip_mkroute_input(skb, &res, &fl, in_dev, daddr, saddr, tos);
done:
- in_dev_put(in_dev);
if (free_res)
fib_res_put(&res);
out: return err;
@@ -2192,7 +2188,7 @@ brd_input:
err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
&itag, skb->mark);
if (err < 0)
- goto martian_source;
+ goto martian_source_keep_err;
if (err)
flags |= RTCF_DIRECTSRC;
}
@@ -2273,8 +2269,10 @@ e_nobufs:
goto done;
martian_source:
+ err = -EINVAL;
+martian_source_keep_err:
ip_handle_martian_source(dev, in_dev, skb, daddr, saddr);
- goto e_inval;
+ goto done;
}
int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
@@ -2284,16 +2282,18 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
unsigned hash;
int iif = dev->ifindex;
struct net *net;
+ int res;
net = dev_net(dev);
+ rcu_read_lock();
+
if (!rt_caching(net))
goto skip_cache;
tos &= IPTOS_RT_MASK;
hash = rt_hash(daddr, saddr, iif, rt_genid(net));
- rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
rth = rcu_dereference(rth->u.dst.rt_next)) {
if ((((__force u32)rth->fl.fl4_dst ^ (__force u32)daddr) |
@@ -2317,7 +2317,6 @@ int ip_route_input_common(struct sk_buff *skb, __be32 daddr, __be32 saddr,
}
RT_CACHE_STAT_INC(in_hlist_search);
}
- rcu_read_unlock();
skip_cache:
/* Multicast recognition logic is moved from route cache to here.
@@ -2332,12 +2331,11 @@ skip_cache:
route cache entry is created eventually.
*/
if (ipv4_is_multicast(daddr)) {
- struct in_device *in_dev;
+ struct in_device *in_dev = __in_dev_get_rcu(dev);
- rcu_read_lock();
- if ((in_dev = __in_dev_get_rcu(dev)) != NULL) {
+ if (in_dev) {
int our = ip_check_mc(in_dev, daddr, saddr,
- ip_hdr(skb)->protocol);
+ ip_hdr(skb)->protocol);
if (our
#ifdef CONFIG_IP_MROUTE
||
@@ -2345,15 +2343,18 @@ skip_cache:
IN_DEV_MFORWARD(in_dev))
#endif
) {
+ int res = ip_route_input_mc(skb, daddr, saddr,
+ tos, dev, our);
rcu_read_unlock();
- return ip_route_input_mc(skb, daddr, saddr,
- tos, dev, our);
+ return res;
}
}
rcu_read_unlock();
return -EINVAL;
}
- return ip_route_input_slow(skb, daddr, saddr, tos, dev);
+ res = ip_route_input_slow(skb, daddr, saddr, tos, dev);
+ rcu_read_unlock();
+ return res;
}
EXPORT_SYMBOL(ip_route_input_common);
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index 5c24db4a3c91..5c48124332de 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -138,23 +138,23 @@ static __u32 check_tcp_syn_cookie(__u32 cookie, __be32 saddr, __be32 daddr,
}
/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
+ * MSS Values are taken from the 2009 paper
+ * 'Measuring TCP Maximum Segment Size' by S. Alcock and R. Nelson:
+ * - values 1440 to 1460 accounted for 80% of observed mss values
+ * - values outside the 536-1460 range are rare (<0.2%).
+ *
+ * Table must be sorted.
*/
static __u16 const msstab[] = {
- 64 - 1,
- 256 - 1,
- 512 - 1,
- 536 - 1,
- 1024 - 1,
- 1440 - 1,
- 1460 - 1,
- 4312 - 1,
- (__u16)-1
+ 64,
+ 512,
+ 536,
+ 1024,
+ 1440,
+ 1460,
+ 4312,
+ 8960,
};
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
/*
* Generate a syncookie. mssp points to the mss, which is returned
@@ -169,10 +169,10 @@ __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
tcp_synq_overflow(sk);
- /* XXX sort msstab[] by probability? Binary search? */
- for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
- ;
- *mssp = msstab[mssind] + 1;
+ for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+ if (mss >= msstab[mssind])
+ break;
+ *mssp = msstab[mssind];
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
@@ -202,7 +202,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
jiffies / (HZ * 60),
COUNTER_TRIES);
- return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+ return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}
static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb,
@@ -266,7 +266,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct rtable *rt;
__u8 rcv_wscale;
- if (!sysctl_tcp_syncookies || !th->ack)
+ if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
if (tcp_synq_no_recent_overflow(sk) ||
@@ -347,7 +347,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
{ .sport = th->dest,
.dport = th->source } } };
security_req_classify_flow(req, &fl);
- if (ip_route_output_key(&init_net, &rt, &fl)) {
+ if (ip_route_output_key(sock_net(sk), &rt, &fl)) {
reqsk_free(req);
goto out;
}
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 6596b4feeddc..49d0d2b8900c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2999,6 +2999,7 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
const unsigned head_data_len = skb_headlen(skb) > header_len ?
skb_headlen(skb) - header_len : 0;
const struct skb_shared_info *shi = skb_shinfo(skb);
+ struct sk_buff *frag_iter;
sg_init_table(&sg, 1);
@@ -3013,6 +3014,10 @@ int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp,
return 1;
}
+ skb_walk_frags(skb, frag_iter)
+ if (tcp_md5_hash_skb_data(hp, frag_iter, 0))
+ return 1;
+
return 0;
}
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
index c209e054a634..377bc9349371 100644
--- a/net/ipv4/tcp_hybla.c
+++ b/net/ipv4/tcp_hybla.c
@@ -126,8 +126,8 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
* calculate 2^fract in a <<7 value.
*/
is_slowstart = 1;
- increment = ((1 << ca->rho) * hybla_fraction(rho_fractions))
- - 128;
+ increment = ((1 << min(ca->rho, 16U)) *
+ hybla_fraction(rho_fractions)) - 128;
} else {
/*
* congestion avoidance
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 3e6dafcb1071..548d575e6cc6 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2639,7 +2639,7 @@ static void DBGUNDO(struct sock *sk, const char *msg)
if (sk->sk_family == AF_INET) {
printk(KERN_DEBUG "Undo %s %pI4/%u c%u l%u ss%u/%u p%u\n",
msg,
- &inet->daddr, ntohs(inet->dport),
+ &inet->inet_daddr, ntohs(inet->inet_dport),
tp->snd_cwnd, tcp_left_out(tp),
tp->snd_ssthresh, tp->prior_ssthresh,
tp->packets_out);
@@ -2649,7 +2649,7 @@ static void DBGUNDO(struct sock *sk, const char *msg)
struct ipv6_pinfo *np = inet6_sk(sk);
printk(KERN_DEBUG "Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n",
msg,
- &np->daddr, ntohs(inet->dport),
+ &np->daddr, ntohs(inet->inet_dport),
tp->snd_cwnd, tcp_left_out(tp),
tp->snd_ssthresh, tp->prior_ssthresh,
tp->packets_out);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 202cf09c4cd4..acdc4c989853 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -793,19 +793,20 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
kfree(inet_rsk(req)->opt);
}
-#ifdef CONFIG_SYN_COOKIES
-static void syn_flood_warning(struct sk_buff *skb)
+static void syn_flood_warning(const struct sk_buff *skb)
{
- static unsigned long warntime;
+ const char *msg;
- if (time_after(jiffies, (warntime + HZ * 60))) {
- warntime = jiffies;
- printk(KERN_INFO
- "possible SYN flooding on port %d. Sending cookies.\n",
- ntohs(tcp_hdr(skb)->dest));
- }
-}
+#ifdef CONFIG_SYN_COOKIES
+ if (sysctl_tcp_syncookies)
+ msg = "Sending cookies";
+ else
#endif
+ msg = "Dropping request";
+
+ pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
+ ntohs(tcp_hdr(skb)->dest), msg);
+}
/*
* Save and compile IPv4 options into the request_sock if needed.
@@ -1243,6 +1244,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* evidently real one.
*/
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
+ if (net_ratelimit())
+ syn_flood_warning(skb);
#ifdef CONFIG_SYN_COOKIES
if (sysctl_tcp_syncookies) {
want_cookie = 1;
@@ -1328,7 +1331,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (want_cookie) {
#ifdef CONFIG_SYN_COOKIES
- syn_flood_warning(skb);
req->cookie_ts = tmp_opt.tstamp_ok;
#endif
isn = cookie_v4_init_sequence(sk, skb, &req->mss);
@@ -1504,7 +1506,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
}
#ifdef CONFIG_SYN_COOKIES
- if (!th->rst && !th->syn && th->ack)
+ if (!th->syn)
sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
#endif
return sk;
@@ -1555,6 +1557,7 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
#endif
if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+ sock_rps_save_rxhash(sk, skb->rxhash);
TCP_CHECK_TIMER(sk);
if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
rsk = sk;
@@ -1579,7 +1582,9 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
}
return 0;
}
- }
+ } else
+ sock_rps_save_rxhash(sk, skb->rxhash);
+
TCP_CHECK_TIMER(sk);
if (tcp_rcv_state_process(sk, skb, tcp_hdr(skb), skb->len)) {
@@ -1672,8 +1677,6 @@ process:
skb->dev = NULL;
- sock_rps_save_rxhash(sk, skb->rxhash);
-
bh_lock_sock_nested(sk);
ret = 0;
if (!sock_owned_by_user(sk)) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 58585748bdac..eec4ff456e33 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -633,9 +633,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
if (!inet->recverr) {
if (!harderr || sk->sk_state != TCP_ESTABLISHED)
goto out;
- } else {
+ } else
ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1));
- }
+
sk->sk_err = err;
sk->sk_error_report(sk);
out:
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 8c4348cb1950..f0e774cea386 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -53,11 +53,7 @@ static struct ip6addrlbl_table
static inline
struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
{
-#ifdef CONFIG_NET_NS
- return lbl->lbl_net;
-#else
- return &init_net;
-#endif
+ return read_pnet(&lbl->lbl_net);
}
/*
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index e733942dafe1..94b1b9c954bf 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -651,7 +651,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
if (dst == NULL) {
struct inet_sock *inet = inet_sk(sk);
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
@@ -665,12 +665,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl.fl_ip_sport = inet->inet_sport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err) {
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 712684687c9a..7d929a22cbc2 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -38,10 +38,11 @@ int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct dst_entry *dst;
struct flowi fl;
struct ip6_flowlabel *flowlabel = NULL;
+ struct ipv6_txoptions *opt;
int addr_type;
int err;
@@ -155,19 +156,8 @@ ipv4_connected:
security_sk_classify_flow(sk, &fl);
- if (flowlabel) {
- if (flowlabel->opt && flowlabel->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) flowlabel->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
- } else if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ opt = flowlabel ? flowlabel->opt : np->opt;
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index 8a659f92d17a..853a633a94d4 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -874,3 +874,27 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space,
return opt;
}
+/**
+ * fl6_update_dst - update flowi destination address with info given
+ * by srcrt option, if any.
+ *
+ * @fl: flowi for which fl6_dst is to be updated
+ * @opt: struct ipv6_txoptions in which to look for srcrt opt
+ * @orig: copy of original fl6_dst address if modified
+ *
+ * Returns NULL if no txoptions or no srcrt, otherwise returns orig
+ * and initial value of fl->fl6_dst set in orig
+ */
+struct in6_addr *fl6_update_dst(struct flowi *fl,
+ const struct ipv6_txoptions *opt,
+ struct in6_addr *orig)
+{
+ if (!opt || !opt->srcrt)
+ return NULL;
+
+ ipv6_addr_copy(orig, &fl->fl6_dst);
+ ipv6_addr_copy(&fl->fl6_dst, ((struct rt0_hdr *)opt->srcrt)->addr);
+ return orig;
+}
+
+EXPORT_SYMBOL_GPL(fl6_update_dst);
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 0c5e3c3b7fd5..8a1628023bd1 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -185,7 +185,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi fl;
struct dst_entry *dst;
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
memset(&fl, 0, sizeof(fl));
fl.proto = sk->sk_protocol;
@@ -199,12 +199,7 @@ int inet6_csk_xmit(struct sk_buff *skb)
fl.fl_ip_dport = inet->inet_dport;
security_sk_classify_flow(sk, &fl);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 073071f2b75b..89c0b077c7aa 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -120,7 +120,7 @@ static void mroute_clean_tables(struct mr6_table *mrt);
static void ipmr_expire_process(unsigned long arg);
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
-#define ip6mr_for_each_table(mrt, met) \
+#define ip6mr_for_each_table(mrt, net) \
list_for_each_entry_rcu(mrt, &net->ipv6.mr6_tables, list)
static struct mr6_table *ip6mr_get_table(struct net *net, u32 id)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 59f1881968c7..8752e8084806 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1356,7 +1356,10 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
IPV6_TLV_PADN, 0 };
/* we assume size > sizeof(ra) here */
- skb = sock_alloc_send_skb(sk, size + LL_ALLOCATED_SPACE(dev), 1, &err);
+ size += LL_ALLOCATED_SPACE(dev);
+ /* limit our allocations to order-0 page */
+ size = min_t(int, size, SKB_MAX_ORDER(0, 0));
+ skb = sock_alloc_send_skb(sk, size, 1, &err);
if (!skb)
return NULL;
@@ -1995,8 +1998,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)
&psf->sf_addr))
break;
if (!dpsf) {
- dpsf = (struct ip6_sf_list *)
- kmalloc(sizeof(*dpsf), GFP_ATOMIC);
+ dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC);
if (!dpsf)
continue;
*dpsf = *psf;
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 6f517bd83692..9d2d68f0e605 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -363,7 +363,7 @@ ip6t_do_table(struct sk_buff *skb,
cpu = smp_processor_id();
table_base = private->entries[cpu];
jumpstack = (struct ip6t_entry **)private->jumpstack[cpu];
- stackptr = &private->stackptr[cpu];
+ stackptr = per_cpu_ptr(private->stackptr, cpu);
origptr = *stackptr;
e = get_entry(table_base, private->hook_entry[hook]);
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4a4dcbe4f8b2..864eb8e03b1b 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -725,7 +725,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
{
struct ipv6_txoptions opt_space;
struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct raw6_sock *rp = raw6_sk(sk);
@@ -847,13 +847,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk,
if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
fl.oif = np->mcast_oif;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 294cbe8b0725..252d76199c41 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -814,7 +814,7 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk,
{
int flags = 0;
- if (fl->oif || rt6_need_strict(&fl->fl6_dst))
+ if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE;
if (!ipv6_addr_any(&fl->fl6_src))
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index e51e650ea80b..702c532ec21e 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -249,8 +249,6 @@ failed:
return NULL;
}
-static DEFINE_SPINLOCK(ipip6_prl_lock);
-
#define for_each_prl_rcu(start) \
for (prl = rcu_dereference(start); \
prl; \
@@ -340,7 +338,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
if (a->addr == htonl(INADDR_ANY))
return -EINVAL;
- spin_lock(&ipip6_prl_lock);
+ ASSERT_RTNL();
for (p = t->prl; p; p = p->next) {
if (p->addr == a->addr) {
@@ -370,7 +368,6 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg)
t->prl_count++;
rcu_assign_pointer(t->prl, p);
out:
- spin_unlock(&ipip6_prl_lock);
return err;
}
@@ -397,7 +394,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
struct ip_tunnel_prl_entry *x, **p;
int err = 0;
- spin_lock(&ipip6_prl_lock);
+ ASSERT_RTNL();
if (a && a->addr != htonl(INADDR_ANY)) {
for (p = &t->prl; *p; p = &(*p)->next) {
@@ -419,7 +416,6 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a)
}
}
out:
- spin_unlock(&ipip6_prl_lock);
return err;
}
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 34d1f0690d7e..70d330f8c990 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -27,28 +27,17 @@ extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
-/*
- * This table has to be sorted and terminated with (__u16)-1.
- * XXX generate a better table.
- * Unresolved Issues: HIPPI with a 64k MSS is not well supported.
- *
- * Taken directly from ipv4 implementation.
- * Should this list be modified for ipv6 use or is it close enough?
- * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart
- */
+/* Table must be sorted. */
static __u16 const msstab[] = {
- 64 - 1,
- 256 - 1,
- 512 - 1,
- 536 - 1,
- 1024 - 1,
- 1440 - 1,
- 1460 - 1,
- 4312 - 1,
- (__u16)-1
+ 64,
+ 512,
+ 536,
+ 1280 - 60,
+ 1480 - 60,
+ 1500 - 60,
+ 4460 - 60,
+ 9000 - 60,
};
-/* The number doesn't include the -1 terminator */
-#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
/*
* This (misnamed) value is the age of syncookie which is permitted.
@@ -134,9 +123,11 @@ __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)
tcp_synq_overflow(sk);
- for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
- ;
- *mssp = msstab[mssind] + 1;
+ for (mssind = ARRAY_SIZE(msstab) - 1; mssind ; mssind--)
+ if (mss >= msstab[mssind])
+ break;
+
+ *mssp = msstab[mssind];
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);
@@ -154,7 +145,7 @@ static inline int cookie_check(struct sk_buff *skb, __u32 cookie)
th->source, th->dest, seq,
jiffies / (HZ * 60), COUNTER_TRIES);
- return mssind < NUM_MSS ? msstab[mssind] + 1 : 0;
+ return mssind < ARRAY_SIZE(msstab) ? msstab[mssind] : 0;
}
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
@@ -174,7 +165,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
struct dst_entry *dst;
__u8 rcv_wscale;
- if (!sysctl_tcp_syncookies || !th->ack)
+ if (!sysctl_tcp_syncookies || !th->ack || th->rst)
goto out;
if (tcp_synq_no_recent_overflow(sk) ||
@@ -240,17 +231,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
* me if there is a preferred way.
*/
{
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr);
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2b7c3a100e2c..5887141ad641 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -129,7 +129,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct inet_connection_sock *icsk = inet_csk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
- struct in6_addr *saddr = NULL, *final_p = NULL, final;
+ struct in6_addr *saddr = NULL, *final_p, final;
struct flowi fl;
struct dst_entry *dst;
int addr_type;
@@ -250,12 +250,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl.fl_ip_dport = usin->sin6_port;
fl.fl_ip_sport = inet->inet_sport;
- if (np->opt && np->opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *)np->opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, np->opt, &final);
security_sk_classify_flow(sk, &fl);
@@ -477,7 +472,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
struct ipv6_pinfo *np = inet6_sk(sk);
struct sk_buff * skb;
struct ipv6_txoptions *opt = NULL;
- struct in6_addr * final_p = NULL, final;
+ struct in6_addr * final_p, final;
struct flowi fl;
struct dst_entry *dst;
int err = -1;
@@ -494,12 +489,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req,
security_req_classify_flow(req, &fl);
opt = np->opt;
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
err = ip6_dst_lookup(sk, &dst, &fl);
if (err)
@@ -1167,7 +1157,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
}
#ifdef CONFIG_SYN_COOKIES
- if (!th->rst && !th->syn && th->ack)
+ if (!th->syn)
sk = cookie_v6_check(sk, skb);
#endif
return sk;
@@ -1392,18 +1382,13 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
goto out_overflow;
if (dst == NULL) {
- struct in6_addr *final_p = NULL, final;
+ struct in6_addr *final_p, final;
struct flowi fl;
memset(&fl, 0, sizeof(fl));
fl.proto = IPPROTO_TCP;
ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr);
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
- }
+ final_p = fl6_update_dst(&fl, opt, &final);
ipv6_addr_copy(&fl.fl6_src, &treq->loc_addr);
fl.oif = sk->sk_bound_dev_if;
fl.mark = sk->sk_mark;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 87be58673b55..1dd1affdead2 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -927,7 +927,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
- struct in6_addr *daddr, *final_p = NULL, final;
+ struct in6_addr *daddr, *final_p, final;
struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL;
struct flowi fl;
@@ -1097,14 +1097,9 @@ do_udp_sendmsg:
ipv6_addr_copy(&fl.fl6_src, &np->saddr);
fl.fl_ip_sport = inet->inet_sport;
- /* merge ip6_build_xmit from ip6_output */
- if (opt && opt->srcrt) {
- struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl.fl6_dst);
- ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
- final_p = &final;
+ final_p = fl6_update_dst(&fl, opt, &final);
+ if (final_p)
connected = 0;
- }
if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
fl.oif = np->mcast_oif;
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c
index f28ad2cc8428..499c045d6910 100644
--- a/net/iucv/iucv.c
+++ b/net/iucv/iucv.c
@@ -1463,7 +1463,7 @@ struct iucv_path_pending {
u32 res3;
u8 ippollfg;
u8 res4[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_pending(struct iucv_irq_data *data)
{
@@ -1524,7 +1524,7 @@ struct iucv_path_complete {
u32 res3;
u8 ippollfg;
u8 res4[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_complete(struct iucv_irq_data *data)
{
@@ -1554,7 +1554,7 @@ struct iucv_path_severed {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_severed(struct iucv_irq_data *data)
{
@@ -1590,7 +1590,7 @@ struct iucv_path_quiesced {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_quiesced(struct iucv_irq_data *data)
{
@@ -1618,7 +1618,7 @@ struct iucv_path_resumed {
u32 res4;
u8 ippollfg;
u8 res5[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_path_resumed(struct iucv_irq_data *data)
{
@@ -1649,7 +1649,7 @@ struct iucv_message_complete {
u32 ipbfln2f;
u8 ippollfg;
u8 res2[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_message_complete(struct iucv_irq_data *data)
{
@@ -1694,7 +1694,7 @@ struct iucv_message_pending {
u32 ipbfln2f;
u8 ippollfg;
u8 res2[3];
-} __attribute__ ((packed));
+} __packed;
static void iucv_message_pending(struct iucv_irq_data *data)
{
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 8a91f6c0bb18..83eec7a8bd1f 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -33,6 +33,13 @@ config MAC80211_RC_MINSTREL
---help---
This option enables the 'minstrel' TX rate control algorithm
+config MAC80211_RC_MINSTREL_HT
+ bool "Minstrel 802.11n support" if EMBEDDED
+ depends on MAC80211_RC_MINSTREL
+ default y
+ ---help---
+ This option enables the 'minstrel_ht' TX rate control algorithm
+
choice
prompt "Default rate control algorithm"
depends on MAC80211_HAS_RC
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 84b48ba8a77e..fdb54e61d637 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -51,7 +51,11 @@ rc80211_pid-$(CONFIG_MAC80211_DEBUGFS) += rc80211_pid_debugfs.o
rc80211_minstrel-y := rc80211_minstrel.o
rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o
+rc80211_minstrel_ht-y := rc80211_minstrel_ht.o
+rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o
+
mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y)
mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y)
+mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y)
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index c163d0a149f4..d1b6664a2532 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -332,14 +332,16 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
spin_unlock(&local->ampdu_lock);
- spin_unlock_bh(&sta->lock);
- /* send an addBA request */
+ /* prepare tid data */
sta->ampdu_mlme.dialog_token_allocator++;
sta->ampdu_mlme.tid_tx[tid]->dialog_token =
sta->ampdu_mlme.dialog_token_allocator;
sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
+ spin_unlock_bh(&sta->lock);
+
+ /* send AddBA request */
ieee80211_send_addba_request(sdata, pubsta->addr, tid,
sta->ampdu_mlme.tid_tx[tid]->dialog_token,
sta->ampdu_mlme.tid_tx[tid]->ssn,
@@ -538,14 +540,13 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
return ret;
}
-int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
- enum ieee80211_back_parties initiator)
+int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
{
struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
- trace_api_stop_tx_ba_session(pubsta, tid, initiator);
+ trace_api_stop_tx_ba_session(pubsta, tid);
if (!local->ops->ampdu_action)
return -EINVAL;
@@ -553,7 +554,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
if (tid >= STA_TID_NUM)
return -EINVAL;
- return __ieee80211_stop_tx_ba_session(sta, tid, initiator);
+ return __ieee80211_stop_tx_ba_session(sta, tid, WLAN_BACK_INITIATOR);
}
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c7000a6ca379..1f76d048388b 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -120,6 +120,9 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_key *key;
int err;
+ if (!netif_running(dev))
+ return -ENETDOWN;
+
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
switch (params->cipher) {
@@ -145,7 +148,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
if (!key)
return -ENOMEM;
- rcu_read_lock();
+ mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
sta = sta_info_get_bss(sdata, mac_addr);
@@ -160,7 +163,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev,
err = 0;
out_unlock:
- rcu_read_unlock();
+ mutex_unlock(&sdata->local->sta_mtx);
return err;
}
@@ -174,7 +177,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- rcu_read_lock();
+ mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
ret = -ENOENT;
@@ -202,7 +205,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
ret = 0;
out_unlock:
- rcu_read_unlock();
+ mutex_unlock(&sdata->local->sta_mtx);
return ret;
}
@@ -305,15 +308,10 @@ static int ieee80211_config_default_key(struct wiphy *wiphy,
struct net_device *dev,
u8 key_idx)
{
- struct ieee80211_sub_if_data *sdata;
-
- rcu_read_lock();
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
ieee80211_set_default_key(sdata, key_idx);
- rcu_read_unlock();
-
return 0;
}
@@ -600,7 +598,7 @@ struct iapp_layer2_update {
u8 ssap; /* 0 */
u8 control;
u8 xid_info[3];
-} __attribute__ ((packed));
+} __packed;
static void ieee80211_send_layer2_update(struct sta_info *sta)
{
@@ -1554,10 +1552,12 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
static int ieee80211_action(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie)
{
return ieee80211_mgd_action(IEEE80211_DEV_TO_SUB_IF(dev), chan,
- channel_type, buf, len, cookie);
+ channel_type, channel_type_valid,
+ buf, len, cookie);
}
struct cfg80211_ops mac80211_config_ops = {
diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
index 5d218c530a4e..32be11e4c4d9 100644
--- a/net/mac80211/chan.c
+++ b/net/mac80211/chan.c
@@ -5,7 +5,7 @@
#include <linux/nl80211.h>
#include "ieee80211_i.h"
-enum ieee80211_chan_mode
+static enum ieee80211_chan_mode
__ieee80211_get_channel_mode(struct ieee80211_local *local,
struct ieee80211_sub_if_data *ignore)
{
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 637929b65ccc..a694c593ff6a 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -307,9 +307,6 @@ static const struct file_operations queues_ops = {
/* statistics stuff */
-#define DEBUGFS_STATS_FILE(name, buflen, fmt, value...) \
- DEBUGFS_READONLY_FILE(stats_ ##name, buflen, fmt, ##value)
-
static ssize_t format_devstat_counter(struct ieee80211_local *local,
char __user *userbuf,
size_t count, loff_t *ppos,
@@ -351,75 +348,16 @@ static const struct file_operations stats_ ##name## _ops = { \
.open = mac80211_open_file_generic, \
};
-#define DEBUGFS_STATS_ADD(name) \
+#define DEBUGFS_STATS_ADD(name, field) \
+ debugfs_create_u32(#name, 0400, statsd, (u32 *) &field);
+#define DEBUGFS_DEVSTATS_ADD(name) \
debugfs_create_file(#name, 0400, statsd, local, &stats_ ##name## _ops);
-DEBUGFS_STATS_FILE(transmitted_fragment_count, 20, "%u",
- local->dot11TransmittedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_transmitted_frame_count, 20, "%u",
- local->dot11MulticastTransmittedFrameCount);
-DEBUGFS_STATS_FILE(failed_count, 20, "%u",
- local->dot11FailedCount);
-DEBUGFS_STATS_FILE(retry_count, 20, "%u",
- local->dot11RetryCount);
-DEBUGFS_STATS_FILE(multiple_retry_count, 20, "%u",
- local->dot11MultipleRetryCount);
-DEBUGFS_STATS_FILE(frame_duplicate_count, 20, "%u",
- local->dot11FrameDuplicateCount);
-DEBUGFS_STATS_FILE(received_fragment_count, 20, "%u",
- local->dot11ReceivedFragmentCount);
-DEBUGFS_STATS_FILE(multicast_received_frame_count, 20, "%u",
- local->dot11MulticastReceivedFrameCount);
-DEBUGFS_STATS_FILE(transmitted_frame_count, 20, "%u",
- local->dot11TransmittedFrameCount);
-#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
-DEBUGFS_STATS_FILE(tx_handlers_drop, 20, "%u",
- local->tx_handlers_drop);
-DEBUGFS_STATS_FILE(tx_handlers_queued, 20, "%u",
- local->tx_handlers_queued);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unencrypted, 20, "%u",
- local->tx_handlers_drop_unencrypted);
-DEBUGFS_STATS_FILE(tx_handlers_drop_fragment, 20, "%u",
- local->tx_handlers_drop_fragment);
-DEBUGFS_STATS_FILE(tx_handlers_drop_wep, 20, "%u",
- local->tx_handlers_drop_wep);
-DEBUGFS_STATS_FILE(tx_handlers_drop_not_assoc, 20, "%u",
- local->tx_handlers_drop_not_assoc);
-DEBUGFS_STATS_FILE(tx_handlers_drop_unauth_port, 20, "%u",
- local->tx_handlers_drop_unauth_port);
-DEBUGFS_STATS_FILE(rx_handlers_drop, 20, "%u",
- local->rx_handlers_drop);
-DEBUGFS_STATS_FILE(rx_handlers_queued, 20, "%u",
- local->rx_handlers_queued);
-DEBUGFS_STATS_FILE(rx_handlers_drop_nullfunc, 20, "%u",
- local->rx_handlers_drop_nullfunc);
-DEBUGFS_STATS_FILE(rx_handlers_drop_defrag, 20, "%u",
- local->rx_handlers_drop_defrag);
-DEBUGFS_STATS_FILE(rx_handlers_drop_short, 20, "%u",
- local->rx_handlers_drop_short);
-DEBUGFS_STATS_FILE(rx_handlers_drop_passive_scan, 20, "%u",
- local->rx_handlers_drop_passive_scan);
-DEBUGFS_STATS_FILE(tx_expand_skb_head, 20, "%u",
- local->tx_expand_skb_head);
-DEBUGFS_STATS_FILE(tx_expand_skb_head_cloned, 20, "%u",
- local->tx_expand_skb_head_cloned);
-DEBUGFS_STATS_FILE(rx_expand_skb_head, 20, "%u",
- local->rx_expand_skb_head);
-DEBUGFS_STATS_FILE(rx_expand_skb_head2, 20, "%u",
- local->rx_expand_skb_head2);
-DEBUGFS_STATS_FILE(rx_handlers_fragments, 20, "%u",
- local->rx_handlers_fragments);
-DEBUGFS_STATS_FILE(tx_status_drop, 20, "%u",
- local->tx_status_drop);
-
-#endif
-
DEBUGFS_DEVSTATS_FILE(dot11ACKFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSFailureCount);
DEBUGFS_DEVSTATS_FILE(dot11FCSErrorCount);
DEBUGFS_DEVSTATS_FILE(dot11RTSSuccessCount);
-
void debugfs_hw_add(struct ieee80211_local *local)
{
struct dentry *phyd = local->hw.wiphy->debugfsdir;
@@ -448,38 +386,60 @@ void debugfs_hw_add(struct ieee80211_local *local)
if (!statsd)
return;
- DEBUGFS_STATS_ADD(transmitted_fragment_count);
- DEBUGFS_STATS_ADD(multicast_transmitted_frame_count);
- DEBUGFS_STATS_ADD(failed_count);
- DEBUGFS_STATS_ADD(retry_count);
- DEBUGFS_STATS_ADD(multiple_retry_count);
- DEBUGFS_STATS_ADD(frame_duplicate_count);
- DEBUGFS_STATS_ADD(received_fragment_count);
- DEBUGFS_STATS_ADD(multicast_received_frame_count);
- DEBUGFS_STATS_ADD(transmitted_frame_count);
+ DEBUGFS_STATS_ADD(transmitted_fragment_count,
+ local->dot11TransmittedFragmentCount);
+ DEBUGFS_STATS_ADD(multicast_transmitted_frame_count,
+ local->dot11MulticastTransmittedFrameCount);
+ DEBUGFS_STATS_ADD(failed_count, local->dot11FailedCount);
+ DEBUGFS_STATS_ADD(retry_count, local->dot11RetryCount);
+ DEBUGFS_STATS_ADD(multiple_retry_count,
+ local->dot11MultipleRetryCount);
+ DEBUGFS_STATS_ADD(frame_duplicate_count,
+ local->dot11FrameDuplicateCount);
+ DEBUGFS_STATS_ADD(received_fragment_count,
+ local->dot11ReceivedFragmentCount);
+ DEBUGFS_STATS_ADD(multicast_received_frame_count,
+ local->dot11MulticastReceivedFrameCount);
+ DEBUGFS_STATS_ADD(transmitted_frame_count,
+ local->dot11TransmittedFrameCount);
#ifdef CONFIG_MAC80211_DEBUG_COUNTERS
- DEBUGFS_STATS_ADD(tx_handlers_drop);
- DEBUGFS_STATS_ADD(tx_handlers_queued);
- DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted);
- DEBUGFS_STATS_ADD(tx_handlers_drop_fragment);
- DEBUGFS_STATS_ADD(tx_handlers_drop_wep);
- DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc);
- DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port);
- DEBUGFS_STATS_ADD(rx_handlers_drop);
- DEBUGFS_STATS_ADD(rx_handlers_queued);
- DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc);
- DEBUGFS_STATS_ADD(rx_handlers_drop_defrag);
- DEBUGFS_STATS_ADD(rx_handlers_drop_short);
- DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan);
- DEBUGFS_STATS_ADD(tx_expand_skb_head);
- DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned);
- DEBUGFS_STATS_ADD(rx_expand_skb_head);
- DEBUGFS_STATS_ADD(rx_expand_skb_head2);
- DEBUGFS_STATS_ADD(rx_handlers_fragments);
- DEBUGFS_STATS_ADD(tx_status_drop);
+ DEBUGFS_STATS_ADD(tx_handlers_drop, local->tx_handlers_drop);
+ DEBUGFS_STATS_ADD(tx_handlers_queued, local->tx_handlers_queued);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unencrypted,
+ local->tx_handlers_drop_unencrypted);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_fragment,
+ local->tx_handlers_drop_fragment);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_wep,
+ local->tx_handlers_drop_wep);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_not_assoc,
+ local->tx_handlers_drop_not_assoc);
+ DEBUGFS_STATS_ADD(tx_handlers_drop_unauth_port,
+ local->tx_handlers_drop_unauth_port);
+ DEBUGFS_STATS_ADD(rx_handlers_drop, local->rx_handlers_drop);
+ DEBUGFS_STATS_ADD(rx_handlers_queued, local->rx_handlers_queued);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc,
+ local->rx_handlers_drop_nullfunc);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_defrag,
+ local->rx_handlers_drop_defrag);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_short,
+ local->rx_handlers_drop_short);
+ DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan,
+ local->rx_handlers_drop_passive_scan);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head,
+ local->tx_expand_skb_head);
+ DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned,
+ local->tx_expand_skb_head_cloned);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head,
+ local->rx_expand_skb_head);
+ DEBUGFS_STATS_ADD(rx_expand_skb_head2,
+ local->rx_expand_skb_head2);
+ DEBUGFS_STATS_ADD(rx_handlers_fragments,
+ local->rx_handlers_fragments);
+ DEBUGFS_STATS_ADD(tx_status_drop,
+ local->tx_status_drop);
#endif
- DEBUGFS_STATS_ADD(dot11ACKFailureCount);
- DEBUGFS_STATS_ADD(dot11RTSFailureCount);
- DEBUGFS_STATS_ADD(dot11FCSErrorCount);
- DEBUGFS_STATS_ADD(dot11RTSSuccessCount);
+ DEBUGFS_DEVSTATS_ADD(dot11ACKFailureCount);
+ DEBUGFS_DEVSTATS_ADD(dot11RTSFailureCount);
+ DEBUGFS_DEVSTATS_ADD(dot11FCSErrorCount);
+ DEBUGFS_DEVSTATS_ADD(dot11RTSSuccessCount);
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index e763f1529ddb..576e024715e3 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -30,7 +30,6 @@ static ssize_t sta_ ##name## _read(struct file *file, \
}
#define STA_READ_D(name, field) STA_READ(name, 20, field, "%d\n")
#define STA_READ_U(name, field) STA_READ(name, 20, field, "%u\n")
-#define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n")
#define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n")
#define STA_OPS(name) \
@@ -52,19 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \
STA_FILE(aid, sta.aid, D);
STA_FILE(dev, sdata->name, S);
-STA_FILE(rx_packets, rx_packets, LU);
-STA_FILE(tx_packets, tx_packets, LU);
-STA_FILE(rx_bytes, rx_bytes, LU);
-STA_FILE(tx_bytes, tx_bytes, LU);
-STA_FILE(rx_duplicates, num_duplicates, LU);
-STA_FILE(rx_fragments, rx_fragments, LU);
-STA_FILE(rx_dropped, rx_dropped, LU);
-STA_FILE(tx_fragments, tx_fragments, LU);
-STA_FILE(tx_filtered, tx_filtered_count, LU);
-STA_FILE(tx_retry_failed, tx_retry_failed, LU);
-STA_FILE(tx_retry_count, tx_retry_count, LU);
STA_FILE(last_signal, last_signal, D);
-STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU);
static ssize_t sta_flags_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
@@ -210,8 +197,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
if (start)
ret = ieee80211_start_tx_ba_session(&sta->sta, tid);
else
- ret = ieee80211_stop_tx_ba_session(&sta->sta, tid,
- WLAN_BACK_RECIPIENT);
+ ret = ieee80211_stop_tx_ba_session(&sta->sta, tid);
} else {
__ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, 3);
ret = 0;
@@ -307,6 +293,13 @@ STA_OPS(ht_capa);
debugfs_create_file(#name, 0400, \
sta->debugfs.dir, sta, &sta_ ##name## _ops);
+#define DEBUGFS_ADD_COUNTER(name, field) \
+ if (sizeof(sta->field) == sizeof(u32)) \
+ debugfs_create_u32(#name, 0400, sta->debugfs.dir, \
+ (u32 *) &sta->field); \
+ else \
+ debugfs_create_u64(#name, 0400, sta->debugfs.dir, \
+ (u64 *) &sta->field);
void ieee80211_sta_debugfs_add(struct sta_info *sta)
{
@@ -339,20 +332,21 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
DEBUGFS_ADD(last_seq_ctrl);
DEBUGFS_ADD(agg_status);
DEBUGFS_ADD(dev);
- DEBUGFS_ADD(rx_packets);
- DEBUGFS_ADD(tx_packets);
- DEBUGFS_ADD(rx_bytes);
- DEBUGFS_ADD(tx_bytes);
- DEBUGFS_ADD(rx_duplicates);
- DEBUGFS_ADD(rx_fragments);
- DEBUGFS_ADD(rx_dropped);
- DEBUGFS_ADD(tx_fragments);
- DEBUGFS_ADD(tx_filtered);
- DEBUGFS_ADD(tx_retry_failed);
- DEBUGFS_ADD(tx_retry_count);
DEBUGFS_ADD(last_signal);
- DEBUGFS_ADD(wep_weak_iv_count);
DEBUGFS_ADD(ht_capa);
+
+ DEBUGFS_ADD_COUNTER(rx_packets, rx_packets);
+ DEBUGFS_ADD_COUNTER(tx_packets, tx_packets);
+ DEBUGFS_ADD_COUNTER(rx_bytes, rx_bytes);
+ DEBUGFS_ADD_COUNTER(tx_bytes, tx_bytes);
+ DEBUGFS_ADD_COUNTER(rx_duplicates, num_duplicates);
+ DEBUGFS_ADD_COUNTER(rx_fragments, rx_fragments);
+ DEBUGFS_ADD_COUNTER(rx_dropped, rx_dropped);
+ DEBUGFS_ADD_COUNTER(tx_fragments, tx_fragments);
+ DEBUGFS_ADD_COUNTER(tx_filtered, tx_filtered_count);
+ DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
+ DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
+ DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
}
void ieee80211_sta_debugfs_remove(struct sta_info *sta)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4f2271316650..7d18a3245e3d 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -83,6 +83,23 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
trace_drv_bss_info_changed(local, sdata, info, changed);
}
+struct in_ifaddr;
+static inline int drv_configure_arp_filter(struct ieee80211_local *local,
+ struct ieee80211_vif *vif,
+ struct in_ifaddr *ifa_list)
+{
+ int ret = 0;
+
+ might_sleep();
+
+ if (local->ops->configure_arp_filter)
+ ret = local->ops->configure_arp_filter(&local->hw, vif,
+ ifa_list);
+
+ trace_drv_configure_arp_filter(local, vif_to_sdata(vif), ifa_list, ret);
+ return ret;
+}
+
static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
struct netdev_hw_addr_list *mc_list)
{
@@ -252,9 +269,6 @@ static inline int drv_sta_add(struct ieee80211_local *local,
if (local->ops->sta_add)
ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
- else if (local->ops->sta_notify)
- local->ops->sta_notify(&local->hw, &sdata->vif,
- STA_NOTIFY_ADD, sta);
trace_drv_sta_add(local, sdata, sta, ret);
@@ -269,9 +283,6 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
if (local->ops->sta_remove)
local->ops->sta_remove(&local->hw, &sdata->vif, sta);
- else if (local->ops->sta_notify)
- local->ops->sta_notify(&local->hw, &sdata->vif,
- STA_NOTIFY_REMOVE, sta);
trace_drv_sta_remove(local, sdata, sta);
}
@@ -349,7 +360,7 @@ static inline int drv_get_survey(struct ieee80211_local *local, int idx,
struct survey_info *survey)
{
int ret = -EOPNOTSUPP;
- if (local->ops->conf_tx)
+ if (local->ops->get_survey)
ret = local->ops->get_survey(&local->hw, idx, survey);
/* trace_drv_get_survey(local, idx, survey, ret); */
return ret;
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 6a9b2342a9c2..6b90630151ab 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -219,6 +219,31 @@ TRACE_EVENT(drv_bss_info_changed,
)
);
+TRACE_EVENT(drv_configure_arp_filter,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct in_ifaddr *ifa_list, int ret),
+
+ TP_ARGS(local, sdata, ifa_list, ret),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->ret = ret;
+ ),
+
+ TP_printk(
+ VIF_PR_FMT LOCAL_PR_FMT " ret:%d",
+ VIF_PR_ARG, LOCAL_PR_ARG, __entry->ret
+ )
+);
+
TRACE_EVENT(drv_prepare_multicast,
TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
@@ -851,25 +876,23 @@ TRACE_EVENT(api_start_tx_ba_cb,
);
TRACE_EVENT(api_stop_tx_ba_session,
- TP_PROTO(struct ieee80211_sta *sta, u16 tid, u16 initiator),
+ TP_PROTO(struct ieee80211_sta *sta, u16 tid),
- TP_ARGS(sta, tid, initiator),
+ TP_ARGS(sta, tid),
TP_STRUCT__entry(
STA_ENTRY
__field(u16, tid)
- __field(u16, initiator)
),
TP_fast_assign(
STA_ASSIGN;
__entry->tid = tid;
- __entry->initiator = initiator;
),
TP_printk(
- STA_PR_FMT " tid:%d initiator:%d",
- STA_PR_ARG, __entry->tid, __entry->initiator
+ STA_PR_FMT " tid:%d",
+ STA_PR_ARG, __entry->tid
)
);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b2cc1fda6cfd..d7a96ced2c83 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -798,6 +798,15 @@ static void ieee80211_ibss_work(struct work_struct *work)
}
}
+static void ieee80211_queue_ibss_work(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+ struct ieee80211_local *local = sdata->local;
+
+ set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
+ ieee80211_queue_work(&local->hw, &ifibss->work);
+}
+
static void ieee80211_ibss_timer(unsigned long data)
{
struct ieee80211_sub_if_data *sdata =
@@ -810,8 +819,7 @@ static void ieee80211_ibss_timer(unsigned long data)
return;
}
- set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
- ieee80211_queue_work(&local->hw, &ifibss->work);
+ ieee80211_queue_ibss_work(sdata);
}
#ifdef CONFIG_PM
@@ -859,7 +867,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
if (!sdata->u.ibss.ssid_len)
continue;
sdata->u.ibss.last_scan_completed = jiffies;
- mod_timer(&sdata->u.ibss.timer, 0);
+ ieee80211_queue_ibss_work(sdata);
}
mutex_unlock(&local->iflist_mtx);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 1a9e2da37a93..1e779e833473 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -746,10 +746,10 @@ struct ieee80211_local {
struct mutex iflist_mtx;
/*
- * Key lock, protects sdata's key_list and sta_info's
+ * Key mutex, protects sdata's key_list and sta_info's
* key pointers (write access, they're RCU.)
*/
- spinlock_t key_lock;
+ struct mutex key_mtx;
/* Scanning and BSS list */
@@ -851,6 +851,7 @@ struct ieee80211_local {
struct work_struct dynamic_ps_disable_work;
struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier;
+ struct notifier_block ifa_notifier;
int user_power_level; /* in dBm */
int power_constr_level; /* in dBm */
@@ -988,6 +989,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie);
ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb);
@@ -996,6 +998,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
+int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_sw_ie *sw_elem,
struct ieee80211_bss *bss,
@@ -1084,7 +1087,7 @@ struct ieee80211_tx_status_rtap_hdr {
u8 padding_for_rate;
__le16 tx_flags;
u8 data_retries;
-} __attribute__ ((packed));
+} __packed;
/* HT */
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 50deb017fd6e..1afa9ec81fe8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -268,7 +268,6 @@ static int ieee80211_open(struct net_device *dev)
changed |= ieee80211_reset_erp_info(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
- ieee80211_enable_keys(sdata);
if (sdata->vif.type == NL80211_IFTYPE_STATION)
netif_carrier_off(dev);
@@ -321,15 +320,6 @@ static int ieee80211_open(struct net_device *dev)
ieee80211_recalc_ps(local, -1);
- /*
- * ieee80211_sta_work is disabled while network interface
- * is down. Therefore, some configuration changes may not
- * yet be effective. Trigger execution of ieee80211_sta_work
- * to fix this.
- */
- if (sdata->vif.type == NL80211_IFTYPE_STATION)
- ieee80211_queue_work(&local->hw, &sdata->u.mgd.work);
-
netif_tx_start_all_queues(dev);
return 0;
@@ -531,8 +521,8 @@ static int ieee80211_stop(struct net_device *dev)
BSS_CHANGED_BEACON_ENABLED);
}
- /* disable all keys for as long as this netdev is down */
- ieee80211_disable_keys(sdata);
+ /* free all remaining keys, there shouldn't be any */
+ ieee80211_free_keys(sdata);
drv_remove_interface(local, &sdata->vif);
}
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index e8f6e3b252d8..d0d9001a4a6a 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -36,80 +36,20 @@
* There is currently no way of knowing this except by looking into
* debugfs.
*
- * All key operations are protected internally so you can call them at
- * any time.
+ * All key operations are protected internally.
*
* Within mac80211, key references are, just as STA structure references,
* protected by RCU. Note, however, that some things are unprotected,
* namely the key->sta dereferences within the hardware acceleration
- * functions. This means that sta_info_destroy() must flush the key todo
- * list.
- *
- * All the direct key list manipulation functions must not sleep because
- * they can operate on STA info structs that are protected by RCU.
+ * functions. This means that sta_info_destroy() must remove the key
+ * which waits for an RCU grace period.
*/
static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
-/* key mutex: used to synchronise todo runners */
-static DEFINE_MUTEX(key_mutex);
-static DEFINE_SPINLOCK(todo_lock);
-static LIST_HEAD(todo_list);
-
-static void key_todo(struct work_struct *work)
+static void assert_key_lock(struct ieee80211_local *local)
{
- ieee80211_key_todo();
-}
-
-static DECLARE_WORK(todo_work, key_todo);
-
-/**
- * add_todo - add todo item for a key
- *
- * @key: key to add to do item for
- * @flag: todo flag(s)
- *
- * Must be called with IRQs or softirqs disabled.
- */
-static void add_todo(struct ieee80211_key *key, u32 flag)
-{
- if (!key)
- return;
-
- spin_lock(&todo_lock);
- key->flags |= flag;
- /*
- * Remove again if already on the list so that we move it to the end.
- */
- if (!list_empty(&key->todo))
- list_del(&key->todo);
- list_add_tail(&key->todo, &todo_list);
- schedule_work(&todo_work);
- spin_unlock(&todo_lock);
-}
-
-/**
- * ieee80211_key_lock - lock the mac80211 key operation lock
- *
- * This locks the (global) mac80211 key operation lock, all
- * key operations must be done under this lock.
- */
-static void ieee80211_key_lock(void)
-{
- mutex_lock(&key_mutex);
-}
-
-/**
- * ieee80211_key_unlock - unlock the mac80211 key operation lock
- */
-static void ieee80211_key_unlock(void)
-{
- mutex_unlock(&key_mutex);
-}
-
-static void assert_key_lock(void)
-{
- WARN_ON(!mutex_is_locked(&key_mutex));
+ WARN_ON(!mutex_is_locked(&local->key_mtx));
}
static struct ieee80211_sta *get_sta_for_key(struct ieee80211_key *key)
@@ -126,12 +66,13 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
struct ieee80211_sta *sta;
int ret;
- assert_key_lock();
might_sleep();
if (!key->local->ops->set_key)
return;
+ assert_key_lock(key->local);
+
sta = get_sta_for_key(key);
sdata = key->sdata;
@@ -142,11 +83,8 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
ret = drv_set_key(key->local, SET_KEY, sdata, sta, &key->conf);
- if (!ret) {
- spin_lock_bh(&todo_lock);
+ if (!ret)
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock_bh(&todo_lock);
- }
if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP)
printk(KERN_ERR "mac80211-%s: failed to set key "
@@ -161,18 +99,15 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
struct ieee80211_sta *sta;
int ret;
- assert_key_lock();
might_sleep();
if (!key || !key->local->ops->set_key)
return;
- spin_lock_bh(&todo_lock);
- if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) {
- spin_unlock_bh(&todo_lock);
+ assert_key_lock(key->local);
+
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
return;
- }
- spin_unlock_bh(&todo_lock);
sta = get_sta_for_key(key);
sdata = key->sdata;
@@ -191,9 +126,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
wiphy_name(key->local->hw.wiphy),
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
- spin_lock_bh(&todo_lock);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
- spin_unlock_bh(&todo_lock);
}
static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
@@ -201,22 +134,24 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_key *key = NULL;
+ assert_key_lock(sdata->local);
+
if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
key = sdata->keys[idx];
rcu_assign_pointer(sdata->default_key, key);
- if (key)
- add_todo(key, KEY_FLAG_TODO_DEFKEY);
+ if (key) {
+ ieee80211_debugfs_key_remove_default(key->sdata);
+ ieee80211_debugfs_key_add_default(key->sdata);
+ }
}
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
__ieee80211_set_default_key(sdata, idx);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
static void
@@ -224,24 +159,26 @@ __ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata, int idx)
{
struct ieee80211_key *key = NULL;
+ assert_key_lock(sdata->local);
+
if (idx >= NUM_DEFAULT_KEYS &&
idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
key = sdata->keys[idx];
rcu_assign_pointer(sdata->default_mgmt_key, key);
- if (key)
- add_todo(key, KEY_FLAG_TODO_DEFMGMTKEY);
+ if (key) {
+ ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
+ ieee80211_debugfs_key_add_mgmt_default(key->sdata);
+ }
}
void ieee80211_set_default_mgmt_key(struct ieee80211_sub_if_data *sdata,
int idx)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
__ieee80211_set_default_mgmt_key(sdata, idx);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
@@ -352,7 +289,6 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
}
memcpy(key->conf.key, key_data, key_len);
INIT_LIST_HEAD(&key->list);
- INIT_LIST_HEAD(&key->todo);
if (alg == ALG_CCMP) {
/*
@@ -382,12 +318,27 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg,
return key;
}
+static void __ieee80211_key_destroy(struct ieee80211_key *key)
+{
+ if (!key)
+ return;
+
+ ieee80211_key_disable_hw_accel(key);
+
+ if (key->conf.alg == ALG_CCMP)
+ ieee80211_aes_key_free(key->u.ccmp.tfm);
+ if (key->conf.alg == ALG_AES_CMAC)
+ ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
+ ieee80211_debugfs_key_remove(key);
+
+ kfree(key);
+}
+
void ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta)
{
struct ieee80211_key *old_key;
- unsigned long flags;
int idx;
BUG_ON(!sdata);
@@ -431,7 +382,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
}
}
- spin_lock_irqsave(&sdata->local->key_lock, flags);
+ mutex_lock(&sdata->local->key_mtx);
if (sta)
old_key = sta->key;
@@ -439,15 +390,13 @@ void ieee80211_key_link(struct ieee80211_key *key,
old_key = sdata->keys[idx];
__ieee80211_key_replace(sdata, sta, old_key, key);
+ __ieee80211_key_destroy(old_key);
- /* free old key later */
- add_todo(old_key, KEY_FLAG_TODO_DELETE);
+ ieee80211_debugfs_key_add(key);
- add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS);
- if (ieee80211_sdata_running(sdata))
- add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD);
+ ieee80211_key_enable_hw_accel(key);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
+ mutex_unlock(&sdata->local->key_mtx);
}
static void __ieee80211_key_free(struct ieee80211_key *key)
@@ -458,170 +407,65 @@ static void __ieee80211_key_free(struct ieee80211_key *key)
if (key->sdata)
__ieee80211_key_replace(key->sdata, key->sta,
key, NULL);
-
- add_todo(key, KEY_FLAG_TODO_DELETE);
+ __ieee80211_key_destroy(key);
}
void ieee80211_key_free(struct ieee80211_key *key)
{
- unsigned long flags;
+ struct ieee80211_local *local;
if (!key)
return;
- if (!key->sdata) {
- /* The key has not been linked yet, simply free it
- * and don't Oops */
- if (key->conf.alg == ALG_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- kfree(key);
- return;
- }
+ local = key->sdata->local;
- spin_lock_irqsave(&key->sdata->local->key_lock, flags);
+ mutex_lock(&local->key_mtx);
__ieee80211_key_free(key);
- spin_unlock_irqrestore(&key->sdata->local->key_lock, flags);
+ mutex_unlock(&local->key_mtx);
}
-/*
- * To be safe against concurrent manipulations of the list (which shouldn't
- * actually happen) we need to hold the spinlock. But under the spinlock we
- * can't actually do much, so we defer processing to the todo list. Then run
- * the todo list to be sure the operation and possibly previously pending
- * operations are completed.
- */
-static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata,
- u32 todo_flags)
+void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key;
- unsigned long flags;
-
- might_sleep();
-
- spin_lock_irqsave(&sdata->local->key_lock, flags);
- list_for_each_entry(key, &sdata->key_list, list)
- add_todo(key, todo_flags);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
- ieee80211_key_todo();
-}
-void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
-{
ASSERT_RTNL();
if (WARN_ON(!ieee80211_sdata_running(sdata)))
return;
- ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD);
-}
-
-void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
-{
- ASSERT_RTNL();
-
- ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE);
-}
-
-static void __ieee80211_key_destroy(struct ieee80211_key *key)
-{
- if (!key)
- return;
-
- ieee80211_key_disable_hw_accel(key);
+ mutex_lock(&sdata->local->key_mtx);
- if (key->conf.alg == ALG_CCMP)
- ieee80211_aes_key_free(key->u.ccmp.tfm);
- if (key->conf.alg == ALG_AES_CMAC)
- ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
- ieee80211_debugfs_key_remove(key);
+ list_for_each_entry(key, &sdata->key_list, list)
+ ieee80211_key_enable_hw_accel(key);
- kfree(key);
+ mutex_unlock(&sdata->local->key_mtx);
}
-static void __ieee80211_key_todo(void)
+void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key;
- bool work_done;
- u32 todoflags;
- /*
- * NB: sta_info_destroy relies on this!
- */
- synchronize_rcu();
-
- spin_lock_bh(&todo_lock);
- while (!list_empty(&todo_list)) {
- key = list_first_entry(&todo_list, struct ieee80211_key, todo);
- list_del_init(&key->todo);
- todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS |
- KEY_FLAG_TODO_DEFKEY |
- KEY_FLAG_TODO_DEFMGMTKEY |
- KEY_FLAG_TODO_HWACCEL_ADD |
- KEY_FLAG_TODO_HWACCEL_REMOVE |
- KEY_FLAG_TODO_DELETE);
- key->flags &= ~todoflags;
- spin_unlock_bh(&todo_lock);
-
- work_done = false;
-
- if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) {
- ieee80211_debugfs_key_add(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DEFKEY) {
- ieee80211_debugfs_key_remove_default(key->sdata);
- ieee80211_debugfs_key_add_default(key->sdata);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DEFMGMTKEY) {
- ieee80211_debugfs_key_remove_mgmt_default(key->sdata);
- ieee80211_debugfs_key_add_mgmt_default(key->sdata);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) {
- ieee80211_key_enable_hw_accel(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) {
- ieee80211_key_disable_hw_accel(key);
- work_done = true;
- }
- if (todoflags & KEY_FLAG_TODO_DELETE) {
- __ieee80211_key_destroy(key);
- work_done = true;
- }
+ ASSERT_RTNL();
- WARN_ON(!work_done);
+ mutex_lock(&sdata->local->key_mtx);
- spin_lock_bh(&todo_lock);
- }
- spin_unlock_bh(&todo_lock);
-}
+ list_for_each_entry(key, &sdata->key_list, list)
+ ieee80211_key_disable_hw_accel(key);
-void ieee80211_key_todo(void)
-{
- ieee80211_key_lock();
- __ieee80211_key_todo();
- ieee80211_key_unlock();
+ mutex_unlock(&sdata->local->key_mtx);
}
void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_key *key, *tmp;
- unsigned long flags;
- ieee80211_key_lock();
+ mutex_lock(&sdata->local->key_mtx);
ieee80211_debugfs_key_remove_default(sdata);
ieee80211_debugfs_key_remove_mgmt_default(sdata);
- spin_lock_irqsave(&sdata->local->key_lock, flags);
list_for_each_entry_safe(key, tmp, &sdata->key_list, list)
__ieee80211_key_free(key);
- spin_unlock_irqrestore(&sdata->local->key_lock, flags);
-
- __ieee80211_key_todo();
- ieee80211_key_unlock();
+ mutex_unlock(&sdata->local->key_mtx);
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index bdc2968c2bbe..9996e3be6e63 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -38,25 +38,9 @@ struct sta_info;
*
* @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present
* in the hardware for TX crypto hardware acceleration.
- * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an
- * RCU grace period, no longer be reachable other than from the
- * todo list.
- * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration.
- * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware
- * acceleration.
- * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated.
- * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs.
- * @KEY_FLAG_TODO_DEFMGMTKEY: Key is default management key and debugfs needs
- * to be updated.
*/
enum ieee80211_internal_key_flags {
KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0),
- KEY_FLAG_TODO_DELETE = BIT(1),
- KEY_FLAG_TODO_HWACCEL_ADD = BIT(2),
- KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3),
- KEY_FLAG_TODO_DEFKEY = BIT(4),
- KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5),
- KEY_FLAG_TODO_DEFMGMTKEY = BIT(6),
};
enum ieee80211_internal_tkip_state {
@@ -79,10 +63,8 @@ struct ieee80211_key {
/* for sdata list */
struct list_head list;
- /* for todo list */
- struct list_head todo;
- /* protected by todo lock! */
+ /* protected by key mutex */
unsigned int flags;
union {
@@ -155,6 +137,4 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
-void ieee80211_key_todo(void);
-
#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 22a384dfab65..5706156d1ecf 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -329,6 +329,60 @@ static void ieee80211_recalc_smps_work(struct work_struct *work)
mutex_unlock(&local->iflist_mtx);
}
+#ifdef CONFIG_INET
+int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata)
+{
+ struct in_device *idev;
+ int ret = 0;
+
+ BUG_ON(!sdata);
+ ASSERT_RTNL();
+
+ idev = sdata->dev->ip_ptr;
+ if (!idev)
+ return 0;
+
+ ret = drv_configure_arp_filter(sdata->local, &sdata->vif,
+ idev->ifa_list);
+ return ret;
+}
+
+static int ieee80211_ifa_changed(struct notifier_block *nb,
+ unsigned long data, void *arg)
+{
+ struct in_ifaddr *ifa = arg;
+ struct ieee80211_local *local =
+ container_of(nb, struct ieee80211_local,
+ ifa_notifier);
+ struct net_device *ndev = ifa->ifa_dev->dev;
+ struct wireless_dev *wdev = ndev->ieee80211_ptr;
+ struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_if_managed *ifmgd;
+
+ /* Make sure it's our interface that got changed */
+ if (!wdev)
+ return NOTIFY_DONE;
+
+ if (wdev->wiphy != local->hw.wiphy)
+ return NOTIFY_DONE;
+
+ /* We are concerned about IP addresses only when associated */
+ sdata = IEEE80211_DEV_TO_SUB_IF(ndev);
+
+ /* ARP filtering is only supported in managed mode */
+ if (sdata->vif.type != NL80211_IFTYPE_STATION)
+ return NOTIFY_DONE;
+
+ ifmgd = &sdata->u.mgd;
+ mutex_lock(&ifmgd->mtx);
+ if (ifmgd->associated)
+ ieee80211_set_arp_filter(sdata);
+ mutex_unlock(&ifmgd->mtx);
+
+ return NOTIFY_DONE;
+}
+#endif
+
struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
const struct ieee80211_ops *ops)
{
@@ -396,7 +450,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
mutex_init(&local->iflist_mtx);
mutex_init(&local->scan_mtx);
- spin_lock_init(&local->key_lock);
+ mutex_init(&local->key_mtx);
spin_lock_init(&local->filter_lock);
spin_lock_init(&local->queue_stop_reason_lock);
@@ -612,14 +666,24 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
ieee80211_max_network_latency;
result = pm_qos_add_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
-
if (result) {
rtnl_lock();
goto fail_pm_qos;
}
+#ifdef CONFIG_INET
+ local->ifa_notifier.notifier_call = ieee80211_ifa_changed;
+ result = register_inetaddr_notifier(&local->ifa_notifier);
+ if (result)
+ goto fail_ifa;
+#endif
+
return 0;
+ fail_ifa:
+ pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
+ &local->network_latency_notifier);
+ rtnl_lock();
fail_pm_qos:
ieee80211_led_exit(local);
ieee80211_remove_interfaces(local);
@@ -647,6 +711,9 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
pm_qos_remove_notifier(PM_QOS_NETWORK_LATENCY,
&local->network_latency_notifier);
+#ifdef CONFIG_INET
+ unregister_inetaddr_notifier(&local->ifa_notifier);
+#endif
rtnl_lock();
@@ -704,6 +771,10 @@ static int __init ieee80211_init(void)
if (ret)
return ret;
+ ret = rc80211_minstrel_ht_init();
+ if (ret)
+ goto err_minstrel;
+
ret = rc80211_pid_init();
if (ret)
goto err_pid;
@@ -716,6 +787,8 @@ static int __init ieee80211_init(void)
err_netdev:
rc80211_pid_exit();
err_pid:
+ rc80211_minstrel_ht_exit();
+ err_minstrel:
rc80211_minstrel_exit();
return ret;
@@ -724,6 +797,7 @@ static int __init ieee80211_init(void)
static void __exit ieee80211_exit(void)
{
rc80211_pid_exit();
+ rc80211_minstrel_ht_exit();
rc80211_minstrel_exit();
/*
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 0839c4e8fd2e..2ab4e86d9929 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1692,14 +1692,52 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
rma = ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
break;
case IEEE80211_STYPE_ACTION:
- if (mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
+ switch (mgmt->u.action.category) {
+ case WLAN_CATEGORY_BACK: {
+ struct ieee80211_local *local = sdata->local;
+ int len = skb->len;
+ struct sta_info *sta;
+
+ rcu_read_lock();
+ sta = sta_info_get(sdata, mgmt->sa);
+ if (!sta) {
+ rcu_read_unlock();
+ break;
+ }
+
+ local_bh_disable();
+
+ switch (mgmt->u.action.u.addba_req.action_code) {
+ case WLAN_ACTION_ADDBA_REQ:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.addba_req)))
+ break;
+ ieee80211_process_addba_request(local, sta, mgmt, len);
+ break;
+ case WLAN_ACTION_ADDBA_RESP:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.addba_resp)))
+ break;
+ ieee80211_process_addba_resp(local, sta, mgmt, len);
+ break;
+ case WLAN_ACTION_DELBA:
+ if (len < (IEEE80211_MIN_ACTION_SIZE +
+ sizeof(mgmt->u.action.u.delba)))
+ break;
+ ieee80211_process_delba(sdata, sta, mgmt, len);
+ break;
+ }
+ local_bh_enable();
+ rcu_read_unlock();
break;
-
- ieee80211_sta_process_chanswitch(sdata,
- &mgmt->u.action.u.chan_switch.sw_elem,
- (void *)ifmgd->associated->priv,
- rx_status->mactime);
- break;
+ }
+ case WLAN_CATEGORY_SPECTRUM_MGMT:
+ ieee80211_sta_process_chanswitch(sdata,
+ &mgmt->u.action.u.chan_switch.sw_elem,
+ (void *)ifmgd->associated->priv,
+ rx_status->mactime);
+ break;
+ }
}
mutex_unlock(&ifmgd->mtx);
@@ -1763,7 +1801,7 @@ static void ieee80211_sta_work(struct work_struct *work)
/*
* ieee80211_queue_work() should have picked up most cases,
- * here we'll pick the the rest.
+ * here we'll pick the rest.
*/
if (WARN(local->suspended, "STA MLME work scheduled while "
"going to suspend\n"))
@@ -2078,8 +2116,18 @@ static enum work_done_result ieee80211_assoc_done(struct ieee80211_work *wk,
cfg80211_send_assoc_timeout(wk->sdata->dev,
wk->filter_ta);
return WORK_DONE_DESTROY;
+ } else {
+ mutex_unlock(&wk->sdata->u.mgd.mtx);
+#ifdef CONFIG_INET
+ /*
+ * configure ARP filter IP addresses to the driver,
+ * intentionally outside the mgd mutex.
+ */
+ rtnl_lock();
+ ieee80211_set_arp_filter(wk->sdata);
+ rtnl_unlock();
+#endif
}
- mutex_unlock(&wk->sdata->u.mgd.mtx);
}
cfg80211_send_rx_assoc(wk->sdata->dev, skb->data, skb->len);
@@ -2308,6 +2356,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata,
int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie)
{
struct ieee80211_local *local = sdata->local;
@@ -2315,9 +2364,11 @@ int ieee80211_mgd_action(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb;
/* Check that we are on the requested channel for transmission */
- if ((chan != local->tmp_channel ||
- channel_type != local->tmp_channel_type) &&
- (chan != local->oper_channel ||
+ if (chan != local->tmp_channel &&
+ chan != local->oper_channel)
+ return -EBUSY;
+ if (channel_type_valid &&
+ (channel_type != local->tmp_channel_type &&
channel_type != local->_oper_channel_type))
return -EBUSY;
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index 6d0bd198af19..be04d46110fe 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -103,6 +103,7 @@ ieee80211_rate_control_ops_get(const char *name)
struct rate_control_ops *ops;
const char *alg_name;
+ kparam_block_sysfs_write(ieee80211_default_rc_algo);
if (!name)
alg_name = ieee80211_default_rc_algo;
else
@@ -120,6 +121,7 @@ ieee80211_rate_control_ops_get(const char *name)
/* try built-in one if specific alg requested but not found */
if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
+ kparam_unblock_sysfs_write(ieee80211_default_rc_algo);
return ops;
}
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h
index 065a96190e32..168427b0ffdc 100644
--- a/net/mac80211/rate.h
+++ b/net/mac80211/rate.h
@@ -147,5 +147,18 @@ static inline void rc80211_minstrel_exit(void)
}
#endif
+#ifdef CONFIG_MAC80211_RC_MINSTREL_HT
+extern int rc80211_minstrel_ht_init(void);
+extern void rc80211_minstrel_ht_exit(void);
+#else
+static inline int rc80211_minstrel_ht_init(void)
+{
+ return 0;
+}
+static inline void rc80211_minstrel_ht_exit(void)
+{
+}
+#endif
+
#endif /* IEEE80211_RATE_H */
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
new file mode 100644
index 000000000000..c23f08251da4
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/random.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rate.h"
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+#define AVG_PKT_SIZE 1200
+#define SAMPLE_COLUMNS 10
+#define EWMA_LEVEL 75
+
+/* Number of bits for an average sized packet */
+#define MCS_NBITS (AVG_PKT_SIZE << 3)
+
+/* Number of symbols for a packet with (bps) bits per symbol */
+#define MCS_NSYMS(bps) ((MCS_NBITS + (bps) - 1) / (bps))
+
+/* Transmission time for a packet containing (syms) symbols */
+#define MCS_SYMBOL_TIME(sgi, syms) \
+ (sgi ? \
+ ((syms) * 18 + 4) / 5 : /* syms * 3.6 us */ \
+ (syms) << 2 /* syms * 4 us */ \
+ )
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define MCS_DURATION(streams, sgi, bps) MCS_SYMBOL_TIME(sgi, MCS_NSYMS((streams) * (bps)))
+
+/* MCS rate information for an MCS group */
+#define MCS_GROUP(_streams, _sgi, _ht40) { \
+ .streams = _streams, \
+ .flags = \
+ (_sgi ? IEEE80211_TX_RC_SHORT_GI : 0) | \
+ (_ht40 ? IEEE80211_TX_RC_40_MHZ_WIDTH : 0), \
+ .duration = { \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 108 : 52), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 162 : 78), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 216 : 104), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 324 : 156), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 432 : 208), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 486 : 234), \
+ MCS_DURATION(_streams, _sgi, _ht40 ? 540 : 260) \
+ } \
+}
+
+/*
+ * To enable sufficiently targeted rate sampling, MCS rates are divided into
+ * groups, based on the number of streams and flags (HT40, SGI) that they
+ * use.
+ */
+const struct mcs_group minstrel_mcs_groups[] = {
+ MCS_GROUP(1, 0, 0),
+ MCS_GROUP(2, 0, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 0),
+#endif
+
+ MCS_GROUP(1, 1, 0),
+ MCS_GROUP(2, 1, 0),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 0),
+#endif
+
+ MCS_GROUP(1, 0, 1),
+ MCS_GROUP(2, 0, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 0, 1),
+#endif
+
+ MCS_GROUP(1, 1, 1),
+ MCS_GROUP(2, 1, 1),
+#if MINSTREL_MAX_STREAMS >= 3
+ MCS_GROUP(3, 1, 1),
+#endif
+};
+
+static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES];
+
+/*
+ * Perform EWMA (Exponentially Weighted Moving Average) calculation
+ */
+static int
+minstrel_ewma(int old, int new, int weight)
+{
+ return (new * (100 - weight) + old * weight) / 100;
+}
+
+/*
+ * Look up an MCS group index based on mac80211 rate information
+ */
+static int
+minstrel_ht_get_group_idx(struct ieee80211_tx_rate *rate)
+{
+ int streams = (rate->idx / MCS_GROUP_RATES) + 1;
+ u32 flags = IEEE80211_TX_RC_SHORT_GI | IEEE80211_TX_RC_40_MHZ_WIDTH;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) {
+ if (minstrel_mcs_groups[i].streams != streams)
+ continue;
+ if (minstrel_mcs_groups[i].flags != (rate->flags & flags))
+ continue;
+
+ return i;
+ }
+
+ WARN_ON(1);
+ return 0;
+}
+
+static inline struct minstrel_rate_stats *
+minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index)
+{
+ return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES];
+}
+
+
+/*
+ * Recalculate success probabilities and counters for a rate using EWMA
+ */
+static void
+minstrel_calc_rate_ewma(struct minstrel_priv *mp, struct minstrel_rate_stats *mr)
+{
+ if (unlikely(mr->attempts > 0)) {
+ mr->sample_skipped = 0;
+ mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts);
+ if (!mr->att_hist)
+ mr->probability = mr->cur_prob;
+ else
+ mr->probability = minstrel_ewma(mr->probability,
+ mr->cur_prob, EWMA_LEVEL);
+ mr->att_hist += mr->attempts;
+ mr->succ_hist += mr->success;
+ } else {
+ mr->sample_skipped++;
+ }
+ mr->last_success = mr->success;
+ mr->last_attempts = mr->attempts;
+ mr->success = 0;
+ mr->attempts = 0;
+}
+
+/*
+ * Calculate throughput based on the average A-MPDU length, taking into account
+ * the expected number of retransmissions and their expected length
+ */
+static void
+minstrel_ht_calc_tp(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int group, int rate)
+{
+ struct minstrel_rate_stats *mr;
+ unsigned int usecs;
+
+ mr = &mi->groups[group].rates[rate];
+
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->cur_tp = 0;
+ return;
+ }
+
+ usecs = mi->overhead / MINSTREL_TRUNC(mi->avg_ampdu_len);
+ usecs += minstrel_mcs_groups[group].duration[rate];
+ mr->cur_tp = MINSTREL_TRUNC((1000000 / usecs) * mr->probability);
+}
+
+/*
+ * Update rate statistics and select new primary rates
+ *
+ * Rules for rate selection:
+ * - max_prob_rate must use only one stream, as a tradeoff between delivery
+ * probability and throughput during strong fluctuations
+ * - as long as the max prob rate has a probability of more than 3/4, pick
+ * higher throughput rates, even if the probablity is a bit lower
+ */
+static void
+minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+ struct minstrel_rate_stats *mr;
+ int cur_prob, cur_prob_tp, cur_tp, cur_tp2;
+ int group, i, index;
+
+ if (mi->ampdu_packets > 0) {
+ mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len,
+ MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL);
+ mi->ampdu_len = 0;
+ mi->ampdu_packets = 0;
+ }
+
+ mi->sample_slow = 0;
+ mi->sample_count = 0;
+ mi->max_tp_rate = 0;
+ mi->max_tp_rate2 = 0;
+ mi->max_prob_rate = 0;
+
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mg->max_tp_rate = 0;
+ mg->max_tp_rate2 = 0;
+ mg->max_prob_rate = 0;
+ mi->sample_count++;
+
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ if (!(mg->supported & BIT(i)))
+ continue;
+
+ mr = &mg->rates[i];
+ mr->retry_updated = false;
+ index = MCS_GROUP_RATES * group + i;
+ minstrel_calc_rate_ewma(mp, mr);
+ minstrel_ht_calc_tp(mp, mi, group, i);
+
+ if (!mr->cur_tp)
+ continue;
+
+ /* ignore the lowest rate of each single-stream group */
+ if (!i && minstrel_mcs_groups[group].streams == 1)
+ continue;
+
+ if ((mr->cur_tp > cur_prob_tp && mr->probability >
+ MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) {
+ mg->max_prob_rate = index;
+ cur_prob = mr->probability;
+ }
+
+ if (mr->cur_tp > cur_tp) {
+ swap(index, mg->max_tp_rate);
+ cur_tp = mr->cur_tp;
+ mr = minstrel_get_ratestats(mi, index);
+ }
+
+ if (index >= mg->max_tp_rate)
+ continue;
+
+ if (mr->cur_tp > cur_tp2) {
+ mg->max_tp_rate2 = index;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+ }
+
+ /* try to sample up to half of the availble rates during each interval */
+ mi->sample_count *= 4;
+
+ cur_prob = 0;
+ cur_prob_tp = 0;
+ cur_tp = 0;
+ cur_tp2 = 0;
+ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+ mg = &mi->groups[group];
+ if (!mg->supported)
+ continue;
+
+ mr = minstrel_get_ratestats(mi, mg->max_prob_rate);
+ if (cur_prob_tp < mr->cur_tp &&
+ minstrel_mcs_groups[group].streams == 1) {
+ mi->max_prob_rate = mg->max_prob_rate;
+ cur_prob = mr->cur_prob;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate);
+ if (cur_tp < mr->cur_tp) {
+ mi->max_tp_rate = mg->max_tp_rate;
+ cur_tp = mr->cur_tp;
+ }
+
+ mr = minstrel_get_ratestats(mi, mg->max_tp_rate2);
+ if (cur_tp2 < mr->cur_tp) {
+ mi->max_tp_rate2 = mg->max_tp_rate2;
+ cur_tp2 = mr->cur_tp;
+ }
+ }
+
+ mi->stats_update = jiffies;
+}
+
+static bool
+minstrel_ht_txstat_valid(struct ieee80211_tx_rate *rate)
+{
+ if (!rate->count)
+ return false;
+
+ if (rate->idx < 0)
+ return false;
+
+ return !!(rate->flags & IEEE80211_TX_RC_MCS);
+}
+
+static void
+minstrel_next_sample_idx(struct minstrel_ht_sta *mi)
+{
+ struct minstrel_mcs_group_data *mg;
+
+ for (;;) {
+ mi->sample_group++;
+ mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups);
+ mg = &mi->groups[mi->sample_group];
+
+ if (!mg->supported)
+ continue;
+
+ if (++mg->index >= MCS_GROUP_RATES) {
+ mg->index = 0;
+ if (++mg->column >= ARRAY_SIZE(sample_table))
+ mg->column = 0;
+ }
+ break;
+ }
+}
+
+static void
+minstrel_downgrade_rate(struct minstrel_ht_sta *mi, int *idx, bool primary)
+{
+ int group, orig_group;
+
+ orig_group = group = *idx / MCS_GROUP_RATES;
+ while (group > 0) {
+ group--;
+
+ if (!mi->groups[group].supported)
+ continue;
+
+ if (minstrel_mcs_groups[group].streams >
+ minstrel_mcs_groups[orig_group].streams)
+ continue;
+
+ if (primary)
+ *idx = mi->groups[group].max_tp_rate;
+ else
+ *idx = mi->groups[group].max_tp_rate2;
+ break;
+ }
+}
+
+static void
+minstrel_aggr_check(struct minstrel_priv *mp, struct ieee80211_sta *pubsta, struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ u16 tid;
+
+ if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
+ return;
+
+ if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+ return;
+
+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
+ if (likely(sta->ampdu_mlme.tid_state_tx[tid] != HT_AGG_STATE_IDLE))
+ return;
+
+ ieee80211_start_tx_ba_session(pubsta, tid);
+}
+
+static void
+minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ struct sk_buff *skb)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_rate_stats *rate, *rate2;
+ struct minstrel_priv *mp = priv;
+ bool last = false;
+ int group;
+ int i = 0;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.tx_status(priv, sband, sta, &msp->legacy, skb);
+
+ /* This packet was aggregated but doesn't carry status info */
+ if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_STAT_AMPDU))
+ return;
+
+ if (!info->status.ampdu_len) {
+ info->status.ampdu_ack_len = 1;
+ info->status.ampdu_len = 1;
+ }
+
+ mi->ampdu_packets++;
+ mi->ampdu_len += info->status.ampdu_len;
+
+ if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) {
+ mi->sample_wait = 4 + 2 * MINSTREL_TRUNC(mi->avg_ampdu_len);
+ mi->sample_tries = 3;
+ mi->sample_count--;
+ }
+
+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
+ mi->sample_packets += info->status.ampdu_len;
+ minstrel_next_sample_idx(mi);
+ }
+
+ for (i = 0; !last; i++) {
+ last = (i == IEEE80211_TX_MAX_RATES - 1) ||
+ !minstrel_ht_txstat_valid(&ar[i + 1]);
+
+ if (!minstrel_ht_txstat_valid(&ar[i]))
+ break;
+
+ group = minstrel_ht_get_group_idx(&ar[i]);
+ rate = &mi->groups[group].rates[ar[i].idx % 8];
+
+ if (last && (info->flags & IEEE80211_TX_STAT_ACK))
+ rate->success += info->status.ampdu_ack_len;
+
+ rate->attempts += ar[i].count * info->status.ampdu_len;
+ }
+
+ /*
+ * check for sudden death of spatial multiplexing,
+ * downgrade to a lower number of streams if necessary.
+ */
+ rate = minstrel_get_ratestats(mi, mi->max_tp_rate);
+ if (rate->attempts > 30 &&
+ MINSTREL_FRAC(rate->success, rate->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate, true);
+
+ rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate2);
+ if (rate->attempts > 30 &&
+ MINSTREL_FRAC(rate->success, rate->attempts) <
+ MINSTREL_FRAC(20, 100))
+ minstrel_downgrade_rate(mi, &mi->max_tp_rate2, false);
+
+ if (time_after(jiffies, mi->stats_update + (mp->update_interval / 2 * HZ) / 1000)) {
+ minstrel_ht_update_stats(mp, mi);
+ minstrel_aggr_check(mp, sta, skb);
+ }
+}
+
+static void
+minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ int index)
+{
+ struct minstrel_rate_stats *mr;
+ const struct mcs_group *group;
+ unsigned int tx_time, tx_time_rtscts, tx_time_data;
+ unsigned int cw = mp->cw_min;
+ unsigned int t_slot = 9; /* FIXME */
+ unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (mr->probability < MINSTREL_FRAC(1, 10)) {
+ mr->retry_count = 1;
+ mr->retry_count_rtscts = 1;
+ return;
+ }
+
+ mr->retry_count = 2;
+ mr->retry_count_rtscts = 2;
+ mr->retry_updated = true;
+
+ group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
+ tx_time = 2 * (t_slot + mi->overhead + tx_time_data);
+ tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data);
+ do {
+ cw = (cw << 1) | 1;
+ cw = min(cw, mp->cw_max);
+ tx_time += cw + t_slot + mi->overhead;
+ tx_time_rtscts += cw + t_slot + mi->overhead_rtscts;
+ if (tx_time_rtscts < mp->segment_size)
+ mr->retry_count_rtscts++;
+ } while ((tx_time < mp->segment_size) &&
+ (++mr->retry_count < mp->max_retry));
+}
+
+
+static void
+minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi,
+ struct ieee80211_tx_rate *rate, int index,
+ struct ieee80211_tx_rate_control *txrc,
+ bool sample, bool rtscts)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ struct minstrel_rate_stats *mr;
+
+ mr = minstrel_get_ratestats(mi, index);
+ if (!mr->retry_updated)
+ minstrel_calc_retransmit(mp, mi, index);
+
+ if (mr->probability < MINSTREL_FRAC(20, 100))
+ rate->count = 2;
+ else if (rtscts)
+ rate->count = mr->retry_count_rtscts;
+ else
+ rate->count = mr->retry_count;
+
+ rate->flags = IEEE80211_TX_RC_MCS | group->flags;
+ if (txrc->short_preamble)
+ rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
+ if (txrc->rts || rtscts)
+ rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
+ rate->idx = index % MCS_GROUP_RATES + (group->streams - 1) * MCS_GROUP_RATES;
+}
+
+static inline int
+minstrel_get_duration(int index)
+{
+ const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
+ return group->duration[index % MCS_GROUP_RATES];
+}
+
+static int
+minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
+{
+ struct minstrel_rate_stats *mr;
+ struct minstrel_mcs_group_data *mg;
+ int sample_idx = 0;
+
+ if (mi->sample_wait > 0) {
+ mi->sample_wait--;
+ return -1;
+ }
+
+ if (!mi->sample_tries)
+ return -1;
+
+ mi->sample_tries--;
+ mg = &mi->groups[mi->sample_group];
+ sample_idx = sample_table[mg->column][mg->index];
+ mr = &mg->rates[sample_idx];
+ sample_idx += mi->sample_group * MCS_GROUP_RATES;
+
+ /*
+ * When not using MRR, do not sample if the probability is already
+ * higher than 95% to avoid wasting airtime
+ */
+ if (!mp->has_mrr && (mr->probability > MINSTREL_FRAC(95, 100)))
+ goto next;
+
+ /*
+ * Make sure that lower rates get sampled only occasionally,
+ * if the link is working perfectly.
+ */
+ if (minstrel_get_duration(sample_idx) >
+ minstrel_get_duration(mi->max_tp_rate)) {
+ if (mr->sample_skipped < 10)
+ goto next;
+
+ if (mi->sample_slow++ > 2)
+ goto next;
+ }
+
+ return sample_idx;
+
+next:
+ minstrel_next_sample_idx(mi);
+ return -1;
+}
+
+static void
+minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
+ struct ieee80211_tx_rate_control *txrc)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb);
+ struct ieee80211_tx_rate *ar = info->status.rates;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_priv *mp = priv;
+ int sample_idx;
+
+ if (rate_control_send_low(sta, priv_sta, txrc))
+ return;
+
+ if (!msp->is_ht)
+ return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc);
+
+ info->flags |= mi->tx_flags;
+ sample_idx = minstrel_get_sample_rate(mp, mi);
+ if (sample_idx >= 0) {
+ minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
+ txrc, true, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate,
+ txrc, false, true);
+ info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
+ } else {
+ minstrel_ht_set_rate(mp, mi, &ar[0], mi->max_tp_rate,
+ txrc, false, false);
+ minstrel_ht_set_rate(mp, mi, &ar[1], mi->max_tp_rate2,
+ txrc, false, true);
+ }
+ minstrel_ht_set_rate(mp, mi, &ar[2], mi->max_prob_rate, txrc, false, true);
+
+ ar[3].count = 0;
+ ar[3].idx = -1;
+
+ mi->total_packets++;
+
+ /* wraparound */
+ if (mi->total_packets == ~0) {
+ mi->total_packets = 0;
+ mi->sample_packets = 0;
+ }
+}
+
+static void
+minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ enum nl80211_channel_type oper_chan_type)
+{
+ struct minstrel_priv *mp = priv;
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs;
+ struct ieee80211_local *local = hw_to_local(mp->hw);
+ u16 sta_cap = sta->ht_cap.cap;
+ int ack_dur;
+ int stbc;
+ int i;
+
+ /* fall back to the old minstrel for legacy stations */
+ if (sta && !sta->ht_cap.ht_supported) {
+ msp->is_ht = false;
+ memset(&msp->legacy, 0, sizeof(msp->legacy));
+ msp->legacy.r = msp->ratelist;
+ msp->legacy.sample_table = msp->sample_table;
+ return mac80211_minstrel.rate_init(priv, sband, sta, &msp->legacy);
+ }
+
+ BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) !=
+ MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS);
+
+ msp->is_ht = true;
+ memset(mi, 0, sizeof(*mi));
+ mi->stats_update = jiffies;
+
+ ack_dur = ieee80211_frame_duration(local, 10, 60, 1, 1);
+ mi->overhead = ieee80211_frame_duration(local, 0, 60, 1, 1) + ack_dur;
+ mi->overhead_rtscts = mi->overhead + 2 * ack_dur;
+
+ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1);
+
+ /* When using MRR, sample more on the first attempt, without delay */
+ if (mp->has_mrr) {
+ mi->sample_count = 16;
+ mi->sample_wait = 0;
+ } else {
+ mi->sample_count = 8;
+ mi->sample_wait = 8;
+ }
+ mi->sample_tries = 4;
+
+ stbc = (sta_cap & IEEE80211_HT_CAP_RX_STBC) >>
+ IEEE80211_HT_CAP_RX_STBC_SHIFT;
+ mi->tx_flags |= stbc << IEEE80211_TX_CTL_STBC_SHIFT;
+
+ if (sta_cap & IEEE80211_HT_CAP_LDPC_CODING)
+ mi->tx_flags |= IEEE80211_TX_CTL_LDPC;
+
+ if (oper_chan_type != NL80211_CHAN_HT40MINUS &&
+ oper_chan_type != NL80211_CHAN_HT40PLUS)
+ sta_cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ for (i = 0; i < ARRAY_SIZE(mi->groups); i++) {
+ u16 req = 0;
+
+ mi->groups[i].supported = 0;
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI) {
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SGI_40;
+ else
+ req |= IEEE80211_HT_CAP_SGI_20;
+ }
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ req |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+
+ if ((sta_cap & req) != req)
+ continue;
+
+ mi->groups[i].supported =
+ mcs->rx_mask[minstrel_mcs_groups[i].streams - 1];
+ }
+}
+
+static void
+minstrel_ht_rate_init(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_priv *mp = priv;
+
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, mp->hw->conf.channel_type);
+}
+
+static void
+minstrel_ht_rate_update(void *priv, struct ieee80211_supported_band *sband,
+ struct ieee80211_sta *sta, void *priv_sta,
+ u32 changed, enum nl80211_channel_type oper_chan_type)
+{
+ minstrel_ht_update_caps(priv, sband, sta, priv_sta, oper_chan_type);
+}
+
+static void *
+minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp)
+{
+ struct ieee80211_supported_band *sband;
+ struct minstrel_ht_sta_priv *msp;
+ struct minstrel_priv *mp = priv;
+ struct ieee80211_hw *hw = mp->hw;
+ int max_rates = 0;
+ int i;
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ sband = hw->wiphy->bands[i];
+ if (sband && sband->n_bitrates > max_rates)
+ max_rates = sband->n_bitrates;
+ }
+
+ msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp);
+ if (!msp)
+ return NULL;
+
+ msp->ratelist = kzalloc(sizeof(struct minstrel_rate) * max_rates, gfp);
+ if (!msp->ratelist)
+ goto error;
+
+ msp->sample_table = kmalloc(SAMPLE_COLUMNS * max_rates, gfp);
+ if (!msp->sample_table)
+ goto error1;
+
+ return msp;
+
+error1:
+ kfree(msp->sample_table);
+error:
+ kfree(msp);
+ return NULL;
+}
+
+static void
+minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ kfree(msp->sample_table);
+ kfree(msp->ratelist);
+ kfree(msp);
+}
+
+static void *
+minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
+{
+ return mac80211_minstrel.alloc(hw, debugfsdir);
+}
+
+static void
+minstrel_ht_free(void *priv)
+{
+ mac80211_minstrel.free(priv);
+}
+
+static struct rate_control_ops mac80211_minstrel_ht = {
+ .name = "minstrel_ht",
+ .tx_status = minstrel_ht_tx_status,
+ .get_rate = minstrel_ht_get_rate,
+ .rate_init = minstrel_ht_rate_init,
+ .rate_update = minstrel_ht_rate_update,
+ .alloc_sta = minstrel_ht_alloc_sta,
+ .free_sta = minstrel_ht_free_sta,
+ .alloc = minstrel_ht_alloc,
+ .free = minstrel_ht_free,
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .add_sta_debugfs = minstrel_ht_add_sta_debugfs,
+ .remove_sta_debugfs = minstrel_ht_remove_sta_debugfs,
+#endif
+};
+
+
+static void
+init_sample_table(void)
+{
+ int col, i, new_idx;
+ u8 rnd[MCS_GROUP_RATES];
+
+ memset(sample_table, 0xff, sizeof(sample_table));
+ for (col = 0; col < SAMPLE_COLUMNS; col++) {
+ for (i = 0; i < MCS_GROUP_RATES; i++) {
+ get_random_bytes(rnd, sizeof(rnd));
+ new_idx = (i + rnd[i]) % MCS_GROUP_RATES;
+
+ while (sample_table[col][new_idx] != 0xff)
+ new_idx = (new_idx + 1) % MCS_GROUP_RATES;
+
+ sample_table[col][new_idx] = i;
+ }
+ }
+}
+
+int __init
+rc80211_minstrel_ht_init(void)
+{
+ init_sample_table();
+ return ieee80211_rate_control_register(&mac80211_minstrel_ht);
+}
+
+void
+rc80211_minstrel_ht_exit(void)
+{
+ ieee80211_rate_control_unregister(&mac80211_minstrel_ht);
+}
diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h
new file mode 100644
index 000000000000..696c0fc6e0b7
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RC_MINSTREL_HT_H
+#define __RC_MINSTREL_HT_H
+
+/*
+ * The number of streams can be changed to 2 to reduce code
+ * size and memory footprint.
+ */
+#define MINSTREL_MAX_STREAMS 3
+#define MINSTREL_STREAM_GROUPS 4
+
+/* scaled fraction values */
+#define MINSTREL_SCALE 16
+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
+#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+#define MCS_GROUP_RATES 8
+
+struct mcs_group {
+ u32 flags;
+ unsigned int streams;
+ unsigned int duration[MCS_GROUP_RATES];
+};
+
+struct minstrel_rate_stats {
+ /* current / last sampling period attempts/success counters */
+ unsigned int attempts, last_attempts;
+ unsigned int success, last_success;
+
+ /* total attempts/success counters */
+ u64 att_hist, succ_hist;
+
+ /* current throughput */
+ unsigned int cur_tp;
+
+ /* packet delivery probabilities */
+ unsigned int cur_prob, probability;
+
+ /* maximum retry counts */
+ unsigned int retry_count;
+ unsigned int retry_count_rtscts;
+
+ bool retry_updated;
+ u8 sample_skipped;
+};
+
+struct minstrel_mcs_group_data {
+ u8 index;
+ u8 column;
+
+ /* bitfield of supported MCS rates of this group */
+ u8 supported;
+
+ /* selected primary rates */
+ unsigned int max_tp_rate;
+ unsigned int max_tp_rate2;
+ unsigned int max_prob_rate;
+
+ /* MCS rate statistics */
+ struct minstrel_rate_stats rates[MCS_GROUP_RATES];
+};
+
+struct minstrel_ht_sta {
+ /* ampdu length (average, per sampling interval) */
+ unsigned int ampdu_len;
+ unsigned int ampdu_packets;
+
+ /* ampdu length (EWMA) */
+ unsigned int avg_ampdu_len;
+
+ /* best throughput rate */
+ unsigned int max_tp_rate;
+
+ /* second best throughput rate */
+ unsigned int max_tp_rate2;
+
+ /* best probability rate */
+ unsigned int max_prob_rate;
+
+ /* time of last status update */
+ unsigned long stats_update;
+
+ /* overhead time in usec for each frame */
+ unsigned int overhead;
+ unsigned int overhead_rtscts;
+
+ unsigned int total_packets;
+ unsigned int sample_packets;
+
+ /* tx flags to add for frames for this sta */
+ u32 tx_flags;
+
+ u8 sample_wait;
+ u8 sample_tries;
+ u8 sample_count;
+ u8 sample_slow;
+
+ /* current MCS group to be sampled */
+ u8 sample_group;
+
+ /* MCS rate group info and statistics */
+ struct minstrel_mcs_group_data groups[MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS];
+};
+
+struct minstrel_ht_sta_priv {
+ union {
+ struct minstrel_ht_sta ht;
+ struct minstrel_sta_info legacy;
+ };
+#ifdef CONFIG_MAC80211_DEBUGFS
+ struct dentry *dbg_stats;
+#endif
+ void *ratelist;
+ void *sample_table;
+ bool is_ht;
+};
+
+void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
+void minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta);
+
+#endif
diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c
new file mode 100644
index 000000000000..4fb3ccbd8b40
--- /dev/null
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/netdevice.h>
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/debugfs.h>
+#include <linux/ieee80211.h>
+#include <net/mac80211.h>
+#include "rc80211_minstrel.h"
+#include "rc80211_minstrel_ht.h"
+
+extern const struct mcs_group minstrel_mcs_groups[];
+
+static int
+minstrel_ht_stats_open(struct inode *inode, struct file *file)
+{
+ struct minstrel_ht_sta_priv *msp = inode->i_private;
+ struct minstrel_ht_sta *mi = &msp->ht;
+ struct minstrel_debugfs_info *ms;
+ unsigned int i, j, tp, prob, eprob;
+ char *p;
+ int ret;
+
+ if (!msp->is_ht) {
+ inode->i_private = &msp->legacy;
+ ret = minstrel_stats_open(inode, file);
+ inode->i_private = msp;
+ return ret;
+ }
+
+ ms = kmalloc(sizeof(*ms) + 8192, GFP_KERNEL);
+ if (!ms)
+ return -ENOMEM;
+
+ file->private_data = ms;
+ p = ms->buf;
+ p += sprintf(p, "type rate throughput ewma prob this prob "
+ "this succ/attempt success attempts\n");
+ for (i = 0; i < MINSTREL_MAX_STREAMS * MINSTREL_STREAM_GROUPS; i++) {
+ char htmode = '2';
+ char gimode = 'L';
+
+ if (!mi->groups[i].supported)
+ continue;
+
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ htmode = '4';
+ if (minstrel_mcs_groups[i].flags & IEEE80211_TX_RC_SHORT_GI)
+ gimode = 'S';
+
+ for (j = 0; j < MCS_GROUP_RATES; j++) {
+ struct minstrel_rate_stats *mr = &mi->groups[i].rates[j];
+ int idx = i * MCS_GROUP_RATES + j;
+
+ if (!(mi->groups[i].supported & BIT(j)))
+ continue;
+
+ p += sprintf(p, "HT%c0/%cGI ", htmode, gimode);
+
+ *(p++) = (idx == mi->max_tp_rate) ? 'T' : ' ';
+ *(p++) = (idx == mi->max_tp_rate2) ? 't' : ' ';
+ *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' ';
+ p += sprintf(p, "MCS%-2u", (minstrel_mcs_groups[i].streams - 1) *
+ MCS_GROUP_RATES + j);
+
+ tp = mr->cur_tp / 10;
+ prob = MINSTREL_TRUNC(mr->cur_prob * 1000);
+ eprob = MINSTREL_TRUNC(mr->probability * 1000);
+
+ p += sprintf(p, " %6u.%1u %6u.%1u %6u.%1u "
+ "%3u(%3u) %8llu %8llu\n",
+ tp / 10, tp % 10,
+ eprob / 10, eprob % 10,
+ prob / 10, prob % 10,
+ mr->last_success,
+ mr->last_attempts,
+ (unsigned long long)mr->succ_hist,
+ (unsigned long long)mr->att_hist);
+ }
+ }
+ p += sprintf(p, "\nTotal packet count:: ideal %d "
+ "lookaround %d\n",
+ max(0, (int) mi->total_packets - (int) mi->sample_packets),
+ mi->sample_packets);
+ p += sprintf(p, "Average A-MPDU length: %d.%d\n",
+ MINSTREL_TRUNC(mi->avg_ampdu_len),
+ MINSTREL_TRUNC(mi->avg_ampdu_len * 10) % 10);
+ ms->len = p - ms->buf;
+
+ return 0;
+}
+
+static const struct file_operations minstrel_ht_stat_fops = {
+ .owner = THIS_MODULE,
+ .open = minstrel_ht_stats_open,
+ .read = minstrel_stats_read,
+ .release = minstrel_stats_release,
+};
+
+void
+minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ msp->dbg_stats = debugfs_create_file("rc_stats", S_IRUGO, dir, msp,
+ &minstrel_ht_stat_fops);
+}
+
+void
+minstrel_ht_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+ struct minstrel_ht_sta_priv *msp = priv_sta;
+
+ debugfs_remove(msp->dbg_stats);
+}
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 6e2a7bcd8cb8..6a15632e7eca 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -825,6 +825,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
ieee80211_rx_result result = RX_DROP_UNUSABLE;
struct ieee80211_key *stakey = NULL;
int mmie_keyidx = -1;
+ __le16 fc;
/*
* Key selection 101
@@ -866,13 +867,15 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (rx->sta)
stakey = rcu_dereference(rx->sta->key);
- if (!ieee80211_has_protected(hdr->frame_control))
+ fc = hdr->frame_control;
+
+ if (!ieee80211_has_protected(fc))
mmie_keyidx = ieee80211_get_mmie_keyidx(rx->skb);
if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
rx->key = stakey;
/* Skip decryption if the frame is not protected. */
- if (!ieee80211_has_protected(hdr->frame_control))
+ if (!ieee80211_has_protected(fc))
return RX_CONTINUE;
} else if (mmie_keyidx >= 0) {
/* Broadcast/multicast robust management frame / BIP */
@@ -884,7 +887,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
return RX_DROP_MONITOR; /* unexpected BIP keyidx */
rx->key = rcu_dereference(rx->sdata->keys[mmie_keyidx]);
- } else if (!ieee80211_has_protected(hdr->frame_control)) {
+ } else if (!ieee80211_has_protected(fc)) {
/*
* The frame was not protected, so skip decryption. However, we
* need to set rx->key if there is a key that could have been
@@ -892,7 +895,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
* have been expected.
*/
struct ieee80211_key *key = NULL;
- if (ieee80211_is_mgmt(hdr->frame_control) &&
+ if (ieee80211_is_mgmt(fc) &&
is_multicast_ether_addr(hdr->addr1) &&
(key = rcu_dereference(rx->sdata->default_mgmt_key)))
rx->key = key;
@@ -914,7 +917,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
(status->flag & RX_FLAG_IV_STRIPPED))
return RX_CONTINUE;
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
+ hdrlen = ieee80211_hdrlen(fc);
if (rx->skb->len < 8 + hdrlen)
return RX_DROP_UNUSABLE; /* TODO: count this? */
@@ -947,19 +950,17 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx)
if (skb_linearize(rx->skb))
return RX_DROP_UNUSABLE;
-
- hdr = (struct ieee80211_hdr *)rx->skb->data;
-
- /* Check for weak IVs if possible */
- if (rx->sta && rx->key->conf.alg == ALG_WEP &&
- ieee80211_is_data(hdr->frame_control) &&
- (!(status->flag & RX_FLAG_IV_STRIPPED) ||
- !(status->flag & RX_FLAG_DECRYPTED)) &&
- ieee80211_wep_is_weak_iv(rx->skb, rx->key))
- rx->sta->wep_weak_iv_count++;
+ /* the hdr variable is invalid now! */
switch (rx->key->conf.alg) {
case ALG_WEP:
+ /* Check for weak IVs if possible */
+ if (rx->sta && ieee80211_is_data(fc) &&
+ (!(status->flag & RX_FLAG_IV_STRIPPED) ||
+ !(status->flag & RX_FLAG_DECRYPTED)) &&
+ ieee80211_wep_is_weak_iv(rx->skb, rx->key))
+ rx->sta->wep_weak_iv_count++;
+
result = ieee80211_crypto_wep_decrypt(rx);
break;
case ALG_TKIP:
@@ -1818,17 +1819,26 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
return RX_CONTINUE;
if (ieee80211_is_back_req(bar->frame_control)) {
+ struct {
+ __le16 control, start_seq_num;
+ } __packed bar_data;
+
if (!rx->sta)
return RX_DROP_MONITOR;
+
+ if (skb_copy_bits(skb, offsetof(struct ieee80211_bar, control),
+ &bar_data, sizeof(bar_data)))
+ return RX_DROP_MONITOR;
+
spin_lock(&rx->sta->lock);
- tid = le16_to_cpu(bar->control) >> 12;
+ tid = le16_to_cpu(bar_data.control) >> 12;
if (!rx->sta->ampdu_mlme.tid_active_rx[tid]) {
spin_unlock(&rx->sta->lock);
return RX_DROP_MONITOR;
}
tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid];
- start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4;
+ start_seq_num = le16_to_cpu(bar_data.start_seq_num) >> 4;
/* reset session timer */
if (tid_agg_rx->timeout)
@@ -1843,7 +1853,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
return RX_QUEUED;
}
- return RX_CONTINUE;
+ /*
+ * After this point, we only want management frames,
+ * so we can drop all remaining control frames to
+ * cooked monitor interfaces.
+ */
+ return RX_DROP_MONITOR;
}
static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
@@ -1935,6 +1950,9 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
if (len < IEEE80211_MIN_ACTION_SIZE + 1)
break;
+ if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ return ieee80211_sta_rx_mgmt(sdata, rx->skb);
+
switch (mgmt->u.action.u.addba_req.action_code) {
case WLAN_ACTION_ADDBA_REQ:
if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -2139,7 +2157,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
u8 rate_or_pad;
__le16 chan_freq;
__le16 chan_flags;
- } __attribute__ ((packed)) *rthdr;
+ } __packed *rthdr;
struct sk_buff *skb = rx->skb, *skb2;
struct net_device *prev_dev = NULL;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index ba9360a475b0..4607da9a6ff7 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -648,14 +648,6 @@ static int __must_check __sta_info_destroy(struct sta_info *sta)
if (sta->key) {
ieee80211_key_free(sta->key);
- /*
- * We have only unlinked the key, and actually destroying it
- * may mean it is removed from hardware which requires that
- * the key->sta pointer is still valid, so flush the key todo
- * list here.
- */
- ieee80211_key_todo();
-
WARN_ON(sta->key);
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index df9d45544ca5..813da34db733 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -120,6 +120,28 @@ struct tid_ampdu_rx {
};
/**
+ * struct sta_ampdu_mlme - STA aggregation information.
+ *
+ * @tid_active_rx: TID's state in Rx session state machine.
+ * @tid_rx: aggregation info for Rx per TID
+ * @tid_state_tx: TID's state in Tx session state machine.
+ * @tid_tx: aggregation info for Tx per TID
+ * @addba_req_num: number of times addBA request has been sent.
+ * @dialog_token_allocator: dialog token enumerator for each new session;
+ */
+struct sta_ampdu_mlme {
+ /* rx */
+ bool tid_active_rx[STA_TID_NUM];
+ struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+ /* tx */
+ u8 tid_state_tx[STA_TID_NUM];
+ struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+ u8 addba_req_num[STA_TID_NUM];
+ u8 dialog_token_allocator;
+};
+
+
+/**
* enum plink_state - state of a mesh peer link finite state machine
*
* @PLINK_LISTEN: initial state, considered the implicit state of non existant
@@ -143,28 +165,6 @@ enum plink_state {
};
/**
- * struct sta_ampdu_mlme - STA aggregation information.
- *
- * @tid_active_rx: TID's state in Rx session state machine.
- * @tid_rx: aggregation info for Rx per TID
- * @tid_state_tx: TID's state in Tx session state machine.
- * @tid_tx: aggregation info for Tx per TID
- * @addba_req_num: number of times addBA request has been sent.
- * @dialog_token_allocator: dialog token enumerator for each new session;
- */
-struct sta_ampdu_mlme {
- /* rx */
- bool tid_active_rx[STA_TID_NUM];
- struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
- /* tx */
- u8 tid_state_tx[STA_TID_NUM];
- struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
- u8 addba_req_num[STA_TID_NUM];
- u8 dialog_token_allocator;
-};
-
-
-/**
* struct sta_info - STA information
*
* This structure collects information about a station that
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 94613af009f3..34da67995d94 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -47,7 +47,7 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local,
/*
* This skb 'survived' a round-trip through the driver, and
* hopefully the driver didn't mangle it too badly. However,
- * we can definitely not rely on the the control information
+ * we can definitely not rely on the control information
* being correct. Clear it so we don't get junk there, and
* indicate that it needs new processing, but must not be
* modified/encrypted again.
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index be3d4a698692..4157717ed786 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -840,7 +840,7 @@ static void ieee80211_work_work(struct work_struct *work)
/*
* ieee80211_queue_work() should have picked up most cases,
- * here we'll pick the the rest.
+ * here we'll pick the rest.
*/
if (WARN(local->suspended, "work scheduled while going to suspend\n"))
return;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index eeeb8bc73982..77288980fae0 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -619,9 +619,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL;
/* Don't set timer yet: wait for confirmation */
setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct);
-#ifdef CONFIG_NET_NS
- ct->ct_net = net;
-#endif
+ write_pnet(&ct->ct_net, net);
#ifdef CONFIG_NF_CONNTRACK_ZONES
if (zone) {
struct nf_conntrack_zone *nf_ct_zone;
@@ -1363,9 +1361,7 @@ static int nf_conntrack_init_init_net(void)
goto err_extend;
#endif
/* Set up fake conntrack: to never be deleted, not in any hashes */
-#ifdef CONFIG_NET_NS
- nf_conntrack_untracked.ct_net = &init_net;
-#endif
+ write_pnet(&nf_conntrack_untracked.ct_net, &init_net);
atomic_set(&nf_conntrack_untracked.ct_general.use, 1);
/* - and look it like as a confirmed connection */
set_bit(IPS_CONFIRMED_BIT, &nf_conntrack_untracked.status);
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 445de702b8b7..e34622fa0003 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -699,10 +699,8 @@ void xt_free_table_info(struct xt_table_info *info)
vfree(info->jumpstack);
else
kfree(info->jumpstack);
- if (sizeof(unsigned int) * nr_cpu_ids > PAGE_SIZE)
- vfree(info->stackptr);
- else
- kfree(info->stackptr);
+
+ free_percpu(info->stackptr);
kfree(info);
}
@@ -753,14 +751,9 @@ static int xt_jumpstack_alloc(struct xt_table_info *i)
unsigned int size;
int cpu;
- size = sizeof(unsigned int) * nr_cpu_ids;
- if (size > PAGE_SIZE)
- i->stackptr = vmalloc(size);
- else
- i->stackptr = kmalloc(size, GFP_KERNEL);
+ i->stackptr = alloc_percpu(unsigned int);
if (i->stackptr == NULL)
return -ENOMEM;
- memset(i->stackptr, 0, size);
size = sizeof(void **) * nr_cpu_ids;
if (size > PAGE_SIZE)
@@ -844,10 +837,6 @@ struct xt_table *xt_register_table(struct net *net,
struct xt_table_info *private;
struct xt_table *t, *table;
- ret = xt_jumpstack_alloc(newinfo);
- if (ret < 0)
- return ERR_PTR(ret);
-
/* Don't add one object to multiple lists. */
table = kmemdup(input_table, sizeof(struct xt_table), GFP_KERNEL);
if (!table) {
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 2078a277e06b..9a17f28b1253 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -83,6 +83,7 @@
#include <linux/if_vlan.h>
#include <linux/virtio_net.h>
#include <linux/errqueue.h>
+#include <linux/net_tstamp.h>
#ifdef CONFIG_INET
#include <net/inet_common.h>
@@ -202,6 +203,7 @@ struct packet_sock {
unsigned int tp_hdrlen;
unsigned int tp_reserve;
unsigned int tp_loss:1;
+ unsigned int tp_tstamp;
struct packet_type prot_hook ____cacheline_aligned_in_smp;
};
@@ -656,6 +658,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
struct sk_buff *copy_skb = NULL;
struct timeval tv;
struct timespec ts;
+ struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
if (skb->pkt_type == PACKET_LOOPBACK)
goto drop;
@@ -737,7 +740,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h1->tp_snaplen = snaplen;
h.h1->tp_mac = macoff;
h.h1->tp_net = netoff;
- if (skb->tstamp.tv64)
+ if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+ && shhwtstamps->syststamp.tv64)
+ tv = ktime_to_timeval(shhwtstamps->syststamp);
+ else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+ && shhwtstamps->hwtstamp.tv64)
+ tv = ktime_to_timeval(shhwtstamps->hwtstamp);
+ else if (skb->tstamp.tv64)
tv = ktime_to_timeval(skb->tstamp);
else
do_gettimeofday(&tv);
@@ -750,7 +759,13 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
h.h2->tp_snaplen = snaplen;
h.h2->tp_mac = macoff;
h.h2->tp_net = netoff;
- if (skb->tstamp.tv64)
+ if ((po->tp_tstamp & SOF_TIMESTAMPING_SYS_HARDWARE)
+ && shhwtstamps->syststamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->syststamp);
+ else if ((po->tp_tstamp & SOF_TIMESTAMPING_RAW_HARDWARE)
+ && shhwtstamps->hwtstamp.tv64)
+ ts = ktime_to_timespec(shhwtstamps->hwtstamp);
+ else if (skb->tstamp.tv64)
ts = ktime_to_timespec(skb->tstamp);
else
getnstimeofday(&ts);
@@ -2027,6 +2042,18 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
po->has_vnet_hdr = !!val;
return 0;
}
+ case PACKET_TIMESTAMP:
+ {
+ int val;
+
+ if (optlen != sizeof(val))
+ return -EINVAL;
+ if (copy_from_user(&val, optval, sizeof(val)))
+ return -EFAULT;
+
+ po->tp_tstamp = val;
+ return 0;
+ }
default:
return -ENOPROTOOPT;
}
@@ -2119,6 +2146,12 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
val = po->tp_loss;
data = &val;
break;
+ case PACKET_TIMESTAMP:
+ if (len > sizeof(int))
+ len = sizeof(int);
+ val = po->tp_tstamp;
+ data = &val;
+ break;
default:
return -ENOPROTOOPT;
}
diff --git a/net/phonet/pep.c b/net/phonet/pep.c
index 7b048a35ca58..94d72e85a475 100644
--- a/net/phonet/pep.c
+++ b/net/phonet/pep.c
@@ -1045,12 +1045,12 @@ static void pep_sock_unhash(struct sock *sk)
lock_sock(sk);
if ((1 << sk->sk_state) & ~(TCPF_CLOSE|TCPF_LISTEN)) {
skparent = pn->listener;
- sk_del_node_init(sk);
release_sock(sk);
- sk = skparent;
pn = pep_sk(skparent);
- lock_sock(sk);
+ lock_sock(skparent);
+ sk_del_node_init(sk);
+ sk = skparent;
}
/* Unhash a listening sock only when it is closed
* and all of its active connected pipes are closed. */
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
index 10ed0d55f759..f68832798db2 100644
--- a/net/rds/ib_cm.c
+++ b/net/rds/ib_cm.c
@@ -475,6 +475,7 @@ int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
err = rds_ib_setup_qp(conn);
if (err) {
rds_ib_conn_error(conn, "rds_ib_setup_qp failed (%d)\n", err);
+ mutex_unlock(&conn->c_cm_lock);
goto out;
}
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
index a9d951b4fbae..b5dd6ac39be8 100644
--- a/net/rds/iw_cm.c
+++ b/net/rds/iw_cm.c
@@ -452,6 +452,7 @@ int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
err = rds_iw_setup_qp(conn);
if (err) {
rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", err);
+ mutex_unlock(&conn->c_cm_lock);
goto out;
}
diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c
index d885ba311564..570949417f38 100644
--- a/net/sched/act_nat.c
+++ b/net/sched/act_nat.c
@@ -159,6 +159,9 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
iph->daddr = new_addr;
csum_replace4(&iph->check, addr, new_addr);
+ } else if ((iph->frag_off & htons(IP_OFFSET)) ||
+ iph->protocol != IPPROTO_ICMP) {
+ goto out;
}
ihl = iph->ihl * 4;
@@ -247,6 +250,7 @@ static int tcf_nat(struct sk_buff *skb, struct tc_action *a,
break;
}
+out:
return action;
drop:
diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c
index fdbd0b7bd840..50e3d945e1f4 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -125,7 +125,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
{
struct tcf_pedit *p = a->priv;
int i, munged = 0;
- u8 *pptr;
+ unsigned int off;
if (!(skb->tc_verd & TC_OK2MUNGE)) {
/* should we set skb->cloned? */
@@ -134,7 +134,7 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
}
}
- pptr = skb_network_header(skb);
+ off = skb_network_offset(skb);
spin_lock(&p->tcf_lock);
@@ -144,17 +144,17 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
struct tc_pedit_key *tkey = p->tcfp_keys;
for (i = p->tcfp_nkeys; i > 0; i--, tkey++) {
- u32 *ptr;
+ u32 *ptr, _data;
int offset = tkey->off;
if (tkey->offmask) {
- if (skb->len > tkey->at) {
- char *j = pptr + tkey->at;
- offset += ((*j & tkey->offmask) >>
- tkey->shift);
- } else {
+ char *d, _d;
+
+ d = skb_header_pointer(skb, off + tkey->at, 1,
+ &_d);
+ if (!d)
goto bad;
- }
+ offset += (*d & tkey->offmask) >> tkey->shift;
}
if (offset % 4) {
@@ -169,9 +169,13 @@ static int tcf_pedit(struct sk_buff *skb, struct tc_action *a,
goto bad;
}
- ptr = (u32 *)(pptr+offset);
+ ptr = skb_header_pointer(skb, off + offset, 4, &_data);
+ if (!ptr)
+ goto bad;
/* just do it, baby */
*ptr = ((*ptr & tkey->mask) ^ tkey->val);
+ if (ptr == &_data)
+ skb_store_bits(skb, off + offset, ptr, 4);
munged++;
}
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index 96275422c619..4f522143811e 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -98,11 +98,11 @@ static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_re
{
struct {
struct tc_u_knode *knode;
- u8 *ptr;
+ unsigned int off;
} stack[TC_U32_MAXDEPTH];
struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;
- u8 *ptr = skb_network_header(skb);
+ unsigned int off = skb_network_offset(skb);
struct tc_u_knode *n;
int sdepth = 0;
int off2 = 0;
@@ -134,8 +134,14 @@ next_knode:
#endif
for (i = n->sel.nkeys; i>0; i--, key++) {
-
- if ((*(__be32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) {
+ unsigned int toff;
+ __be32 *data, _data;
+
+ toff = off + key->off + (off2 & key->offmask);
+ data = skb_header_pointer(skb, toff, 4, &_data);
+ if (!data)
+ goto out;
+ if ((*data ^ key->val) & key->mask) {
n = n->next;
goto next_knode;
}
@@ -174,29 +180,45 @@ check_terminal:
if (sdepth >= TC_U32_MAXDEPTH)
goto deadloop;
stack[sdepth].knode = n;
- stack[sdepth].ptr = ptr;
+ stack[sdepth].off = off;
sdepth++;
ht = n->ht_down;
sel = 0;
- if (ht->divisor)
- sel = ht->divisor&u32_hash_fold(*(__be32*)(ptr+n->sel.hoff), &n->sel,n->fshift);
-
+ if (ht->divisor) {
+ __be32 *data, _data;
+
+ data = skb_header_pointer(skb, off + n->sel.hoff, 4,
+ &_data);
+ if (!data)
+ goto out;
+ sel = ht->divisor & u32_hash_fold(*data, &n->sel,
+ n->fshift);
+ }
if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))
goto next_ht;
if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) {
off2 = n->sel.off + 3;
- if (n->sel.flags&TC_U32_VAROFFSET)
- off2 += ntohs(n->sel.offmask & *(__be16*)(ptr+n->sel.offoff)) >>n->sel.offshift;
+ if (n->sel.flags & TC_U32_VAROFFSET) {
+ __be16 *data, _data;
+
+ data = skb_header_pointer(skb,
+ off + n->sel.offoff,
+ 2, &_data);
+ if (!data)
+ goto out;
+ off2 += ntohs(n->sel.offmask & *data) >>
+ n->sel.offshift;
+ }
off2 &= ~3;
}
if (n->sel.flags&TC_U32_EAT) {
- ptr += off2;
+ off += off2;
off2 = 0;
}
- if (ptr < skb_tail_pointer(skb))
+ if (off < skb->len)
goto next_ht;
}
@@ -204,9 +226,10 @@ check_terminal:
if (sdepth--) {
n = stack[sdepth].knode;
ht = n->ht_up;
- ptr = stack[sdepth].ptr;
+ off = stack[sdepth].off;
goto check_terminal;
}
+out:
return -1;
deadloop:
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index a63029ef3edd..d20fcd2a5519 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -205,7 +205,7 @@ void __qdisc_run(struct Qdisc *q)
}
}
- clear_bit(__QDISC_STATE_RUNNING, &q->state);
+ qdisc_run_end(q);
}
unsigned long dev_trans_start(struct net_device *dev)
@@ -327,6 +327,24 @@ void netif_carrier_off(struct net_device *dev)
}
EXPORT_SYMBOL(netif_carrier_off);
+/**
+ * netif_notify_peers - notify network peers about existence of @dev
+ * @dev: network device
+ *
+ * Generate traffic such that interested network peers are aware of
+ * @dev, such as by generating a gratuitous ARP. This may be used when
+ * a device wants to inform the rest of the network about some sort of
+ * reconfiguration such as a failover event or virtual machine
+ * migration.
+ */
+void netif_notify_peers(struct net_device *dev)
+{
+ rtnl_lock();
+ call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
+ rtnl_unlock();
+}
+EXPORT_SYMBOL(netif_notify_peers);
+
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
under all circumstances. It is difficult to invent anything faster or
cheaper.
@@ -543,6 +561,7 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q);
+ spin_lock_init(&sch->busylock);
sch->ops = ops;
sch->enqueue = ops->enqueue;
sch->dequeue = ops->dequeue;
@@ -779,7 +798,7 @@ static bool some_qdisc_is_busy(struct net_device *dev)
spin_lock_bh(root_lock);
- val = (test_bit(__QDISC_STATE_RUNNING, &q->state) ||
+ val = (qdisc_is_running(q) ||
test_bit(__QDISC_STATE_SCHED, &q->state));
spin_unlock_bh(root_lock);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index bd2a50b482ac..246f92924658 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1817,7 +1817,7 @@ malformed:
struct __sctp_missing {
__be32 num_missing;
__be16 type;
-} __attribute__((packed));
+} __packed;
/*
* Report a missing mandatory parameter.
diff --git a/net/socket.c b/net/socket.c
index 367d5477d00f..acfa1738663d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -124,7 +124,7 @@ static int sock_fasync(int fd, struct file *filp, int on);
static ssize_t sock_sendpage(struct file *file, struct page *page,
int offset, size_t size, loff_t *ppos, int more);
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
+ struct pipe_inode_info *pipe, size_t len,
unsigned int flags);
/*
@@ -162,7 +162,7 @@ static const struct net_proto_family *net_families[NPROTO] __read_mostly;
* Statistics counters of the socket lists
*/
-static DEFINE_PER_CPU(int, sockets_in_use) = 0;
+static DEFINE_PER_CPU(int, sockets_in_use);
/*
* Support routines.
@@ -309,9 +309,9 @@ static int init_inodecache(void)
}
static const struct super_operations sockfs_ops = {
- .alloc_inode = sock_alloc_inode,
- .destroy_inode =sock_destroy_inode,
- .statfs = simple_statfs,
+ .alloc_inode = sock_alloc_inode,
+ .destroy_inode = sock_destroy_inode,
+ .statfs = simple_statfs,
};
static int sockfs_get_sb(struct file_system_type *fs_type,
@@ -411,6 +411,7 @@ int sock_map_fd(struct socket *sock, int flags)
return fd;
}
+EXPORT_SYMBOL(sock_map_fd);
static struct socket *sock_from_file(struct file *file, int *err)
{
@@ -422,7 +423,7 @@ static struct socket *sock_from_file(struct file *file, int *err)
}
/**
- * sockfd_lookup - Go from a file number to its socket slot
+ * sockfd_lookup - Go from a file number to its socket slot
* @fd: file handle
* @err: pointer to an error code return
*
@@ -450,6 +451,7 @@ struct socket *sockfd_lookup(int fd, int *err)
fput(file);
return sock;
}
+EXPORT_SYMBOL(sockfd_lookup);
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
@@ -540,6 +542,7 @@ void sock_release(struct socket *sock)
}
sock->file = NULL;
}
+EXPORT_SYMBOL(sock_release);
int sock_tx_timestamp(struct msghdr *msg, struct sock *sk,
union skb_shared_tx *shtx)
@@ -586,6 +589,7 @@ int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
+EXPORT_SYMBOL(sock_sendmsg);
int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size)
@@ -604,6 +608,7 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
set_fs(oldfs);
return result;
}
+EXPORT_SYMBOL(kernel_sendmsg);
static int ktime2ts(ktime_t kt, struct timespec *ts)
{
@@ -664,7 +669,6 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
put_cmsg(msg, SOL_SOCKET,
SCM_TIMESTAMPING, sizeof(ts), &ts);
}
-
EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -720,6 +724,7 @@ int sock_recvmsg(struct socket *sock, struct msghdr *msg,
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
+EXPORT_SYMBOL(sock_recvmsg);
static int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg,
size_t size, int flags)
@@ -752,6 +757,7 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
set_fs(oldfs);
return result;
}
+EXPORT_SYMBOL(kernel_recvmsg);
static void sock_aio_dtor(struct kiocb *iocb)
{
@@ -774,7 +780,7 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
}
static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
- struct pipe_inode_info *pipe, size_t len,
+ struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct socket *sock = file->private_data;
@@ -887,7 +893,7 @@ static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
*/
static DEFINE_MUTEX(br_ioctl_mutex);
-static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg) = NULL;
+static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg);
void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
{
@@ -895,7 +901,6 @@ void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *))
br_ioctl_hook = hook;
mutex_unlock(&br_ioctl_mutex);
}
-
EXPORT_SYMBOL(brioctl_set);
static DEFINE_MUTEX(vlan_ioctl_mutex);
@@ -907,7 +912,6 @@ void vlan_ioctl_set(int (*hook) (struct net *, void __user *))
vlan_ioctl_hook = hook;
mutex_unlock(&vlan_ioctl_mutex);
}
-
EXPORT_SYMBOL(vlan_ioctl_set);
static DEFINE_MUTEX(dlci_ioctl_mutex);
@@ -919,7 +923,6 @@ void dlci_ioctl_set(int (*hook) (unsigned int, void __user *))
dlci_ioctl_hook = hook;
mutex_unlock(&dlci_ioctl_mutex);
}
-
EXPORT_SYMBOL(dlci_ioctl_set);
static long sock_do_ioctl(struct net *net, struct socket *sock,
@@ -1047,6 +1050,7 @@ out_release:
sock = NULL;
goto out;
}
+EXPORT_SYMBOL(sock_create_lite);
/* No kernel lock held - perfect */
static unsigned int sock_poll(struct file *file, poll_table *wait)
@@ -1147,6 +1151,7 @@ call_kill:
rcu_read_unlock();
return 0;
}
+EXPORT_SYMBOL(sock_wake_async);
static int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
@@ -1265,11 +1270,13 @@ int sock_create(int family, int type, int protocol, struct socket **res)
{
return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0);
}
+EXPORT_SYMBOL(sock_create);
int sock_create_kern(int family, int type, int protocol, struct socket **res)
{
return __sock_create(&init_net, family, type, protocol, res, 1);
}
+EXPORT_SYMBOL(sock_create_kern);
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
@@ -1474,7 +1481,8 @@ SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
goto out;
err = -ENFILE;
- if (!(newsock = sock_alloc()))
+ newsock = sock_alloc();
+ if (!newsock)
goto out_put;
newsock->type = sock->type;
@@ -1861,8 +1869,7 @@ SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags)
if (MSG_CMSG_COMPAT & flags) {
if (get_compat_msghdr(&msg_sys, msg_compat))
return -EFAULT;
- }
- else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
+ } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
@@ -1964,8 +1971,7 @@ static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg,
if (MSG_CMSG_COMPAT & flags) {
if (get_compat_msghdr(msg_sys, msg_compat))
return -EFAULT;
- }
- else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
+ } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))
return -EFAULT;
err = -EMSGSIZE;
@@ -2191,10 +2197,10 @@ SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg,
/* Argument list sizes for sys_socketcall */
#define AL(x) ((x) * sizeof(unsigned long))
static const unsigned char nargs[20] = {
- AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
- AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
- AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
- AL(4),AL(5)
+ AL(0), AL(3), AL(3), AL(3), AL(2), AL(3),
+ AL(3), AL(3), AL(4), AL(4), AL(4), AL(6),
+ AL(6), AL(2), AL(5), AL(5), AL(3), AL(3),
+ AL(4), AL(5)
};
#undef AL
@@ -2340,6 +2346,7 @@ int sock_register(const struct net_proto_family *ops)
printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
return err;
}
+EXPORT_SYMBOL(sock_register);
/**
* sock_unregister - remove a protocol handler
@@ -2366,6 +2373,7 @@ void sock_unregister(int family)
printk(KERN_INFO "NET: Unregistered protocol family %d\n", family);
}
+EXPORT_SYMBOL(sock_unregister);
static int __init sock_init(void)
{
@@ -2490,13 +2498,13 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
ifc.ifc_req = NULL;
uifc = compat_alloc_user_space(sizeof(struct ifconf));
} else {
- size_t len =((ifc32.ifc_len / sizeof (struct compat_ifreq)) + 1) *
- sizeof (struct ifreq);
+ size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) *
+ sizeof(struct ifreq);
uifc = compat_alloc_user_space(sizeof(struct ifconf) + len);
ifc.ifc_len = len;
ifr = ifc.ifc_req = (void __user *)(uifc + 1);
ifr32 = compat_ptr(ifc32.ifcbuf);
- for (i = 0; i < ifc32.ifc_len; i += sizeof (struct compat_ifreq)) {
+ for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) {
if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
ifr++;
@@ -2516,9 +2524,9 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
ifr = ifc.ifc_req;
ifr32 = compat_ptr(ifc32.ifcbuf);
for (i = 0, j = 0;
- i + sizeof (struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
- i += sizeof (struct compat_ifreq), j += sizeof (struct ifreq)) {
- if (copy_in_user(ifr32, ifr, sizeof (struct compat_ifreq)))
+ i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len;
+ i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) {
+ if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq)))
return -EFAULT;
ifr32++;
ifr++;
@@ -2567,7 +2575,7 @@ static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32
compat_uptr_t uptr32;
struct ifreq __user *uifr;
- uifr = compat_alloc_user_space(sizeof (*uifr));
+ uifr = compat_alloc_user_space(sizeof(*uifr));
if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
@@ -2601,9 +2609,9 @@ static int bond_ioctl(struct net *net, unsigned int cmd,
return -EFAULT;
old_fs = get_fs();
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
err = dev_ioctl(net, cmd, &kifr);
- set_fs (old_fs);
+ set_fs(old_fs);
return err;
case SIOCBONDSLAVEINFOQUERY:
@@ -2710,9 +2718,9 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
return -EFAULT;
old_fs = get_fs();
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
err = dev_ioctl(net, cmd, (void __user *)&ifr);
- set_fs (old_fs);
+ set_fs(old_fs);
if (cmd == SIOCGIFMAP && !err) {
err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
@@ -2734,7 +2742,7 @@ static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uif
compat_uptr_t uptr32;
struct ifreq __user *uifr;
- uifr = compat_alloc_user_space(sizeof (*uifr));
+ uifr = compat_alloc_user_space(sizeof(*uifr));
if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq)))
return -EFAULT;
@@ -2750,20 +2758,20 @@ static int compat_siocshwtstamp(struct net *net, struct compat_ifreq __user *uif
}
struct rtentry32 {
- u32 rt_pad1;
+ u32 rt_pad1;
struct sockaddr rt_dst; /* target address */
struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */
struct sockaddr rt_genmask; /* target network mask (IP) */
- unsigned short rt_flags;
- short rt_pad2;
- u32 rt_pad3;
- unsigned char rt_tos;
- unsigned char rt_class;
- short rt_pad4;
- short rt_metric; /* +1 for binary compatibility! */
+ unsigned short rt_flags;
+ short rt_pad2;
+ u32 rt_pad3;
+ unsigned char rt_tos;
+ unsigned char rt_class;
+ short rt_pad4;
+ short rt_metric; /* +1 for binary compatibility! */
/* char * */ u32 rt_dev; /* forcing the device at add */
- u32 rt_mtu; /* per route MTU/Window */
- u32 rt_window; /* Window clamping */
+ u32 rt_mtu; /* per route MTU/Window */
+ u32 rt_window; /* Window clamping */
unsigned short rt_irtt; /* Initial RTT */
};
@@ -2793,29 +2801,29 @@ static int routing_ioctl(struct net *net, struct socket *sock,
if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */
struct in6_rtmsg32 __user *ur6 = argp;
- ret = copy_from_user (&r6.rtmsg_dst, &(ur6->rtmsg_dst),
+ ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
3 * sizeof(struct in6_addr));
- ret |= __get_user (r6.rtmsg_type, &(ur6->rtmsg_type));
- ret |= __get_user (r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
- ret |= __get_user (r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
- ret |= __get_user (r6.rtmsg_metric, &(ur6->rtmsg_metric));
- ret |= __get_user (r6.rtmsg_info, &(ur6->rtmsg_info));
- ret |= __get_user (r6.rtmsg_flags, &(ur6->rtmsg_flags));
- ret |= __get_user (r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
+ ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
+ ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
+ ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
+ ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
+ ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
+ ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
+ ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
r = (void *) &r6;
} else { /* ipv4 */
struct rtentry32 __user *ur4 = argp;
- ret = copy_from_user (&r4.rt_dst, &(ur4->rt_dst),
+ ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
3 * sizeof(struct sockaddr));
- ret |= __get_user (r4.rt_flags, &(ur4->rt_flags));
- ret |= __get_user (r4.rt_metric, &(ur4->rt_metric));
- ret |= __get_user (r4.rt_mtu, &(ur4->rt_mtu));
- ret |= __get_user (r4.rt_window, &(ur4->rt_window));
- ret |= __get_user (r4.rt_irtt, &(ur4->rt_irtt));
- ret |= __get_user (rtdev, &(ur4->rt_dev));
+ ret |= __get_user(r4.rt_flags, &(ur4->rt_flags));
+ ret |= __get_user(r4.rt_metric, &(ur4->rt_metric));
+ ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu));
+ ret |= __get_user(r4.rt_window, &(ur4->rt_window));
+ ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt));
+ ret |= __get_user(rtdev, &(ur4->rt_dev));
if (rtdev) {
- ret |= copy_from_user (devname, compat_ptr(rtdev), 15);
+ ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
r4.rt_dev = devname; devname[15] = 0;
} else
r4.rt_dev = NULL;
@@ -2828,9 +2836,9 @@ static int routing_ioctl(struct net *net, struct socket *sock,
goto out;
}
- set_fs (KERNEL_DS);
+ set_fs(KERNEL_DS);
ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r);
- set_fs (old_fs);
+ set_fs(old_fs);
out:
return ret;
@@ -2993,11 +3001,13 @@ int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen)
{
return sock->ops->bind(sock, addr, addrlen);
}
+EXPORT_SYMBOL(kernel_bind);
int kernel_listen(struct socket *sock, int backlog)
{
return sock->ops->listen(sock, backlog);
}
+EXPORT_SYMBOL(kernel_listen);
int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
{
@@ -3022,24 +3032,28 @@ int kernel_accept(struct socket *sock, struct socket **newsock, int flags)
done:
return err;
}
+EXPORT_SYMBOL(kernel_accept);
int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen,
int flags)
{
return sock->ops->connect(sock, addr, addrlen, flags);
}
+EXPORT_SYMBOL(kernel_connect);
int kernel_getsockname(struct socket *sock, struct sockaddr *addr,
int *addrlen)
{
return sock->ops->getname(sock, addr, addrlen, 0);
}
+EXPORT_SYMBOL(kernel_getsockname);
int kernel_getpeername(struct socket *sock, struct sockaddr *addr,
int *addrlen)
{
return sock->ops->getname(sock, addr, addrlen, 1);
}
+EXPORT_SYMBOL(kernel_getpeername);
int kernel_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen)
@@ -3056,6 +3070,7 @@ int kernel_getsockopt(struct socket *sock, int level, int optname,
set_fs(oldfs);
return err;
}
+EXPORT_SYMBOL(kernel_getsockopt);
int kernel_setsockopt(struct socket *sock, int level, int optname,
char *optval, unsigned int optlen)
@@ -3072,6 +3087,7 @@ int kernel_setsockopt(struct socket *sock, int level, int optname,
set_fs(oldfs);
return err;
}
+EXPORT_SYMBOL(kernel_setsockopt);
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags)
@@ -3083,6 +3099,7 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
return sock_no_sendpage(sock, page, offset, size, flags);
}
+EXPORT_SYMBOL(kernel_sendpage);
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
{
@@ -3095,33 +3112,10 @@ int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
return err;
}
+EXPORT_SYMBOL(kernel_sock_ioctl);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how)
{
return sock->ops->shutdown(sock, how);
}
-
-EXPORT_SYMBOL(sock_create);
-EXPORT_SYMBOL(sock_create_kern);
-EXPORT_SYMBOL(sock_create_lite);
-EXPORT_SYMBOL(sock_map_fd);
-EXPORT_SYMBOL(sock_recvmsg);
-EXPORT_SYMBOL(sock_register);
-EXPORT_SYMBOL(sock_release);
-EXPORT_SYMBOL(sock_sendmsg);
-EXPORT_SYMBOL(sock_unregister);
-EXPORT_SYMBOL(sock_wake_async);
-EXPORT_SYMBOL(sockfd_lookup);
-EXPORT_SYMBOL(kernel_sendmsg);
-EXPORT_SYMBOL(kernel_recvmsg);
-EXPORT_SYMBOL(kernel_bind);
-EXPORT_SYMBOL(kernel_listen);
-EXPORT_SYMBOL(kernel_accept);
-EXPORT_SYMBOL(kernel_connect);
-EXPORT_SYMBOL(kernel_getsockname);
-EXPORT_SYMBOL(kernel_getpeername);
-EXPORT_SYMBOL(kernel_getsockopt);
-EXPORT_SYMBOL(kernel_setsockopt);
-EXPORT_SYMBOL(kernel_sendpage);
-EXPORT_SYMBOL(kernel_sock_ioctl);
EXPORT_SYMBOL(kernel_sock_shutdown);
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 2a9675136c68..8239dc50a613 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2571,7 +2571,8 @@ void cleanup_socket_xprt(void)
xprt_unregister_transport(&xs_bc_tcp_transport);
}
-static int param_set_uint_minmax(const char *val, struct kernel_param *kp,
+static int param_set_uint_minmax(const char *val,
+ const struct kernel_param *kp,
unsigned int min, unsigned int max)
{
unsigned long num;
@@ -2586,34 +2587,37 @@ static int param_set_uint_minmax(const char *val, struct kernel_param *kp,
return 0;
}
-static int param_set_portnr(const char *val, struct kernel_param *kp)
+static int param_set_portnr(const char *val, const struct kernel_param *kp)
{
return param_set_uint_minmax(val, kp,
RPC_MIN_RESVPORT,
RPC_MAX_RESVPORT);
}
-static int param_get_portnr(char *buffer, struct kernel_param *kp)
-{
- return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_portnr = {
+ .set = param_set_portnr,
+ .get = param_get_uint,
+};
+
#define param_check_portnr(name, p) \
__param_check(name, p, unsigned int);
module_param_named(min_resvport, xprt_min_resvport, portnr, 0644);
module_param_named(max_resvport, xprt_max_resvport, portnr, 0644);
-static int param_set_slot_table_size(const char *val, struct kernel_param *kp)
+static int param_set_slot_table_size(const char *val,
+ const struct kernel_param *kp)
{
return param_set_uint_minmax(val, kp,
RPC_MIN_SLOT_TABLE,
RPC_MAX_SLOT_TABLE);
}
-static int param_get_slot_table_size(char *buffer, struct kernel_param *kp)
-{
- return param_get_uint(buffer, kp);
-}
+static struct kernel_param_ops param_ops_slot_table_size = {
+ .set = param_set_slot_table_size,
+ .get = param_get_uint,
+};
+
#define param_check_slot_table_size(name, p) \
__param_check(name, p, unsigned int);
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index b01a6f6397d7..d0c92dddb26b 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -35,8 +35,9 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
if (!ht_cap->ht_supported)
return NULL;
- if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
- ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+ if (channel_type != NL80211_CHAN_HT20 &&
+ (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+ ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
return NULL;
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index ae930acf75e9..63d57ae399c3 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -339,6 +339,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie);
/* SME */
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 48ead6f0426d..f69ae19f497f 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -827,6 +827,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type,
+ bool channel_type_valid,
const u8 *buf, size_t len, u64 *cookie)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -855,7 +856,7 @@ int cfg80211_mlme_action(struct cfg80211_registered_device *rdev,
/* Transmit the Action frame as requested by user space */
return rdev->ops->action(&rdev->wiphy, dev, chan, channel_type,
- buf, len, cookie);
+ channel_type_valid, buf, len, cookie);
}
bool cfg80211_rx_action(struct net_device *dev, int freq, const u8 *buf,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index db71150b8040..90ab3c8519be 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -4681,6 +4681,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
struct net_device *dev;
struct ieee80211_channel *chan;
enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
+ bool channel_type_valid = false;
u32 freq;
int err;
void *hdr;
@@ -4722,6 +4723,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
err = -EINVAL;
goto out;
}
+ channel_type_valid = true;
}
freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
@@ -4745,6 +4747,7 @@ static int nl80211_action(struct sk_buff *skb, struct genl_info *info)
goto free_msg;
}
err = cfg80211_mlme_action(rdev, dev, chan, channel_type,
+ channel_type_valid,
nla_data(info->attrs[NL80211_ATTR_FRAME]),
nla_len(info->attrs[NL80211_ATTR_FRAME]),
&cookie);
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 6a329158bdfa..a3cca0a94346 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -95,13 +95,13 @@ resume:
goto error_nolock;
}
- dst = dst_pop(dst);
+ dst = skb_dst_pop(skb);
if (!dst) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
err = -EHOSTUNREACH;
goto error_nolock;
}
- skb_dst_set(skb, dst);
+ skb_dst_set_noref(skb, dst);
x = dst->xfrm;
} while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL));
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index d965a2bad8d3..4bf27d901333 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -2153,6 +2153,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
return 0;
}
+ skb_dst_force(skb);
dst = skb_dst(skb);
res = xfrm_lookup(net, &dst, &fl, NULL, 0) == 0;
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 0b94d2fa3a88..390aae4bb222 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -82,7 +82,7 @@ ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
lib-target := $(obj)/lib.a
endif
-ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),)
+ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(subdir-m) $(lib-target)),)
builtin-target := $(obj)/built-in.o
endif
@@ -156,14 +156,14 @@ $(obj)/%.i: $(src)/%.c FORCE
cmd_gensymtypes = \
$(CPP) -D__GENKSYMS__ $(c_flags) $< | \
- $(GENKSYMS) -T $@ -a $(ARCH) \
+ $(GENKSYMS) $(if $(1), -T $(2)) -a $(ARCH) \
$(if $(KBUILD_PRESERVE),-p) \
- $(if $(1),-r $(firstword $(wildcard $(@:.symtypes=.symref) /dev/null)))
+ -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null))
quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@
cmd_cc_symtypes_c = \
set -e; \
- $(call cmd_gensymtypes, true) >/dev/null; \
+ $(call cmd_gensymtypes,true,$@) >/dev/null; \
test -s $@ || rm -f $@
$(obj)/%.symtypes : $(src)/%.c FORCE
@@ -192,16 +192,16 @@ else
# the actual value of the checksum generated by genksyms
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
-cmd_modversions = \
- if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
- $(call cmd_gensymtypes, $(KBUILD_SYMTYPES)) \
- > $(@D)/.tmp_$(@F:.o=.ver); \
- \
- $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
- -T $(@D)/.tmp_$(@F:.o=.ver); \
- rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
- else \
- mv -f $(@D)/.tmp_$(@F) $@; \
+cmd_modversions = \
+ if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \
+ $(call cmd_gensymtypes,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \
+ > $(@D)/.tmp_$(@F:.o=.ver); \
+ \
+ $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \
+ -T $(@D)/.tmp_$(@F:.o=.ver); \
+ rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \
+ else \
+ mv -f $(@D)/.tmp_$(@F) $@; \
fi;
endif
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index cbcd654215e6..54fd1b700131 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -241,7 +241,7 @@ cmd_lzma = (cat $(filter-out FORCE,$^) | \
lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
-quiet_cmd_lzo = LZO $@
+quiet_cmd_lzo = LZO $@
cmd_lzo = (cat $(filter-out FORCE,$^) | \
lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
(rm -f $@ ; false)
diff --git a/scripts/checkincludes.pl b/scripts/checkincludes.pl
index 676ddc07d6fa..97b2c6143fe4 100755
--- a/scripts/checkincludes.pl
+++ b/scripts/checkincludes.pl
@@ -11,6 +11,8 @@
# you do have real dups and do not have them under #ifdef's. You
# could also just review the results.
+use strict;
+
sub usage {
print "Usage: checkincludes.pl [-r]\n";
print "By default we just warn of duplicates\n";
@@ -35,23 +37,24 @@ if ($#ARGV >= 1) {
}
}
-foreach $file (@ARGV) {
- open(FILE, $file) or die "Cannot open $file: $!.\n";
+foreach my $file (@ARGV) {
+ open(my $f, '<', $file)
+ or die "Cannot open $file: $!.\n";
my %includedfiles = ();
my @file_lines = ();
- while (<FILE>) {
+ while (<$f>) {
if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
++$includedfiles{$1};
}
push(@file_lines, $_);
}
- close(FILE);
+ close($f);
if (!$remove) {
- foreach $filename (keys %includedfiles) {
+ foreach my $filename (keys %includedfiles) {
if ($includedfiles{$filename} > 1) {
print "$file: $filename is included more than once.\n";
}
@@ -59,27 +62,28 @@ foreach $file (@ARGV) {
next;
}
- open(FILE,">$file") || die("Cannot write to $file: $!");
+ open($f, '>', $file)
+ or die("Cannot write to $file: $!");
my $dups = 0;
foreach (@file_lines) {
if (m/^\s*#\s*include\s*[<"](\S*)[>"]/o) {
- foreach $filename (keys %includedfiles) {
+ foreach my $filename (keys %includedfiles) {
if ($1 eq $filename) {
if ($includedfiles{$filename} > 1) {
$includedfiles{$filename}--;
$dups++;
} else {
- print FILE $_;
+ print {$f} $_;
}
}
}
} else {
- print FILE $_;
+ print {$f} $_;
}
}
if ($dups > 0) {
print "$file: removed $dups duplicate includes\n";
}
- close(FILE);
+ close($f);
}
diff --git a/scripts/checkkconfigsymbols.sh b/scripts/checkkconfigsymbols.sh
index 46be3c5a62b7..2ca49bb31efc 100755
--- a/scripts/checkkconfigsymbols.sh
+++ b/scripts/checkkconfigsymbols.sh
@@ -14,7 +14,7 @@ find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while
do
# Output the bare Kconfig variable and the filename; the _MODULE part at
# the end is not removed here (would need perl an not-hungry regexp for that).
- sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Z_]\+\).*!\2 '$i'!p' < $i
+ sed -ne 's!^.*\<\(UML_\)\?CONFIG_\([0-9A-Za-z_]\+\).*!\2 '$i'!p' < $i
done | \
# Smart "sort|uniq" implemented in awk and tuned to collect the names of all
# files which use a given symbol
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl
index 14ee68e991dd..1afff6658a7d 100755
--- a/scripts/checkstack.pl
+++ b/scripts/checkstack.pl
@@ -21,6 +21,8 @@
#
# TODO : Port to all architectures (one regex per arch)
+use strict;
+
# check for arch
#
# $re is used for two matches:
@@ -104,19 +106,11 @@ my (@stack, $re, $dre, $x, $xs);
}
}
-sub bysize($) {
- my ($asize, $bsize);
- ($asize = $a) =~ s/.*: *(.*)$/$1/;
- ($bsize = $b) =~ s/.*: *(.*)$/$1/;
- $bsize <=> $asize
-}
-
#
# main()
#
my $funcre = qr/^$x* <(.*)>:$/;
-my $func;
-my $file, $lastslash;
+my ($func, $file, $lastslash);
while (my $line = <STDIN>) {
if ($line =~ m/$funcre/) {
@@ -173,4 +167,6 @@ while (my $line = <STDIN>) {
}
}
-print sort bysize @stack;
+# Sort output by size (last field)
+print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;
+
diff --git a/scripts/checkversion.pl b/scripts/checkversion.pl
index ec7d21161bdc..b444e89a0095 100755
--- a/scripts/checkversion.pl
+++ b/scripts/checkversion.pl
@@ -5,23 +5,22 @@
# including <linux/version.h> that don't need it.
# Copyright (C) 2003, Randy Dunlap <rdunlap@xenotime.net>
+use strict;
+
$| = 1;
-my $debugging = 0;
+my $debugging;
-foreach $file (@ARGV)
-{
+foreach my $file (@ARGV) {
# Open this file.
- open(FILE, $file) || die "Can't open $file: $!\n";
+ open( my $f, '<', $file )
+ or die "Can't open $file: $!\n";
# Initialize variables.
- my $fInComment = 0;
- my $fInString = 0;
- my $fUseVersion = 0;
+ my ($fInComment, $fInString, $fUseVersion);
my $iLinuxVersion = 0;
- LINE: while ( <FILE> )
- {
+ while (<$f>) {
# Strip comments.
$fInComment && (s+^.*?\*/+ +o ? ($fInComment = 0) : next);
m+/\*+o && (s+/\*.*?\*/+ +go, (s+/\*.*$+ +o && ($fInComment = 1)));
@@ -43,8 +42,8 @@ foreach $file (@ARGV)
# Look for uses: LINUX_VERSION_CODE, KERNEL_VERSION, UTS_RELEASE
if (($_ =~ /LINUX_VERSION_CODE/) || ($_ =~ /\WKERNEL_VERSION/)) {
$fUseVersion = 1;
- last LINE if $iLinuxVersion;
- }
+ last if $iLinuxVersion;
+ }
}
# Report used version IDs without include?
@@ -67,5 +66,5 @@ foreach $file (@ARGV)
}
}
- close(FILE);
+ close($f);
}
diff --git a/scripts/decodecode b/scripts/decodecode
index 4b00647814bc..18ba881c3415 100755
--- a/scripts/decodecode
+++ b/scripts/decodecode
@@ -7,7 +7,7 @@
# AFLAGS=--32 decodecode < 386.oops
cleanup() {
- rm -f $T $T.s $T.o $T.oo $T.aa $T.aaa
+ rm -f $T $T.s $T.o $T.oo $T.aa $T.dis
exit 1
}
@@ -39,6 +39,29 @@ fi
echo $code
code=`echo $code | sed -e 's/.*Code: //'`
+width=`expr index "$code" ' '`
+width=$((($width-1)/2))
+case $width in
+1) type=byte ;;
+2) type=2byte ;;
+4) type=4byte ;;
+esac
+
+disas() {
+ ${CROSS_COMPILE}as $AFLAGS -o $1.o $1.s > /dev/null 2>&1
+
+ if [ "$ARCH" = "arm" ]; then
+ if [ $width -eq 2 ]; then
+ OBJDUMPFLAGS="-M force-thumb"
+ fi
+
+ ${CROSS_COMPILE}strip $1.o
+ fi
+
+ ${CROSS_COMPILE}objdump $OBJDUMPFLAGS -S $1.o | \
+ grep -v "/tmp\|Disassembly\|\.text\|^$" > $1.dis 2>&1
+}
+
marker=`expr index "$code" "\<"`
if [ $marker -eq 0 ]; then
marker=`expr index "$code" "\("`
@@ -49,26 +72,25 @@ if [ $marker -ne 0 ]; then
echo All code >> $T.oo
echo ======== >> $T.oo
beforemark=`echo "$code"`
- echo -n " .byte 0x" > $T.s
- echo $beforemark | sed -e 's/ /,0x/g' | sed -e 's/<//g' | sed -e 's/>//g' >> $T.s
- as $AFLAGS -o $T.o $T.s &> /dev/null
- objdump -S $T.o | grep -v "/tmp" | grep -v "Disassembly" | grep -v "\.text" | grep -v "^$" &> $T.ooo
- cat $T.ooo >> $T.oo
- rm -f $T.o $T.s $T.ooo
+ echo -n " .$type 0x" > $T.s
+ echo $beforemark | sed -e 's/ /,0x/g; s/[<>()]//g' >> $T.s
+ disas $T
+ cat $T.dis >> $T.oo
+ rm -f $T.o $T.s $T.dis
# and fix code at-and-after marker
code=`echo "$code" | cut -c$((${marker} + 1))-`
fi
echo Code starting with the faulting instruction > $T.aa
echo =========================================== >> $T.aa
-code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g'`
-echo -n " .byte 0x" > $T.s
+code=`echo $code | sed -e 's/ [<(]/ /;s/[>)] / /;s/ /,0x/g; s/[>)]$//'`
+echo -n " .$type 0x" > $T.s
echo $code >> $T.s
-as $AFLAGS -o $T.o $T.s &> /dev/null
-objdump -S $T.o | grep -v "Disassembly" | grep -v "/tmp" | grep -v "\.text" | grep -v "^$" &> $T.aaa
-cat $T.aaa >> $T.aa
+disas $T
+cat $T.dis >> $T.aa
-faultline=`cat $T.aaa | head -1 | cut -d":" -f2`
+faultline=`cat $T.dis | head -1 | cut -d":" -f2`
+faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
cat $T.oo | sed -e "s/\($faultline\)/\*\1 <-- trapping instruction/g"
echo
diff --git a/scripts/export_report.pl b/scripts/export_report.pl
index 705b5ba7c152..04dce7c15f83 100644
--- a/scripts/export_report.pl
+++ b/scripts/export_report.pl
@@ -49,10 +49,10 @@ sub usage {
}
sub collectcfiles {
- my @file = `cat .tmp_versions/*.mod | grep '.*\.ko\$'`;
- @file = grep {s/\.ko/.mod.c/} @file;
- chomp @file;
- return @file;
+ my @file
+ = `cat .tmp_versions/*.mod | grep '.*\.ko\$' | sed s/\.ko$/.mod.c/`;
+ chomp @file;
+ return @file;
}
my (%SYMBOL, %MODULE, %opt, @allcfiles);
@@ -71,37 +71,40 @@ if (not defined $opt{'k'}) {
$opt{'k'} = "Module.symvers";
}
-unless (open(MODULE_SYMVERS, $opt{'k'})) {
- die "Sorry, cannot open $opt{'k'}: $!\n";
-}
+open (my $module_symvers, '<', $opt{'k'})
+ or die "Sorry, cannot open $opt{'k'}: $!\n";
if (defined $opt{'o'}) {
- unless (open(OUTPUT_HANDLE, ">$opt{'o'}")) {
- die "Sorry, cannot open $opt{'o'} $!\n";
- }
- select OUTPUT_HANDLE;
+ open (my $out, '>', $opt{'o'})
+ or die "Sorry, cannot open $opt{'o'} $!\n";
+
+ select $out;
}
+
#
# collect all the symbols and their attributes from the
# Module.symvers file
#
-while ( <MODULE_SYMVERS> ) {
+while ( <$module_symvers> ) {
chomp;
my (undef, $symbol, $module, $gpl) = split;
$SYMBOL { $symbol } = [ $module , "0" , $symbol, $gpl];
}
-close(MODULE_SYMVERS);
+close($module_symvers);
#
# collect the usage count of each symbol.
#
foreach my $thismod (@allcfiles) {
- unless (open(MODULE_MODULE, $thismod)) {
- print "Sorry, cannot open $thismod: $!\n";
+ my $module;
+
+ unless (open ($module, '<', $thismod)) {
+ warn "Sorry, cannot open $thismod: $!\n";
next;
}
+
my $state=0;
- while ( <MODULE_MODULE> ) {
+ while ( <$module> ) {
chomp;
if ($state == 0) {
$state = 1 if ($_ =~ /static const struct modversion_info/);
@@ -124,7 +127,7 @@ foreach my $thismod (@allcfiles) {
if ($state != 2) {
print "WARNING:$thismod is not built with CONFIG_MODVERSION enabled\n";
}
- close(MODULE_MODULE);
+ close($module);
}
print "\tThis file reports the exported symbols usage patterns by in-tree\n",
diff --git a/scripts/gen_initramfs_list.sh b/scripts/gen_initramfs_list.sh
index a932ae52f921..5958fffb2114 100644
--- a/scripts/gen_initramfs_list.sh
+++ b/scripts/gen_initramfs_list.sh
@@ -202,6 +202,7 @@ input_file() {
print_mtime "$1" >> ${output}
cat "$1" >> ${output}
else
+ echo "$1 \\"
cat "$1" | while read type dir file perm ; do
if [ "$type" == "file" ]; then
echo "$file \\";
@@ -231,7 +232,7 @@ arg="$1"
case "$arg" in
"-l") # files included in initramfs - used by kbuild
dep_list="list_"
- echo "deps_initramfs := \\"
+ echo "deps_initramfs := $0 \\"
shift
;;
"-o") # generate compressed cpio image named $1
diff --git a/scripts/genksyms/genksyms.c b/scripts/genksyms/genksyms.c
index af6b8363a2d5..f99115ebe925 100644
--- a/scripts/genksyms/genksyms.c
+++ b/scripts/genksyms/genksyms.c
@@ -758,8 +758,10 @@ int main(int argc, char **argv)
/* setlinebuf(debugfile); */
}
- if (flag_reference)
+ if (flag_reference) {
read_reference(ref_file);
+ fclose(ref_file);
+ }
yyparse();
diff --git a/scripts/headerdep.pl b/scripts/headerdep.pl
index b7f6c560e24d..8dd019bc5a73 100755
--- a/scripts/headerdep.pl
+++ b/scripts/headerdep.pl
@@ -80,8 +80,7 @@ sub search {
my $path = "$i/$filename";
return $path if -f $path;
}
-
- return undef;
+ return;
}
sub parse_all {
diff --git a/scripts/headers_check.pl b/scripts/headers_check.pl
index db1dd7a549f2..50d6cfd1fa77 100644
--- a/scripts/headers_check.pl
+++ b/scripts/headers_check.pl
@@ -28,11 +28,12 @@ my $lineno = 0;
my $filename;
foreach my $file (@files) {
- local *FH;
$filename = $file;
- open(FH, "<$filename") or die "$filename: $!\n";
+
+ open(my $fh, '<', $filename)
+ or die "$filename: $!\n";
$lineno = 0;
- while ($line = <FH>) {
+ while ($line = <$fh>) {
$lineno++;
&check_include();
&check_asm_types();
@@ -40,7 +41,7 @@ foreach my $file (@files) {
&check_declarations();
# Dropped for now. Too much noise &check_config();
}
- close FH;
+ close $fh;
}
exit $ret;
@@ -78,7 +79,7 @@ sub check_config
}
my $linux_asm_types;
-sub check_asm_types()
+sub check_asm_types
{
if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
return;
diff --git a/scripts/headers_install.pl b/scripts/headers_install.pl
index b89ca2c58fdb..4ca3be3b2e50 100644
--- a/scripts/headers_install.pl
+++ b/scripts/headers_install.pl
@@ -23,13 +23,13 @@ my ($readdir, $installdir, $arch, @files) = @ARGV;
my $unifdef = "scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__";
foreach my $file (@files) {
- local *INFILE;
- local *OUTFILE;
my $tmpfile = "$installdir/$file.tmp";
- open(INFILE, "<$readdir/$file")
- or die "$readdir/$file: $!\n";
- open(OUTFILE, ">$tmpfile") or die "$tmpfile: $!\n";
- while (my $line = <INFILE>) {
+
+ open(my $in, '<', "$readdir/$file")
+ or die "$readdir/$file: $!\n";
+ open(my $out, '>', $tmpfile)
+ or die "$tmpfile: $!\n";
+ while (my $line = <$in>) {
$line =~ s/([\s(])__user\s/$1/g;
$line =~ s/([\s(])__force\s/$1/g;
$line =~ s/([\s(])__iomem\s/$1/g;
@@ -39,10 +39,11 @@ foreach my $file (@files) {
$line =~ s/(^|\s)(inline)\b/$1__$2__/g;
$line =~ s/(^|\s)(asm)\b(\s|[(]|$)/$1__$2__$3/g;
$line =~ s/(^|\s|[(])(volatile)\b(\s|[(]|$)/$1__$2__$3/g;
- printf OUTFILE "%s", $line;
+ printf {$out} "%s", $line;
}
- close OUTFILE;
- close INFILE;
+ close $out;
+ close $in;
+
system $unifdef . " $tmpfile > $installdir/$file";
unlink $tmpfile;
}
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 86c3896a1e01..e3902fb39afd 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -108,8 +108,10 @@ static int read_symbol(FILE *in, struct sym_entry *s)
rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
if (rc != 3) {
if (rc != EOF) {
- /* skip line */
- fgets(str, 500, in);
+ /* skip line. sym is used as dummy to
+ * shut of "warn_unused_result" warning.
+ */
+ sym = fgets(str, 500, in);
}
return -1;
}
diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore
index 6a36a76e6606..624f6502e03e 100644
--- a/scripts/kconfig/.gitignore
+++ b/scripts/kconfig/.gitignore
@@ -17,6 +17,7 @@ gconf.glade.h
#
conf
mconf
+nconf
qconf
gconf
kxgettext
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 186c46604d06..0a34335bf0f9 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -23,6 +23,9 @@ menuconfig: $(obj)/mconf
config: $(obj)/conf
$< $(Kconfig)
+nconfig: $(obj)/nconf
+ $< $(Kconfig)
+
oldconfig: $(obj)/conf
$< -o $(Kconfig)
@@ -69,6 +72,12 @@ localyesconfig: $(obj)/streamline_config.pl $(obj)/conf
fi
$(Q)rm -f .tmp.config
+nonint_oldconfig: $(obj)/conf
+ $< -b $(Kconfig)
+
+loose_nonint_oldconfig: $(obj)/conf
+ $< -B $(Kconfig)
+
# Create new linux.pot file
# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files
# The symlink is used to repair a deficiency in arch/um
@@ -120,6 +129,7 @@ endif
# Help text used by make help
help:
@echo ' config - Update current config utilising a line-oriented program'
+ @echo ' nconfig - Update current config utilising a ncurses menu based program'
@echo ' menuconfig - Update current config utilising a menu based program'
@echo ' xconfig - Update current config utilising a QT based front-end'
@echo ' gconfig - Update current config utilising a GTK based front-end'
@@ -132,6 +142,10 @@ help:
@echo ' allmodconfig - New config selecting modules when possible'
@echo ' allyesconfig - New config where all options are accepted with yes'
@echo ' allnoconfig - New config where all options are answered with no'
+ @echo ' nonint_oldconfig - Checks the current configuration and fails if an option is '
+ @echo ' not set'
+ @echo ' loose_nonint_oldconfig - Same as nonint_oldconfig, but updates the config file with '
+ @echo ' missing config options as unset'
# lxdialog stuff
check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
@@ -147,6 +161,8 @@ HOST_EXTRACFLAGS += -DLOCALE
# ===========================================================================
# Shared Makefile for the various kconfig executables:
# conf: Used for defconfig, oldconfig and related targets
+# nconf: Used for the nconfig target.
+# Utilizes ncurses
# mconf: Used for the menuconfig target
# Utilizes the lxdialog package
# qconf: Used for the xconfig target
@@ -159,11 +175,16 @@ lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
conf-objs := conf.o zconf.tab.o
-mconf-objs := mconf.o zconf.tab.o $(lxdialog)
+mconf-objs := mconf.o zconf.tab.o $(lxdialog)
+nconf-objs := nconf.o zconf.tab.o nconf.gui.o
kxgettext-objs := kxgettext.o zconf.tab.o
hostprogs-y := conf qconf gconf kxgettext
+ifeq ($(MAKECMDGOALS),nconfig)
+ hostprogs-y += nconf
+endif
+
ifeq ($(MAKECMDGOALS),menuconfig)
hostprogs-y += mconf
endif
@@ -187,7 +208,7 @@ endif
clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
.tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c gconf.glade.h
-clean-files += mconf qconf gconf
+clean-files += mconf qconf gconf nconf
clean-files += config.pot linux.pot
# Check that we have the required ncurses stuff installed for lxdialog (menuconfig)
@@ -208,10 +229,11 @@ HOSTCFLAGS_zconf.tab.o := -I$(src)
HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl
HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK
-HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0`
+HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl
HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \
-D LKC_DIRECT_LINK
+HOSTLOADLIBES_nconf = -lmenu -lpanel -lncurses
$(obj)/qconf.o: $(obj)/.tmp_qtcheck
ifeq ($(qconf-target),1)
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 9960d1c303f8..3fa4abf3b084 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -16,6 +16,10 @@
#define LKC_DIRECT_LINK
#include "lkc.h"
+/* Return codes */
+#define EUNSETOPT 2 /* if -B and -b are used and unset config
+ * options were found */
+
static void conf(struct menu *menu);
static void check_conf(struct menu *menu);
@@ -23,6 +27,8 @@ enum {
ask_all,
ask_new,
ask_silent,
+ dont_ask,
+ dont_ask_dont_tell,
set_default,
set_yes,
set_mod,
@@ -37,6 +43,7 @@ static int sync_kconfig;
static int conf_cnt;
static char line[128];
static struct menu *rootEntry;
+static int unset_variables;
static void print_help(struct menu *menu)
{
@@ -360,7 +367,10 @@ static void conf(struct menu *menu)
switch (prop->type) {
case P_MENU:
- if (input_mode == ask_silent && rootEntry != menu) {
+ if ((input_mode == ask_silent ||
+ input_mode == dont_ask ||
+ input_mode == dont_ask_dont_tell) &&
+ rootEntry != menu) {
check_conf(menu);
return;
}
@@ -418,10 +428,23 @@ static void check_conf(struct menu *menu)
if (sym && !sym_has_value(sym)) {
if (sym_is_changable(sym) ||
(sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) {
- if (!conf_cnt++)
- printf(_("*\n* Restart config...\n*\n"));
- rootEntry = menu_get_parent_menu(menu);
- conf(rootEntry);
+ if (input_mode == dont_ask ||
+ input_mode == dont_ask_dont_tell) {
+ if (input_mode == dont_ask &&
+ sym->name && !sym_is_choice_value(sym)) {
+ if (!unset_variables)
+ fprintf(stderr, "The following"
+ " variables are not set:\n");
+ fprintf(stderr, "CONFIG_%s\n",
+ sym->name);
+ unset_variables++;
+ }
+ } else {
+ if (!conf_cnt++)
+ printf(_("*\n* Restart config...\n*\n"));
+ rootEntry = menu_get_parent_menu(menu);
+ conf(rootEntry);
+ }
}
}
@@ -439,7 +462,7 @@ int main(int ac, char **av)
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
- while ((opt = getopt(ac, av, "osdD:nmyrh")) != -1) {
+ while ((opt = getopt(ac, av, "osbBdD:nmyrh")) != -1) {
switch (opt) {
case 'o':
input_mode = ask_silent;
@@ -448,6 +471,12 @@ int main(int ac, char **av)
input_mode = ask_silent;
sync_kconfig = 1;
break;
+ case 'b':
+ input_mode = dont_ask;
+ break;
+ case 'B':
+ input_mode = dont_ask_dont_tell;
+ break;
case 'd':
input_mode = set_default;
break;
@@ -525,6 +554,8 @@ int main(int ac, char **av)
case ask_silent:
case ask_all:
case ask_new:
+ case dont_ask:
+ case dont_ask_dont_tell:
conf_read(NULL);
break;
case set_no:
@@ -586,12 +617,16 @@ int main(int ac, char **av)
conf(&rootmenu);
input_mode = ask_silent;
/* fall through */
+ case dont_ask:
+ case dont_ask_dont_tell:
case ask_silent:
/* Update until a loop caused no more changes */
do {
conf_cnt = 0;
check_conf(&rootmenu);
- } while (conf_cnt);
+ } while (conf_cnt &&
+ (input_mode != dont_ask &&
+ input_mode != dont_ask_dont_tell));
break;
}
@@ -607,11 +642,11 @@ int main(int ac, char **av)
fprintf(stderr, _("\n*** Error during update of the kernel configuration.\n\n"));
return 1;
}
- } else {
+ } else if (!unset_variables || input_mode != dont_ask) {
if (conf_write(NULL)) {
fprintf(stderr, _("\n*** Error during writing of the kernel configuration.\n\n"));
exit(1);
}
}
- return 0;
+ return unset_variables ? EUNSETOPT : 0;
}
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index edd3f39a080a..8f18e37892cb 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1097,9 +1097,32 @@ void expr_fprint(struct expr *e, FILE *out)
static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str)
{
- str_append((struct gstr*)data, str);
+ struct gstr *gs = (struct gstr*)data;
+ const char *sym_str = NULL;
+
if (sym)
- str_printf((struct gstr*)data, " [=%s]", sym_get_string_value(sym));
+ sym_str = sym_get_string_value(sym);
+
+ if (gs->max_width) {
+ unsigned extra_length = strlen(str);
+ const char *last_cr = strrchr(gs->s, '\n');
+ unsigned last_line_length;
+
+ if (sym_str)
+ extra_length += 4 + strlen(sym_str);
+
+ if (!last_cr)
+ last_cr = gs->s;
+
+ last_line_length = strlen(gs->s) - (last_cr - gs->s);
+
+ if ((last_line_length + extra_length) > gs->max_width)
+ str_append(gs, "\\\n");
+ }
+
+ str_append(gs, str);
+ if (sym && sym->type != S_UNKNOWN)
+ str_printf(gs, " [=%s]", sym_str);
}
void expr_gstr_print(struct expr *e, struct gstr *gs)
diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
index 6408fefae083..891cd9ce9ba2 100644
--- a/scripts/kconfig/expr.h
+++ b/scripts/kconfig/expr.h
@@ -86,7 +86,7 @@ struct symbol {
struct expr_value rev_dep;
};
-#define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
+#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER)
#define SYMBOL_CONST 0x0001 /* symbol is const */
#define SYMBOL_CHECK 0x0008 /* used during dependency checking */
@@ -108,8 +108,7 @@ struct symbol {
#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */
#define SYMBOL_MAXLENGTH 256
-#define SYMBOL_HASHSIZE 257
-#define SYMBOL_HASHMASK 0xff
+#define SYMBOL_HASHSIZE 9973
/* A property represent the config options that can be associated
* with a config "symbol".
diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c
index 65464366fe38..d66988265f89 100644
--- a/scripts/kconfig/gconf.c
+++ b/scripts/kconfig/gconf.c
@@ -30,13 +30,16 @@ enum {
SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
};
+enum {
+ OPT_NORMAL, OPT_ALL, OPT_PROMPT
+};
+
static gint view_mode = FULL_VIEW;
static gboolean show_name = TRUE;
static gboolean show_range = TRUE;
static gboolean show_value = TRUE;
-static gboolean show_all = FALSE;
-static gboolean show_debug = FALSE;
static gboolean resizeable = FALSE;
+static int opt_mode = OPT_NORMAL;
GtkWidget *main_wnd = NULL;
GtkWidget *tree1_w = NULL; // left frame
@@ -76,36 +79,7 @@ static void conf_changed(void);
/* Helping/Debugging Functions */
-
-const char *dbg_print_stype(int val)
-{
- static char buf[256];
-
- bzero(buf, 256);
-
- if (val == S_UNKNOWN)
- strcpy(buf, "unknown");
- if (val == S_BOOLEAN)
- strcpy(buf, "boolean");
- if (val == S_TRISTATE)
- strcpy(buf, "tristate");
- if (val == S_INT)
- strcpy(buf, "int");
- if (val == S_HEX)
- strcpy(buf, "hex");
- if (val == S_STRING)
- strcpy(buf, "string");
- if (val == S_OTHER)
- strcpy(buf, "other");
-
-#ifdef DEBUG
- printf("%s", buf);
-#endif
-
- return buf;
-}
-
-const char *dbg_print_flags(int val)
+const char *dbg_sym_flags(int val)
{
static char buf[256];
@@ -131,40 +105,10 @@ const char *dbg_print_flags(int val)
strcat(buf, "auto/");
buf[strlen(buf) - 1] = '\0';
-#ifdef DEBUG
- printf("%s", buf);
-#endif
-
- return buf;
-}
-
-const char *dbg_print_ptype(int val)
-{
- static char buf[256];
-
- bzero(buf, 256);
-
- if (val == P_UNKNOWN)
- strcpy(buf, "unknown");
- if (val == P_PROMPT)
- strcpy(buf, "prompt");
- if (val == P_COMMENT)
- strcpy(buf, "comment");
- if (val == P_MENU)
- strcpy(buf, "menu");
- if (val == P_DEFAULT)
- strcpy(buf, "default");
- if (val == P_CHOICE)
- strcpy(buf, "choice");
-
-#ifdef DEBUG
- printf("%s", buf);
-#endif
return buf;
}
-
void replace_button_icon(GladeXML * xml, GdkDrawable * window,
GtkStyle * style, gchar * btn_name, gchar ** xpm)
{
@@ -697,20 +641,29 @@ void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
void
-on_show_all_options1_activate(GtkMenuItem * menuitem, gpointer user_data)
+on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
{
- show_all = GTK_CHECK_MENU_ITEM(menuitem)->active;
+ opt_mode = OPT_NORMAL;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
+}
+
+void
+on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
+{
+ opt_mode = OPT_ALL;
gtk_tree_store_clear(tree2);
- display_tree(&rootmenu); // instead of update_tree to speed-up
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
}
void
-on_show_debug_info1_activate(GtkMenuItem * menuitem, gpointer user_data)
+on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
{
- show_debug = GTK_CHECK_MENU_ITEM(menuitem)->active;
- update_tree(&rootmenu, NULL);
+ opt_mode = OPT_PROMPT;
+ gtk_tree_store_clear(tree2);
+ display_tree(&rootmenu); /* instead of update_tree to speed-up */
}
@@ -1161,9 +1114,12 @@ static gchar **fill_row(struct menu *menu)
row[COL_OPTION] =
g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
- sym && sym_has_value(sym) ? "(NEW)" : "");
+ sym && !sym_has_value(sym) ? "(NEW)" : "");
- if (show_all && !menu_is_visible(menu))
+ if (opt_mode == OPT_ALL && !menu_is_visible(menu))
+ row[COL_COLOR] = g_strdup("DarkGray");
+ else if (opt_mode == OPT_PROMPT &&
+ menu_has_prompt(menu) && !menu_is_visible(menu))
row[COL_COLOR] = g_strdup("DarkGray");
else
row[COL_COLOR] = g_strdup("Black");
@@ -1386,16 +1342,20 @@ static void update_tree(struct menu *src, GtkTreeIter * dst)
menu2 ? menu_get_prompt(menu2) : "nil");
#endif
- if (!menu_is_visible(child1) && !show_all) { // remove node
+ if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
+ (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
+ (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
+
+ /* remove node */
if (gtktree_iter_find_node(dst, menu1) != NULL) {
memcpy(&tmp, child2, sizeof(GtkTreeIter));
valid = gtk_tree_model_iter_next(model2,
child2);
gtk_tree_store_remove(tree2, &tmp);
if (!valid)
- return; // next parent
+ return; /* next parent */
else
- goto reparse; // next child
+ goto reparse; /* next child */
} else
continue;
}
@@ -1464,17 +1424,19 @@ static void display_tree(struct menu *menu)
&& (tree == tree2))
continue;
- if (menu_is_visible(child) || show_all)
+ if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
+ (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
+ (opt_mode == OPT_ALL && menu_get_prompt(child)))
place_node(child, fill_row(child));
#ifdef DEBUG
printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
- dbg_print_ptype(ptype);
+ printf("%s", prop_get_type_name(ptype));
printf(" | ");
if (sym) {
- dbg_print_stype(sym->type);
+ printf("%s", sym_type_name(sym->type));
printf(" | ");
- dbg_print_flags(sym->flags);
+ printf("%s", dbg_sym_flags(sym->flags));
printf("\n");
} else
printf("\n");
diff --git a/scripts/kconfig/gconf.glade b/scripts/kconfig/gconf.glade
index b1c86c19292c..d52b0a75d824 100644
--- a/scripts/kconfig/gconf.glade
+++ b/scripts/kconfig/gconf.glade
@@ -190,26 +190,40 @@
</child>
<child>
- <widget class="GtkCheckMenuItem" id="show_all_options1">
+ <widget class="GtkRadioMenuItem" id="set_option_mode1">
+ <property name="visible">True</property>
+ <property name="tooltip" translatable="yes">Show normal options</property>
+ <property name="label" translatable="yes">Show normal options</property>
+ <property name="use_underline">True</property>
+ <property name="active">True</property>
+ <signal name="activate" handler="on_set_option_mode1_activate"/>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkRadioMenuItem" id="set_option_mode2">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Show all options</property>
<property name="label" translatable="yes">Show all _options</property>
<property name="use_underline">True</property>
<property name="active">False</property>
- <signal name="activate" handler="on_show_all_options1_activate"/>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode2_activate"/>
</widget>
</child>
<child>
- <widget class="GtkCheckMenuItem" id="show_debug_info1">
+ <widget class="GtkRadioMenuItem" id="set_option_mode3">
<property name="visible">True</property>
- <property name="tooltip" translatable="yes">Show masked options</property>
- <property name="label" translatable="yes">Show _debug info</property>
+ <property name="tooltip" translatable="yes">Show all options with prompts</property>
+ <property name="label" translatable="yes">Show all prompt options</property>
<property name="use_underline">True</property>
<property name="active">False</property>
- <signal name="activate" handler="on_show_debug_info1_activate"/>
+ <property name="group">set_option_mode1</property>
+ <signal name="activate" handler="on_set_option_mode3_activate"/>
</widget>
</child>
+
</widget>
</child>
</widget>
diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h
index f379b0bf8c9e..ce6549cdaccf 100644
--- a/scripts/kconfig/lkc.h
+++ b/scripts/kconfig/lkc.h
@@ -84,7 +84,7 @@ void conf_set_all_new_symbols(enum conf_def_mode mode);
void kconfig_load(void);
/* menu.c */
-void menu_init(void);
+void _menu_init(void);
void menu_warn(struct menu *menu, const char *fmt, ...);
struct menu *menu_add_menu(void);
void menu_end_menu(void);
@@ -106,6 +106,11 @@ int file_write_dep(const char *name);
struct gstr {
size_t len;
char *s;
+ /*
+ * when max_width is not zero long lines in string s (if any) get
+ * wrapped not to exceed the max_width value
+ */
+ int max_width;
};
struct gstr str_new(void);
struct gstr str_assign(const char *s);
diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h
index ffeb532b2cff..7cadcad8233b 100644
--- a/scripts/kconfig/lkc_proto.h
+++ b/scripts/kconfig/lkc_proto.h
@@ -11,13 +11,15 @@ P(conf_set_changed_callback, void,(void (*fn)(void)));
/* menu.c */
P(rootmenu,struct menu,);
-P(menu_is_visible,bool,(struct menu *menu));
+P(menu_is_visible, bool, (struct menu *menu));
+P(menu_has_prompt, bool, (struct menu *menu));
P(menu_get_prompt,const char *,(struct menu *menu));
P(menu_get_root_menu,struct menu *,(struct menu *menu));
P(menu_get_parent_menu,struct menu *,(struct menu *menu));
P(menu_has_help,bool,(struct menu *menu));
P(menu_get_help,const char *,(struct menu *menu));
-P(get_symbol_str,void,(struct gstr *r, struct symbol *sym));
+P(get_symbol_str, void, (struct gstr *r, struct symbol *sym));
+P(get_relations_str, struct gstr, (struct symbol **sym_arr));
P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help));
/* symbol.c */
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index bcc6f19c3a35..a2eb80fbc896 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -31,6 +31,10 @@ static int list_width, check_x, item_x;
static void print_item(WINDOW * win, int choice, int selected)
{
int i;
+ char *list_item = malloc(list_width + 1);
+
+ strncpy(list_item, item_str(), list_width - item_x);
+ list_item[list_width - item_x] = '\0';
/* Clear 'residue' of last item */
wattrset(win, dlg.menubox.atr);
@@ -45,13 +49,14 @@ static void print_item(WINDOW * win, int choice, int selected)
wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
- mvwaddch(win, choice, item_x, item_str()[0]);
+ mvwaddch(win, choice, item_x, list_item[0]);
wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
- waddstr(win, (char *)item_str() + 1);
+ waddstr(win, list_item + 1);
if (selected) {
wmove(win, choice, check_x + 1);
wrefresh(win);
}
+ free(list_item);
}
/*
@@ -175,6 +180,7 @@ do_resize:
check_x = 0;
item_foreach()
check_x = MAX(check_x, strlen(item_str()) + 4);
+ check_x = MIN(check_x, list_width);
check_x = (list_width - check_x) / 2;
item_x = check_x + 4;
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index 616c60138183..dd8e587c50e2 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -180,7 +180,7 @@ do_resize:
case KEY_LEFT:
switch (button) {
case -1:
- button = 1; /* Indicates "Cancel" button is selected */
+ button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 0:
@@ -204,7 +204,7 @@ do_resize:
print_buttons(dialog, height, width, 0);
break;
case 0:
- button = 1; /* Indicates "Cancel" button is selected */
+ button = 1; /* Indicates "Help" button is selected */
print_buttons(dialog, height, width, 1);
break;
case 1:
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index fa9d633f293c..1d604738fa13 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -383,6 +383,10 @@ do_resize:
case 'n':
case 'm':
case '/':
+ case 'h':
+ case '?':
+ case 'z':
+ case '\n':
/* save scroll info */
*s_scroll = scroll;
delwin(menu);
@@ -390,8 +394,10 @@ do_resize:
item_set(scroll + choice);
item_set_selected(1);
switch (key) {
+ case 'h':
+ case '?':
+ return 2;
case 's':
- return 3;
case 'y':
return 3;
case 'n':
@@ -402,18 +408,12 @@ do_resize:
return 6;
case '/':
return 7;
+ case 'z':
+ return 8;
+ case '\n':
+ return button;
}
return 0;
- case 'h':
- case '?':
- button = 2;
- case '\n':
- *s_scroll = scroll;
- delwin(menu);
- delwin(dialog);
- item_set(scroll + choice);
- item_set_selected(1);
- return button;
case 'e':
case 'x':
key = KEY_ESC;
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 8413cf38ed27..d2f6e056c058 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -67,13 +67,15 @@ static const char mconf_readme[] = N_(
" there is a delayed response which you may find annoying.\n"
"\n"
" Also, the <TAB> and cursor keys will cycle between <Select>,\n"
-" <Exit> and <Help>\n"
+" <Exit> and <Help>.\n"
"\n"
"o To get help with an item, use the cursor keys to highlight <Help>\n"
-" and Press <ENTER>.\n"
+" and press <ENTER>.\n"
"\n"
" Shortcut: Press <H> or <?>.\n"
"\n"
+"o To toggle the display of hidden options, press <Z>.\n"
+"\n"
"\n"
"Radiolists (Choice lists)\n"
"-----------\n"
@@ -272,6 +274,7 @@ static int indent;
static struct menu *current_menu;
static int child_count;
static int single_menu_mode;
+static int show_all_options;
static void conf(struct menu *menu);
static void conf_choice(struct menu *menu);
@@ -282,19 +285,6 @@ static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
-static struct gstr get_relations_str(struct symbol **sym_arr)
-{
- struct symbol *sym;
- struct gstr res = str_new();
- int i;
-
- for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
- get_symbol_str(&res, sym);
- if (!i)
- str_append(&res, _("No matches found.\n"));
- return res;
-}
-
static char filename[PATH_MAX+1];
static void set_config_filename(const char *config_filename)
{
@@ -359,8 +349,16 @@ static void build_conf(struct menu *menu)
int type, tmp, doint = 2;
tristate val;
char ch;
-
- if (!menu_is_visible(menu))
+ bool visible;
+
+ /*
+ * note: menu_is_visible() has side effect that it will
+ * recalc the value of the symbol.
+ */
+ visible = menu_is_visible(menu);
+ if (show_all_options && !menu_has_prompt(menu))
+ return;
+ else if (!show_all_options && !visible)
return;
sym = menu->sym;
@@ -619,6 +617,9 @@ static void conf(struct menu *menu)
case 7:
search_conf();
break;
+ case 8:
+ show_all_options = !show_all_options;
+ break;
}
}
}
@@ -638,6 +639,7 @@ static void show_help(struct menu *menu)
{
struct gstr help = str_new();
+ help.max_width = getmaxx(stdscr) - 10;
menu_get_ext_help(menu, &help);
show_helptext(_(menu_get_prompt(menu)), str_get(&help));
diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
index 059a2465c574..eef17bacb6bc 100644
--- a/scripts/kconfig/menu.c
+++ b/scripts/kconfig/menu.c
@@ -38,7 +38,7 @@ static void prop_warn(struct property *prop, const char *fmt, ...)
va_end(ap);
}
-void menu_init(void)
+void _menu_init(void)
{
current_entry = current_menu = &rootmenu;
last_entry_ptr = &rootmenu.list;
@@ -197,7 +197,7 @@ static void sym_check_prop(struct symbol *sym)
if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) &&
prop->expr->type != E_SYMBOL)
prop_warn(prop,
- "default for config symbol '%'"
+ "default for config symbol '%s'"
" must be a single symbol", sym->name);
break;
case P_SELECT:
@@ -390,6 +390,13 @@ void menu_finalize(struct menu *parent)
}
}
+bool menu_has_prompt(struct menu *menu)
+{
+ if (!menu->prompt)
+ return false;
+ return true;
+}
+
bool menu_is_visible(struct menu *menu)
{
struct menu *child;
@@ -398,6 +405,7 @@ bool menu_is_visible(struct menu *menu)
if (!menu->prompt)
return false;
+
sym = menu->sym;
if (sym) {
sym_calc_value(sym);
@@ -407,12 +415,18 @@ bool menu_is_visible(struct menu *menu)
if (visible != no)
return true;
+
if (!sym || sym_get_tristate_value(menu->sym) == no)
return false;
- for (child = menu->list; child; child = child->next)
- if (menu_is_visible(child))
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child)) {
+ if (sym)
+ sym->flags |= SYMBOL_DEF_USER;
return true;
+ }
+ }
+
return false;
}
@@ -491,9 +505,19 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
bool hit;
struct property *prop;
- if (sym && sym->name)
+ if (sym && sym->name) {
str_printf(r, "Symbol: %s [=%s]\n", sym->name,
sym_get_string_value(sym));
+ str_printf(r, "Type : %s\n", sym_type_name(sym->type));
+ if (sym->type == S_INT || sym->type == S_HEX) {
+ prop = sym_get_range_prop(sym);
+ if (prop) {
+ str_printf(r, "Range : ");
+ expr_gstr_print(prop->expr, r);
+ str_append(r, "\n");
+ }
+ }
+ }
for_all_prompts(sym, prop)
get_prompt_str(r, prop);
hit = false;
@@ -515,6 +539,20 @@ void get_symbol_str(struct gstr *r, struct symbol *sym)
str_append(r, "\n\n");
}
+struct gstr get_relations_str(struct symbol **sym_arr)
+{
+ struct symbol *sym;
+ struct gstr res = str_new();
+ int i;
+
+ for (i = 0; sym_arr && (sym = sym_arr[i]); i++)
+ get_symbol_str(&res, sym);
+ if (!i)
+ str_append(&res, _("No matches found.\n"));
+ return res;
+}
+
+
void menu_get_ext_help(struct menu *menu, struct gstr *help)
{
struct symbol *sym = menu->sym;
diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c
new file mode 100644
index 000000000000..762caf80ce37
--- /dev/null
+++ b/scripts/kconfig/nconf.c
@@ -0,0 +1,1568 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#define LKC_DIRECT_LINK
+#include "lkc.h"
+#include "nconf.h"
+
+static const char nconf_readme[] = N_(
+"Overview\n"
+"--------\n"
+"Some kernel features may be built directly into the kernel.\n"
+"Some may be made into loadable runtime modules. Some features\n"
+"may be completely removed altogether. There are also certain\n"
+"kernel parameters which are not really features, but must be\n"
+"entered in as decimal or hexadecimal numbers or possibly text.\n"
+"\n"
+"Menu items beginning with following braces represent features that\n"
+" [ ] can be built in or removed\n"
+" < > can be built in, modularized or removed\n"
+" { } can be built in or modularized (selected by other feature)\n"
+" - - are selected by other feature,\n"
+" XXX cannot be selected. use Symbol Info to find out why,\n"
+"while *, M or whitespace inside braces means to build in, build as\n"
+"a module or to exclude the feature respectively.\n"
+"\n"
+"To change any of these features, highlight it with the cursor\n"
+"keys and press <Y> to build it in, <M> to make it a module or\n"
+"<N> to removed it. You may also press the <Space Bar> to cycle\n"
+"through the available options (ie. Y->N->M->Y).\n"
+"\n"
+"Some additional keyboard hints:\n"
+"\n"
+"Menus\n"
+"----------\n"
+"o Use the Up/Down arrow keys (cursor keys) to highlight the item\n"
+" you wish to change use <Enter> or <Space>. Goto submenu by \n"
+" pressing <Enter> of <right-arrow>. Use <Esc> or <left-arrow> to go back.\n"
+" Submenus are designated by \"--->\".\n"
+"\n"
+" Shortcut: Press the option's highlighted letter (hotkey).\n"
+" Pressing a hotkey more than once will sequence\n"
+" through all visible items which use that hotkey.\n"
+"\n"
+" You may also use the <PAGE UP> and <PAGE DOWN> keys to scroll\n"
+" unseen options into view.\n"
+"\n"
+"o To exit a menu use the just press <ESC> <F5> <F8> or <left-arrow>.\n"
+"\n"
+"o To get help with an item, press <F1>\n"
+" Shortcut: Press <h> or <?>.\n"
+"\n"
+"\n"
+"Radiolists (Choice lists)\n"
+"-----------\n"
+"o Use the cursor keys to select the option you wish to set and press\n"
+" <S> or the <SPACE BAR>.\n"
+"\n"
+" Shortcut: Press the first letter of the option you wish to set then\n"
+" press <S> or <SPACE BAR>.\n"
+"\n"
+"o To see available help for the item, press <F1>\n"
+" Shortcut: Press <H> or <?>.\n"
+"\n"
+"\n"
+"Data Entry\n"
+"-----------\n"
+"o Enter the requested information and press <ENTER>\n"
+" If you are entering hexadecimal values, it is not necessary to\n"
+" add the '0x' prefix to the entry.\n"
+"\n"
+"o For help, press <F1>.\n"
+"\n"
+"\n"
+"Text Box (Help Window)\n"
+"--------\n"
+"o Use the cursor keys to scroll up/down/left/right. The VI editor\n"
+" keys h,j,k,l function here as do <SPACE BAR> for those\n"
+" who are familiar with less and lynx.\n"
+"\n"
+"o Press <Enter>, <F1>, <F5>, <F7> or <Esc> to exit.\n"
+"\n"
+"\n"
+"Alternate Configuration Files\n"
+"-----------------------------\n"
+"nconfig supports the use of alternate configuration files for\n"
+"those who, for various reasons, find it necessary to switch\n"
+"between different kernel configurations.\n"
+"\n"
+"At the end of the main menu you will find two options. One is\n"
+"for saving the current configuration to a file of your choosing.\n"
+"The other option is for loading a previously saved alternate\n"
+"configuration.\n"
+"\n"
+"Even if you don't use alternate configuration files, but you\n"
+"find during a nconfig session that you have completely messed\n"
+"up your settings, you may use the \"Load Alternate...\" option to\n"
+"restore your previously saved settings from \".config\" without\n"
+"restarting nconfig.\n"
+"\n"
+"Other information\n"
+"-----------------\n"
+"If you use nconfig in an XTERM window make sure you have your\n"
+"$TERM variable set to point to a xterm definition which supports color.\n"
+"Otherwise, nconfig will look rather bad. nconfig will not\n"
+"display correctly in a RXVT window because rxvt displays only one\n"
+"intensity of color, bright.\n"
+"\n"
+"nconfig will display larger menus on screens or xterms which are\n"
+"set to display more than the standard 25 row by 80 column geometry.\n"
+"In order for this to work, the \"stty size\" command must be able to\n"
+"display the screen's current row and column geometry. I STRONGLY\n"
+"RECOMMEND that you make sure you do NOT have the shell variables\n"
+"LINES and COLUMNS exported into your environment. Some distributions\n"
+"export those variables via /etc/profile. Some ncurses programs can\n"
+"become confused when those variables (LINES & COLUMNS) don't reflect\n"
+"the true screen size.\n"
+"\n"
+"Optional personality available\n"
+"------------------------------\n"
+"If you prefer to have all of the kernel options listed in a single\n"
+"menu, rather than the default multimenu hierarchy, run the nconfig\n"
+"with NCONFIG_MODE environment variable set to single_menu. Example:\n"
+"\n"
+"make NCONFIG_MODE=single_menu nconfig\n"
+"\n"
+"<Enter> will then unroll the appropriate category, or enfold it if it\n"
+"is already unrolled.\n"
+"\n"
+"Note that this mode can eventually be a little more CPU expensive\n"
+"(especially with a larger number of unrolled categories) than the\n"
+"default mode.\n"
+"\n"),
+menu_no_f_instructions[] = N_(
+" You do not have function keys support. Please follow the\n"
+" following instructions:\n"
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options\n"
+" Press <Esc> or <left-arrow> to go back one menu, \n"
+" <?> or <h> for Help, </> for Search.\n"
+" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+" <Esc> always leaves the current window\n"),
+menu_instructions[] = N_(
+" Arrow keys navigate the menu.\n"
+" <Enter> or <right-arrow> selects submenus --->.\n"
+" Capital Letters are hotkeys.\n"
+" Pressing <Y> includes, <N> excludes, <M> modularizes features.\n"
+" Pressing SpaceBar toggles between the above options\n"
+" Press <Esc>, <F3> or <left-arrow> to go back one menu, \n"
+" <?>, <F1> or <h> for Help, </> for Search.\n"
+" <1> is interchangable with <F1>, <2> with <F2>, etc.\n"
+" Legend: [*] built-in [ ] excluded <M> module < > module capable.\n"
+" <Esc> always leaves the current window\n"),
+radiolist_instructions[] = N_(
+" Use the arrow keys to navigate this window or\n"
+" press the hotkey of the item you wish to select\n"
+" followed by the <SPACE BAR>.\n"
+" Press <?>, <F1> or <h> for additional information about this option.\n"),
+inputbox_instructions_int[] = N_(
+"Please enter a decimal value.\n"
+"Fractions will not be accepted.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_hex[] = N_(
+"Please enter a hexadecimal value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+inputbox_instructions_string[] = N_(
+"Please enter a string value.\n"
+"Press <RETURN> to accept, <ESC> to cancel."),
+setmod_text[] = N_(
+"This feature depends on another which\n"
+"has been configured as a module.\n"
+"As a result, this feature will be built as a module."),
+nohelp_text[] = N_(
+"There is no help available for this kernel option.\n"),
+load_config_text[] = N_(
+"Enter the name of the configuration file you wish to load.\n"
+"Accept the name shown to restore the configuration you\n"
+"last retrieved. Leave blank to abort."),
+load_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep several different kernel\n"
+"configurations available on a single machine.\n"
+"\n"
+"If you have saved a previous configuration in a file other than the\n"
+"kernel's default, entering the name of the file here will allow you\n"
+"to modify that configuration.\n"
+"\n"
+"If you are uncertain, then you have probably never used alternate\n"
+"configuration files. You should therefor leave this blank to abort.\n"),
+save_config_text[] = N_(
+"Enter a filename to which this configuration should be saved\n"
+"as an alternate. Leave blank to abort."),
+save_config_help[] = N_(
+"\n"
+"For various reasons, one may wish to keep different kernel\n"
+"configurations available on a single machine.\n"
+"\n"
+"Entering a file name here will allow you to later retrieve, modify\n"
+"and use the current configuration as an alternate to whatever\n"
+"configuration options you have selected at that time.\n"
+"\n"
+"If you are uncertain what all this means then you should probably\n"
+"leave this blank.\n"),
+search_help[] = N_(
+"\n"
+"Search for CONFIG_ symbols and display their relations.\n"
+"Regular expressions are allowed.\n"
+"Example: search for \"^FOO\"\n"
+"Result:\n"
+"-----------------------------------------------------------------\n"
+"Symbol: FOO [ = m]\n"
+"Prompt: Foo bus is used to drive the bar HW\n"
+"Defined at drivers/pci/Kconfig:47\n"
+"Depends on: X86_LOCAL_APIC && X86_IO_APIC || IA64\n"
+"Location:\n"
+" -> Bus options (PCI, PCMCIA, EISA, MCA, ISA)\n"
+" -> PCI support (PCI [ = y])\n"
+" -> PCI access mode (<choice> [ = y])\n"
+"Selects: LIBCRC32\n"
+"Selected by: BAR\n"
+"-----------------------------------------------------------------\n"
+"o The line 'Prompt:' shows the text used in the menu structure for\n"
+" this CONFIG_ symbol\n"
+"o The 'Defined at' line tell at what file / line number the symbol\n"
+" is defined\n"
+"o The 'Depends on:' line tell what symbols needs to be defined for\n"
+" this symbol to be visible in the menu (selectable)\n"
+"o The 'Location:' lines tell where in the menu structure this symbol\n"
+" is located\n"
+" A location followed by a [ = y] indicate that this is a selectable\n"
+" menu item - and current value is displayed inside brackets.\n"
+"o The 'Selects:' line tell what symbol will be automatically\n"
+" selected if this symbol is selected (y or m)\n"
+"o The 'Selected by' line tell what symbol has selected this symbol\n"
+"\n"
+"Only relevant lines are shown.\n"
+"\n\n"
+"Search examples:\n"
+"Examples: USB = > find all CONFIG_ symbols containing USB\n"
+" ^USB => find all CONFIG_ symbols starting with USB\n"
+" USB$ => find all CONFIG_ symbols ending with USB\n"
+"\n");
+
+struct mitem {
+ char str[256];
+ char tag;
+ void *usrptr;
+ int is_hot;
+ int is_visible;
+};
+
+#define MAX_MENU_ITEMS 4096
+static int show_all_items;
+static int indent;
+static struct menu *current_menu;
+static int child_count;
+static int single_menu_mode;
+/* the window in which all information appears */
+static WINDOW *main_window;
+/* the largest size of the menu window */
+static int mwin_max_lines;
+static int mwin_max_cols;
+/* the window in which we show option buttons */
+static MENU *curses_menu;
+static ITEM *curses_menu_items[MAX_MENU_ITEMS];
+static struct mitem k_menu_items[MAX_MENU_ITEMS];
+static int items_num;
+static int global_exit;
+/* the currently selected button */
+const char *current_instructions = menu_instructions;
+/* this array is used to implement hot keys. it is updated in item_make and
+ * resetted in clean_items. It would be better to use a hash, but lets keep it
+ * simple... */
+#define MAX_SAME_KEY MAX_MENU_ITEMS
+struct {
+ int count;
+ int ptrs[MAX_MENU_ITEMS];
+} hotkeys[1<<(sizeof(char)*8)];
+
+static void conf(struct menu *menu);
+static void conf_choice(struct menu *menu);
+static void conf_string(struct menu *menu);
+static void conf_load(void);
+static void conf_save(void);
+static void show_help(struct menu *menu);
+static int do_exit(void);
+static void setup_windows(void);
+
+typedef void (*function_key_handler_t)(int *key, struct menu *menu);
+static void handle_f1(int *key, struct menu *current_item);
+static void handle_f2(int *key, struct menu *current_item);
+static void handle_f3(int *key, struct menu *current_item);
+static void handle_f4(int *key, struct menu *current_item);
+static void handle_f5(int *key, struct menu *current_item);
+static void handle_f6(int *key, struct menu *current_item);
+static void handle_f7(int *key, struct menu *current_item);
+static void handle_f8(int *key, struct menu *current_item);
+
+struct function_keys {
+ const char *key_str;
+ const char *func;
+ function_key key;
+ function_key_handler_t handler;
+};
+
+static const int function_keys_num = 8;
+struct function_keys function_keys[] = {
+ {
+ .key_str = "F1",
+ .func = "Help",
+ .key = F_HELP,
+ .handler = handle_f1,
+ },
+ {
+ .key_str = "F2",
+ .func = "Symbol Info",
+ .key = F_SYMBOL,
+ .handler = handle_f2,
+ },
+ {
+ .key_str = "F3",
+ .func = "Instructions",
+ .key = F_INSTS,
+ .handler = handle_f3,
+ },
+ {
+ .key_str = "F4",
+ .func = "Config",
+ .key = F_CONF,
+ .handler = handle_f4,
+ },
+ {
+ .key_str = "F5",
+ .func = "Back",
+ .key = F_BACK,
+ .handler = handle_f5,
+ },
+ {
+ .key_str = "F6",
+ .func = "Save",
+ .key = F_SAVE,
+ .handler = handle_f6,
+ },
+ {
+ .key_str = "F7",
+ .func = "Load",
+ .key = F_LOAD,
+ .handler = handle_f7,
+ },
+ {
+ .key_str = "F8",
+ .func = "Exit",
+ .key = F_EXIT,
+ .handler = handle_f8,
+ },
+};
+
+static void print_function_line(void)
+{
+ int i;
+ int offset = 1;
+ const int skip = 1;
+
+ for (i = 0; i < function_keys_num; i++) {
+ wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]);
+ mvwprintw(main_window, LINES-3, offset,
+ "%s",
+ function_keys[i].key_str);
+ wattrset(main_window, attributes[FUNCTION_TEXT]);
+ offset += strlen(function_keys[i].key_str);
+ mvwprintw(main_window, LINES-3,
+ offset, "%s",
+ function_keys[i].func);
+ offset += strlen(function_keys[i].func) + skip;
+ }
+ wattrset(main_window, attributes[NORMAL]);
+}
+
+/* help */
+static void handle_f1(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("README"), _(nconf_readme));
+ return;
+}
+
+/* symbole help */
+static void handle_f2(int *key, struct menu *current_item)
+{
+ show_help(current_item);
+ return;
+}
+
+/* instructions */
+static void handle_f3(int *key, struct menu *current_item)
+{
+ show_scroll_win(main_window,
+ _("Instructions"),
+ _(current_instructions));
+ return;
+}
+
+/* config */
+static void handle_f4(int *key, struct menu *current_item)
+{
+ int res = btn_dialog(main_window,
+ _("Show all symbols?"),
+ 2,
+ " <Show All> ",
+ "<Don't show all>");
+ if (res == 0)
+ show_all_items = 1;
+ else if (res == 1)
+ show_all_items = 0;
+
+ return;
+}
+
+/* back */
+static void handle_f5(int *key, struct menu *current_item)
+{
+ *key = KEY_LEFT;
+ return;
+}
+
+/* save */
+static void handle_f6(int *key, struct menu *current_item)
+{
+ conf_save();
+ return;
+}
+
+/* load */
+static void handle_f7(int *key, struct menu *current_item)
+{
+ conf_load();
+ return;
+}
+
+/* exit */
+static void handle_f8(int *key, struct menu *current_item)
+{
+ do_exit();
+ return;
+}
+
+/* return != 0 to indicate the key was handles */
+static int process_special_keys(int *key, struct menu *menu)
+{
+ int i;
+
+ if (*key == KEY_RESIZE) {
+ setup_windows();
+ return 1;
+ }
+
+ for (i = 0; i < function_keys_num; i++) {
+ if (*key == KEY_F(function_keys[i].key) ||
+ *key == '0' + function_keys[i].key){
+ function_keys[i].handler(key, menu);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static void clean_items(void)
+{
+ int i;
+ for (i = 0; curses_menu_items[i]; i++)
+ free_item(curses_menu_items[i]);
+ bzero(curses_menu_items, sizeof(curses_menu_items));
+ bzero(k_menu_items, sizeof(k_menu_items));
+ bzero(hotkeys, sizeof(hotkeys));
+ items_num = 0;
+}
+
+/* return the index of the next hot item, or -1 if no such item exists */
+static int get_next_hot(int c)
+{
+ static int hot_index;
+ static int hot_char;
+
+ if (c < 0 || c > 255 || hotkeys[c].count <= 0)
+ return -1;
+
+ if (hot_char == c) {
+ hot_index = (hot_index+1)%hotkeys[c].count;
+ return hotkeys[c].ptrs[hot_index];
+ } else {
+ hot_char = c;
+ hot_index = 0;
+ return hotkeys[c].ptrs[0];
+ }
+}
+
+/* can the char c be a hot key? no, if c is a common shortcut used elsewhere */
+static int canbhot(char c)
+{
+ c = tolower(c);
+ return isalnum(c) && c != 'y' && c != 'm' && c != 'h' &&
+ c != 'n' && c != '?';
+}
+
+/* check if str already contains a hot key. */
+static int is_hot(int index)
+{
+ return k_menu_items[index].is_hot;
+}
+
+/* find the first possible hot key, and mark it.
+ * index is the index of the item in the menu
+ * return 0 on success*/
+static int make_hot(char *dest, int len, const char *org, int index)
+{
+ int position = -1;
+ int i;
+ int tmp;
+ int c;
+ int org_len = strlen(org);
+
+ if (org == NULL || is_hot(index))
+ return 1;
+
+ /* make sure not to make hot keys out of markers.
+ * find where to start looking for a hot key
+ */
+ i = 0;
+ /* skip white space */
+ while (i < org_len && org[i] == ' ')
+ i++;
+ if (i == org_len)
+ return -1;
+ /* if encountering '(' or '<' or '[', find the match and look from there
+ **/
+ if (org[i] == '[' || org[i] == '<' || org[i] == '(') {
+ i++;
+ for (; i < org_len; i++)
+ if (org[i] == ']' || org[i] == '>' || org[i] == ')')
+ break;
+ }
+ if (i == org_len)
+ return -1;
+ for (; i < org_len; i++) {
+ if (canbhot(org[i]) && org[i-1] != '<' && org[i-1] != '(') {
+ position = i;
+ break;
+ }
+ }
+ if (position == -1)
+ return 1;
+
+ /* ok, char at org[position] should be a hot key to this item */
+ c = tolower(org[position]);
+ tmp = hotkeys[c].count;
+ hotkeys[c].ptrs[tmp] = index;
+ hotkeys[c].count++;
+ /*
+ snprintf(dest, len, "%.*s(%c)%s", position, org, org[position],
+ &org[position+1]);
+ */
+ /* make org[position] uppercase, and all leading letter small case */
+ strncpy(dest, org, len);
+ for (i = 0; i < position; i++)
+ dest[i] = tolower(dest[i]);
+ dest[position] = toupper(dest[position]);
+ k_menu_items[index].is_hot = 1;
+ return 0;
+}
+
+/* Make a new item. Add a hotkey mark in the first possible letter.
+ * As ncurses does not allow any attributes inside menue item, we mark the
+ * hot key as the first capitalized letter in the string */
+static void item_make(struct menu *menu, char tag, const char *fmt, ...)
+{
+ va_list ap;
+ char tmp_str[256];
+
+ if (items_num > MAX_MENU_ITEMS-1)
+ return;
+
+ bzero(&k_menu_items[items_num], sizeof(k_menu_items[0]));
+ k_menu_items[items_num].tag = tag;
+ k_menu_items[items_num].usrptr = menu;
+ if (menu != NULL)
+ k_menu_items[items_num].is_visible =
+ menu_is_visible(menu);
+ else
+ k_menu_items[items_num].is_visible = 1;
+
+ va_start(ap, fmt);
+ vsnprintf(tmp_str, sizeof(tmp_str), fmt, ap);
+ if (!k_menu_items[items_num].is_visible)
+ memcpy(tmp_str, "XXX", 3);
+ va_end(ap);
+ if (make_hot(
+ k_menu_items[items_num].str,
+ sizeof(k_menu_items[items_num].str), tmp_str, items_num) != 0)
+ strncpy(k_menu_items[items_num].str,
+ tmp_str,
+ sizeof(k_menu_items[items_num].str));
+
+ curses_menu_items[items_num] = new_item(
+ k_menu_items[items_num].str,
+ k_menu_items[items_num].str);
+ set_item_userptr(curses_menu_items[items_num],
+ &k_menu_items[items_num]);
+ /*
+ if (!k_menu_items[items_num].is_visible)
+ item_opts_off(curses_menu_items[items_num], O_SELECTABLE);
+ */
+
+ items_num++;
+ curses_menu_items[items_num] = NULL;
+}
+
+/* very hackish. adds a string to the last item added */
+static void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ int index = items_num-1;
+ char new_str[256];
+ char tmp_str[256];
+
+ if (index < 0)
+ return;
+
+ va_start(ap, fmt);
+ vsnprintf(new_str, sizeof(new_str), fmt, ap);
+ va_end(ap);
+ snprintf(tmp_str, sizeof(tmp_str), "%s%s",
+ k_menu_items[index].str, new_str);
+ if (make_hot(k_menu_items[index].str,
+ sizeof(k_menu_items[index].str), tmp_str, index) != 0)
+ strncpy(k_menu_items[index].str,
+ tmp_str,
+ sizeof(k_menu_items[index].str));
+
+ free_item(curses_menu_items[index]);
+ curses_menu_items[index] = new_item(
+ k_menu_items[index].str,
+ k_menu_items[index].str);
+ set_item_userptr(curses_menu_items[index],
+ &k_menu_items[index]);
+}
+
+/* get the tag of the currently selected item */
+static char item_tag(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ if (cur == NULL)
+ return 0;
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->tag;
+}
+
+static int curses_item_index(void)
+{
+ return item_index(current_item(curses_menu));
+}
+
+static void *item_data(void)
+{
+ ITEM *cur;
+ struct mitem *mcur;
+
+ cur = current_item(curses_menu);
+ mcur = (struct mitem *) item_userptr(cur);
+ return mcur->usrptr;
+
+}
+
+static int item_is_tag(char tag)
+{
+ return item_tag() == tag;
+}
+
+static char filename[PATH_MAX+1];
+static char menu_backtitle[PATH_MAX+128];
+static const char *set_config_filename(const char *config_filename)
+{
+ int size;
+ struct symbol *sym;
+
+ sym = sym_lookup("KERNELVERSION", 0);
+ sym_calc_value(sym);
+ size = snprintf(menu_backtitle, sizeof(menu_backtitle),
+ _("%s - Linux Kernel v%s Configuration"),
+ config_filename, sym_get_string_value(sym));
+ if (size >= sizeof(menu_backtitle))
+ menu_backtitle[sizeof(menu_backtitle)-1] = '\0';
+
+ size = snprintf(filename, sizeof(filename), "%s", config_filename);
+ if (size >= sizeof(filename))
+ filename[sizeof(filename)-1] = '\0';
+ return menu_backtitle;
+}
+
+/* command = 0 is supress, 1 is restore */
+static void supress_stdout(int command)
+{
+ static FILE *org_stdout;
+ static FILE *org_stderr;
+
+ if (command == 0) {
+ org_stdout = stdout;
+ org_stderr = stderr;
+ stdout = fopen("/dev/null", "a");
+ stderr = fopen("/dev/null", "a");
+ } else {
+ fclose(stdout);
+ fclose(stderr);
+ stdout = org_stdout;
+ stderr = org_stderr;
+ }
+}
+
+/* return = 0 means we are successful.
+ * -1 means go on doing what you were doing
+ */
+static int do_exit(void)
+{
+ int res;
+ if (!conf_get_changed()) {
+ global_exit = 1;
+ return 0;
+ }
+ res = btn_dialog(main_window,
+ _("Do you wish to save your "
+ "new kernel configuration?\n"
+ "<ESC> to cancel and resume nconfig."),
+ 2,
+ " <save> ",
+ "<don't save>");
+ if (res == KEY_EXIT) {
+ global_exit = 0;
+ return -1;
+ }
+
+ /* if we got here, the user really wants to exit */
+ switch (res) {
+ case 0:
+ supress_stdout(0);
+ res = conf_write(filename);
+ supress_stdout(1);
+ if (res)
+ btn_dialog(
+ main_window,
+ _("Error during writing of the kernel "
+ "configuration.\n"
+ "Your kernel configuration "
+ "changes were NOT saved."),
+ 1,
+ "<OK>");
+ else {
+ char buf[1024];
+ snprintf(buf, 1024,
+ _("Configuration written to %s\n"
+ "End of Linux kernel configuration.\n"
+ "Execute 'make' to build the kernel or try"
+ " 'make help'."), filename);
+ btn_dialog(
+ main_window,
+ buf,
+ 1,
+ "<OK>");
+ }
+ break;
+ default:
+ btn_dialog(
+ main_window,
+ _("Your kernel configuration changes were NOT saved."),
+ 1,
+ "<OK>");
+ break;
+ }
+ global_exit = 1;
+ return 0;
+}
+
+
+static void search_conf(void)
+{
+ struct symbol **sym_arr;
+ struct gstr res;
+ char dialog_input_result[100];
+ char *dialog_input;
+ int dres;
+again:
+ dres = dialog_inputbox(main_window,
+ _("Search Configuration Parameter"),
+ _("Enter CONFIG_ (sub)string to search for "
+ "(with or without \"CONFIG\")"),
+ "", dialog_input_result, 99);
+ switch (dres) {
+ case 0:
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Search Configuration"), search_help);
+ goto again;
+ default:
+ return;
+ }
+
+ /* strip CONFIG_ if necessary */
+ dialog_input = dialog_input_result;
+ if (strncasecmp(dialog_input_result, "CONFIG_", 7) == 0)
+ dialog_input += 7;
+
+ sym_arr = sym_re_search(dialog_input);
+ res = get_relations_str(sym_arr);
+ free(sym_arr);
+ show_scroll_win(main_window,
+ _("Search Results"), str_get(&res));
+ str_free(&res);
+}
+
+
+static void build_conf(struct menu *menu)
+{
+ struct symbol *sym;
+ struct property *prop;
+ struct menu *child;
+ int type, tmp, doint = 2;
+ tristate val;
+ char ch;
+
+ if (!menu || (!show_all_items && !menu_is_visible(menu)))
+ return;
+
+ sym = menu->sym;
+ prop = menu->prompt;
+ if (!sym) {
+ if (prop && menu != current_menu) {
+ const char *prompt = menu_get_prompt(menu);
+ enum prop_type ptype;
+ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
+ switch (ptype) {
+ case P_MENU:
+ child_count++;
+ prompt = _(prompt);
+ if (single_menu_mode) {
+ item_make(menu, 'm',
+ "%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
+ } else
+ item_make(menu, 'm',
+ " %*c%s --->",
+ indent + 1,
+ ' ', prompt);
+
+ if (single_menu_mode && menu->data)
+ goto conf_childs;
+ return;
+ case P_COMMENT:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':',
+ " %*c*** %s ***",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ break;
+ default:
+ if (prompt) {
+ child_count++;
+ item_make(menu, ':', "---%*c%s",
+ indent + 1, ' ',
+ _(prompt));
+ }
+ }
+ } else
+ doint = 0;
+ goto conf_childs;
+ }
+
+ type = sym_get_type(sym);
+ if (sym_is_choice(sym)) {
+ struct symbol *def_sym = sym_get_choice_value(sym);
+ struct menu *def_menu = NULL;
+
+ child_count++;
+ for (child = menu->list; child; child = child->next) {
+ if (menu_is_visible(child) && child->sym == def_sym)
+ def_menu = child;
+ }
+
+ val = sym_get_tristate_value(sym);
+ if (sym_is_changable(sym)) {
+ switch (type) {
+ case S_BOOLEAN:
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ item_make(menu, 't', "<%c>", ch);
+ break;
+ }
+ } else {
+ item_make(menu, def_menu ? 't' : ':', " ");
+ }
+
+ item_add_str("%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ if (val == yes) {
+ if (def_menu) {
+ item_add_str(" (%s)",
+ _(menu_get_prompt(def_menu)));
+ item_add_str(" --->");
+ if (def_menu->list) {
+ indent += 2;
+ build_conf(def_menu);
+ indent -= 2;
+ }
+ }
+ return;
+ }
+ } else {
+ if (menu == current_menu) {
+ item_make(menu, ':',
+ "---%*c%s", indent + 1,
+ ' ', _(menu_get_prompt(menu)));
+ goto conf_childs;
+ }
+ child_count++;
+ val = sym_get_tristate_value(sym);
+ if (sym_is_choice_value(sym) && val == yes) {
+ item_make(menu, ':', " ");
+ } else {
+ switch (type) {
+ case S_BOOLEAN:
+ if (sym_is_changable(sym))
+ item_make(menu, 't', "[%c]",
+ val == no ? ' ' : '*');
+ else
+ item_make(menu, 't', "-%c-",
+ val == no ? ' ' : '*');
+ break;
+ case S_TRISTATE:
+ switch (val) {
+ case yes:
+ ch = '*';
+ break;
+ case mod:
+ ch = 'M';
+ break;
+ default:
+ ch = ' ';
+ break;
+ }
+ if (sym_is_changable(sym)) {
+ if (sym->rev_dep.tri == mod)
+ item_make(menu,
+ 't', "{%c}", ch);
+ else
+ item_make(menu,
+ 't', "<%c>", ch);
+ } else
+ item_make(menu, 't', "-%c-", ch);
+ break;
+ default:
+ tmp = 2 + strlen(sym_get_string_value(sym));
+ item_make(menu, 's', " (%s)",
+ sym_get_string_value(sym));
+ tmp = indent - tmp + 4;
+ if (tmp < 0)
+ tmp = 0;
+ item_add_str("%*c%s%s", tmp, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) ||
+ !sym_is_changable(sym)) ? "" :
+ _(" (NEW)"));
+ goto conf_childs;
+ }
+ }
+ item_add_str("%*c%s%s", indent + 1, ' ',
+ _(menu_get_prompt(menu)),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : _(" (NEW)"));
+ if (menu->prompt && menu->prompt->type == P_MENU) {
+ item_add_str(" --->");
+ return;
+ }
+ }
+
+conf_childs:
+ indent += doint;
+ for (child = menu->list; child; child = child->next)
+ build_conf(child);
+ indent -= doint;
+}
+
+static void reset_menu(void)
+{
+ unpost_menu(curses_menu);
+ clean_items();
+}
+
+/* adjust the menu to show this item.
+ * prefer not to scroll the menu if possible*/
+static void center_item(int selected_index, int *last_top_row)
+{
+ int toprow;
+ int maxy, maxx;
+
+ scale_menu(curses_menu, &maxy, &maxx);
+ set_top_row(curses_menu, *last_top_row);
+ toprow = top_row(curses_menu);
+ if (selected_index >= toprow && selected_index < toprow+maxy) {
+ /* we can only move the selected item. no need to scroll */
+ set_current_item(curses_menu,
+ curses_menu_items[selected_index]);
+ } else {
+ toprow = max(selected_index-maxy/2, 0);
+ if (toprow >= item_count(curses_menu)-maxy)
+ toprow = item_count(curses_menu)-mwin_max_lines;
+ set_top_row(curses_menu, toprow);
+ set_current_item(curses_menu,
+ curses_menu_items[selected_index]);
+ }
+ *last_top_row = toprow;
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+/* this function assumes reset_menu has been called before */
+static void show_menu(const char *prompt, const char *instructions,
+ int selected_index, int *last_top_row)
+{
+ int maxx, maxy;
+ WINDOW *menu_window;
+
+ current_instructions = instructions;
+
+ clear();
+ wattrset(main_window, attributes[NORMAL]);
+ print_in_middle(stdscr, 1, 0, COLS,
+ menu_backtitle,
+ attributes[MAIN_HEADING]);
+
+ wattrset(main_window, attributes[MAIN_MENU_BOX]);
+ box(main_window, 0, 0);
+ wattrset(main_window, attributes[MAIN_MENU_HEADING]);
+ mvwprintw(main_window, 0, 3, " %s ", prompt);
+ wattrset(main_window, attributes[NORMAL]);
+
+ set_menu_items(curses_menu, curses_menu_items);
+
+ /* position the menu at the middle of the screen */
+ scale_menu(curses_menu, &maxy, &maxx);
+ maxx = min(maxx, mwin_max_cols-2);
+ maxy = mwin_max_lines-2;
+ menu_window = derwin(main_window,
+ maxy,
+ maxx,
+ 2,
+ (mwin_max_cols-maxx)/2);
+ keypad(menu_window, TRUE);
+ set_menu_win(curses_menu, menu_window);
+ set_menu_sub(curses_menu, menu_window);
+
+ /* must reassert this after changing items, otherwise returns to a
+ * default of 16
+ */
+ set_menu_format(curses_menu, maxy, 1);
+ center_item(selected_index, last_top_row);
+ set_menu_format(curses_menu, maxy, 1);
+
+ print_function_line();
+
+ /* Post the menu */
+ post_menu(curses_menu);
+ refresh_all_windows(main_window);
+}
+
+
+static void conf(struct menu *menu)
+{
+ char pattern[256];
+ struct menu *submenu = 0;
+ const char *prompt = menu_get_prompt(menu);
+ struct symbol *sym;
+ struct menu *active_menu = NULL;
+ int res;
+ int current_index = 0;
+ int last_top_row = 0;
+
+ bzero(pattern, sizeof(pattern));
+
+ while (!global_exit) {
+ reset_menu();
+ current_menu = menu;
+ build_conf(menu);
+ if (!child_count)
+ break;
+
+ show_menu(prompt ? _(prompt) : _("Main Menu"),
+ _(menu_instructions),
+ current_index, &last_top_row);
+ keypad((menu_win(curses_menu)), TRUE);
+ while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
+ if (process_special_keys(&res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 ||
+ res == 32 || res == 'n' || res == 'y' ||
+ res == KEY_LEFT || res == KEY_RIGHT ||
+ res == 'm' || res == '/')
+ break;
+ else if (canbhot(res)) {
+ /* check for hot keys: */
+ int tmp = get_next_hot(res);
+ if (tmp != -1)
+ center_item(tmp, &last_top_row);
+ }
+ refresh_all_windows(main_window);
+ }
+
+ refresh_all_windows(main_window);
+ /* if ESC or left*/
+ if (res == 27 || (menu != &rootmenu && res == KEY_LEFT))
+ break;
+
+ /* remember location in the menu */
+ last_top_row = top_row(curses_menu);
+ current_index = curses_item_index();
+
+ if (!item_tag())
+ continue;
+
+ submenu = (struct menu *) item_data();
+ active_menu = (struct menu *)item_data();
+ if (!submenu || !menu_is_visible(submenu))
+ continue;
+ if (submenu)
+ sym = submenu->sym;
+ else
+ sym = NULL;
+
+ switch (res) {
+ case ' ':
+ if (item_is_tag('t'))
+ sym_toggle_tristate_value(sym);
+ else if (item_is_tag('m'))
+ conf(submenu);
+ break;
+ case KEY_RIGHT:
+ case 10: /* ENTER WAS PRESSED */
+ switch (item_tag()) {
+ case 'm':
+ if (single_menu_mode)
+ submenu->data =
+ (void *) (long) !submenu->data;
+ else
+ conf(submenu);
+ break;
+ case 't':
+ if (sym_is_choice(sym) &&
+ sym_get_tristate_value(sym) == yes)
+ conf_choice(submenu);
+ else if (submenu->prompt &&
+ submenu->prompt->type == P_MENU)
+ conf(submenu);
+ else if (res == 10)
+ sym_toggle_tristate_value(sym);
+ break;
+ case 's':
+ conf_string(submenu);
+ break;
+ }
+ break;
+ case 'y':
+ if (item_is_tag('t')) {
+ if (sym_set_tristate_value(sym, yes))
+ break;
+ if (sym_set_tristate_value(sym, mod))
+ btn_dialog(main_window, setmod_text, 0);
+ }
+ break;
+ case 'n':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, no);
+ break;
+ case 'm':
+ if (item_is_tag('t'))
+ sym_set_tristate_value(sym, mod);
+ break;
+ case '/':
+ search_conf();
+ break;
+ }
+ }
+}
+
+static void show_help(struct menu *menu)
+{
+ struct gstr help = str_new();
+
+ if (menu && menu->sym && menu_has_help(menu)) {
+ if (menu->sym->name) {
+ str_printf(&help, "CONFIG_%s:\n\n", menu->sym->name);
+ str_append(&help, _(menu_get_help(menu)));
+ str_append(&help, "\n");
+ get_symbol_str(&help, menu->sym);
+ }
+ } else {
+ str_append(&help, nohelp_text);
+ }
+ show_scroll_win(main_window, _(menu_get_prompt(menu)), str_get(&help));
+ str_free(&help);
+}
+
+static void conf_choice(struct menu *menu)
+{
+ const char *prompt = _(menu_get_prompt(menu));
+ struct menu *child = 0;
+ struct symbol *active;
+ int selected_index = 0;
+ int last_top_row = 0;
+ int res, i = 0;
+
+ active = sym_get_choice_value(menu->sym);
+ /* this is mostly duplicated from the conf() function. */
+ while (!global_exit) {
+ reset_menu();
+
+ for (i = 0, child = menu->list; child; child = child->next) {
+ if (!show_all_items && !menu_is_visible(child))
+ continue;
+
+ if (child->sym == sym_get_choice_value(menu->sym))
+ item_make(child, ':', "<X> %s",
+ _(menu_get_prompt(child)));
+ else
+ item_make(child, ':', " %s",
+ _(menu_get_prompt(child)));
+ if (child->sym == active){
+ last_top_row = top_row(curses_menu);
+ selected_index = i;
+ }
+ i++;
+ }
+ show_menu(prompt ? _(prompt) : _("Choice Menu"),
+ _(radiolist_instructions),
+ selected_index,
+ &last_top_row);
+ while (!global_exit && (res = wgetch(menu_win(curses_menu)))) {
+ if (process_special_keys(
+ &res,
+ (struct menu *) item_data()))
+ break;
+ switch (res) {
+ case KEY_DOWN:
+ menu_driver(curses_menu, REQ_DOWN_ITEM);
+ break;
+ case KEY_UP:
+ menu_driver(curses_menu, REQ_UP_ITEM);
+ break;
+ case KEY_NPAGE:
+ menu_driver(curses_menu, REQ_SCR_DPAGE);
+ break;
+ case KEY_PPAGE:
+ menu_driver(curses_menu, REQ_SCR_UPAGE);
+ break;
+ case KEY_HOME:
+ menu_driver(curses_menu, REQ_FIRST_ITEM);
+ break;
+ case KEY_END:
+ menu_driver(curses_menu, REQ_LAST_ITEM);
+ break;
+ case 'h':
+ case '?':
+ show_help((struct menu *) item_data());
+ break;
+ }
+ if (res == 10 || res == 27 || res == ' ' ||
+ res == KEY_LEFT)
+ break;
+ else if (canbhot(res)) {
+ /* check for hot keys: */
+ int tmp = get_next_hot(res);
+ if (tmp != -1)
+ center_item(tmp, &last_top_row);
+ }
+ refresh_all_windows(main_window);
+ }
+ /* if ESC or left */
+ if (res == 27 || res == KEY_LEFT)
+ break;
+
+ child = item_data();
+ if (!child || !menu_is_visible(child))
+ continue;
+ switch (res) {
+ case ' ':
+ case 10:
+ case KEY_RIGHT:
+ sym_set_tristate_value(child->sym, yes);
+ return;
+ case 'h':
+ case '?':
+ show_help(child);
+ active = child->sym;
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_string(struct menu *menu)
+{
+ const char *prompt = menu_get_prompt(menu);
+ char dialog_input_result[256];
+
+ while (1) {
+ int res;
+ const char *heading;
+
+ switch (sym_get_type(menu->sym)) {
+ case S_INT:
+ heading = _(inputbox_instructions_int);
+ break;
+ case S_HEX:
+ heading = _(inputbox_instructions_hex);
+ break;
+ case S_STRING:
+ heading = _(inputbox_instructions_string);
+ break;
+ default:
+ heading = _("Internal nconf error!");
+ }
+ res = dialog_inputbox(main_window,
+ prompt ? _(prompt) : _("Main Menu"),
+ heading,
+ sym_get_string_value(menu->sym),
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (sym_set_string_value(menu->sym,
+ dialog_input_result))
+ return;
+ btn_dialog(main_window,
+ _("You have made an invalid entry."), 0);
+ break;
+ case 1:
+ show_help(menu);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_load(void)
+{
+ char dialog_input_result[256];
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, load_config_text,
+ filename,
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ if (!conf_read(dialog_input_result)) {
+ set_config_filename(dialog_input_result);
+ sym_set_change_count(1);
+ return;
+ }
+ btn_dialog(main_window, _("File does not exist!"), 0);
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Load Alternate Configuration"),
+ load_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+static void conf_save(void)
+{
+ char dialog_input_result[256];
+ while (1) {
+ int res;
+ res = dialog_inputbox(main_window,
+ NULL, save_config_text,
+ filename,
+ dialog_input_result,
+ sizeof(dialog_input_result));
+ switch (res) {
+ case 0:
+ if (!dialog_input_result[0])
+ return;
+ supress_stdout(0);
+ res = conf_write(dialog_input_result);
+ supress_stdout(1);
+ if (!res) {
+ char buf[1024];
+ sprintf(buf, "%s %s",
+ _("configuration file saved to: "),
+ dialog_input_result);
+ btn_dialog(main_window,
+ buf, 1, "<OK>");
+ set_config_filename(dialog_input_result);
+ return;
+ }
+ btn_dialog(main_window, _("Can't create file! "
+ "Probably a nonexistent directory."),
+ 1, "<OK>");
+ break;
+ case 1:
+ show_scroll_win(main_window,
+ _("Save Alternate Configuration"),
+ save_config_help);
+ break;
+ case KEY_EXIT:
+ return;
+ }
+ }
+}
+
+void setup_windows(void)
+{
+ if (main_window != NULL)
+ delwin(main_window);
+
+ /* set up the menu and menu window */
+ main_window = newwin(LINES-2, COLS-2, 2, 1);
+ keypad(main_window, TRUE);
+ mwin_max_lines = LINES-6;
+ mwin_max_cols = COLS-6;
+
+ /* panels order is from bottom to top */
+ new_panel(main_window);
+}
+
+int main(int ac, char **av)
+{
+ char *mode;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ conf_parse(av[1]);
+ conf_read(NULL);
+
+ mode = getenv("NCONFIG_MODE");
+ if (mode) {
+ if (!strcasecmp(mode, "single_menu"))
+ single_menu_mode = 1;
+ }
+
+ /* Initialize curses */
+ initscr();
+ /* set color theme */
+ set_colors();
+
+ cbreak();
+ noecho();
+ keypad(stdscr, TRUE);
+ curs_set(0);
+
+ if (COLS < 75 || LINES < 20) {
+ endwin();
+ printf("Your terminal should have at "
+ "least 20 lines and 75 columns\n");
+ return 1;
+ }
+
+ notimeout(stdscr, FALSE);
+ ESCDELAY = 1;
+
+ /* set btns menu */
+ curses_menu = new_menu(curses_menu_items);
+ menu_opts_off(curses_menu, O_SHOWDESC);
+ menu_opts_off(curses_menu, O_SHOWMATCH);
+ menu_opts_on(curses_menu, O_ONEVALUE);
+ menu_opts_on(curses_menu, O_NONCYCLIC);
+ set_menu_mark(curses_menu, " ");
+ set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]);
+ set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]);
+ set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]);
+
+ set_config_filename(conf_get_configname());
+ setup_windows();
+
+ /* check for KEY_FUNC(1) */
+ if (has_key(KEY_F(1)) == FALSE) {
+ show_scroll_win(main_window,
+ _("Instructions"),
+ _(menu_no_f_instructions));
+ }
+
+
+
+ /* do the work */
+ while (!global_exit) {
+ conf(&rootmenu);
+ if (!global_exit && do_exit() == 0)
+ break;
+ }
+ /* ok, we are done */
+ unpost_menu(curses_menu);
+ free_menu(curses_menu);
+ delwin(main_window);
+ clear();
+ refresh();
+ endwin();
+ return 0;
+}
+
diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c
new file mode 100644
index 000000000000..115edb437fb1
--- /dev/null
+++ b/scripts/kconfig/nconf.gui.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+#include "nconf.h"
+
+/* a list of all the different widgets we use */
+attributes_t attributes[ATTR_MAX+1] = {0};
+
+/* available colors:
+ COLOR_BLACK 0
+ COLOR_RED 1
+ COLOR_GREEN 2
+ COLOR_YELLOW 3
+ COLOR_BLUE 4
+ COLOR_MAGENTA 5
+ COLOR_CYAN 6
+ COLOR_WHITE 7
+ */
+static void set_normal_colors(void)
+{
+ init_pair(NORMAL, -1, -1);
+ init_pair(MAIN_HEADING, COLOR_MAGENTA, -1);
+
+ /* FORE is for the selected item */
+ init_pair(MAIN_MENU_FORE, -1, -1);
+ /* BACK for all the rest */
+ init_pair(MAIN_MENU_BACK, -1, -1);
+ init_pair(MAIN_MENU_GREY, -1, -1);
+ init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1);
+ init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1);
+
+ init_pair(SCROLLWIN_TEXT, -1, -1);
+ init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1);
+ init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1);
+
+ init_pair(DIALOG_TEXT, -1, -1);
+ init_pair(DIALOG_BOX, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1);
+ init_pair(DIALOG_MENU_FORE, COLOR_RED, -1);
+
+ init_pair(INPUT_BOX, COLOR_YELLOW, -1);
+ init_pair(INPUT_HEADING, COLOR_GREEN, -1);
+ init_pair(INPUT_TEXT, -1, -1);
+ init_pair(INPUT_FIELD, -1, -1);
+
+ init_pair(FUNCTION_HIGHLIGHT, -1, -1);
+ init_pair(FUNCTION_TEXT, COLOR_BLUE, -1);
+}
+
+/* available attributes:
+ A_NORMAL Normal display (no highlight)
+ A_STANDOUT Best highlighting mode of the terminal.
+ A_UNDERLINE Underlining
+ A_REVERSE Reverse video
+ A_BLINK Blinking
+ A_DIM Half bright
+ A_BOLD Extra bright or bold
+ A_PROTECT Protected mode
+ A_INVIS Invisible or blank mode
+ A_ALTCHARSET Alternate character set
+ A_CHARTEXT Bit-mask to extract a character
+ COLOR_PAIR(n) Color-pair number n
+ */
+static void normal_color_theme(void)
+{
+ /* automatically add color... */
+#define mkattr(name, attr) do { \
+attributes[name] = attr | COLOR_PAIR(name); } while (0)
+ mkattr(NORMAL, NORMAL);
+ mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattr(MAIN_MENU_FORE, A_REVERSE);
+ mkattr(MAIN_MENU_BACK, A_NORMAL);
+ mkattr(MAIN_MENU_GREY, A_NORMAL);
+ mkattr(MAIN_MENU_HEADING, A_BOLD);
+ mkattr(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattr(SCROLLWIN_TEXT, A_NORMAL);
+ mkattr(SCROLLWIN_HEADING, A_BOLD);
+ mkattr(SCROLLWIN_BOX, A_BOLD);
+
+ mkattr(DIALOG_TEXT, A_BOLD);
+ mkattr(DIALOG_BOX, A_BOLD);
+ mkattr(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattr(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattr(INPUT_BOX, A_NORMAL);
+ mkattr(INPUT_HEADING, A_BOLD);
+ mkattr(INPUT_TEXT, A_NORMAL);
+ mkattr(INPUT_FIELD, A_UNDERLINE);
+
+ mkattr(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattr(FUNCTION_TEXT, A_REVERSE);
+}
+
+static void no_colors_theme(void)
+{
+ /* automatically add highlight, no color */
+#define mkattrn(name, attr) { attributes[name] = attr; }
+
+ mkattrn(NORMAL, NORMAL);
+ mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE);
+
+ mkattrn(MAIN_MENU_FORE, A_STANDOUT);
+ mkattrn(MAIN_MENU_BACK, A_NORMAL);
+ mkattrn(MAIN_MENU_GREY, A_NORMAL);
+ mkattrn(MAIN_MENU_HEADING, A_BOLD);
+ mkattrn(MAIN_MENU_BOX, A_NORMAL);
+
+ mkattrn(SCROLLWIN_TEXT, A_NORMAL);
+ mkattrn(SCROLLWIN_HEADING, A_BOLD);
+ mkattrn(SCROLLWIN_BOX, A_BOLD);
+
+ mkattrn(DIALOG_TEXT, A_NORMAL);
+ mkattrn(DIALOG_BOX, A_BOLD);
+ mkattrn(DIALOG_MENU_FORE, A_STANDOUT);
+ mkattrn(DIALOG_MENU_BACK, A_NORMAL);
+
+ mkattrn(INPUT_BOX, A_BOLD);
+ mkattrn(INPUT_HEADING, A_BOLD);
+ mkattrn(INPUT_TEXT, A_NORMAL);
+ mkattrn(INPUT_FIELD, A_UNDERLINE);
+
+ mkattrn(FUNCTION_HIGHLIGHT, A_BOLD);
+ mkattrn(FUNCTION_TEXT, A_REVERSE);
+}
+
+void set_colors()
+{
+ start_color();
+ use_default_colors();
+ set_normal_colors();
+ if (has_colors()) {
+ normal_color_theme();
+ } else {
+ /* give deafults */
+ no_colors_theme();
+ }
+}
+
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color)
+{ int length, x, y;
+ float temp;
+
+
+ if (win == NULL)
+ win = stdscr;
+ getyx(win, y, x);
+ if (startx != 0)
+ x = startx;
+ if (starty != 0)
+ y = starty;
+ if (width == 0)
+ width = 80;
+
+ length = strlen(string);
+ temp = (width - length) / 2;
+ x = startx + (int)temp;
+ wattrset(win, color);
+ mvwprintw(win, y, x, "%s", string);
+ refresh();
+}
+
+int get_line_no(const char *text)
+{
+ int i;
+ int total = 1;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0'; i++)
+ if (text[i] == '\n')
+ total++;
+ return total;
+}
+
+const char *get_line(const char *text, int line_no)
+{
+ int i;
+ int lines = 0;
+
+ if (!text)
+ return 0;
+
+ for (i = 0; text[i] != '\0' && lines < line_no; i++)
+ if (text[i] == '\n')
+ lines++;
+ return text+i;
+}
+
+int get_line_length(const char *line)
+{
+ int res = 0;
+ while (*line != '\0' && *line != '\n') {
+ line++;
+ res++;
+ }
+ return res;
+}
+
+/* print all lines to the window. */
+void fill_window(WINDOW *win, const char *text)
+{
+ int x, y;
+ int total_lines = get_line_no(text);
+ int i;
+
+ getmaxyx(win, y, x);
+ /* do not go over end of line */
+ total_lines = min(total_lines, y);
+ for (i = 0; i < total_lines; i++) {
+ char tmp[x+10];
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ strncpy(tmp, line, min(len, x));
+ tmp[len] = '\0';
+ mvwprintw(win, i, 0, tmp);
+ }
+}
+
+/* get the message, and buttons.
+ * each button must be a char*
+ * return the selected button
+ *
+ * this dialog is used for 2 different things:
+ * 1) show a text box, no buttons.
+ * 2) show a dialog, with horizontal buttons
+ */
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...)
+{
+ va_list ap;
+ char *btn;
+ int btns_width = 0;
+ int msg_lines = 0;
+ int msg_width = 0;
+ int total_width;
+ int win_rows = 0;
+ WINDOW *win;
+ WINDOW *msg_win;
+ WINDOW *menu_win;
+ MENU *menu;
+ ITEM *btns[btn_num+1];
+ int i, x, y;
+ int res = -1;
+
+
+ va_start(ap, btn_num);
+ for (i = 0; i < btn_num; i++) {
+ btn = va_arg(ap, char *);
+ btns[i] = new_item(btn, "");
+ btns_width += strlen(btn)+1;
+ }
+ va_end(ap);
+ btns[btn_num] = NULL;
+
+ /* find the widest line of msg: */
+ msg_lines = get_line_no(msg);
+ for (i = 0; i < msg_lines; i++) {
+ const char *line = get_line(msg, i);
+ int len = get_line_length(line);
+ if (msg_width < len)
+ msg_width = len;
+ }
+
+ total_width = max(msg_width, btns_width);
+ /* place dialog in middle of screen */
+ y = (LINES-(msg_lines+4))/2;
+ x = (COLS-(total_width+4))/2;
+
+
+ /* create the windows */
+ if (btn_num > 0)
+ win_rows = msg_lines+4;
+ else
+ win_rows = msg_lines+2;
+
+ win = newwin(win_rows, total_width+4, y, x);
+ keypad(win, TRUE);
+ menu_win = derwin(win, 1, btns_width, win_rows-2,
+ 1+(total_width+2-btns_width)/2);
+ menu = new_menu(btns);
+ msg_win = derwin(win, win_rows-2, msg_width, 1,
+ 1+(total_width+2-msg_width)/2);
+
+ set_menu_fore(menu, attributes[DIALOG_MENU_FORE]);
+ set_menu_back(menu, attributes[DIALOG_MENU_BACK]);
+
+ wattrset(win, attributes[DIALOG_BOX]);
+ box(win, 0, 0);
+
+ /* print message */
+ wattrset(msg_win, attributes[DIALOG_TEXT]);
+ fill_window(msg_win, msg);
+
+ set_menu_win(menu, win);
+ set_menu_sub(menu, menu_win);
+ set_menu_format(menu, 1, btn_num);
+ menu_opts_off(menu, O_SHOWDESC);
+ menu_opts_off(menu, O_SHOWMATCH);
+ menu_opts_on(menu, O_ONEVALUE);
+ menu_opts_on(menu, O_NONCYCLIC);
+ set_menu_mark(menu, "");
+ post_menu(menu);
+
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(win))) {
+ switch (res) {
+ case KEY_LEFT:
+ menu_driver(menu, REQ_LEFT_ITEM);
+ break;
+ case KEY_RIGHT:
+ menu_driver(menu, REQ_RIGHT_ITEM);
+ break;
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case ' ':
+ case KEY_F(F_BACK):
+ case KEY_F(F_EXIT):
+ break;
+ }
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10 || res == ' ') {
+ res = item_index(current_item(menu));
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ }
+ }
+
+ unpost_menu(menu);
+ free_menu(menu);
+ for (i = 0; i < btn_num; i++)
+ free_item(btns[i]);
+
+ delwin(win);
+ return res;
+}
+
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char *result, int result_len)
+{
+ int prompt_lines = 0;
+ int prompt_width = 0;
+ WINDOW *win;
+ WINDOW *prompt_win;
+ WINDOW *form_win;
+ PANEL *panel;
+ int i, x, y;
+ int res = -1;
+ int cursor_position = strlen(init);
+
+
+ /* find the widest line of msg: */
+ prompt_lines = get_line_no(prompt);
+ for (i = 0; i < prompt_lines; i++) {
+ const char *line = get_line(prompt, i);
+ int len = get_line_length(line);
+ prompt_width = max(prompt_width, len);
+ }
+
+ if (title)
+ prompt_width = max(prompt_width, strlen(title));
+
+ /* place dialog in middle of screen */
+ y = (LINES-(prompt_lines+4))/2;
+ x = (COLS-(prompt_width+4))/2;
+
+ strncpy(result, init, result_len);
+
+ /* create the windows */
+ win = newwin(prompt_lines+6, prompt_width+7, y, x);
+ prompt_win = derwin(win, prompt_lines+1, prompt_width, 2, 2);
+ form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2);
+ keypad(form_win, TRUE);
+
+ wattrset(form_win, attributes[INPUT_FIELD]);
+
+ wattrset(win, attributes[INPUT_BOX]);
+ box(win, 0, 0);
+ wattrset(win, attributes[INPUT_HEADING]);
+ if (title)
+ mvwprintw(win, 0, 3, "%s", title);
+
+ /* print message */
+ wattrset(prompt_win, attributes[INPUT_TEXT]);
+ fill_window(prompt_win, prompt);
+
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ mvwprintw(form_win, 0, 0, "%s", result);
+
+ /* create panels */
+ panel = new_panel(win);
+
+ /* show the cursor */
+ curs_set(1);
+
+ touchwin(win);
+ refresh_all_windows(main_window);
+ while ((res = wgetch(form_win))) {
+ int len = strlen(result);
+ switch (res) {
+ case 10: /* ENTER */
+ case 27: /* ESCAPE */
+ case KEY_F(F_HELP):
+ case KEY_F(F_EXIT):
+ case KEY_F(F_BACK):
+ break;
+ case 127:
+ case KEY_BACKSPACE:
+ if (cursor_position > 0) {
+ memmove(&result[cursor_position-1],
+ &result[cursor_position],
+ len-cursor_position+1);
+ cursor_position--;
+ }
+ break;
+ case KEY_DC:
+ if (cursor_position >= 0 && cursor_position < len) {
+ memmove(&result[cursor_position],
+ &result[cursor_position+1],
+ len-cursor_position+1);
+ }
+ break;
+ case KEY_UP:
+ case KEY_RIGHT:
+ if (cursor_position < len &&
+ cursor_position < min(result_len, prompt_width))
+ cursor_position++;
+ break;
+ case KEY_DOWN:
+ case KEY_LEFT:
+ if (cursor_position > 0)
+ cursor_position--;
+ break;
+ default:
+ if ((isgraph(res) || isspace(res)) &&
+ len-2 < result_len) {
+ /* insert the char at the proper position */
+ memmove(&result[cursor_position+1],
+ &result[cursor_position],
+ len+1);
+ result[cursor_position] = res;
+ cursor_position++;
+ } else {
+ mvprintw(0, 0, "unknow key: %d\n", res);
+ }
+ break;
+ }
+ wmove(form_win, 0, 0);
+ wclrtoeol(form_win);
+ mvwprintw(form_win, 0, 0, "%*s", prompt_width, " ");
+ mvwprintw(form_win, 0, 0, "%s", result);
+ wmove(form_win, 0, cursor_position);
+ touchwin(win);
+ refresh_all_windows(main_window);
+
+ if (res == 10) {
+ res = 0;
+ break;
+ } else if (res == 27 || res == KEY_F(F_BACK) ||
+ res == KEY_F(F_EXIT)) {
+ res = KEY_EXIT;
+ break;
+ } else if (res == KEY_F(F_HELP)) {
+ res = 1;
+ break;
+ }
+ }
+
+ /* hide the cursor */
+ curs_set(0);
+ del_panel(panel);
+ delwin(prompt_win);
+ delwin(form_win);
+ delwin(win);
+ return res;
+}
+
+/* refresh all windows in the correct order */
+void refresh_all_windows(WINDOW *main_window)
+{
+ update_panels();
+ touchwin(main_window);
+ refresh();
+}
+
+/* layman's scrollable window... */
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text)
+{
+ int res;
+ int total_lines = get_line_no(text);
+ int x, y;
+ int start_x = 0, start_y = 0;
+ int text_lines = 0, text_cols = 0;
+ int total_cols = 0;
+ int win_cols = 0;
+ int win_lines = 0;
+ int i = 0;
+ WINDOW *win;
+ WINDOW *pad;
+ PANEL *panel;
+
+ /* find the widest line of msg: */
+ total_lines = get_line_no(text);
+ for (i = 0; i < total_lines; i++) {
+ const char *line = get_line(text, i);
+ int len = get_line_length(line);
+ total_cols = max(total_cols, len+2);
+ }
+
+ /* create the pad */
+ pad = newpad(total_lines+10, total_cols+10);
+ wattrset(pad, attributes[SCROLLWIN_TEXT]);
+ fill_window(pad, text);
+
+ win_lines = min(total_lines+4, LINES-2);
+ win_cols = min(total_cols+2, COLS-2);
+ text_lines = max(win_lines-4, 0);
+ text_cols = max(win_cols-2, 0);
+
+ /* place window in middle of screen */
+ y = (LINES-win_lines)/2;
+ x = (COLS-win_cols)/2;
+
+ win = newwin(win_lines, win_cols, y, x);
+ keypad(win, TRUE);
+ /* show the help in the help window, and show the help panel */
+ wattrset(win, attributes[SCROLLWIN_BOX]);
+ box(win, 0, 0);
+ wattrset(win, attributes[SCROLLWIN_HEADING]);
+ mvwprintw(win, 0, 3, " %s ", title);
+ panel = new_panel(win);
+
+ /* handle scrolling */
+ do {
+
+ copywin(pad, win, start_y, start_x, 2, 2, text_lines,
+ text_cols, 0);
+ print_in_middle(win,
+ text_lines+2,
+ 0,
+ text_cols,
+ "<OK>",
+ attributes[DIALOG_MENU_FORE]);
+ wrefresh(win);
+
+ res = wgetch(win);
+ switch (res) {
+ case KEY_NPAGE:
+ case ' ':
+ start_y += text_lines-2;
+ break;
+ case KEY_PPAGE:
+ start_y -= text_lines+2;
+ break;
+ case KEY_HOME:
+ start_y = 0;
+ break;
+ case KEY_END:
+ start_y = total_lines-text_lines;
+ break;
+ case KEY_DOWN:
+ case 'j':
+ start_y++;
+ break;
+ case KEY_UP:
+ case 'k':
+ start_y--;
+ break;
+ case KEY_LEFT:
+ case 'h':
+ start_x--;
+ break;
+ case KEY_RIGHT:
+ case 'l':
+ start_x++;
+ break;
+ }
+ if (res == 10 || res == 27 || res == 'q'
+ || res == KEY_F(F_BACK) || res == KEY_F(F_EXIT)) {
+ break;
+ }
+ if (start_y < 0)
+ start_y = 0;
+ if (start_y >= total_lines-text_lines)
+ start_y = total_lines-text_lines;
+ if (start_x < 0)
+ start_x = 0;
+ if (start_x >= total_cols-text_cols)
+ start_x = total_cols-text_cols;
+ } while (res);
+
+ del_panel(panel);
+ delwin(win);
+ refresh_all_windows(main_window);
+}
diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h
new file mode 100644
index 000000000000..fb4296666004
--- /dev/null
+++ b/scripts/kconfig/nconf.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008 Nir Tzachar <nir.tzachar@gmail.com?
+ * Released under the terms of the GNU GPL v2.0.
+ *
+ * Derived from menuconfig.
+ *
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <locale.h>
+#include <curses.h>
+#include <menu.h>
+#include <panel.h>
+#include <form.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "ncurses.h"
+
+#define max(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a > _b ? _a : _b; })
+
+#define min(a, b) ({\
+ typeof(a) _a = a;\
+ typeof(b) _b = b;\
+ _a < _b ? _a : _b; })
+
+typedef enum {
+ NORMAL = 1,
+ MAIN_HEADING,
+ MAIN_MENU_BOX,
+ MAIN_MENU_FORE,
+ MAIN_MENU_BACK,
+ MAIN_MENU_GREY,
+ MAIN_MENU_HEADING,
+ SCROLLWIN_TEXT,
+ SCROLLWIN_HEADING,
+ SCROLLWIN_BOX,
+ DIALOG_TEXT,
+ DIALOG_MENU_FORE,
+ DIALOG_MENU_BACK,
+ DIALOG_BOX,
+ INPUT_BOX,
+ INPUT_HEADING,
+ INPUT_TEXT,
+ INPUT_FIELD,
+ FUNCTION_TEXT,
+ FUNCTION_HIGHLIGHT,
+ ATTR_MAX
+} attributes_t;
+extern attributes_t attributes[];
+
+typedef enum {
+ F_HELP = 1,
+ F_SYMBOL = 2,
+ F_INSTS = 3,
+ F_CONF = 4,
+ F_BACK = 5,
+ F_SAVE = 6,
+ F_LOAD = 7,
+ F_EXIT = 8
+} function_key;
+
+void set_colors(void);
+
+/* this changes the windows attributes !!! */
+void print_in_middle(WINDOW *win,
+ int starty,
+ int startx,
+ int width,
+ const char *string,
+ chtype color);
+int get_line_length(const char *line);
+int get_line_no(const char *text);
+const char *get_line(const char *text, int line_no);
+void fill_window(WINDOW *win, const char *text);
+int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...);
+int dialog_inputbox(WINDOW *main_window,
+ const char *title, const char *prompt,
+ const char *init, char *result, int result_len);
+void refresh_all_windows(WINDOW *main_window);
+void show_scroll_win(WINDOW *main_window,
+ const char *title,
+ const char *text);
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index 00c51507cfcc..820df2d1217b 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -58,11 +58,10 @@ QValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
{
QValueList<int> result;
QStringList entryList = readListEntry(key, ok);
- if (ok) {
- QStringList::Iterator it;
- for (it = entryList.begin(); it != entryList.end(); ++it)
- result.push_back((*it).toInt());
- }
+ QStringList::Iterator it;
+
+ for (it = entryList.begin(); it != entryList.end(); ++it)
+ result.push_back((*it).toInt());
return result;
}
@@ -149,7 +148,7 @@ void ConfigItem::updateMenu(void)
case S_TRISTATE:
char ch;
- if (!sym_is_changable(sym) && !list->showAll) {
+ if (!sym_is_changable(sym) && list->optMode == normalOpt) {
setPixmap(promptColIdx, 0);
setText(noColIdx, QString::null);
setText(modColIdx, QString::null);
@@ -320,7 +319,7 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
- showAll(false), showName(false), showRange(false), showData(false),
+ showName(false), showRange(false), showData(false), optMode(normalOpt),
rootEntry(0), headerPopup(0)
{
int i;
@@ -337,10 +336,10 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
if (name) {
configSettings->beginGroup(name);
- showAll = configSettings->readBoolEntry("/showAll", false);
showName = configSettings->readBoolEntry("/showName", false);
showRange = configSettings->readBoolEntry("/showRange", false);
showData = configSettings->readBoolEntry("/showData", false);
+ optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
configSettings->endGroup();
connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
}
@@ -352,6 +351,17 @@ ConfigList::ConfigList(ConfigView* p, const char *name)
reinit();
}
+bool ConfigList::menuSkip(struct menu *menu)
+{
+ if (optMode == normalOpt && menu_is_visible(menu))
+ return false;
+ if (optMode == promptOpt && menu_has_prompt(menu))
+ return false;
+ if (optMode == allOpt)
+ return false;
+ return true;
+}
+
void ConfigList::reinit(void)
{
removeColumn(dataColIdx);
@@ -380,7 +390,7 @@ void ConfigList::saveSettings(void)
configSettings->writeEntry("/showName", showName);
configSettings->writeEntry("/showRange", showRange);
configSettings->writeEntry("/showData", showData);
- configSettings->writeEntry("/showAll", showAll);
+ configSettings->writeEntry("/optionMode", (int)optMode);
configSettings->endGroup();
}
}
@@ -606,7 +616,7 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
}
visible = menu_is_visible(child);
- if (showAll || visible) {
+ if (!menuSkip(child)) {
if (!child->sym && !child->list && !child->prompt)
continue;
if (!item || item->menu != child)
@@ -835,7 +845,10 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
e->ignore();
}
-ConfigView* ConfigView::viewList;
+ConfigView*ConfigView::viewList;
+QAction *ConfigView::showNormalAction;
+QAction *ConfigView::showAllAction;
+QAction *ConfigView::showPromptAction;
ConfigView::ConfigView(QWidget* parent, const char *name)
: Parent(parent, name)
@@ -860,13 +873,16 @@ ConfigView::~ConfigView(void)
}
}
-void ConfigView::setShowAll(bool b)
+void ConfigView::setOptionMode(QAction *act)
{
- if (list->showAll != b) {
- list->showAll = b;
- list->updateListAll();
- emit showAllChanged(b);
- }
+ if (act == showNormalAction)
+ list->optMode = normalOpt;
+ else if (act == showAllAction)
+ list->optMode = allOpt;
+ else
+ list->optMode = promptOpt;
+
+ list->updateListAll();
}
void ConfigView::setShowName(bool b)
@@ -964,34 +980,6 @@ void ConfigInfoView::setInfo(struct menu *m)
menuInfo();
}
-void ConfigInfoView::setSource(const QString& name)
-{
- const char *p = name.latin1();
-
- menu = NULL;
- sym = NULL;
-
- switch (p[0]) {
- case 'm':
- struct menu *m;
-
- if (sscanf(p, "m%p", &m) == 1 && menu != m) {
- menu = m;
- menuInfo();
- emit menuSelected(menu);
- }
- break;
- case 's':
- struct symbol *s;
-
- if (sscanf(p, "s%p", &s) == 1 && sym != s) {
- sym = s;
- symbolInfo();
- }
- break;
- }
-}
-
void ConfigInfoView::symbolInfo(void)
{
QString str;
@@ -1349,11 +1337,24 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
showDataAction->setOn(configList->showData);
- QAction *showAllAction = new QAction(NULL, _("Show All Options"), 0, this);
- showAllAction->setToggleAction(TRUE);
- connect(showAllAction, SIGNAL(toggled(bool)), configView, SLOT(setShowAll(bool)));
- connect(showAllAction, SIGNAL(toggled(bool)), menuView, SLOT(setShowAll(bool)));
- showAllAction->setOn(configList->showAll);
+
+ QActionGroup *optGroup = new QActionGroup(this);
+ optGroup->setExclusive(TRUE);
+ connect(optGroup, SIGNAL(selected(QAction *)), configView,
+ SLOT(setOptionMode(QAction *)));
+ connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+ SLOT(setOptionMode(QAction *)));
+
+ configView->showNormalAction = new QAction(NULL, _("Show Normal Options"), 0, optGroup);
+ configView->showAllAction = new QAction(NULL, _("Show All Options"), 0, optGroup);
+ configView->showPromptAction = new QAction(NULL, _("Show Prompt Options"), 0, optGroup);
+ configView->showNormalAction->setToggleAction(TRUE);
+ configView->showNormalAction->setOn(configList->optMode == normalOpt);
+ configView->showAllAction->setToggleAction(TRUE);
+ configView->showAllAction->setOn(configList->optMode == allOpt);
+ configView->showPromptAction->setToggleAction(TRUE);
+ configView->showPromptAction->setOn(configList->optMode == promptOpt);
+
QAction *showDebugAction = new QAction(NULL, _("Show Debug Info"), 0, this);
showDebugAction->setToggleAction(TRUE);
connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
@@ -1396,7 +1397,8 @@ ConfigMainWindow::ConfigMainWindow(void)
showRangeAction->addTo(optionMenu);
showDataAction->addTo(optionMenu);
optionMenu->insertSeparator();
- showAllAction->addTo(optionMenu);
+ optGroup->addTo(optionMenu);
+ optionMenu->insertSeparator();
showDebugAction->addTo(optionMenu);
// create help menu
@@ -1491,7 +1493,7 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
ConfigList* list = NULL;
ConfigItem* item;
- if (!menu_is_visible(menu) && !configView->showAll())
+ if (configList->menuSkip(menu))
return;
switch (configList->mode) {
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index b3b5657b6b35..636a74b23bf9 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -44,6 +44,9 @@ enum colIdx {
enum listMode {
singleMode, menuMode, symbolMode, fullMode, listMode
};
+enum optionMode {
+ normalOpt = 0, allOpt, promptOpt
+};
class ConfigList : public QListView {
Q_OBJECT
@@ -115,6 +118,8 @@ public:
void setAllOpen(bool open);
void setParentMenu(void);
+ bool menuSkip(struct menu *);
+
template <class P>
void updateMenuList(P*, struct menu*);
@@ -124,8 +129,9 @@ public:
QPixmap choiceYesPix, choiceNoPix;
QPixmap menuPix, menuInvPix, menuBackPix, voidPix;
- bool showAll, showName, showRange, showData;
+ bool showName, showRange, showData;
enum listMode mode;
+ enum optionMode optMode;
struct menu *rootEntry;
QColorGroup disabledColorGroup;
QColorGroup inactivedColorGroup;
@@ -222,17 +228,15 @@ public:
static void updateList(ConfigItem* item);
static void updateListAll(void);
- bool showAll(void) const { return list->showAll; }
bool showName(void) const { return list->showName; }
bool showRange(void) const { return list->showRange; }
bool showData(void) const { return list->showData; }
public slots:
- void setShowAll(bool);
void setShowName(bool);
void setShowRange(bool);
void setShowData(bool);
+ void setOptionMode(QAction *);
signals:
- void showAllChanged(bool);
void showNameChanged(bool);
void showRangeChanged(bool);
void showDataChanged(bool);
@@ -242,6 +246,10 @@ public:
static ConfigView* viewList;
ConfigView* nextView;
+
+ static QAction *showNormalAction;
+ static QAction *showAllAction;
+ static QAction *showPromptAction;
};
class ConfigInfoView : public QTextBrowser {
@@ -254,7 +262,6 @@ public:
public slots:
void setInfo(struct menu *menu);
void saveSettings(void);
- void setSource(const QString& name);
void setShowDebug(bool);
signals:
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 6c8fbbb66ebc..2e7a048e0cfc 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -651,12 +651,20 @@ bool sym_is_changable(struct symbol *sym)
return sym->visible > sym->rev_dep.tri;
}
+static unsigned strhash(const char *s)
+{
+ /* fnv32 hash */
+ unsigned hash = 2166136261U;
+ for (; *s; s++)
+ hash = (hash ^ *s) * 0x01000193;
+ return hash;
+}
+
struct symbol *sym_lookup(const char *name, int flags)
{
struct symbol *symbol;
- const char *ptr;
char *new_name;
- int hash = 0;
+ int hash;
if (name) {
if (name[0] && !name[1]) {
@@ -666,12 +674,11 @@ struct symbol *sym_lookup(const char *name, int flags)
case 'n': return &symbol_no;
}
}
- for (ptr = name; *ptr; ptr++)
- hash += *ptr;
- hash &= 0xff;
+ hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (!strcmp(symbol->name, name) &&
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
(flags ? symbol->flags & flags
: !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE))))
return symbol;
@@ -679,7 +686,7 @@ struct symbol *sym_lookup(const char *name, int flags)
new_name = strdup(name);
} else {
new_name = NULL;
- hash = 256;
+ hash = 0;
}
symbol = malloc(sizeof(*symbol));
@@ -697,7 +704,6 @@ struct symbol *sym_lookup(const char *name, int flags)
struct symbol *sym_find(const char *name)
{
struct symbol *symbol = NULL;
- const char *ptr;
int hash = 0;
if (!name)
@@ -710,12 +716,11 @@ struct symbol *sym_find(const char *name)
case 'n': return &symbol_no;
}
}
- for (ptr = name; *ptr; ptr++)
- hash += *ptr;
- hash &= 0xff;
+ hash = strhash(name) % SYMBOL_HASHSIZE;
for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) {
- if (!strcmp(symbol->name, name) &&
+ if (symbol->name &&
+ !strcmp(symbol->name, name) &&
!(symbol->flags & SYMBOL_CONST))
break;
}
@@ -750,6 +755,7 @@ struct symbol **sym_re_search(const char *pattern)
return NULL;
}
}
+ sym_calc_value(sym);
sym_arr[cnt++] = sym;
}
if (sym_arr)
diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c
index 25d1ec4ca28a..78b5c04e736b 100644
--- a/scripts/kconfig/util.c
+++ b/scripts/kconfig/util.c
@@ -78,6 +78,7 @@ struct gstr str_new(void)
struct gstr gs;
gs.s = malloc(sizeof(char) * 64);
gs.len = 64;
+ gs.max_width = 0;
strcpy(gs.s, "\0");
return gs;
}
@@ -88,6 +89,7 @@ struct gstr str_assign(const char *s)
struct gstr gs;
gs.s = strdup(s);
gs.len = strlen(s) + 1;
+ gs.max_width = 0;
return gs;
}
diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
index 6e9dcd59aa87..32a9eefd842c 100644
--- a/scripts/kconfig/zconf.tab.c_shipped
+++ b/scripts/kconfig/zconf.tab.c_shipped
@@ -104,7 +104,7 @@ static void zconf_error(const char *err, ...);
static void zconferror(const char *err);
static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
-struct symbol *symbol_hash[257];
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
static struct menu *current_menu, *current_entry;
@@ -2220,7 +2220,7 @@ void conf_parse(const char *name)
zconf_initscan(name);
sym_init();
- menu_init();
+ _menu_init();
modules_sym = sym_lookup(NULL, 0);
modules_sym->type = S_BOOLEAN;
modules_sym->flags |= SYMBOL_AUTO;
@@ -2336,9 +2336,9 @@ static void print_symbol(FILE *out, struct menu *menu)
struct property *prop;
if (sym_is_choice(sym))
- fprintf(out, "choice\n");
+ fprintf(out, "\nchoice\n");
else
- fprintf(out, "config %s\n", sym->name);
+ fprintf(out, "\nconfig %s\n", sym->name);
switch (sym->type) {
case S_BOOLEAN:
fputs(" boolean\n", out);
@@ -2384,6 +2384,21 @@ static void print_symbol(FILE *out, struct menu *menu)
case P_CHOICE:
fputs(" #choice value\n", out);
break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
default:
fprintf(out, " unknown prop %d!\n", prop->type);
break;
@@ -2395,7 +2410,6 @@ static void print_symbol(FILE *out, struct menu *menu)
menu->help[len] = 0;
fprintf(out, " help\n%s\n", menu->help);
}
- fputc('\n', out);
}
void zconfdump(FILE *out)
@@ -2428,7 +2442,6 @@ void zconfdump(FILE *out)
expr_fprint(prop->visible.expr, out);
fputc('\n', out);
}
- fputs("\n", out);
}
if (menu->list)
diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y
index 8c43491f8cc9..23dfd3baa7a1 100644
--- a/scripts/kconfig/zconf.y
+++ b/scripts/kconfig/zconf.y
@@ -27,7 +27,7 @@ static void zconf_error(const char *err, ...);
static void zconferror(const char *err);
static bool zconf_endtoken(struct kconf_id *id, int starttoken, int endtoken);
-struct symbol *symbol_hash[257];
+struct symbol *symbol_hash[SYMBOL_HASHSIZE];
static struct menu *current_menu, *current_entry;
@@ -475,7 +475,7 @@ void conf_parse(const char *name)
zconf_initscan(name);
sym_init();
- menu_init();
+ _menu_init();
modules_sym = sym_lookup(NULL, 0);
modules_sym->type = S_BOOLEAN;
modules_sym->flags |= SYMBOL_AUTO;
@@ -591,9 +591,9 @@ static void print_symbol(FILE *out, struct menu *menu)
struct property *prop;
if (sym_is_choice(sym))
- fprintf(out, "choice\n");
+ fprintf(out, "\nchoice\n");
else
- fprintf(out, "config %s\n", sym->name);
+ fprintf(out, "\nconfig %s\n", sym->name);
switch (sym->type) {
case S_BOOLEAN:
fputs(" boolean\n", out);
@@ -639,6 +639,21 @@ static void print_symbol(FILE *out, struct menu *menu)
case P_CHOICE:
fputs(" #choice value\n", out);
break;
+ case P_SELECT:
+ fputs( " select ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_RANGE:
+ fputs( " range ", out);
+ expr_fprint(prop->expr, out);
+ fputc('\n', out);
+ break;
+ case P_MENU:
+ fputs( " menu ", out);
+ print_quoted_string(out, prop->text);
+ fputc('\n', out);
+ break;
default:
fprintf(out, " unknown prop %d!\n", prop->type);
break;
@@ -650,7 +665,6 @@ static void print_symbol(FILE *out, struct menu *menu)
menu->help[len] = 0;
fprintf(out, " help\n%s\n", menu->help);
}
- fputc('\n', out);
}
void zconfdump(FILE *out)
@@ -683,7 +697,6 @@ void zconfdump(FILE *out)
expr_fprint(prop->visible.expr, out);
fputc('\n', out);
}
- fputs("\n", out);
}
if (menu->list)
diff --git a/scripts/markup_oops.pl b/scripts/markup_oops.pl
index e950f9cde019..827896f56501 100644
--- a/scripts/markup_oops.pl
+++ b/scripts/markup_oops.pl
@@ -2,6 +2,7 @@
use File::Basename;
use Math::BigInt;
+use Getopt::Long;
# Copyright 2008, Intel Corporation
#
@@ -15,6 +16,16 @@ use Math::BigInt;
# Arjan van de Ven <arjan@linux.intel.com>
+my $cross_compile = "";
+my $vmlinux_name = "";
+my $modulefile = "";
+
+# Get options
+Getopt::Long::GetOptions(
+ 'cross-compile|c=s' => \$cross_compile,
+ 'module|m=s' => \$modulefile,
+ 'help|h' => \&usage,
+) || usage ();
my $vmlinux_name = $ARGV[0];
if (!defined($vmlinux_name)) {
my $kerver = `uname -r`;
@@ -23,9 +34,8 @@ if (!defined($vmlinux_name)) {
print "No vmlinux specified, assuming $vmlinux_name\n";
}
my $filename = $vmlinux_name;
-#
-# Step 1: Parse the oops to find the EIP value
-#
+
+# Parse the oops to find the EIP value
my $target = "0";
my $function;
@@ -177,26 +187,26 @@ my $decodestart = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("
my $decodestop = Math::BigInt->from_hex("0x$target") + 8192;
if ($target eq "0") {
print "No oops found!\n";
- print "Usage: \n";
- print " dmesg | perl scripts/markup_oops.pl vmlinux\n";
- exit;
+ usage();
}
# if it's a module, we need to find the .ko file and calculate a load offset
if ($module ne "") {
- my $modulefile = `modinfo $module | grep '^filename:' | awk '{ print \$2 }'`;
- chomp($modulefile);
+ if ($modulefile eq "") {
+ $modulefile = `modinfo -F filename $module`;
+ chomp($modulefile);
+ }
$filename = $modulefile;
if ($filename eq "") {
print "Module .ko file for $module not found. Aborting\n";
exit;
}
# ok so we found the module, now we need to calculate the vma offset
- open(FILE, "objdump -dS $filename |") || die "Cannot start objdump";
+ open(FILE, $cross_compile."objdump -dS $filename |") || die "Cannot start objdump";
while (<FILE>) {
if ($_ =~ /^([0-9a-f]+) \<$function\>\:/) {
my $fu = $1;
- $vmaoffset = hex($target) - hex($fu) - hex($func_offset);
+ $vmaoffset = Math::BigInt->from_hex("0x$target") - Math::BigInt->from_hex("0x$fu") - Math::BigInt->from_hex("0x$func_offset");
}
}
close(FILE);
@@ -204,7 +214,7 @@ if ($module ne "") {
my $counter = 0;
my $state = 0;
-my $center = 0;
+my $center = -1;
my @lines;
my @reglines;
@@ -212,7 +222,7 @@ sub InRange {
my ($address, $target) = @_;
my $ad = "0x".$address;
my $ta = "0x".$target;
- my $delta = hex($ad) - hex($ta);
+ my $delta = Math::BigInt->from_hex($ad) - Math::BigInt->from_hex($ta);
if (($delta > -4096) && ($delta < 4096)) {
return 1;
@@ -225,7 +235,7 @@ sub InRange {
# first, parse the input into the lines array, but to keep size down,
# we only do this for 4Kb around the sweet spot
-open(FILE, "objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump";
+open(FILE, $cross_compile."objdump -dS --adjust-vma=$vmaoffset --start-address=$decodestart --stop-address=$decodestop $filename |") || die "Cannot start objdump";
while (<FILE>) {
my $line = $_;
@@ -236,7 +246,8 @@ while (<FILE>) {
$state = 1;
}
}
- } else {
+ }
+ if ($state == 1) {
if ($line =~ /^([a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]+)\:/) {
my $val = $1;
if (!InRange($val, $target)) {
@@ -259,7 +270,7 @@ if ($counter == 0) {
exit;
}
-if ($center == 0) {
+if ($center == -1) {
print "No matching code found \n";
exit;
}
@@ -344,3 +355,16 @@ while ($i < $finish) {
$i = $i +1;
}
+sub usage {
+ print <<EOT;
+Usage:
+ dmesg | perl $0 [OPTION] [VMLINUX]
+
+OPTION:
+ -c, --cross-compile CROSS_COMPILE Specify the prefix used for toolchain.
+ -m, --module MODULE_DIRNAME Specify the module filename.
+ -h, --help Help.
+EOT
+ exit;
+}
+
diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h
index 23dbad80cce9..50ad317a4bf9 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -67,9 +67,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN"
echo \#define LINUX_COMPILE_BY \"`whoami`\"
echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
- if [ -x /bin/dnsdomainname ]; then
- domain=`dnsdomainname 2> /dev/null`
- elif [ -x /bin/domainname ]; then
+ domain=`dnsdomainname 2> /dev/null`
+ if [ -z "$domain" ]; then
domain=`domainname 2> /dev/null`
fi
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 20923613467c..a5d1457cf239 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -781,10 +781,13 @@ static void check_section(const char *modname, struct elf_info *elf,
#define ALL_EXIT_TEXT_SECTIONS \
".exit.text$", ".devexit.text$", ".cpuexit.text$", ".memexit.text$"
-#define ALL_INIT_SECTIONS INIT_SECTIONS, DEV_INIT_SECTIONS, \
- CPU_INIT_SECTIONS, MEM_INIT_SECTIONS
-#define ALL_EXIT_SECTIONS EXIT_SECTIONS, DEV_EXIT_SECTIONS, \
- CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS
+#define ALL_XXXINIT_SECTIONS DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, \
+ MEM_INIT_SECTIONS
+#define ALL_XXXEXIT_SECTIONS DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, \
+ MEM_EXIT_SECTIONS
+
+#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS
+#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS
#define DATA_SECTIONS ".data$", ".data.rel$"
#define TEXT_SECTIONS ".text$"
@@ -814,33 +817,29 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL };
/* symbols in .data that may refer to init/exit sections */
-static const char *symbol_white_list[] =
-{
- "*driver",
- "*_template", /* scsi uses *_template a lot */
- "*_timer", /* arm uses ops structures named _timer a lot */
- "*_sht", /* scsi also used *_sht to some extent */
- "*_ops",
- "*_probe",
- "*_probe_one",
- "*_console",
- NULL
-};
+#define DEFAULT_SYMBOL_WHITE_LIST \
+ "*driver", \
+ "*_template", /* scsi uses *_template a lot */ \
+ "*_timer", /* arm uses ops structures named _timer a lot */ \
+ "*_sht", /* scsi also used *_sht to some extent */ \
+ "*_ops", \
+ "*_probe", \
+ "*_probe_one", \
+ "*_console"
static const char *head_sections[] = { ".head.text*", NULL };
static const char *linker_symbols[] =
{ "__init_begin", "_sinittext", "_einittext", NULL };
enum mismatch {
- NO_MISMATCH,
- TEXT_TO_INIT,
- DATA_TO_INIT,
- TEXT_TO_EXIT,
- DATA_TO_EXIT,
- XXXINIT_TO_INIT,
- XXXEXIT_TO_EXIT,
- INIT_TO_EXIT,
- EXIT_TO_INIT,
+ TEXT_TO_ANY_INIT,
+ DATA_TO_ANY_INIT,
+ TEXT_TO_ANY_EXIT,
+ DATA_TO_ANY_EXIT,
+ XXXINIT_TO_SOME_INIT,
+ XXXEXIT_TO_SOME_EXIT,
+ ANY_INIT_TO_ANY_EXIT,
+ ANY_EXIT_TO_ANY_INIT,
EXPORT_TO_INIT_EXIT,
};
@@ -848,6 +847,7 @@ struct sectioncheck {
const char *fromsec[20];
const char *tosec[20];
enum mismatch mismatch;
+ const char *symbol_white_list[20];
};
const struct sectioncheck sectioncheck[] = {
@@ -857,80 +857,103 @@ const struct sectioncheck sectioncheck[] = {
{
.fromsec = { TEXT_SECTIONS, NULL },
.tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_INIT,
+ .mismatch = TEXT_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
- .tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = DATA_TO_INIT,
+ .tosec = { ALL_XXXINIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
+},
+{
+ .fromsec = { DATA_SECTIONS, NULL },
+ .tosec = { INIT_SECTIONS, NULL },
+ .mismatch = DATA_TO_ANY_INIT,
+ .symbol_white_list = {
+ "*_template", "*_timer", "*_sht", "*_ops",
+ "*_probe", "*_probe_one", "*_console", NULL
+ },
},
{
.fromsec = { TEXT_SECTIONS, NULL },
.tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = TEXT_TO_EXIT,
+ .mismatch = TEXT_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
{
.fromsec = { DATA_SECTIONS, NULL },
.tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = DATA_TO_EXIT,
+ .mismatch = DATA_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference init code/data from devinit/cpuinit/meminit code/data */
{
- .fromsec = { DEV_INIT_SECTIONS, CPU_INIT_SECTIONS, MEM_INIT_SECTIONS, NULL },
+ .fromsec = { ALL_XXXINIT_SECTIONS, NULL },
.tosec = { INIT_SECTIONS, NULL },
- .mismatch = XXXINIT_TO_INIT,
+ .mismatch = XXXINIT_TO_SOME_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference cpuinit code/data from meminit code/data */
{
.fromsec = { MEM_INIT_SECTIONS, NULL },
.tosec = { CPU_INIT_SECTIONS, NULL },
- .mismatch = XXXINIT_TO_INIT,
+ .mismatch = XXXINIT_TO_SOME_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference meminit code/data from cpuinit code/data */
{
.fromsec = { CPU_INIT_SECTIONS, NULL },
.tosec = { MEM_INIT_SECTIONS, NULL },
- .mismatch = XXXINIT_TO_INIT,
+ .mismatch = XXXINIT_TO_SOME_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference exit code/data from devexit/cpuexit/memexit code/data */
{
- .fromsec = { DEV_EXIT_SECTIONS, CPU_EXIT_SECTIONS, MEM_EXIT_SECTIONS, NULL },
+ .fromsec = { ALL_XXXEXIT_SECTIONS, NULL },
.tosec = { EXIT_SECTIONS, NULL },
- .mismatch = XXXEXIT_TO_EXIT,
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference cpuexit code/data from memexit code/data */
{
.fromsec = { MEM_EXIT_SECTIONS, NULL },
.tosec = { CPU_EXIT_SECTIONS, NULL },
- .mismatch = XXXEXIT_TO_EXIT,
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not reference memexit code/data from cpuexit code/data */
{
.fromsec = { CPU_EXIT_SECTIONS, NULL },
.tosec = { MEM_EXIT_SECTIONS, NULL },
- .mismatch = XXXEXIT_TO_EXIT,
+ .mismatch = XXXEXIT_TO_SOME_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use exit code/data from init code */
{
.fromsec = { ALL_INIT_SECTIONS, NULL },
.tosec = { ALL_EXIT_SECTIONS, NULL },
- .mismatch = INIT_TO_EXIT,
+ .mismatch = ANY_INIT_TO_ANY_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not use init code/data from exit code */
{
.fromsec = { ALL_EXIT_SECTIONS, NULL },
.tosec = { ALL_INIT_SECTIONS, NULL },
- .mismatch = EXIT_TO_INIT,
+ .mismatch = ANY_EXIT_TO_ANY_INIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
},
/* Do not export init/exit functions or data */
{
.fromsec = { "__ksymtab*", NULL },
.tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL },
- .mismatch = EXPORT_TO_INIT_EXIT
+ .mismatch = EXPORT_TO_INIT_EXIT,
+ .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL },
}
};
-static int section_mismatch(const char *fromsec, const char *tosec)
+static const struct sectioncheck *section_mismatch(
+ const char *fromsec, const char *tosec)
{
int i;
int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck);
@@ -939,10 +962,10 @@ static int section_mismatch(const char *fromsec, const char *tosec)
for (i = 0; i < elems; i++) {
if (match(fromsec, check->fromsec) &&
match(tosec, check->tosec))
- return check->mismatch;
+ return check;
check++;
}
- return NO_MISMATCH;
+ return NULL;
}
/**
@@ -958,10 +981,17 @@ static int section_mismatch(const char *fromsec, const char *tosec)
* fromsec = .data*
* atsym =__param*
*
+ * Pattern 1a:
+ * module_param_call() ops can refer to __init set function if permissions=0
+ * The pattern is identified by:
+ * tosec = .init.text
+ * fromsec = .data*
+ * atsym = __param_ops_*
+ *
* Pattern 2:
* Many drivers utilise a *driver container with references to
* add, remove, probe functions etc.
- * These functions may often be marked __init and we do not want to
+ * These functions may often be marked __devinit and we do not want to
* warn here.
* the pattern is identified by:
* tosec = init or exit section
@@ -982,7 +1012,8 @@ static int section_mismatch(const char *fromsec, const char *tosec)
* refsymname = __init_begin, _sinittext, _einittext
*
**/
-static int secref_whitelist(const char *fromsec, const char *fromsym,
+static int secref_whitelist(const struct sectioncheck *mismatch,
+ const char *fromsec, const char *fromsym,
const char *tosec, const char *tosym)
{
/* Check for pattern 1 */
@@ -991,10 +1022,16 @@ static int secref_whitelist(const char *fromsec, const char *fromsym,
(strncmp(fromsym, "__param", strlen("__param")) == 0))
return 0;
+ /* Check for pattern 1a */
+ if (strcmp(tosec, ".init.text") == 0 &&
+ match(fromsec, data_sections) &&
+ (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0))
+ return 0;
+
/* Check for pattern 2 */
if (match(tosec, init_exit_sections) &&
match(fromsec, data_sections) &&
- match(fromsym, symbol_white_list))
+ match(fromsym, mismatch->symbol_white_list))
return 0;
/* Check for pattern 3 */
@@ -1155,7 +1192,8 @@ static int is_function(Elf_Sym *sym)
* Try to find symbols near it so user can find it.
* Check whitelist before warning - it may be a false positive.
*/
-static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
+static void report_sec_mismatch(const char *modname,
+ const struct sectioncheck *mismatch,
const char *fromsec,
unsigned long long fromaddr,
const char *fromsym,
@@ -1186,8 +1224,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec,
tosym, to_p);
- switch (mismatch) {
- case TEXT_TO_INIT:
+ switch (mismatch->mismatch) {
+ case TEXT_TO_ANY_INIT:
fprintf(stderr,
"The function %s%s() references\n"
"the %s %s%s%s.\n"
@@ -1197,8 +1235,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
to, sec2annotation(tosec), tosym, to_p,
fromsym, sec2annotation(tosec), tosym);
break;
- case DATA_TO_INIT: {
- const char **s = symbol_white_list;
+ case DATA_TO_ANY_INIT: {
+ const char *const *s = mismatch->symbol_white_list;
fprintf(stderr,
"The variable %s references\n"
"the %s %s%s%s\n"
@@ -1211,15 +1249,15 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
fprintf(stderr, "\n");
break;
}
- case TEXT_TO_EXIT:
+ case TEXT_TO_ANY_EXIT:
fprintf(stderr,
"The function %s() references a %s in an exit section.\n"
"Often the %s %s%s has valid usage outside the exit section\n"
"and the fix is to remove the %sannotation of %s.\n",
fromsym, to, to, tosym, to_p, sec2annotation(tosec), tosym);
break;
- case DATA_TO_EXIT: {
- const char **s = symbol_white_list;
+ case DATA_TO_ANY_EXIT: {
+ const char *const *s = mismatch->symbol_white_list;
fprintf(stderr,
"The variable %s references\n"
"the %s %s%s%s\n"
@@ -1232,8 +1270,8 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
fprintf(stderr, "\n");
break;
}
- case XXXINIT_TO_INIT:
- case XXXEXIT_TO_EXIT:
+ case XXXINIT_TO_SOME_INIT:
+ case XXXEXIT_TO_SOME_EXIT:
fprintf(stderr,
"The %s %s%s%s references\n"
"a %s %s%s%s.\n"
@@ -1243,7 +1281,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
to, sec2annotation(tosec), tosym, to_p,
tosym, fromsym, tosym);
break;
- case INIT_TO_EXIT:
+ case ANY_INIT_TO_ANY_EXIT:
fprintf(stderr,
"The %s %s%s%s references\n"
"a %s %s%s%s.\n"
@@ -1256,7 +1294,7 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
to, sec2annotation(tosec), tosym, to_p,
sec2annotation(tosec), tosym, to_p);
break;
- case EXIT_TO_INIT:
+ case ANY_EXIT_TO_ANY_INIT:
fprintf(stderr,
"The %s %s%s%s references\n"
"a %s %s%s%s.\n"
@@ -1275,8 +1313,6 @@ static void report_sec_mismatch(const char *modname, enum mismatch mismatch,
"Fix this by removing the %sannotation of %s "
"or drop the export.\n",
tosym, sec2annotation(tosec), sec2annotation(tosec), tosym);
- case NO_MISMATCH:
- /* To get warnings on missing members */
break;
}
fprintf(stderr, "\n");
@@ -1286,11 +1322,11 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
Elf_Rela *r, Elf_Sym *sym, const char *fromsec)
{
const char *tosec;
- enum mismatch mismatch;
+ const struct sectioncheck *mismatch;
tosec = sec_name(elf, sym->st_shndx);
mismatch = section_mismatch(fromsec, tosec);
- if (mismatch != NO_MISMATCH) {
+ if (mismatch) {
Elf_Sym *to;
Elf_Sym *from;
const char *tosym;
@@ -1302,7 +1338,8 @@ static void check_section_mismatch(const char *modname, struct elf_info *elf,
tosym = sym_name(elf, to);
/* check whitelist - we may ignore it */
- if (secref_whitelist(fromsec, fromsym, tosec, tosym)) {
+ if (secref_whitelist(mismatch,
+ fromsec, fromsym, tosec, tosym)) {
report_sec_mismatch(modname, mismatch,
fromsec, r->r_offset, fromsym,
is_function(from), tosec, tosym,
diff --git a/scripts/namespace.pl b/scripts/namespace.pl
index c6e88c652c2f..361d0f71184b 100755
--- a/scripts/namespace.pl
+++ b/scripts/namespace.pl
@@ -175,12 +175,11 @@ sub do_nm
}
if (! -e "$source.c" && ! -e "$source.S") {
# No obvious source, exclude the object if it is conglomerate
- if (! open(OBJDUMPDATA, "$objdump $basename|")) {
- printf STDERR "$objdump $fullname failed $!\n";
- return;
- }
+ open(my $objdumpdata, "$objdump $basename|")
+ or die "$objdump $fullname failed $!\n";
+
my $comment;
- while (<OBJDUMPDATA>) {
+ while (<$objdumpdata>) {
chomp();
if (/^In archive/) {
# Archives are always conglomerate
@@ -190,18 +189,18 @@ sub do_nm
next if (! /^[ 0-9a-f]{5,} /);
$comment .= substr($_, 43);
}
- close(OBJDUMPDATA);
+ close($objdumpdata);
+
if (!defined($comment) || $comment !~ /GCC\:.*GCC\:/m) {
printf STDERR "No source file found for $fullname\n";
}
return;
}
- if (! open(NMDATA, "$nm $basename|")) {
- printf STDERR "$nm $fullname failed $!\n";
- return;
- }
+ open (my $nmdata, "$nm $basename|")
+ or die "$nm $fullname failed $!\n";
+
my @nmdata;
- while (<NMDATA>) {
+ while (<$nmdata>) {
chop;
($type, $name) = (split(/ +/, $_, 3))[1..2];
# Expected types
@@ -268,7 +267,8 @@ sub do_nm
}
}
}
- close(NMDATA);
+ close($nmdata);
+
if ($#nmdata < 0) {
if (
$fullname ne "lib/brlock.o"
@@ -316,8 +316,7 @@ sub drop_def
sub list_multiply_defined
{
- my ($name, $module);
- foreach $name (keys(%def)) {
+ foreach my $name (keys(%def)) {
if ($#{$def{$name}} > 0) {
# Special case for cond_syscall
if ($#{$def{$name}} == 1 && $name =~ /^sys_/ &&
@@ -333,8 +332,9 @@ sub list_multiply_defined
&drop_def("arch/x86/kernel/vsyscall-sysenter_32.o", $name);
next;
}
+
printf "$name is multiply defined in :-\n";
- foreach $module (@{$def{$name}}) {
+ foreach my $module (@{$def{$name}}) {
printf "\t$module\n";
}
}
@@ -343,12 +343,13 @@ sub list_multiply_defined
sub resolve_external_references
{
- my ($object, $type, $name, $i, $j, $kstrtab, $ksymtab, $export);
+ my ($kstrtab, $ksymtab, $export);
+
printf "\n";
- foreach $object (keys(%nmdata)) {
+ foreach my $object (keys(%nmdata)) {
my $nmdata = $nmdata{$object};
- for ($i = 0; $i <= $#{$nmdata}; ++$i) {
- ($type, $name) = split(' ', $nmdata->[$i], 2);
+ for (my $i = 0; $i <= $#{$nmdata}; ++$i) {
+ my ($type, $name) = split(' ', $nmdata->[$i], 2);
if ($type eq "U" || $type eq "w") {
if (exists($def{$name}) || exists($ksymtab{$name})) {
# add the owning object to the nmdata
@@ -357,7 +358,7 @@ sub resolve_external_references
$kstrtab = "R __kstrtab_$name";
$ksymtab = "R __ksymtab_$name";
$export = 0;
- for ($j = 0; $j <= $#{$nmdata}; ++$j) {
+ for (my $j = 0; $j <= $#{$nmdata}; ++$j) {
if ($nmdata->[$j] eq $kstrtab ||
$nmdata->[$j] eq $ksymtab) {
$export = 1;
@@ -424,11 +425,11 @@ sub resolve_external_references
sub list_extra_externals
{
my %noref = ();
- my ($name, @module, $module, $export);
- foreach $name (keys(%def)) {
+
+ foreach my $name (keys(%def)) {
if (! exists($ref{$name})) {
- @module = @{$def{$name}};
- foreach $module (@module) {
+ my @module = @{$def{$name}};
+ foreach my $module (@module) {
if (! exists($noref{$module})) {
$noref{$module} = [];
}
@@ -438,16 +439,16 @@ sub list_extra_externals
}
if (%noref) {
printf "\nExternally defined symbols with no external references\n";
- foreach $module (sort(keys(%noref))) {
+ foreach my $module (sort(keys(%noref))) {
printf " $module\n";
foreach (sort(@{$noref{$module}})) {
- if (exists($export{$_})) {
- $export = " (export only)";
- }
- else {
- $export = "";
- }
- printf " $_$export\n";
+ my $export;
+ if (exists($export{$_})) {
+ $export = " (export only)";
+ } else {
+ $export = "";
+ }
+ printf " $_$export\n";
}
}
}
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index 8b357b0bd250..5f1e2fc7f171 100644
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -18,6 +18,8 @@ create_package() {
cp debian/copyright "$pdir/usr/share/doc/$pname/"
cp debian/changelog "$pdir/usr/share/doc/$pname/changelog.Debian"
gzip -9 "$pdir/usr/share/doc/$pname/changelog.Debian"
+ sh -c "cd '$pdir'; find . -type f ! -path './DEBIAN/*' -printf '%P\0' \
+ | xargs -r0 md5sum > DEBIAN/md5sums"
# Fix ownership and permissions
chown -R root:root "$pdir"
@@ -146,10 +148,11 @@ EOF
# Generate a control file
cat <<EOF > debian/control
Source: linux-upstream
-Section: admin
+Section: kernel
Priority: optional
Maintainer: $maintainer
-Standards-Version: 3.8.1
+Standards-Version: 3.8.4
+Homepage: http://www.kernel.org/
EOF
if [ "$ARCH" = "um" ]; then
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index fa27f3dac769..15440f55aef6 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -39,7 +39,7 @@ if ! $PREBUILT; then
echo "Source: kernel-$__KERNELRELEASE.tar.gz"
fi
-echo "BuildRoot: /var/tmp/%{name}-%{PACKAGE_VERSION}-root"
+echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root"
echo "Provides: $PROVIDES"
echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
echo "%define debug_package %{nil}"
diff --git a/scripts/profile2linkerlist.pl b/scripts/profile2linkerlist.pl
index cb4260ebdb91..6943fa7cc95b 100644
--- a/scripts/profile2linkerlist.pl
+++ b/scripts/profile2linkerlist.pl
@@ -7,15 +7,13 @@
# usage:
# readprofile | sort -rn | perl profile2linkerlist.pl > functionlist
#
+use strict;
while (<>) {
my $line = $_;
$_ =~ /\W*[0-9]+\W*([a-zA-Z\_0-9]+)\W*[0-9]+/;
- if ( ($line =~ /unknown/) || ($line =~ /total/)) {
-
- } else {
- print "*(.text.$1)\n";
- }
+ print "*(.text.$1)\n"
+ unless ($line =~ /unknown/) || ($line =~ /total/);
}
diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py
index 4c79660793cf..44423b4dcb82 100644
--- a/scripts/rt-tester/rt-tester.py
+++ b/scripts/rt-tester/rt-tester.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
#
# rt-mutex tester
#
diff --git a/scripts/show_delta b/scripts/show_delta
index 48a706ab3d0c..17df3051747a 100755
--- a/scripts/show_delta
+++ b/scripts/show_delta
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
#
# show_deltas: Read list of printk messages instrumented with
# time data, and format with time deltas.
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 1a0c44d7c4a7..8509bb512935 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -5,7 +5,7 @@
# mode may be any of: tags, TAGS, cscope
#
# Uses the following environment variables:
-# ARCH, SUBARCH, srctree, src, obj
+# ARCH, SUBARCH, SRCARCH, srctree, src, obj
if [ "$KBUILD_VERBOSE" = "1" ]; then
set -x
@@ -17,28 +17,48 @@ ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \
-name .git ) \
-prune -o"
-# Do not use full path is we do not use O=.. builds
+# Do not use full path if we do not use O=.. builds
+# Use make O=. {tags|cscope}
+# to force full paths for a non-O= build
if [ "${KBUILD_SRC}" = "" ]; then
tree=
else
tree=${srctree}/
fi
+# Find all available archs
+find_all_archs()
+{
+ ALLSOURCE_ARCHS=""
+ for arch in `ls ${tree}arch`; do
+ ALLSOURCE_ARCHS="${ALLSOURCE_ARCHS} "${arch##\/}
+ done
+}
+
# Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH
if [ "${ALLSOURCE_ARCHS}" = "" ]; then
ALLSOURCE_ARCHS=${SRCARCH}
+elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then
+ find_all_archs
fi
# find sources in arch/$ARCH
find_arch_sources()
{
- find ${tree}arch/$1 $ignore -name "$2" -print;
+ for i in $archincludedir; do
+ prune="$prune -wholename $i -prune -o"
+ done
+ find ${tree}arch/$1 $ignore $prune -name "$2" -print;
}
# find sources in arch/$1/include
find_arch_include_sources()
{
- find ${tree}arch/$1/include $ignore -name "$2" -print;
+ include=$(find ${tree}arch/$1/ -name include -type d);
+ if [ -n "$include" ]; then
+ archincludedir="$archincludedir $include"
+ find $include $ignore -name "$2" -print;
+ fi
}
# find sources in include/
@@ -63,14 +83,15 @@ find_sources()
all_sources()
{
- for arch in $ALLSOURCE_ARCHS
- do
- find_sources $arch '*.[chS]'
- done
+ find_arch_include_sources ${SRCARCH} '*.[chS]'
if [ ! -z "$archinclude" ]; then
find_arch_include_sources $archinclude '*.[chS]'
fi
find_include_sources '*.[chS]'
+ for arch in $ALLSOURCE_ARCHS
+ do
+ find_sources $arch '*.[chS]'
+ done
find_other_sources '*.[chS]'
}
@@ -89,13 +110,7 @@ all_defconfigs()
docscope()
{
- # always use absolute paths for cscope, as recommended by cscope
- # upstream
- case "$tree" in
- /*) ;;
- *) tree=$PWD/$tree ;;
- esac
- (cd /; echo \-k; echo \-q; all_sources) > cscope.files
+ (echo \-k; echo \-q; all_sources) > cscope.files
cscope -b -f cscope.out
}
diff --git a/security/capability.c b/security/capability.c
index 8168e3ecd5bf..4aeb699da1b3 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -268,8 +268,7 @@ static int cap_path_rename(struct path *old_path, struct dentry *old_dentry,
return 0;
}
-static int cap_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static int cap_path_truncate(struct path *path)
{
return 0;
}
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 13074b454743..6261745e4459 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -33,7 +33,7 @@ static int key_get_type_from_user(char *type,
ret = strncpy_from_user(type, _type, len);
if (ret < 0)
- return -EFAULT;
+ return ret;
if (ret == 0 || ret >= len)
return -EINVAL;
@@ -1080,7 +1080,7 @@ set:
return old_setting;
error:
abort_creds(new);
- return -EINVAL;
+ return ret;
} /* end keyctl_set_reqkey_keyring() */
diff --git a/security/security.c b/security/security.c
index 351942a4ca0e..7461b1bc296c 100644
--- a/security/security.c
+++ b/security/security.c
@@ -417,12 +417,11 @@ int security_path_rename(struct path *old_dir, struct dentry *old_dentry,
new_dentry);
}
-int security_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+int security_path_truncate(struct path *path)
{
if (unlikely(IS_PRIVATE(path->dentry->d_inode)))
return 0;
- return security_ops->path_truncate(path, length, time_attrs);
+ return security_ops->path_truncate(path);
}
int security_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
@@ -620,7 +619,13 @@ void security_inode_getsecid(const struct inode *inode, u32 *secid)
int security_file_permission(struct file *file, int mask)
{
- return security_ops->file_permission(file, mask);
+ int ret;
+
+ ret = security_ops->file_permission(file, mask);
+ if (ret)
+ return ret;
+
+ return fsnotify_perm(file, mask);
}
int security_file_alloc(struct file *file)
@@ -684,7 +689,13 @@ int security_file_receive(struct file *file)
int security_dentry_open(struct file *file, const struct cred *cred)
{
- return security_ops->dentry_open(file, cred);
+ int ret;
+
+ ret = security_ops->dentry_open(file, cred);
+ if (ret)
+ return ret;
+
+ return fsnotify_perm(file, MAY_OPEN);
}
int security_task_create(unsigned long clone_flags)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 7f1a304712a9..3662b0f15ec5 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -288,7 +288,6 @@ static struct avc_node *avc_alloc_node(void)
if (!node)
goto out;
- INIT_RCU_HEAD(&node->rhead);
INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations);
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c
index dc92792271f1..65ebfe954f85 100644
--- a/security/selinux/netnode.c
+++ b/security/selinux/netnode.c
@@ -183,8 +183,6 @@ static void sel_netnode_insert(struct sel_netnode *node)
BUG();
}
- INIT_RCU_HEAD(&node->rcu);
-
/* we need to impose a limit on the growth of the hash table so check
* this bucket to make sure it is within the specified bounds */
list_add_rcu(&node->list, &sel_netnode_hash[idx].list);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 0f2fc480fc61..07abc9ce72f2 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -2191,7 +2191,7 @@ static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
/**
* smack_d_instantiate - Make sure the blob is correct on an inode
- * @opt_dentry: unused
+ * @opt_dentry: dentry where inode will be attached
* @inode: the object
*
* Set the inode's security blob if it hasn't been done already.
@@ -2310,20 +2310,10 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
/*
* Get the dentry for xattr.
*/
- if (opt_dentry == NULL) {
- dp = d_find_alias(inode);
- if (dp == NULL)
- break;
- } else {
- dp = dget(opt_dentry);
- if (dp == NULL)
- break;
- }
-
+ dp = dget(opt_dentry);
fetched = smk_fetch(inode, dp);
if (fetched != NULL)
final = fetched;
-
dput(dp);
break;
}
diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile
index 4fb39030f6bd..3aa6f076948e 100644
--- a/security/tomoyo/Makefile
+++ b/security/tomoyo/Makefile
@@ -1 +1 @@
-obj-y = common.o realpath.o tomoyo.o domain.o file.o gc.o path_group.o
+obj-y = common.o domain.o file.o gc.o load_policy.o memory.o mount.o number_group.o path_group.o realpath.o securityfs_if.o tomoyo.o util.o
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c
index b5dbdc9ff73c..811adb5e9fea 100644
--- a/security/tomoyo/common.c
+++ b/security/tomoyo/common.c
@@ -3,99 +3,77 @@
*
* Common functions for TOMOYO.
*
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
- *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/security.h>
-#include <linux/hardirq.h>
#include "common.h"
-/* Lock for protecting policy. */
-DEFINE_MUTEX(tomoyo_policy_lock);
+static struct tomoyo_profile tomoyo_default_profile = {
+ .learning = &tomoyo_default_profile.preference,
+ .permissive = &tomoyo_default_profile.preference,
+ .enforcing = &tomoyo_default_profile.preference,
+ .preference.enforcing_verbose = true,
+ .preference.learning_max_entry = 2048,
+ .preference.learning_verbose = false,
+ .preference.permissive_verbose = true
+};
-/* Has loading policy done? */
-bool tomoyo_policy_loaded;
+/* Profile version. Currently only 20090903 is defined. */
+static unsigned int tomoyo_profile_version;
+
+/* Profile table. Memory is allocated as needed. */
+static struct tomoyo_profile *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
/* String table for functionality that takes 4 modes. */
static const char *tomoyo_mode_4[4] = {
"disabled", "learning", "permissive", "enforcing"
};
-/* String table for functionality that takes 2 modes. */
-static const char *tomoyo_mode_2[4] = {
- "disabled", "enabled", "enabled", "enabled"
-};
-/*
- * tomoyo_control_array is a static data which contains
- *
- * (1) functionality name used by /sys/kernel/security/tomoyo/profile .
- * (2) initial values for "struct tomoyo_profile".
- * (3) max values for "struct tomoyo_profile".
- */
-static struct {
- const char *keyword;
- unsigned int current_value;
- const unsigned int max_value;
-} tomoyo_control_array[TOMOYO_MAX_CONTROL_INDEX] = {
- [TOMOYO_MAC_FOR_FILE] = { "MAC_FOR_FILE", 0, 3 },
- [TOMOYO_MAX_ACCEPT_ENTRY] = { "MAX_ACCEPT_ENTRY", 2048, INT_MAX },
- [TOMOYO_VERBOSE] = { "TOMOYO_VERBOSE", 1, 1 },
+/* String table for /sys/kernel/security/tomoyo/profile */
+static const char *tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX
+ + TOMOYO_MAX_MAC_CATEGORY_INDEX] = {
+ [TOMOYO_MAC_FILE_EXECUTE] = "file::execute",
+ [TOMOYO_MAC_FILE_OPEN] = "file::open",
+ [TOMOYO_MAC_FILE_CREATE] = "file::create",
+ [TOMOYO_MAC_FILE_UNLINK] = "file::unlink",
+ [TOMOYO_MAC_FILE_MKDIR] = "file::mkdir",
+ [TOMOYO_MAC_FILE_RMDIR] = "file::rmdir",
+ [TOMOYO_MAC_FILE_MKFIFO] = "file::mkfifo",
+ [TOMOYO_MAC_FILE_MKSOCK] = "file::mksock",
+ [TOMOYO_MAC_FILE_TRUNCATE] = "file::truncate",
+ [TOMOYO_MAC_FILE_SYMLINK] = "file::symlink",
+ [TOMOYO_MAC_FILE_REWRITE] = "file::rewrite",
+ [TOMOYO_MAC_FILE_MKBLOCK] = "file::mkblock",
+ [TOMOYO_MAC_FILE_MKCHAR] = "file::mkchar",
+ [TOMOYO_MAC_FILE_LINK] = "file::link",
+ [TOMOYO_MAC_FILE_RENAME] = "file::rename",
+ [TOMOYO_MAC_FILE_CHMOD] = "file::chmod",
+ [TOMOYO_MAC_FILE_CHOWN] = "file::chown",
+ [TOMOYO_MAC_FILE_CHGRP] = "file::chgrp",
+ [TOMOYO_MAC_FILE_IOCTL] = "file::ioctl",
+ [TOMOYO_MAC_FILE_CHROOT] = "file::chroot",
+ [TOMOYO_MAC_FILE_MOUNT] = "file::mount",
+ [TOMOYO_MAC_FILE_UMOUNT] = "file::umount",
+ [TOMOYO_MAC_FILE_PIVOT_ROOT] = "file::pivot_root",
+ [TOMOYO_MAX_MAC_INDEX + TOMOYO_MAC_CATEGORY_FILE] = "file",
};
-/*
- * tomoyo_profile is a structure which is used for holding the mode of access
- * controls. TOMOYO has 4 modes: disabled, learning, permissive, enforcing.
- * An administrator can define up to 256 profiles.
- * The ->profile of "struct tomoyo_domain_info" is used for remembering
- * the profile's number (0 - 255) assigned to that domain.
- */
-static struct tomoyo_profile {
- unsigned int value[TOMOYO_MAX_CONTROL_INDEX];
- const struct tomoyo_path_info *comment;
-} *tomoyo_profile_ptr[TOMOYO_MAX_PROFILES];
-
/* Permit policy management by non-root user? */
static bool tomoyo_manage_by_non_root;
/* Utility functions. */
-/* Open operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_open_control(const u8 type, struct file *file);
-/* Close /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_close_control(struct file *file);
-/* Read operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_read_control(struct file *file, char __user *buffer,
- const int buffer_len);
-/* Write operation for /sys/kernel/security/tomoyo/ interface. */
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
- const int buffer_len);
-
/**
- * tomoyo_parse_name_union - Parse a tomoyo_name_union.
- *
- * @filename: Name or name group.
- * @ptr: Pointer to "struct tomoyo_name_union".
+ * tomoyo_yesno - Return "yes" or "no".
*
- * Returns true on success, false otherwise.
+ * @value: Bool value.
*/
-bool tomoyo_parse_name_union(const char *filename,
- struct tomoyo_name_union *ptr)
+static const char *tomoyo_yesno(const unsigned int value)
{
- if (!tomoyo_is_correct_path(filename, 0, 0, 0))
- return false;
- if (filename[0] == '@') {
- ptr->group = tomoyo_get_path_group(filename + 1);
- ptr->is_group = true;
- return ptr->group != NULL;
- }
- ptr->filename = tomoyo_get_name(filename);
- ptr->is_group = false;
- return ptr->filename != NULL;
+ return value ? "yes" : "no";
}
/**
@@ -119,661 +97,53 @@ static bool tomoyo_print_name_union(struct tomoyo_io_buffer *head,
}
/**
- * tomoyo_is_byte_range - Check whether the string isa \ooo style octal value.
- *
- * @str: Pointer to the string.
- *
- * Returns true if @str is a \ooo style octal value, false otherwise.
- *
- * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
- * This function verifies that \ooo is in valid range.
- */
-static inline bool tomoyo_is_byte_range(const char *str)
-{
- return *str >= '0' && *str++ <= '3' &&
- *str >= '0' && *str++ <= '7' &&
- *str >= '0' && *str <= '7';
-}
-
-/**
- * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
- *
- * @c: The character to check.
- *
- * Returns true if @c is an alphabet character, false otherwise.
- */
-static inline bool tomoyo_is_alphabet_char(const char c)
-{
- return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
-}
-
-/**
- * tomoyo_make_byte - Make byte value from three octal characters.
- *
- * @c1: The first character.
- * @c2: The second character.
- * @c3: The third character.
- *
- * Returns byte value.
- */
-static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
-{
- return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
-}
-
-/**
- * tomoyo_str_starts - Check whether the given string starts with the given keyword.
- *
- * @src: Pointer to pointer to the string.
- * @find: Pointer to the keyword.
+ * tomoyo_print_number_union - Print a tomoyo_number_union.
*
- * Returns true if @src starts with @find, false otherwise.
- *
- * The @src is updated to point the first character after the @find
- * if @src starts with @find.
- */
-static bool tomoyo_str_starts(char **src, const char *find)
-{
- const int len = strlen(find);
- char *tmp = *src;
-
- if (strncmp(tmp, find, len))
- return false;
- tmp += len;
- *src = tmp;
- return true;
-}
-
-/**
- * tomoyo_normalize_line - Format string.
- *
- * @buffer: The line to normalize.
- *
- * Leading and trailing whitespaces are removed.
- * Multiple whitespaces are packed into single space.
- *
- * Returns nothing.
- */
-static void tomoyo_normalize_line(unsigned char *buffer)
-{
- unsigned char *sp = buffer;
- unsigned char *dp = buffer;
- bool first = true;
-
- while (tomoyo_is_invalid(*sp))
- sp++;
- while (*sp) {
- if (!first)
- *dp++ = ' ';
- first = false;
- while (tomoyo_is_valid(*sp))
- *dp++ = *sp++;
- while (tomoyo_is_invalid(*sp))
- sp++;
- }
- *dp = '\0';
-}
-
-/**
- * tomoyo_tokenize - Tokenize string.
- *
- * @buffer: The line to tokenize.
- * @w: Pointer to "char *".
- * @size: Sizeof @w .
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_number_union".
*
* Returns true on success, false otherwise.
*/
-bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union *ptr)
{
- int count = size / sizeof(char *);
- int i;
- for (i = 0; i < count; i++)
- w[i] = "";
- for (i = 0; i < count; i++) {
- char *cp = strchr(buffer, ' ');
- if (cp)
- *cp = '\0';
- w[i] = buffer;
- if (!cp)
- break;
- buffer = cp + 1;
- }
- return i < count || !*buffer;
-}
-
-/**
- * tomoyo_is_correct_path - Validate a pathname.
- * @filename: The pathname to check.
- * @start_type: Should the pathname start with '/'?
- * 1 = must / -1 = must not / 0 = don't care
- * @pattern_type: Can the pathname contain a wildcard?
- * 1 = must / -1 = must not / 0 = don't care
- * @end_type: Should the pathname end with '/'?
- * 1 = must / -1 = must not / 0 = don't care
- *
- * Check whether the given filename follows the naming rules.
- * Returns true if @filename follows the naming rules, false otherwise.
- */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
- const s8 pattern_type, const s8 end_type)
-{
- const char *const start = filename;
- bool in_repetition = false;
- bool contains_pattern = false;
- unsigned char c;
- unsigned char d;
- unsigned char e;
-
- if (!filename)
- goto out;
- c = *filename;
- if (start_type == 1) { /* Must start with '/' */
- if (c != '/')
- goto out;
- } else if (start_type == -1) { /* Must not start with '/' */
- if (c == '/')
- goto out;
- }
- if (c)
- c = *(filename + strlen(filename) - 1);
- if (end_type == 1) { /* Must end with '/' */
- if (c != '/')
- goto out;
- } else if (end_type == -1) { /* Must not end with '/' */
- if (c == '/')
- goto out;
- }
- while (1) {
- c = *filename++;
- if (!c)
- break;
- if (c == '\\') {
- c = *filename++;
- switch (c) {
- case '\\': /* "\\" */
- continue;
- case '$': /* "\$" */
- case '+': /* "\+" */
- case '?': /* "\?" */
- case '*': /* "\*" */
- case '@': /* "\@" */
- case 'x': /* "\x" */
- case 'X': /* "\X" */
- case 'a': /* "\a" */
- case 'A': /* "\A" */
- case '-': /* "\-" */
- if (pattern_type == -1)
- break; /* Must not contain pattern */
- contains_pattern = true;
- continue;
- case '{': /* "/\{" */
- if (filename - 3 < start ||
- *(filename - 3) != '/')
- break;
- if (pattern_type == -1)
- break; /* Must not contain pattern */
- contains_pattern = true;
- in_repetition = true;
- continue;
- case '}': /* "\}/" */
- if (*filename != '/')
- break;
- if (!in_repetition)
- break;
- in_repetition = false;
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- d = *filename++;
- if (d < '0' || d > '7')
- break;
- e = *filename++;
- if (e < '0' || e > '7')
- break;
- c = tomoyo_make_byte(c, d, e);
- if (tomoyo_is_invalid(c))
- continue; /* pattern is not \000 */
- }
- goto out;
- } else if (in_repetition && c == '/') {
- goto out;
- } else if (tomoyo_is_invalid(c)) {
- goto out;
- }
- }
- if (pattern_type == 1) { /* Must contain pattern */
- if (!contains_pattern)
- goto out;
- }
- if (in_repetition)
- goto out;
- return true;
- out:
- return false;
-}
-
-/**
- * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
- * @domainname: The domainname to check.
- *
- * Returns true if @domainname follows the naming rules, false otherwise.
- */
-bool tomoyo_is_correct_domain(const unsigned char *domainname)
-{
- unsigned char c;
- unsigned char d;
- unsigned char e;
-
- if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
- TOMOYO_ROOT_NAME_LEN))
- goto out;
- domainname += TOMOYO_ROOT_NAME_LEN;
- if (!*domainname)
- return true;
- do {
- if (*domainname++ != ' ')
- goto out;
- if (*domainname++ != '/')
- goto out;
- while ((c = *domainname) != '\0' && c != ' ') {
- domainname++;
- if (c == '\\') {
- c = *domainname++;
- switch ((c)) {
- case '\\': /* "\\" */
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- d = *domainname++;
- if (d < '0' || d > '7')
- break;
- e = *domainname++;
- if (e < '0' || e > '7')
- break;
- c = tomoyo_make_byte(c, d, e);
- if (tomoyo_is_invalid(c))
- /* pattern is not \000 */
- continue;
- }
- goto out;
- } else if (tomoyo_is_invalid(c)) {
- goto out;
- }
- }
- } while (*domainname);
- return true;
- out:
- return false;
-}
-
-/**
- * tomoyo_is_domain_def - Check whether the given token can be a domainname.
- *
- * @buffer: The token to check.
- *
- * Returns true if @buffer possibly be a domainname, false otherwise.
- */
-bool tomoyo_is_domain_def(const unsigned char *buffer)
-{
- return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
-}
-
-/**
- * tomoyo_find_domain - Find a domain by the given name.
- *
- * @domainname: The domainname to find.
- *
- * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
-{
- struct tomoyo_domain_info *domain;
- struct tomoyo_path_info name;
-
- name.name = domainname;
- tomoyo_fill_path_info(&name);
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- if (!domain->is_deleted &&
- !tomoyo_pathcmp(&name, domain->domainname))
- return domain;
- }
- return NULL;
-}
-
-/**
- * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
- *
- * @filename: The string to evaluate.
- *
- * Returns the initial length without a pattern in @filename.
- */
-static int tomoyo_const_part_length(const char *filename)
-{
- char c;
- int len = 0;
-
- if (!filename)
- return 0;
- while ((c = *filename++) != '\0') {
- if (c != '\\') {
- len++;
- continue;
- }
- c = *filename++;
- switch (c) {
- case '\\': /* "\\" */
- len += 2;
- continue;
- case '0': /* "\ooo" */
- case '1':
- case '2':
- case '3':
- c = *filename++;
- if (c < '0' || c > '7')
- break;
- c = *filename++;
- if (c < '0' || c > '7')
- break;
- len += 4;
- continue;
- }
+ unsigned long min;
+ unsigned long max;
+ u8 min_type;
+ u8 max_type;
+ if (!tomoyo_io_printf(head, " "))
+ return false;
+ if (ptr->is_group)
+ return tomoyo_io_printf(head, "@%s",
+ ptr->group->group_name->name);
+ min_type = ptr->min_type;
+ max_type = ptr->max_type;
+ min = ptr->values[0];
+ max = ptr->values[1];
+ switch (min_type) {
+ case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+ if (!tomoyo_io_printf(head, "0x%lX", min))
+ return false;
break;
- }
- return len;
-}
-
-/**
- * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
- *
- * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
- *
- * The caller sets "struct tomoyo_path_info"->name.
- */
-void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
-{
- const char *name = ptr->name;
- const int len = strlen(name);
-
- ptr->const_len = tomoyo_const_part_length(name);
- ptr->is_dir = len && (name[len - 1] == '/');
- ptr->is_patterned = (ptr->const_len < len);
- ptr->hash = full_name_hash(name, len);
-}
-
-/**
- * tomoyo_file_matches_pattern2 - Pattern matching without '/' character
- * and "\-" pattern.
- *
- * @filename: The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern: The start of pattern to compare.
- * @pattern_end: The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern2(const char *filename,
- const char *filename_end,
- const char *pattern,
- const char *pattern_end)
-{
- while (filename < filename_end && pattern < pattern_end) {
- char c;
- if (*pattern != '\\') {
- if (*filename++ != *pattern++)
- return false;
- continue;
- }
- c = *filename;
- pattern++;
- switch (*pattern) {
- int i;
- int j;
- case '?':
- if (c == '/') {
- return false;
- } else if (c == '\\') {
- if (filename[1] == '\\')
- filename++;
- else if (tomoyo_is_byte_range(filename + 1))
- filename += 3;
- else
- return false;
- }
- break;
- case '\\':
- if (c != '\\')
- return false;
- if (*++filename != '\\')
- return false;
- break;
- case '+':
- if (!isdigit(c))
- return false;
- break;
- case 'x':
- if (!isxdigit(c))
- return false;
- break;
- case 'a':
- if (!tomoyo_is_alphabet_char(c))
- return false;
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- if (c == '\\' && tomoyo_is_byte_range(filename + 1)
- && strncmp(filename + 1, pattern, 3) == 0) {
- filename += 3;
- pattern += 2;
- break;
- }
- return false; /* Not matched. */
- case '*':
- case '@':
- for (i = 0; i <= filename_end - filename; i++) {
- if (tomoyo_file_matches_pattern2(
- filename + i, filename_end,
- pattern + 1, pattern_end))
- return true;
- c = filename[i];
- if (c == '.' && *pattern == '@')
- break;
- if (c != '\\')
- continue;
- if (filename[i + 1] == '\\')
- i++;
- else if (tomoyo_is_byte_range(filename + i + 1))
- i += 3;
- else
- break; /* Bad pattern. */
- }
- return false; /* Not matched. */
- default:
- j = 0;
- c = *pattern;
- if (c == '$') {
- while (isdigit(filename[j]))
- j++;
- } else if (c == 'X') {
- while (isxdigit(filename[j]))
- j++;
- } else if (c == 'A') {
- while (tomoyo_is_alphabet_char(filename[j]))
- j++;
- }
- for (i = 1; i <= j; i++) {
- if (tomoyo_file_matches_pattern2(
- filename + i, filename_end,
- pattern + 1, pattern_end))
- return true;
- }
- return false; /* Not matched or bad pattern. */
- }
- filename++;
- pattern++;
- }
- while (*pattern == '\\' &&
- (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
- pattern += 2;
- return filename == filename_end && pattern == pattern_end;
-}
-
-/**
- * tomoyo_file_matches_pattern - Pattern matching without without '/' character.
- *
- * @filename: The start of string to check.
- * @filename_end: The end of string to check.
- * @pattern: The start of pattern to compare.
- * @pattern_end: The end of pattern to compare.
- *
- * Returns true if @filename matches @pattern, false otherwise.
- */
-static bool tomoyo_file_matches_pattern(const char *filename,
- const char *filename_end,
- const char *pattern,
- const char *pattern_end)
-{
- const char *pattern_start = pattern;
- bool first = true;
- bool result;
-
- while (pattern < pattern_end - 1) {
- /* Split at "\-" pattern. */
- if (*pattern++ != '\\' || *pattern++ != '-')
- continue;
- result = tomoyo_file_matches_pattern2(filename,
- filename_end,
- pattern_start,
- pattern - 2);
- if (first)
- result = !result;
- if (result)
+ case TOMOYO_VALUE_TYPE_OCTAL:
+ if (!tomoyo_io_printf(head, "0%lo", min))
return false;
- first = false;
- pattern_start = pattern;
- }
- result = tomoyo_file_matches_pattern2(filename, filename_end,
- pattern_start, pattern_end);
- return first ? result : !result;
-}
-
-/**
- * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
- *
- * @f: The start of string to check.
- * @p: The start of pattern to compare.
- *
- * Returns true if @f matches @p, false otherwise.
- */
-static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
-{
- const char *f_delimiter;
- const char *p_delimiter;
-
- while (*f && *p) {
- f_delimiter = strchr(f, '/');
- if (!f_delimiter)
- f_delimiter = f + strlen(f);
- p_delimiter = strchr(p, '/');
- if (!p_delimiter)
- p_delimiter = p + strlen(p);
- if (*p == '\\' && *(p + 1) == '{')
- goto recursive;
- if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
- p_delimiter))
+ break;
+ default:
+ if (!tomoyo_io_printf(head, "%lu", min))
return false;
- f = f_delimiter;
- if (*f)
- f++;
- p = p_delimiter;
- if (*p)
- p++;
+ break;
+ }
+ if (min == max && min_type == max_type)
+ return true;
+ switch (max_type) {
+ case TOMOYO_VALUE_TYPE_HEXADECIMAL:
+ return tomoyo_io_printf(head, "-0x%lX", max);
+ case TOMOYO_VALUE_TYPE_OCTAL:
+ return tomoyo_io_printf(head, "-0%lo", max);
+ default:
+ return tomoyo_io_printf(head, "-%lu", max);
}
- /* Ignore trailing "\*" and "\@" in @pattern. */
- while (*p == '\\' &&
- (*(p + 1) == '*' || *(p + 1) == '@'))
- p += 2;
- return !*f && !*p;
- recursive:
- /*
- * The "\{" pattern is permitted only after '/' character.
- * This guarantees that below "*(p - 1)" is safe.
- * Also, the "\}" pattern is permitted only before '/' character
- * so that "\{" + "\}" pair will not break the "\-" operator.
- */
- if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
- *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
- return false; /* Bad pattern. */
- do {
- /* Compare current component with pattern. */
- if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
- p_delimiter - 2))
- break;
- /* Proceed to next component. */
- f = f_delimiter;
- if (!*f)
- break;
- f++;
- /* Continue comparison. */
- if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
- return true;
- f_delimiter = strchr(f, '/');
- } while (f_delimiter);
- return false; /* Not matched. */
-}
-
-/**
- * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
- *
- * @filename: The filename to check.
- * @pattern: The pattern to compare.
- *
- * Returns true if matches, false otherwise.
- *
- * The following patterns are available.
- * \\ \ itself.
- * \ooo Octal representation of a byte.
- * \* Zero or more repetitions of characters other than '/'.
- * \@ Zero or more repetitions of characters other than '/' or '.'.
- * \? 1 byte character other than '/'.
- * \$ One or more repetitions of decimal digits.
- * \+ 1 decimal digit.
- * \X One or more repetitions of hexadecimal digits.
- * \x 1 hexadecimal digit.
- * \A One or more repetitions of alphabet characters.
- * \a 1 alphabet character.
- *
- * \- Subtraction operator.
- *
- * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
- * /dir/dir/dir/ ).
- */
-bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
- const struct tomoyo_path_info *pattern)
-{
- const char *f = filename->name;
- const char *p = pattern->name;
- const int len = pattern->const_len;
-
- /* If @pattern doesn't contain pattern, I can use strcmp(). */
- if (!pattern->is_patterned)
- return !tomoyo_pathcmp(filename, pattern);
- /* Don't compare directory and non-directory. */
- if (filename->is_dir != pattern->is_dir)
- return false;
- /* Compare the initial length without patterns. */
- if (strncmp(f, p, len))
- return false;
- f += len;
- p += len;
- return tomoyo_path_matches_pattern2(f, p);
}
/**
@@ -805,172 +175,62 @@ bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
}
/**
- * tomoyo_get_exe - Get tomoyo_realpath() of current process.
- *
- * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
- *
- * This function uses kzalloc(), so the caller must call kfree()
- * if this function didn't return NULL.
- */
-static const char *tomoyo_get_exe(void)
-{
- struct mm_struct *mm = current->mm;
- struct vm_area_struct *vma;
- const char *cp = NULL;
-
- if (!mm)
- return NULL;
- down_read(&mm->mmap_sem);
- for (vma = mm->mmap; vma; vma = vma->vm_next) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
- cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
- break;
- }
- }
- up_read(&mm->mmap_sem);
- return cp;
-}
-
-/**
- * tomoyo_get_msg - Get warning message.
- *
- * @is_enforce: Is it enforcing mode?
- *
- * Returns "ERROR" or "WARNING".
- */
-const char *tomoyo_get_msg(const bool is_enforce)
-{
- if (is_enforce)
- return "ERROR";
- else
- return "WARNING";
-}
-
-/**
- * tomoyo_check_flags - Check mode for specified functionality.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @index: The functionality to check mode.
- *
- * TOMOYO checks only process context.
- * This code disables TOMOYO's enforcement in case the function is called from
- * interrupt context.
- */
-unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
- const u8 index)
-{
- const u8 profile = domain->profile;
-
- if (WARN_ON(in_interrupt()))
- return 0;
- return tomoyo_policy_loaded && index < TOMOYO_MAX_CONTROL_INDEX
-#if TOMOYO_MAX_PROFILES != 256
- && profile < TOMOYO_MAX_PROFILES
-#endif
- && tomoyo_profile_ptr[profile] ?
- tomoyo_profile_ptr[profile]->value[index] : 0;
-}
-
-/**
- * tomoyo_verbose_mode - Check whether TOMOYO is verbose mode.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if domain policy violation warning should be printed to
- * console.
- */
-bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain)
-{
- return tomoyo_check_flags(domain, TOMOYO_VERBOSE) != 0;
-}
-
-/**
- * tomoyo_domain_quota_is_ok - Check for domain's quota.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- *
- * Returns true if the domain is not exceeded quota, false otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain)
-{
- unsigned int count = 0;
- struct tomoyo_acl_info *ptr;
-
- if (!domain)
- return true;
- list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
- switch (ptr->type) {
- struct tomoyo_path_acl *acl;
- u32 perm;
- u8 i;
- case TOMOYO_TYPE_PATH_ACL:
- acl = container_of(ptr, struct tomoyo_path_acl, head);
- perm = acl->perm | (((u32) acl->perm_high) << 16);
- for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
- if (perm & (1 << i))
- count++;
- if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
- count -= 2;
- break;
- case TOMOYO_TYPE_PATH2_ACL:
- perm = container_of(ptr, struct tomoyo_path2_acl, head)
- ->perm;
- for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
- if (perm & (1 << i))
- count++;
- break;
- }
- }
- if (count < tomoyo_check_flags(domain, TOMOYO_MAX_ACCEPT_ENTRY))
- return true;
- if (!domain->quota_warned) {
- domain->quota_warned = true;
- printk(KERN_WARNING "TOMOYO-WARNING: "
- "Domain '%s' has so many ACLs to hold. "
- "Stopped learning mode.\n", domain->domainname->name);
- }
- return false;
-}
-
-/**
* tomoyo_find_or_assign_new_profile - Create a new profile.
*
* @profile: Profile number to create.
*
* Returns pointer to "struct tomoyo_profile" on success, NULL otherwise.
*/
-static struct tomoyo_profile *tomoyo_find_or_assign_new_profile(const unsigned
- int profile)
+static struct tomoyo_profile *tomoyo_find_or_assign_new_profile
+(const unsigned int profile)
{
- struct tomoyo_profile *ptr = NULL;
- int i;
-
+ struct tomoyo_profile *ptr;
+ struct tomoyo_profile *entry;
if (profile >= TOMOYO_MAX_PROFILES)
return NULL;
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return NULL;
ptr = tomoyo_profile_ptr[profile];
if (ptr)
- goto ok;
- ptr = kmalloc(sizeof(*ptr), GFP_NOFS);
- if (!tomoyo_memory_ok(ptr)) {
- kfree(ptr);
- ptr = NULL;
- goto ok;
+ return ptr;
+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ ptr = tomoyo_profile_ptr[profile];
+ if (!ptr && tomoyo_memory_ok(entry)) {
+ ptr = entry;
+ ptr->learning = &tomoyo_default_profile.preference;
+ ptr->permissive = &tomoyo_default_profile.preference;
+ ptr->enforcing = &tomoyo_default_profile.preference;
+ ptr->default_config = TOMOYO_CONFIG_DISABLED;
+ memset(ptr->config, TOMOYO_CONFIG_USE_DEFAULT,
+ sizeof(ptr->config));
+ mb(); /* Avoid out-of-order execution. */
+ tomoyo_profile_ptr[profile] = ptr;
+ entry = NULL;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++)
- ptr->value[i] = tomoyo_control_array[i].current_value;
- mb(); /* Avoid out-of-order execution. */
- tomoyo_profile_ptr[profile] = ptr;
- ok:
mutex_unlock(&tomoyo_policy_lock);
+ out:
+ kfree(entry);
return ptr;
}
/**
- * tomoyo_write_profile - Write to profile table.
+ * tomoyo_profile - Find a profile.
+ *
+ * @profile: Profile number to find.
+ *
+ * Returns pointer to "struct tomoyo_profile".
+ */
+struct tomoyo_profile *tomoyo_profile(const u8 profile)
+{
+ struct tomoyo_profile *ptr = tomoyo_profile_ptr[profile];
+ if (!tomoyo_policy_loaded)
+ return &tomoyo_default_profile;
+ BUG_ON(!ptr);
+ return ptr;
+}
+
+/**
+ * tomoyo_write_profile - Write profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -980,64 +240,116 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
{
char *data = head->write_buf;
unsigned int i;
- unsigned int value;
+ int value;
+ int mode;
+ u8 config;
+ bool use_default = false;
char *cp;
struct tomoyo_profile *profile;
- unsigned long num;
-
- cp = strchr(data, '-');
- if (cp)
- *cp = '\0';
- if (strict_strtoul(data, 10, &num))
- return -EINVAL;
- if (cp)
+ if (sscanf(data, "PROFILE_VERSION=%u", &tomoyo_profile_version) == 1)
+ return 0;
+ i = simple_strtoul(data, &cp, 10);
+ if (data == cp) {
+ profile = &tomoyo_default_profile;
+ } else {
+ if (*cp != '-')
+ return -EINVAL;
data = cp + 1;
- profile = tomoyo_find_or_assign_new_profile(num);
- if (!profile)
- return -EINVAL;
+ profile = tomoyo_find_or_assign_new_profile(i);
+ if (!profile)
+ return -EINVAL;
+ }
cp = strchr(data, '=');
if (!cp)
return -EINVAL;
- *cp = '\0';
+ *cp++ = '\0';
+ if (profile != &tomoyo_default_profile)
+ use_default = strstr(cp, "use_default") != NULL;
+ if (strstr(cp, "verbose=yes"))
+ value = 1;
+ else if (strstr(cp, "verbose=no"))
+ value = 0;
+ else
+ value = -1;
+ if (!strcmp(data, "PREFERENCE::enforcing")) {
+ if (use_default) {
+ profile->enforcing = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->enforcing = &profile->preference;
+ if (value >= 0)
+ profile->preference.enforcing_verbose = value;
+ return 0;
+ }
+ if (!strcmp(data, "PREFERENCE::permissive")) {
+ if (use_default) {
+ profile->permissive = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->permissive = &profile->preference;
+ if (value >= 0)
+ profile->preference.permissive_verbose = value;
+ return 0;
+ }
+ if (!strcmp(data, "PREFERENCE::learning")) {
+ char *cp2;
+ if (use_default) {
+ profile->learning = &tomoyo_default_profile.preference;
+ return 0;
+ }
+ profile->learning = &profile->preference;
+ if (value >= 0)
+ profile->preference.learning_verbose = value;
+ cp2 = strstr(cp, "max_entry=");
+ if (cp2)
+ sscanf(cp2 + 10, "%u",
+ &profile->preference.learning_max_entry);
+ return 0;
+ }
+ if (profile == &tomoyo_default_profile)
+ return -EINVAL;
if (!strcmp(data, "COMMENT")) {
const struct tomoyo_path_info *old_comment = profile->comment;
- profile->comment = tomoyo_get_name(cp + 1);
+ profile->comment = tomoyo_get_name(cp);
tomoyo_put_name(old_comment);
return 0;
}
- for (i = 0; i < TOMOYO_MAX_CONTROL_INDEX; i++) {
- if (strcmp(data, tomoyo_control_array[i].keyword))
- continue;
- if (sscanf(cp + 1, "%u", &value) != 1) {
- int j;
- const char **modes;
- switch (i) {
- case TOMOYO_VERBOSE:
- modes = tomoyo_mode_2;
- break;
- default:
- modes = tomoyo_mode_4;
- break;
- }
- for (j = 0; j < 4; j++) {
- if (strcmp(cp + 1, modes[j]))
- continue;
- value = j;
- break;
- }
- if (j == 4)
- return -EINVAL;
- } else if (value > tomoyo_control_array[i].max_value) {
- value = tomoyo_control_array[i].max_value;
+ if (!strcmp(data, "CONFIG")) {
+ i = TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX;
+ config = profile->default_config;
+ } else if (tomoyo_str_starts(&data, "CONFIG::")) {
+ config = 0;
+ for (i = 0; i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+ if (strcmp(data, tomoyo_mac_keywords[i]))
+ continue;
+ config = profile->config[i];
+ break;
}
- profile->value[i] = value;
- return 0;
+ if (i == TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ return -EINVAL;
+ } else {
+ return -EINVAL;
}
- return -EINVAL;
+ if (use_default) {
+ config = TOMOYO_CONFIG_USE_DEFAULT;
+ } else {
+ for (mode = 3; mode >= 0; mode--)
+ if (strstr(cp, tomoyo_mode_4[mode]))
+ /*
+ * Update lower 3 bits in order to distinguish
+ * 'config' from 'TOMOYO_CONFIG_USE_DEAFULT'.
+ */
+ config = (config & ~7) | mode;
+ }
+ if (i < TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX)
+ profile->config[i] = config;
+ else if (config != TOMOYO_CONFIG_USE_DEFAULT)
+ profile->default_config = config;
+ return 0;
}
/**
- * tomoyo_read_profile - Read from profile table.
+ * tomoyo_read_profile - Read profile table.
*
* @head: Pointer to "struct tomoyo_io_buffer".
*
@@ -1045,53 +357,82 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer *head)
*/
static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
{
- static const int total = TOMOYO_MAX_CONTROL_INDEX + 1;
- int step;
-
+ int index;
if (head->read_eof)
return 0;
- for (step = head->read_step; step < TOMOYO_MAX_PROFILES * total;
- step++) {
- const u8 index = step / total;
- u8 type = step % total;
+ if (head->read_bit)
+ goto body;
+ tomoyo_io_printf(head, "PROFILE_VERSION=%s\n", "20090903");
+ tomoyo_io_printf(head, "PREFERENCE::learning={ verbose=%s "
+ "max_entry=%u }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ learning_verbose),
+ tomoyo_default_profile.preference.learning_max_entry);
+ tomoyo_io_printf(head, "PREFERENCE::permissive={ verbose=%s }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ permissive_verbose));
+ tomoyo_io_printf(head, "PREFERENCE::enforcing={ verbose=%s }\n",
+ tomoyo_yesno(tomoyo_default_profile.preference.
+ enforcing_verbose));
+ head->read_bit = 1;
+ body:
+ for (index = head->read_step; index < TOMOYO_MAX_PROFILES; index++) {
+ bool done;
+ u8 config;
+ int i;
+ int pos;
const struct tomoyo_profile *profile
= tomoyo_profile_ptr[index];
- head->read_step = step;
+ const struct tomoyo_path_info *comment;
+ head->read_step = index;
if (!profile)
continue;
- if (!type) { /* Print profile' comment tag. */
- if (!tomoyo_io_printf(head, "%u-COMMENT=%s\n",
- index, profile->comment ?
- profile->comment->name : ""))
- break;
- continue;
- }
- type--;
- if (type < TOMOYO_MAX_CONTROL_INDEX) {
- const unsigned int value = profile->value[type];
- const char **modes = NULL;
- const char *keyword
- = tomoyo_control_array[type].keyword;
- switch (tomoyo_control_array[type].max_value) {
- case 3:
- modes = tomoyo_mode_4;
- break;
- case 1:
- modes = tomoyo_mode_2;
- break;
- }
- if (modes) {
- if (!tomoyo_io_printf(head, "%u-%s=%s\n", index,
- keyword, modes[value]))
- break;
- } else {
- if (!tomoyo_io_printf(head, "%u-%s=%u\n", index,
- keyword, value))
- break;
- }
+ pos = head->read_avail;
+ comment = profile->comment;
+ done = tomoyo_io_printf(head, "%u-COMMENT=%s\n", index,
+ comment ? comment->name : "");
+ if (!done)
+ goto out;
+ config = profile->default_config;
+ if (!tomoyo_io_printf(head, "%u-CONFIG={ mode=%s }\n", index,
+ tomoyo_mode_4[config & 3]))
+ goto out;
+ for (i = 0; i < TOMOYO_MAX_MAC_INDEX +
+ TOMOYO_MAX_MAC_CATEGORY_INDEX; i++) {
+ config = profile->config[i];
+ if (config == TOMOYO_CONFIG_USE_DEFAULT)
+ continue;
+ if (!tomoyo_io_printf(head,
+ "%u-CONFIG::%s={ mode=%s }\n",
+ index, tomoyo_mac_keywords[i],
+ tomoyo_mode_4[config & 3]))
+ goto out;
}
+ if (profile->learning != &tomoyo_default_profile.preference &&
+ !tomoyo_io_printf(head, "%u-PREFERENCE::learning={ "
+ "verbose=%s max_entry=%u }\n", index,
+ tomoyo_yesno(profile->preference.
+ learning_verbose),
+ profile->preference.learning_max_entry))
+ goto out;
+ if (profile->permissive != &tomoyo_default_profile.preference
+ && !tomoyo_io_printf(head, "%u-PREFERENCE::permissive={ "
+ "verbose=%s }\n", index,
+ tomoyo_yesno(profile->preference.
+ permissive_verbose)))
+ goto out;
+ if (profile->enforcing != &tomoyo_default_profile.preference &&
+ !tomoyo_io_printf(head, "%u-PREFERENCE::enforcing={ "
+ "verbose=%s }\n", index,
+ tomoyo_yesno(profile->preference.
+ enforcing_verbose)))
+ goto out;
+ continue;
+ out:
+ head->read_avail = pos;
+ break;
}
- if (step == TOMOYO_MAX_PROFILES * total)
+ if (index == TOMOYO_MAX_PROFILES)
head->read_eof = true;
return 0;
}
@@ -1109,7 +450,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
*
* or
*
- * # echo '/usr/lib/ccs/editpolicy' > /sys/kernel/security/tomoyo/manager
+ * # echo '/usr/sbin/tomoyo-editpolicy' > /sys/kernel/security/tomoyo/manager
* (if you want to specify by a program's location)
*
* and is deleted by
@@ -1119,7 +460,7 @@ static int tomoyo_read_profile(struct tomoyo_io_buffer *head)
*
* or
*
- * # echo 'delete /usr/lib/ccs/editpolicy' > \
+ * # echo 'delete /usr/sbin/tomoyo-editpolicy' > \
* /sys/kernel/security/tomoyo/manager
*
* and all entries are retrieved by
@@ -1150,7 +491,7 @@ static int tomoyo_update_manager_entry(const char *manager,
return -EINVAL;
e.is_domain = true;
} else {
- if (!tomoyo_is_correct_path(manager, 1, -1, -1))
+ if (!tomoyo_is_correct_path(manager))
return -EINVAL;
}
e.manager = tomoyo_get_name(manager);
@@ -1299,12 +640,17 @@ static bool tomoyo_is_select_one(struct tomoyo_io_buffer *head,
{
unsigned int pid;
struct tomoyo_domain_info *domain = NULL;
+ bool global_pid = false;
- if (sscanf(data, "pid=%u", &pid) == 1) {
+ if (sscanf(data, "pid=%u", &pid) == 1 ||
+ (global_pid = true, sscanf(data, "global-pid=%u", &pid) == 1)) {
struct task_struct *p;
rcu_read_lock();
read_lock(&tasklist_lock);
- p = find_task_by_vpid(pid);
+ if (global_pid)
+ p = find_task_by_pid_ns(pid, &init_pid_ns);
+ else
+ p = find_task_by_vpid(pid);
if (p)
domain = tomoyo_real_domain(p);
read_unlock(&tasklist_lock);
@@ -1373,6 +719,24 @@ static int tomoyo_delete_domain(char *domainname)
}
/**
+ * tomoyo_write_domain_policy2 - Write domain policy.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_write_domain_policy2(char *data,
+ struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_MOUNT))
+ return tomoyo_write_mount_policy(data, domain, is_delete);
+ return tomoyo_write_file_policy(data, domain, is_delete);
+}
+
+/**
* tomoyo_write_domain_policy - Write domain policy.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1422,7 +786,15 @@ static int tomoyo_write_domain_policy(struct tomoyo_io_buffer *head)
domain->ignore_global_allow_read = !is_delete;
return 0;
}
- return tomoyo_write_file_policy(data, domain, is_delete);
+ if (!strcmp(data, TOMOYO_KEYWORD_QUOTA_EXCEEDED)) {
+ domain->quota_warned = !is_delete;
+ return 0;
+ }
+ if (!strcmp(data, TOMOYO_KEYWORD_TRANSITION_FAILED)) {
+ domain->transition_failed = !is_delete;
+ return 0;
+ }
+ return tomoyo_write_domain_policy2(data, domain, is_delete);
}
/**
@@ -1438,7 +810,7 @@ static bool tomoyo_print_path_acl(struct tomoyo_io_buffer *head,
{
int pos;
u8 bit;
- const u32 perm = ptr->perm | (((u32) ptr->perm_high) << 16);
+ const u16 perm = ptr->perm;
for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_OPERATION; bit++) {
if (!(perm & (1 << bit)))
@@ -1497,6 +869,102 @@ static bool tomoyo_print_path2_acl(struct tomoyo_io_buffer *head,
}
/**
+ * tomoyo_print_path_number_acl - Print a path_number ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_path_number_acl".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_path_number_acl(struct tomoyo_io_buffer *head,
+ struct tomoyo_path_number_acl *ptr)
+{
+ int pos;
+ u8 bit;
+ const u8 perm = ptr->perm;
+ for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER_OPERATION;
+ bit++) {
+ if (!(perm & (1 << bit)))
+ continue;
+ pos = head->read_avail;
+ if (!tomoyo_io_printf(head, "allow_%s",
+ tomoyo_path_number2keyword(bit)) ||
+ !tomoyo_print_name_union(head, &ptr->name) ||
+ !tomoyo_print_number_union(head, &ptr->number) ||
+ !tomoyo_io_printf(head, "\n"))
+ goto out;
+ }
+ head->read_bit = 0;
+ return true;
+ out:
+ head->read_bit = bit;
+ head->read_avail = pos;
+ return false;
+}
+
+/**
+ * tomoyo_print_path_number3_acl - Print a path_number3 ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_path_number3_acl".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_path_number3_acl(struct tomoyo_io_buffer *head,
+ struct tomoyo_path_number3_acl *ptr)
+{
+ int pos;
+ u8 bit;
+ const u16 perm = ptr->perm;
+ for (bit = head->read_bit; bit < TOMOYO_MAX_PATH_NUMBER3_OPERATION;
+ bit++) {
+ if (!(perm & (1 << bit)))
+ continue;
+ pos = head->read_avail;
+ if (!tomoyo_io_printf(head, "allow_%s",
+ tomoyo_path_number32keyword(bit)) ||
+ !tomoyo_print_name_union(head, &ptr->name) ||
+ !tomoyo_print_number_union(head, &ptr->mode) ||
+ !tomoyo_print_number_union(head, &ptr->major) ||
+ !tomoyo_print_number_union(head, &ptr->minor) ||
+ !tomoyo_io_printf(head, "\n"))
+ goto out;
+ }
+ head->read_bit = 0;
+ return true;
+ out:
+ head->read_bit = bit;
+ head->read_avail = pos;
+ return false;
+}
+
+/**
+ * tomoyo_print_mount_acl - Print a mount ACL entry.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ * @ptr: Pointer to "struct tomoyo_mount_acl".
+ *
+ * Returns true on success, false otherwise.
+ */
+static bool tomoyo_print_mount_acl(struct tomoyo_io_buffer *head,
+ struct tomoyo_mount_acl *ptr)
+{
+ const int pos = head->read_avail;
+ if (ptr->is_deleted)
+ return true;
+ if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_ALLOW_MOUNT) ||
+ !tomoyo_print_name_union(head, &ptr->dev_name) ||
+ !tomoyo_print_name_union(head, &ptr->dir_name) ||
+ !tomoyo_print_name_union(head, &ptr->fs_type) ||
+ !tomoyo_print_number_union(head, &ptr->flags) ||
+ !tomoyo_io_printf(head, "\n")) {
+ head->read_avail = pos;
+ return false;
+ }
+ return true;
+}
+
+/**
* tomoyo_print_entry - Print an ACL entry.
*
* @head: Pointer to "struct tomoyo_io_buffer".
@@ -1519,6 +987,23 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head,
= container_of(ptr, struct tomoyo_path2_acl, head);
return tomoyo_print_path2_acl(head, acl);
}
+ if (acl_type == TOMOYO_TYPE_PATH_NUMBER_ACL) {
+ struct tomoyo_path_number_acl *acl
+ = container_of(ptr, struct tomoyo_path_number_acl,
+ head);
+ return tomoyo_print_path_number_acl(head, acl);
+ }
+ if (acl_type == TOMOYO_TYPE_PATH_NUMBER3_ACL) {
+ struct tomoyo_path_number3_acl *acl
+ = container_of(ptr, struct tomoyo_path_number3_acl,
+ head);
+ return tomoyo_print_path_number3_acl(head, acl);
+ }
+ if (acl_type == TOMOYO_TYPE_MOUNT_ACL) {
+ struct tomoyo_mount_acl *acl
+ = container_of(ptr, struct tomoyo_mount_acl, head);
+ return tomoyo_print_mount_acl(head, acl);
+ }
BUG(); /* This must not happen. */
return false;
}
@@ -1607,7 +1092,7 @@ tail_mark:
* This is equivalent to doing
*
* ( echo "select " $domainname; echo "use_profile " $profile ) |
- * /usr/lib/ccs/loadpolicy -d
+ * /usr/sbin/tomoyo-loadpolicy -d
*
* Caller holds tomoyo_read_lock().
*/
@@ -1740,6 +1225,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN))
return tomoyo_write_domain_initializer_policy(data, true,
is_delete);
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_AGGREGATOR))
+ return tomoyo_write_aggregator_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALIAS))
return tomoyo_write_alias_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_ALLOW_READ))
@@ -1750,6 +1237,8 @@ static int tomoyo_write_exception_policy(struct tomoyo_io_buffer *head)
return tomoyo_write_no_rewrite_policy(data, is_delete);
if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_PATH_GROUP))
return tomoyo_write_path_group_policy(data, is_delete);
+ if (tomoyo_str_starts(&data, TOMOYO_KEYWORD_NUMBER_GROUP))
+ return tomoyo_write_number_group_policy(data, is_delete);
return -EINVAL;
}
@@ -1793,6 +1282,8 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
head->read_var2 = NULL;
head->read_step = 6;
case 6:
+ if (!tomoyo_read_aggregator_policy(head))
+ break;
head->read_var2 = NULL;
head->read_step = 7;
case 7:
@@ -1812,6 +1303,12 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
head->read_var2 = NULL;
head->read_step = 10;
case 10:
+ if (!tomoyo_read_number_group_policy(head))
+ break;
+ head->read_var1 = NULL;
+ head->read_var2 = NULL;
+ head->read_step = 11;
+ case 11:
head->read_eof = true;
break;
default:
@@ -1821,89 +1318,355 @@ static int tomoyo_read_exception_policy(struct tomoyo_io_buffer *head)
return 0;
}
-/* path to policy loader */
-static const char *tomoyo_loader = "/sbin/tomoyo-init";
+/**
+ * tomoyo_print_header - Get header line of audit log.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns string representation.
+ *
+ * This function uses kmalloc(), so caller must kfree() if this function
+ * didn't return NULL.
+ */
+static char *tomoyo_print_header(struct tomoyo_request_info *r)
+{
+ static const char *tomoyo_mode_4[4] = {
+ "disabled", "learning", "permissive", "enforcing"
+ };
+ struct timeval tv;
+ const pid_t gpid = task_pid_nr(current);
+ static const int tomoyo_buffer_len = 4096;
+ char *buffer = kmalloc(tomoyo_buffer_len, GFP_NOFS);
+ if (!buffer)
+ return NULL;
+ do_gettimeofday(&tv);
+ snprintf(buffer, tomoyo_buffer_len - 1,
+ "#timestamp=%lu profile=%u mode=%s (global-pid=%u)"
+ " task={ pid=%u ppid=%u uid=%u gid=%u euid=%u"
+ " egid=%u suid=%u sgid=%u fsuid=%u fsgid=%u }",
+ tv.tv_sec, r->profile, tomoyo_mode_4[r->mode], gpid,
+ (pid_t) sys_getpid(), (pid_t) sys_getppid(),
+ current_uid(), current_gid(), current_euid(),
+ current_egid(), current_suid(), current_sgid(),
+ current_fsuid(), current_fsgid());
+ return buffer;
+}
/**
- * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ * tomoyo_init_audit_log - Allocate buffer for audit logs.
+ *
+ * @len: Required size.
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns pointer to allocated memory.
*
- * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ * The @len is updated to add the header lines' size on success.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
*/
-static bool tomoyo_policy_loader_exists(void)
+static char *tomoyo_init_audit_log(int *len, struct tomoyo_request_info *r)
{
- /*
- * Don't activate MAC if the policy loader doesn't exist.
- * If the initrd includes /sbin/init but real-root-dev has not
- * mounted on / yet, activating MAC will block the system since
- * policies are not loaded yet.
- * Thus, let do_execve() call this function everytime.
- */
- struct path path;
+ char *buf = NULL;
+ const char *header;
+ const char *domainname;
+ if (!r->domain)
+ r->domain = tomoyo_domain();
+ domainname = r->domain->domainname->name;
+ header = tomoyo_print_header(r);
+ if (!header)
+ return NULL;
+ *len += strlen(domainname) + strlen(header) + 10;
+ buf = kzalloc(*len, GFP_NOFS);
+ if (buf)
+ snprintf(buf, (*len) - 1, "%s\n%s\n", header, domainname);
+ kfree(header);
+ return buf;
+}
- if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
- printk(KERN_INFO "Not activating Mandatory Access Control now "
- "since %s doesn't exist.\n", tomoyo_loader);
- return false;
+/* Wait queue for tomoyo_query_list. */
+static DECLARE_WAIT_QUEUE_HEAD(tomoyo_query_wait);
+
+/* Lock for manipulating tomoyo_query_list. */
+static DEFINE_SPINLOCK(tomoyo_query_list_lock);
+
+/* Structure for query. */
+struct tomoyo_query_entry {
+ struct list_head list;
+ char *query;
+ int query_len;
+ unsigned int serial;
+ int timer;
+ int answer;
+};
+
+/* The list for "struct tomoyo_query_entry". */
+static LIST_HEAD(tomoyo_query_list);
+
+/*
+ * Number of "struct file" referring /sys/kernel/security/tomoyo/query
+ * interface.
+ */
+static atomic_t tomoyo_query_observers = ATOMIC_INIT(0);
+
+/**
+ * tomoyo_supervisor - Ask for the supervisor's decision.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ *
+ * Returns 0 if the supervisor decided to permit the access request which
+ * violated the policy in enforcing mode, TOMOYO_RETRY_REQUEST if the
+ * supervisor decided to retry the access request which violated the policy in
+ * enforcing mode, 0 if it is not in enforcing mode, -EPERM otherwise.
+ */
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+ va_list args;
+ int error = -EPERM;
+ int pos;
+ int len;
+ static unsigned int tomoyo_serial;
+ struct tomoyo_query_entry *tomoyo_query_entry = NULL;
+ bool quota_exceeded = false;
+ char *header;
+ switch (r->mode) {
+ char *buffer;
+ case TOMOYO_CONFIG_LEARNING:
+ if (!tomoyo_domain_quota_is_ok(r))
+ return 0;
+ va_start(args, fmt);
+ len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 4;
+ va_end(args);
+ buffer = kmalloc(len, GFP_NOFS);
+ if (!buffer)
+ return 0;
+ va_start(args, fmt);
+ vsnprintf(buffer, len - 1, fmt, args);
+ va_end(args);
+ tomoyo_normalize_line(buffer);
+ tomoyo_write_domain_policy2(buffer, r->domain, false);
+ kfree(buffer);
+ /* fall through */
+ case TOMOYO_CONFIG_PERMISSIVE:
+ return 0;
}
- path_put(&path);
- return true;
+ if (!r->domain)
+ r->domain = tomoyo_domain();
+ if (!atomic_read(&tomoyo_query_observers))
+ return -EPERM;
+ va_start(args, fmt);
+ len = vsnprintf((char *) &pos, sizeof(pos) - 1, fmt, args) + 32;
+ va_end(args);
+ header = tomoyo_init_audit_log(&len, r);
+ if (!header)
+ goto out;
+ tomoyo_query_entry = kzalloc(sizeof(*tomoyo_query_entry), GFP_NOFS);
+ if (!tomoyo_query_entry)
+ goto out;
+ tomoyo_query_entry->query = kzalloc(len, GFP_NOFS);
+ if (!tomoyo_query_entry->query)
+ goto out;
+ len = ksize(tomoyo_query_entry->query);
+ INIT_LIST_HEAD(&tomoyo_query_entry->list);
+ spin_lock(&tomoyo_query_list_lock);
+ if (tomoyo_quota_for_query && tomoyo_query_memory_size + len +
+ sizeof(*tomoyo_query_entry) >= tomoyo_quota_for_query) {
+ quota_exceeded = true;
+ } else {
+ tomoyo_query_memory_size += len + sizeof(*tomoyo_query_entry);
+ tomoyo_query_entry->serial = tomoyo_serial++;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (quota_exceeded)
+ goto out;
+ pos = snprintf(tomoyo_query_entry->query, len - 1, "Q%u-%hu\n%s",
+ tomoyo_query_entry->serial, r->retry, header);
+ kfree(header);
+ header = NULL;
+ va_start(args, fmt);
+ vsnprintf(tomoyo_query_entry->query + pos, len - 1 - pos, fmt, args);
+ tomoyo_query_entry->query_len = strlen(tomoyo_query_entry->query) + 1;
+ va_end(args);
+ spin_lock(&tomoyo_query_list_lock);
+ list_add_tail(&tomoyo_query_entry->list, &tomoyo_query_list);
+ spin_unlock(&tomoyo_query_list_lock);
+ /* Give 10 seconds for supervisor's opinion. */
+ for (tomoyo_query_entry->timer = 0;
+ atomic_read(&tomoyo_query_observers) && tomoyo_query_entry->timer < 100;
+ tomoyo_query_entry->timer++) {
+ wake_up(&tomoyo_query_wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ / 10);
+ if (tomoyo_query_entry->answer)
+ break;
+ }
+ spin_lock(&tomoyo_query_list_lock);
+ list_del(&tomoyo_query_entry->list);
+ tomoyo_query_memory_size -= len + sizeof(*tomoyo_query_entry);
+ spin_unlock(&tomoyo_query_list_lock);
+ switch (tomoyo_query_entry->answer) {
+ case 3: /* Asked to retry by administrator. */
+ error = TOMOYO_RETRY_REQUEST;
+ r->retry++;
+ break;
+ case 1:
+ /* Granted by administrator. */
+ error = 0;
+ break;
+ case 0:
+ /* Timed out. */
+ break;
+ default:
+ /* Rejected by administrator. */
+ break;
+ }
+ out:
+ if (tomoyo_query_entry)
+ kfree(tomoyo_query_entry->query);
+ kfree(tomoyo_query_entry);
+ kfree(header);
+ return error;
}
/**
- * tomoyo_load_policy - Run external policy loader to load policy.
+ * tomoyo_poll_query - poll() for /sys/kernel/security/tomoyo/query.
*
- * @filename: The program about to start.
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
*
- * This function checks whether @filename is /sbin/init , and if so
- * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
- * and then continues invocation of /sbin/init.
- * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
- * writes to /sys/kernel/security/tomoyo/ interfaces.
+ * Returns POLLIN | POLLRDNORM when ready to read, 0 otherwise.
*
- * Returns nothing.
+ * Waits for access requests which violated policy in enforcing mode.
*/
-void tomoyo_load_policy(const char *filename)
+static int tomoyo_poll_query(struct file *file, poll_table *wait)
{
- char *argv[2];
- char *envp[3];
-
- if (tomoyo_policy_loaded)
- return;
- /*
- * Check filename is /sbin/init or /sbin/tomoyo-start.
- * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
- * be passed.
- * You can create /sbin/tomoyo-start by
- * "ln -s /bin/true /sbin/tomoyo-start".
- */
- if (strcmp(filename, "/sbin/init") &&
- strcmp(filename, "/sbin/tomoyo-start"))
- return;
- if (!tomoyo_policy_loader_exists())
- return;
-
- printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
- tomoyo_loader);
- argv[0] = (char *) tomoyo_loader;
- argv[1] = NULL;
- envp[0] = "HOME=/";
- envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
- envp[2] = NULL;
- call_usermodehelper(argv[0], argv, envp, 1);
-
- printk(KERN_INFO "TOMOYO: 2.2.0 2009/04/01\n");
- printk(KERN_INFO "Mandatory Access Control activated.\n");
- tomoyo_policy_loaded = true;
- { /* Check all profiles currently assigned to domains are defined. */
- struct tomoyo_domain_info *domain;
- list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
- const u8 profile = domain->profile;
- if (tomoyo_profile_ptr[profile])
+ struct list_head *tmp;
+ bool found = false;
+ u8 i;
+ for (i = 0; i < 2; i++) {
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query_entry *ptr
+ = list_entry(tmp, struct tomoyo_query_entry,
+ list);
+ if (ptr->answer)
continue;
- panic("Profile %u (used by '%s') not defined.\n",
- profile, domain->domainname->name);
+ found = true;
+ break;
}
+ spin_unlock(&tomoyo_query_list_lock);
+ if (found)
+ return POLLIN | POLLRDNORM;
+ if (i)
+ break;
+ poll_wait(file, &tomoyo_query_wait, wait);
+ }
+ return 0;
+}
+
+/**
+ * tomoyo_read_query - Read access requests which violated policy in enforcing mode.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+static int tomoyo_read_query(struct tomoyo_io_buffer *head)
+{
+ struct list_head *tmp;
+ int pos = 0;
+ int len = 0;
+ char *buf;
+ if (head->read_avail)
+ return 0;
+ if (head->read_buf) {
+ kfree(head->read_buf);
+ head->read_buf = NULL;
+ head->readbuf_size = 0;
+ }
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query_entry *ptr
+ = list_entry(tmp, struct tomoyo_query_entry, list);
+ if (ptr->answer)
+ continue;
+ if (pos++ != head->read_step)
+ continue;
+ len = ptr->query_len;
+ break;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (!len) {
+ head->read_step = 0;
+ return 0;
+ }
+ buf = kzalloc(len, GFP_NOFS);
+ if (!buf)
+ return 0;
+ pos = 0;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query_entry *ptr
+ = list_entry(tmp, struct tomoyo_query_entry, list);
+ if (ptr->answer)
+ continue;
+ if (pos++ != head->read_step)
+ continue;
+ /*
+ * Some query can be skipped because tomoyo_query_list
+ * can change, but I don't care.
+ */
+ if (len == ptr->query_len)
+ memmove(buf, ptr->query, len);
+ break;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (buf[0]) {
+ head->read_avail = len;
+ head->readbuf_size = head->read_avail;
+ head->read_buf = buf;
+ head->read_step++;
+ } else {
+ kfree(buf);
+ }
+ return 0;
+}
+
+/**
+ * tomoyo_write_answer - Write the supervisor's decision.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int tomoyo_write_answer(struct tomoyo_io_buffer *head)
+{
+ char *data = head->write_buf;
+ struct list_head *tmp;
+ unsigned int serial;
+ unsigned int answer;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query_entry *ptr
+ = list_entry(tmp, struct tomoyo_query_entry, list);
+ ptr->timer = 0;
+ }
+ spin_unlock(&tomoyo_query_list_lock);
+ if (sscanf(data, "A%u=%u", &serial, &answer) != 2)
+ return -EINVAL;
+ spin_lock(&tomoyo_query_list_lock);
+ list_for_each(tmp, &tomoyo_query_list) {
+ struct tomoyo_query_entry *ptr
+ = list_entry(tmp, struct tomoyo_query_entry, list);
+ if (ptr->serial != serial)
+ continue;
+ if (!ptr->answer)
+ ptr->answer = answer;
+ break;
}
+ spin_unlock(&tomoyo_query_list_lock);
+ return 0;
}
/**
@@ -1916,7 +1679,7 @@ void tomoyo_load_policy(const char *filename)
static int tomoyo_read_version(struct tomoyo_io_buffer *head)
{
if (!head->read_eof) {
- tomoyo_io_printf(head, "2.2.0");
+ tomoyo_io_printf(head, "2.3.0-pre");
head->read_eof = true;
}
return 0;
@@ -1953,13 +1716,14 @@ static int tomoyo_read_self_domain(struct tomoyo_io_buffer *head)
*
* Caller acquires tomoyo_read_lock().
*/
-static int tomoyo_open_control(const u8 type, struct file *file)
+int tomoyo_open_control(const u8 type, struct file *file)
{
struct tomoyo_io_buffer *head = kzalloc(sizeof(*head), GFP_NOFS);
if (!head)
return -ENOMEM;
mutex_init(&head->io_sem);
+ head->type = type;
switch (type) {
case TOMOYO_DOMAINPOLICY:
/* /sys/kernel/security/tomoyo/domain_policy */
@@ -2001,6 +1765,11 @@ static int tomoyo_open_control(const u8 type, struct file *file)
head->write = tomoyo_write_profile;
head->read = tomoyo_read_profile;
break;
+ case TOMOYO_QUERY: /* /sys/kernel/security/tomoyo/query */
+ head->poll = tomoyo_poll_query;
+ head->write = tomoyo_write_answer;
+ head->read = tomoyo_read_query;
+ break;
case TOMOYO_MANAGER:
/* /sys/kernel/security/tomoyo/manager */
head->write = tomoyo_write_manager_policy;
@@ -2013,7 +1782,9 @@ static int tomoyo_open_control(const u8 type, struct file *file)
* for reading.
*/
head->read = NULL;
- } else {
+ head->poll = NULL;
+ } else if (!head->poll) {
+ /* Don't allocate read_buf for poll() access. */
if (!head->readbuf_size)
head->readbuf_size = 4096 * 2;
head->read_buf = kzalloc(head->readbuf_size, GFP_NOFS);
@@ -2037,7 +1808,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
return -ENOMEM;
}
}
- head->reader_idx = tomoyo_read_lock();
+ if (type != TOMOYO_QUERY)
+ head->reader_idx = tomoyo_read_lock();
file->private_data = head;
/*
* Call the handler now if the file is
@@ -2048,10 +1820,35 @@ static int tomoyo_open_control(const u8 type, struct file *file)
*/
if (type == TOMOYO_SELFDOMAIN)
tomoyo_read_control(file, NULL, 0);
+ /*
+ * If the file is /sys/kernel/security/tomoyo/query , increment the
+ * observer counter.
+ * The obserber counter is used by tomoyo_supervisor() to see if
+ * there is some process monitoring /sys/kernel/security/tomoyo/query.
+ */
+ else if (type == TOMOYO_QUERY)
+ atomic_inc(&tomoyo_query_observers);
return 0;
}
/**
+ * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @wait: Pointer to "poll_table".
+ *
+ * Waits for read readiness.
+ * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd .
+ */
+int tomoyo_poll_control(struct file *file, poll_table *wait)
+{
+ struct tomoyo_io_buffer *head = file->private_data;
+ if (!head->poll)
+ return -ENOSYS;
+ return head->poll(file, wait);
+}
+
+/**
* tomoyo_read_control - read() for /sys/kernel/security/tomoyo/ interface.
*
* @file: Pointer to "struct file".
@@ -2062,8 +1859,8 @@ static int tomoyo_open_control(const u8 type, struct file *file)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_read_control(struct file *file, char __user *buffer,
- const int buffer_len)
+int tomoyo_read_control(struct file *file, char __user *buffer,
+ const int buffer_len)
{
int len = 0;
struct tomoyo_io_buffer *head = file->private_data;
@@ -2107,8 +1904,8 @@ static int tomoyo_read_control(struct file *file, char __user *buffer,
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_write_control(struct file *file, const char __user *buffer,
- const int buffer_len)
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+ const int buffer_len)
{
struct tomoyo_io_buffer *head = file->private_data;
int error = buffer_len;
@@ -2159,12 +1956,19 @@ static int tomoyo_write_control(struct file *file, const char __user *buffer,
*
* Caller looses tomoyo_read_lock().
*/
-static int tomoyo_close_control(struct file *file)
+int tomoyo_close_control(struct file *file)
{
struct tomoyo_io_buffer *head = file->private_data;
const bool is_write = !!head->write_buf;
- tomoyo_read_unlock(head->reader_idx);
+ /*
+ * If the file is /sys/kernel/security/tomoyo/query , decrement the
+ * observer counter.
+ */
+ if (head->type == TOMOYO_QUERY)
+ atomic_dec(&tomoyo_query_observers);
+ else
+ tomoyo_read_unlock(head->reader_idx);
/* Release memory used for policy I/O. */
kfree(head->read_buf);
head->read_buf = NULL;
@@ -2179,129 +1983,25 @@ static int tomoyo_close_control(struct file *file)
}
/**
- * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file: Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_open(struct inode *inode, struct file *file)
-{
- const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
- - ((u8 *) NULL);
- return tomoyo_open_control(key, file);
-}
-
-/**
- * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
- *
- * @inode: Pointer to "struct inode".
- * @file: Pointer to "struct file".
- *
- * Returns 0 on success, negative value otherwise.
- */
-static int tomoyo_release(struct inode *inode, struct file *file)
-{
- return tomoyo_close_control(file);
-}
-
-/**
- * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file: Pointer to "struct file".
- * @buf: Pointer to buffer.
- * @count: Size of @buf.
- * @ppos: Unused.
- *
- * Returns bytes read on success, negative value otherwise.
- */
-static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
- loff_t *ppos)
-{
- return tomoyo_read_control(file, buf, count);
-}
-
-/**
- * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
- *
- * @file: Pointer to "struct file".
- * @buf: Pointer to buffer.
- * @count: Size of @buf.
- * @ppos: Unused.
- *
- * Returns @count on success, negative value otherwise.
- */
-static ssize_t tomoyo_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- return tomoyo_write_control(file, buf, count);
-}
-
-/*
- * tomoyo_operations is a "struct file_operations" which is used for handling
- * /sys/kernel/security/tomoyo/ interface.
- *
- * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
- * See tomoyo_io_buffer for internals.
- */
-static const struct file_operations tomoyo_operations = {
- .open = tomoyo_open,
- .release = tomoyo_release,
- .read = tomoyo_read,
- .write = tomoyo_write,
-};
-
-/**
- * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
- *
- * @name: The name of the interface file.
- * @mode: The permission of the interface file.
- * @parent: The parent directory.
- * @key: Type of interface.
- *
- * Returns nothing.
- */
-static void __init tomoyo_create_entry(const char *name, const mode_t mode,
- struct dentry *parent, const u8 key)
-{
- securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
- &tomoyo_operations);
-}
-
-/**
- * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
- *
- * Returns 0.
+ * tomoyo_check_profile - Check all profiles currently assigned to domains are defined.
*/
-static int __init tomoyo_initerface_init(void)
+void tomoyo_check_profile(void)
{
- struct dentry *tomoyo_dir;
-
- /* Don't create securityfs entries unless registered. */
- if (current_cred()->security != &tomoyo_kernel_domain)
- return 0;
-
- tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
- tomoyo_create_entry("domain_policy", 0600, tomoyo_dir,
- TOMOYO_DOMAINPOLICY);
- tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
- TOMOYO_EXCEPTIONPOLICY);
- tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
- TOMOYO_SELFDOMAIN);
- tomoyo_create_entry(".domain_status", 0600, tomoyo_dir,
- TOMOYO_DOMAIN_STATUS);
- tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
- TOMOYO_PROCESS_STATUS);
- tomoyo_create_entry("meminfo", 0600, tomoyo_dir,
- TOMOYO_MEMINFO);
- tomoyo_create_entry("profile", 0600, tomoyo_dir,
- TOMOYO_PROFILE);
- tomoyo_create_entry("manager", 0600, tomoyo_dir,
- TOMOYO_MANAGER);
- tomoyo_create_entry("version", 0400, tomoyo_dir,
- TOMOYO_VERSION);
- return 0;
+ struct tomoyo_domain_info *domain;
+ const int idx = tomoyo_read_lock();
+ tomoyo_policy_loaded = true;
+ /* Check all profiles currently assigned to domains are defined. */
+ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+ const u8 profile = domain->profile;
+ if (tomoyo_profile_ptr[profile])
+ continue;
+ panic("Profile %u (used by '%s') not defined.\n",
+ profile, domain->domainname->name);
+ }
+ tomoyo_read_unlock(idx);
+ if (tomoyo_profile_version != 20090903)
+ panic("Profile version %u is not supported.\n",
+ tomoyo_profile_version);
+ printk(KERN_INFO "TOMOYO: 2.3.0-pre 2010/06/03\n");
+ printk(KERN_INFO "Mandatory Access Control activated.\n");
}
-
-fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h
index 9f1ae5e3ba51..c777c594a00b 100644
--- a/security/tomoyo/common.h
+++ b/security/tomoyo/common.h
@@ -20,6 +20,7 @@
#include <linux/mount.h>
#include <linux/list.h>
#include <linux/cred.h>
+#include <linux/poll.h>
struct linux_binprm;
/********** Constants definitions. **********/
@@ -32,20 +33,23 @@ struct linux_binprm;
#define TOMOYO_HASH_BITS 8
#define TOMOYO_MAX_HASH (1u<<TOMOYO_HASH_BITS)
-/*
- * This is the max length of a token.
- *
- * A token consists of only ASCII printable characters.
- * Non printable characters in a token is represented in \ooo style
- * octal string. Thus, \ itself is represented as \\.
- */
-#define TOMOYO_MAX_PATHNAME_LEN 4000
+#define TOMOYO_EXEC_TMPSIZE 4096
/* Profile number is an integer between 0 and 255. */
#define TOMOYO_MAX_PROFILES 256
+enum tomoyo_mode_index {
+ TOMOYO_CONFIG_DISABLED,
+ TOMOYO_CONFIG_LEARNING,
+ TOMOYO_CONFIG_PERMISSIVE,
+ TOMOYO_CONFIG_ENFORCING,
+ TOMOYO_CONFIG_USE_DEFAULT = 255
+};
+
/* Keywords for ACLs. */
+#define TOMOYO_KEYWORD_AGGREGATOR "aggregator "
#define TOMOYO_KEYWORD_ALIAS "alias "
+#define TOMOYO_KEYWORD_ALLOW_MOUNT "allow_mount "
#define TOMOYO_KEYWORD_ALLOW_READ "allow_read "
#define TOMOYO_KEYWORD_DELETE "delete "
#define TOMOYO_KEYWORD_DENY_REWRITE "deny_rewrite "
@@ -55,36 +59,42 @@ struct linux_binprm;
#define TOMOYO_KEYWORD_NO_INITIALIZE_DOMAIN "no_initialize_domain "
#define TOMOYO_KEYWORD_NO_KEEP_DOMAIN "no_keep_domain "
#define TOMOYO_KEYWORD_PATH_GROUP "path_group "
+#define TOMOYO_KEYWORD_NUMBER_GROUP "number_group "
#define TOMOYO_KEYWORD_SELECT "select "
#define TOMOYO_KEYWORD_USE_PROFILE "use_profile "
#define TOMOYO_KEYWORD_IGNORE_GLOBAL_ALLOW_READ "ignore_global_allow_read"
+#define TOMOYO_KEYWORD_QUOTA_EXCEEDED "quota_exceeded"
+#define TOMOYO_KEYWORD_TRANSITION_FAILED "transition_failed"
/* A domain definition starts with <kernel>. */
#define TOMOYO_ROOT_NAME "<kernel>"
#define TOMOYO_ROOT_NAME_LEN (sizeof(TOMOYO_ROOT_NAME) - 1)
-/* Index numbers for Access Controls. */
-enum tomoyo_mac_index {
- TOMOYO_MAC_FOR_FILE, /* domain_policy.conf */
- TOMOYO_MAX_ACCEPT_ENTRY,
- TOMOYO_VERBOSE,
- TOMOYO_MAX_CONTROL_INDEX
-};
+/* Value type definition. */
+#define TOMOYO_VALUE_TYPE_INVALID 0
+#define TOMOYO_VALUE_TYPE_DECIMAL 1
+#define TOMOYO_VALUE_TYPE_OCTAL 2
+#define TOMOYO_VALUE_TYPE_HEXADECIMAL 3
/* Index numbers for Access Controls. */
enum tomoyo_acl_entry_type_index {
TOMOYO_TYPE_PATH_ACL,
TOMOYO_TYPE_PATH2_ACL,
+ TOMOYO_TYPE_PATH_NUMBER_ACL,
+ TOMOYO_TYPE_PATH_NUMBER3_ACL,
+ TOMOYO_TYPE_MOUNT_ACL,
};
/* Index numbers for File Controls. */
/*
- * TYPE_READ_WRITE_ACL is special. TYPE_READ_WRITE_ACL is automatically set
- * if both TYPE_READ_ACL and TYPE_WRITE_ACL are set. Both TYPE_READ_ACL and
- * TYPE_WRITE_ACL are automatically set if TYPE_READ_WRITE_ACL is set.
- * TYPE_READ_WRITE_ACL is automatically cleared if either TYPE_READ_ACL or
- * TYPE_WRITE_ACL is cleared. Both TYPE_READ_ACL and TYPE_WRITE_ACL are
- * automatically cleared if TYPE_READ_WRITE_ACL is cleared.
+ * TOMOYO_TYPE_READ_WRITE is special. TOMOYO_TYPE_READ_WRITE is automatically
+ * set if both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are set.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically set if
+ * TOMOYO_TYPE_READ_WRITE is set.
+ * TOMOYO_TYPE_READ_WRITE is automatically cleared if either TOMOYO_TYPE_READ
+ * or TOMOYO_TYPE_WRITE is cleared.
+ * Both TOMOYO_TYPE_READ and TOMOYO_TYPE_WRITE are automatically cleared if
+ * TOMOYO_TYPE_READ_WRITE is cleared.
*/
enum tomoyo_path_acl_index {
@@ -92,27 +102,22 @@ enum tomoyo_path_acl_index {
TOMOYO_TYPE_EXECUTE,
TOMOYO_TYPE_READ,
TOMOYO_TYPE_WRITE,
- TOMOYO_TYPE_CREATE,
TOMOYO_TYPE_UNLINK,
- TOMOYO_TYPE_MKDIR,
TOMOYO_TYPE_RMDIR,
- TOMOYO_TYPE_MKFIFO,
- TOMOYO_TYPE_MKSOCK,
- TOMOYO_TYPE_MKBLOCK,
- TOMOYO_TYPE_MKCHAR,
TOMOYO_TYPE_TRUNCATE,
TOMOYO_TYPE_SYMLINK,
TOMOYO_TYPE_REWRITE,
- TOMOYO_TYPE_IOCTL,
- TOMOYO_TYPE_CHMOD,
- TOMOYO_TYPE_CHOWN,
- TOMOYO_TYPE_CHGRP,
TOMOYO_TYPE_CHROOT,
- TOMOYO_TYPE_MOUNT,
TOMOYO_TYPE_UMOUNT,
TOMOYO_MAX_PATH_OPERATION
};
+enum tomoyo_path_number3_acl_index {
+ TOMOYO_TYPE_MKBLOCK,
+ TOMOYO_TYPE_MKCHAR,
+ TOMOYO_MAX_PATH_NUMBER3_OPERATION
+};
+
enum tomoyo_path2_acl_index {
TOMOYO_TYPE_LINK,
TOMOYO_TYPE_RENAME,
@@ -120,6 +125,18 @@ enum tomoyo_path2_acl_index {
TOMOYO_MAX_PATH2_OPERATION
};
+enum tomoyo_path_number_acl_index {
+ TOMOYO_TYPE_CREATE,
+ TOMOYO_TYPE_MKDIR,
+ TOMOYO_TYPE_MKFIFO,
+ TOMOYO_TYPE_MKSOCK,
+ TOMOYO_TYPE_IOCTL,
+ TOMOYO_TYPE_CHMOD,
+ TOMOYO_TYPE_CHOWN,
+ TOMOYO_TYPE_CHGRP,
+ TOMOYO_MAX_PATH_NUMBER_OPERATION
+};
+
enum tomoyo_securityfs_interface_index {
TOMOYO_DOMAINPOLICY,
TOMOYO_EXCEPTIONPOLICY,
@@ -129,20 +146,60 @@ enum tomoyo_securityfs_interface_index {
TOMOYO_SELFDOMAIN,
TOMOYO_VERSION,
TOMOYO_PROFILE,
+ TOMOYO_QUERY,
TOMOYO_MANAGER
};
+enum tomoyo_mac_index {
+ TOMOYO_MAC_FILE_EXECUTE,
+ TOMOYO_MAC_FILE_OPEN,
+ TOMOYO_MAC_FILE_CREATE,
+ TOMOYO_MAC_FILE_UNLINK,
+ TOMOYO_MAC_FILE_MKDIR,
+ TOMOYO_MAC_FILE_RMDIR,
+ TOMOYO_MAC_FILE_MKFIFO,
+ TOMOYO_MAC_FILE_MKSOCK,
+ TOMOYO_MAC_FILE_TRUNCATE,
+ TOMOYO_MAC_FILE_SYMLINK,
+ TOMOYO_MAC_FILE_REWRITE,
+ TOMOYO_MAC_FILE_MKBLOCK,
+ TOMOYO_MAC_FILE_MKCHAR,
+ TOMOYO_MAC_FILE_LINK,
+ TOMOYO_MAC_FILE_RENAME,
+ TOMOYO_MAC_FILE_CHMOD,
+ TOMOYO_MAC_FILE_CHOWN,
+ TOMOYO_MAC_FILE_CHGRP,
+ TOMOYO_MAC_FILE_IOCTL,
+ TOMOYO_MAC_FILE_CHROOT,
+ TOMOYO_MAC_FILE_MOUNT,
+ TOMOYO_MAC_FILE_UMOUNT,
+ TOMOYO_MAC_FILE_PIVOT_ROOT,
+ TOMOYO_MAX_MAC_INDEX
+};
+
+enum tomoyo_mac_category_index {
+ TOMOYO_MAC_CATEGORY_FILE,
+ TOMOYO_MAX_MAC_CATEGORY_INDEX
+};
+
+#define TOMOYO_RETRY_REQUEST 1 /* Retry this request. */
+
/********** Structure definitions. **********/
/*
- * tomoyo_page_buffer is a structure which is used for holding a pathname
- * obtained from "struct dentry" and "struct vfsmount" pair.
- * As of now, it is 4096 bytes. If users complain that 4096 bytes is too small
- * (because TOMOYO escapes non ASCII printable characters using \ooo format),
- * we will make the buffer larger.
+ * tomoyo_request_info is a structure which is used for holding
+ *
+ * (1) Domain information of current process.
+ * (2) How many retries are made for this request.
+ * (3) Profile number used for this request.
+ * (4) Access control mode of the profile.
*/
-struct tomoyo_page_buffer {
- char buffer[4096];
+struct tomoyo_request_info {
+ struct tomoyo_domain_info *domain;
+ u8 retry;
+ u8 profile;
+ u8 mode; /* One of tomoyo_mode_index . */
+ u8 type;
};
/*
@@ -183,34 +240,20 @@ struct tomoyo_name_entry {
struct tomoyo_path_info entry;
};
-/*
- * tomoyo_path_info_with_data is a structure which is used for holding a
- * pathname obtained from "struct dentry" and "struct vfsmount" pair.
- *
- * "struct tomoyo_path_info_with_data" consists of "struct tomoyo_path_info"
- * and buffer for the pathname, while "struct tomoyo_page_buffer" consists of
- * buffer for the pathname only.
- *
- * "struct tomoyo_path_info_with_data" is intended to allow TOMOYO to release
- * both "struct tomoyo_path_info" and buffer for the pathname by single kfree()
- * so that we don't need to return two pointers to the caller. If the caller
- * puts "struct tomoyo_path_info" on stack memory, we will be able to remove
- * "struct tomoyo_path_info_with_data".
- */
-struct tomoyo_path_info_with_data {
- /* Keep "head" first, for this pointer is passed to kfree(). */
- struct tomoyo_path_info head;
- char barrier1[16]; /* Safeguard for overrun. */
- char body[TOMOYO_MAX_PATHNAME_LEN];
- char barrier2[16]; /* Safeguard for overrun. */
-};
-
struct tomoyo_name_union {
const struct tomoyo_path_info *filename;
struct tomoyo_path_group *group;
u8 is_group;
};
+struct tomoyo_number_union {
+ unsigned long values[2];
+ struct tomoyo_number_group *group;
+ u8 min_type;
+ u8 max_type;
+ u8 is_group;
+};
+
/* Structure for "path_group" directive. */
struct tomoyo_path_group {
struct list_head list;
@@ -219,6 +262,14 @@ struct tomoyo_path_group {
atomic_t users;
};
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group {
+ struct list_head list;
+ const struct tomoyo_path_info *group_name;
+ struct list_head member_list;
+ atomic_t users;
+};
+
/* Structure for "path_group" directive. */
struct tomoyo_path_group_member {
struct list_head list;
@@ -226,6 +277,13 @@ struct tomoyo_path_group_member {
const struct tomoyo_path_info *member_name;
};
+/* Structure for "number_group" directive. */
+struct tomoyo_number_group_member {
+ struct list_head list;
+ bool is_deleted;
+ struct tomoyo_number_union number;
+};
+
/*
* tomoyo_acl_info is a structure which is used for holding
*
@@ -299,20 +357,62 @@ struct tomoyo_domain_info {
* (3) "name" is the pathname.
*
* Directives held by this structure are "allow_read/write", "allow_execute",
- * "allow_read", "allow_write", "allow_create", "allow_unlink", "allow_mkdir",
- * "allow_rmdir", "allow_mkfifo", "allow_mksock", "allow_mkblock",
- * "allow_mkchar", "allow_truncate", "allow_symlink", "allow_rewrite",
- * "allow_chmod", "allow_chown", "allow_chgrp", "allow_chroot", "allow_mount"
- * and "allow_unmount".
+ * "allow_read", "allow_write", "allow_unlink", "allow_rmdir",
+ * "allow_truncate", "allow_symlink", "allow_rewrite", "allow_chroot" and
+ * "allow_unmount".
*/
struct tomoyo_path_acl {
struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_ACL */
- u8 perm_high;
u16 perm;
struct tomoyo_name_union name;
};
/*
+ * tomoyo_path_number_acl is a structure which is used for holding an
+ * entry with one pathname and one number operation.
+ * It has following fields.
+ *
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "perm" which is a bitmask of permitted operations.
+ * (3) "name" is the pathname.
+ * (4) "number" is the numeric value.
+ *
+ * Directives held by this structure are "allow_create", "allow_mkdir",
+ * "allow_ioctl", "allow_mkfifo", "allow_mksock", "allow_chmod", "allow_chown"
+ * and "allow_chgrp".
+ *
+ */
+struct tomoyo_path_number_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER_ACL */
+ u8 perm;
+ struct tomoyo_name_union name;
+ struct tomoyo_number_union number;
+};
+
+/*
+ * tomoyo_path_number3_acl is a structure which is used for holding an
+ * entry with one pathname and three numbers operation.
+ * It has following fields.
+ *
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "perm" which is a bitmask of permitted operations.
+ * (3) "mode" is the create mode.
+ * (4) "major" is the major number of device node.
+ * (5) "minor" is the minor number of device node.
+ *
+ * Directives held by this structure are "allow_mkchar", "allow_mkblock".
+ *
+ */
+struct tomoyo_path_number3_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_PATH_NUMBER3_ACL */
+ u8 perm;
+ struct tomoyo_name_union name;
+ struct tomoyo_number_union mode;
+ struct tomoyo_number_union major;
+ struct tomoyo_number_union minor;
+};
+
+/*
* tomoyo_path2_acl is a structure which is used for holding an
* entry with two pathnames operation (i.e. link(), rename() and pivot_root()).
* It has following fields.
@@ -333,6 +433,29 @@ struct tomoyo_path2_acl {
};
/*
+ * tomoyo_mount_acl is a structure which is used for holding an
+ * entry for mount operation.
+ * It has following fields.
+ *
+ * (1) "head" which is a "struct tomoyo_acl_info".
+ * (2) "is_deleted" is boolean.
+ * (3) "dev_name" is the device name.
+ * (4) "dir_name" is the mount point.
+ * (5) "flags" is the mount flags.
+ *
+ * Directives held by this structure are "allow_rename", "allow_link" and
+ * "allow_pivot_root".
+ */
+struct tomoyo_mount_acl {
+ struct tomoyo_acl_info head; /* type = TOMOYO_TYPE_MOUNT_ACL */
+ bool is_deleted;
+ struct tomoyo_name_union dev_name;
+ struct tomoyo_name_union dir_name;
+ struct tomoyo_name_union fs_type;
+ struct tomoyo_number_union flags;
+};
+
+/*
* tomoyo_io_buffer is a structure which is used for reading and modifying
* configuration via /sys/kernel/security/tomoyo/ interface.
* It has many fields. ->read_var1 , ->read_var2 , ->write_var1 are used as
@@ -358,6 +481,7 @@ struct tomoyo_path2_acl {
struct tomoyo_io_buffer {
int (*read) (struct tomoyo_io_buffer *);
int (*write) (struct tomoyo_io_buffer *);
+ int (*poll) (struct file *file, poll_table *wait);
/* Exclusive lock for this structure. */
struct mutex io_sem;
/* Index returned by tomoyo_read_lock(). */
@@ -388,6 +512,8 @@ struct tomoyo_io_buffer {
int write_avail;
/* Size of write buffer. */
int writebuf_size;
+ /* Type of this interface. */
+ u8 type;
};
/*
@@ -494,6 +620,24 @@ struct tomoyo_domain_keeper_entry {
};
/*
+ * tomoyo_aggregator_entry is a structure which is used for holding
+ * "aggregator" entries.
+ * It has following fields.
+ *
+ * (1) "list" which is linked to tomoyo_aggregator_list .
+ * (2) "original_name" which is originally requested name.
+ * (3) "aggregated_name" which is name to rewrite.
+ * (4) "is_deleted" is a bool which is true if marked as deleted, false
+ * otherwise.
+ */
+struct tomoyo_aggregator_entry {
+ struct list_head list;
+ const struct tomoyo_path_info *original_name;
+ const struct tomoyo_path_info *aggregated_name;
+ bool is_deleted;
+};
+
+/*
* tomoyo_alias_entry is a structure which is used for holding "alias" entries.
* It has following fields.
*
@@ -531,32 +675,89 @@ struct tomoyo_policy_manager_entry {
bool is_deleted; /* True if this entry is deleted. */
};
+struct tomoyo_preference {
+ unsigned int learning_max_entry;
+ bool enforcing_verbose;
+ bool learning_verbose;
+ bool permissive_verbose;
+};
+
+struct tomoyo_profile {
+ const struct tomoyo_path_info *comment;
+ struct tomoyo_preference *learning;
+ struct tomoyo_preference *permissive;
+ struct tomoyo_preference *enforcing;
+ struct tomoyo_preference preference;
+ u8 default_config;
+ u8 config[TOMOYO_MAX_MAC_INDEX + TOMOYO_MAX_MAC_CATEGORY_INDEX];
+};
+
/********** Function prototypes. **********/
+extern asmlinkage long sys_getpid(void);
+extern asmlinkage long sys_getppid(void);
+
+/* Check whether the given string starts with the given keyword. */
+bool tomoyo_str_starts(char **src, const char *find);
+/* Get tomoyo_realpath() of current process. */
+const char *tomoyo_get_exe(void);
+/* Format string. */
+void tomoyo_normalize_line(unsigned char *buffer);
+/* Print warning or error message on console. */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+/* Check all profiles currently assigned to domains are defined. */
+void tomoyo_check_profile(void);
+/* Open operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_open_control(const u8 type, struct file *file);
+/* Close /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_close_control(struct file *file);
+/* Read operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_read_control(struct file *file, char __user *buffer,
+ const int buffer_len);
+/* Write operation for /sys/kernel/security/tomoyo/ interface. */
+int tomoyo_write_control(struct file *file, const char __user *buffer,
+ const int buffer_len);
+/* Check whether the domain has too many ACL entries to hold. */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r);
+/* Print out of memory warning message. */
+void tomoyo_warn_oom(const char *function);
/* Check whether the given name matches the given name_union. */
bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr);
-/* Check whether the domain has too many ACL entries to hold. */
-bool tomoyo_domain_quota_is_ok(struct tomoyo_domain_info * const domain);
+/* Check whether the given number matches the given number_union. */
+bool tomoyo_compare_number_union(const unsigned long value,
+ const struct tomoyo_number_union *ptr);
+int tomoyo_get_mode(const u8 profile, const u8 index);
/* Transactional sprintf() for policy dump. */
bool tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fmt, ...)
__attribute__ ((format(printf, 2, 3)));
/* Check whether the domainname is correct. */
bool tomoyo_is_correct_domain(const unsigned char *domainname);
/* Check whether the token is correct. */
-bool tomoyo_is_correct_path(const char *filename, const s8 start_type,
- const s8 pattern_type, const s8 end_type);
+bool tomoyo_is_correct_path(const char *filename);
+bool tomoyo_is_correct_word(const char *string);
/* Check whether the token can be a domainname. */
bool tomoyo_is_domain_def(const unsigned char *buffer);
bool tomoyo_parse_name_union(const char *filename,
struct tomoyo_name_union *ptr);
/* Check whether the given filename matches the given path_group. */
bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
- const struct tomoyo_path_group *group,
- const bool may_use_pattern);
+ const struct tomoyo_path_group *group);
+/* Check whether the given value matches the given number_group. */
+bool tomoyo_number_matches_group(const unsigned long min,
+ const unsigned long max,
+ const struct tomoyo_number_group *group);
/* Check whether the given filename matches the given pattern. */
bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
const struct tomoyo_path_info *pattern);
+
+bool tomoyo_print_number_union(struct tomoyo_io_buffer *head,
+ const struct tomoyo_number_union *ptr);
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num);
+
+/* Read "aggregator" entry in exception policy. */
+bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head);
/* Read "alias" entry in exception policy. */
bool tomoyo_read_alias_policy(struct tomoyo_io_buffer *head);
/*
@@ -570,6 +771,8 @@ bool tomoyo_read_domain_keeper_policy(struct tomoyo_io_buffer *head);
bool tomoyo_read_file_pattern(struct tomoyo_io_buffer *head);
/* Read "path_group" entry in exception policy. */
bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head);
+/* Read "number_group" entry in exception policy. */
+bool tomoyo_read_number_group_policy(struct tomoyo_io_buffer *head);
/* Read "allow_read" entry in exception policy. */
bool tomoyo_read_globally_readable_policy(struct tomoyo_io_buffer *head);
/* Read "deny_rewrite" entry in exception policy. */
@@ -580,12 +783,21 @@ bool tomoyo_tokenize(char *buffer, char *w[], size_t size);
bool tomoyo_verbose_mode(const struct tomoyo_domain_info *domain);
/* Convert double path operation to operation name. */
const char *tomoyo_path22keyword(const u8 operation);
+const char *tomoyo_path_number2keyword(const u8 operation);
+const char *tomoyo_path_number32keyword(const u8 operation);
/* Get the last component of the given domainname. */
const char *tomoyo_get_last_name(const struct tomoyo_domain_info *domain);
-/* Get warning message. */
-const char *tomoyo_get_msg(const bool is_enforce);
/* Convert single path operation to operation name. */
const char *tomoyo_path2keyword(const u8 operation);
+/* Fill "struct tomoyo_request_info". */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+ struct tomoyo_domain_info *domain,
+ const u8 index);
+/* Check permission for mount operation. */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+ unsigned long flags, void *data_page);
+/* Create "aggregator" entry in exception policy. */
+int tomoyo_write_aggregator_policy(char *data, const bool is_delete);
/* Create "alias" entry in exception policy. */
int tomoyo_write_alias_policy(char *data, const bool is_delete);
/*
@@ -608,21 +820,29 @@ int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
const bool is_delete);
/* Create "allow_read" entry in exception policy. */
int tomoyo_write_globally_readable_policy(char *data, const bool is_delete);
+/* Create "allow_mount" entry in domain policy. */
+int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete);
/* Create "deny_rewrite" entry in exception policy. */
int tomoyo_write_no_rewrite_policy(char *data, const bool is_delete);
/* Create "file_pattern" entry in exception policy. */
int tomoyo_write_pattern_policy(char *data, const bool is_delete);
/* Create "path_group" entry in exception policy. */
int tomoyo_write_path_group_policy(char *data, const bool is_delete);
+int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+/* Create "number_group" entry in exception policy. */
+int tomoyo_write_number_group_policy(char *data, const bool is_delete);
/* Find a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname);
/* Find or create a domain by the given name. */
struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
domainname,
const u8 profile);
-
+struct tomoyo_profile *tomoyo_profile(const u8 profile);
/* Allocate memory for "struct tomoyo_path_group". */
struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name);
+struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name);
/* Check mode for specified functionality. */
unsigned int tomoyo_check_flags(const struct tomoyo_domain_info *domain,
@@ -632,12 +852,10 @@ void tomoyo_fill_path_info(struct tomoyo_path_info *ptr);
/* Run policy loader when /sbin/init starts. */
void tomoyo_load_policy(const char *filename);
-/* Convert binary string to ascii string. */
-int tomoyo_encode(char *buffer, int buflen, const char *str);
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr);
-/* Returns realpath(3) of the given pathname but ignores chroot'ed root. */
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
- int newname_len);
+/* Convert binary string to ascii string. */
+char *tomoyo_encode(const char *str);
/*
* Returns realpath(3) of the given pathname but ignores chroot'ed root.
@@ -651,6 +869,8 @@ char *tomoyo_realpath(const char *pathname);
char *tomoyo_realpath_nofollow(const char *pathname);
/* Same with tomoyo_realpath() except that the pathname is already solved. */
char *tomoyo_realpath_from_path(struct path *path);
+/* Get patterned pathname. */
+const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename);
/* Check memory quota. */
bool tomoyo_memory_ok(void *ptr);
@@ -668,18 +888,24 @@ int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head);
/* Set memory quota. */
int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head);
-/* Initialize realpath related code. */
-void __init tomoyo_realpath_init(void);
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+/* Initialize mm related code. */
+void __init tomoyo_mm_init(void);
+int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename);
int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
struct path *path, const int flag);
+int tomoyo_path_number_perm(const u8 operation, struct path *path,
+ unsigned long number);
+int tomoyo_path_number3_perm(const u8 operation, struct path *path,
+ const unsigned int mode, unsigned int dev);
int tomoyo_path_perm(const u8 operation, struct path *path);
int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct path *path2);
-int tomoyo_check_rewrite_permission(struct file *filp);
int tomoyo_find_next_domain(struct linux_binprm *bprm);
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+ const unsigned long value, const u8 type);
+
/* Drop refcount on tomoyo_name_union. */
void tomoyo_put_name_union(struct tomoyo_name_union *ptr);
@@ -697,8 +923,10 @@ extern struct srcu_struct tomoyo_ss;
extern struct list_head tomoyo_domain_list;
extern struct list_head tomoyo_path_group_list;
+extern struct list_head tomoyo_number_group_list;
extern struct list_head tomoyo_domain_initializer_list;
extern struct list_head tomoyo_domain_keeper_list;
+extern struct list_head tomoyo_aggregator_list;
extern struct list_head tomoyo_alias_list;
extern struct list_head tomoyo_globally_readable_list;
extern struct list_head tomoyo_pattern_list;
@@ -715,6 +943,9 @@ extern bool tomoyo_policy_loaded;
/* The kernel's domain. */
extern struct tomoyo_domain_info tomoyo_kernel_domain;
+extern unsigned int tomoyo_quota_for_query;
+extern unsigned int tomoyo_query_memory_size;
+
/********** Inlined functions. **********/
static inline int tomoyo_read_lock(void)
@@ -773,6 +1004,12 @@ static inline void tomoyo_put_path_group(struct tomoyo_path_group *group)
atomic_dec(&group->users);
}
+static inline void tomoyo_put_number_group(struct tomoyo_number_group *group)
+{
+ if (group)
+ atomic_dec(&group->users);
+}
+
static inline struct tomoyo_domain_info *tomoyo_domain(void)
{
return current_cred()->security;
@@ -797,6 +1034,14 @@ static inline bool tomoyo_is_same_name_union
p1->is_group == p2->is_group;
}
+static inline bool tomoyo_is_same_number_union
+(const struct tomoyo_number_union *p1, const struct tomoyo_number_union *p2)
+{
+ return p1->values[0] == p2->values[0] && p1->values[1] == p2->values[1]
+ && p1->group == p2->group && p1->min_type == p2->min_type &&
+ p1->max_type == p2->max_type && p1->is_group == p2->is_group;
+}
+
static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
const struct tomoyo_path_acl *p2)
{
@@ -804,6 +1049,18 @@ static inline bool tomoyo_is_same_path_acl(const struct tomoyo_path_acl *p1,
tomoyo_is_same_name_union(&p1->name, &p2->name);
}
+static inline bool tomoyo_is_same_path_number3_acl
+(const struct tomoyo_path_number3_acl *p1,
+ const struct tomoyo_path_number3_acl *p2)
+{
+ return tomoyo_is_same_acl_head(&p1->head, &p2->head)
+ && tomoyo_is_same_name_union(&p1->name, &p2->name)
+ && tomoyo_is_same_number_union(&p1->mode, &p2->mode)
+ && tomoyo_is_same_number_union(&p1->major, &p2->major)
+ && tomoyo_is_same_number_union(&p1->minor, &p2->minor);
+}
+
+
static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
const struct tomoyo_path2_acl *p2)
{
@@ -812,6 +1069,25 @@ static inline bool tomoyo_is_same_path2_acl(const struct tomoyo_path2_acl *p1,
tomoyo_is_same_name_union(&p1->name2, &p2->name2);
}
+static inline bool tomoyo_is_same_path_number_acl
+(const struct tomoyo_path_number_acl *p1,
+ const struct tomoyo_path_number_acl *p2)
+{
+ return tomoyo_is_same_acl_head(&p1->head, &p2->head)
+ && tomoyo_is_same_name_union(&p1->name, &p2->name)
+ && tomoyo_is_same_number_union(&p1->number, &p2->number);
+}
+
+static inline bool tomoyo_is_same_mount_acl(const struct tomoyo_mount_acl *p1,
+ const struct tomoyo_mount_acl *p2)
+{
+ return tomoyo_is_same_acl_head(&p1->head, &p2->head) &&
+ tomoyo_is_same_name_union(&p1->dev_name, &p2->dev_name) &&
+ tomoyo_is_same_name_union(&p1->dir_name, &p2->dir_name) &&
+ tomoyo_is_same_name_union(&p1->fs_type, &p2->fs_type) &&
+ tomoyo_is_same_number_union(&p1->flags, &p2->flags);
+}
+
static inline bool tomoyo_is_same_domain_initializer_entry
(const struct tomoyo_domain_initializer_entry *p1,
const struct tomoyo_domain_initializer_entry *p2)
@@ -830,6 +1106,14 @@ static inline bool tomoyo_is_same_domain_keeper_entry
&& p1->program == p2->program;
}
+static inline bool tomoyo_is_same_aggregator_entry
+(const struct tomoyo_aggregator_entry *p1,
+ const struct tomoyo_aggregator_entry *p2)
+{
+ return p1->original_name == p2->original_name &&
+ p1->aggregated_name == p2->aggregated_name;
+}
+
static inline bool tomoyo_is_same_alias_entry
(const struct tomoyo_alias_entry *p1, const struct tomoyo_alias_entry *p2)
{
diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
index cd8ba4446763..09ec37c12a9c 100644
--- a/security/tomoyo/domain.c
+++ b/security/tomoyo/domain.c
@@ -1,12 +1,9 @@
/*
* security/tomoyo/domain.c
*
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Domain transition functions for TOMOYO.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include "common.h"
@@ -134,11 +131,11 @@ static int tomoyo_update_domain_initializer_entry(const char *domainname,
struct tomoyo_domain_initializer_entry e = { .is_not = is_not };
int error = is_delete ? -ENOENT : -ENOMEM;
- if (!tomoyo_is_correct_path(program, 1, -1, -1))
- return -EINVAL; /* No patterns allowed. */
+ if (!tomoyo_is_correct_path(program))
+ return -EINVAL;
if (domainname) {
if (!tomoyo_is_domain_def(domainname) &&
- tomoyo_is_correct_path(domainname, 1, -1, -1))
+ tomoyo_is_correct_path(domainname))
e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL;
@@ -345,12 +342,12 @@ static int tomoyo_update_domain_keeper_entry(const char *domainname,
int error = is_delete ? -ENOENT : -ENOMEM;
if (!tomoyo_is_domain_def(domainname) &&
- tomoyo_is_correct_path(domainname, 1, -1, -1))
+ tomoyo_is_correct_path(domainname))
e.is_last_name = true;
else if (!tomoyo_is_correct_domain(domainname))
return -EINVAL;
if (program) {
- if (!tomoyo_is_correct_path(program, 1, -1, -1))
+ if (!tomoyo_is_correct_path(program))
return -EINVAL;
e.program = tomoyo_get_name(program);
if (!e.program)
@@ -486,6 +483,136 @@ static bool tomoyo_is_domain_keeper(const struct tomoyo_path_info *domainname,
}
/*
+ * tomoyo_aggregator_list is used for holding list of rewrite table for
+ * execve() request. Some programs provides similar functionality. This keyword
+ * allows users to aggregate such programs.
+ *
+ * Entries are added by
+ *
+ * # echo 'aggregator /usr/bin/vi /./editor' > \
+ * /sys/kernel/security/tomoyo/exception_policy
+ * # echo 'aggregator /usr/bin/emacs /./editor' > \
+ * /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and are deleted by
+ *
+ * # echo 'delete aggregator /usr/bin/vi /./editor' > \
+ * /sys/kernel/security/tomoyo/exception_policy
+ * # echo 'delete aggregator /usr/bin/emacs /./editor' > \
+ * /sys/kernel/security/tomoyo/exception_policy
+ *
+ * and all entries are retrieved by
+ *
+ * # grep ^aggregator /sys/kernel/security/tomoyo/exception_policy
+ *
+ * In the example above, if /usr/bin/vi or /usr/bin/emacs are executed,
+ * permission is checked for /./editor and domainname which the current process
+ * will belong to after execve() succeeds is calculated using /./editor .
+ */
+LIST_HEAD(tomoyo_aggregator_list);
+
+/**
+ * tomoyo_update_aggregator_entry - Update "struct tomoyo_aggregator_entry" list.
+ *
+ * @original_name: The original program's name.
+ * @aggregated_name: The program name to use.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_update_aggregator_entry(const char *original_name,
+ const char *aggregated_name,
+ const bool is_delete)
+{
+ struct tomoyo_aggregator_entry *ptr;
+ struct tomoyo_aggregator_entry e = { };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+
+ if (!tomoyo_is_correct_path(original_name) ||
+ !tomoyo_is_correct_path(aggregated_name))
+ return -EINVAL;
+ e.original_name = tomoyo_get_name(original_name);
+ e.aggregated_name = tomoyo_get_name(aggregated_name);
+ if (!e.original_name || !e.aggregated_name ||
+ e.aggregated_name->is_patterned) /* No patterns allowed. */
+ goto out;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) {
+ if (!tomoyo_is_same_aggregator_entry(ptr, &e))
+ continue;
+ ptr->is_deleted = is_delete;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error) {
+ struct tomoyo_aggregator_entry *entry =
+ tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ list_add_tail_rcu(&entry->list,
+ &tomoyo_aggregator_list);
+ error = 0;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name(e.original_name);
+ tomoyo_put_name(e.aggregated_name);
+ return error;
+}
+
+/**
+ * tomoyo_read_aggregator_policy - Read "struct tomoyo_aggregator_entry" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_read_aggregator_policy(struct tomoyo_io_buffer *head)
+{
+ struct list_head *pos;
+ bool done = true;
+
+ list_for_each_cookie(pos, head->read_var2, &tomoyo_aggregator_list) {
+ struct tomoyo_aggregator_entry *ptr;
+
+ ptr = list_entry(pos, struct tomoyo_aggregator_entry, list);
+ if (ptr->is_deleted)
+ continue;
+ done = tomoyo_io_printf(head, TOMOYO_KEYWORD_AGGREGATOR
+ "%s %s\n", ptr->original_name->name,
+ ptr->aggregated_name->name);
+ if (!done)
+ break;
+ }
+ return done;
+}
+
+/**
+ * tomoyo_write_aggregator_policy - Write "struct tomoyo_aggregator_entry" list.
+ *
+ * @data: String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_aggregator_policy(char *data, const bool is_delete)
+{
+ char *cp = strchr(data, ' ');
+
+ if (!cp)
+ return -EINVAL;
+ *cp++ = '\0';
+ return tomoyo_update_aggregator_entry(data, cp, is_delete);
+}
+
+/*
* tomoyo_alias_list is used for holding list of symlink's pathnames which are
* allowed to be passed to an execve() request. Normally, the domainname which
* the current process will belong to after execve() succeeds is calculated
@@ -536,13 +663,14 @@ static int tomoyo_update_alias_entry(const char *original_name,
struct tomoyo_alias_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
- if (!tomoyo_is_correct_path(original_name, 1, -1, -1) ||
- !tomoyo_is_correct_path(aliased_name, 1, -1, -1))
- return -EINVAL; /* No patterns allowed. */
+ if (!tomoyo_is_correct_path(original_name) ||
+ !tomoyo_is_correct_path(aliased_name))
+ return -EINVAL;
e.original_name = tomoyo_get_name(original_name);
e.aliased_name = tomoyo_get_name(aliased_name);
- if (!e.original_name || !e.aliased_name)
- goto out;
+ if (!e.original_name || !e.aliased_name ||
+ e.original_name->is_patterned || e.aliased_name->is_patterned)
+ goto out; /* No patterns allowed. */
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
@@ -678,86 +806,91 @@ struct tomoyo_domain_info *tomoyo_find_or_assign_new_domain(const char *
*/
int tomoyo_find_next_domain(struct linux_binprm *bprm)
{
- /*
- * This function assumes that the size of buffer returned by
- * tomoyo_realpath() = TOMOYO_MAX_PATHNAME_LEN.
- */
- struct tomoyo_page_buffer *tmp = kzalloc(sizeof(*tmp), GFP_NOFS);
+ struct tomoyo_request_info r;
+ char *tmp = kzalloc(TOMOYO_EXEC_TMPSIZE, GFP_NOFS);
struct tomoyo_domain_info *old_domain = tomoyo_domain();
struct tomoyo_domain_info *domain = NULL;
const char *old_domain_name = old_domain->domainname->name;
const char *original_name = bprm->filename;
- char *new_domain_name = NULL;
- char *real_program_name = NULL;
- char *symlink_program_name = NULL;
- const u8 mode = tomoyo_check_flags(old_domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ u8 mode;
+ bool is_enforce;
int retval = -ENOMEM;
- struct tomoyo_path_info r; /* real name */
- struct tomoyo_path_info s; /* symlink name */
- struct tomoyo_path_info l; /* last name */
- static bool initialized;
-
+ bool need_kfree = false;
+ struct tomoyo_path_info rn = { }; /* real name */
+ struct tomoyo_path_info sn = { }; /* symlink name */
+ struct tomoyo_path_info ln; /* last name */
+
+ ln.name = tomoyo_get_last_name(old_domain);
+ tomoyo_fill_path_info(&ln);
+ mode = tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_EXECUTE);
+ is_enforce = (mode == TOMOYO_CONFIG_ENFORCING);
if (!tmp)
goto out;
- if (!initialized) {
- /*
- * Built-in initializers. This is needed because policies are
- * not loaded until starting /sbin/init.
- */
- tomoyo_update_domain_initializer_entry(NULL, "/sbin/hotplug",
- false, false);
- tomoyo_update_domain_initializer_entry(NULL, "/sbin/modprobe",
- false, false);
- initialized = true;
+ retry:
+ if (need_kfree) {
+ kfree(rn.name);
+ need_kfree = false;
}
-
/* Get tomoyo_realpath of program. */
retval = -ENOENT;
- /* I hope tomoyo_realpath() won't fail with -ENOMEM. */
- real_program_name = tomoyo_realpath(original_name);
- if (!real_program_name)
+ rn.name = tomoyo_realpath(original_name);
+ if (!rn.name)
goto out;
+ tomoyo_fill_path_info(&rn);
+ need_kfree = true;
+
/* Get tomoyo_realpath of symbolic link. */
- symlink_program_name = tomoyo_realpath_nofollow(original_name);
- if (!symlink_program_name)
+ sn.name = tomoyo_realpath_nofollow(original_name);
+ if (!sn.name)
goto out;
-
- r.name = real_program_name;
- tomoyo_fill_path_info(&r);
- s.name = symlink_program_name;
- tomoyo_fill_path_info(&s);
- l.name = tomoyo_get_last_name(old_domain);
- tomoyo_fill_path_info(&l);
+ tomoyo_fill_path_info(&sn);
/* Check 'alias' directive. */
- if (tomoyo_pathcmp(&r, &s)) {
+ if (tomoyo_pathcmp(&rn, &sn)) {
struct tomoyo_alias_entry *ptr;
/* Is this program allowed to be called via symbolic links? */
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (ptr->is_deleted ||
- tomoyo_pathcmp(&r, ptr->original_name) ||
- tomoyo_pathcmp(&s, ptr->aliased_name))
+ tomoyo_pathcmp(&rn, ptr->original_name) ||
+ tomoyo_pathcmp(&sn, ptr->aliased_name))
continue;
- memset(real_program_name, 0, TOMOYO_MAX_PATHNAME_LEN);
- strncpy(real_program_name, ptr->aliased_name->name,
- TOMOYO_MAX_PATHNAME_LEN - 1);
- tomoyo_fill_path_info(&r);
+ kfree(rn.name);
+ need_kfree = false;
+ /* This is OK because it is read only. */
+ rn = *ptr->aliased_name;
+ break;
+ }
+ }
+
+ /* Check 'aggregator' directive. */
+ {
+ struct tomoyo_aggregator_entry *ptr;
+ list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) {
+ if (ptr->is_deleted ||
+ !tomoyo_path_matches_pattern(&rn,
+ ptr->original_name))
+ continue;
+ if (need_kfree)
+ kfree(rn.name);
+ need_kfree = false;
+ /* This is OK because it is read only. */
+ rn = *ptr->aggregated_name;
break;
}
}
/* Check execute permission. */
- retval = tomoyo_check_exec_perm(old_domain, &r);
+ retval = tomoyo_check_exec_perm(&r, &rn);
+ if (retval == TOMOYO_RETRY_REQUEST)
+ goto retry;
if (retval < 0)
goto out;
- new_domain_name = tmp->buffer;
- if (tomoyo_is_domain_initializer(old_domain->domainname, &r, &l)) {
+ if (tomoyo_is_domain_initializer(old_domain->domainname, &rn, &ln)) {
/* Transit to the child of tomoyo_kernel_domain domain. */
- snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
- TOMOYO_ROOT_NAME " " "%s", real_program_name);
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
+ TOMOYO_ROOT_NAME " " "%s", rn.name);
} else if (old_domain == &tomoyo_kernel_domain &&
!tomoyo_policy_loaded) {
/*
@@ -766,28 +899,32 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
* initializers because they might start before /sbin/init.
*/
domain = old_domain;
- } else if (tomoyo_is_domain_keeper(old_domain->domainname, &r, &l)) {
+ } else if (tomoyo_is_domain_keeper(old_domain->domainname, &rn, &ln)) {
/* Keep current domain. */
domain = old_domain;
} else {
/* Normal domain transition. */
- snprintf(new_domain_name, TOMOYO_MAX_PATHNAME_LEN + 1,
- "%s %s", old_domain_name, real_program_name);
+ snprintf(tmp, TOMOYO_EXEC_TMPSIZE - 1,
+ "%s %s", old_domain_name, rn.name);
}
- if (domain || strlen(new_domain_name) >= TOMOYO_MAX_PATHNAME_LEN)
+ if (domain || strlen(tmp) >= TOMOYO_EXEC_TMPSIZE - 10)
goto done;
- domain = tomoyo_find_domain(new_domain_name);
+ domain = tomoyo_find_domain(tmp);
if (domain)
goto done;
- if (is_enforce)
- goto done;
- domain = tomoyo_find_or_assign_new_domain(new_domain_name,
- old_domain->profile);
+ if (is_enforce) {
+ int error = tomoyo_supervisor(&r, "# wants to create domain\n"
+ "%s\n", tmp);
+ if (error == TOMOYO_RETRY_REQUEST)
+ goto retry;
+ if (error < 0)
+ goto done;
+ }
+ domain = tomoyo_find_or_assign_new_domain(tmp, old_domain->profile);
done:
if (domain)
goto out;
- printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n",
- new_domain_name);
+ printk(KERN_WARNING "TOMOYO-ERROR: Domain '%s' not defined.\n", tmp);
if (is_enforce)
retval = -EPERM;
else
@@ -798,8 +935,9 @@ int tomoyo_find_next_domain(struct linux_binprm *bprm)
/* Update reference count on "struct tomoyo_domain_info". */
atomic_inc(&domain->users);
bprm->cred->security = domain;
- kfree(real_program_name);
- kfree(symlink_program_name);
+ if (need_kfree)
+ kfree(rn.name);
+ kfree(sn.name);
kfree(tmp);
return retval;
}
diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c
index 1c6f8238ec47..8e51348d022e 100644
--- a/security/tomoyo/file.c
+++ b/security/tomoyo/file.c
@@ -1,50 +1,92 @@
/*
* security/tomoyo/file.c
*
- * Implementation of the Domain-Based Mandatory Access Control.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Pathname restriction functions.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include "common.h"
#include <linux/slab.h>
-/* Keyword array for single path operations. */
+/* Keyword array for operations with one pathname. */
static const char *tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION] = {
[TOMOYO_TYPE_READ_WRITE] = "read/write",
[TOMOYO_TYPE_EXECUTE] = "execute",
[TOMOYO_TYPE_READ] = "read",
[TOMOYO_TYPE_WRITE] = "write",
- [TOMOYO_TYPE_CREATE] = "create",
[TOMOYO_TYPE_UNLINK] = "unlink",
- [TOMOYO_TYPE_MKDIR] = "mkdir",
[TOMOYO_TYPE_RMDIR] = "rmdir",
- [TOMOYO_TYPE_MKFIFO] = "mkfifo",
- [TOMOYO_TYPE_MKSOCK] = "mksock",
- [TOMOYO_TYPE_MKBLOCK] = "mkblock",
- [TOMOYO_TYPE_MKCHAR] = "mkchar",
[TOMOYO_TYPE_TRUNCATE] = "truncate",
[TOMOYO_TYPE_SYMLINK] = "symlink",
[TOMOYO_TYPE_REWRITE] = "rewrite",
- [TOMOYO_TYPE_IOCTL] = "ioctl",
- [TOMOYO_TYPE_CHMOD] = "chmod",
- [TOMOYO_TYPE_CHOWN] = "chown",
- [TOMOYO_TYPE_CHGRP] = "chgrp",
[TOMOYO_TYPE_CHROOT] = "chroot",
- [TOMOYO_TYPE_MOUNT] = "mount",
[TOMOYO_TYPE_UMOUNT] = "unmount",
};
-/* Keyword array for double path operations. */
+/* Keyword array for operations with one pathname and three numbers. */
+static const char *tomoyo_path_number3_keyword
+[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = {
+ [TOMOYO_TYPE_MKBLOCK] = "mkblock",
+ [TOMOYO_TYPE_MKCHAR] = "mkchar",
+};
+
+/* Keyword array for operations with two pathnames. */
static const char *tomoyo_path2_keyword[TOMOYO_MAX_PATH2_OPERATION] = {
- [TOMOYO_TYPE_LINK] = "link",
- [TOMOYO_TYPE_RENAME] = "rename",
+ [TOMOYO_TYPE_LINK] = "link",
+ [TOMOYO_TYPE_RENAME] = "rename",
[TOMOYO_TYPE_PIVOT_ROOT] = "pivot_root",
};
+/* Keyword array for operations with one pathname and one number. */
+static const char *tomoyo_path_number_keyword
+[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+ [TOMOYO_TYPE_CREATE] = "create",
+ [TOMOYO_TYPE_MKDIR] = "mkdir",
+ [TOMOYO_TYPE_MKFIFO] = "mkfifo",
+ [TOMOYO_TYPE_MKSOCK] = "mksock",
+ [TOMOYO_TYPE_IOCTL] = "ioctl",
+ [TOMOYO_TYPE_CHMOD] = "chmod",
+ [TOMOYO_TYPE_CHOWN] = "chown",
+ [TOMOYO_TYPE_CHGRP] = "chgrp",
+};
+
+static const u8 tomoyo_p2mac[TOMOYO_MAX_PATH_OPERATION] = {
+ [TOMOYO_TYPE_READ_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_EXECUTE] = TOMOYO_MAC_FILE_EXECUTE,
+ [TOMOYO_TYPE_READ] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_WRITE] = TOMOYO_MAC_FILE_OPEN,
+ [TOMOYO_TYPE_UNLINK] = TOMOYO_MAC_FILE_UNLINK,
+ [TOMOYO_TYPE_RMDIR] = TOMOYO_MAC_FILE_RMDIR,
+ [TOMOYO_TYPE_TRUNCATE] = TOMOYO_MAC_FILE_TRUNCATE,
+ [TOMOYO_TYPE_SYMLINK] = TOMOYO_MAC_FILE_SYMLINK,
+ [TOMOYO_TYPE_REWRITE] = TOMOYO_MAC_FILE_REWRITE,
+ [TOMOYO_TYPE_CHROOT] = TOMOYO_MAC_FILE_CHROOT,
+ [TOMOYO_TYPE_UMOUNT] = TOMOYO_MAC_FILE_UMOUNT,
+};
+
+static const u8 tomoyo_pnnn2mac[TOMOYO_MAX_PATH_NUMBER3_OPERATION] = {
+ [TOMOYO_TYPE_MKBLOCK] = TOMOYO_MAC_FILE_MKBLOCK,
+ [TOMOYO_TYPE_MKCHAR] = TOMOYO_MAC_FILE_MKCHAR,
+};
+
+static const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION] = {
+ [TOMOYO_TYPE_LINK] = TOMOYO_MAC_FILE_LINK,
+ [TOMOYO_TYPE_RENAME] = TOMOYO_MAC_FILE_RENAME,
+ [TOMOYO_TYPE_PIVOT_ROOT] = TOMOYO_MAC_FILE_PIVOT_ROOT,
+};
+
+static const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION] = {
+ [TOMOYO_TYPE_CREATE] = TOMOYO_MAC_FILE_CREATE,
+ [TOMOYO_TYPE_MKDIR] = TOMOYO_MAC_FILE_MKDIR,
+ [TOMOYO_TYPE_MKFIFO] = TOMOYO_MAC_FILE_MKFIFO,
+ [TOMOYO_TYPE_MKSOCK] = TOMOYO_MAC_FILE_MKSOCK,
+ [TOMOYO_TYPE_IOCTL] = TOMOYO_MAC_FILE_IOCTL,
+ [TOMOYO_TYPE_CHMOD] = TOMOYO_MAC_FILE_CHMOD,
+ [TOMOYO_TYPE_CHOWN] = TOMOYO_MAC_FILE_CHOWN,
+ [TOMOYO_TYPE_CHGRP] = TOMOYO_MAC_FILE_CHGRP,
+};
+
void tomoyo_put_name_union(struct tomoyo_name_union *ptr)
{
if (!ptr)
@@ -59,21 +101,22 @@ bool tomoyo_compare_name_union(const struct tomoyo_path_info *name,
const struct tomoyo_name_union *ptr)
{
if (ptr->is_group)
- return tomoyo_path_matches_group(name, ptr->group, 1);
+ return tomoyo_path_matches_group(name, ptr->group);
return tomoyo_path_matches_pattern(name, ptr->filename);
}
-static bool tomoyo_compare_name_union_pattern(const struct tomoyo_path_info
- *name,
- const struct tomoyo_name_union
- *ptr, const bool may_use_pattern)
+void tomoyo_put_number_union(struct tomoyo_number_union *ptr)
+{
+ if (ptr && ptr->is_group)
+ tomoyo_put_number_group(ptr->group);
+}
+
+bool tomoyo_compare_number_union(const unsigned long value,
+ const struct tomoyo_number_union *ptr)
{
if (ptr->is_group)
- return tomoyo_path_matches_group(name, ptr->group,
- may_use_pattern);
- if (may_use_pattern || !ptr->filename->is_patterned)
- return tomoyo_path_matches_pattern(name, ptr->filename);
- return false;
+ return tomoyo_number_matches_group(value, value, ptr->group);
+ return value >= ptr->values[0] && value <= ptr->values[1];
}
/**
@@ -90,6 +133,19 @@ const char *tomoyo_path2keyword(const u8 operation)
}
/**
+ * tomoyo_path_number32keyword - Get the name of path/number/number/number operations.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of path/number/number/number operation.
+ */
+const char *tomoyo_path_number32keyword(const u8 operation)
+{
+ return (operation < TOMOYO_MAX_PATH_NUMBER3_OPERATION)
+ ? tomoyo_path_number3_keyword[operation] : NULL;
+}
+
+/**
* tomoyo_path22keyword - Get the name of double path operation.
*
* @operation: Type of operation.
@@ -103,6 +159,30 @@ const char *tomoyo_path22keyword(const u8 operation)
}
/**
+ * tomoyo_path_number2keyword - Get the name of path/number operations.
+ *
+ * @operation: Type of operation.
+ *
+ * Returns the name of path/number operation.
+ */
+const char *tomoyo_path_number2keyword(const u8 operation)
+{
+ return (operation < TOMOYO_MAX_PATH_NUMBER_OPERATION)
+ ? tomoyo_path_number_keyword[operation] : NULL;
+}
+
+static void tomoyo_add_slash(struct tomoyo_path_info *buf)
+{
+ if (buf->is_dir)
+ return;
+ /*
+ * This is OK because tomoyo_encode() reserves space for appending "/".
+ */
+ strcat((char *) buf->name, "/");
+ tomoyo_fill_path_info(buf);
+}
+
+/**
* tomoyo_strendswith - Check whether the token ends with the given token.
*
* @name: The token to check.
@@ -121,30 +201,21 @@ static bool tomoyo_strendswith(const char *name, const char *tail)
}
/**
- * tomoyo_get_path - Get realpath.
+ * tomoyo_get_realpath - Get realpath.
*
+ * @buf: Pointer to "struct tomoyo_path_info".
* @path: Pointer to "struct path".
*
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ * Returns true on success, false otherwise.
*/
-static struct tomoyo_path_info *tomoyo_get_path(struct path *path)
+static bool tomoyo_get_realpath(struct tomoyo_path_info *buf, struct path *path)
{
- int error;
- struct tomoyo_path_info_with_data *buf = kzalloc(sizeof(*buf),
- GFP_NOFS);
-
- if (!buf)
- return NULL;
- /* Reserve one byte for appending "/". */
- error = tomoyo_realpath_from_path2(path, buf->body,
- sizeof(buf->body) - 2);
- if (!error) {
- buf->head.name = buf->body;
- tomoyo_fill_path_info(&buf->head);
- return &buf->head;
+ buf->name = tomoyo_realpath_from_path(path);
+ if (buf->name) {
+ tomoyo_fill_path_info(buf);
+ return true;
}
- kfree(buf);
- return NULL;
+ return false;
}
static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
@@ -199,7 +270,7 @@ static int tomoyo_update_globally_readable_entry(const char *filename,
struct tomoyo_globally_readable_file_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
- if (!tomoyo_is_correct_path(filename, 1, 0, -1))
+ if (!tomoyo_is_correct_word(filename))
return -EINVAL;
e.filename = tomoyo_get_name(filename);
if (!e.filename)
@@ -343,13 +414,14 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
const bool is_delete)
{
struct tomoyo_pattern_entry *ptr;
- struct tomoyo_pattern_entry e = { .pattern = tomoyo_get_name(pattern) };
+ struct tomoyo_pattern_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
+ if (!tomoyo_is_correct_word(pattern))
+ return -EINVAL;
+ e.pattern = tomoyo_get_name(pattern);
if (!e.pattern)
return error;
- if (!e.pattern->is_patterned)
- goto out;
if (mutex_lock_interruptible(&tomoyo_policy_lock))
goto out;
list_for_each_entry_rcu(ptr, &tomoyo_pattern_list, list) {
@@ -374,7 +446,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
}
/**
- * tomoyo_get_file_pattern - Get patterned pathname.
+ * tomoyo_file_pattern - Get patterned pathname.
*
* @filename: The filename to find patterned pathname.
*
@@ -382,8 +454,7 @@ static int tomoyo_update_file_pattern_entry(const char *pattern,
*
* Caller holds tomoyo_read_lock().
*/
-static const struct tomoyo_path_info *
-tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
+const char *tomoyo_file_pattern(const struct tomoyo_path_info *filename)
{
struct tomoyo_pattern_entry *ptr;
const struct tomoyo_path_info *pattern = NULL;
@@ -403,7 +474,7 @@ tomoyo_get_file_pattern(const struct tomoyo_path_info *filename)
}
if (pattern)
filename = pattern;
- return filename;
+ return filename->name;
}
/**
@@ -496,7 +567,7 @@ static int tomoyo_update_no_rewrite_entry(const char *pattern,
struct tomoyo_no_rewrite_entry e = { };
int error = is_delete ? -ENOENT : -ENOMEM;
- if (!tomoyo_is_correct_path(pattern, 0, 0, 0))
+ if (!tomoyo_is_correct_word(pattern))
return -EINVAL;
e.pattern = tomoyo_get_name(pattern);
if (!e.pattern)
@@ -596,8 +667,8 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
/**
* tomoyo_update_file_acl - Update file's read/write/execute ACL.
*
- * @filename: Filename.
* @perm: Permission (between 1 to 7).
+ * @filename: Filename.
* @domain: Pointer to "struct tomoyo_domain_info".
* @is_delete: True if it is a delete request.
*
@@ -610,7 +681,7 @@ bool tomoyo_read_no_rewrite_policy(struct tomoyo_io_buffer *head)
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_update_file_acl(const char *filename, u8 perm,
+static int tomoyo_update_file_acl(u8 perm, const char *filename,
struct tomoyo_domain_info * const domain,
const bool is_delete)
{
@@ -638,21 +709,21 @@ static int tomoyo_update_file_acl(const char *filename, u8 perm,
}
/**
- * tomoyo_path_acl2 - Check permission for single path operation.
+ * tomoyo_path_acl - Check permission for single path operation.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @filename: Filename to check.
* @perm: Permission.
- * @may_use_pattern: True if patterned ACL is permitted.
*
* Returns 0 on success, -EPERM otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
- const struct tomoyo_path_info *filename,
- const u32 perm, const bool may_use_pattern)
+static int tomoyo_path_acl(const struct tomoyo_request_info *r,
+ const struct tomoyo_path_info *filename,
+ const u32 perm)
{
+ struct tomoyo_domain_info *domain = r->domain;
struct tomoyo_acl_info *ptr;
int error = -EPERM;
@@ -661,15 +732,8 @@ static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
if (ptr->type != TOMOYO_TYPE_PATH_ACL)
continue;
acl = container_of(ptr, struct tomoyo_path_acl, head);
- if (perm <= 0xFFFF) {
- if (!(acl->perm & perm))
- continue;
- } else {
- if (!(acl->perm_high & (perm >> 16)))
- continue;
- }
- if (!tomoyo_compare_name_union_pattern(filename, &acl->name,
- may_use_pattern))
+ if (!(acl->perm & perm) ||
+ !tomoyo_compare_name_union(filename, &acl->name))
continue;
error = 0;
break;
@@ -678,139 +742,59 @@ static int tomoyo_path_acl2(const struct tomoyo_domain_info *domain,
}
/**
- * tomoyo_check_file_acl - Check permission for opening files.
- *
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @filename: Filename to check.
- * @operation: Mode ("read" or "write" or "read/write" or "execute").
- *
- * Returns 0 on success, -EPERM otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-static int tomoyo_check_file_acl(const struct tomoyo_domain_info *domain,
- const struct tomoyo_path_info *filename,
- const u8 operation)
-{
- u32 perm = 0;
-
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
- if (operation == 6)
- perm = 1 << TOMOYO_TYPE_READ_WRITE;
- else if (operation == 4)
- perm = 1 << TOMOYO_TYPE_READ;
- else if (operation == 2)
- perm = 1 << TOMOYO_TYPE_WRITE;
- else if (operation == 1)
- perm = 1 << TOMOYO_TYPE_EXECUTE;
- else
- BUG();
- return tomoyo_path_acl2(domain, filename, perm, operation != 1);
-}
-
-/**
- * tomoyo_check_file_perm2 - Check permission for opening files.
+ * tomoyo_file_perm - Check permission for opening files.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @filename: Filename to check.
- * @perm: Mode ("read" or "write" or "read/write" or "execute").
- * @operation: Operation name passed used for verbose mode.
- * @mode: Access control mode.
+ * @mode: Mode ("read" or "write" or "read/write" or "execute").
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_check_file_perm2(struct tomoyo_domain_info * const domain,
- const struct tomoyo_path_info *filename,
- const u8 perm, const char *operation,
- const u8 mode)
+static int tomoyo_file_perm(struct tomoyo_request_info *r,
+ const struct tomoyo_path_info *filename,
+ const u8 mode)
{
- const bool is_enforce = (mode == 3);
const char *msg = "<unknown>";
int error = 0;
+ u32 perm = 0;
if (!filename)
return 0;
- error = tomoyo_check_file_acl(domain, filename, perm);
- if (error && perm == 4 && !domain->ignore_global_allow_read
- && tomoyo_is_globally_readable_file(filename))
- error = 0;
- if (perm == 6)
+
+ if (mode == 6) {
msg = tomoyo_path2keyword(TOMOYO_TYPE_READ_WRITE);
- else if (perm == 4)
+ perm = 1 << TOMOYO_TYPE_READ_WRITE;
+ } else if (mode == 4) {
msg = tomoyo_path2keyword(TOMOYO_TYPE_READ);
- else if (perm == 2)
+ perm = 1 << TOMOYO_TYPE_READ;
+ } else if (mode == 2) {
msg = tomoyo_path2keyword(TOMOYO_TYPE_WRITE);
- else if (perm == 1)
+ perm = 1 << TOMOYO_TYPE_WRITE;
+ } else if (mode == 1) {
msg = tomoyo_path2keyword(TOMOYO_TYPE_EXECUTE);
- else
+ perm = 1 << TOMOYO_TYPE_EXECUTE;
+ } else
BUG();
- if (!error)
- return 0;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s(%s) %s' denied "
- "for %s\n", tomoyo_get_msg(is_enforce), msg, operation,
- filename->name, tomoyo_get_last_name(domain));
- if (is_enforce)
- return error;
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- /* Don't use patterns for execute permission. */
- const struct tomoyo_path_info *patterned_file = (perm != 1) ?
- tomoyo_get_file_pattern(filename) : filename;
- tomoyo_update_file_acl(patterned_file->name, perm,
- domain, false);
- }
- return 0;
-}
-
-/**
- * tomoyo_write_file_policy - Update file related list.
- *
- * @data: String to parse.
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @is_delete: True if it is a delete request.
- *
- * Returns 0 on success, negative value otherwise.
- *
- * Caller holds tomoyo_read_lock().
- */
-int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
- const bool is_delete)
-{
- char *filename = strchr(data, ' ');
- char *filename2;
- unsigned int perm;
- u8 type;
-
- if (!filename)
- return -EINVAL;
- *filename++ = '\0';
- if (sscanf(data, "%u", &perm) == 1)
- return tomoyo_update_file_acl(filename, (u8) perm, domain,
- is_delete);
- if (strncmp(data, "allow_", 6))
- goto out;
- data += 6;
- for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
- if (strcmp(data, tomoyo_path_keyword[type]))
- continue;
- return tomoyo_update_path_acl(type, filename, domain,
- is_delete);
- }
- filename2 = strchr(filename, ' ');
- if (!filename2)
- goto out;
- *filename2++ = '\0';
- for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
- if (strcmp(data, tomoyo_path2_keyword[type]))
- continue;
- return tomoyo_update_path2_acl(type, filename, filename2,
- domain, is_delete);
- }
- out:
- return -EINVAL;
+ do {
+ error = tomoyo_path_acl(r, filename, perm);
+ if (error && mode == 4 && !r->domain->ignore_global_allow_read
+ && tomoyo_is_globally_readable_file(filename))
+ error = 0;
+ if (!error)
+ break;
+ tomoyo_warn_log(r, "%s %s", msg, filename->name);
+ error = tomoyo_supervisor(r, "allow_%s %s\n", msg,
+ tomoyo_file_pattern(filename));
+ /*
+ * Do not retry for execute request, for alias may have
+ * changed.
+ */
+ } while (error == TOMOYO_RETRY_REQUEST && mode != 1);
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
}
/**
@@ -829,13 +813,12 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
struct tomoyo_domain_info *const domain,
const bool is_delete)
{
- static const u32 tomoyo_rw_mask =
+ static const u16 tomoyo_rw_mask =
(1 << TOMOYO_TYPE_READ) | (1 << TOMOYO_TYPE_WRITE);
- const u32 perm = 1 << type;
+ const u16 perm = 1 << type;
struct tomoyo_acl_info *ptr;
struct tomoyo_path_acl e = {
.head.type = TOMOYO_TYPE_PATH_ACL,
- .perm_high = perm >> 16,
.perm = perm
};
int error = is_delete ? -ENOENT : -ENOMEM;
@@ -854,19 +837,13 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
if (!tomoyo_is_same_path_acl(acl, &e))
continue;
if (is_delete) {
- if (perm <= 0xFFFF)
- acl->perm &= ~perm;
- else
- acl->perm_high &= ~(perm >> 16);
+ acl->perm &= ~perm;
if ((acl->perm & tomoyo_rw_mask) != tomoyo_rw_mask)
acl->perm &= ~(1 << TOMOYO_TYPE_READ_WRITE);
else if (!(acl->perm & (1 << TOMOYO_TYPE_READ_WRITE)))
acl->perm &= ~tomoyo_rw_mask;
} else {
- if (perm <= 0xFFFF)
- acl->perm |= perm;
- else
- acl->perm_high |= (perm >> 16);
+ acl->perm |= perm;
if ((acl->perm & tomoyo_rw_mask) == tomoyo_rw_mask)
acl->perm |= 1 << TOMOYO_TYPE_READ_WRITE;
else if (acl->perm & (1 << TOMOYO_TYPE_READ_WRITE))
@@ -891,6 +868,71 @@ static int tomoyo_update_path_acl(const u8 type, const char *filename,
}
/**
+ * tomoyo_update_path_number3_acl - Update "struct tomoyo_path_number3_acl" list.
+ *
+ * @type: Type of operation.
+ * @filename: Filename.
+ * @mode: Create mode.
+ * @major: Device major number.
+ * @minor: Device minor number.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_update_path_number3_acl(const u8 type,
+ const char *filename,
+ char *mode,
+ char *major, char *minor,
+ struct tomoyo_domain_info *
+ const domain,
+ const bool is_delete)
+{
+ const u8 perm = 1 << type;
+ struct tomoyo_acl_info *ptr;
+ struct tomoyo_path_number3_acl e = {
+ .head.type = TOMOYO_TYPE_PATH_NUMBER3_ACL,
+ .perm = perm
+ };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ if (!tomoyo_parse_name_union(filename, &e.name) ||
+ !tomoyo_parse_number_union(mode, &e.mode) ||
+ !tomoyo_parse_number_union(major, &e.major) ||
+ !tomoyo_parse_number_union(minor, &e.minor))
+ goto out;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_path_number3_acl *acl =
+ container_of(ptr, struct tomoyo_path_number3_acl, head);
+ if (!tomoyo_is_same_path_number3_acl(acl, &e))
+ continue;
+ if (is_delete)
+ acl->perm &= ~perm;
+ else
+ acl->perm |= perm;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error) {
+ struct tomoyo_path_number3_acl *entry =
+ tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ list_add_tail_rcu(&entry->head.list,
+ &domain->acl_info_list);
+ error = 0;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name_union(&e.name);
+ tomoyo_put_number_union(&e.mode);
+ tomoyo_put_number_union(&e.major);
+ tomoyo_put_number_union(&e.minor);
+ return error;
+}
+
+/**
* tomoyo_update_path2_acl - Update "struct tomoyo_path2_acl" list.
*
* @type: Type of operation.
@@ -952,28 +994,53 @@ static int tomoyo_update_path2_acl(const u8 type, const char *filename1,
}
/**
- * tomoyo_path_acl - Check permission for single path operation.
+ * tomoyo_path_number3_acl - Check permission for path/number/number/number operation.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
- * @type: Type of operation.
+ * @r: Pointer to "struct tomoyo_request_info".
* @filename: Filename to check.
+ * @perm: Permission.
+ * @mode: Create mode.
+ * @major: Device major number.
+ * @minor: Device minor number.
*
- * Returns 0 on success, negative value otherwise.
+ * Returns 0 on success, -EPERM otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
- const struct tomoyo_path_info *filename)
+static int tomoyo_path_number3_acl(struct tomoyo_request_info *r,
+ const struct tomoyo_path_info *filename,
+ const u16 perm, const unsigned int mode,
+ const unsigned int major,
+ const unsigned int minor)
{
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
- return tomoyo_path_acl2(domain, filename, 1 << type, 1);
+ struct tomoyo_domain_info *domain = r->domain;
+ struct tomoyo_acl_info *ptr;
+ int error = -EPERM;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_path_number3_acl *acl;
+ if (ptr->type != TOMOYO_TYPE_PATH_NUMBER3_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_path_number3_acl, head);
+ if (!tomoyo_compare_number_union(mode, &acl->mode))
+ continue;
+ if (!tomoyo_compare_number_union(major, &acl->major))
+ continue;
+ if (!tomoyo_compare_number_union(minor, &acl->minor))
+ continue;
+ if (!(acl->perm & perm))
+ continue;
+ if (!tomoyo_compare_name_union(filename, &acl->name))
+ continue;
+ error = 0;
+ break;
+ }
+ return error;
}
/**
* tomoyo_path2_acl - Check permission for double path operation.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @type: Type of operation.
* @filename1: First filename to check.
* @filename2: Second filename to check.
@@ -982,17 +1049,15 @@ static int tomoyo_path_acl(struct tomoyo_domain_info *domain, const u8 type,
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
- const u8 type,
+static int tomoyo_path2_acl(const struct tomoyo_request_info *r, const u8 type,
const struct tomoyo_path_info *filename1,
const struct tomoyo_path_info *filename2)
{
+ const struct tomoyo_domain_info *domain = r->domain;
struct tomoyo_acl_info *ptr;
const u8 perm = 1 << type;
int error = -EPERM;
- if (!tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE))
- return 0;
list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
struct tomoyo_path2_acl *acl;
if (ptr->type != TOMOYO_TYPE_PATH2_ACL)
@@ -1011,44 +1076,38 @@ static int tomoyo_path2_acl(const struct tomoyo_domain_info *domain,
}
/**
- * tomoyo_path_permission2 - Check permission for single path operation.
+ * tomoyo_path_permission - Check permission for single path operation.
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @operation: Type of operation.
* @filename: Filename to check.
- * @mode: Access control mode.
*
* Returns 0 on success, negative value otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
- u8 operation,
- const struct tomoyo_path_info *filename,
- const u8 mode)
+static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operation,
+ const struct tomoyo_path_info *filename)
{
const char *msg;
int error;
- const bool is_enforce = (mode == 3);
- if (!mode)
- return 0;
next:
- error = tomoyo_path_acl(domain, operation, filename);
- msg = tomoyo_path2keyword(operation);
- if (!error)
- goto ok;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s %s' denied for %s\n",
- tomoyo_get_msg(is_enforce), msg, filename->name,
- tomoyo_get_last_name(domain));
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name = tomoyo_get_file_pattern(filename)->name;
- tomoyo_update_path_acl(operation, name, domain, false);
- }
- if (!is_enforce)
+ r->type = tomoyo_p2mac[operation];
+ r->mode = tomoyo_get_mode(r->profile, r->type);
+ if (r->mode == TOMOYO_CONFIG_DISABLED)
+ return 0;
+ do {
+ error = tomoyo_path_acl(r, filename, 1 << operation);
+ if (!error)
+ break;
+ msg = tomoyo_path2keyword(operation);
+ tomoyo_warn_log(r, "%s %s", msg, filename->name);
+ error = tomoyo_supervisor(r, "allow_%s %s\n", msg,
+ tomoyo_file_pattern(filename));
+ } while (error == TOMOYO_RETRY_REQUEST);
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
- ok:
/*
* Since "allow_truncate" doesn't imply "allow_rewrite" permission,
* we need to check "allow_rewrite" permission if the filename is
@@ -1063,23 +1122,206 @@ static int tomoyo_path_permission2(struct tomoyo_domain_info *const domain,
}
/**
+ * tomoyo_path_number_acl - Check permission for ioctl/chmod/chown/chgrp operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @type: Operation.
+ * @filename: Filename to check.
+ * @number: Number.
+ *
+ * Returns 0 on success, -EPERM otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_path_number_acl(struct tomoyo_request_info *r, const u8 type,
+ const struct tomoyo_path_info *filename,
+ const unsigned long number)
+{
+ struct tomoyo_domain_info *domain = r->domain;
+ struct tomoyo_acl_info *ptr;
+ const u8 perm = 1 << type;
+ int error = -EPERM;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_path_number_acl *acl;
+ if (ptr->type != TOMOYO_TYPE_PATH_NUMBER_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_path_number_acl,
+ head);
+ if (!(acl->perm & perm) ||
+ !tomoyo_compare_number_union(number, &acl->number) ||
+ !tomoyo_compare_name_union(filename, &acl->name))
+ continue;
+ error = 0;
+ break;
+ }
+ return error;
+}
+
+/**
+ * tomoyo_update_path_number_acl - Update ioctl/chmod/chown/chgrp ACL.
+ *
+ * @type: Type of operation.
+ * @filename: Filename.
+ * @number: Number.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static inline int tomoyo_update_path_number_acl(const u8 type,
+ const char *filename,
+ char *number,
+ struct tomoyo_domain_info *
+ const domain,
+ const bool is_delete)
+{
+ const u8 perm = 1 << type;
+ struct tomoyo_acl_info *ptr;
+ struct tomoyo_path_number_acl e = {
+ .head.type = TOMOYO_TYPE_PATH_NUMBER_ACL,
+ .perm = perm
+ };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ if (!domain)
+ return -EINVAL;
+ if (!tomoyo_parse_name_union(filename, &e.name))
+ return -EINVAL;
+ if (!tomoyo_parse_number_union(number, &e.number))
+ goto out;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_path_number_acl *acl =
+ container_of(ptr, struct tomoyo_path_number_acl, head);
+ if (!tomoyo_is_same_path_number_acl(acl, &e))
+ continue;
+ if (is_delete)
+ acl->perm &= ~perm;
+ else
+ acl->perm |= perm;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error) {
+ struct tomoyo_path_number_acl *entry =
+ tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ list_add_tail_rcu(&entry->head.list,
+ &domain->acl_info_list);
+ error = 0;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name_union(&e.name);
+ tomoyo_put_number_union(&e.number);
+ return error;
+}
+
+/**
+ * tomoyo_path_number_perm2 - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
+ *
+ * @r: Pointer to "strct tomoyo_request_info".
+ * @filename: Filename to check.
+ * @number: Number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_path_number_perm2(struct tomoyo_request_info *r,
+ const u8 type,
+ const struct tomoyo_path_info *filename,
+ const unsigned long number)
+{
+ char buffer[64];
+ int error;
+ u8 radix;
+ const char *msg;
+
+ if (!filename)
+ return 0;
+ switch (type) {
+ case TOMOYO_TYPE_CREATE:
+ case TOMOYO_TYPE_MKDIR:
+ case TOMOYO_TYPE_MKFIFO:
+ case TOMOYO_TYPE_MKSOCK:
+ case TOMOYO_TYPE_CHMOD:
+ radix = TOMOYO_VALUE_TYPE_OCTAL;
+ break;
+ case TOMOYO_TYPE_IOCTL:
+ radix = TOMOYO_VALUE_TYPE_HEXADECIMAL;
+ break;
+ default:
+ radix = TOMOYO_VALUE_TYPE_DECIMAL;
+ break;
+ }
+ tomoyo_print_ulong(buffer, sizeof(buffer), number, radix);
+ do {
+ error = tomoyo_path_number_acl(r, type, filename, number);
+ if (!error)
+ break;
+ msg = tomoyo_path_number2keyword(type);
+ tomoyo_warn_log(r, "%s %s %s", msg, filename->name, buffer);
+ error = tomoyo_supervisor(r, "allow_%s %s %s\n", msg,
+ tomoyo_file_pattern(filename),
+ buffer);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
+}
+
+/**
+ * tomoyo_path_number_perm - Check permission for "create", "mkdir", "mkfifo", "mksock", "ioctl", "chmod", "chown", "chgrp".
+ *
+ * @type: Type of operation.
+ * @path: Pointer to "struct path".
+ * @number: Number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_path_number_perm(const u8 type, struct path *path,
+ unsigned long number)
+{
+ struct tomoyo_request_info r;
+ int error = -ENOMEM;
+ struct tomoyo_path_info buf;
+ int idx;
+
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_pn2mac[type])
+ == TOMOYO_CONFIG_DISABLED || !path->mnt || !path->dentry)
+ return 0;
+ idx = tomoyo_read_lock();
+ if (!tomoyo_get_realpath(&buf, path))
+ goto out;
+ if (type == TOMOYO_TYPE_MKDIR)
+ tomoyo_add_slash(&buf);
+ error = tomoyo_path_number_perm2(&r, type, &buf, number);
+ out:
+ kfree(buf.name);
+ tomoyo_read_unlock(idx);
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
+}
+
+/**
* tomoyo_check_exec_perm - Check permission for "execute".
*
- * @domain: Pointer to "struct tomoyo_domain_info".
+ * @r: Pointer to "struct tomoyo_request_info".
* @filename: Check permission for "execute".
*
* Returns 0 on success, negativevalue otherwise.
*
* Caller holds tomoyo_read_lock().
*/
-int tomoyo_check_exec_perm(struct tomoyo_domain_info *domain,
+int tomoyo_check_exec_perm(struct tomoyo_request_info *r,
const struct tomoyo_path_info *filename)
{
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
-
- if (!mode)
+ if (r->mode == TOMOYO_CONFIG_DISABLED)
return 0;
- return tomoyo_check_file_perm2(domain, filename, 1, "do_execve", mode);
+ return tomoyo_file_perm(r, filename, 1);
}
/**
@@ -1096,24 +1338,17 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
{
const u8 acc_mode = ACC_MODE(flag);
int error = -ENOMEM;
- struct tomoyo_path_info *buf;
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ struct tomoyo_path_info buf;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path->mnt)
- return 0;
- if (acc_mode == 0)
- return 0;
- if (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode))
- /*
- * I don't check directories here because mkdir() and rmdir()
- * don't call me.
- */
+ if (!path->mnt ||
+ (path->dentry->d_inode && S_ISDIR(path->dentry->d_inode->i_mode)))
return 0;
+ buf.name = NULL;
+ r.mode = TOMOYO_CONFIG_DISABLED;
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(path);
- if (!buf)
+ if (!tomoyo_get_realpath(&buf, path))
goto out;
error = 0;
/*
@@ -1121,28 +1356,36 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
* we need to check "allow_rewrite" permission when the filename is not
* opened for append mode or the filename is truncated at open time.
*/
- if ((acc_mode & MAY_WRITE) &&
- ((flag & O_TRUNC) || !(flag & O_APPEND)) &&
- (tomoyo_is_no_rewrite_file(buf))) {
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE,
- buf, mode);
+ if ((acc_mode & MAY_WRITE) && !(flag & O_APPEND)
+ && tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_REWRITE)
+ != TOMOYO_CONFIG_DISABLED) {
+ if (!tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ if (tomoyo_is_no_rewrite_file(&buf))
+ error = tomoyo_path_permission(&r, TOMOYO_TYPE_REWRITE,
+ &buf);
+ }
+ if (!error && acc_mode &&
+ tomoyo_init_request_info(&r, domain, TOMOYO_MAC_FILE_OPEN)
+ != TOMOYO_CONFIG_DISABLED) {
+ if (!buf.name && !tomoyo_get_realpath(&buf, path)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ error = tomoyo_file_perm(&r, &buf, acc_mode);
}
- if (!error)
- error = tomoyo_check_file_perm2(domain, buf, acc_mode, "open",
- mode);
- if (!error && (flag & O_TRUNC))
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_TRUNCATE,
- buf, mode);
out:
- kfree(buf);
+ kfree(buf.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
/**
- * tomoyo_path_perm - Check permission for "create", "unlink", "mkdir", "rmdir", "mkfifo", "mksock", "mkblock", "mkchar", "truncate", "symlink", "ioctl", "chmod", "chown", "chgrp", "chroot", "mount" and "unmount".
+ * tomoyo_path_perm - Check permission for "unlink", "rmdir", "truncate", "symlink", "rewrite", "chroot" and "unmount".
*
* @operation: Type of operation.
* @path: Pointer to "struct path".
@@ -1152,71 +1395,113 @@ int tomoyo_check_open_permission(struct tomoyo_domain_info *domain,
int tomoyo_path_perm(const u8 operation, struct path *path)
{
int error = -ENOMEM;
- struct tomoyo_path_info *buf;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
+ struct tomoyo_path_info buf;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path->mnt)
+ if (!path->mnt)
+ return 0;
+ if (tomoyo_init_request_info(&r, NULL, tomoyo_p2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
+ buf.name = NULL;
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(path);
- if (!buf)
+ if (!tomoyo_get_realpath(&buf, path))
goto out;
switch (operation) {
- case TOMOYO_TYPE_MKDIR:
+ case TOMOYO_TYPE_REWRITE:
+ if (!tomoyo_is_no_rewrite_file(&buf)) {
+ error = 0;
+ goto out;
+ }
+ break;
case TOMOYO_TYPE_RMDIR:
case TOMOYO_TYPE_CHROOT:
- if (!buf->is_dir) {
- /*
- * tomoyo_get_path() reserves space for appending "/."
- */
- strcat((char *) buf->name, "/");
- tomoyo_fill_path_info(buf);
- }
+ case TOMOYO_TYPE_UMOUNT:
+ tomoyo_add_slash(&buf);
+ break;
}
- error = tomoyo_path_permission2(domain, operation, buf, mode);
+ error = tomoyo_path_permission(&r, operation, &buf);
out:
- kfree(buf);
+ kfree(buf.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
+}
+
+/**
+ * tomoyo_path_number3_perm2 - Check permission for path/number/number/number operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @operation: Type of operation.
+ * @filename: Filename to check.
+ * @mode: Create mode.
+ * @dev: Device number.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_path_number3_perm2(struct tomoyo_request_info *r,
+ const u8 operation,
+ const struct tomoyo_path_info *filename,
+ const unsigned int mode,
+ const unsigned int dev)
+{
+ int error;
+ const char *msg;
+ const unsigned int major = MAJOR(dev);
+ const unsigned int minor = MINOR(dev);
+
+ do {
+ error = tomoyo_path_number3_acl(r, filename, 1 << operation,
+ mode, major, minor);
+ if (!error)
+ break;
+ msg = tomoyo_path_number32keyword(operation);
+ tomoyo_warn_log(r, "%s %s 0%o %u %u", msg, filename->name,
+ mode, major, minor);
+ error = tomoyo_supervisor(r, "allow_%s %s 0%o %u %u\n", msg,
+ tomoyo_file_pattern(filename), mode,
+ major, minor);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
/**
- * tomoyo_check_rewrite_permission - Check permission for "rewrite".
+ * tomoyo_path_number3_perm - Check permission for "mkblock" and "mkchar".
*
- * @filp: Pointer to "struct file".
+ * @operation: Type of operation. (TOMOYO_TYPE_MKCHAR or TOMOYO_TYPE_MKBLOCK)
+ * @path: Pointer to "struct path".
+ * @mode: Create mode.
+ * @dev: Device number.
*
* Returns 0 on success, negative value otherwise.
*/
-int tomoyo_check_rewrite_permission(struct file *filp)
+int tomoyo_path_number3_perm(const u8 operation, struct path *path,
+ const unsigned int mode, unsigned int dev)
{
+ struct tomoyo_request_info r;
int error = -ENOMEM;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
- struct tomoyo_path_info *buf;
+ struct tomoyo_path_info buf;
int idx;
- if (!mode || !filp->f_path.mnt)
+ if (!path->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pnnn2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
-
idx = tomoyo_read_lock();
- buf = tomoyo_get_path(&filp->f_path);
- if (!buf)
- goto out;
- if (!tomoyo_is_no_rewrite_file(buf)) {
- error = 0;
- goto out;
+ error = -ENOMEM;
+ if (tomoyo_get_realpath(&buf, path)) {
+ error = tomoyo_path_number3_perm2(&r, operation, &buf, mode,
+ new_decode_dev(dev));
+ kfree(buf.name);
}
- error = tomoyo_path_permission2(domain, TOMOYO_TYPE_REWRITE, buf, mode);
- out:
- kfree(buf);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
@@ -1234,56 +1519,107 @@ int tomoyo_path2_perm(const u8 operation, struct path *path1,
struct path *path2)
{
int error = -ENOMEM;
- struct tomoyo_path_info *buf1, *buf2;
- struct tomoyo_domain_info *domain = tomoyo_domain();
- const u8 mode = tomoyo_check_flags(domain, TOMOYO_MAC_FOR_FILE);
- const bool is_enforce = (mode == 3);
const char *msg;
+ struct tomoyo_path_info buf1;
+ struct tomoyo_path_info buf2;
+ struct tomoyo_request_info r;
int idx;
- if (!mode || !path1->mnt || !path2->mnt)
+ if (!path1->mnt || !path2->mnt ||
+ tomoyo_init_request_info(&r, NULL, tomoyo_pp2mac[operation])
+ == TOMOYO_CONFIG_DISABLED)
return 0;
+ buf1.name = NULL;
+ buf2.name = NULL;
idx = tomoyo_read_lock();
- buf1 = tomoyo_get_path(path1);
- buf2 = tomoyo_get_path(path2);
- if (!buf1 || !buf2)
- goto out;
- {
- struct dentry *dentry = path1->dentry;
- if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)) {
- /*
- * tomoyo_get_path() reserves space for appending "/."
- */
- if (!buf1->is_dir) {
- strcat((char *) buf1->name, "/");
- tomoyo_fill_path_info(buf1);
- }
- if (!buf2->is_dir) {
- strcat((char *) buf2->name, "/");
- tomoyo_fill_path_info(buf2);
- }
- }
- }
- error = tomoyo_path2_acl(domain, operation, buf1, buf2);
- msg = tomoyo_path22keyword(operation);
- if (!error)
+ if (!tomoyo_get_realpath(&buf1, path1) ||
+ !tomoyo_get_realpath(&buf2, path2))
goto out;
- if (tomoyo_verbose_mode(domain))
- printk(KERN_WARNING "TOMOYO-%s: Access '%s %s %s' "
- "denied for %s\n", tomoyo_get_msg(is_enforce),
- msg, buf1->name, buf2->name,
- tomoyo_get_last_name(domain));
- if (mode == 1 && tomoyo_domain_quota_is_ok(domain)) {
- const char *name1 = tomoyo_get_file_pattern(buf1)->name;
- const char *name2 = tomoyo_get_file_pattern(buf2)->name;
- tomoyo_update_path2_acl(operation, name1, name2, domain,
- false);
- }
+ switch (operation) {
+ struct dentry *dentry;
+ case TOMOYO_TYPE_RENAME:
+ case TOMOYO_TYPE_LINK:
+ dentry = path1->dentry;
+ if (!dentry->d_inode || !S_ISDIR(dentry->d_inode->i_mode))
+ break;
+ /* fall through */
+ case TOMOYO_TYPE_PIVOT_ROOT:
+ tomoyo_add_slash(&buf1);
+ tomoyo_add_slash(&buf2);
+ break;
+ }
+ do {
+ error = tomoyo_path2_acl(&r, operation, &buf1, &buf2);
+ if (!error)
+ break;
+ msg = tomoyo_path22keyword(operation);
+ tomoyo_warn_log(&r, "%s %s %s", msg, buf1.name, buf2.name);
+ error = tomoyo_supervisor(&r, "allow_%s %s %s\n", msg,
+ tomoyo_file_pattern(&buf1),
+ tomoyo_file_pattern(&buf2));
+ } while (error == TOMOYO_RETRY_REQUEST);
out:
- kfree(buf1);
- kfree(buf2);
+ kfree(buf1.name);
+ kfree(buf2.name);
tomoyo_read_unlock(idx);
- if (!is_enforce)
+ if (r.mode != TOMOYO_CONFIG_ENFORCING)
error = 0;
return error;
}
+
+/**
+ * tomoyo_write_file_policy - Update file related list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+int tomoyo_write_file_policy(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ char *w[5];
+ u8 type;
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[1][0])
+ return -EINVAL;
+ if (strncmp(w[0], "allow_", 6)) {
+ unsigned int perm;
+ if (sscanf(w[0], "%u", &perm) == 1)
+ return tomoyo_update_file_acl((u8) perm, w[1], domain,
+ is_delete);
+ goto out;
+ }
+ w[0] += 6;
+ for (type = 0; type < TOMOYO_MAX_PATH_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path_keyword[type]))
+ continue;
+ return tomoyo_update_path_acl(type, w[1], domain, is_delete);
+ }
+ if (!w[2][0])
+ goto out;
+ for (type = 0; type < TOMOYO_MAX_PATH2_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path2_keyword[type]))
+ continue;
+ return tomoyo_update_path2_acl(type, w[1], w[2], domain,
+ is_delete);
+ }
+ for (type = 0; type < TOMOYO_MAX_PATH_NUMBER_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path_number_keyword[type]))
+ continue;
+ return tomoyo_update_path_number_acl(type, w[1], w[2], domain,
+ is_delete);
+ }
+ if (!w[3][0] || !w[4][0])
+ goto out;
+ for (type = 0; type < TOMOYO_MAX_PATH_NUMBER3_OPERATION; type++) {
+ if (strcmp(w[0], tomoyo_path_number3_keyword[type]))
+ continue;
+ return tomoyo_update_path_number3_acl(type, w[1], w[2], w[3],
+ w[4], domain, is_delete);
+ }
+ out:
+ return -EINVAL;
+}
diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c
index b9cc71b04314..8a31f0c628b2 100644
--- a/security/tomoyo/gc.c
+++ b/security/tomoyo/gc.c
@@ -14,8 +14,11 @@
enum tomoyo_gc_id {
TOMOYO_ID_PATH_GROUP,
TOMOYO_ID_PATH_GROUP_MEMBER,
+ TOMOYO_ID_NUMBER_GROUP,
+ TOMOYO_ID_NUMBER_GROUP_MEMBER,
TOMOYO_ID_DOMAIN_INITIALIZER,
TOMOYO_ID_DOMAIN_KEEPER,
+ TOMOYO_ID_AGGREGATOR,
TOMOYO_ID_ALIAS,
TOMOYO_ID_GLOBALLY_READABLE,
TOMOYO_ID_PATTERN,
@@ -75,6 +78,12 @@ static void tomoyo_del_domain_keeper(struct tomoyo_domain_keeper_entry *ptr)
tomoyo_put_name(ptr->program);
}
+static void tomoyo_del_aggregator(struct tomoyo_aggregator_entry *ptr)
+{
+ tomoyo_put_name(ptr->original_name);
+ tomoyo_put_name(ptr->aggregated_name);
+}
+
static void tomoyo_del_alias(struct tomoyo_alias_entry *ptr)
{
tomoyo_put_name(ptr->original_name);
@@ -104,6 +113,34 @@ static void tomoyo_del_acl(struct tomoyo_acl_info *acl)
tomoyo_put_name_union(&entry->name2);
}
break;
+ case TOMOYO_TYPE_PATH_NUMBER_ACL:
+ {
+ struct tomoyo_path_number_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->name);
+ tomoyo_put_number_union(&entry->number);
+ }
+ break;
+ case TOMOYO_TYPE_PATH_NUMBER3_ACL:
+ {
+ struct tomoyo_path_number3_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->name);
+ tomoyo_put_number_union(&entry->mode);
+ tomoyo_put_number_union(&entry->major);
+ tomoyo_put_number_union(&entry->minor);
+ }
+ break;
+ case TOMOYO_TYPE_MOUNT_ACL:
+ {
+ struct tomoyo_mount_acl *entry
+ = container_of(acl, typeof(*entry), head);
+ tomoyo_put_name_union(&entry->dev_name);
+ tomoyo_put_name_union(&entry->dir_name);
+ tomoyo_put_name_union(&entry->fs_type);
+ tomoyo_put_number_union(&entry->flags);
+ }
+ break;
default:
printk(KERN_WARNING "Unknown type\n");
break;
@@ -162,6 +199,16 @@ static void tomoyo_del_path_group(struct tomoyo_path_group *group)
tomoyo_put_name(group->group_name);
}
+static void tomoyo_del_number_group_member(struct tomoyo_number_group_member
+ *member)
+{
+}
+
+static void tomoyo_del_number_group(struct tomoyo_number_group *group)
+{
+ tomoyo_put_name(group->group_name);
+}
+
static void tomoyo_collect_entry(void)
{
if (mutex_lock_interruptible(&tomoyo_policy_lock))
@@ -224,6 +271,17 @@ static void tomoyo_collect_entry(void)
}
}
{
+ struct tomoyo_aggregator_entry *ptr;
+ list_for_each_entry_rcu(ptr, &tomoyo_aggregator_list, list) {
+ if (!ptr->is_deleted)
+ continue;
+ if (tomoyo_add_to_gc(TOMOYO_ID_AGGREGATOR, ptr))
+ list_del_rcu(&ptr->list);
+ else
+ break;
+ }
+ }
+ {
struct tomoyo_alias_entry *ptr;
list_for_each_entry_rcu(ptr, &tomoyo_alias_list, list) {
if (!ptr->is_deleted)
@@ -256,10 +314,7 @@ static void tomoyo_collect_entry(void)
case TOMOYO_TYPE_PATH_ACL:
if (container_of(acl,
struct tomoyo_path_acl,
- head)->perm ||
- container_of(acl,
- struct tomoyo_path_acl,
- head)->perm_high)
+ head)->perm)
continue;
break;
case TOMOYO_TYPE_PATH2_ACL:
@@ -268,6 +323,18 @@ static void tomoyo_collect_entry(void)
head)->perm)
continue;
break;
+ case TOMOYO_TYPE_PATH_NUMBER_ACL:
+ if (container_of(acl,
+ struct tomoyo_path_number_acl,
+ head)->perm)
+ continue;
+ break;
+ case TOMOYO_TYPE_PATH_NUMBER3_ACL:
+ if (container_of(acl,
+ struct tomoyo_path_number3_acl,
+ head)->perm)
+ continue;
+ break;
default:
continue;
}
@@ -329,6 +396,29 @@ static void tomoyo_collect_entry(void)
break;
}
}
+ {
+ struct tomoyo_number_group *group;
+ list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) {
+ struct tomoyo_number_group_member *member;
+ list_for_each_entry_rcu(member, &group->member_list,
+ list) {
+ if (!member->is_deleted)
+ continue;
+ if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP_MEMBER,
+ member))
+ list_del_rcu(&member->list);
+ else
+ break;
+ }
+ if (!list_empty(&group->member_list) ||
+ atomic_read(&group->users))
+ continue;
+ if (tomoyo_add_to_gc(TOMOYO_ID_NUMBER_GROUP, group))
+ list_del_rcu(&group->list);
+ else
+ break;
+ }
+ }
mutex_unlock(&tomoyo_policy_lock);
}
@@ -345,6 +435,9 @@ static void tomoyo_kfree_entry(void)
case TOMOYO_ID_DOMAIN_KEEPER:
tomoyo_del_domain_keeper(p->element);
break;
+ case TOMOYO_ID_AGGREGATOR:
+ tomoyo_del_aggregator(p->element);
+ break;
case TOMOYO_ID_ALIAS:
tomoyo_del_alias(p->element);
break;
@@ -376,6 +469,12 @@ static void tomoyo_kfree_entry(void)
case TOMOYO_ID_PATH_GROUP:
tomoyo_del_path_group(p->element);
break;
+ case TOMOYO_ID_NUMBER_GROUP_MEMBER:
+ tomoyo_del_number_group_member(p->element);
+ break;
+ case TOMOYO_ID_NUMBER_GROUP:
+ tomoyo_del_number_group(p->element);
+ break;
default:
printk(KERN_WARNING "Unknown type\n");
break;
diff --git a/security/tomoyo/load_policy.c b/security/tomoyo/load_policy.c
new file mode 100644
index 000000000000..bbada7ca1b91
--- /dev/null
+++ b/security/tomoyo/load_policy.c
@@ -0,0 +1,81 @@
+/*
+ * security/tomoyo/load_policy.c
+ *
+ * Policy loader launcher for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include "common.h"
+
+/* path to policy loader */
+static const char *tomoyo_loader = "/sbin/tomoyo-init";
+
+/**
+ * tomoyo_policy_loader_exists - Check whether /sbin/tomoyo-init exists.
+ *
+ * Returns true if /sbin/tomoyo-init exists, false otherwise.
+ */
+static bool tomoyo_policy_loader_exists(void)
+{
+ /*
+ * Don't activate MAC if the policy loader doesn't exist.
+ * If the initrd includes /sbin/init but real-root-dev has not
+ * mounted on / yet, activating MAC will block the system since
+ * policies are not loaded yet.
+ * Thus, let do_execve() call this function everytime.
+ */
+ struct path path;
+
+ if (kern_path(tomoyo_loader, LOOKUP_FOLLOW, &path)) {
+ printk(KERN_INFO "Not activating Mandatory Access Control now "
+ "since %s doesn't exist.\n", tomoyo_loader);
+ return false;
+ }
+ path_put(&path);
+ return true;
+}
+
+/**
+ * tomoyo_load_policy - Run external policy loader to load policy.
+ *
+ * @filename: The program about to start.
+ *
+ * This function checks whether @filename is /sbin/init , and if so
+ * invoke /sbin/tomoyo-init and wait for the termination of /sbin/tomoyo-init
+ * and then continues invocation of /sbin/init.
+ * /sbin/tomoyo-init reads policy files in /etc/tomoyo/ directory and
+ * writes to /sys/kernel/security/tomoyo/ interfaces.
+ *
+ * Returns nothing.
+ */
+void tomoyo_load_policy(const char *filename)
+{
+ char *argv[2];
+ char *envp[3];
+
+ if (tomoyo_policy_loaded)
+ return;
+ /*
+ * Check filename is /sbin/init or /sbin/tomoyo-start.
+ * /sbin/tomoyo-start is a dummy filename in case where /sbin/init can't
+ * be passed.
+ * You can create /sbin/tomoyo-start by
+ * "ln -s /bin/true /sbin/tomoyo-start".
+ */
+ if (strcmp(filename, "/sbin/init") &&
+ strcmp(filename, "/sbin/tomoyo-start"))
+ return;
+ if (!tomoyo_policy_loader_exists())
+ return;
+
+ printk(KERN_INFO "Calling %s to load policy. Please wait.\n",
+ tomoyo_loader);
+ argv[0] = (char *) tomoyo_loader;
+ argv[1] = NULL;
+ envp[0] = "HOME=/";
+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+ envp[2] = NULL;
+ call_usermodehelper(argv[0], argv, envp, 1);
+ tomoyo_check_profile();
+}
diff --git a/security/tomoyo/memory.c b/security/tomoyo/memory.c
new file mode 100644
index 000000000000..4809febc1acb
--- /dev/null
+++ b/security/tomoyo/memory.c
@@ -0,0 +1,235 @@
+/*
+ * security/tomoyo/memory.c
+ *
+ * Memory management functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/hash.h>
+#include <linux/slab.h>
+#include "common.h"
+
+/**
+ * tomoyo_warn_oom - Print out of memory warning message.
+ *
+ * @function: Function's name.
+ */
+void tomoyo_warn_oom(const char *function)
+{
+ /* Reduce error messages. */
+ static pid_t tomoyo_last_pid;
+ const pid_t pid = current->pid;
+ if (tomoyo_last_pid != pid) {
+ printk(KERN_WARNING "ERROR: Out of memory at %s.\n",
+ function);
+ tomoyo_last_pid = pid;
+ }
+ if (!tomoyo_policy_loaded)
+ panic("MAC Initialization failed.\n");
+}
+
+/* Memory allocated for policy. */
+static atomic_t tomoyo_policy_memory_size;
+/* Quota for holding policy. */
+static unsigned int tomoyo_quota_for_policy;
+
+/**
+ * tomoyo_memory_ok - Check memory quota.
+ *
+ * @ptr: Pointer to allocated memory.
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Returns true if @ptr is not NULL and quota not exceeded, false otherwise.
+ */
+bool tomoyo_memory_ok(void *ptr)
+{
+ size_t s = ptr ? ksize(ptr) : 0;
+ atomic_add(s, &tomoyo_policy_memory_size);
+ if (ptr && (!tomoyo_quota_for_policy ||
+ atomic_read(&tomoyo_policy_memory_size)
+ <= tomoyo_quota_for_policy)) {
+ memset(ptr, 0, s);
+ return true;
+ }
+ atomic_sub(s, &tomoyo_policy_memory_size);
+ tomoyo_warn_oom(__func__);
+ return false;
+}
+
+/**
+ * tomoyo_commit_ok - Check memory quota.
+ *
+ * @data: Data to copy from.
+ * @size: Size in byte.
+ *
+ * Returns pointer to allocated memory on success, NULL otherwise.
+ * @data is zero-cleared on success.
+ */
+void *tomoyo_commit_ok(void *data, const unsigned int size)
+{
+ void *ptr = kzalloc(size, GFP_NOFS);
+ if (tomoyo_memory_ok(ptr)) {
+ memmove(ptr, data, size);
+ memset(data, 0, size);
+ return ptr;
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_memory_free - Free memory for elements.
+ *
+ * @ptr: Pointer to allocated memory.
+ */
+void tomoyo_memory_free(void *ptr)
+{
+ atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
+ kfree(ptr);
+}
+
+/*
+ * tomoyo_name_list is used for holding string data used by TOMOYO.
+ * Since same string data is likely used for multiple times (e.g.
+ * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
+ * "const struct tomoyo_path_info *".
+ */
+struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
+
+/**
+ * tomoyo_get_name - Allocate permanent memory for string data.
+ *
+ * @name: The string to store into the permernent memory.
+ *
+ * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
+ */
+const struct tomoyo_path_info *tomoyo_get_name(const char *name)
+{
+ struct tomoyo_name_entry *ptr;
+ unsigned int hash;
+ int len;
+ int allocated_len;
+ struct list_head *head;
+
+ if (!name)
+ return NULL;
+ len = strlen(name) + 1;
+ hash = full_name_hash((const unsigned char *) name, len - 1);
+ head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ return NULL;
+ list_for_each_entry(ptr, head, list) {
+ if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
+ continue;
+ atomic_inc(&ptr->users);
+ goto out;
+ }
+ ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
+ allocated_len = ptr ? ksize(ptr) : 0;
+ if (!ptr || (tomoyo_quota_for_policy &&
+ atomic_read(&tomoyo_policy_memory_size) + allocated_len
+ > tomoyo_quota_for_policy)) {
+ kfree(ptr);
+ ptr = NULL;
+ tomoyo_warn_oom(__func__);
+ goto out;
+ }
+ atomic_add(allocated_len, &tomoyo_policy_memory_size);
+ ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
+ memmove((char *) ptr->entry.name, name, len);
+ atomic_set(&ptr->users, 1);
+ tomoyo_fill_path_info(&ptr->entry);
+ list_add_tail(&ptr->list, head);
+ out:
+ mutex_unlock(&tomoyo_policy_lock);
+ return ptr ? &ptr->entry : NULL;
+}
+
+/**
+ * tomoyo_mm_init - Initialize mm related code.
+ */
+void __init tomoyo_mm_init(void)
+{
+ int idx;
+
+ for (idx = 0; idx < TOMOYO_MAX_HASH; idx++)
+ INIT_LIST_HEAD(&tomoyo_name_list[idx]);
+ INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
+ tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
+ list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
+ idx = tomoyo_read_lock();
+ if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
+ panic("Can't register tomoyo_kernel_domain");
+ {
+ /* Load built-in policy. */
+ tomoyo_write_domain_initializer_policy("/sbin/hotplug",
+ false, false);
+ tomoyo_write_domain_initializer_policy("/sbin/modprobe",
+ false, false);
+ }
+ tomoyo_read_unlock(idx);
+}
+
+
+/* Memory allocated for query lists. */
+unsigned int tomoyo_query_memory_size;
+/* Quota for holding query lists. */
+unsigned int tomoyo_quota_for_query;
+
+/**
+ * tomoyo_read_memory_counter - Check for memory usage in bytes.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns memory usage.
+ */
+int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
+{
+ if (!head->read_eof) {
+ const unsigned int policy
+ = atomic_read(&tomoyo_policy_memory_size);
+ const unsigned int query = tomoyo_query_memory_size;
+ char buffer[64];
+
+ memset(buffer, 0, sizeof(buffer));
+ if (tomoyo_quota_for_policy)
+ snprintf(buffer, sizeof(buffer) - 1,
+ " (Quota: %10u)",
+ tomoyo_quota_for_policy);
+ else
+ buffer[0] = '\0';
+ tomoyo_io_printf(head, "Policy: %10u%s\n", policy,
+ buffer);
+ if (tomoyo_quota_for_query)
+ snprintf(buffer, sizeof(buffer) - 1,
+ " (Quota: %10u)",
+ tomoyo_quota_for_query);
+ else
+ buffer[0] = '\0';
+ tomoyo_io_printf(head, "Query lists: %10u%s\n", query,
+ buffer);
+ tomoyo_io_printf(head, "Total: %10u\n", policy + query);
+ head->read_eof = true;
+ }
+ return 0;
+}
+
+/**
+ * tomoyo_write_memory_quota - Set memory quota.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns 0.
+ */
+int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
+{
+ char *data = head->write_buf;
+ unsigned int size;
+
+ if (sscanf(data, "Policy: %u", &size) == 1)
+ tomoyo_quota_for_policy = size;
+ else if (sscanf(data, "Query lists: %u", &size) == 1)
+ tomoyo_quota_for_query = size;
+ return 0;
+}
diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c
new file mode 100644
index 000000000000..77ee8bf41948
--- /dev/null
+++ b/security/tomoyo/mount.c
@@ -0,0 +1,312 @@
+/*
+ * security/tomoyo/mount.c
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Keywords for mount restrictions. */
+
+/* Allow to call 'mount --bind /source_dir /dest_dir' */
+#define TOMOYO_MOUNT_BIND_KEYWORD "--bind"
+/* Allow to call 'mount --move /old_dir /new_dir ' */
+#define TOMOYO_MOUNT_MOVE_KEYWORD "--move"
+/* Allow to call 'mount -o remount /dir ' */
+#define TOMOYO_MOUNT_REMOUNT_KEYWORD "--remount"
+/* Allow to call 'mount --make-unbindable /dir' */
+#define TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD "--make-unbindable"
+/* Allow to call 'mount --make-private /dir' */
+#define TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD "--make-private"
+/* Allow to call 'mount --make-slave /dir' */
+#define TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD "--make-slave"
+/* Allow to call 'mount --make-shared /dir' */
+#define TOMOYO_MOUNT_MAKE_SHARED_KEYWORD "--make-shared"
+
+/**
+ * tomoyo_mount_acl2 - Check permission for mount() operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file.
+ * @dir: Pointer to "struct path".
+ * @type: Name of filesystem type.
+ * @flags: Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl2(struct tomoyo_request_info *r, char *dev_name,
+ struct path *dir, char *type, unsigned long flags)
+{
+ struct path path;
+ struct tomoyo_acl_info *ptr;
+ struct file_system_type *fstype = NULL;
+ const char *requested_type = NULL;
+ const char *requested_dir_name = NULL;
+ const char *requested_dev_name = NULL;
+ struct tomoyo_path_info rtype;
+ struct tomoyo_path_info rdev;
+ struct tomoyo_path_info rdir;
+ int need_dev = 0;
+ int error = -ENOMEM;
+
+ /* Get fstype. */
+ requested_type = tomoyo_encode(type);
+ if (!requested_type)
+ goto out;
+ rtype.name = requested_type;
+ tomoyo_fill_path_info(&rtype);
+
+ /* Get mount point. */
+ requested_dir_name = tomoyo_realpath_from_path(dir);
+ if (!requested_dir_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+ rdir.name = requested_dir_name;
+ tomoyo_fill_path_info(&rdir);
+
+ /* Compare fs name. */
+ if (!strcmp(type, TOMOYO_MOUNT_REMOUNT_KEYWORD)) {
+ /* dev_name is ignored. */
+ } else if (!strcmp(type, TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MAKE_SHARED_KEYWORD)) {
+ /* dev_name is ignored. */
+ } else if (!strcmp(type, TOMOYO_MOUNT_BIND_KEYWORD) ||
+ !strcmp(type, TOMOYO_MOUNT_MOVE_KEYWORD)) {
+ need_dev = -1; /* dev_name is a directory */
+ } else {
+ fstype = get_fs_type(type);
+ if (!fstype) {
+ error = -ENODEV;
+ goto out;
+ }
+ if (fstype->fs_flags & FS_REQUIRES_DEV)
+ /* dev_name is a block device file. */
+ need_dev = 1;
+ }
+ if (need_dev) {
+ /* Get mount point or device file. */
+ if (kern_path(dev_name, LOOKUP_FOLLOW, &path)) {
+ error = -ENOENT;
+ goto out;
+ }
+ requested_dev_name = tomoyo_realpath_from_path(&path);
+ if (!requested_dev_name) {
+ error = -ENOENT;
+ goto out;
+ }
+ } else {
+ /* Map dev_name to "<NULL>" if no dev_name given. */
+ if (!dev_name)
+ dev_name = "<NULL>";
+ requested_dev_name = tomoyo_encode(dev_name);
+ if (!requested_dev_name) {
+ error = -ENOMEM;
+ goto out;
+ }
+ }
+ rdev.name = requested_dev_name;
+ tomoyo_fill_path_info(&rdev);
+ list_for_each_entry_rcu(ptr, &r->domain->acl_info_list, list) {
+ struct tomoyo_mount_acl *acl;
+ if (ptr->type != TOMOYO_TYPE_MOUNT_ACL)
+ continue;
+ acl = container_of(ptr, struct tomoyo_mount_acl, head);
+ if (acl->is_deleted ||
+ !tomoyo_compare_number_union(flags, &acl->flags) ||
+ !tomoyo_compare_name_union(&rtype, &acl->fs_type) ||
+ !tomoyo_compare_name_union(&rdir, &acl->dir_name) ||
+ (need_dev &&
+ !tomoyo_compare_name_union(&rdev, &acl->dev_name)))
+ continue;
+ error = 0;
+ break;
+ }
+ if (error)
+ error = tomoyo_supervisor(r, TOMOYO_KEYWORD_ALLOW_MOUNT
+ "%s %s %s 0x%lX\n",
+ tomoyo_file_pattern(&rdev),
+ tomoyo_file_pattern(&rdir),
+ requested_type, flags);
+ out:
+ kfree(requested_dev_name);
+ kfree(requested_dir_name);
+ if (fstype)
+ put_filesystem(fstype);
+ kfree(requested_type);
+ return error;
+}
+
+/**
+ * tomoyo_mount_acl - Check permission for mount() operation.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @dev_name: Name of device file.
+ * @dir: Pointer to "struct path".
+ * @type: Name of filesystem type.
+ * @flags: Mount options.
+ *
+ * Returns 0 on success, negative value otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+static int tomoyo_mount_acl(struct tomoyo_request_info *r, char *dev_name,
+ struct path *dir, char *type, unsigned long flags)
+{
+ int error;
+ error = -EPERM;
+ if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
+ flags &= ~MS_MGC_MSK;
+ switch (flags & (MS_REMOUNT | MS_MOVE | MS_BIND)) {
+ case MS_REMOUNT:
+ case MS_MOVE:
+ case MS_BIND:
+ case 0:
+ break;
+ default:
+ printk(KERN_WARNING "ERROR: "
+ "%s%s%sare given for single mount operation.\n",
+ flags & MS_REMOUNT ? "'remount' " : "",
+ flags & MS_MOVE ? "'move' " : "",
+ flags & MS_BIND ? "'bind' " : "");
+ return -EINVAL;
+ }
+ switch (flags & (MS_UNBINDABLE | MS_PRIVATE | MS_SLAVE | MS_SHARED)) {
+ case MS_UNBINDABLE:
+ case MS_PRIVATE:
+ case MS_SLAVE:
+ case MS_SHARED:
+ case 0:
+ break;
+ default:
+ printk(KERN_WARNING "ERROR: "
+ "%s%s%s%sare given for single mount operation.\n",
+ flags & MS_UNBINDABLE ? "'unbindable' " : "",
+ flags & MS_PRIVATE ? "'private' " : "",
+ flags & MS_SLAVE ? "'slave' " : "",
+ flags & MS_SHARED ? "'shared' " : "");
+ return -EINVAL;
+ }
+ if (flags & MS_REMOUNT)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_REMOUNT_KEYWORD,
+ flags & ~MS_REMOUNT);
+ else if (flags & MS_MOVE)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_MOVE_KEYWORD,
+ flags & ~MS_MOVE);
+ else if (flags & MS_BIND)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_BIND_KEYWORD,
+ flags & ~MS_BIND);
+ else if (flags & MS_UNBINDABLE)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_MAKE_UNBINDABLE_KEYWORD,
+ flags & ~MS_UNBINDABLE);
+ else if (flags & MS_PRIVATE)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_MAKE_PRIVATE_KEYWORD,
+ flags & ~MS_PRIVATE);
+ else if (flags & MS_SLAVE)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_MAKE_SLAVE_KEYWORD,
+ flags & ~MS_SLAVE);
+ else if (flags & MS_SHARED)
+ error = tomoyo_mount_acl(r, dev_name, dir,
+ TOMOYO_MOUNT_MAKE_SHARED_KEYWORD,
+ flags & ~MS_SHARED);
+ else
+ do {
+ error = tomoyo_mount_acl2(r, dev_name, dir, type,
+ flags);
+ } while (error == TOMOYO_RETRY_REQUEST);
+ if (r->mode != TOMOYO_CONFIG_ENFORCING)
+ error = 0;
+ return error;
+}
+
+/**
+ * tomoyo_mount_permission - Check permission for mount() operation.
+ *
+ * @dev_name: Name of device file.
+ * @path: Pointer to "struct path".
+ * @type: Name of filesystem type. May be NULL.
+ * @flags: Mount options.
+ * @data_page: Optional data. May be NULL.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_mount_permission(char *dev_name, struct path *path, char *type,
+ unsigned long flags, void *data_page)
+{
+ struct tomoyo_request_info r;
+ int error;
+ int idx;
+
+ if (tomoyo_init_request_info(&r, NULL, TOMOYO_MAC_FILE_MOUNT)
+ == TOMOYO_CONFIG_DISABLED)
+ return 0;
+ if (!type)
+ type = "<NULL>";
+ idx = tomoyo_read_lock();
+ error = tomoyo_mount_acl(&r, dev_name, path, type, flags);
+ tomoyo_read_unlock(idx);
+ return error;
+}
+
+/**
+ * tomoyo_write_mount_policy - Write "struct tomoyo_mount_acl" list.
+ *
+ * @data: String to parse.
+ * @domain: Pointer to "struct tomoyo_domain_info".
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+int tomoyo_write_mount_policy(char *data, struct tomoyo_domain_info *domain,
+ const bool is_delete)
+{
+ struct tomoyo_acl_info *ptr;
+ struct tomoyo_mount_acl e = { .head.type = TOMOYO_TYPE_MOUNT_ACL };
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ char *w[4];
+ if (!tomoyo_tokenize(data, w, sizeof(w)) || !w[3][0])
+ return -EINVAL;
+ if (!tomoyo_parse_name_union(w[0], &e.dev_name) ||
+ !tomoyo_parse_name_union(w[1], &e.dir_name) ||
+ !tomoyo_parse_name_union(w[2], &e.fs_type) ||
+ !tomoyo_parse_number_union(w[3], &e.flags))
+ goto out;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ struct tomoyo_mount_acl *acl =
+ container_of(ptr, struct tomoyo_mount_acl, head);
+ if (!tomoyo_is_same_mount_acl(acl, &e))
+ continue;
+ acl->is_deleted = is_delete;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error) {
+ struct tomoyo_mount_acl *entry =
+ tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ list_add_tail_rcu(&entry->head.list,
+ &domain->acl_info_list);
+ error = 0;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name_union(&e.dev_name);
+ tomoyo_put_name_union(&e.dir_name);
+ tomoyo_put_name_union(&e.fs_type);
+ tomoyo_put_number_union(&e.flags);
+ return error;
+}
diff --git a/security/tomoyo/number_group.c b/security/tomoyo/number_group.c
new file mode 100644
index 000000000000..8d6ef8f006ff
--- /dev/null
+++ b/security/tomoyo/number_group.c
@@ -0,0 +1,175 @@
+/*
+ * security/tomoyo/number_group.c
+ *
+ * Copyright (C) 2005-2009 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* The list for "struct tomoyo_number_group". */
+LIST_HEAD(tomoyo_number_group_list);
+
+/**
+ * tomoyo_get_number_group - Allocate memory for "struct tomoyo_number_group".
+ *
+ * @group_name: The name of number group.
+ *
+ * Returns pointer to "struct tomoyo_number_group" on success,
+ * NULL otherwise.
+ */
+struct tomoyo_number_group *tomoyo_get_number_group(const char *group_name)
+{
+ struct tomoyo_number_group *entry = NULL;
+ struct tomoyo_number_group *group = NULL;
+ const struct tomoyo_path_info *saved_group_name;
+ int error = -ENOMEM;
+ if (!tomoyo_is_correct_word(group_name))
+ return NULL;
+ saved_group_name = tomoyo_get_name(group_name);
+ if (!saved_group_name)
+ return NULL;
+ entry = kzalloc(sizeof(*entry), GFP_NOFS);
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(group, &tomoyo_number_group_list, list) {
+ if (saved_group_name != group->group_name)
+ continue;
+ atomic_inc(&group->users);
+ error = 0;
+ break;
+ }
+ if (error && tomoyo_memory_ok(entry)) {
+ INIT_LIST_HEAD(&entry->member_list);
+ entry->group_name = saved_group_name;
+ saved_group_name = NULL;
+ atomic_set(&entry->users, 1);
+ list_add_tail_rcu(&entry->list, &tomoyo_number_group_list);
+ group = entry;
+ entry = NULL;
+ error = 0;
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_name(saved_group_name);
+ kfree(entry);
+ return !error ? group : NULL;
+}
+
+/**
+ * tomoyo_write_number_group_policy - Write "struct tomoyo_number_group" list.
+ *
+ * @data: String to parse.
+ * @is_delete: True if it is a delete request.
+ *
+ * Returns 0 on success, nagative value otherwise.
+ */
+int tomoyo_write_number_group_policy(char *data, const bool is_delete)
+{
+ struct tomoyo_number_group *group;
+ struct tomoyo_number_group_member e = { };
+ struct tomoyo_number_group_member *member;
+ int error = is_delete ? -ENOENT : -ENOMEM;
+ char *w[2];
+ if (!tomoyo_tokenize(data, w, sizeof(w)))
+ return -EINVAL;
+ if (!tomoyo_parse_number_union(w[1], &e.number))
+ return -EINVAL;
+ if (e.number.is_group || e.number.values[0] > e.number.values[1]) {
+ tomoyo_put_number_union(&e.number);
+ return -EINVAL;
+ }
+ group = tomoyo_get_number_group(w[0]);
+ if (!group)
+ return -ENOMEM;
+ if (mutex_lock_interruptible(&tomoyo_policy_lock))
+ goto out;
+ list_for_each_entry_rcu(member, &group->member_list, list) {
+ if (memcmp(&member->number, &e.number, sizeof(e.number)))
+ continue;
+ member->is_deleted = is_delete;
+ error = 0;
+ break;
+ }
+ if (!is_delete && error) {
+ struct tomoyo_number_group_member *entry =
+ tomoyo_commit_ok(&e, sizeof(e));
+ if (entry) {
+ list_add_tail_rcu(&entry->list, &group->member_list);
+ error = 0;
+ }
+ }
+ mutex_unlock(&tomoyo_policy_lock);
+ out:
+ tomoyo_put_number_group(group);
+ return error;
+}
+
+/**
+ * tomoyo_read_number_group_policy - Read "struct tomoyo_number_group" list.
+ *
+ * @head: Pointer to "struct tomoyo_io_buffer".
+ *
+ * Returns true on success, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_read_number_group_policy(struct tomoyo_io_buffer *head)
+{
+ struct list_head *gpos;
+ struct list_head *mpos;
+ list_for_each_cookie(gpos, head->read_var1, &tomoyo_number_group_list) {
+ struct tomoyo_number_group *group;
+ const char *name;
+ group = list_entry(gpos, struct tomoyo_number_group, list);
+ name = group->group_name->name;
+ list_for_each_cookie(mpos, head->read_var2,
+ &group->member_list) {
+ int pos;
+ const struct tomoyo_number_group_member *member
+ = list_entry(mpos,
+ struct tomoyo_number_group_member,
+ list);
+ if (member->is_deleted)
+ continue;
+ pos = head->read_avail;
+ if (!tomoyo_io_printf(head, TOMOYO_KEYWORD_NUMBER_GROUP
+ "%s", name) ||
+ !tomoyo_print_number_union(head, &member->number) ||
+ !tomoyo_io_printf(head, "\n")) {
+ head->read_avail = pos;
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * tomoyo_number_matches_group - Check whether the given number matches members of the given number group.
+ *
+ * @min: Min number.
+ * @max: Max number.
+ * @group: Pointer to "struct tomoyo_number_group".
+ *
+ * Returns true if @min and @max partially overlaps @group, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_number_matches_group(const unsigned long min,
+ const unsigned long max,
+ const struct tomoyo_number_group *group)
+{
+ struct tomoyo_number_group_member *member;
+ bool matched = false;
+ list_for_each_entry_rcu(member, &group->member_list, list) {
+ if (member->is_deleted)
+ continue;
+ if (min > member->number.values[1] ||
+ max < member->number.values[0])
+ continue;
+ matched = true;
+ break;
+ }
+ return matched;
+}
diff --git a/security/tomoyo/path_group.c b/security/tomoyo/path_group.c
index c988041c8e1c..07e4f782367b 100644
--- a/security/tomoyo/path_group.c
+++ b/security/tomoyo/path_group.c
@@ -6,7 +6,7 @@
#include <linux/slab.h>
#include "common.h"
-/* The list for "struct ccs_path_group". */
+/* The list for "struct tomoyo_path_group". */
LIST_HEAD(tomoyo_path_group_list);
/**
@@ -22,8 +22,7 @@ struct tomoyo_path_group *tomoyo_get_path_group(const char *group_name)
struct tomoyo_path_group *group = NULL;
const struct tomoyo_path_info *saved_group_name;
int error = -ENOMEM;
- if (!tomoyo_is_correct_path(group_name, 0, 0, 0) ||
- !group_name[0])
+ if (!tomoyo_is_correct_word(group_name))
return NULL;
saved_group_name = tomoyo_get_name(group_name);
if (!saved_group_name)
@@ -141,29 +140,21 @@ bool tomoyo_read_path_group_policy(struct tomoyo_io_buffer *head)
*
* @pathname: The name of pathname.
* @group: Pointer to "struct tomoyo_path_group".
- * @may_use_pattern: True if wild card is permitted.
*
* Returns true if @pathname matches pathnames in @group, false otherwise.
*
* Caller holds tomoyo_read_lock().
*/
bool tomoyo_path_matches_group(const struct tomoyo_path_info *pathname,
- const struct tomoyo_path_group *group,
- const bool may_use_pattern)
+ const struct tomoyo_path_group *group)
{
struct tomoyo_path_group_member *member;
bool matched = false;
list_for_each_entry_rcu(member, &group->member_list, list) {
if (member->is_deleted)
continue;
- if (!member->member_name->is_patterned) {
- if (tomoyo_pathcmp(pathname, member->member_name))
- continue;
- } else if (may_use_pattern) {
- if (!tomoyo_path_matches_pattern(pathname,
- member->member_name))
- continue;
- } else
+ if (!tomoyo_path_matches_pattern(pathname,
+ member->member_name))
continue;
matched = true;
break;
diff --git a/security/tomoyo/realpath.c b/security/tomoyo/realpath.c
index d1b96f019621..153fa23a05cc 100644
--- a/security/tomoyo/realpath.c
+++ b/security/tomoyo/realpath.c
@@ -1,155 +1,164 @@
/*
* security/tomoyo/realpath.c
*
- * Get the canonicalized absolute pathnames. The basis for TOMOYO.
- *
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
+ * Pathname calculation functions for TOMOYO.
*
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/types.h>
#include <linux/mount.h>
#include <linux/mnt_namespace.h>
#include <linux/fs_struct.h>
-#include <linux/hash.h>
#include <linux/magic.h>
#include <linux/slab.h>
+#include <net/sock.h>
#include "common.h"
/**
* tomoyo_encode: Convert binary string to ascii string.
*
- * @buffer: Buffer for ASCII string.
- * @buflen: Size of @buffer.
- * @str: Binary string.
+ * @str: String in binary format.
*
- * Returns 0 on success, -ENOMEM otherwise.
+ * Returns pointer to @str in ascii format on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so caller must kfree() if this function
+ * didn't return NULL.
*/
-int tomoyo_encode(char *buffer, int buflen, const char *str)
+char *tomoyo_encode(const char *str)
{
- while (1) {
- const unsigned char c = *(unsigned char *) str++;
+ int len = 0;
+ const char *p = str;
+ char *cp;
+ char *cp0;
- if (tomoyo_is_valid(c)) {
- if (--buflen <= 0)
- break;
- *buffer++ = (char) c;
- if (c != '\\')
- continue;
- if (--buflen <= 0)
- break;
- *buffer++ = (char) c;
- continue;
- }
- if (!c) {
- if (--buflen <= 0)
- break;
- *buffer = '\0';
- return 0;
+ if (!p)
+ return NULL;
+ while (*p) {
+ const unsigned char c = *p++;
+ if (c == '\\')
+ len += 2;
+ else if (c > ' ' && c < 127)
+ len++;
+ else
+ len += 4;
+ }
+ len++;
+ /* Reserve space for appending "/". */
+ cp = kzalloc(len + 10, GFP_NOFS);
+ if (!cp)
+ return NULL;
+ cp0 = cp;
+ p = str;
+ while (*p) {
+ const unsigned char c = *p++;
+
+ if (c == '\\') {
+ *cp++ = '\\';
+ *cp++ = '\\';
+ } else if (c > ' ' && c < 127) {
+ *cp++ = c;
+ } else {
+ *cp++ = '\\';
+ *cp++ = (c >> 6) + '0';
+ *cp++ = ((c >> 3) & 7) + '0';
+ *cp++ = (c & 7) + '0';
}
- buflen -= 4;
- if (buflen <= 0)
- break;
- *buffer++ = '\\';
- *buffer++ = (c >> 6) + '0';
- *buffer++ = ((c >> 3) & 7) + '0';
- *buffer++ = (c & 7) + '0';
}
- return -ENOMEM;
+ return cp0;
}
/**
- * tomoyo_realpath_from_path2 - Returns realpath(3) of the given dentry but ignores chroot'ed root.
+ * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
*
- * @path: Pointer to "struct path".
- * @newname: Pointer to buffer to return value in.
- * @newname_len: Size of @newname.
+ * @path: Pointer to "struct path".
*
- * Returns 0 on success, negative value otherwise.
+ * Returns the realpath of the given @path on success, NULL otherwise.
*
* If dentry is a directory, trailing '/' is appended.
* Characters out of 0x20 < c < 0x7F range are converted to
* \ooo style octal string.
* Character \ is converted to \\ string.
+ *
+ * These functions use kzalloc(), so the caller must call kfree()
+ * if these functions didn't return NULL.
*/
-int tomoyo_realpath_from_path2(struct path *path, char *newname,
- int newname_len)
+char *tomoyo_realpath_from_path(struct path *path)
{
- int error = -ENOMEM;
+ char *buf = NULL;
+ char *name = NULL;
+ unsigned int buf_len = PAGE_SIZE / 2;
struct dentry *dentry = path->dentry;
- char *sp;
-
- if (!dentry || !path->mnt || !newname || newname_len <= 2048)
- return -EINVAL;
- if (dentry->d_op && dentry->d_op->d_dname) {
+ bool is_dir;
+ if (!dentry)
+ return NULL;
+ is_dir = dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode);
+ while (1) {
+ struct path ns_root = { .mnt = NULL, .dentry = NULL };
+ char *pos;
+ buf_len <<= 1;
+ kfree(buf);
+ buf = kmalloc(buf_len, GFP_NOFS);
+ if (!buf)
+ break;
+ /* Get better name for socket. */
+ if (dentry->d_sb && dentry->d_sb->s_magic == SOCKFS_MAGIC) {
+ struct inode *inode = dentry->d_inode;
+ struct socket *sock = inode ? SOCKET_I(inode) : NULL;
+ struct sock *sk = sock ? sock->sk : NULL;
+ if (sk) {
+ snprintf(buf, buf_len - 1, "socket:[family=%u:"
+ "type=%u:protocol=%u]", sk->sk_family,
+ sk->sk_type, sk->sk_protocol);
+ } else {
+ snprintf(buf, buf_len - 1, "socket:[unknown]");
+ }
+ name = tomoyo_encode(buf);
+ break;
+ }
/* For "socket:[\$]" and "pipe:[\$]". */
- static const int offset = 1536;
- sp = dentry->d_op->d_dname(dentry, newname + offset,
- newname_len - offset);
- } else {
- struct path ns_root = {.mnt = NULL, .dentry = NULL};
-
+ if (dentry->d_op && dentry->d_op->d_dname) {
+ pos = dentry->d_op->d_dname(dentry, buf, buf_len - 1);
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
+ }
+ /* If we don't have a vfsmount, we can't calculate. */
+ if (!path->mnt)
+ break;
spin_lock(&dcache_lock);
/* go to whatever namespace root we are under */
- sp = __d_path(path, &ns_root, newname, newname_len);
+ pos = __d_path(path, &ns_root, buf, buf_len);
spin_unlock(&dcache_lock);
/* Prepend "/proc" prefix if using internal proc vfs mount. */
- if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
+ if (!IS_ERR(pos) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
- sp -= 5;
- if (sp >= newname)
- memcpy(sp, "/proc", 5);
+ pos -= 5;
+ if (pos >= buf)
+ memcpy(pos, "/proc", 5);
else
- sp = ERR_PTR(-ENOMEM);
- }
- }
- if (IS_ERR(sp))
- error = PTR_ERR(sp);
- else
- error = tomoyo_encode(newname, sp - newname, sp);
- /* Append trailing '/' if dentry is a directory. */
- if (!error && dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode)
- && *newname) {
- sp = newname + strlen(newname);
- if (*(sp - 1) != '/') {
- if (sp < newname + newname_len - 4) {
- *sp++ = '/';
- *sp = '\0';
- } else {
- error = -ENOMEM;
- }
+ pos = ERR_PTR(-ENOMEM);
}
+ if (IS_ERR(pos))
+ continue;
+ name = tomoyo_encode(pos);
+ break;
}
- if (error)
- printk(KERN_WARNING "tomoyo_realpath: Pathname too long.\n");
- return error;
-}
-
-/**
- * tomoyo_realpath_from_path - Returns realpath(3) of the given pathname but ignores chroot'ed root.
- *
- * @path: Pointer to "struct path".
- *
- * Returns the realpath of the given @path on success, NULL otherwise.
- *
- * These functions use kzalloc(), so the caller must call kfree()
- * if these functions didn't return NULL.
- */
-char *tomoyo_realpath_from_path(struct path *path)
-{
- char *buf = kzalloc(sizeof(struct tomoyo_page_buffer), GFP_NOFS);
-
- BUILD_BUG_ON(sizeof(struct tomoyo_page_buffer)
- <= TOMOYO_MAX_PATHNAME_LEN - 1);
- if (!buf)
- return NULL;
- if (tomoyo_realpath_from_path2(path, buf,
- TOMOYO_MAX_PATHNAME_LEN - 1) == 0)
- return buf;
kfree(buf);
- return NULL;
+ if (!name)
+ tomoyo_warn_oom(__func__);
+ else if (is_dir && *name) {
+ /* Append trailing '/' if dentry is a directory. */
+ char *pos = name + strlen(name) - 1;
+ if (*pos != '/')
+ /*
+ * This is OK because tomoyo_encode() reserves space
+ * for appending "/".
+ */
+ *++pos = '/';
+ }
+ return name;
}
/**
@@ -189,191 +198,3 @@ char *tomoyo_realpath_nofollow(const char *pathname)
}
return NULL;
}
-
-/* Memory allocated for non-string data. */
-static atomic_t tomoyo_policy_memory_size;
-/* Quota for holding policy. */
-static unsigned int tomoyo_quota_for_policy;
-
-/**
- * tomoyo_memory_ok - Check memory quota.
- *
- * @ptr: Pointer to allocated memory.
- *
- * Returns true on success, false otherwise.
- *
- * Caller holds tomoyo_policy_lock.
- * Memory pointed by @ptr will be zeroed on success.
- */
-bool tomoyo_memory_ok(void *ptr)
-{
- int allocated_len = ptr ? ksize(ptr) : 0;
- atomic_add(allocated_len, &tomoyo_policy_memory_size);
- if (ptr && (!tomoyo_quota_for_policy ||
- atomic_read(&tomoyo_policy_memory_size)
- <= tomoyo_quota_for_policy)) {
- memset(ptr, 0, allocated_len);
- return true;
- }
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_alloc_element().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- return false;
-}
-
-/**
- * tomoyo_commit_ok - Check memory quota.
- *
- * @data: Data to copy from.
- * @size: Size in byte.
- *
- * Returns pointer to allocated memory on success, NULL otherwise.
- */
-void *tomoyo_commit_ok(void *data, const unsigned int size)
-{
- void *ptr = kzalloc(size, GFP_NOFS);
- if (tomoyo_memory_ok(ptr)) {
- memmove(ptr, data, size);
- memset(data, 0, size);
- return ptr;
- }
- return NULL;
-}
-
-/**
- * tomoyo_memory_free - Free memory for elements.
- *
- * @ptr: Pointer to allocated memory.
- */
-void tomoyo_memory_free(void *ptr)
-{
- atomic_sub(ksize(ptr), &tomoyo_policy_memory_size);
- kfree(ptr);
-}
-
-/*
- * tomoyo_name_list is used for holding string data used by TOMOYO.
- * Since same string data is likely used for multiple times (e.g.
- * "/lib/libc-2.5.so"), TOMOYO shares string data in the form of
- * "const struct tomoyo_path_info *".
- */
-struct list_head tomoyo_name_list[TOMOYO_MAX_HASH];
-
-/**
- * tomoyo_get_name - Allocate permanent memory for string data.
- *
- * @name: The string to store into the permernent memory.
- *
- * Returns pointer to "struct tomoyo_path_info" on success, NULL otherwise.
- */
-const struct tomoyo_path_info *tomoyo_get_name(const char *name)
-{
- struct tomoyo_name_entry *ptr;
- unsigned int hash;
- int len;
- int allocated_len;
- struct list_head *head;
-
- if (!name)
- return NULL;
- len = strlen(name) + 1;
- hash = full_name_hash((const unsigned char *) name, len - 1);
- head = &tomoyo_name_list[hash_long(hash, TOMOYO_HASH_BITS)];
- if (mutex_lock_interruptible(&tomoyo_policy_lock))
- return NULL;
- list_for_each_entry(ptr, head, list) {
- if (hash != ptr->entry.hash || strcmp(name, ptr->entry.name))
- continue;
- atomic_inc(&ptr->users);
- goto out;
- }
- ptr = kzalloc(sizeof(*ptr) + len, GFP_NOFS);
- allocated_len = ptr ? ksize(ptr) : 0;
- if (!ptr || (tomoyo_quota_for_policy &&
- atomic_read(&tomoyo_policy_memory_size) + allocated_len
- > tomoyo_quota_for_policy)) {
- kfree(ptr);
- printk(KERN_WARNING "ERROR: Out of memory "
- "for tomoyo_get_name().\n");
- if (!tomoyo_policy_loaded)
- panic("MAC Initialization failed.\n");
- ptr = NULL;
- goto out;
- }
- atomic_add(allocated_len, &tomoyo_policy_memory_size);
- ptr->entry.name = ((char *) ptr) + sizeof(*ptr);
- memmove((char *) ptr->entry.name, name, len);
- atomic_set(&ptr->users, 1);
- tomoyo_fill_path_info(&ptr->entry);
- list_add_tail(&ptr->list, head);
- out:
- mutex_unlock(&tomoyo_policy_lock);
- return ptr ? &ptr->entry : NULL;
-}
-
-/**
- * tomoyo_realpath_init - Initialize realpath related code.
- */
-void __init tomoyo_realpath_init(void)
-{
- int i;
-
- BUILD_BUG_ON(TOMOYO_MAX_PATHNAME_LEN > PATH_MAX);
- for (i = 0; i < TOMOYO_MAX_HASH; i++)
- INIT_LIST_HEAD(&tomoyo_name_list[i]);
- INIT_LIST_HEAD(&tomoyo_kernel_domain.acl_info_list);
- tomoyo_kernel_domain.domainname = tomoyo_get_name(TOMOYO_ROOT_NAME);
- /*
- * tomoyo_read_lock() is not needed because this function is
- * called before the first "delete" request.
- */
- list_add_tail_rcu(&tomoyo_kernel_domain.list, &tomoyo_domain_list);
- if (tomoyo_find_domain(TOMOYO_ROOT_NAME) != &tomoyo_kernel_domain)
- panic("Can't register tomoyo_kernel_domain");
-}
-
-/**
- * tomoyo_read_memory_counter - Check for memory usage in bytes.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns memory usage.
- */
-int tomoyo_read_memory_counter(struct tomoyo_io_buffer *head)
-{
- if (!head->read_eof) {
- const unsigned int policy
- = atomic_read(&tomoyo_policy_memory_size);
- char buffer[64];
-
- memset(buffer, 0, sizeof(buffer));
- if (tomoyo_quota_for_policy)
- snprintf(buffer, sizeof(buffer) - 1,
- " (Quota: %10u)",
- tomoyo_quota_for_policy);
- else
- buffer[0] = '\0';
- tomoyo_io_printf(head, "Policy: %10u%s\n", policy, buffer);
- tomoyo_io_printf(head, "Total: %10u\n", policy);
- head->read_eof = true;
- }
- return 0;
-}
-
-/**
- * tomoyo_write_memory_quota - Set memory quota.
- *
- * @head: Pointer to "struct tomoyo_io_buffer".
- *
- * Returns 0.
- */
-int tomoyo_write_memory_quota(struct tomoyo_io_buffer *head)
-{
- char *data = head->write_buf;
- unsigned int size;
-
- if (sscanf(data, "Policy: %u", &size) == 1)
- tomoyo_quota_for_policy = size;
- return 0;
-}
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
new file mode 100644
index 000000000000..5eb53510c4a7
--- /dev/null
+++ b/security/tomoyo/securityfs_if.c
@@ -0,0 +1,140 @@
+/*
+ * security/tomoyo/common.c
+ *
+ * Securityfs interface for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/security.h>
+#include "common.h"
+
+/**
+ * tomoyo_open - open() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_open(struct inode *inode, struct file *file)
+{
+ const int key = ((u8 *) file->f_path.dentry->d_inode->i_private)
+ - ((u8 *) NULL);
+ return tomoyo_open_control(key, file);
+}
+
+/**
+ * tomoyo_release - close() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @inode: Pointer to "struct inode".
+ * @file: Pointer to "struct file".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int tomoyo_release(struct inode *inode, struct file *file)
+{
+ return tomoyo_close_control(file);
+}
+
+/**
+ * tomoyo_read - read() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos: Unused.
+ *
+ * Returns bytes read on success, negative value otherwise.
+ */
+static ssize_t tomoyo_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ return tomoyo_read_control(file, buf, count);
+}
+
+/**
+ * tomoyo_write - write() for /sys/kernel/security/tomoyo/ interface.
+ *
+ * @file: Pointer to "struct file".
+ * @buf: Pointer to buffer.
+ * @count: Size of @buf.
+ * @ppos: Unused.
+ *
+ * Returns @count on success, negative value otherwise.
+ */
+static ssize_t tomoyo_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return tomoyo_write_control(file, buf, count);
+}
+
+/*
+ * tomoyo_operations is a "struct file_operations" which is used for handling
+ * /sys/kernel/security/tomoyo/ interface.
+ *
+ * Some files under /sys/kernel/security/tomoyo/ directory accept open(O_RDWR).
+ * See tomoyo_io_buffer for internals.
+ */
+static const struct file_operations tomoyo_operations = {
+ .open = tomoyo_open,
+ .release = tomoyo_release,
+ .read = tomoyo_read,
+ .write = tomoyo_write,
+};
+
+/**
+ * tomoyo_create_entry - Create interface files under /sys/kernel/security/tomoyo/ directory.
+ *
+ * @name: The name of the interface file.
+ * @mode: The permission of the interface file.
+ * @parent: The parent directory.
+ * @key: Type of interface.
+ *
+ * Returns nothing.
+ */
+static void __init tomoyo_create_entry(const char *name, const mode_t mode,
+ struct dentry *parent, const u8 key)
+{
+ securityfs_create_file(name, mode, parent, ((u8 *) NULL) + key,
+ &tomoyo_operations);
+}
+
+/**
+ * tomoyo_initerface_init - Initialize /sys/kernel/security/tomoyo/ interface.
+ *
+ * Returns 0.
+ */
+static int __init tomoyo_initerface_init(void)
+{
+ struct dentry *tomoyo_dir;
+
+ /* Don't create securityfs entries unless registered. */
+ if (current_cred()->security != &tomoyo_kernel_domain)
+ return 0;
+
+ tomoyo_dir = securityfs_create_dir("tomoyo", NULL);
+ tomoyo_create_entry("query", 0600, tomoyo_dir,
+ TOMOYO_QUERY);
+ tomoyo_create_entry("domain_policy", 0600, tomoyo_dir,
+ TOMOYO_DOMAINPOLICY);
+ tomoyo_create_entry("exception_policy", 0600, tomoyo_dir,
+ TOMOYO_EXCEPTIONPOLICY);
+ tomoyo_create_entry("self_domain", 0400, tomoyo_dir,
+ TOMOYO_SELFDOMAIN);
+ tomoyo_create_entry(".domain_status", 0600, tomoyo_dir,
+ TOMOYO_DOMAIN_STATUS);
+ tomoyo_create_entry(".process_status", 0600, tomoyo_dir,
+ TOMOYO_PROCESS_STATUS);
+ tomoyo_create_entry("meminfo", 0600, tomoyo_dir,
+ TOMOYO_MEMINFO);
+ tomoyo_create_entry("profile", 0600, tomoyo_dir,
+ TOMOYO_PROFILE);
+ tomoyo_create_entry("manager", 0600, tomoyo_dir,
+ TOMOYO_MANAGER);
+ tomoyo_create_entry("version", 0400, tomoyo_dir,
+ TOMOYO_VERSION);
+ return 0;
+}
+
+fs_initcall(tomoyo_initerface_init);
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c
index dedd97d0c163..7be732cadd47 100644
--- a/security/tomoyo/tomoyo.c
+++ b/security/tomoyo/tomoyo.c
@@ -3,10 +3,7 @@
*
* LSM hooks for TOMOYO Linux.
*
- * Copyright (C) 2005-2009 NTT DATA CORPORATION
- *
- * Version: 2.2.0 2009/04/01
- *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
*/
#include <linux/security.h>
@@ -96,8 +93,7 @@ static int tomoyo_bprm_check_security(struct linux_binprm *bprm)
return tomoyo_check_open_permission(domain, &bprm->file->f_path, O_RDONLY);
}
-static int tomoyo_path_truncate(struct path *path, loff_t length,
- unsigned int time_attrs)
+static int tomoyo_path_truncate(struct path *path)
{
return tomoyo_path_perm(TOMOYO_TYPE_TRUNCATE, path);
}
@@ -112,7 +108,8 @@ static int tomoyo_path_mkdir(struct path *parent, struct dentry *dentry,
int mode)
{
struct path path = { parent->mnt, dentry };
- return tomoyo_path_perm(TOMOYO_TYPE_MKDIR, &path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_MKDIR, &path,
+ mode & S_IALLUGO);
}
static int tomoyo_path_rmdir(struct path *parent, struct dentry *dentry)
@@ -133,6 +130,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
{
struct path path = { parent->mnt, dentry };
int type = TOMOYO_TYPE_CREATE;
+ const unsigned int perm = mode & S_IALLUGO;
switch (mode & S_IFMT) {
case S_IFCHR:
@@ -141,6 +139,12 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
case S_IFBLK:
type = TOMOYO_TYPE_MKBLOCK;
break;
+ default:
+ goto no_dev;
+ }
+ return tomoyo_path_number3_perm(type, &path, perm, dev);
+ no_dev:
+ switch (mode & S_IFMT) {
case S_IFIFO:
type = TOMOYO_TYPE_MKFIFO;
break;
@@ -148,7 +152,7 @@ static int tomoyo_path_mknod(struct path *parent, struct dentry *dentry,
type = TOMOYO_TYPE_MKSOCK;
break;
}
- return tomoyo_path_perm(type, &path);
+ return tomoyo_path_number_perm(type, &path, perm);
}
static int tomoyo_path_link(struct dentry *old_dentry, struct path *new_dir,
@@ -173,7 +177,7 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd,
unsigned long arg)
{
if (cmd == F_SETFL && ((arg ^ file->f_flags) & O_APPEND))
- return tomoyo_check_rewrite_permission(file);
+ return tomoyo_path_perm(TOMOYO_TYPE_REWRITE, &file->f_path);
return 0;
}
@@ -189,23 +193,24 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred)
static int tomoyo_file_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- return tomoyo_path_perm(TOMOYO_TYPE_IOCTL, &file->f_path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_IOCTL, &file->f_path, cmd);
}
static int tomoyo_path_chmod(struct dentry *dentry, struct vfsmount *mnt,
mode_t mode)
{
struct path path = { mnt, dentry };
- return tomoyo_path_perm(TOMOYO_TYPE_CHMOD, &path);
+ return tomoyo_path_number_perm(TOMOYO_TYPE_CHMOD, &path,
+ mode & S_IALLUGO);
}
static int tomoyo_path_chown(struct path *path, uid_t uid, gid_t gid)
{
int error = 0;
if (uid != (uid_t) -1)
- error = tomoyo_path_perm(TOMOYO_TYPE_CHOWN, path);
+ error = tomoyo_path_number_perm(TOMOYO_TYPE_CHOWN, path, uid);
if (!error && gid != (gid_t) -1)
- error = tomoyo_path_perm(TOMOYO_TYPE_CHGRP, path);
+ error = tomoyo_path_number_perm(TOMOYO_TYPE_CHGRP, path, gid);
return error;
}
@@ -217,7 +222,7 @@ static int tomoyo_path_chroot(struct path *path)
static int tomoyo_sb_mount(char *dev_name, struct path *path,
char *type, unsigned long flags, void *data)
{
- return tomoyo_path_perm(TOMOYO_TYPE_MOUNT, path);
+ return tomoyo_mount_permission(dev_name, path, type, flags, data);
}
static int tomoyo_sb_umount(struct vfsmount *mnt, int flags)
@@ -277,7 +282,7 @@ static int __init tomoyo_init(void)
panic("Failure registering TOMOYO Linux");
printk(KERN_INFO "TOMOYO Linux initialized\n");
cred->security = &tomoyo_kernel_domain;
- tomoyo_realpath_init();
+ tomoyo_mm_init();
return 0;
}
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c
new file mode 100644
index 000000000000..307793ed6075
--- /dev/null
+++ b/security/tomoyo/util.c
@@ -0,0 +1,963 @@
+/*
+ * security/tomoyo/util.c
+ *
+ * Utility functions for TOMOYO.
+ *
+ * Copyright (C) 2005-2010 NTT DATA CORPORATION
+ */
+
+#include <linux/slab.h>
+#include "common.h"
+
+/* Lock for protecting policy. */
+DEFINE_MUTEX(tomoyo_policy_lock);
+
+/* Has /sbin/init started? */
+bool tomoyo_policy_loaded;
+
+/**
+ * tomoyo_parse_ulong - Parse an "unsigned long" value.
+ *
+ * @result: Pointer to "unsigned long".
+ * @str: Pointer to string to parse.
+ *
+ * Returns value type on success, 0 otherwise.
+ *
+ * The @src is updated to point the first character after the value
+ * on success.
+ */
+u8 tomoyo_parse_ulong(unsigned long *result, char **str)
+{
+ const char *cp = *str;
+ char *ep;
+ int base = 10;
+ if (*cp == '0') {
+ char c = *(cp + 1);
+ if (c == 'x' || c == 'X') {
+ base = 16;
+ cp += 2;
+ } else if (c >= '0' && c <= '7') {
+ base = 8;
+ cp++;
+ }
+ }
+ *result = simple_strtoul(cp, &ep, base);
+ if (cp == ep)
+ return 0;
+ *str = ep;
+ switch (base) {
+ case 16:
+ return TOMOYO_VALUE_TYPE_HEXADECIMAL;
+ case 8:
+ return TOMOYO_VALUE_TYPE_OCTAL;
+ default:
+ return TOMOYO_VALUE_TYPE_DECIMAL;
+ }
+}
+
+/**
+ * tomoyo_print_ulong - Print an "unsigned long" value.
+ *
+ * @buffer: Pointer to buffer.
+ * @buffer_len: Size of @buffer.
+ * @value: An "unsigned long" value.
+ * @type: Type of @value.
+ *
+ * Returns nothing.
+ */
+void tomoyo_print_ulong(char *buffer, const int buffer_len,
+ const unsigned long value, const u8 type)
+{
+ if (type == TOMOYO_VALUE_TYPE_DECIMAL)
+ snprintf(buffer, buffer_len, "%lu", value);
+ else if (type == TOMOYO_VALUE_TYPE_OCTAL)
+ snprintf(buffer, buffer_len, "0%lo", value);
+ else if (type == TOMOYO_VALUE_TYPE_HEXADECIMAL)
+ snprintf(buffer, buffer_len, "0x%lX", value);
+ else
+ snprintf(buffer, buffer_len, "type(%u)", type);
+}
+
+/**
+ * tomoyo_parse_name_union - Parse a tomoyo_name_union.
+ *
+ * @filename: Name or name group.
+ * @ptr: Pointer to "struct tomoyo_name_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_name_union(const char *filename,
+ struct tomoyo_name_union *ptr)
+{
+ if (!tomoyo_is_correct_word(filename))
+ return false;
+ if (filename[0] == '@') {
+ ptr->group = tomoyo_get_path_group(filename + 1);
+ ptr->is_group = true;
+ return ptr->group != NULL;
+ }
+ ptr->filename = tomoyo_get_name(filename);
+ ptr->is_group = false;
+ return ptr->filename != NULL;
+}
+
+/**
+ * tomoyo_parse_number_union - Parse a tomoyo_number_union.
+ *
+ * @data: Number or number range or number group.
+ * @ptr: Pointer to "struct tomoyo_number_union".
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_parse_number_union(char *data, struct tomoyo_number_union *num)
+{
+ u8 type;
+ unsigned long v;
+ memset(num, 0, sizeof(*num));
+ if (data[0] == '@') {
+ if (!tomoyo_is_correct_word(data))
+ return false;
+ num->group = tomoyo_get_number_group(data + 1);
+ num->is_group = true;
+ return num->group != NULL;
+ }
+ type = tomoyo_parse_ulong(&v, &data);
+ if (!type)
+ return false;
+ num->values[0] = v;
+ num->min_type = type;
+ if (!*data) {
+ num->values[1] = v;
+ num->max_type = type;
+ return true;
+ }
+ if (*data++ != '-')
+ return false;
+ type = tomoyo_parse_ulong(&v, &data);
+ if (!type || *data)
+ return false;
+ num->values[1] = v;
+ num->max_type = type;
+ return true;
+}
+
+/**
+ * tomoyo_is_byte_range - Check whether the string is a \ooo style octal value.
+ *
+ * @str: Pointer to the string.
+ *
+ * Returns true if @str is a \ooo style octal value, false otherwise.
+ *
+ * TOMOYO uses \ooo style representation for 0x01 - 0x20 and 0x7F - 0xFF.
+ * This function verifies that \ooo is in valid range.
+ */
+static inline bool tomoyo_is_byte_range(const char *str)
+{
+ return *str >= '0' && *str++ <= '3' &&
+ *str >= '0' && *str++ <= '7' &&
+ *str >= '0' && *str <= '7';
+}
+
+/**
+ * tomoyo_is_alphabet_char - Check whether the character is an alphabet.
+ *
+ * @c: The character to check.
+ *
+ * Returns true if @c is an alphabet character, false otherwise.
+ */
+static inline bool tomoyo_is_alphabet_char(const char c)
+{
+ return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
+}
+
+/**
+ * tomoyo_make_byte - Make byte value from three octal characters.
+ *
+ * @c1: The first character.
+ * @c2: The second character.
+ * @c3: The third character.
+ *
+ * Returns byte value.
+ */
+static inline u8 tomoyo_make_byte(const u8 c1, const u8 c2, const u8 c3)
+{
+ return ((c1 - '0') << 6) + ((c2 - '0') << 3) + (c3 - '0');
+}
+
+/**
+ * tomoyo_str_starts - Check whether the given string starts with the given keyword.
+ *
+ * @src: Pointer to pointer to the string.
+ * @find: Pointer to the keyword.
+ *
+ * Returns true if @src starts with @find, false otherwise.
+ *
+ * The @src is updated to point the first character after the @find
+ * if @src starts with @find.
+ */
+bool tomoyo_str_starts(char **src, const char *find)
+{
+ const int len = strlen(find);
+ char *tmp = *src;
+
+ if (strncmp(tmp, find, len))
+ return false;
+ tmp += len;
+ *src = tmp;
+ return true;
+}
+
+/**
+ * tomoyo_normalize_line - Format string.
+ *
+ * @buffer: The line to normalize.
+ *
+ * Leading and trailing whitespaces are removed.
+ * Multiple whitespaces are packed into single space.
+ *
+ * Returns nothing.
+ */
+void tomoyo_normalize_line(unsigned char *buffer)
+{
+ unsigned char *sp = buffer;
+ unsigned char *dp = buffer;
+ bool first = true;
+
+ while (tomoyo_is_invalid(*sp))
+ sp++;
+ while (*sp) {
+ if (!first)
+ *dp++ = ' ';
+ first = false;
+ while (tomoyo_is_valid(*sp))
+ *dp++ = *sp++;
+ while (tomoyo_is_invalid(*sp))
+ sp++;
+ }
+ *dp = '\0';
+}
+
+/**
+ * tomoyo_tokenize - Tokenize string.
+ *
+ * @buffer: The line to tokenize.
+ * @w: Pointer to "char *".
+ * @size: Sizeof @w .
+ *
+ * Returns true on success, false otherwise.
+ */
+bool tomoyo_tokenize(char *buffer, char *w[], size_t size)
+{
+ int count = size / sizeof(char *);
+ int i;
+ for (i = 0; i < count; i++)
+ w[i] = "";
+ for (i = 0; i < count; i++) {
+ char *cp = strchr(buffer, ' ');
+ if (cp)
+ *cp = '\0';
+ w[i] = buffer;
+ if (!cp)
+ break;
+ buffer = cp + 1;
+ }
+ return i < count || !*buffer;
+}
+
+/**
+ * tomoyo_is_correct_word2 - Validate a string.
+ *
+ * @string: The string to check. May be non-'\0'-terminated.
+ * @len: Length of @string.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+static bool tomoyo_is_correct_word2(const char *string, size_t len)
+{
+ const char *const start = string;
+ bool in_repetition = false;
+ unsigned char c;
+ unsigned char d;
+ unsigned char e;
+ if (!len)
+ goto out;
+ while (len--) {
+ c = *string++;
+ if (c == '\\') {
+ if (!len--)
+ goto out;
+ c = *string++;
+ switch (c) {
+ case '\\': /* "\\" */
+ continue;
+ case '$': /* "\$" */
+ case '+': /* "\+" */
+ case '?': /* "\?" */
+ case '*': /* "\*" */
+ case '@': /* "\@" */
+ case 'x': /* "\x" */
+ case 'X': /* "\X" */
+ case 'a': /* "\a" */
+ case 'A': /* "\A" */
+ case '-': /* "\-" */
+ continue;
+ case '{': /* "/\{" */
+ if (string - 3 < start || *(string - 3) != '/')
+ break;
+ in_repetition = true;
+ continue;
+ case '}': /* "\}/" */
+ if (*string != '/')
+ break;
+ if (!in_repetition)
+ break;
+ in_repetition = false;
+ continue;
+ case '0': /* "\ooo" */
+ case '1':
+ case '2':
+ case '3':
+ if (!len-- || !len--)
+ break;
+ d = *string++;
+ e = *string++;
+ if (d < '0' || d > '7' || e < '0' || e > '7')
+ break;
+ c = tomoyo_make_byte(c, d, e);
+ if (tomoyo_is_invalid(c))
+ continue; /* pattern is not \000 */
+ }
+ goto out;
+ } else if (in_repetition && c == '/') {
+ goto out;
+ } else if (tomoyo_is_invalid(c)) {
+ goto out;
+ }
+ }
+ if (in_repetition)
+ goto out;
+ return true;
+ out:
+ return false;
+}
+
+/**
+ * tomoyo_is_correct_word - Validate a string.
+ *
+ * @string: The string to check.
+ *
+ * Check whether the given string follows the naming rules.
+ * Returns true if @string follows the naming rules, false otherwise.
+ */
+bool tomoyo_is_correct_word(const char *string)
+{
+ return tomoyo_is_correct_word2(string, strlen(string));
+}
+
+/**
+ * tomoyo_is_correct_path - Validate a pathname.
+ *
+ * @filename: The pathname to check.
+ *
+ * Check whether the given pathname follows the naming rules.
+ * Returns true if @filename follows the naming rules, false otherwise.
+ */
+bool tomoyo_is_correct_path(const char *filename)
+{
+ return *filename == '/' && tomoyo_is_correct_word(filename);
+}
+
+/**
+ * tomoyo_is_correct_domain - Check whether the given domainname follows the naming rules.
+ *
+ * @domainname: The domainname to check.
+ *
+ * Returns true if @domainname follows the naming rules, false otherwise.
+ */
+bool tomoyo_is_correct_domain(const unsigned char *domainname)
+{
+ if (!domainname || strncmp(domainname, TOMOYO_ROOT_NAME,
+ TOMOYO_ROOT_NAME_LEN))
+ goto out;
+ domainname += TOMOYO_ROOT_NAME_LEN;
+ if (!*domainname)
+ return true;
+ if (*domainname++ != ' ')
+ goto out;
+ while (1) {
+ const unsigned char *cp = strchr(domainname, ' ');
+ if (!cp)
+ break;
+ if (*domainname != '/' ||
+ !tomoyo_is_correct_word2(domainname, cp - domainname - 1))
+ goto out;
+ domainname = cp + 1;
+ }
+ return tomoyo_is_correct_path(domainname);
+ out:
+ return false;
+}
+
+/**
+ * tomoyo_is_domain_def - Check whether the given token can be a domainname.
+ *
+ * @buffer: The token to check.
+ *
+ * Returns true if @buffer possibly be a domainname, false otherwise.
+ */
+bool tomoyo_is_domain_def(const unsigned char *buffer)
+{
+ return !strncmp(buffer, TOMOYO_ROOT_NAME, TOMOYO_ROOT_NAME_LEN);
+}
+
+/**
+ * tomoyo_find_domain - Find a domain by the given name.
+ *
+ * @domainname: The domainname to find.
+ *
+ * Returns pointer to "struct tomoyo_domain_info" if found, NULL otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+struct tomoyo_domain_info *tomoyo_find_domain(const char *domainname)
+{
+ struct tomoyo_domain_info *domain;
+ struct tomoyo_path_info name;
+
+ name.name = domainname;
+ tomoyo_fill_path_info(&name);
+ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) {
+ if (!domain->is_deleted &&
+ !tomoyo_pathcmp(&name, domain->domainname))
+ return domain;
+ }
+ return NULL;
+}
+
+/**
+ * tomoyo_const_part_length - Evaluate the initial length without a pattern in a token.
+ *
+ * @filename: The string to evaluate.
+ *
+ * Returns the initial length without a pattern in @filename.
+ */
+static int tomoyo_const_part_length(const char *filename)
+{
+ char c;
+ int len = 0;
+
+ if (!filename)
+ return 0;
+ while ((c = *filename++) != '\0') {
+ if (c != '\\') {
+ len++;
+ continue;
+ }
+ c = *filename++;
+ switch (c) {
+ case '\\': /* "\\" */
+ len += 2;
+ continue;
+ case '0': /* "\ooo" */
+ case '1':
+ case '2':
+ case '3':
+ c = *filename++;
+ if (c < '0' || c > '7')
+ break;
+ c = *filename++;
+ if (c < '0' || c > '7')
+ break;
+ len += 4;
+ continue;
+ }
+ break;
+ }
+ return len;
+}
+
+/**
+ * tomoyo_fill_path_info - Fill in "struct tomoyo_path_info" members.
+ *
+ * @ptr: Pointer to "struct tomoyo_path_info" to fill in.
+ *
+ * The caller sets "struct tomoyo_path_info"->name.
+ */
+void tomoyo_fill_path_info(struct tomoyo_path_info *ptr)
+{
+ const char *name = ptr->name;
+ const int len = strlen(name);
+
+ ptr->const_len = tomoyo_const_part_length(name);
+ ptr->is_dir = len && (name[len - 1] == '/');
+ ptr->is_patterned = (ptr->const_len < len);
+ ptr->hash = full_name_hash(name, len);
+}
+
+/**
+ * tomoyo_file_matches_pattern2 - Pattern matching without '/' character and "\-" pattern.
+ *
+ * @filename: The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern: The start of pattern to compare.
+ * @pattern_end: The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern2(const char *filename,
+ const char *filename_end,
+ const char *pattern,
+ const char *pattern_end)
+{
+ while (filename < filename_end && pattern < pattern_end) {
+ char c;
+ if (*pattern != '\\') {
+ if (*filename++ != *pattern++)
+ return false;
+ continue;
+ }
+ c = *filename;
+ pattern++;
+ switch (*pattern) {
+ int i;
+ int j;
+ case '?':
+ if (c == '/') {
+ return false;
+ } else if (c == '\\') {
+ if (filename[1] == '\\')
+ filename++;
+ else if (tomoyo_is_byte_range(filename + 1))
+ filename += 3;
+ else
+ return false;
+ }
+ break;
+ case '\\':
+ if (c != '\\')
+ return false;
+ if (*++filename != '\\')
+ return false;
+ break;
+ case '+':
+ if (!isdigit(c))
+ return false;
+ break;
+ case 'x':
+ if (!isxdigit(c))
+ return false;
+ break;
+ case 'a':
+ if (!tomoyo_is_alphabet_char(c))
+ return false;
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ if (c == '\\' && tomoyo_is_byte_range(filename + 1)
+ && strncmp(filename + 1, pattern, 3) == 0) {
+ filename += 3;
+ pattern += 2;
+ break;
+ }
+ return false; /* Not matched. */
+ case '*':
+ case '@':
+ for (i = 0; i <= filename_end - filename; i++) {
+ if (tomoyo_file_matches_pattern2(
+ filename + i, filename_end,
+ pattern + 1, pattern_end))
+ return true;
+ c = filename[i];
+ if (c == '.' && *pattern == '@')
+ break;
+ if (c != '\\')
+ continue;
+ if (filename[i + 1] == '\\')
+ i++;
+ else if (tomoyo_is_byte_range(filename + i + 1))
+ i += 3;
+ else
+ break; /* Bad pattern. */
+ }
+ return false; /* Not matched. */
+ default:
+ j = 0;
+ c = *pattern;
+ if (c == '$') {
+ while (isdigit(filename[j]))
+ j++;
+ } else if (c == 'X') {
+ while (isxdigit(filename[j]))
+ j++;
+ } else if (c == 'A') {
+ while (tomoyo_is_alphabet_char(filename[j]))
+ j++;
+ }
+ for (i = 1; i <= j; i++) {
+ if (tomoyo_file_matches_pattern2(
+ filename + i, filename_end,
+ pattern + 1, pattern_end))
+ return true;
+ }
+ return false; /* Not matched or bad pattern. */
+ }
+ filename++;
+ pattern++;
+ }
+ while (*pattern == '\\' &&
+ (*(pattern + 1) == '*' || *(pattern + 1) == '@'))
+ pattern += 2;
+ return filename == filename_end && pattern == pattern_end;
+}
+
+/**
+ * tomoyo_file_matches_pattern - Pattern matching without '/' character.
+ *
+ * @filename: The start of string to check.
+ * @filename_end: The end of string to check.
+ * @pattern: The start of pattern to compare.
+ * @pattern_end: The end of pattern to compare.
+ *
+ * Returns true if @filename matches @pattern, false otherwise.
+ */
+static bool tomoyo_file_matches_pattern(const char *filename,
+ const char *filename_end,
+ const char *pattern,
+ const char *pattern_end)
+{
+ const char *pattern_start = pattern;
+ bool first = true;
+ bool result;
+
+ while (pattern < pattern_end - 1) {
+ /* Split at "\-" pattern. */
+ if (*pattern++ != '\\' || *pattern++ != '-')
+ continue;
+ result = tomoyo_file_matches_pattern2(filename,
+ filename_end,
+ pattern_start,
+ pattern - 2);
+ if (first)
+ result = !result;
+ if (result)
+ return false;
+ first = false;
+ pattern_start = pattern;
+ }
+ result = tomoyo_file_matches_pattern2(filename, filename_end,
+ pattern_start, pattern_end);
+ return first ? result : !result;
+}
+
+/**
+ * tomoyo_path_matches_pattern2 - Do pathname pattern matching.
+ *
+ * @f: The start of string to check.
+ * @p: The start of pattern to compare.
+ *
+ * Returns true if @f matches @p, false otherwise.
+ */
+static bool tomoyo_path_matches_pattern2(const char *f, const char *p)
+{
+ const char *f_delimiter;
+ const char *p_delimiter;
+
+ while (*f && *p) {
+ f_delimiter = strchr(f, '/');
+ if (!f_delimiter)
+ f_delimiter = f + strlen(f);
+ p_delimiter = strchr(p, '/');
+ if (!p_delimiter)
+ p_delimiter = p + strlen(p);
+ if (*p == '\\' && *(p + 1) == '{')
+ goto recursive;
+ if (!tomoyo_file_matches_pattern(f, f_delimiter, p,
+ p_delimiter))
+ return false;
+ f = f_delimiter;
+ if (*f)
+ f++;
+ p = p_delimiter;
+ if (*p)
+ p++;
+ }
+ /* Ignore trailing "\*" and "\@" in @pattern. */
+ while (*p == '\\' &&
+ (*(p + 1) == '*' || *(p + 1) == '@'))
+ p += 2;
+ return !*f && !*p;
+ recursive:
+ /*
+ * The "\{" pattern is permitted only after '/' character.
+ * This guarantees that below "*(p - 1)" is safe.
+ * Also, the "\}" pattern is permitted only before '/' character
+ * so that "\{" + "\}" pair will not break the "\-" operator.
+ */
+ if (*(p - 1) != '/' || p_delimiter <= p + 3 || *p_delimiter != '/' ||
+ *(p_delimiter - 1) != '}' || *(p_delimiter - 2) != '\\')
+ return false; /* Bad pattern. */
+ do {
+ /* Compare current component with pattern. */
+ if (!tomoyo_file_matches_pattern(f, f_delimiter, p + 2,
+ p_delimiter - 2))
+ break;
+ /* Proceed to next component. */
+ f = f_delimiter;
+ if (!*f)
+ break;
+ f++;
+ /* Continue comparison. */
+ if (tomoyo_path_matches_pattern2(f, p_delimiter + 1))
+ return true;
+ f_delimiter = strchr(f, '/');
+ } while (f_delimiter);
+ return false; /* Not matched. */
+}
+
+/**
+ * tomoyo_path_matches_pattern - Check whether the given filename matches the given pattern.
+ *
+ * @filename: The filename to check.
+ * @pattern: The pattern to compare.
+ *
+ * Returns true if matches, false otherwise.
+ *
+ * The following patterns are available.
+ * \\ \ itself.
+ * \ooo Octal representation of a byte.
+ * \* Zero or more repetitions of characters other than '/'.
+ * \@ Zero or more repetitions of characters other than '/' or '.'.
+ * \? 1 byte character other than '/'.
+ * \$ One or more repetitions of decimal digits.
+ * \+ 1 decimal digit.
+ * \X One or more repetitions of hexadecimal digits.
+ * \x 1 hexadecimal digit.
+ * \A One or more repetitions of alphabet characters.
+ * \a 1 alphabet character.
+ *
+ * \- Subtraction operator.
+ *
+ * /\{dir\}/ '/' + 'One or more repetitions of dir/' (e.g. /dir/ /dir/dir/
+ * /dir/dir/dir/ ).
+ */
+bool tomoyo_path_matches_pattern(const struct tomoyo_path_info *filename,
+ const struct tomoyo_path_info *pattern)
+{
+ const char *f = filename->name;
+ const char *p = pattern->name;
+ const int len = pattern->const_len;
+
+ /* If @pattern doesn't contain pattern, I can use strcmp(). */
+ if (!pattern->is_patterned)
+ return !tomoyo_pathcmp(filename, pattern);
+ /* Don't compare directory and non-directory. */
+ if (filename->is_dir != pattern->is_dir)
+ return false;
+ /* Compare the initial length without patterns. */
+ if (strncmp(f, p, len))
+ return false;
+ f += len;
+ p += len;
+ return tomoyo_path_matches_pattern2(f, p);
+}
+
+/**
+ * tomoyo_get_exe - Get tomoyo_realpath() of current process.
+ *
+ * Returns the tomoyo_realpath() of current process on success, NULL otherwise.
+ *
+ * This function uses kzalloc(), so the caller must call kfree()
+ * if this function didn't return NULL.
+ */
+const char *tomoyo_get_exe(void)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ const char *cp = NULL;
+
+ if (!mm)
+ return NULL;
+ down_read(&mm->mmap_sem);
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) {
+ cp = tomoyo_realpath_from_path(&vma->vm_file->f_path);
+ break;
+ }
+ }
+ up_read(&mm->mmap_sem);
+ return cp;
+}
+
+/**
+ * tomoyo_get_mode - Get MAC mode.
+ *
+ * @profile: Profile number.
+ * @index: Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_get_mode(const u8 profile, const u8 index)
+{
+ u8 mode;
+ const u8 category = TOMOYO_MAC_CATEGORY_FILE;
+ if (!tomoyo_policy_loaded)
+ return TOMOYO_CONFIG_DISABLED;
+ mode = tomoyo_profile(profile)->config[index];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->config[category];
+ if (mode == TOMOYO_CONFIG_USE_DEFAULT)
+ mode = tomoyo_profile(profile)->default_config;
+ return mode & 3;
+}
+
+/**
+ * tomoyo_init_request_info - Initialize "struct tomoyo_request_info" members.
+ *
+ * @r: Pointer to "struct tomoyo_request_info" to initialize.
+ * @domain: Pointer to "struct tomoyo_domain_info". NULL for tomoyo_domain().
+ * @index: Index number of functionality.
+ *
+ * Returns mode.
+ */
+int tomoyo_init_request_info(struct tomoyo_request_info *r,
+ struct tomoyo_domain_info *domain, const u8 index)
+{
+ u8 profile;
+ memset(r, 0, sizeof(*r));
+ if (!domain)
+ domain = tomoyo_domain();
+ r->domain = domain;
+ profile = domain->profile;
+ r->profile = profile;
+ r->type = index;
+ r->mode = tomoyo_get_mode(profile, index);
+ return r->mode;
+}
+
+/**
+ * tomoyo_last_word - Get last component of a line.
+ *
+ * @line: A line.
+ *
+ * Returns the last word of a line.
+ */
+static const char *tomoyo_last_word(const char *name)
+{
+ const char *cp = strrchr(name, ' ');
+ if (cp)
+ return cp + 1;
+ return name;
+}
+
+/**
+ * tomoyo_warn_log - Print warning or error message on console.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ * @fmt: The printf()'s format string, followed by parameters.
+ */
+void tomoyo_warn_log(struct tomoyo_request_info *r, const char *fmt, ...)
+{
+ va_list args;
+ char *buffer;
+ const struct tomoyo_domain_info * const domain = r->domain;
+ const struct tomoyo_profile *profile = tomoyo_profile(domain->profile);
+ switch (r->mode) {
+ case TOMOYO_CONFIG_ENFORCING:
+ if (!profile->enforcing->enforcing_verbose)
+ return;
+ break;
+ case TOMOYO_CONFIG_PERMISSIVE:
+ if (!profile->permissive->permissive_verbose)
+ return;
+ break;
+ case TOMOYO_CONFIG_LEARNING:
+ if (!profile->learning->learning_verbose)
+ return;
+ break;
+ }
+ buffer = kmalloc(4096, GFP_NOFS);
+ if (!buffer)
+ return;
+ va_start(args, fmt);
+ vsnprintf(buffer, 4095, fmt, args);
+ va_end(args);
+ buffer[4095] = '\0';
+ printk(KERN_WARNING "%s: Access %s denied for %s\n",
+ r->mode == TOMOYO_CONFIG_ENFORCING ? "ERROR" : "WARNING", buffer,
+ tomoyo_last_word(domain->domainname->name));
+ kfree(buffer);
+}
+
+/**
+ * tomoyo_domain_quota_is_ok - Check for domain's quota.
+ *
+ * @r: Pointer to "struct tomoyo_request_info".
+ *
+ * Returns true if the domain is not exceeded quota, false otherwise.
+ *
+ * Caller holds tomoyo_read_lock().
+ */
+bool tomoyo_domain_quota_is_ok(struct tomoyo_request_info *r)
+{
+ unsigned int count = 0;
+ struct tomoyo_domain_info *domain = r->domain;
+ struct tomoyo_acl_info *ptr;
+
+ if (r->mode != TOMOYO_CONFIG_LEARNING)
+ return false;
+ if (!domain)
+ return true;
+ list_for_each_entry_rcu(ptr, &domain->acl_info_list, list) {
+ switch (ptr->type) {
+ u16 perm;
+ u8 i;
+ case TOMOYO_TYPE_PATH_ACL:
+ perm = container_of(ptr, struct tomoyo_path_acl, head)
+ ->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ if (perm & (1 << TOMOYO_TYPE_READ_WRITE))
+ count -= 2;
+ break;
+ case TOMOYO_TYPE_PATH2_ACL:
+ perm = container_of(ptr, struct tomoyo_path2_acl, head)
+ ->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH2_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ case TOMOYO_TYPE_PATH_NUMBER_ACL:
+ perm = container_of(ptr, struct tomoyo_path_number_acl,
+ head)->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH_NUMBER_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ case TOMOYO_TYPE_PATH_NUMBER3_ACL:
+ perm = container_of(ptr, struct tomoyo_path_number3_acl,
+ head)->perm;
+ for (i = 0; i < TOMOYO_MAX_PATH_NUMBER3_OPERATION; i++)
+ if (perm & (1 << i))
+ count++;
+ break;
+ case TOMOYO_TYPE_MOUNT_ACL:
+ if (!container_of(ptr, struct tomoyo_mount_acl, head)->
+ is_deleted)
+ count++;
+ }
+ }
+ if (count < tomoyo_profile(domain->profile)->learning->
+ learning_max_entry)
+ return true;
+ if (!domain->quota_warned) {
+ domain->quota_warned = true;
+ printk(KERN_WARNING "TOMOYO-WARNING: "
+ "Domain '%s' has so many ACLs to hold. "
+ "Stopped learning mode.\n", domain->domainname->name);
+ }
+ return false;
+}
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index 678933721735..3ff8cc5f487a 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -437,9 +437,11 @@ static int i2sbus_shutdown(struct macio_dev* dev)
}
static struct macio_driver i2sbus_drv = {
- .name = "soundbus-i2s",
- .owner = THIS_MODULE,
- .match_table = i2sbus_match,
+ .driver = {
+ .name = "soundbus-i2s",
+ .owner = THIS_MODULE,
+ .of_match_table = i2sbus_match,
+ },
.probe = i2sbus_probe,
.remove = i2sbus_remove,
#ifdef CONFIG_PM
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c
index ea2bf82c9373..434af3c56d52 100644
--- a/sound/core/pcm_misc.c
+++ b/sound/core/pcm_misc.c
@@ -128,6 +128,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 4, .phys = 4, .le = -1, .signd = -1,
.silence = {},
},
+ [SNDRV_PCM_FORMAT_G723_24] = {
+ .width = 3, .phys = 3, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40] = {
+ .width = 5, .phys = 5, .le = -1, .signd = -1,
+ .silence = {},
+ },
/* FIXME: the following three formats are not defined properly yet */
[SNDRV_PCM_FORMAT_MPEG] = {
.le = -1, .signd = -1,
@@ -186,6 +194,14 @@ static struct pcm_format_data pcm_formats[SNDRV_PCM_FORMAT_LAST+1] = {
.width = 18, .phys = 24, .le = 0, .signd = 0,
.silence = { 0x02, 0x00, 0x00 },
},
+ [SNDRV_PCM_FORMAT_G723_24_1B] = {
+ .width = 3, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
+ [SNDRV_PCM_FORMAT_G723_40_1B] = {
+ .width = 5, .phys = 8, .le = -1, .signd = -1,
+ .silence = {},
+ },
};
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index f74c7372b3d1..1db586af4f9c 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (err)
return -err;
+ memset(&prev_ctl, 0, sizeof(prev_ctl));
+ prev_ctl.control_type = -1;
+
for (idx = 0; idx < 2000; idx++) {
err = hpi_mixer_get_control_by_index(
ss, asihpi->h_mixer,
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index dc79564fea30..1df25cf5ce38 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
if (WARN_ONCE(!azx_dev->period_bytes,
"hda-intel: zero azx_dev->period_bytes"))
return -1; /* this shouldn't happen! */
- if (wallclk <= azx_dev->period_wallclk &&
+ if (wallclk < (azx_dev->period_wallclk * 5) / 4 &&
pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
/* NG - it's below the first next period boundary */
return bdl_pos_adj[chip->dev_index] ? 0 : -1;
- azx_dev->start_wallclk = wallclk;
+ azx_dev->start_wallclk += wallclk;
return 1; /* OK, it's fine */
}
@@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
@@ -2296,6 +2298,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
+ SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
{}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 17d4548cc353..d792cddbf4c2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
+ SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc67979..d35f848db6b5 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,9 +28,12 @@ source "sound/soc/atmel/Kconfig"
source "sound/soc/au1x/Kconfig"
source "sound/soc/blackfin/Kconfig"
source "sound/soc/davinci/Kconfig"
+source "sound/soc/ep93xx/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/imx/Kconfig"
+source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
+source "sound/soc/kirkwood/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141d4167..97661b747b91 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,9 +6,12 @@ obj-$(CONFIG_SND_SOC) += atmel/
obj-$(CONFIG_SND_SOC) += au1x/
obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += davinci/
+obj-$(CONFIG_SND_SOC) += ep93xx/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
+obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
+obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
diff --git a/sound/soc/atmel/atmel-pcm.c b/sound/soc/atmel/atmel-pcm.c
index f6b3cc04b34b..dc5249fba85c 100644
--- a/sound/soc/atmel/atmel-pcm.c
+++ b/sound/soc/atmel/atmel-pcm.c
@@ -77,7 +77,6 @@ struct atmel_runtime_data {
size_t period_size;
dma_addr_t period_ptr; /* physical address of next period */
- int periods; /* period index of period_ptr */
/* PDC register save */
u32 pdc_xpr_save;
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index 0b59806905d1..c85844d4845b 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -549,7 +549,6 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream,
printk(KERN_WARNING "atmel_ssc_dai: unsupported DAI format 0x%x\n",
ssc_p->daifmt);
return -EINVAL;
- break;
}
pr_debug("atmel_ssc_hw_params: "
"RCMR=%08x RFMR=%08x TCMR=%08x TFMR=%08x\n",
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index a61ccd2d505f..d14a5a91a465 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -375,12 +375,10 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
}
ret = -EBUSY;
- wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
- "au1xpsc_ac97");
- if (!wd->ioarea)
+ if (!request_mem_region(r->start, resource_size(r), pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, 0xffff);
+ wd->mmio = ioremap(r->start, resource_size(r));
if (!wd->mmio)
goto out1;
@@ -410,8 +408,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
snd_soc_unregister_dai(&au1xpsc_ac97_dai);
out1:
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
out0:
kfree(wd);
return ret;
@@ -420,6 +417,7 @@ out0:
static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
{
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
@@ -433,8 +431,7 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
au_sync();
iounmap(wd->mmio);
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
kfree(wd);
au1xpsc_ac97_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c
index 495be6e71931..737b2384f6c5 100644
--- a/sound/soc/au1x/psc-i2s.c
+++ b/sound/soc/au1x/psc-i2s.c
@@ -321,12 +321,10 @@ static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev)
}
ret = -EBUSY;
- wd->ioarea = request_mem_region(r->start, r->end - r->start + 1,
- "au1xpsc_i2s");
- if (!wd->ioarea)
+ if (!request_mem_region(r->start, resource_size(r), pdev->name))
goto out0;
- wd->mmio = ioremap(r->start, 0xffff);
+ wd->mmio = ioremap(r->start, resource_size(r));
if (!wd->mmio)
goto out1;
@@ -362,8 +360,7 @@ static int __init au1xpsc_i2s_drvprobe(struct platform_device *pdev)
snd_soc_unregister_dai(&au1xpsc_i2s_dai);
out1:
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
out0:
kfree(wd);
return ret;
@@ -372,6 +369,7 @@ out0:
static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
{
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
+ struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (wd->dmapd)
au1xpsc_pcm_destroy(wd->dmapd);
@@ -384,8 +382,7 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
au_sync();
iounmap(wd->mmio);
- release_resource(wd->ioarea);
- kfree(wd->ioarea);
+ release_mem_region(r->start, resource_size(r));
kfree(wd);
au1xpsc_i2s_workdata = NULL; /* MDEV */
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h
index 32d3807d3f5a..093775d4dc3e 100644
--- a/sound/soc/au1x/psc.h
+++ b/sound/soc/au1x/psc.h
@@ -32,7 +32,6 @@ struct au1xpsc_audio_data {
unsigned long rate;
unsigned long pm[2];
- struct resource *ioarea;
struct mutex lock;
struct platform_device *dmapd;
};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 31ac5538fe7e..c37c84458b58 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -22,6 +22,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
+ select SND_SOC_CS42L51 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_DA7210 if I2C
@@ -120,6 +121,9 @@ config SND_SOC_AK4671
config SND_SOC_CQ0093VC
tristate
+config SND_SOC_CS42L51
+ tristate
+
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 91429eab0707..4a9c205caf56 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
+snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
@@ -74,6 +75,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
+obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index c8ca1142b2f4..1def75e4862f 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -24,6 +24,7 @@
/* codec private data */
struct ad193x_priv {
+ unsigned int sysclk;
struct snd_soc_codec codec;
u8 reg_cache[AD193X_NUM_REGS];
};
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
+static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
+ switch (freq) {
+ case 12288000:
+ case 18432000:
+ case 24576000:
+ case 36864000:
+ ad193x->sysclk = freq;
+ return 0;
+ }
+ return -EINVAL;
+}
+
static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
- int word_len = 0, reg = 0;
+ int word_len = 0, reg = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
switch (params_format(params)) {
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break;
}
+ switch (ad193x->sysclk) {
+ case 12288000:
+ master_rate = AD193X_PLL_INPUT_256;
+ break;
+ case 18432000:
+ master_rate = AD193X_PLL_INPUT_384;
+ break;
+ case 24576000:
+ master_rate = AD193X_PLL_INPUT_512;
+ break;
+ case 36864000:
+ master_rate = AD193X_PLL_INPUT_768;
+ break;
+ }
+
+ reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
+ reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
+ snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
+
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
/* pll input: mclki/xi */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
+ ad193x->sysclk = 12288000;
ret = snd_soc_register_codec(codec);
if (ret != 0) {
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
.hw_params = ad193x_hw_params,
.digital_mute = ad193x_mute,
.set_tdm_slot = ad193x_set_tdm_slot,
+ .set_sysclk = ad193x_set_dai_sysclk,
.set_fmt = ad193x_set_dai_fmt,
};
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index a03c880d52f9..654ba64ae04c 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -11,6 +11,11 @@
#define AD193X_PLL_CLK_CTRL0 0x800
#define AD193X_PLL_POWERDOWN 0x01
+#define AD193X_PLL_INPUT_MASK (~0x6)
+#define AD193X_PLL_INPUT_256 (0 << 1)
+#define AD193X_PLL_INPUT_384 (1 << 1)
+#define AD193X_PLL_INPUT_512 (2 << 1)
+#define AD193X_PLL_INPUT_768 (3 << 1)
#define AD193X_PLL_CLK_CTRL1 0x801
#define AD193X_DAC_CTRL0 0x802
#define AD193X_DAC_POWERDOWN 0x01
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
new file mode 100644
index 000000000000..dd9b8550c402
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.c
@@ -0,0 +1,763 @@
+/*
+ * cs42l51.c
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * Based on cs4270.c - Copyright (c) Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * For now:
+ * - Only I2C is support. Not SPI
+ * - master mode *NOT* supported
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/tlv.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pcm.h>
+#include <linux/i2c.h>
+
+#include "cs42l51.h"
+
+enum master_slave_mode {
+ MODE_SLAVE,
+ MODE_SLAVE_AUTO,
+ MODE_MASTER,
+};
+
+struct cs42l51_private {
+ unsigned int mclk;
+ unsigned int audio_mode; /* The mode (I2S or left-justified) */
+ enum master_slave_mode func;
+ struct snd_soc_codec codec;
+ u8 reg_cache[CS42L51_NUMREGS];
+};
+
+static struct snd_soc_codec *cs42l51_codec;
+
+#define CS42L51_FORMATS ( \
+ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
+ SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \
+ SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \
+ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE)
+
+static int cs42l51_fill_cache(struct snd_soc_codec *codec)
+{
+ u8 *cache = codec->reg_cache + 1;
+ struct i2c_client *i2c_client = codec->control_data;
+ s32 length;
+
+ length = i2c_smbus_read_i2c_block_data(i2c_client,
+ CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache);
+ if (length != CS42L51_NUMREGS) {
+ dev_err(&i2c_client->dev,
+ "I2C read failure, addr=0x%x (ret=%d vs %d)\n",
+ i2c_client->addr, length, CS42L51_NUMREGS);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct snd_soc_codec *codec;
+ struct cs42l51_private *cs42l51;
+ int ret = 0;
+ int reg;
+
+ if (cs42l51_codec)
+ return -EBUSY;
+
+ /* Verify that we have a CS42L51 */
+ ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to read I2C\n");
+ goto error;
+ }
+
+ if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) &&
+ (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) {
+ dev_err(&i2c_client->dev, "Invalid chip id\n");
+ ret = -ENODEV;
+ goto error;
+ }
+
+ dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n",
+ ret & 7);
+
+ cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL);
+ if (!cs42l51) {
+ dev_err(&i2c_client->dev, "could not allocate codec\n");
+ return -ENOMEM;
+ }
+ codec = &cs42l51->codec;
+
+ mutex_init(&codec->mutex);
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->dev = &i2c_client->dev;
+ codec->name = "CS42L51";
+ codec->owner = THIS_MODULE;
+ codec->dai = &cs42l51_dai;
+ codec->num_dai = 1;
+ snd_soc_codec_set_drvdata(codec, cs42l51);
+
+ codec->control_data = i2c_client;
+ codec->reg_cache = cs42l51->reg_cache;
+ codec->reg_cache_size = CS42L51_NUMREGS;
+ i2c_set_clientdata(i2c_client, codec);
+
+ ret = cs42l51_fill_cache(codec);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to fill register cache\n");
+ goto error_alloc;
+ }
+
+ ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret);
+ goto error_alloc;
+ }
+
+ /*
+ * DAC configuration
+ * - Use signal processor
+ * - auto mute
+ * - vol changes immediate
+ * - no de-emphasize
+ */
+ reg = CS42L51_DAC_CTL_DATA_SEL(1)
+ | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0);
+ ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg);
+ if (ret < 0)
+ goto error_alloc;
+
+ cs42l51_dai.dev = codec->dev;
+ cs42l51_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret != 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto error_alloc;
+ }
+
+ ret = snd_soc_register_dai(&cs42l51_dai);
+ if (ret < 0) {
+ dev_err(&i2c_client->dev, "failed to register DAIe\n");
+ goto error_reg;
+ }
+
+ return 0;
+
+error_reg:
+ snd_soc_unregister_codec(codec);
+error_alloc:
+ kfree(cs42l51);
+error:
+ return ret;
+}
+
+static int cs42l51_i2c_remove(struct i2c_client *client)
+{
+ struct cs42l51_private *cs42l51 = i2c_get_clientdata(client);
+ snd_soc_unregister_dai(&cs42l51_dai);
+ snd_soc_unregister_codec(cs42l51_codec);
+ cs42l51_codec = NULL;
+ kfree(cs42l51);
+ return 0;
+}
+
+
+static const struct i2c_device_id cs42l51_id[] = {
+ {"cs42l51", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cs42l51_id);
+
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "CS42L51 I2C",
+ .owner = THIS_MODULE,
+ },
+ .id_table = cs42l51_id,
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+};
+
+static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3;
+
+ switch (value) {
+ default:
+ case 0:
+ ucontrol->value.integer.value[0] = 0;
+ break;
+ /* same value : (L+R)/2 and (R+L)/2 */
+ case 1:
+ case 2:
+ ucontrol->value.integer.value[0] = 1;
+ break;
+ case 3:
+ ucontrol->value.integer.value[0] = 2;
+ break;
+ }
+
+ return 0;
+}
+
+#define CHAN_MIX_NORMAL 0x00
+#define CHAN_MIX_BOTH 0x55
+#define CHAN_MIX_SWAP 0xFF
+
+static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned char val;
+
+ switch (ucontrol->value.integer.value[0]) {
+ default:
+ case 0:
+ val = CHAN_MIX_NORMAL;
+ break;
+ case 1:
+ val = CHAN_MIX_BOTH;
+ break;
+ case 2:
+ val = CHAN_MIX_SWAP;
+ break;
+ }
+
+ snd_soc_write(codec, CS42L51_PCM_MIXER, val);
+
+ return 1;
+}
+
+static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0);
+static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0);
+/* This is a lie. after -102 db, it stays at -102 */
+/* maybe a range would be better */
+static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0);
+
+static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0);
+static const char *chan_mix[] = {
+ "L R",
+ "L+R",
+ "R L",
+};
+
+static const struct soc_enum cs42l51_chan_mix =
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix);
+
+static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
+ SOC_DOUBLE_R_SX_TLV("PCM Playback Volume",
+ CS42L51_PCMA_VOL, CS42L51_PCMB_VOL,
+ 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ SOC_DOUBLE_R("PCM Playback Switch",
+ CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1),
+ SOC_DOUBLE_R_SX_TLV("Analog Playback Volume",
+ CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL,
+ 8, 0xffffff19, 0x18, aout_tlv),
+ SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume",
+ CS42L51_ADCA_VOL, CS42L51_ADCB_VOL,
+ 7, 0xffffff99, 0x18, adc_pcm_tlv),
+ SOC_DOUBLE_R("ADC Mixer Switch",
+ CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1),
+ SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0),
+ SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0),
+ SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0),
+ SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0),
+ SOC_DOUBLE_TLV("Mic Boost Volume",
+ CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv),
+ SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv),
+ SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv),
+ SOC_ENUM_EXT("PCM channel mixer",
+ cs42l51_chan_mix,
+ cs42l51_get_chan_mix, cs42l51_set_chan_mix),
+};
+
+/*
+ * to power down, one must:
+ * 1.) Enable the PDN bit
+ * 2.) enable power-down for the select channels
+ * 3.) disable the PDN bit.
+ */
+static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ unsigned long value;
+
+ value = snd_soc_read(w->codec, CS42L51_POWER_CTL1);
+ value &= ~CS42L51_POWER_CTL1_PDN;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMD:
+ value |= CS42L51_POWER_CTL1_PDN;
+ break;
+ default:
+ case SND_SOC_DAPM_POST_PMD:
+ break;
+ }
+ snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+ CS42L51_POWER_CTL1_PDN, value);
+
+ return 0;
+}
+
+static const char *cs42l51_dac_names[] = {"Direct PCM",
+ "DSP PCM", "ADC"};
+static const struct soc_enum cs42l51_dac_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names);
+static const struct snd_kcontrol_new cs42l51_dac_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum);
+
+static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left",
+ "MIC Left", "MIC+preamp Left"};
+static const struct soc_enum cs42l51_adcl_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names);
+static const struct snd_kcontrol_new cs42l51_adcl_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum);
+
+static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right",
+ "MIC Right", "MIC+preamp Right"};
+static const struct soc_enum cs42l51_adcr_mux_enum =
+ SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names);
+static const struct snd_kcontrol_new cs42l51_adcr_mux_controls =
+ SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum);
+
+static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = {
+ SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1),
+ SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture",
+ CS42L51_POWER_CTL1, 1, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture",
+ CS42L51_POWER_CTL1, 2, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback",
+ CS42L51_POWER_CTL1, 5, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+ SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback",
+ CS42L51_POWER_CTL1, 6, 1,
+ cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD),
+
+ /* analog/mic */
+ SND_SOC_DAPM_INPUT("AIN1L"),
+ SND_SOC_DAPM_INPUT("AIN1R"),
+ SND_SOC_DAPM_INPUT("AIN2L"),
+ SND_SOC_DAPM_INPUT("AIN2R"),
+ SND_SOC_DAPM_INPUT("MICL"),
+ SND_SOC_DAPM_INPUT("MICR"),
+
+ SND_SOC_DAPM_MIXER("Mic Preamp Left",
+ CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0),
+ SND_SOC_DAPM_MIXER("Mic Preamp Right",
+ CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0),
+
+ /* HP */
+ SND_SOC_DAPM_OUTPUT("HPL"),
+ SND_SOC_DAPM_OUTPUT("HPR"),
+
+ /* mux */
+ SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0,
+ &cs42l51_dac_mux_controls),
+ SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0,
+ &cs42l51_adcl_mux_controls),
+ SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0,
+ &cs42l51_adcr_mux_controls),
+};
+
+static const struct snd_soc_dapm_route cs42l51_routes[] = {
+ {"HPL", NULL, "Left DAC"},
+ {"HPR", NULL, "Right DAC"},
+
+ {"Left ADC", NULL, "Left PGA"},
+ {"Right ADC", NULL, "Right PGA"},
+
+ {"Mic Preamp Left", NULL, "MICL"},
+ {"Mic Preamp Right", NULL, "MICR"},
+
+ {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" },
+ {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" },
+ {"PGA-ADC Mux Left", "MIC Left", "MICL" },
+ {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" },
+ {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" },
+ {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" },
+ {"PGA-ADC Mux Right", "MIC Right", "MICR" },
+ {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" },
+
+ {"Left PGA", NULL, "PGA-ADC Mux Left"},
+ {"Right PGA", NULL, "PGA-ADC Mux Right"},
+};
+
+static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
+ unsigned int format)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ case SND_SOC_DAIFMT_LEFT_J:
+ case SND_SOC_DAIFMT_RIGHT_J:
+ cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK;
+ break;
+ default:
+ dev_err(codec->dev, "invalid DAI format\n");
+ ret = -EINVAL;
+ }
+
+ switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ cs42l51->func = MODE_MASTER;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ cs42l51->func = MODE_SLAVE_AUTO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+struct cs42l51_ratios {
+ unsigned int ratio;
+ unsigned char speed_mode;
+ unsigned char mclk;
+};
+
+static struct cs42l51_ratios slave_ratios[] = {
+ { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 },
+ { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+ { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 },
+ { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 },
+ { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
+ { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 },
+ { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 },
+ { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
+ { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 },
+ { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
+ { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 },
+};
+
+static struct cs42l51_ratios slave_auto_ratios[] = {
+ { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 },
+ { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 },
+ { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 },
+ { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 },
+ { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 },
+ { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 },
+ { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 },
+ { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 },
+};
+
+static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai,
+ int clk_id, unsigned int freq, int dir)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ struct cs42l51_ratios *ratios = NULL;
+ int nr_ratios = 0;
+ unsigned int rates = 0;
+ unsigned int rate_min = -1;
+ unsigned int rate_max = 0;
+ int i;
+
+ cs42l51->mclk = freq;
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ return -EINVAL;
+ case MODE_SLAVE:
+ ratios = slave_ratios;
+ nr_ratios = ARRAY_SIZE(slave_ratios);
+ break;
+ case MODE_SLAVE_AUTO:
+ ratios = slave_auto_ratios;
+ nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+ break;
+ }
+
+ for (i = 0; i < nr_ratios; i++) {
+ unsigned int rate = freq / ratios[i].ratio;
+ rates |= snd_pcm_rate_to_rate_bit(rate);
+ if (rate < rate_min)
+ rate_min = rate;
+ if (rate > rate_max)
+ rate_max = rate;
+ }
+ rates &= ~SNDRV_PCM_RATE_KNOT;
+
+ if (!rates) {
+ dev_err(codec->dev, "could not find a valid sample rate\n");
+ return -EINVAL;
+ }
+
+ codec_dai->playback.rates = rates;
+ codec_dai->playback.rate_min = rate_min;
+ codec_dai->playback.rate_max = rate_max;
+
+ codec_dai->capture.rates = rates;
+ codec_dai->capture.rate_min = rate_min;
+ codec_dai->capture.rate_max = rate_max;
+
+ return 0;
+}
+
+static int cs42l51_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_device *socdev = rtd->socdev;
+ struct snd_soc_codec *codec = socdev->card->codec;
+ struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
+ int ret;
+ unsigned int i;
+ unsigned int rate;
+ unsigned int ratio;
+ struct cs42l51_ratios *ratios = NULL;
+ int nr_ratios = 0;
+ int intf_ctl, power_ctl, fmt;
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ return -EINVAL;
+ case MODE_SLAVE:
+ ratios = slave_ratios;
+ nr_ratios = ARRAY_SIZE(slave_ratios);
+ break;
+ case MODE_SLAVE_AUTO:
+ ratios = slave_auto_ratios;
+ nr_ratios = ARRAY_SIZE(slave_auto_ratios);
+ break;
+ }
+
+ /* Figure out which MCLK/LRCK ratio to use */
+ rate = params_rate(params); /* Sampling rate, in Hz */
+ ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */
+ for (i = 0; i < nr_ratios; i++) {
+ if (ratios[i].ratio == ratio)
+ break;
+ }
+
+ if (i == nr_ratios) {
+ /* We did not find a matching ratio */
+ dev_err(codec->dev, "could not find matching ratio\n");
+ return -EINVAL;
+ }
+
+ intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL);
+ power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL);
+
+ intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S
+ | CS42L51_INTF_CTL_DAC_FORMAT(7));
+ power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3)
+ | CS42L51_MIC_POWER_CTL_MCLK_DIV2);
+
+ switch (cs42l51->func) {
+ case MODE_MASTER:
+ intf_ctl |= CS42L51_INTF_CTL_MASTER;
+ power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+ break;
+ case MODE_SLAVE:
+ power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode);
+ break;
+ case MODE_SLAVE_AUTO:
+ power_ctl |= CS42L51_MIC_POWER_CTL_AUTO;
+ break;
+ }
+
+ switch (cs42l51->audio_mode) {
+ case SND_SOC_DAIFMT_I2S:
+ intf_ctl |= CS42L51_INTF_CTL_ADC_I2S;
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S);
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24);
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ case SNDRV_PCM_FORMAT_S16_BE:
+ fmt = CS42L51_DAC_DIF_RJ16;
+ break;
+ case SNDRV_PCM_FORMAT_S18_3LE:
+ case SNDRV_PCM_FORMAT_S18_3BE:
+ fmt = CS42L51_DAC_DIF_RJ18;
+ break;
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ case SNDRV_PCM_FORMAT_S20_3BE:
+ fmt = CS42L51_DAC_DIF_RJ20;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ case SNDRV_PCM_FORMAT_S24_BE:
+ fmt = CS42L51_DAC_DIF_RJ24;
+ break;
+ default:
+ dev_err(codec->dev, "unknown format\n");
+ return -EINVAL;
+ }
+ intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt);
+ break;
+ default:
+ dev_err(codec->dev, "unknown format\n");
+ return -EINVAL;
+ }
+
+ if (ratios[i].mclk)
+ power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2;
+
+ ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ int reg;
+ int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE;
+
+ reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL);
+
+ if (mute)
+ reg |= mask;
+ else
+ reg &= ~mask;
+
+ return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg);
+}
+
+static struct snd_soc_dai_ops cs42l51_dai_ops = {
+ .hw_params = cs42l51_hw_params,
+ .set_sysclk = cs42l51_set_dai_sysclk,
+ .set_fmt = cs42l51_set_dai_fmt,
+ .digital_mute = cs42l51_dai_mute,
+};
+
+struct snd_soc_dai cs42l51_dai = {
+ .name = "CS42L51 HiFi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = CS42L51_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_96000,
+ .formats = CS42L51_FORMATS,
+ },
+ .ops = &cs42l51_dai_ops,
+};
+EXPORT_SYMBOL_GPL(cs42l51_dai);
+
+
+static int cs42l51_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret = 0;
+
+ if (!cs42l51_codec) {
+ dev_err(&pdev->dev, "CS42L51 codec not yet registered\n");
+ return -EINVAL;
+ }
+
+ socdev->card->codec = cs42l51_codec;
+ codec = socdev->card->codec;
+
+ /* Register PCMs */
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to create PCMs\n");
+ return ret;
+ }
+
+ snd_soc_add_controls(codec, cs42l51_snd_controls,
+ ARRAY_SIZE(cs42l51_snd_controls));
+ snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
+ ARRAY_SIZE(cs42l51_dapm_widgets));
+ snd_soc_dapm_add_routes(codec, cs42l51_routes,
+ ARRAY_SIZE(cs42l51_routes));
+
+ return 0;
+}
+
+
+static int cs42l51_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+ snd_soc_dapm_free(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_device_cs42l51 = {
+ .probe = cs42l51_probe,
+ .remove = cs42l51_remove
+};
+EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51);
+
+static int __init cs42l51_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&cs42l51_i2c_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
+ return ret;
+ }
+ return 0;
+}
+module_init(cs42l51_init);
+
+static void __exit cs42l51_exit(void)
+{
+ i2c_del_driver(&cs42l51_i2c_driver);
+}
+module_exit(cs42l51_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h
new file mode 100644
index 000000000000..8f0bd9786ad2
--- /dev/null
+++ b/sound/soc/codecs/cs42l51.h
@@ -0,0 +1,163 @@
+/*
+ * cs42l51.h
+ *
+ * ASoC Driver for Cirrus Logic CS42L51 codecs
+ *
+ * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef _CS42L51_H
+#define _CS42L51_H
+
+#define CS42L51_CHIP_ID 0x1B
+#define CS42L51_CHIP_REV_A 0x00
+#define CS42L51_CHIP_REV_B 0x01
+
+#define CS42L51_CHIP_REV_ID 0x01
+#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
+
+#define CS42L51_POWER_CTL1 0x02
+#define CS42L51_POWER_CTL1_PDN_DACB (1<<6)
+#define CS42L51_POWER_CTL1_PDN_DACA (1<<5)
+#define CS42L51_POWER_CTL1_PDN_PGAB (1<<4)
+#define CS42L51_POWER_CTL1_PDN_PGAA (1<<3)
+#define CS42L51_POWER_CTL1_PDN_ADCB (1<<2)
+#define CS42L51_POWER_CTL1_PDN_ADCA (1<<1)
+#define CS42L51_POWER_CTL1_PDN (1<<0)
+
+#define CS42L51_MIC_POWER_CTL 0x03
+#define CS42L51_MIC_POWER_CTL_AUTO (1<<7)
+#define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5)
+#define CS42L51_QSM_MODE 3
+#define CS42L51_HSM_MODE 2
+#define CS42L51_SSM_MODE 1
+#define CS42L51_DSM_MODE 0
+#define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4)
+#define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3)
+#define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2)
+#define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1)
+#define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0)
+
+#define CS42L51_INTF_CTL 0x04
+#define CS42L51_INTF_CTL_LOOPBACK (1<<7)
+#define CS42L51_INTF_CTL_MASTER (1<<6)
+#define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3)
+#define CS42L51_DAC_DIF_LJ24 0x00
+#define CS42L51_DAC_DIF_I2S 0x01
+#define CS42L51_DAC_DIF_RJ24 0x02
+#define CS42L51_DAC_DIF_RJ20 0x03
+#define CS42L51_DAC_DIF_RJ18 0x04
+#define CS42L51_DAC_DIF_RJ16 0x05
+#define CS42L51_INTF_CTL_ADC_I2S (1<<2)
+#define CS42L51_INTF_CTL_DIGMIX (1<<1)
+#define CS42L51_INTF_CTL_MICMIX (1<<0)
+
+#define CS42L51_MIC_CTL 0x05
+#define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7)
+#define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6)
+#define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5)
+#define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4)
+#define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2)
+#define CS42L51_MIC_CTL_MICB_BOOST (1<<1)
+#define CS42L51_MIC_CTL_MICA_BOOST (1<<0)
+
+#define CS42L51_ADC_CTL 0x06
+#define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7)
+#define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6)
+#define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5)
+#define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4)
+#define CS42L51_ADC_CTL_SOFTB (1<<3)
+#define CS42L51_ADC_CTL_ZCROSSB (1<<2)
+#define CS42L51_ADC_CTL_SOFTA (1<<1)
+#define CS42L51_ADC_CTL_ZCROSSA (1<<0)
+
+#define CS42L51_ADC_INPUT 0x07
+#define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6)
+#define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4)
+#define CS42L51_ADC_INPUT_INV_ADCB (1<<3)
+#define CS42L51_ADC_INPUT_INV_ADCA (1<<2)
+#define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1)
+#define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0)
+
+#define CS42L51_DAC_OUT_CTL 0x08
+#define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5)
+#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4)
+#define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3)
+#define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2)
+#define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1)
+#define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0)
+
+#define CS42L51_DAC_CTL 0x09
+#define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6)
+#define CS42L51_DAC_CTL_FREEZE (1<<5)
+#define CS42L51_DAC_CTL_DEEMPH (1<<3)
+#define CS42L51_DAC_CTL_AMUTE (1<<2)
+#define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0)
+
+#define CS42L51_ALC_PGA_CTL 0x0A
+#define CS42L51_ALC_PGB_CTL 0x0B
+#define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7)
+#define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6)
+#define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0)
+
+#define CS42L51_ADCA_ATT 0x0C
+#define CS42L51_ADCB_ATT 0x0D
+
+#define CS42L51_ADCA_VOL 0x0E
+#define CS42L51_ADCB_VOL 0x0F
+#define CS42L51_PCMA_VOL 0x10
+#define CS42L51_PCMB_VOL 0x11
+#define CS42L51_MIX_MUTE_ADCMIX (1<<7)
+#define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0)
+
+#define CS42L51_BEEP_FREQ 0x12
+#define CS42L51_BEEP_VOL 0x13
+#define CS42L51_BEEP_CONF 0x14
+
+#define CS42L51_TONE_CTL 0x15
+#define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4)
+#define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0)
+
+#define CS42L51_AOUTA_VOL 0x16
+#define CS42L51_AOUTB_VOL 0x17
+#define CS42L51_PCM_MIXER 0x18
+#define CS42L51_LIMIT_THRES_DIS 0x19
+#define CS42L51_LIMIT_REL 0x1A
+#define CS42L51_LIMIT_ATT 0x1B
+#define CS42L51_ALC_EN 0x1C
+#define CS42L51_ALC_REL 0x1D
+#define CS42L51_ALC_THRES 0x1E
+#define CS42L51_NOISE_CONF 0x1F
+
+#define CS42L51_STATUS 0x20
+#define CS42L51_STATUS_SP_CLKERR (1<<6)
+#define CS42L51_STATUS_SPEA_OVFL (1<<5)
+#define CS42L51_STATUS_SPEB_OVFL (1<<4)
+#define CS42L51_STATUS_PCMA_OVFL (1<<3)
+#define CS42L51_STATUS_PCMB_OVFL (1<<2)
+#define CS42L51_STATUS_ADCA_OVFL (1<<1)
+#define CS42L51_STATUS_ADCB_OVFL (1<<0)
+
+#define CS42L51_CHARGE_FREQ 0x21
+
+#define CS42L51_FIRSTREG 0x01
+/*
+ * Hack: with register 0x21, it makes 33 registers. Looks like someone in the
+ * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
+ * 32 regs
+ */
+#define CS42L51_LASTREG 0x20
+#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
+
+extern struct snd_soc_dai cs42l51_dai;
+extern struct snd_soc_codec_device soc_codec_device_cs42l51;
+#endif
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c
index a63191141052..9119836051a4 100644
--- a/sound/soc/codecs/spdif_transciever.c
+++ b/sound/soc/codecs/spdif_transciever.c
@@ -16,8 +16,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
+#include <sound/initval.h>
#include "spdif_transciever.h"
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL");
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+static struct snd_soc_codec *spdif_dit_codec;
+
+static int spdif_dit_codec_probe(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (spdif_dit_codec == NULL) {
+ dev_err(&pdev->dev, "Codec device not registered\n");
+ return -ENODEV;
+ }
+
+ socdev->card->codec = spdif_dit_codec;
+ codec = spdif_dit_codec;
+
+ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
+ if (ret < 0) {
+ dev_err(codec->dev, "failed to create pcms: %d\n", ret);
+ goto err_create_pcms;
+ }
+
+ return 0;
+
+err_create_pcms:
+ return ret;
+}
+
+static int spdif_dit_codec_remove(struct platform_device *pdev)
+{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+
+ snd_soc_free_pcms(socdev);
+
+ return 0;
+}
+
+struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
+ .probe = spdif_dit_codec_probe,
+ .remove = spdif_dit_codec_remove,
+}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
+
struct snd_soc_dai dit_stub_dai = {
.name = "DIT",
.playback = {
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
+ struct snd_soc_codec *codec;
+ int ret;
+
+ if (spdif_dit_codec) {
+ dev_err(&pdev->dev, "Another Codec is registered\n");
+ ret = -EINVAL;
+ goto err_reg_codec;
+ }
+
+ codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
+ if (codec == NULL)
+ return -ENOMEM;
+
+ codec->dev = &pdev->dev;
+
+ mutex_init(&codec->mutex);
+
+ INIT_LIST_HEAD(&codec->dapm_widgets);
+ INIT_LIST_HEAD(&codec->dapm_paths);
+
+ codec->name = "spdif-dit";
+ codec->owner = THIS_MODULE;
+ codec->dai = &dit_stub_dai;
+ codec->num_dai = 1;
+
+ spdif_dit_codec = codec;
+
+ ret = snd_soc_register_codec(codec);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to register codec: %d\n", ret);
+ goto err_reg_codec;
+ }
+
dit_stub_dai.dev = &pdev->dev;
- return snd_soc_register_dai(&dit_stub_dai);
+ ret = snd_soc_register_dai(&dit_stub_dai);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to register dai: %d\n", ret);
+ goto err_reg_dai;
+ }
+
+ return 0;
+
+err_reg_dai:
+ snd_soc_unregister_codec(codec);
+err_reg_codec:
+ kfree(spdif_dit_codec);
+ return ret;
}
static int spdif_dit_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&dit_stub_dai);
+ snd_soc_unregister_codec(spdif_dit_codec);
+ kfree(spdif_dit_codec);
+ spdif_dit_codec = NULL;
return 0;
}
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h
index 296f2eb6c4ef..1e102124f546 100644
--- a/sound/soc/codecs/spdif_transciever.h
+++ b/sound/soc/codecs/spdif_transciever.h
@@ -12,6 +12,7 @@
#ifndef CODEC_STUBS_H
#define CODEC_STUBS_H
+extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
extern struct snd_soc_dai dit_stub_dai;
#endif /* CODEC_STUBS_H */
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index 65adc77eada1..2fa946ce23a2 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -120,6 +120,8 @@ struct tlv320dac33_priv {
* samples */
unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */
+ unsigned int uthr;
+
enum dac33_state state;
};
@@ -442,6 +444,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
return ret;
}
+static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = dac33->uthr;
+
+ return 0;
+}
+
+static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
+ int ret = 0;
+
+ if (dac33->substream)
+ return -EBUSY;
+
+ if (dac33->uthr == ucontrol->value.integer.value[0])
+ return 0;
+
+ if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
+ ucontrol->value.integer.value[0] > MODE7_UTHR)
+ ret = -EINVAL;
+ else
+ dac33->uthr = ucontrol->value.integer.value[0];
+
+ return ret;
+}
+
static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -506,6 +541,8 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = {
static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = {
SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
dac33_get_nsample, dac33_set_nsample),
+ SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
+ dac33_get_uthr, dac33_set_uthr),
SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum,
dac33_get_fifo_mode, dac33_set_fifo_mode),
};
@@ -985,7 +1022,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
* Configure the threshold levels, and leave 10 sample space
* at the bottom, and also at the top of the FIFO
*/
- dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR));
+ dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
break;
default:
@@ -1052,8 +1089,8 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
break;
case DAC33_FIFO_MODE7:
dac33->mode7_us_to_lthr =
- SAMPLES_TO_US(substream->runtime->rate,
- MODE7_UTHR - MODE7_LTHR + 1);
+ SAMPLES_TO_US(substream->runtime->rate,
+ dac33->uthr - MODE7_LTHR + 1);
dac33->t_stamp1 = 0;
break;
default:
@@ -1104,7 +1141,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
struct snd_soc_codec *codec = socdev->card->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
unsigned long long t0, t1, t_now;
- unsigned int time_delta;
+ unsigned int time_delta, uthr;
int samples_out, samples_in, samples;
snd_pcm_sframes_t delay = 0;
@@ -1182,6 +1219,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
case DAC33_FIFO_MODE7:
spin_lock(&dac33->lock);
t0 = dac33->t_stamp1;
+ uthr = dac33->uthr;
spin_unlock(&dac33->lock);
t_now = ktime_to_us(ktime_get());
@@ -1194,7 +1232,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
* Either the timestamps are messed or equal. Report
* maximum delay
*/
- delay = MODE7_UTHR;
+ delay = uthr;
goto out;
}
@@ -1208,8 +1246,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
substream->runtime->rate,
time_delta);
- if (likely(MODE7_UTHR > samples_out))
- delay = MODE7_UTHR - samples_out;
+ if (likely(uthr > samples_out))
+ delay = uthr - samples_out;
else
delay = 0;
} else {
@@ -1227,8 +1265,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
time_delta);
delay = MODE7_LTHR + samples_in - samples_out;
- if (unlikely(delay > MODE7_UTHR))
- delay = MODE7_UTHR;
+ if (unlikely(delay > uthr))
+ delay = uthr;
}
break;
default:
@@ -1484,6 +1522,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
dac33->irq = client->irq;
dac33->nsample = NSAMPLE_MAX;
dac33->nsample_max = NSAMPLE_MAX;
+ dac33->uthr = MODE7_UTHR;
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b4fcdb01fc49..8d36bfa20552 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -43,37 +43,37 @@
*/
static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* this register not used */
- 0x91, /* REG_CODEC_MODE (0x1) */
- 0xc3, /* REG_OPTION (0x2) */
+ 0x00, /* REG_CODEC_MODE (0x1) */
+ 0x00, /* REG_OPTION (0x2) */
0x00, /* REG_UNKNOWN (0x3) */
0x00, /* REG_MICBIAS_CTL (0x4) */
- 0x20, /* REG_ANAMICL (0x5) */
+ 0x00, /* REG_ANAMICL (0x5) */
0x00, /* REG_ANAMICR (0x6) */
0x00, /* REG_AVADC_CTL (0x7) */
0x00, /* REG_ADCMICSEL (0x8) */
0x00, /* REG_DIGMIXING (0x9) */
- 0x0c, /* REG_ATXL1PGA (0xA) */
- 0x0c, /* REG_ATXR1PGA (0xB) */
- 0x00, /* REG_AVTXL2PGA (0xC) */
- 0x00, /* REG_AVTXR2PGA (0xD) */
+ 0x0f, /* REG_ATXL1PGA (0xA) */
+ 0x0f, /* REG_ATXR1PGA (0xB) */
+ 0x0f, /* REG_AVTXL2PGA (0xC) */
+ 0x0f, /* REG_AVTXR2PGA (0xD) */
0x00, /* REG_AUDIO_IF (0xE) */
0x00, /* REG_VOICE_IF (0xF) */
- 0x00, /* REG_ARXR1PGA (0x10) */
- 0x00, /* REG_ARXL1PGA (0x11) */
- 0x6c, /* REG_ARXR2PGA (0x12) */
- 0x6c, /* REG_ARXL2PGA (0x13) */
- 0x00, /* REG_VRXPGA (0x14) */
+ 0x3f, /* REG_ARXR1PGA (0x10) */
+ 0x3f, /* REG_ARXL1PGA (0x11) */
+ 0x3f, /* REG_ARXR2PGA (0x12) */
+ 0x3f, /* REG_ARXL2PGA (0x13) */
+ 0x25, /* REG_VRXPGA (0x14) */
0x00, /* REG_VSTPGA (0x15) */
0x00, /* REG_VRX2ARXPGA (0x16) */
0x00, /* REG_AVDAC_CTL (0x17) */
0x00, /* REG_ARX2VTXPGA (0x18) */
- 0x00, /* REG_ARXL1_APGA_CTL (0x19) */
- 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */
- 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */
- 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */
+ 0x32, /* REG_ARXL1_APGA_CTL (0x19) */
+ 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */
+ 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */
+ 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */
0x00, /* REG_ATX2ARXPGA (0x1D) */
0x00, /* REG_BT_IF (0x1E) */
- 0x00, /* REG_BTPGA (0x1F) */
+ 0x55, /* REG_BTPGA (0x1F) */
0x00, /* REG_BTSTPGA (0x20) */
0x00, /* REG_EAR_CTL (0x21) */
0x00, /* REG_HS_SEL (0x22) */
@@ -85,32 +85,32 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = {
0x00, /* REG_PRECKR_CTL (0x28) */
0x00, /* REG_HFL_CTL (0x29) */
0x00, /* REG_HFR_CTL (0x2A) */
- 0x00, /* REG_ALC_CTL (0x2B) */
+ 0x05, /* REG_ALC_CTL (0x2B) */
0x00, /* REG_ALC_SET1 (0x2C) */
0x00, /* REG_ALC_SET2 (0x2D) */
0x00, /* REG_BOOST_CTL (0x2E) */
0x00, /* REG_SOFTVOL_CTL (0x2F) */
- 0x00, /* REG_DTMF_FREQSEL (0x30) */
+ 0x13, /* REG_DTMF_FREQSEL (0x30) */
0x00, /* REG_DTMF_TONEXT1H (0x31) */
0x00, /* REG_DTMF_TONEXT1L (0x32) */
0x00, /* REG_DTMF_TONEXT2H (0x33) */
0x00, /* REG_DTMF_TONEXT2L (0x34) */
- 0x00, /* REG_DTMF_TONOFF (0x35) */
- 0x00, /* REG_DTMF_WANONOFF (0x36) */
+ 0x79, /* REG_DTMF_TONOFF (0x35) */
+ 0x11, /* REG_DTMF_WANONOFF (0x36) */
0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */
0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */
0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */
0x06, /* REG_APLL_CTL (0x3A) */
0x00, /* REG_DTMF_CTL (0x3B) */
- 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */
- 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */
+ 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */
+ 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */
0x00, /* REG_MISC_SET_1 (0x3E) */
0x00, /* REG_PCMBTMUX (0x3F) */
0x00, /* not used (0x40) */
0x00, /* not used (0x41) */
0x00, /* not used (0x42) */
0x00, /* REG_RX_PATH_SEL (0x43) */
- 0x00, /* REG_VDL_APGA_CTL (0x44) */
+ 0x32, /* REG_VDL_APGA_CTL (0x44) */
0x00, /* REG_VIBRA_CTL (0x45) */
0x00, /* REG_VIBRA_SET (0x46) */
0x00, /* REG_VIBRA_PWM_SET (0x47) */
@@ -244,58 +244,93 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
udelay(10);
}
-static void twl4030_init_chip(struct snd_soc_codec *codec)
+static inline void twl4030_check_defaults(struct snd_soc_codec *codec)
{
- u8 *cache = codec->reg_cache;
- int i;
+ int i, difference = 0;
+ u8 val;
+
+ dev_dbg(codec->dev, "Checking TWL audio default configuration\n");
+ for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) {
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i);
+ if (val != twl4030_reg[i]) {
+ difference++;
+ dev_dbg(codec->dev,
+ "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n",
+ i, val, twl4030_reg[i]);
+ }
+ }
+ dev_dbg(codec->dev, "Found %d non maching registers. %s\n",
+ difference, difference ? "Not OK" : "OK");
+}
- /* clear CODECPDZ prior to setting register defaults */
- twl4030_codec_enable(codec, 0);
+static inline void twl4030_reset_registers(struct snd_soc_codec *codec)
+{
+ int i;
/* set all audio section registers to reasonable defaults */
for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++)
if (i != TWL4030_REG_APLL_CTL)
- twl4030_write(codec, i, cache[i]);
+ twl4030_write(codec, i, twl4030_reg[i]);
}
-static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
+static void twl4030_init_chip(struct platform_device *pdev)
{
+ struct snd_soc_device *socdev = platform_get_drvdata(pdev);
+ struct twl4030_setup_data *setup = socdev->codec_data;
+ struct snd_soc_codec *codec = socdev->card->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- int status = -1;
+ u8 reg, byte;
+ int i = 0;
- if (enable) {
- twl4030->apll_enabled++;
- if (twl4030->apll_enabled == 1)
- status = twl4030_codec_enable_resource(
- TWL4030_CODEC_RES_APLL);
- } else {
- twl4030->apll_enabled--;
- if (!twl4030->apll_enabled)
- status = twl4030_codec_disable_resource(
- TWL4030_CODEC_RES_APLL);
- }
+ /* Check defaults, if instructed before anything else */
+ if (setup && setup->check_defaults)
+ twl4030_check_defaults(codec);
- if (status >= 0)
- twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
-}
+ /* Reset registers, if no setup data or if instructed to do so */
+ if (!setup || (setup && setup->reset_registers))
+ twl4030_reset_registers(codec);
-static void twl4030_power_up(struct snd_soc_codec *codec)
-{
- struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- u8 anamicl, regmisc1, byte;
- int i = 0;
+ /* Refresh APLL_CTL register from HW */
+ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
+ TWL4030_REG_APLL_CTL);
+ twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte);
- if (twl4030->codec_powered)
+ /* anti-pop when changing analog gain */
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
+ twl4030_write(codec, TWL4030_REG_MISC_SET_1,
+ reg | TWL4030_SMOOTH_ANAVOL_EN);
+
+ twl4030_write(codec, TWL4030_REG_OPTION,
+ TWL4030_ATXL1_EN | TWL4030_ATXR1_EN |
+ TWL4030_ARXL2_EN | TWL4030_ARXR2_EN);
+
+ /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */
+ twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32);
+
+ /* Machine dependent setup */
+ if (!setup)
return;
- /* set CODECPDZ to turn on codec */
- twl4030_codec_enable(codec, 1);
+ /* Configuration for headset ramp delay from setup data */
+ if (setup->sysclk != twl4030->sysclk)
+ dev_warn(codec->dev,
+ "Mismatch in APLL mclk: %u (configured: %u)\n",
+ setup->sysclk, twl4030->sysclk);
+
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
+ reg &= ~TWL4030_RAMP_DELAY;
+ reg |= (setup->ramp_delay_value << 2);
+ twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg);
/* initiate offset cancellation */
- anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ twl4030_codec_enable(codec, 1);
+
+ reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL);
+ reg &= ~TWL4030_OFFSET_CNCL_SEL;
+ reg |= setup->offset_cncl_path;
twl4030_write(codec, TWL4030_REG_ANAMICL,
- anamicl | TWL4030_CNCL_OFFSET_START);
+ reg | TWL4030_CNCL_OFFSET_START);
/* wait for offset cancellation to complete */
do {
@@ -310,23 +345,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec)
/* Make sure that the reg_cache has the same value as the HW */
twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte);
- /* anti-pop when changing analog gain */
- regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1);
- twl4030_write(codec, TWL4030_REG_MISC_SET_1,
- regmisc1 | TWL4030_SMOOTH_ANAVOL_EN);
-
- /* toggle CODECPDZ as per TRM */
twl4030_codec_enable(codec, 0);
- twl4030_codec_enable(codec, 1);
}
-/*
- * Unconditional power down
- */
-static void twl4030_power_down(struct snd_soc_codec *codec)
+static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
{
- /* power down */
- twl4030_codec_enable(codec, 0);
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
+ int status = -1;
+
+ if (enable) {
+ twl4030->apll_enabled++;
+ if (twl4030->apll_enabled == 1)
+ status = twl4030_codec_enable_resource(
+ TWL4030_CODEC_RES_APLL);
+ } else {
+ twl4030->apll_enabled--;
+ if (!twl4030->apll_enabled)
+ status = twl4030_codec_disable_resource(
+ TWL4030_CODEC_RES_APLL);
+ }
+
+ if (status >= 0)
+ twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
}
/* Earpiece */
@@ -1605,10 +1645,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF)
- twl4030_power_up(codec);
+ twl4030_codec_enable(codec, 1);
break;
case SND_SOC_BIAS_OFF:
- twl4030_power_down(codec);
+ twl4030_codec_enable(codec, 0);
break;
}
codec->bias_level = level;
@@ -1794,13 +1834,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (mode != old_mode) {
- /* change rate and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
- twl4030_codec_enable(codec, 1);
- }
-
/* sample size */
old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF);
format = old_format;
@@ -1818,16 +1851,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if (format != old_format) {
-
- /* clear CODECPDZ before changing format (codec requirement) */
- twl4030_codec_enable(codec, 0);
-
- /* change format */
- twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-
- /* set CODECPDZ afterwards */
- twl4030_codec_enable(codec, 1);
+ if (format != old_format || mode != old_mode) {
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ }
}
/* Store the important parameters for the DAI configuration and set
@@ -1877,6 +1914,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
@@ -1911,15 +1949,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
if (format != old_format) {
-
- /* clear CODECPDZ before changing format (codec requirement) */
- twl4030_codec_enable(codec, 0);
-
- /* change format */
- twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
-
- /* set CODECPDZ afterwards */
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_AUDIO_IF, format);
+ }
}
return 0;
@@ -2011,6 +2051,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_mode, mode;
/* Enable voice digital filters */
@@ -2035,10 +2076,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream,
}
if (mode != old_mode) {
- /* change rate and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode);
+ }
}
return 0;
@@ -2068,6 +2116,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
+ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
u8 old_format, format;
/* get format */
@@ -2099,10 +2148,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai,
}
if (format != old_format) {
- /* change format and set CODECPDZ */
- twl4030_codec_enable(codec, 0);
- twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
- twl4030_codec_enable(codec, 1);
+ if (twl4030->codec_powered) {
+ /*
+ * If the codec is powered, than we need to toggle the
+ * codec power.
+ */
+ twl4030_codec_enable(codec, 0);
+ twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+ twl4030_codec_enable(codec, 1);
+ } else {
+ twl4030_write(codec, TWL4030_REG_VOICE_IF, format);
+ }
}
return 0;
@@ -2202,31 +2258,15 @@ static struct snd_soc_codec *twl4030_codec;
static int twl4030_soc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
- struct twl4030_setup_data *setup = socdev->codec_data;
struct snd_soc_codec *codec;
- struct twl4030_priv *twl4030;
int ret;
BUG_ON(!twl4030_codec);
codec = twl4030_codec;
- twl4030 = snd_soc_codec_get_drvdata(codec);
socdev->card->codec = codec;
- /* Configuration for headset ramp delay from setup data */
- if (setup) {
- unsigned char hs_pop;
-
- if (setup->sysclk != twl4030->sysclk)
- dev_warn(&pdev->dev,
- "Mismatch in APLL mclk: %u (configured: %u)\n",
- setup->sysclk, twl4030->sysclk);
-
- hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
- hs_pop &= ~TWL4030_RAMP_DELAY;
- hs_pop |= (setup->ramp_delay_value << 2);
- twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
- }
+ twl4030_init_chip(pdev);
/* register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -2247,6 +2287,8 @@ static int twl4030_soc_remove(struct platform_device *pdev)
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
+ /* Reset registers to their chip default before leaving */
+ twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
@@ -2287,6 +2329,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
codec->read = twl4030_read_reg_cache;
codec->write = twl4030_write;
codec->set_bias_level = twl4030_set_bias_level;
+ codec->idle_bias_off = 1;
codec->dai = twl4030_dai;
codec->num_dai = ARRAY_SIZE(twl4030_dai);
codec->reg_cache_size = sizeof(twl4030_reg);
@@ -2302,9 +2345,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
- twl4030_init_chip(codec);
codec->bias_level = SND_SOC_BIAS_OFF;
- twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ret = snd_soc_register_codec(codec);
if (ret != 0) {
@@ -2322,7 +2363,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
return 0;
error_codec:
- twl4030_power_down(codec);
+ twl4030_codec_enable(codec, 0);
kfree(codec->reg_cache);
error_cache:
kfree(twl4030);
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index f206d242ca31..788e3d125099 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -42,6 +42,9 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030;
struct twl4030_setup_data {
unsigned int ramp_delay_value;
unsigned int sysclk;
+ unsigned int offset_cncl_path;
+ unsigned int check_defaults:1;
+ unsigned int reset_registers:1;
unsigned int hs_extmute:1;
void (*set_hs_extmute)(int mute);
};
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index af36346ff336..85dd4fb4c681 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case 19200000:
/* mclk input, pll disabled */
hppllctl |= TWL6040_MCLK_19200KHZ |
- TWL6040_HPLLSQRBP |
+ TWL6040_HPLLSQRENA |
TWL6040_HPLLBP;
break;
case 26000000:
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index c018772cc430..dd8d909788c1 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -30,8 +30,6 @@
#include "wm8990.h"
-#define WM8990_VERSION "0.2"
-
/* codec private data */
struct wm8990_priv {
unsigned int sysclk;
@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev)
struct wm8990_priv *wm8990;
int ret;
- pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
-
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
new file mode 100644
index 000000000000..ba66ac8e1419
--- /dev/null
+++ b/sound/soc/ep93xx/Kconfig
@@ -0,0 +1,9 @@
+config SND_EP93XX_SOC
+ tristate "SoC Audio support for the Cirrus Logic EP93xx series"
+ depends on ARCH_EP93XX && SND_SOC
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the EP93xx I2S interface.
+
+config SND_EP93XX_SOC_I2S
+ tristate
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
new file mode 100644
index 000000000000..0239da36cea3
--- /dev/null
+++ b/sound/soc/ep93xx/Makefile
@@ -0,0 +1,8 @@
+# EP93xx Platform Support
+snd-soc-ep93xx-objs := ep93xx-pcm.o
+snd-soc-ep93xx-i2s-objs := ep93xx-i2s.o
+
+obj-$(CONFIG_SND_EP93XX_SOC) += snd-soc-ep93xx.o
+obj-$(CONFIG_SND_EP93XX_SOC_I2S) += snd-soc-ep93xx-i2s.o
+
+# EP93XX Machine Support
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
new file mode 100644
index 000000000000..00b946632184
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -0,0 +1,487 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.c
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * Based on the original driver by:
+ * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+#include <mach/dma.h>
+
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define EP93XX_I2S_TXCLKCFG 0x00
+#define EP93XX_I2S_RXCLKCFG 0x04
+#define EP93XX_I2S_GLCTRL 0x0C
+
+#define EP93XX_I2S_TXLINCTRLDATA 0x28
+#define EP93XX_I2S_TXCTRL 0x2C
+#define EP93XX_I2S_TXWRDLEN 0x30
+#define EP93XX_I2S_TX0EN 0x34
+
+#define EP93XX_I2S_RXLINCTRLDATA 0x58
+#define EP93XX_I2S_RXCTRL 0x5C
+#define EP93XX_I2S_RXWRDLEN 0x60
+#define EP93XX_I2S_RX0EN 0x64
+
+#define EP93XX_I2S_WRDLEN_16 (0 << 0)
+#define EP93XX_I2S_WRDLEN_24 (1 << 0)
+#define EP93XX_I2S_WRDLEN_32 (2 << 0)
+
+#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */
+
+#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */
+#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */
+#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */
+#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */
+#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */
+
+struct ep93xx_i2s_info {
+ struct clk *mclk;
+ struct clk *sclk;
+ struct clk *lrclk;
+ struct ep93xx_pcm_dma_params *dma_params;
+ struct resource *mem;
+ void __iomem *regs;
+};
+
+struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+ [SNDRV_PCM_STREAM_PLAYBACK] = {
+ .name = "i2s-pcm-out",
+ .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
+ },
+ [SNDRV_PCM_STREAM_CAPTURE] = {
+ .name = "i2s-pcm-in",
+ .dma_port = EP93XX_DMA_M2P_PORT_I2S1,
+ },
+};
+
+static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
+ unsigned reg, unsigned val)
+{
+ __raw_writel(val, info->regs + reg);
+}
+
+static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+ unsigned reg)
+{
+ return __raw_readl(info->regs + reg);
+}
+
+static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+{
+ unsigned base_reg;
+ int i;
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Enable clocks */
+ clk_enable(info->mclk);
+ clk_enable(info->sclk);
+ clk_enable(info->lrclk);
+
+ /* Enable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+ }
+
+ /* Enable fifos */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ base_reg = EP93XX_I2S_TX0EN;
+ else
+ base_reg = EP93XX_I2S_RX0EN;
+ for (i = 0; i < 3; i++)
+ ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
+}
+
+static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+{
+ unsigned base_reg;
+ int i;
+
+ /* Disable fifos */
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ base_reg = EP93XX_I2S_TX0EN;
+ else
+ base_reg = EP93XX_I2S_RX0EN;
+ for (i = 0; i < 3; i++)
+ ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
+
+ if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+ (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+ /* Disable i2s */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
+
+ /* Disable clocks */
+ clk_disable(info->lrclk);
+ clk_disable(info->sclk);
+ clk_disable(info->mclk);
+ }
+}
+
+static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+ snd_soc_dai_set_dma_data(cpu_dai, substream,
+ &info->dma_params[substream->stream]);
+ return 0;
+}
+
+static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+ ep93xx_i2s_disable(info, substream->stream);
+}
+
+static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ unsigned int clk_cfg, lin_ctrl;
+
+ clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
+ lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ case SND_SOC_DAIFMT_LEFT_J:
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ case SND_SOC_DAIFMT_RIGHT_J:
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* CPU is master */
+ clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
+ break;
+
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* Codec is master */
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /* Negative bit clock, lrclk low on left word */
+ clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
+ break;
+
+ case SND_SOC_DAIFMT_NB_IF:
+ /* Negative bit clock, lrclk low on right word */
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
+ clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+ break;
+
+ case SND_SOC_DAIFMT_IB_NF:
+ /* Positive bit clock, lrclk low on left word */
+ clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
+ clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+ break;
+
+ case SND_SOC_DAIFMT_IB_IF:
+ /* Positive bit clock, lrclk low on right word */
+ clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
+ break;
+ }
+
+ /* Write new register values */
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
+ return 0;
+}
+
+static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+ unsigned word_len, div, sdiv, lrdiv;
+ int found = 0, err;
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ word_len = EP93XX_I2S_WRDLEN_16;
+ break;
+
+ case SNDRV_PCM_FORMAT_S24_LE:
+ word_len = EP93XX_I2S_WRDLEN_24;
+ break;
+
+ case SNDRV_PCM_FORMAT_S32_LE:
+ word_len = EP93XX_I2S_WRDLEN_32;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
+ else
+ ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
+
+ /*
+ * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
+ * If the lrclk is pulse length is larger than the word size, then the
+ * bit clock will be gated for the unused bits.
+ */
+ div = (clk_get_rate(info->mclk) / params_rate(params)) *
+ params_channels(params);
+ for (sdiv = 2; sdiv <= 4; sdiv += 2)
+ for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
+ if (sdiv * lrdiv == div) {
+ found = 1;
+ goto out;
+ }
+out:
+ if (!found)
+ return -EINVAL;
+
+ err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
+ if (err)
+ return err;
+
+ err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
+ if (err)
+ return err;
+
+ ep93xx_i2s_enable(info, substream->stream);
+ return 0;
+}
+
+static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct ep93xx_i2s_info *info = cpu_dai->private_data;
+
+ if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
+ return -EINVAL;
+
+ return clk_set_rate(info->mclk, freq);
+}
+
+#ifdef CONFIG_PM
+static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
+{
+ struct ep93xx_i2s_info *info = dai->private_data;
+
+ if (!dai->active)
+ return;
+
+ ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
+ ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
+{
+ struct ep93xx_i2s_info *info = dai->private_data;
+
+ if (!dai->active)
+ return;
+
+ ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+ ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+#else
+#define ep93xx_i2s_suspend NULL
+#define ep93xx_i2s_resume NULL
+#endif
+
+static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+ .startup = ep93xx_i2s_startup,
+ .shutdown = ep93xx_i2s_shutdown,
+ .hw_params = ep93xx_i2s_hw_params,
+ .set_sysclk = ep93xx_i2s_set_sysclk,
+ .set_fmt = ep93xx_i2s_set_dai_fmt,
+};
+
+#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai ep93xx_i2s_dai = {
+ .name = "ep93xx-i2s",
+ .id = 0,
+ .symmetric_rates= 1,
+ .suspend = ep93xx_i2s_suspend,
+ .resume = ep93xx_i2s_resume,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = EP93XX_I2S_FORMATS,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = EP93XX_I2S_FORMATS,
+ },
+ .ops = &ep93xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
+
+static int ep93xx_i2s_probe(struct platform_device *pdev)
+{
+ struct ep93xx_i2s_info *info;
+ struct resource *res;
+ int err;
+
+ info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
+ if (!info) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ ep93xx_i2s_dai.dev = &pdev->dev;
+ ep93xx_i2s_dai.private_data = info;
+ info->dma_params = ep93xx_i2s_dma_params;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ err = -ENODEV;
+ goto fail;
+ }
+
+ info->mem = request_mem_region(res->start, resource_size(res),
+ pdev->name);
+ if (!info->mem) {
+ err = -EBUSY;
+ goto fail;
+ }
+
+ info->regs = ioremap(info->mem->start, resource_size(info->mem));
+ if (!info->regs) {
+ err = -ENXIO;
+ goto fail_release_mem;
+ }
+
+ info->mclk = clk_get(&pdev->dev, "mclk");
+ if (IS_ERR(info->mclk)) {
+ err = PTR_ERR(info->mclk);
+ goto fail_unmap_mem;
+ }
+
+ info->sclk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(info->sclk)) {
+ err = PTR_ERR(info->sclk);
+ goto fail_put_mclk;
+ }
+
+ info->lrclk = clk_get(&pdev->dev, "lrclk");
+ if (IS_ERR(info->lrclk)) {
+ err = PTR_ERR(info->lrclk);
+ goto fail_put_sclk;
+ }
+
+ err = snd_soc_register_dai(&ep93xx_i2s_dai);
+ if (err)
+ goto fail_put_lrclk;
+
+ return 0;
+
+fail_put_lrclk:
+ clk_put(info->lrclk);
+fail_put_sclk:
+ clk_put(info->sclk);
+fail_put_mclk:
+ clk_put(info->mclk);
+fail_unmap_mem:
+ iounmap(info->regs);
+fail_release_mem:
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ kfree(info);
+fail:
+ return err;
+}
+
+static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
+{
+ struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+
+ snd_soc_unregister_dai(&ep93xx_i2s_dai);
+ clk_put(info->lrclk);
+ clk_put(info->sclk);
+ clk_put(info->mclk);
+ iounmap(info->regs);
+ release_mem_region(info->mem->start, resource_size(info->mem));
+ kfree(info);
+ return 0;
+}
+
+static struct platform_driver ep93xx_i2s_driver = {
+ .probe = ep93xx_i2s_probe,
+ .remove = __devexit_p(ep93xx_i2s_remove),
+ .driver = {
+ .name = "ep93xx-i2s",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init ep93xx_i2s_init(void)
+{
+ return platform_driver_register(&ep93xx_i2s_driver);
+}
+
+static void __exit ep93xx_i2s_exit(void)
+{
+ platform_driver_unregister(&ep93xx_i2s_driver);
+}
+
+module_init(ep93xx_i2s_init);
+module_exit(ep93xx_i2s_exit);
+
+MODULE_ALIAS("platform:ep93xx-i2s");
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93XX I2S driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
new file mode 100644
index 000000000000..3bd4ebfaa1de
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.h
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#ifndef _EP93XX_SND_SOC_I2S_H
+#define _EP93XX_SND_SOC_I2S_H
+
+extern struct snd_soc_dai ep93xx_i2s_dai;
+
+#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
new file mode 100644
index 000000000000..4ba938400791
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -0,0 +1,319 @@
+/*
+ * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
+ * Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+
+#include "ep93xx-pcm.h"
+
+static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER),
+
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .rate_min = SNDRV_PCM_RATE_8000,
+ .rate_max = SNDRV_PCM_RATE_48000,
+
+ .formats = (SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE |
+ SNDRV_PCM_FMTBIT_S32_LE),
+
+ .buffer_bytes_max = 131072,
+ .period_bytes_min = 32,
+ .period_bytes_max = 32768,
+ .periods_min = 1,
+ .periods_max = 32,
+ .fifo_size = 32,
+};
+
+struct ep93xx_runtime_data
+{
+ struct ep93xx_dma_m2p_client cl;
+ struct ep93xx_pcm_dma_params *params;
+ int pointer_bytes;
+ struct tasklet_struct period_tasklet;
+ int periods;
+ struct ep93xx_dma_buffer buf[32];
+};
+
+static void ep93xx_pcm_period_elapsed(unsigned long data)
+{
+ struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+ snd_pcm_period_elapsed(substream);
+}
+
+static void ep93xx_pcm_buffer_started(void *cookie,
+ struct ep93xx_dma_buffer *buf)
+{
+}
+
+static void ep93xx_pcm_buffer_finished(void *cookie,
+ struct ep93xx_dma_buffer *buf,
+ int bytes, int error)
+{
+ struct snd_pcm_substream *substream = cookie;
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ if (buf == rtd->buf + rtd->periods - 1)
+ rtd->pointer_bytes = 0;
+ else
+ rtd->pointer_bytes += buf->size;
+
+ if (!error) {
+ ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
+ tasklet_schedule(&rtd->period_tasklet);
+ } else {
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ }
+}
+
+static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+ struct ep93xx_pcm_dma_params *dma_params;
+ struct ep93xx_runtime_data *rtd;
+ int ret;
+
+ dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
+
+ rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+ if (!rtd)
+ return -ENOMEM;
+
+ memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
+ rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
+ rtd->period_tasklet.data = (unsigned long)substream;
+
+ rtd->cl.name = dma_params->name;
+ rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
+ ((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+ EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
+ rtd->cl.cookie = substream;
+ rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
+ rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
+ ret = ep93xx_dma_m2p_client_register(&rtd->cl);
+ if (ret < 0) {
+ kfree(rtd);
+ return ret;
+ }
+
+ substream->runtime->private_data = rtd;
+ return 0;
+}
+
+static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ ep93xx_dma_m2p_client_unregister(&rtd->cl);
+ kfree(rtd);
+ return 0;
+}
+
+static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ep93xx_runtime_data *rtd = runtime->private_data;
+ size_t totsize = params_buffer_bytes(params);
+ size_t period = params_period_bytes(params);
+ int i;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = totsize;
+
+ rtd->periods = (totsize + period - 1) / period;
+ for (i = 0; i < rtd->periods; i++) {
+ rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
+ rtd->buf[i].size = period;
+ if ((i + 1) * period > totsize)
+ rtd->buf[i].size = totsize - (i * period);
+ }
+
+ return 0;
+}
+
+static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+ int ret;
+ int i;
+
+ ret = 0;
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ rtd->pointer_bytes = 0;
+ for (i = 0; i < rtd->periods; i++)
+ ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ep93xx_dma_m2p_flush(&rtd->cl);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+ /* FIXME: implement this with sub-period granularity */
+ return bytes_to_frames(runtime, rtd->pointer_bytes);
+}
+
+static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ep93xx_pcm_ops = {
+ .open = ep93xx_pcm_open,
+ .close = ep93xx_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = ep93xx_pcm_hw_params,
+ .hw_free = ep93xx_pcm_hw_free,
+ .trigger = ep93xx_pcm_trigger,
+ .pointer = ep93xx_pcm_pointer,
+ .mmap = ep93xx_pcm_mmap,
+};
+
+static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ buf->bytes = size;
+
+ return (buf->area == NULL) ? -ENOMEM : 0;
+}
+
+static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
+ buf->addr);
+ buf->area = NULL;
+ }
+}
+
+static u64 ep93xx_pcm_dmamask = 0xffffffff;
+
+static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &ep93xx_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->playback.channels_min) {
+ ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ return ret;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+struct snd_soc_platform ep93xx_soc_platform = {
+ .name = "ep93xx-audio",
+ .pcm_ops = &ep93xx_pcm_ops,
+ .pcm_new = &ep93xx_pcm_new,
+ .pcm_free = &ep93xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __init ep93xx_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&ep93xx_soc_platform);
+}
+
+static void __exit ep93xx_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&ep93xx_soc_platform);
+}
+
+module_init(ep93xx_soc_platform_init);
+module_exit(ep93xx_soc_platform_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
new file mode 100644
index 000000000000..4ffdd3f62fe9
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -0,0 +1,22 @@
+/*
+ * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _EP93XX_SND_SOC_PCM_H
+#define _EP93XX_SND_SOC_PCM_H
+
+struct ep93xx_pcm_dma_params {
+ char *name;
+ int dma_port;
+};
+
+extern struct snd_soc_platform ep93xx_soc_platform;
+
+#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig
index eba9b9d257a1..079b23bb0b03 100644
--- a/sound/soc/imx/Kconfig
+++ b/sound/soc/imx/Kconfig
@@ -13,9 +13,27 @@ config SND_MXC_SOC_SSI
config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
- depends on SND_IMX_SOC && EXPERIMENTAL
+ depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
select SND_SOC_WM8350
select SND_MXC_SOC_SSI
help
Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted.
+
+config SND_SOC_PHYCORE_AC97
+ tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
+ depends on MACH_PCM043 || MACH_PCA100
+ select SND_MXC_SOC_SSI
+ select SND_SOC_WM9712
+ help
+ Say Y if you want to add support for SoC audio on Phytec phyCORE
+ and phyCARD boards in AC97 mode
+
+config SND_SOC_EUKREA_TLV320
+ bool "Eukrea TLV320"
+ depends on MACH_EUKREA_MBIMX27_BASEBOARD
+ select SND_IMX_SOC
+ select SND_SOC_TLV320AIC23
+ help
+ Enable I2S based access to the TLV320AIC23B codec attached
+ to the SSI4 interface
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile
index 2d203635ac11..7bc57baf2b0e 100644
--- a/sound/soc/imx/Makefile
+++ b/sound/soc/imx/Makefile
@@ -8,8 +8,10 @@ endif
obj-$(CONFIG_SND_IMX_SOC) += snd-soc-imx.o
# i.MX Machine Support
+snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o
snd-soc-phycore-ac97-objs := phycore-ac97.o
snd-soc-wm1133-ev1-objs := wm1133-ev1.o
+obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o
obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o
obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o
diff --git a/sound/soc/imx/eukrea-tlv320.c b/sound/soc/imx/eukrea-tlv320.c
new file mode 100644
index 000000000000..968380a93e89
--- /dev/null
+++ b/sound/soc/imx/eukrea-tlv320.c
@@ -0,0 +1,135 @@
+/*
+ * eukrea-tlv320.c -- SoC audio for eukrea_cpuimxXX in I2S mode
+ *
+ * Copyright 2010 Eric Bénard, Eukréa Electromatique <eric@eukrea.com>
+ *
+ * based on sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c
+ * which is Copyright 2009 Simtec Electronics
+ * and on sound/soc/imx/phycore-ac97.c which is
+ * Copyright 2009 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <asm/mach-types.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "imx-ssi.h"
+
+#define CODEC_CLOCK 12000000
+
+static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set cpu dai format\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (ret) {
+ pr_err("%s: failed set codec dai format\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0,
+ CODEC_CLOCK, SND_SOC_CLOCK_OUT);
+ if (ret) {
+ pr_err("%s: failed setting codec sysclk\n", __func__);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret) {
+ pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct snd_soc_ops eukrea_tlv320_snd_ops = {
+ .hw_params = eukrea_tlv320_hw_params,
+};
+
+static struct snd_soc_dai_link eukrea_tlv320_dai = {
+ .name = "tlv320aic23",
+ .stream_name = "TLV320AIC23",
+ .codec_dai = &tlv320aic23_dai,
+ .ops = &eukrea_tlv320_snd_ops,
+};
+
+static struct snd_soc_card eukrea_tlv320 = {
+ .name = "cpuimx-audio",
+ .platform = &imx_soc_platform,
+ .dai_link = &eukrea_tlv320_dai,
+ .num_links = 1,
+};
+
+static struct snd_soc_device eukrea_tlv320_snd_devdata = {
+ .card = &eukrea_tlv320,
+ .codec_dev = &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *eukrea_tlv320_snd_device;
+
+static int __init eukrea_tlv320_init(void)
+{
+ int ret;
+
+ if (!machine_is_eukrea_cpuimx27())
+ /* return happy. We might run on a totally different machine */
+ return 0;
+
+ eukrea_tlv320_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!eukrea_tlv320_snd_device)
+ return -ENOMEM;
+
+ eukrea_tlv320_dai.cpu_dai = &imx_ssi_pcm_dai[0];
+
+ platform_set_drvdata(eukrea_tlv320_snd_device, &eukrea_tlv320_snd_devdata);
+ eukrea_tlv320_snd_devdata.dev = &eukrea_tlv320_snd_device->dev;
+ ret = platform_device_add(eukrea_tlv320_snd_device);
+
+ if (ret) {
+ printk(KERN_ERR "ASoC: Platform device allocation failed\n");
+ platform_device_put(eukrea_tlv320_snd_device);
+ }
+
+ return ret;
+}
+
+static void __exit eukrea_tlv320_exit(void)
+{
+ platform_device_unregister(eukrea_tlv320_snd_device);
+}
+
+module_init(eukrea_tlv320_init);
+module_exit(eukrea_tlv320_exit);
+
+MODULE_AUTHOR("Eric Bénard <eric@eukrea.com>");
+MODULE_DESCRIPTION("CPUIMX ALSA SoC driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c
index 80b4fee2442b..50f51624c535 100644
--- a/sound/soc/imx/imx-ssi.c
+++ b/sound/soc/imx/imx-ssi.c
@@ -83,8 +83,6 @@ static int imx_ssi_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
/*
* SSI DAI format configuration.
* Should only be called when port is inactive (i.e. SSIEN = 0).
- * Note: We don't use the I2S modes but instead manually configure the
- * SSI for I2S because the I2S mode is only a register preset.
*/
static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
@@ -99,6 +97,10 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
/* data on rising edge of bclk, frame low 1clk before data */
strcr |= SSI_STCR_TFSI | SSI_STCR_TEFS | SSI_STCR_TXBIT0;
scr |= SSI_SCR_NET;
+ if (ssi->flags & IMX_SSI_USE_I2S_SLAVE) {
+ scr &= ~SSI_I2S_MODE_MASK;
+ scr |= SSI_SCR_I2S_MODE_SLAVE;
+ }
break;
case SND_SOC_DAIFMT_LEFT_J:
/* data on rising edge of bclk, frame high with data */
@@ -143,6 +145,11 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
strcr |= SSI_STCR_TFEN0;
+ if (ssi->flags & IMX_SSI_NET)
+ scr |= SSI_SCR_NET;
+ if (ssi->flags & IMX_SSI_SYN)
+ scr |= SSI_SCR_SYN;
+
writel(strcr, ssi->base + SSI_STCR);
writel(strcr, ssi->base + SSI_SRCR);
writel(scr, ssi->base + SSI_SCR);
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
new file mode 100644
index 000000000000..16ec2a2dba4d
--- /dev/null
+++ b/sound/soc/kirkwood/Kconfig
@@ -0,0 +1,20 @@
+config SND_KIRKWOOD_SOC
+ tristate "SoC Audio for the Marvell Kirkwood chip"
+ depends on ARCH_KIRKWOOD
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the Kirkwood I2S interface. You will also need to select the
+ audio interfaces to support below.
+
+config SND_KIRKWOOD_SOC_I2S
+ tristate
+
+config SND_KIRKWOOD_SOC_OPENRD
+ tristate "SoC Audio support for Kirkwood Openrd Client"
+ depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
+ select SND_KIRKWOOD_SOC_I2S
+ select SND_SOC_CS42L51
+ help
+ Say Y if you want to add support for SoC audio on
+ Openrd Client.
+
diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
new file mode 100644
index 000000000000..33a16dcab5b5
--- /dev/null
+++ b/sound/soc/kirkwood/Makefile
@@ -0,0 +1,9 @@
+snd-soc-kirkwood-objs := kirkwood-dma.o
+snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
+obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
+
+snd-soc-openrd-objs := kirkwood-openrd.o
+
+obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c
new file mode 100644
index 000000000000..a30205be3e2b
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.c
@@ -0,0 +1,383 @@
+/*
+ * kirkwood-dma.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/mbus.h>
+#include <sound/soc.h>
+#include "kirkwood-dma.h"
+#include "kirkwood.h"
+
+#define KIRKWOOD_RATES \
+ (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+struct kirkwood_dma_priv {
+ struct snd_pcm_substream *play_stream;
+ struct snd_pcm_substream *rec_stream;
+ struct kirkwood_dma_data *data;
+};
+
+static struct snd_pcm_hardware kirkwood_dma_snd_hw = {
+ .info = (SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_PAUSE),
+ .formats = KIRKWOOD_FORMATS,
+ .rates = KIRKWOOD_RATES,
+ .rate_min = 44100,
+ .rate_max = 96000,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES * KIRKWOOD_SND_MAX_PERIODS,
+ .period_bytes_min = KIRKWOOD_SND_MIN_PERIOD_BYTES,
+ .period_bytes_max = KIRKWOOD_SND_MAX_PERIOD_BYTES,
+ .periods_min = KIRKWOOD_SND_MIN_PERIODS,
+ .periods_max = KIRKWOOD_SND_MAX_PERIODS,
+ .fifo_size = 0,
+};
+
+static u64 kirkwood_dma_dmamask = 0xFFFFFFFFUL;
+
+static irqreturn_t kirkwood_dma_irq(int irq, void *dev_id)
+{
+ struct kirkwood_dma_priv *prdata = dev_id;
+ struct kirkwood_dma_data *priv = prdata->data;
+ unsigned long mask, status, cause;
+
+ mask = readl(priv->io + KIRKWOOD_INT_MASK);
+ status = readl(priv->io + KIRKWOOD_INT_CAUSE) & mask;
+
+ cause = readl(priv->io + KIRKWOOD_ERR_CAUSE);
+ if (unlikely(cause)) {
+ printk(KERN_WARNING "%s: got err interrupt 0x%lx\n",
+ __func__, cause);
+ writel(cause, priv->io + KIRKWOOD_ERR_CAUSE);
+ return IRQ_HANDLED;
+ }
+
+ /* we've enabled only bytes interrupts ... */
+ if (status & ~(KIRKWOOD_INT_CAUSE_PLAY_BYTES | \
+ KIRKWOOD_INT_CAUSE_REC_BYTES)) {
+ printk(KERN_WARNING "%s: unexpected interrupt %lx\n",
+ __func__, status);
+ return IRQ_NONE;
+ }
+
+ /* ack int */
+ writel(status, priv->io + KIRKWOOD_INT_CAUSE);
+
+ if (status & KIRKWOOD_INT_CAUSE_PLAY_BYTES)
+ snd_pcm_period_elapsed(prdata->play_stream);
+
+ if (status & KIRKWOOD_INT_CAUSE_REC_BYTES)
+ snd_pcm_period_elapsed(prdata->rec_stream);
+
+ return IRQ_HANDLED;
+}
+
+static void kirkwood_dma_conf_mbus_windows(void __iomem *base, int win,
+ unsigned long dma,
+ struct mbus_dram_target_info *dram)
+{
+ int i;
+
+ /* First disable and clear windows */
+ writel(0, base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+ writel(0, base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+
+ /* try to find matching cs for current dma address */
+ for (i = 0; i < dram->num_cs; i++) {
+ struct mbus_dram_window *cs = dram->cs + i;
+ if ((cs->base & 0xffff0000) < (dma & 0xffff0000)) {
+ writel(cs->base & 0xffff0000,
+ base + KIRKWOOD_AUDIO_WIN_BASE_REG(win));
+ writel(((cs->size - 1) & 0xffff0000) |
+ (cs->mbus_attr << 8) |
+ (dram->mbus_dram_target_id << 4) | 1,
+ base + KIRKWOOD_AUDIO_WIN_CTRL_REG(win));
+ }
+ }
+}
+
+static int kirkwood_dma_open(struct snd_pcm_substream *substream)
+{
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ unsigned long addr;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ snd_soc_set_runtime_hwparams(substream, &kirkwood_dma_snd_hw);
+
+ /* Ensure that all constraints linked to dma burst are fullfilled */
+ err = snd_pcm_hw_constraint_minmax(runtime,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ priv->burst * 2,
+ KIRKWOOD_AUDIO_BUF_MAX-1);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_step(runtime, 0,
+ SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
+ priv->burst);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ priv->burst);
+ if (err < 0)
+ return err;
+
+ if (soc_runtime->dai->cpu_dai->private_data == NULL) {
+ prdata = kzalloc(sizeof(struct kirkwood_dma_priv), GFP_KERNEL);
+ if (prdata == NULL)
+ return -ENOMEM;
+
+ prdata->data = priv;
+
+ err = request_irq(priv->irq, kirkwood_dma_irq, IRQF_SHARED,
+ "kirkwood-i2s", prdata);
+ if (err) {
+ kfree(prdata);
+ return -EBUSY;
+ }
+
+ soc_runtime->dai->cpu_dai->private_data = prdata;
+
+ /*
+ * Enable Error interrupts. We're only ack'ing them but
+ * it's usefull for diagnostics
+ */
+ writel((unsigned long)-1, priv->io + KIRKWOOD_ERR_MASK);
+ }
+
+ addr = virt_to_phys(substream->dma_buffer.area);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ prdata->play_stream = substream;
+ kirkwood_dma_conf_mbus_windows(priv->io,
+ KIRKWOOD_PLAYBACK_WIN, addr, priv->dram);
+ } else {
+ prdata->rec_stream = substream;
+ kirkwood_dma_conf_mbus_windows(priv->io,
+ KIRKWOOD_RECORD_WIN, addr, priv->dram);
+ }
+
+ return 0;
+}
+
+static int kirkwood_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_priv *prdata = cpu_dai->private_data;
+ struct kirkwood_dma_data *priv;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ if (!prdata || !priv)
+ return 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prdata->play_stream = NULL;
+ else
+ prdata->rec_stream = NULL;
+
+ if (!prdata->play_stream && !prdata->rec_stream) {
+ writel(0, priv->io + KIRKWOOD_ERR_MASK);
+ free_irq(priv->irq, prdata);
+ kfree(prdata);
+ soc_runtime->dai->cpu_dai->private_data = NULL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ return 0;
+}
+
+static int kirkwood_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_set_runtime_buffer(substream, NULL);
+ return 0;
+}
+
+static int kirkwood_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ unsigned long size, count;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ /* compute buffer size in term of "words" as requested in specs */
+ size = frames_to_bytes(runtime, runtime->buffer_size);
+ size = (size>>2)-1;
+ count = snd_pcm_lib_period_bytes(substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ writel(count, priv->io + KIRKWOOD_PLAY_BYTE_INT_COUNT);
+ writel(runtime->dma_addr, priv->io + KIRKWOOD_PLAY_BUF_ADDR);
+ writel(size, priv->io + KIRKWOOD_PLAY_BUF_SIZE);
+ } else {
+ writel(count, priv->io + KIRKWOOD_REC_BYTE_INT_COUNT);
+ writel(runtime->dma_addr, priv->io + KIRKWOOD_REC_BUF_ADDR);
+ writel(size, priv->io + KIRKWOOD_REC_BUF_SIZE);
+ }
+
+
+ return 0;
+}
+
+static snd_pcm_uframes_t kirkwood_dma_pointer(struct snd_pcm_substream
+ *substream)
+{
+ struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+ struct snd_soc_dai *cpu_dai = soc_runtime->dai->cpu_dai;
+ struct kirkwood_dma_data *priv;
+ snd_pcm_uframes_t count;
+
+ priv = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ count = bytes_to_frames(substream->runtime,
+ readl(priv->io + KIRKWOOD_PLAY_BYTE_COUNT));
+ else
+ count = bytes_to_frames(substream->runtime,
+ readl(priv->io + KIRKWOOD_REC_BYTE_COUNT));
+
+ return count;
+}
+
+struct snd_pcm_ops kirkwood_dma_ops = {
+ .open = kirkwood_dma_open,
+ .close = kirkwood_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = kirkwood_dma_hw_params,
+ .hw_free = kirkwood_dma_hw_free,
+ .prepare = kirkwood_dma_prepare,
+ .pointer = kirkwood_dma_pointer,
+};
+
+static int kirkwood_dma_preallocate_dma_buffer(struct snd_pcm *pcm,
+ int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = kirkwood_dma_snd_hw.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->area = dma_alloc_coherent(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+ buf->bytes = size;
+ buf->private_data = NULL;
+
+ return 0;
+}
+
+static int kirkwood_dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ int ret;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &kirkwood_dma_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = 0xffffffff;
+
+ if (dai->playback.channels_min) {
+ ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ return ret;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = kirkwood_dma_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void kirkwood_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_coherent(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+struct snd_soc_platform kirkwood_soc_platform = {
+ .name = "kirkwood-dma",
+ .pcm_ops = &kirkwood_dma_ops,
+ .pcm_new = kirkwood_dma_new,
+ .pcm_free = kirkwood_dma_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(kirkwood_soc_platform);
+
+static int __init kirkwood_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&kirkwood_soc_platform);
+}
+module_init(kirkwood_soc_platform_init);
+
+static void __exit kirkwood_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&kirkwood_soc_platform);
+}
+module_exit(kirkwood_soc_platform_exit);
+
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Marvell Kirkwood Audio DMA module");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/kirkwood/kirkwood-dma.h b/sound/soc/kirkwood/kirkwood-dma.h
new file mode 100644
index 000000000000..ba4454cd34f1
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-dma.h
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-dma.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _KIRKWOOD_DMA_H
+#define _KIRKWOOD_DMA_H
+
+extern struct snd_soc_platform kirkwood_soc_platform;
+
+#endif
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
new file mode 100644
index 000000000000..0fdc7db7a469
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -0,0 +1,484 @@
+/*
+ * kirkwood-i2s.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/mbus.h>
+#include <linux/delay.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <plat/audio.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood.h"
+
+#define DRV_NAME "kirkwood-i2s"
+
+#define KIRKWOOD_I2S_RATES \
+ (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+#define KIRKWOOD_I2S_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+
+struct snd_soc_dai kirkwood_i2s_dai;
+static struct kirkwood_dma_data *priv;
+
+static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ unsigned long mask;
+ unsigned long value;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_RIGHT_J:
+ mask = KIRKWOOD_I2S_CTL_RJ;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ mask = KIRKWOOD_I2S_CTL_LJ;
+ break;
+ case SND_SOC_DAIFMT_I2S:
+ mask = KIRKWOOD_I2S_CTL_I2S;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Set same format for playback and record
+ * This avoids some troubles.
+ */
+ value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
+ value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+ value |= mask;
+ writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
+
+ value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
+ value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
+ value |= mask;
+ writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
+
+ return 0;
+}
+
+static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
+{
+ unsigned long value;
+
+ value = KIRKWOOD_DCO_CTL_OFFSET_0;
+ switch (rate) {
+ default:
+ case 44100:
+ value |= KIRKWOOD_DCO_CTL_FREQ_11;
+ break;
+ case 48000:
+ value |= KIRKWOOD_DCO_CTL_FREQ_12;
+ break;
+ case 96000:
+ value |= KIRKWOOD_DCO_CTL_FREQ_24;
+ break;
+ }
+ writel(value, io + KIRKWOOD_DCO_CTL);
+
+ /* wait for dco locked */
+ do {
+ cpu_relax();
+ value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
+ value &= KIRKWOOD_DCO_SPCR_STATUS;
+ } while (value == 0);
+}
+
+static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ unsigned int i2s_reg, reg;
+ unsigned long i2s_value, value;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ i2s_reg = KIRKWOOD_I2S_PLAYCTL;
+ reg = KIRKWOOD_PLAYCTL;
+ } else {
+ i2s_reg = KIRKWOOD_I2S_RECCTL;
+ reg = KIRKWOOD_RECCTL;
+ }
+
+ /* set dco conf */
+ kirkwood_set_dco(priv->io, params_rate(params));
+
+ i2s_value = readl(priv->io+i2s_reg);
+ i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
+
+ value = readl(priv->io+reg);
+ value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
+
+ /*
+ * Size settings in play/rec i2s control regs and play/rec control
+ * regs must be the same.
+ */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
+ value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
+ break;
+ /*
+ * doesn't work... S20_3LE != kirkwood 20bit format ?
+ *
+ case SNDRV_PCM_FORMAT_S20_3LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
+ value |= KIRKWOOD_PLAYCTL_SIZE_20;
+ break;
+ */
+ case SNDRV_PCM_FORMAT_S24_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
+ value |= KIRKWOOD_PLAYCTL_SIZE_24;
+ break;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
+ value |= KIRKWOOD_PLAYCTL_SIZE_32;
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(i2s_value, priv->io+i2s_reg);
+ writel(value, priv->io+reg);
+
+ return 0;
+}
+
+static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ unsigned long value;
+
+ /*
+ * specs says KIRKWOOD_PLAYCTL must be read 2 times before
+ * changing it. So read 1 time here and 1 later.
+ */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* stop audio, enable interrupts */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* configure audio & enable i2s playback */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
+ value &= ~(KIRKWOOD_PLAYCTL_PAUSE|KIRKWOOD_PLAYCTL_SPDIF_EN);
+
+ if (priv->burst == 32)
+ value |= KIRKWOOD_PLAYCTL_BURST_32;
+ else
+ value |= KIRKWOOD_PLAYCTL_BURST_128;
+ value |= KIRKWOOD_PLAYCTL_I2S_EN;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* stop audio, disable interrupts */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* disable all playbacks */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value |= KIRKWOOD_PLAYCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~KIRKWOOD_PLAYCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ unsigned long value;
+
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ /* stop audio, enable interrupts */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* configure audio & enable i2s record */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~KIRKWOOD_RECCTL_BURST_MASK;
+ value &= ~KIRKWOOD_RECCTL_MONO;
+ value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_SPDIF_EN);
+
+ if (priv->burst == 32)
+ value |= KIRKWOOD_RECCTL_BURST_32;
+ else
+ value |= KIRKWOOD_RECCTL_BURST_128;
+ value |= KIRKWOOD_RECCTL_I2S_EN;
+
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ /* stop audio, disable interrupts */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ value = readl(priv->io + KIRKWOOD_INT_MASK);
+ value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
+ writel(value, priv->io + KIRKWOOD_INT_MASK);
+
+ /* disable all records */
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value |= KIRKWOOD_RECCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~KIRKWOOD_RECCTL_PAUSE;
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ return kirkwood_i2s_play_trigger(substream, cmd, dai);
+ else
+ return kirkwood_i2s_rec_trigger(substream, cmd, dai);
+
+ return 0;
+}
+
+static int kirkwood_i2s_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ unsigned long value;
+ unsigned int reg_data;
+
+ /* put system in a "safe" state : */
+ /* disable audio interrupts */
+ writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
+ writel(0, priv->io + KIRKWOOD_INT_MASK);
+
+ reg_data = readl(priv->io + 0x1200);
+ reg_data &= (~(0x333FF8));
+ reg_data |= 0x111D18;
+ writel(reg_data, priv->io + 0x1200);
+
+ msleep(500);
+
+ reg_data = readl(priv->io + 0x1200);
+ reg_data &= (~(0x333FF8));
+ reg_data |= 0x111D18;
+ writel(reg_data, priv->io + 0x1200);
+
+ /* disable playback/record */
+ value = readl(priv->io + KIRKWOOD_PLAYCTL);
+ value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_PLAYCTL);
+
+ value = readl(priv->io + KIRKWOOD_RECCTL);
+ value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
+ writel(value, priv->io + KIRKWOOD_RECCTL);
+
+ return 0;
+
+}
+
+static void kirkwood_i2s_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+}
+
+static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
+ .trigger = kirkwood_i2s_trigger,
+ .hw_params = kirkwood_i2s_hw_params,
+ .set_fmt = kirkwood_i2s_set_fmt,
+};
+
+
+struct snd_soc_dai kirkwood_i2s_dai = {
+ .name = DRV_NAME,
+ .id = 0,
+ .probe = kirkwood_i2s_probe,
+ .remove = kirkwood_i2s_remove,
+ .playback = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = KIRKWOOD_I2S_RATES,
+ .formats = KIRKWOOD_I2S_FORMATS,},
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = KIRKWOOD_I2S_RATES,
+ .formats = KIRKWOOD_I2S_FORMATS,},
+ .ops = &kirkwood_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
+
+static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
+{
+ struct resource *mem;
+ struct kirkwood_asoc_platform_data *data =
+ pdev->dev.platform_data;
+ int err;
+
+ priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&pdev->dev, "allocation failed\n");
+ err = -ENOMEM;
+ goto error;
+ }
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "platform_get_resource failed\n");
+ err = -ENXIO;
+ goto err_alloc;
+ }
+
+ priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
+ if (!priv->mem) {
+ dev_err(&pdev->dev, "request_mem_region failed\n");
+ err = -EBUSY;
+ goto error;
+ }
+
+ priv->io = ioremap(priv->mem->start, SZ_16K);
+ if (!priv->io) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ err = -ENOMEM;
+ goto err_iomem;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(&pdev->dev, "platform_get_irq failed\n");
+ err = -ENXIO;
+ goto err_ioremap;
+ }
+
+ if (!data || !data->dram) {
+ dev_err(&pdev->dev, "no platform data ?!\n");
+ err = -EINVAL;
+ goto err_ioremap;
+ }
+
+ priv->dram = data->dram;
+ priv->burst = data->burst;
+
+ kirkwood_i2s_dai.capture.dma_data = priv;
+ kirkwood_i2s_dai.playback.dma_data = priv;
+
+ return snd_soc_register_dai(&kirkwood_i2s_dai);
+
+err_ioremap:
+ iounmap(priv->io);
+err_iomem:
+ release_mem_region(priv->mem->start, SZ_16K);
+err_alloc:
+ kfree(priv);
+error:
+ return err;
+}
+
+static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
+{
+ if (priv) {
+ iounmap(priv->io);
+ release_mem_region(priv->mem->start, SZ_16K);
+ kfree(priv);
+ }
+ snd_soc_unregister_dai(&kirkwood_i2s_dai);
+ return 0;
+}
+
+static struct platform_driver kirkwood_i2s_driver = {
+ .probe = kirkwood_i2s_dev_probe,
+ .remove = kirkwood_i2s_dev_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init kirkwood_i2s_init(void)
+{
+ return platform_driver_register(&kirkwood_i2s_driver);
+}
+module_init(kirkwood_i2s_init);
+
+static void __exit kirkwood_i2s_exit(void)
+{
+ platform_driver_unregister(&kirkwood_i2s_driver);
+}
+module_exit(kirkwood_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
+MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kirkwood-i2s");
diff --git a/sound/soc/kirkwood/kirkwood-i2s.h b/sound/soc/kirkwood/kirkwood-i2s.h
new file mode 100644
index 000000000000..c5595c616d7a
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-i2s.h
@@ -0,0 +1,17 @@
+/*
+ * kirkwood-i2s.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _KIRKWOOD_I2S_H
+#define _KIRKWOOD_I2S_H
+
+extern struct snd_soc_dai kirkwood_i2s_dai;
+
+#endif
diff --git a/sound/soc/kirkwood/kirkwood-openrd.c b/sound/soc/kirkwood/kirkwood-openrd.c
new file mode 100644
index 000000000000..0353d06bc41a
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood-openrd.c
@@ -0,0 +1,126 @@
+/*
+ * kirkwood-openrd.c
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/soc.h>
+#include <mach/kirkwood.h>
+#include <plat/audio.h>
+#include <asm/mach-types.h>
+#include "kirkwood-i2s.h"
+#include "kirkwood-dma.h"
+#include "../codecs/cs42l51.h"
+
+static int openrd_client_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret;
+ unsigned int freq, fmt;
+
+ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0)
+ return ret;
+
+ switch (params_rate(params)) {
+ default:
+ case 44100:
+ freq = 11289600;
+ break;
+ case 48000:
+ freq = 12288000;
+ break;
+ case 96000:
+ freq = 24576000;
+ break;
+ }
+
+ return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
+
+}
+
+static struct snd_soc_ops openrd_client_ops = {
+ .hw_params = openrd_client_hw_params,
+};
+
+
+static struct snd_soc_dai_link openrd_client_dai[] = {
+{
+ .name = "CS42L51",
+ .stream_name = "CS42L51 HiFi",
+ .cpu_dai = &kirkwood_i2s_dai,
+ .codec_dai = &cs42l51_dai,
+ .ops = &openrd_client_ops,
+},
+};
+
+
+static struct snd_soc_card openrd_client = {
+ .name = "OpenRD Client",
+ .platform = &kirkwood_soc_platform,
+ .dai_link = openrd_client_dai,
+ .num_links = ARRAY_SIZE(openrd_client_dai),
+};
+
+static struct snd_soc_device openrd_client_snd_devdata = {
+ .card = &openrd_client,
+ .codec_dev = &soc_codec_device_cs42l51,
+};
+
+static struct platform_device *openrd_client_snd_device;
+
+static int __init openrd_client_init(void)
+{
+ int ret;
+
+ if (!machine_is_openrd_client())
+ return 0;
+
+ openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!openrd_client_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(openrd_client_snd_device,
+ &openrd_client_snd_devdata);
+ openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
+
+ ret = platform_device_add(openrd_client_snd_device);
+ if (ret) {
+ printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
+ platform_device_put(openrd_client_snd_device);
+ }
+
+ return ret;
+}
+
+static void __exit openrd_client_exit(void)
+{
+ platform_device_unregister(openrd_client_snd_device);
+}
+
+module_init(openrd_client_init);
+module_exit(openrd_client_exit);
+
+/* Module information */
+MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
+MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:soc-audio");
diff --git a/sound/soc/kirkwood/kirkwood.h b/sound/soc/kirkwood/kirkwood.h
new file mode 100644
index 000000000000..b6e4f68d71dd
--- /dev/null
+++ b/sound/soc/kirkwood/kirkwood.h
@@ -0,0 +1,126 @@
+/*
+ * kirkwood.h
+ *
+ * (c) 2010 Arnaud Patard <apatard@mandriva.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _KIRKWOOD_AUDIO_H
+#define _KIRKWOOD_AUDIO_H
+
+#define KIRKWOOD_RECORD_WIN 0
+#define KIRKWOOD_PLAYBACK_WIN 1
+#define KIRKWOOD_MAX_AUDIO_WIN 2
+
+#define KIRKWOOD_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
+#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
+
+
+#define KIRKWOOD_RECCTL 0x1000
+#define KIRKWOOD_RECCTL_SPDIF_EN (1<<11)
+#define KIRKWOOD_RECCTL_I2S_EN (1<<10)
+#define KIRKWOOD_RECCTL_PAUSE (1<<9)
+#define KIRKWOOD_RECCTL_MUTE (1<<8)
+#define KIRKWOOD_RECCTL_BURST_MASK (3<<5)
+#define KIRKWOOD_RECCTL_BURST_128 (2<<5)
+#define KIRKWOOD_RECCTL_BURST_32 (1<<5)
+#define KIRKWOOD_RECCTL_MONO (1<<4)
+#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT (1<<3)
+#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT (0<<3)
+#define KIRKWOOD_RECCTL_SIZE_MASK (7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16 (7<<0)
+#define KIRKWOOD_RECCTL_SIZE_16_C (3<<0)
+#define KIRKWOOD_RECCTL_SIZE_20 (2<<0)
+#define KIRKWOOD_RECCTL_SIZE_24 (1<<0)
+#define KIRKWOOD_RECCTL_SIZE_32 (0<<0)
+
+#define KIRKWOOD_REC_BUF_ADDR 0x1004
+#define KIRKWOOD_REC_BUF_SIZE 0x1008
+#define KIRKWOOD_REC_BYTE_COUNT 0x100C
+
+#define KIRKWOOD_PLAYCTL 0x1100
+#define KIRKWOOD_PLAYCTL_PLAY_BUSY (1<<16)
+#define KIRKWOOD_PLAYCTL_BURST_MASK (3<<11)
+#define KIRKWOOD_PLAYCTL_BURST_128 (2<<11)
+#define KIRKWOOD_PLAYCTL_BURST_32 (1<<11)
+#define KIRKWOOD_PLAYCTL_PAUSE (1<<9)
+#define KIRKWOOD_PLAYCTL_SPDIF_MUTE (1<<8)
+#define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7)
+#define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4)
+#define KIRKWOOD_PLAYCTL_I2S_EN (1<<3)
+#define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_20 (2<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0)
+#define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0)
+
+#define KIRKWOOD_PLAY_BUF_ADDR 0x1104
+#define KIRKWOOD_PLAY_BUF_SIZE 0x1108
+#define KIRKWOOD_PLAY_BYTE_COUNT 0x110C
+
+#define KIRKWOOD_DCO_CTL 0x1204
+#define KIRKWOOD_DCO_CTL_OFFSET_MASK (0xFFF<<2)
+#define KIRKWOOD_DCO_CTL_OFFSET_0 (0x800<<2)
+#define KIRKWOOD_DCO_CTL_FREQ_MASK (3<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_11 (0<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_12 (1<<0)
+#define KIRKWOOD_DCO_CTL_FREQ_24 (2<<0)
+
+#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
+#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
+
+#define KIRKWOOD_ERR_CAUSE 0x1300
+#define KIRKWOOD_ERR_MASK 0x1304
+
+#define KIRKWOOD_INT_CAUSE 0x1308
+#define KIRKWOOD_INT_MASK 0x130C
+#define KIRKWOOD_INT_CAUSE_PLAY_BYTES (1<<14)
+#define KIRKWOOD_INT_CAUSE_REC_BYTES (1<<13)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END (1<<7)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q (1<<6)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF (1<<5)
+#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q (1<<4)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_END (1<<3)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q (1<<2)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF (1<<1)
+#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q (1<<0)
+
+#define KIRKWOOD_REC_BYTE_INT_COUNT 0x1310
+#define KIRKWOOD_PLAY_BYTE_INT_COUNT 0x1314
+#define KIRKWOOD_BYTE_INT_COUNT_MASK 0xffffff
+
+#define KIRKWOOD_I2S_PLAYCTL 0x2508
+#define KIRKWOOD_I2S_RECCTL 0x2408
+#define KIRKWOOD_I2S_CTL_JUST_MASK (0xf<<26)
+#define KIRKWOOD_I2S_CTL_LJ (0<<26)
+#define KIRKWOOD_I2S_CTL_I2S (5<<26)
+#define KIRKWOOD_I2S_CTL_RJ (8<<26)
+#define KIRKWOOD_I2S_CTL_SIZE_MASK (3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_16 (3<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_20 (2<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_24 (1<<30)
+#define KIRKWOOD_I2S_CTL_SIZE_32 (0<<30)
+
+#define KIRKWOOD_AUDIO_BUF_MAX (16*1024*1024)
+
+/* Theses values come from the marvell alsa driver */
+/* need to find where they come from */
+#define KIRKWOOD_SND_MIN_PERIODS 8
+#define KIRKWOOD_SND_MAX_PERIODS 16
+#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
+#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
+
+struct kirkwood_dma_data {
+ struct resource *mem;
+ void __iomem *io;
+ int irq;
+ int burst;
+ struct mbus_dram_target_info *dram;
+};
+
+#endif
diff --git a/sound/soc/nuc900/Kconfig b/sound/soc/nuc900/Kconfig
new file mode 100644
index 000000000000..a0ed1c618f60
--- /dev/null
+++ b/sound/soc/nuc900/Kconfig
@@ -0,0 +1,27 @@
+##
+## NUC900 series AC97 API
+##
+config SND_SOC_NUC900
+ tristate "SoC Audio for NUC900 series"
+ depends on ARCH_W90X900
+ help
+ This option enables support for AC97 mode on the NUC900 SoC.
+
+config SND_SOC_NUC900_AC97
+ tristate
+ select AC97_BUS
+ select SND_AC97_CODEC
+ select SND_SOC_AC97_BUS
+
+
+##
+## Boards
+##
+config SND_SOC_NUC900EVB
+ tristate "NUC900 AC97 support for demo board"
+ depends on SND_SOC_NUC900
+ select SND_SOC_NUC900_AC97
+ select SND_SOC_AC97_CODEC
+ help
+ Select this option to enable audio (AC97) on the
+ NUC900 demoboard.
diff --git a/sound/soc/nuc900/Makefile b/sound/soc/nuc900/Makefile
new file mode 100644
index 000000000000..7e46c7150316
--- /dev/null
+++ b/sound/soc/nuc900/Makefile
@@ -0,0 +1,11 @@
+# NUC900 series audio
+snd-soc-nuc900-pcm-objs := nuc900-pcm.o
+snd-soc-nuc900-ac97-objs := nuc900-ac97.o
+
+obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o
+obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o
+
+# Boards
+snd-soc-nuc900-audio-objs := nuc900-audio.o
+
+obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
new file mode 100644
index 000000000000..caa7c901bc2e
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -0,0 +1,430 @@
+/*
+ * Copyright (c) 2009-2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/suspend.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+
+#include <mach/mfp.h>
+
+#include "nuc900-audio.h"
+
+static DEFINE_MUTEX(ac97_mutex);
+struct nuc900_audio *nuc900_ac97_data;
+
+static int nuc900_checkready(void)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+
+ if (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS0) & CODEC_READY))
+ return -EPERM;
+
+ return 0;
+}
+
+/* AC97 controller reads codec register */
+static unsigned short nuc900_ac97_read(struct snd_ac97 *ac97,
+ unsigned short reg)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long timeout = 0x10000, val;
+
+ mutex_lock(&ac97_mutex);
+
+ val = nuc900_checkready();
+ if (!!val) {
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+ goto out;
+ }
+
+ /* set the R_WB bit and write register index */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, R_WB | reg);
+
+ /* set the valid frame bit and valid slots */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ val |= (VALID_FRAME | SLOT1_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
+
+ udelay(100);
+
+ /* polling the AC_R_FINISH */
+ while (!(AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_R_FINISH)
+ && timeout--)
+ mdelay(1);
+
+ if (!timeout) {
+ dev_err(nuc900_audio->dev, "AC97 read register time out !\n");
+ val = -EPERM;
+ goto out;
+ }
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0) ;
+ val &= ~SLOT1_VALID;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, val);
+
+ if (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS1) >> 2 != reg) {
+ dev_err(nuc900_audio->dev,
+ "R_INDEX of REG_ACTL_ACIS1 not match!\n");
+ }
+
+ udelay(100);
+ val = (AUDIO_READ(nuc900_audio->mmio + ACTL_ACIS2) & 0xFFFF);
+
+out:
+ mutex_unlock(&ac97_mutex);
+ return val;
+}
+
+/* AC97 controller writes to codec register */
+static void nuc900_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
+ unsigned short val)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long tmp, timeout = 0x10000;
+
+ mutex_lock(&ac97_mutex);
+
+ tmp = nuc900_checkready();
+ if (!!tmp)
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+
+ /* clear the R_WB bit and write register index */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS1, reg);
+
+ /* write register value */
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS2, val);
+
+ /* set the valid frame bit and valid slots */
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp |= SLOT1_VALID | SLOT2_VALID | VALID_FRAME;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ udelay(100);
+
+ /* polling the AC_W_FINISH */
+ while ((AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON) & AC_W_FINISH)
+ && timeout--)
+ mdelay(1);
+
+ if (!timeout)
+ dev_err(nuc900_audio->dev, "AC97 write register time out !\n");
+
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp &= ~(SLOT1_VALID | SLOT2_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ mutex_unlock(&ac97_mutex);
+
+}
+
+static void nuc900_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* warm reset AC 97 */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val |= AC_W_RES;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ udelay(100);
+
+ val = nuc900_checkready();
+ if (!!val)
+ dev_err(nuc900_audio->dev, "AC97 codec is not ready\n");
+
+ mutex_unlock(&ac97_mutex);
+}
+
+static void nuc900_ac97_cold_reset(struct snd_ac97 *ac97)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* reset Audio Controller */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val |= ACTL_RESET_BIT;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val &= (~ACTL_RESET_BIT);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ /* reset AC-link interface */
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val |= AC_RESET;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ val &= ~AC_RESET;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ /* cold reset AC 97 */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val |= AC_C_RES;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_ACCON);
+ val &= (~AC_C_RES);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACCON, val);
+
+ udelay(100);
+
+ mutex_unlock(&ac97_mutex);
+
+}
+
+/* AC97 controller operations */
+struct snd_ac97_bus_ops soc_ac97_ops = {
+ .read = nuc900_ac97_read,
+ .write = nuc900_ac97_write,
+ .reset = nuc900_ac97_cold_reset,
+ .warm_reset = nuc900_ac97_warm_reset,
+}
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+static int nuc900_ac97_trigger(struct snd_pcm_substream *substream,
+ int cmd, struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ int ret;
+ unsigned long val, tmp;
+
+ ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp |= (SLOT3_VALID | SLOT4_VALID | VALID_FRAME);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
+ tmp |= (P_DMA_END_IRQ | P_DMA_MIDDLE_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, tmp);
+ val |= AC_PLAY;
+ } else {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
+ tmp |= (R_DMA_END_IRQ | R_DMA_MIDDLE_IRQ);
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, tmp);
+ val |= AC_RECORD;
+ }
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ tmp = AUDIO_READ(nuc900_audio->mmio + ACTL_ACOS0);
+ tmp &= ~(SLOT3_VALID | SLOT4_VALID);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_ACOS0, tmp);
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, RESET_PRSR);
+ val &= ~AC_PLAY;
+ } else {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, RESET_PRSR);
+ val &= ~AC_RECORD;
+ }
+
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int nuc900_ac97_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+ unsigned long val;
+
+ mutex_lock(&ac97_mutex);
+
+ /* enable unit clock */
+ clk_enable(nuc900_audio->clk);
+
+ /* enable audio controller and AC-link interface */
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val |= (IIS_AC_PIN_SEL | ACLINK_EN);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+
+ mutex_unlock(&ac97_mutex);
+
+ return 0;
+}
+
+static void nuc900_ac97_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct nuc900_audio *nuc900_audio = nuc900_ac97_data;
+
+ clk_disable(nuc900_audio->clk);
+}
+
+static struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
+ .trigger = nuc900_ac97_trigger,
+};
+
+struct snd_soc_dai nuc900_ac97_dai = {
+ .name = "nuc900-ac97",
+ .probe = nuc900_ac97_probe,
+ .remove = nuc900_ac97_remove,
+ .ac97_control = 1,
+ .playback = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .capture = {
+ .rates = SNDRV_PCM_RATE_8000_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ },
+ .ops = &nuc900_ac97_dai_ops,
+}
+EXPORT_SYMBOL_GPL(nuc900_ac97_dai);
+
+static int __devinit nuc900_ac97_drvprobe(struct platform_device *pdev)
+{
+ struct nuc900_audio *nuc900_audio;
+ int ret;
+
+ if (nuc900_ac97_data)
+ return -EBUSY;
+
+ nuc900_audio = kzalloc(sizeof(struct nuc900_audio), GFP_KERNEL);
+ if (!nuc900_audio)
+ return -ENOMEM;
+
+ spin_lock_init(&nuc900_audio->lock);
+
+ nuc900_audio->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!nuc900_audio->res) {
+ ret = -ENODEV;
+ goto out0;
+ }
+
+ if (!request_mem_region(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res), pdev->name)) {
+ ret = -EBUSY;
+ goto out0;
+ }
+
+ nuc900_audio->mmio = ioremap(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res));
+ if (!nuc900_audio->mmio) {
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ nuc900_audio->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(nuc900_audio->clk)) {
+ ret = PTR_ERR(nuc900_audio->clk);
+ goto out2;
+ }
+
+ nuc900_audio->irq_num = platform_get_irq(pdev, 0);
+ if (!nuc900_audio->irq_num) {
+ ret = -EBUSY;
+ goto out2;
+ }
+
+ nuc900_ac97_data = nuc900_audio;
+
+ nuc900_audio->dev = nuc900_ac97_dai.dev = &pdev->dev;
+
+ ret = snd_soc_register_dai(&nuc900_ac97_dai);
+ if (ret)
+ goto out3;
+
+ mfp_set_groupg(nuc900_audio->dev); /* enbale ac97 multifunction pin*/
+
+ return 0;
+
+out3:
+ clk_put(nuc900_audio->clk);
+out2:
+ iounmap(nuc900_audio->mmio);
+out1:
+ release_mem_region(nuc900_audio->res->start,
+ resource_size(nuc900_audio->res));
+out0:
+ kfree(nuc900_audio);
+ return ret;
+}
+
+static int __devexit nuc900_ac97_drvremove(struct platform_device *pdev)
+{
+
+ snd_soc_unregister_dai(&nuc900_ac97_dai);
+
+ clk_put(nuc900_ac97_data->clk);
+ iounmap(nuc900_ac97_data->mmio);
+ release_mem_region(nuc900_ac97_data->res->start,
+ resource_size(nuc900_ac97_data->res));
+
+ nuc900_ac97_data = NULL;
+
+ return 0;
+}
+
+static struct platform_driver nuc900_ac97_driver = {
+ .driver = {
+ .name = "nuc900-audio",
+ .owner = THIS_MODULE,
+ },
+ .probe = nuc900_ac97_drvprobe,
+ .remove = __devexit_p(nuc900_ac97_drvremove),
+};
+
+static int __init nuc900_ac97_init(void)
+{
+ return platform_driver_register(&nuc900_ac97_driver);
+}
+
+static void __exit nuc900_ac97_exit(void)
+{
+ platform_driver_unregister(&nuc900_ac97_driver);
+}
+
+module_init(nuc900_ac97_init);
+module_exit(nuc900_ac97_exit);
+
+MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("NUC900 AC97 SoC driver!");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:nuc900-ac97");
diff --git a/sound/soc/nuc900/nuc900-audio.c b/sound/soc/nuc900/nuc900-audio.c
new file mode 100644
index 000000000000..b33d5b844d71
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "../codecs/ac97.h"
+#include "nuc900-auido.h"
+
+static struct snd_soc_dai_link nuc900evb_ac97_dai = {
+ .name = "AC97",
+ .stream_name = "AC97 HiFi",
+ .cpu_dai = &nuc900_ac97_dai,
+ .codec_dai = &ac97_dai,
+};
+
+static struct snd_soc_card nuc900evb_audio_machine = {
+ .name = "NUC900EVB_AC97",
+ .dai_link = &nuc900evb_ac97_dai,
+ .num_links = 1,
+ .platform = &nuc900_soc_platform,
+};
+
+static struct snd_soc_device nuc900evb_ac97_devdata = {
+ .card = &nuc900evb_audio_machine,
+ .codec_dev = &soc_codec_dev_ac97,
+};
+
+static struct platform_device *nuc900evb_asoc_dev;
+
+static int __init nuc900evb_audio_init(void)
+{
+ int ret;
+
+ ret = -ENOMEM;
+ nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);
+ if (!nuc900evb_asoc_dev)
+ goto out;
+
+ /* nuc900 board audio device */
+ platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
+
+ nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
+ ret = platform_device_add(nuc900evb_asoc_dev);
+
+ if (ret) {
+ platform_device_put(nuc900evb_asoc_dev);
+ nuc900evb_asoc_dev = NULL;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit nuc900evb_audio_exit(void)
+{
+ platform_device_unregister(nuc900evb_asoc_dev);
+}
+
+module_init(nuc900evb_audio_init);
+module_exit(nuc900evb_audio_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("NUC900 Series ASoC audio support");
+MODULE_AUTHOR("Wan ZongShun");
diff --git a/sound/soc/nuc900/nuc900-audio.h b/sound/soc/nuc900/nuc900-audio.h
new file mode 100644
index 000000000000..3038f519729f
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-audio.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#ifndef _NUC900_AUDIO_H
+#define _NUC900_AUDIO_H
+
+#include <linux/io.h>
+
+/* Audio Control Registers */
+#define ACTL_CON 0x00
+#define ACTL_RESET 0x04
+#define ACTL_RDSTB 0x08
+#define ACTL_RDST_LENGTH 0x0C
+#define ACTL_RDSTC 0x10
+#define ACTL_RSR 0x14
+#define ACTL_PDSTB 0x18
+#define ACTL_PDST_LENGTH 0x1C
+#define ACTL_PDSTC 0x20
+#define ACTL_PSR 0x24
+#define ACTL_IISCON 0x28
+#define ACTL_ACCON 0x2C
+#define ACTL_ACOS0 0x30
+#define ACTL_ACOS1 0x34
+#define ACTL_ACOS2 0x38
+#define ACTL_ACIS0 0x3C
+#define ACTL_ACIS1 0x40
+#define ACTL_ACIS2 0x44
+#define ACTL_COUNTER 0x48
+
+/* bit definition of REG_ACTL_CON register */
+#define R_DMA_IRQ 0x1000
+#define T_DMA_IRQ 0x0800
+#define IIS_AC_PIN_SEL 0x0100
+#define FIFO_TH 0x0080
+#define ADC_EN 0x0010
+#define M80_EN 0x0008
+#define ACLINK_EN 0x0004
+#define IIS_EN 0x0002
+
+/* bit definition of REG_ACTL_RESET register */
+#define W5691_PLAY 0x20000
+#define ACTL_RESET_BIT 0x10000
+#define RECORD_RIGHT_CHNNEL 0x08000
+#define RECORD_LEFT_CHNNEL 0x04000
+#define PLAY_RIGHT_CHNNEL 0x02000
+#define PLAY_LEFT_CHNNEL 0x01000
+#define DAC_PLAY 0x00800
+#define ADC_RECORD 0x00400
+#define M80_PLAY 0x00200
+#define AC_RECORD 0x00100
+#define AC_PLAY 0x00080
+#define IIS_RECORD 0x00040
+#define IIS_PLAY 0x00020
+#define DAC_RESET 0x00010
+#define ADC_RESET 0x00008
+#define M80_RESET 0x00004
+#define AC_RESET 0x00002
+#define IIS_RESET 0x00001
+
+/* bit definition of REG_ACTL_ACCON register */
+#define AC_BCLK_PU_EN 0x20
+#define AC_R_FINISH 0x10
+#define AC_W_FINISH 0x08
+#define AC_W_RES 0x04
+#define AC_C_RES 0x02
+
+/* bit definition of ACTL_RSR register */
+#define R_FIFO_EMPTY 0x04
+#define R_DMA_END_IRQ 0x02
+#define R_DMA_MIDDLE_IRQ 0x01
+
+/* bit definition of ACTL_PSR register */
+#define P_FIFO_EMPTY 0x04
+#define P_DMA_END_IRQ 0x02
+#define P_DMA_MIDDLE_IRQ 0x01
+
+/* bit definition of ACTL_ACOS0 register */
+#define SLOT1_VALID 0x01
+#define SLOT2_VALID 0x02
+#define SLOT3_VALID 0x04
+#define SLOT4_VALID 0x08
+#define VALID_FRAME 0x10
+
+/* bit definition of ACTL_ACOS1 register */
+#define R_WB 0x80
+
+#define CODEC_READY 0x10
+#define RESET_PRSR 0x00
+#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)
+#define AUDIO_READ(addr) __raw_readl(addr)
+
+struct nuc900_audio {
+ void __iomem *mmio;
+ spinlock_t lock;
+ dma_addr_t dma_addr[2];
+ unsigned long buffersize[2];
+ unsigned long irq_num;
+ struct snd_pcm_substream *substream;
+ struct resource *res;
+ struct clk *clk;
+ struct device *dev;
+
+};
+
+extern struct nuc900_audio *nuc900_ac97_data;
+extern struct snd_soc_dai nuc900_ac97_dai;
+extern struct snd_soc_platform nuc900_soc_platform;
+
+#endif /*end _NUC900_AUDIO_H */
diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c
new file mode 100644
index 000000000000..445a18011d8e
--- /dev/null
+++ b/sound/soc/nuc900/nuc900-pcm.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2010 Nuvoton technology corporation.
+ *
+ * Wan ZongShun <mcuos.com@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;version 2 of the License.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+
+#include "nuc900-auido.h"
+
+static const struct snd_pcm_hardware nuc900_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .buffer_bytes_max = 4*1024,
+ .period_bytes_min = 1*1024,
+ .period_bytes_max = 4*1024,
+ .periods_min = 1,
+ .periods_max = 1024,
+};
+
+static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&nuc900_audio->lock, flags);
+
+ ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+ if (ret < 0)
+ return ret;
+
+ nuc900_audio->substream = substream;
+ nuc900_audio->dma_addr[substream->stream] = runtime->dma_addr;
+ nuc900_audio->buffersize[substream->stream] =
+ params_buffer_bytes(params);
+
+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);
+
+ return ret;
+}
+
+static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
+ dma_addr_t dma_addr, size_t count)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ void __iomem *mmio_addr, *mmio_len;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;
+ mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;
+ } else {
+ mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;
+ mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;
+ }
+
+ AUDIO_WRITE(mmio_addr, dma_addr);
+ AUDIO_WRITE(mmio_len, count);
+}
+
+static void nuc900_dma_start(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long val;
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val |= (T_DMA_IRQ | R_DMA_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+}
+
+static void nuc900_dma_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long val;
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+ val &= ~(T_DMA_IRQ | R_DMA_IRQ);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
+}
+
+static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)
+{
+ struct snd_pcm_substream *substream = dev_id;
+ struct nuc900_audio *nuc900_audio = substream->runtime->private_data;
+ unsigned long val;
+
+ spin_lock(&nuc900_audio->lock);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
+
+ if (val & R_DMA_IRQ) {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
+
+ if (val & R_DMA_MIDDLE_IRQ) {
+ val |= R_DMA_MIDDLE_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
+ }
+
+ if (val & R_DMA_END_IRQ) {
+ val |= R_DMA_END_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
+ }
+ } else if (val & T_DMA_IRQ) {
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
+
+ if (val & P_DMA_MIDDLE_IRQ) {
+ val |= P_DMA_MIDDLE_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
+ }
+
+ if (val & P_DMA_END_IRQ) {
+ val |= P_DMA_END_IRQ;
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
+ }
+ } else {
+ dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");
+ spin_unlock(&nuc900_audio->lock);
+ return IRQ_HANDLED;
+ }
+
+ spin_unlock(&nuc900_audio->lock);
+
+ snd_pcm_period_elapsed(substream);
+
+ return IRQ_HANDLED;
+}
+
+static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)
+{
+ snd_pcm_lib_free_pages(substream);
+ return 0;
+}
+
+static int nuc900_dma_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+ unsigned long flags, val;
+
+ spin_lock_irqsave(&nuc900_audio->lock, flags);
+
+ nuc900_update_dma_register(substream,
+ nuc900_audio->dma_addr[substream->stream],
+ nuc900_audio->buffersize[substream->stream]);
+
+ val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
+
+ switch (runtime->channels) {
+ case 1:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
+ val |= PLAY_RIGHT_CHNNEL;
+ } else {
+ val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
+ val |= RECORD_RIGHT_CHNNEL;
+ }
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+ break;
+ case 2:
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
+ else
+ val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
+ AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
+ break;
+ default:
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&nuc900_audio->lock, flags);
+ return 0;
+}
+
+static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ nuc900_dma_start(substream);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ nuc900_dma_stop(substream);
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int nuc900_dma_getposition(struct snd_pcm_substream *substream,
+ dma_addr_t *src, dma_addr_t *dst)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+
+ if (src != NULL)
+ *src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);
+
+ if (dst != NULL)
+ *dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);
+
+ return 0;
+}
+
+static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ dma_addr_t src, dst;
+ unsigned long res;
+
+ nuc900_dma_getposition(substream, &src, &dst);
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ res = dst - runtime->dma_addr;
+ else
+ res = src - runtime->dma_addr;
+
+ return bytes_to_frames(substream->runtime, res);
+}
+
+static int nuc900_dma_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio;
+
+ snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);
+
+ nuc900_audio = nuc900_ac97_data;
+
+ if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,
+ IRQF_DISABLED, "nuc900-dma", substream))
+ return -EBUSY;
+
+ runtime->private_data = nuc900_audio;
+
+ return 0;
+}
+
+static int nuc900_dma_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct nuc900_audio *nuc900_audio = runtime->private_data;
+
+ free_irq(nuc900_audio->irq_num, substream);
+
+ return 0;
+}
+
+static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops nuc900_dma_ops = {
+ .open = nuc900_dma_open,
+ .close = nuc900_dma_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = nuc900_dma_hw_params,
+ .hw_free = nuc900_dma_hw_free,
+ .prepare = nuc900_dma_prepare,
+ .trigger = nuc900_dma_trigger,
+ .pointer = nuc900_dma_pointer,
+ .mmap = nuc900_dma_mmap,
+};
+
+static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
+{
+ snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
+static int nuc900_dma_new(struct snd_card *card,
+ struct snd_soc_dai *dai, struct snd_pcm *pcm)
+{
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &nuc900_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+ card->dev, 4 * 1024, (4 * 1024) - 1);
+
+ return 0;
+}
+
+struct snd_soc_platform nuc900_soc_platform = {
+ .name = "nuc900-dma",
+ .pcm_ops = &nuc900_dma_ops,
+ .pcm_new = nuc900_dma_new,
+ .pcm_free = nuc900_dma_free_dma_buffers,
+}
+EXPORT_SYMBOL_GPL(nuc900_soc_platform);
+
+static int __init nuc900_soc_platform_init(void)
+{
+ return snd_soc_register_platform(&nuc900_soc_platform);
+}
+
+static void __exit nuc900_soc_platform_exit(void)
+{
+ snd_soc_unregister_platform(&nuc900_soc_platform);
+}
+
+module_init(nuc900_soc_platform_init);
+module_exit(nuc900_soc_platform_exit);
+
+MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
+MODULE_DESCRIPTION("nuc900 Audio DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6f44cb4d30b8..aebd3af2ab79 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,6 +59,7 @@ struct omap_mcbsp_data {
int configured;
unsigned int in_freq;
int clk_div;
+ int wlen;
};
#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -155,19 +156,65 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
- int samples;
+ int words;
/* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
- samples = snd_pcm_lib_period_bytes(substream) >> 1;
+ /* The FIFO size depends on the McBSP word configuration */
+ words = snd_pcm_lib_period_bytes(substream) /
+ (mcbsp_data->wlen / 8);
else
- samples = 1;
+ words = 1;
/* Configure McBSP internal buffer usage */
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1);
+ omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
else
- omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1);
+ omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
+}
+
+static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *buffer_size = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct omap_mcbsp_data *mcbsp_data = rule->private;
+ struct snd_interval frames;
+ int size;
+
+ snd_interval_any(&frames);
+ size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
+
+ frames.min = size / channels->min;
+ frames.integer = 1;
+ return snd_interval_refine(buffer_size, &frames);
+}
+
+static int omap_mcbsp_hwrule_max_periodsize(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_interval *period_size = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_pcm_substream *substream = rule->private;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct snd_interval frames;
+ int size;
+
+ snd_interval_any(&frames);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ size = omap_mcbsp_get_max_tx_threshold(mcbsp_data->bus_id);
+ else
+ size = omap_mcbsp_get_max_rx_threshold(mcbsp_data->bus_id);
+
+ frames.max = size / channels->min;
+ frames.integer = 1;
+ return snd_interval_refine(period_size, &frames);
}
static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
@@ -182,33 +229,45 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
if (!cpu_dai->active)
err = omap_mcbsp_request(bus_id);
+ /*
+ * OMAP3 McBSP FIFO is word structured.
+ * McBSP2 has 1024 + 256 = 1280 word long buffer,
+ * McBSP1,3,4,5 has 128 word long buffer
+ * This means that the size of the FIFO depends on the sample format.
+ * For example on McBSP3:
+ * 16bit samples: size is 128 * 2 = 256 bytes
+ * 32bit samples: size is 128 * 4 = 512 bytes
+ * It is simpler to place constraint for buffer and period based on
+ * channels.
+ * McBSP3 as example again (16 or 32 bit samples):
+ * 1 channel (mono): size is 128 frames (128 words)
+ * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
+ * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
+ */
if (cpu_is_omap343x()) {
int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
- int max_period;
/*
- * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer.
- * Set constraint for minimum buffer size to the same than FIFO
- * size in order to avoid underruns in playback startup because
- * HW is keeping the DMA request active until FIFO is filled.
- */
- if (bus_id == 1)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- 4096, UINT_MAX);
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- max_period = omap_mcbsp_get_max_tx_threshold(bus_id);
- else
- max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
-
- max_period++;
- max_period <<= 1;
+ * The first rule is for the buffer size, we should not allow
+ * smaller buffer than the FIFO size to avoid underruns
+ */
+ snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ omap_mcbsp_hwrule_min_buffersize,
+ mcbsp_data,
+ SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
+ /*
+ * In case of threshold mode, the rule will ensure, that the
+ * period size is not bigger than the maximum allowed threshold
+ * value.
+ */
if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
- snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- 32, max_period);
+ snd_pcm_hw_rule_add(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ omap_mcbsp_hwrule_max_periodsize,
+ substream,
+ SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
}
return err;
@@ -409,6 +468,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
}
omap_mcbsp_config(bus_id, &mcbsp_data->regs);
+ mcbsp_data->wlen = wlen;
mcbsp_data->configured = 1;
return 0;
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 2a7cc222d098..292d817c9a94 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -1,6 +1,6 @@
config SND_S3C24XX_SOC
tristate "SoC Audio for the Samsung S3CXXXX chips"
- depends on ARCH_S3C2410 || ARCH_S3C64XX
+ depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
select S3C64XX_DMA if ARCH_S3C64XX
help
Say Y or M if you want to add support for codecs attached to
@@ -120,7 +120,7 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
- depends on SND_S3C24XX_SOC && MACH_SMDK6410
+ depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
select SND_S3C_SOC_AC97
help
diff --git a/sound/soc/s3c24xx/s3c-ac97.c b/sound/soc/s3c24xx/s3c-ac97.c
index ecf4fd04ae96..31f6d45b6384 100644
--- a/sound/soc/s3c24xx/s3c-ac97.c
+++ b/sound/soc/s3c24xx/s3c-ac97.c
@@ -31,7 +31,6 @@
#define AC_CMD_DATA(x) (x & 0xffff)
struct s3c_ac97_info {
- unsigned state;
struct clk *ac97_clk;
void __iomem *regs;
struct mutex lock;
diff --git a/sound/soc/s3c24xx/smdk_wm9713.c b/sound/soc/s3c24xx/smdk_wm9713.c
index 24fd39f38ccb..5527b9e88c98 100644
--- a/sound/soc/s3c24xx/smdk_wm9713.c
+++ b/sound/soc/s3c24xx/smdk_wm9713.c
@@ -25,6 +25,9 @@ static struct snd_soc_card smdk;
* Default CFG switch settings to use this driver:
*
* SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
+ * SMDKC100: Set CFG6 1-3 On, CFG7 1 On
+ * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
+ * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
*/
/*
diff --git a/sound/soc/s6000/s6000-i2s.c b/sound/soc/s6000/s6000-i2s.c
index 5b9ac1759bd2..59e3fa7bcb05 100644
--- a/sound/soc/s6000/s6000-i2s.c
+++ b/sound/soc/s6000/s6000-i2s.c
@@ -451,16 +451,15 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_none;
}
- region = request_mem_region(scbmem->start,
- scbmem->end - scbmem->start + 1,
- pdev->name);
+ region = request_mem_region(scbmem->start, resource_size(scbmem),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S SCB region already claimed\n");
ret = -EBUSY;
goto err_release_none;
}
- mmio = ioremap(scbmem->start, scbmem->end - scbmem->start + 1);
+ mmio = ioremap(scbmem->start, resource_size(scbmem));
if (!mmio) {
dev_err(&pdev->dev, "can't ioremap SCB region\n");
ret = -ENOMEM;
@@ -474,9 +473,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_map;
}
- region = request_mem_region(sifmem->start,
- sifmem->end - sifmem->start + 1,
- pdev->name);
+ region = request_mem_region(sifmem->start, resource_size(sifmem),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S SIF region already claimed\n");
ret = -EBUSY;
@@ -490,8 +488,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
goto err_release_sif;
}
- region = request_mem_region(dma1->start, dma1->end - dma1->start + 1,
- pdev->name);
+ region = request_mem_region(dma1->start, resource_size(dma1),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev, "I2S DMA region already claimed\n");
ret = -EBUSY;
@@ -500,9 +498,8 @@ static int __devinit s6000_i2s_probe(struct platform_device *pdev)
dma2 = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (dma2) {
- region = request_mem_region(dma2->start,
- dma2->end - dma2->start + 1,
- pdev->name);
+ region = request_mem_region(dma2->start, resource_size(dma2),
+ pdev->name);
if (!region) {
dev_err(&pdev->dev,
"I2S DMA region already claimed\n");
@@ -561,15 +558,15 @@ err_release_dev:
kfree(dev);
err_release_dma2:
if (dma2)
- release_mem_region(dma2->start, dma2->end - dma2->start + 1);
+ release_mem_region(dma2->start, resource_size(dma2));
err_release_dma1:
- release_mem_region(dma1->start, dma1->end - dma1->start + 1);
+ release_mem_region(dma1->start, resource_size(dma1));
err_release_sif:
- release_mem_region(sifmem->start, (sifmem->end - sifmem->start) + 1);
+ release_mem_region(sifmem->start, resource_size(sifmem));
err_release_map:
iounmap(mmio);
err_release_scb:
- release_mem_region(scbmem->start, (scbmem->end - scbmem->start) + 1);
+ release_mem_region(scbmem->start, resource_size(scbmem));
err_release_none:
return ret;
}
@@ -590,19 +587,18 @@ static void __devexit s6000_i2s_remove(struct platform_device *pdev)
kfree(dev);
region = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- release_mem_region(region->start, region->end - region->start + 1);
+ release_mem_region(region->start, resource_size(region));
region = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (region)
- release_mem_region(region->start,
- region->end - region->start + 1);
+ release_mem_region(region->start, resource_size(region));
region = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(region->start, (region->end - region->start) + 1);
+ release_mem_region(region->start, resource_size(region));
iounmap(mmio);
region = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_mem_region(region->start, (region->end - region->start) + 1);
+ release_mem_region(region->start, resource_size(region));
}
static struct platform_driver s6000_i2s_driver = {
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 998569d60330..254dd1c6914d 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -2353,6 +2353,101 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
/**
+ * snd_soc_info_volsw_2r_sx - double with tlv and variable data size
+ * mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int max = mc->max;
+ int min = mc->min;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 2;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = max-min;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
+
+/**
+ * snd_soc_get_volsw_2r_sx - double with tlv and variable data size
+ * mixer get callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = (1<<mc->shift)-1;
+ int min = mc->min;
+ int val = snd_soc_read(codec, mc->reg) & mask;
+ int valr = snd_soc_read(codec, mc->rreg) & mask;
+
+ ucontrol->value.integer.value[0] = ((val & 0xff)-min);
+ ucontrol->value.integer.value[1] = ((valr & 0xff)-min);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
+
+/**
+ * snd_soc_put_volsw_2r_sx - double with tlv and variable data size
+ * mixer put callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ unsigned int mask = (1<<mc->shift)-1;
+ int min = mc->min;
+ int ret;
+ unsigned int val, valr, oval, ovalr;
+
+ val = ((ucontrol->value.integer.value[0]+min) & 0xff);
+ val &= mask;
+ valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
+ valr &= mask;
+
+ oval = snd_soc_read(codec, mc->reg) & mask;
+ ovalr = snd_soc_read(codec, mc->rreg) & mask;
+
+ ret = 0;
+ if (oval != val) {
+ ret = snd_soc_write(codec, mc->reg, val);
+ if (ret < 0)
+ return 0;
+ ret = 1;
+ }
+ if (ovalr != valr) {
+ ret = snd_soc_write(codec, mc->rreg, valr);
+ if (ret < 0)
+ return 0;
+ ret = 1;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
+
+/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @clk_id: DAI specific clock ID
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index e7ac7f493a8f..1e362bf8834f 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \
endpoint.o \
urb.o \
pcm.o \
- helper.o
+ helper.o \
+ clock.o
snd-usbmidi-lib-objs := midi.o
diff --git a/sound/usb/card.c b/sound/usb/card.c
index da1346bd4856..7a8ac1d81be7 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
}
case UAC_VERSION_2: {
- struct uac_clock_source_descriptor *cs;
struct usb_interface_assoc_descriptor *assoc =
usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
@@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
return -EINVAL;
}
- /* FIXME: for now, we expect there is at least one clock source
- * descriptor and we always take the first one.
- * We should properly support devices with multiple clock sources,
- * clock selectors and sample rate conversion units. */
-
- cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen,
- NULL, UAC2_CLOCK_SOURCE);
-
- if (!cs) {
- snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n");
- return -EINVAL;
- }
-
- chip->clock_id = cs->bClockID;
-
for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i;
@@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
goto __error;
}
+ chip->ctrl_intf = alts;
+
if (err > 0) {
/* create normal USB audio interfaces */
if (snd_usb_create_streams(chip, ifnum) < 0 ||
diff --git a/sound/usb/card.h b/sound/usb/card.h
index ed92420c1095..1febf2f23754 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -25,6 +25,7 @@ struct audioformat {
unsigned int rate_min, rate_max; /* min/max rates */
unsigned int nr_rates; /* number of rate table entries */
unsigned int *rate_table; /* rate table */
+ unsigned char clock; /* associated clock */
};
struct snd_usb_substream;
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
new file mode 100644
index 000000000000..b7aadd614c70
--- /dev/null
+++ b/sound/usb/clock.c
@@ -0,0 +1,311 @@
+/*
+ * Clock domain and sample rate management functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+
+#include "usbaudio.h"
+#include "card.h"
+#include "midi.h"
+#include "mixer.h"
+#include "proc.h"
+#include "quirks.h"
+#include "endpoint.h"
+#include "helper.h"
+#include "debug.h"
+#include "pcm.h"
+#include "urb.h"
+#include "format.h"
+
+static struct uac_clock_source_descriptor *
+ snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
+ int clock_id)
+{
+ struct uac_clock_source_descriptor *cs = NULL;
+
+ while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ cs, UAC2_CLOCK_SOURCE))) {
+ if (cs->bClockID == clock_id)
+ return cs;
+ }
+
+ return NULL;
+}
+
+static struct uac_clock_selector_descriptor *
+ snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
+ int clock_id)
+{
+ struct uac_clock_selector_descriptor *cs = NULL;
+
+ while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ cs, UAC2_CLOCK_SELECTOR))) {
+ if (cs->bClockID == clock_id)
+ return cs;
+ }
+
+ return NULL;
+}
+
+static struct uac_clock_multiplier_descriptor *
+ snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
+ int clock_id)
+{
+ struct uac_clock_multiplier_descriptor *cs = NULL;
+
+ while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ cs, UAC2_CLOCK_MULTIPLIER))) {
+ if (cs->bClockID == clock_id)
+ return cs;
+ }
+
+ return NULL;
+}
+
+static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
+{
+ unsigned char buf;
+ int ret;
+
+ ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8,
+ &buf, sizeof(buf), 1000);
+
+ if (ret < 0)
+ return ret;
+
+ return buf;
+}
+
+static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
+{
+ int err;
+ unsigned char data;
+ struct usb_device *dev = chip->dev;
+
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8,
+ &data, sizeof(data), 1000);
+
+ if (err < 0) {
+ snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
+ __func__, source_id);
+ return err;
+ }
+
+ return !!data;
+}
+
+/* Try to find the clock source ID of a given clock entity */
+
+static int __uac_clock_find_source(struct snd_usb_audio *chip,
+ struct usb_host_interface *host_iface,
+ int entity_id, unsigned long *visited)
+{
+ struct uac_clock_source_descriptor *source;
+ struct uac_clock_selector_descriptor *selector;
+ struct uac_clock_multiplier_descriptor *multiplier;
+
+ entity_id &= 0xff;
+
+ if (test_and_set_bit(entity_id, visited)) {
+ snd_printk(KERN_WARNING
+ "%s(): recursive clock topology detected, id %d.\n",
+ __func__, entity_id);
+ return -EINVAL;
+ }
+
+ /* first, see if the ID we're looking for is a clock source already */
+ source = snd_usb_find_clock_source(host_iface, entity_id);
+ if (source)
+ return source->bClockID;
+
+ selector = snd_usb_find_clock_selector(host_iface, entity_id);
+ if (selector) {
+ int ret;
+
+ /* the entity ID we are looking for is a selector.
+ * find out what it currently selects */
+ ret = uac_clock_selector_get_val(chip, selector->bClockID);
+ if (ret < 0)
+ return ret;
+
+ if (ret > selector->bNrInPins || ret < 1) {
+ printk(KERN_ERR
+ "%s(): selector reported illegal value, id %d, ret %d\n",
+ __func__, selector->bClockID, ret);
+
+ return -EINVAL;
+ }
+
+ return __uac_clock_find_source(chip, host_iface,
+ selector->baCSourceID[ret-1],
+ visited);
+ }
+
+ /* FIXME: multipliers only act as pass-thru element for now */
+ multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id);
+ if (multiplier)
+ return __uac_clock_find_source(chip, host_iface,
+ multiplier->bCSourceID, visited);
+
+ return -EINVAL;
+}
+
+int snd_usb_clock_find_source(struct snd_usb_audio *chip,
+ struct usb_host_interface *host_iface,
+ int entity_id)
+{
+ DECLARE_BITMAP(visited, 256);
+ memset(visited, 0, sizeof(visited));
+ return __uac_clock_find_source(chip, host_iface, entity_id, visited);
+}
+
+static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
+ struct usb_host_interface *alts,
+ struct audioformat *fmt, int rate)
+{
+ struct usb_device *dev = chip->dev;
+ unsigned int ep;
+ unsigned char data[3];
+ int err, crate;
+
+ ep = get_endpoint(alts, 0)->bEndpointAddress;
+
+ /* if endpoint doesn't have sampling rate control, bail out */
+ if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
+ snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
+ dev->devnum, iface, fmt->altsetting);
+ return 0;
+ }
+
+ data[0] = rate;
+ data[1] = rate >> 8;
+ data[2] = rate >> 16;
+ if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
+ USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+ UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
+ data, sizeof(data), 1000)) < 0) {
+ snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
+ dev->devnum, iface, fmt->altsetting, rate, ep);
+ return err;
+ }
+
+ if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+ USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
+ UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
+ data, sizeof(data), 1000)) < 0) {
+ snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
+ dev->devnum, iface, fmt->altsetting, ep);
+ return 0; /* some devices don't support reading */
+ }
+
+ crate = data[0] | (data[1] << 8) | (data[2] << 16);
+ if (crate != rate) {
+ snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+ // runtime->rate = crate;
+ }
+
+ return 0;
+}
+
+static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
+ struct usb_host_interface *alts,
+ struct audioformat *fmt, int rate)
+{
+ struct usb_device *dev = chip->dev;
+ unsigned char data[4];
+ int err, crate;
+ int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock);
+
+ if (clock < 0)
+ return clock;
+
+ if (!uac_clock_source_is_valid(chip, clock)) {
+ snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
+ dev->devnum, iface, fmt->altsetting, clock);
+ return -ENXIO;
+ }
+
+ data[0] = rate;
+ data[1] = rate >> 8;
+ data[2] = rate >> 16;
+ data[3] = rate >> 24;
+ if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+ data, sizeof(data), 1000)) < 0) {
+ snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
+ dev->devnum, iface, fmt->altsetting, rate);
+ return err;
+ }
+
+ if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+ data, sizeof(data), 1000)) < 0) {
+ snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
+ dev->devnum, iface, fmt->altsetting);
+ return err;
+ }
+
+ crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+ if (crate != rate)
+ snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
+
+ return 0;
+}
+
+int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
+ struct usb_host_interface *alts,
+ struct audioformat *fmt, int rate)
+{
+ struct usb_interface_descriptor *altsd = get_iface_desc(alts);
+
+ switch (altsd->bInterfaceProtocol) {
+ case UAC_VERSION_1:
+ return set_sample_rate_v1(chip, iface, alts, fmt, rate);
+
+ case UAC_VERSION_2:
+ return set_sample_rate_v2(chip, iface, alts, fmt, rate);
+ }
+
+ return -EINVAL;
+}
+
diff --git a/sound/usb/clock.h b/sound/usb/clock.h
new file mode 100644
index 000000000000..beb253684e2d
--- /dev/null
+++ b/sound/usb/clock.h
@@ -0,0 +1,12 @@
+#ifndef __USBAUDIO_CLOCK_H
+#define __USBAUDIO_CLOCK_H
+
+int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
+ struct usb_host_interface *alts,
+ struct audioformat *fmt, int rate);
+
+int snd_usb_clock_find_source(struct snd_usb_audio *chip,
+ struct usb_host_interface *host_iface,
+ int entity_id);
+
+#endif /* __USBAUDIO_CLOCK_H */
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 28ee1ce3971a..9593b91452b9 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
return attributes;
}
+static struct uac2_input_terminal_descriptor *
+ snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+ int terminal_id)
+{
+ struct uac2_input_terminal_descriptor *term = NULL;
+
+ while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ term, UAC_INPUT_TERMINAL))) {
+ if (term->bTerminalID == terminal_id)
+ return term;
+ }
+
+ return NULL;
+}
+
+static struct uac2_output_terminal_descriptor *
+ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
+ int terminal_id)
+{
+ struct uac2_output_terminal_descriptor *term = NULL;
+
+ while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
+ ctrl_iface->extralen,
+ term, UAC_OUTPUT_TERMINAL))) {
+ if (term->bTerminalID == terminal_id)
+ return term;
+ }
+
+ return NULL;
+}
+
int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
{
struct usb_device *dev;
@@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
int i, altno, err, stream;
int format = 0, num_channels = 0;
struct audioformat *fp = NULL;
- int num, protocol;
+ int num, protocol, clock = 0;
struct uac_format_type_i_continuous_descriptor *fmt;
dev = chip->dev;
@@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
}
case UAC_VERSION_2: {
+ struct uac2_input_terminal_descriptor *input_term;
+ struct uac2_output_terminal_descriptor *output_term;
struct uac_as_header_descriptor_v2 *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
@@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
num_channels = as->bNrChannels;
format = le32_to_cpu(as->bmFormats);
- break;
+ /* lookup the terminal associated to this interface
+ * to extract the clock */
+ input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
+ as->bTerminalLink);
+ if (input_term) {
+ clock = input_term->bCSourceID;
+ break;
+ }
+
+ output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
+ as->bTerminalLink);
+ if (output_term) {
+ clock = output_term->bCSourceID;
+ break;
+ }
+
+ snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
+ dev->devnum, iface_no, altno, as->bTerminalLink);
+ continue;
}
default:
@@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
* (fp->maxpacksize & 0x7ff);
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
+ fp->clock = clock;
/* some quirks for attributes here */
diff --git a/sound/usb/format.c b/sound/usb/format.c
index fe29d61de19b..5367cd1e52d9 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -29,6 +29,7 @@
#include "quirks.h"
#include "helper.h"
#include "debug.h"
+#include "clock.h"
/*
* parse the audio format type I descriptor
@@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data;
int i, nr_rates, data_size, ret = 0;
+ int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock);
/* get the number of sample rates first by only fetching 2 bytes */
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
+ UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
tmp, sizeof(tmp), 1000);
if (ret < 0) {
- snd_printk(KERN_ERR "unable to retrieve number of sample rates\n");
+ snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
+ __func__, clock);
goto err;
}
@@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
/* now get the full information */
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
- data, data_size, 1000);
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
+ data, data_size, 1000);
if (ret < 0) {
- snd_printk(KERN_ERR "unable to retrieve sample rate range\n");
+ snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",
+ __func__, clock);
ret = -EINVAL;
goto err_free;
}
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 03ce971e0027..a060d005e209 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -78,39 +78,6 @@ enum {
USB_MIXER_U16,
};
-enum {
- USB_PROC_UPDOWN = 1,
- USB_PROC_UPDOWN_SWITCH = 1,
- USB_PROC_UPDOWN_MODE_SEL = 2,
-
- USB_PROC_PROLOGIC = 2,
- USB_PROC_PROLOGIC_SWITCH = 1,
- USB_PROC_PROLOGIC_MODE_SEL = 2,
-
- USB_PROC_3DENH = 3,
- USB_PROC_3DENH_SWITCH = 1,
- USB_PROC_3DENH_SPACE = 2,
-
- USB_PROC_REVERB = 4,
- USB_PROC_REVERB_SWITCH = 1,
- USB_PROC_REVERB_LEVEL = 2,
- USB_PROC_REVERB_TIME = 3,
- USB_PROC_REVERB_DELAY = 4,
-
- USB_PROC_CHORUS = 5,
- USB_PROC_CHORUS_SWITCH = 1,
- USB_PROC_CHORUS_LEVEL = 2,
- USB_PROC_CHORUS_RATE = 3,
- USB_PROC_CHORUS_DEPTH = 4,
-
- USB_PROC_DCR = 6,
- USB_PROC_DCR_SWITCH = 1,
- USB_PROC_DCR_RATIO = 2,
- USB_PROC_DCR_MAX_AMP = 3,
- USB_PROC_DCR_THRESHOLD = 4,
- USB_PROC_DCR_ATTACK = 5,
- USB_PROC_DCR_RELEASE = 6,
-};
/*E-mu 0202(0404) eXtension Unit(XU) control*/
enum {
@@ -198,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid,
/*
* find an audio control unit with the given unit id
- * this doesn't return any clock related units, so they need to be handled elsewhere
*/
static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit)
{
- unsigned char *p;
+ /* we just parse the header */
+ struct uac_feature_unit_descriptor *hdr = NULL;
- p = NULL;
- while ((p = snd_usb_find_desc(state->buffer, state->buflen, p,
- USB_DT_CS_INTERFACE)) != NULL) {
- if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit)
- return p;
+ while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr,
+ USB_DT_CS_INTERFACE)) != NULL) {
+ if (hdr->bLength >= 4 &&
+ hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL &&
+ hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER &&
+ hdr->bUnitID == unit)
+ return hdr;
}
+
return NULL;
}
-
/*
* copy a string with the given id
*/
@@ -344,8 +313,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
buf, sizeof(buf), 1000);
if (ret < 0) {
- snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
+ snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
+ request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type);
return ret;
}
@@ -462,6 +431,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int index, int value)
{
int err;
+ unsigned int read_only = (channel == 0) ?
+ cval->master_readonly :
+ cval->ch_readonly & (1 << (channel - 1));
+
+ if (read_only) {
+ snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n",
+ __func__, channel, cval->control);
+ return 0;
+ }
+
err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel,
value);
if (err < 0)
@@ -631,6 +610,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm
*/
static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term)
{
+ int err;
void *p1;
memset(term, 0, sizeof(*term));
@@ -651,6 +631,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
term->channels = d->bNrChannels;
term->chconfig = le32_to_cpu(d->bmChannelConfig);
term->name = d->iTerminal;
+
+ /* call recursively to get the clock selectors */
+ err = check_input_term(state, d->bCSourceID, term);
+ if (err < 0)
+ return err;
}
return 0;
case UAC_FEATURE_UNIT: {
@@ -667,7 +652,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
term->name = uac_mixer_unit_iMixer(d);
return 0;
}
- case UAC_SELECTOR_UNIT: {
+ case UAC_SELECTOR_UNIT:
+ case UAC2_CLOCK_SELECTOR: {
struct uac_selector_unit_descriptor *d = p1;
/* call recursively to retrieve the channel info */
if (check_input_term(state, d->baSourceID[0], term) < 0)
@@ -690,6 +676,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_
term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol);
return 0;
}
+ case UAC2_CLOCK_SOURCE: {
+ struct uac_clock_source_descriptor *d = p1;
+ term->type = d->bDescriptorSubtype << 16; /* virtual type */
+ term->id = id;
+ term->name = d->iClockSource;
+ return 0;
+ }
default:
return -ENODEV;
}
@@ -709,16 +702,20 @@ struct usb_feature_control_info {
};
static struct usb_feature_control_info audio_feature_info[] = {
- { "Mute", USB_MIXER_INV_BOOLEAN },
- { "Volume", USB_MIXER_S16 },
+ { "Mute", USB_MIXER_INV_BOOLEAN },
+ { "Volume", USB_MIXER_S16 },
{ "Tone Control - Bass", USB_MIXER_S8 },
{ "Tone Control - Mid", USB_MIXER_S8 },
{ "Tone Control - Treble", USB_MIXER_S8 },
{ "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */
- { "Auto Gain Control", USB_MIXER_BOOLEAN },
- { "Delay Control", USB_MIXER_U16 },
- { "Bass Boost", USB_MIXER_BOOLEAN },
- { "Loudness", USB_MIXER_BOOLEAN },
+ { "Auto Gain Control", USB_MIXER_BOOLEAN },
+ { "Delay Control", USB_MIXER_U16 },
+ { "Bass Boost", USB_MIXER_BOOLEAN },
+ { "Loudness", USB_MIXER_BOOLEAN },
+ /* UAC2 specific */
+ { "Input Gain Control", USB_MIXER_U16 },
+ { "Input Gain Pad Control", USB_MIXER_BOOLEAN },
+ { "Phase Inverter Control", USB_MIXER_BOOLEAN },
};
@@ -958,7 +955,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str)
static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
unsigned int ctl_mask, int control,
struct usb_audio_term *iterm, int unitid,
- int read_only)
+ int readonly_mask)
{
struct uac_feature_unit_descriptor *desc = raw_desc;
unsigned int len = 0;
@@ -970,7 +967,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
control++; /* change from zero-based to 1-based value */
- if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) {
+ if (control == UAC_FU_GRAPHIC_EQUALIZER) {
/* FIXME: not supported yet */
return;
}
@@ -989,20 +986,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
cval->control = control;
cval->cmask = ctl_mask;
cval->val_type = audio_feature_info[control-1].type;
- if (ctl_mask == 0)
+ if (ctl_mask == 0) {
cval->channels = 1; /* master channel */
- else {
+ cval->master_readonly = readonly_mask;
+ } else {
int i, c = 0;
for (i = 0; i < 16; i++)
if (ctl_mask & (1 << i))
c++;
cval->channels = c;
+ cval->ch_readonly = readonly_mask;
}
/* get min/max values */
get_min_max(cval, 0);
- if (read_only)
+ /* if all channels in the mask are marked read-only, make the control
+ * read-only. set_cur_mix_value() will check the mask again and won't
+ * issue write commands to read-only channels. */
+ if (cval->channels == readonly_mask)
kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval);
else
kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval);
@@ -1021,8 +1023,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kctl->id.name, sizeof(kctl->id.name));
switch (control) {
- case UAC_MUTE_CONTROL:
- case UAC_VOLUME_CONTROL:
+ case UAC_FU_MUTE:
+ case UAC_FU_VOLUME:
/* determine the control name. the rule is:
* - if a name id is given in descriptor, use it.
* - if the connected input can be determined, then use the name
@@ -1049,9 +1051,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
len = append_ctl_name(kctl, " Playback");
}
}
- append_ctl_name(kctl, control == UAC_MUTE_CONTROL ?
+ append_ctl_name(kctl, control == UAC_FU_MUTE ?
" Switch" : " Volume");
- if (control == UAC_VOLUME_CONTROL) {
+ if (control == UAC_FU_VOLUME) {
kctl->tlv.c = mixer_vol_tlv;
kctl->vd[0].access |=
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
@@ -1150,7 +1152,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
snd_printk(KERN_INFO
"usbmixer: master volume quirk for PCM2702 chip\n");
/* disable non-functional volume control */
- master_bits &= ~UAC_FU_VOLUME;
+ master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME);
break;
}
if (channels > 0)
@@ -1188,19 +1190,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void
for (j = 0; j < channels; j++) {
unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize);
- if (mask & (1 << (i * 2))) {
+ if (uac2_control_is_readable(mask, i)) {
ch_bits |= (1 << j);
- if (~mask & (1 << ((i * 2) + 1)))
+ if (!uac2_control_is_writeable(mask, i))
ch_read_only |= (1 << j);
}
}
- /* FIXME: the whole unit is read-only if any of the channels is marked read-only */
+ /* NOTE: build_feature_ctl() will mark the control read-only if all channels
+ * are marked read-only in the descriptors. Otherwise, the control will be
+ * reported as writeable, but the driver will not actually issue a write
+ * command for read-only channels */
if (ch_bits & 1) /* the first channel must be set (for ease of programming) */
- build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only);
- if (master_bits & (1 << i * 2))
+ build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only);
+ if (uac2_control_is_readable(master_bits, i))
build_feature_ctl(state, _ftr, 0, i, &iterm, unitid,
- ~master_bits & (1 << ((i * 2) + 1)));
+ !uac2_control_is_writeable(master_bits, i));
}
}
@@ -1392,51 +1397,51 @@ struct procunit_info {
};
static struct procunit_value_info updown_proc_info[] = {
- { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
+ { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
{ 0 }
};
static struct procunit_value_info prologic_proc_info[] = {
- { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 },
+ { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 },
{ 0 }
};
static struct procunit_value_info threed_enh_proc_info[] = {
- { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 },
+ { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 },
{ 0 }
};
static struct procunit_value_info reverb_proc_info[] = {
- { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
- { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 },
- { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 },
+ { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 },
+ { UAC_REVERB_TIME, "Time", USB_MIXER_U16 },
+ { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 },
{ 0 }
};
static struct procunit_value_info chorus_proc_info[] = {
- { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
- { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
- { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
+ { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 },
+ { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 },
+ { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 },
{ 0 }
};
static struct procunit_value_info dcr_proc_info[] = {
- { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN },
- { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 },
- { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 },
- { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
- { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 },
- { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 },
+ { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN },
+ { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 },
+ { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 },
+ { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 },
+ { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 },
+ { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 },
{ 0 }
};
static struct procunit_info procunits[] = {
- { USB_PROC_UPDOWN, "Up Down", updown_proc_info },
- { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info },
- { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info },
- { USB_PROC_REVERB, "Reverb", reverb_proc_info },
- { USB_PROC_CHORUS, "Chorus", chorus_proc_info },
- { USB_PROC_DCR, "DCR", dcr_proc_info },
+ { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info },
+ { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info },
+ { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info },
+ { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info },
+ { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info },
+ { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info },
{ 0 },
};
/*
@@ -1524,7 +1529,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw
cval->channels = 1;
/* get min/max values */
- if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) {
+ if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) {
__u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol);
/* FIXME: hard-coded */
cval->min = 1;
@@ -1619,7 +1624,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_
struct usb_mixer_elem_info *cval = kcontrol->private_data;
int val, err;
- err = get_cur_ctl_value(cval, 0, &val);
+ err = get_cur_ctl_value(cval, cval->control << 8, &val);
if (err < 0) {
if (cval->mixer->ignore_ctl_error) {
ucontrol->value.enumerated.item[0] = 0;
@@ -1638,7 +1643,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
struct usb_mixer_elem_info *cval = kcontrol->private_data;
int val, oval, err;
- err = get_cur_ctl_value(cval, 0, &oval);
+ err = get_cur_ctl_value(cval, cval->control << 8, &oval);
if (err < 0) {
if (cval->mixer->ignore_ctl_error)
return 0;
@@ -1647,7 +1652,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
val = ucontrol->value.enumerated.item[0];
val = get_abs_value(cval, val);
if (val != oval) {
- set_cur_ctl_value(cval, 0, val);
+ set_cur_ctl_value(cval, cval->control << 8, val);
return 1;
}
return 0;
@@ -1729,6 +1734,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
cval->res = 1;
cval->initialized = 1;
+ if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
+ cval->control = UAC2_CX_CLOCK_SELECTOR;
+ else
+ cval->control = 0;
+
namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL);
if (! namelist) {
snd_printk(KERN_ERR "cannot malloc\n");
@@ -1778,7 +1788,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void
if (! len)
strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name));
- if ((state->oterm.type & 0xff00) == 0x0100)
+ if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR)
+ append_ctl_name(kctl, " Clock Source");
+ else if ((state->oterm.type & 0xff00) == 0x0100)
append_ctl_name(kctl, " Capture Source");
else
append_ctl_name(kctl, " Playback Source");
@@ -1812,10 +1824,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid)
switch (p1[2]) {
case UAC_INPUT_TERMINAL:
+ case UAC2_CLOCK_SOURCE:
return 0; /* NOP */
case UAC_MIXER_UNIT:
return parse_audio_mixer_unit(state, unitid, p1);
case UAC_SELECTOR_UNIT:
+ case UAC2_CLOCK_SELECTOR:
return parse_audio_selector_unit(state, unitid, p1);
case UAC_FEATURE_UNIT:
return parse_audio_feature_unit(state, unitid, p1);
@@ -1912,6 +1926,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
err = parse_audio_unit(&state, desc->bSourceID);
if (err < 0)
return err;
+
+ /* for UAC2, use the same approach to also add the clock selectors */
+ err = parse_audio_unit(&state, desc->bCSourceID);
+ if (err < 0)
+ return err;
}
}
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 130123854a6c..a7cf1007fbb0 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -34,6 +34,8 @@ struct usb_mixer_elem_info {
unsigned int id;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
+ unsigned int ch_readonly;
+ unsigned int master_readonly;
int channels;
int val_type;
int min, max, res;
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index d93fc89beba8..f1324c423835 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = {
/* 16: MU (w/o controls) */
{ 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */
{ 17, "Channel Routing", 2 }, /* PU: mode select */
- { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */
- { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */
+ { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */
+ { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */
{ 18, "Master Playback" }, /* FU; others */
/* 19: OT speaker */
/* 20: OT headphone */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 056587de7be4..456829882f40 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -31,6 +31,7 @@
#include "urb.h"
#include "helper.h"
#include "pcm.h"
+#include "clock.h"
/*
* return the current pcm pointer. just based on the hwptr_done value.
@@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
return -EINVAL;
}
-static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
- struct usb_host_interface *alts,
- struct audioformat *fmt, int rate)
-{
- struct usb_device *dev = chip->dev;
- unsigned int ep;
- unsigned char data[3];
- int err, crate;
-
- ep = get_endpoint(alts, 0)->bEndpointAddress;
- /* if endpoint doesn't have sampling rate control, bail out */
- if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
- snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
- dev->devnum, iface, fmt->altsetting);
- return 0;
- }
-
- data[0] = rate;
- data[1] = rate >> 8;
- data[2] = rate >> 16;
- if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
- USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
- UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
- data, sizeof(data), 1000)) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
- dev->devnum, iface, fmt->altsetting, rate, ep);
- return err;
- }
- if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
- USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
- UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
- data, sizeof(data), 1000)) < 0) {
- snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
- dev->devnum, iface, fmt->altsetting, ep);
- return 0; /* some devices don't support reading */
- }
- crate = data[0] | (data[1] << 8) | (data[2] << 16);
- if (crate != rate) {
- snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
- // runtime->rate = crate;
- }
-
- return 0;
-}
-
-static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
- struct usb_host_interface *alts,
- struct audioformat *fmt, int rate)
-{
- struct usb_device *dev = chip->dev;
- unsigned char data[4];
- int err, crate;
-
- data[0] = rate;
- data[1] = rate >> 8;
- data[2] = rate >> 16;
- data[3] = rate >> 24;
- if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
- data, sizeof(data), 1000)) < 0) {
- snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
- dev->devnum, iface, fmt->altsetting, rate);
- return err;
- }
- if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
- data, sizeof(data), 1000)) < 0) {
- snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
- dev->devnum, iface, fmt->altsetting);
- return err;
- }
- crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
- if (crate != rate)
- snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
-
- return 0;
-}
-
-int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
- struct usb_host_interface *alts,
- struct audioformat *fmt, int rate)
-{
- struct usb_interface_descriptor *altsd = get_iface_desc(alts);
-
- switch (altsd->bInterfaceProtocol) {
- case UAC_VERSION_1:
- return set_sample_rate_v1(chip, iface, alts, fmt, rate);
-
- case UAC_VERSION_2:
- return set_sample_rate_v2(chip, iface, alts, fmt, rate);
- }
-
- return -EINVAL;
-}
-
/*
* find a matching format and set up the interface
*/
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 06ebf24d3a4d..24d3319cc34d 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -40,9 +40,6 @@ struct snd_usb_audio {
int num_interfaces;
int num_suspended_intf;
- /* for audio class v2 */
- int clock_id;
-
struct list_head pcm_list; /* list of pcm streams */
int pcm_devs;
@@ -53,6 +50,8 @@ struct snd_usb_audio {
int setup; /* from the 'device_setup' module param */
int nrpacks; /* from the 'nrpacks' module param */
int async_unlink; /* from the 'async_unlink' module param */
+
+ struct usb_host_interface *ctrl_intf; /* the audio control interface */
};
/*
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 44a47e13bd67..99890728409e 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -43,8 +43,10 @@ static int __cmd_buildid_list(void)
if (session == NULL)
return -1;
- if (with_hits)
+ if (with_hits) {
+ symbol_conf.full_paths = true;
perf_session__process_events(session, &build_id__mark_dso_hit_ops);
+ }
perf_session__fprintf_dsos_buildid(session, stdout, with_hits);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 9bc89050e6f8..dc3435e18bde 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -503,7 +503,6 @@ static int __cmd_record(int argc, const char **argv)
{
int i, counter;
struct stat st;
- pid_t pid = 0;
int flags;
int err;
unsigned long waking = 0;
@@ -572,7 +571,7 @@ static int __cmd_record(int argc, const char **argv)
if (forks) {
child_pid = fork();
- if (pid < 0) {
+ if (child_pid < 0) {
perror("failed to fork");
exit(-1);
}
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index f67bce2a83b4..55f3b5dcc731 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1645,6 +1645,7 @@ static struct perf_event_ops event_ops = {
.sample = process_sample_event,
.comm = event__process_comm,
.lost = event__process_lost,
+ .fork = event__process_task,
.ordered_samples = true,
};
diff --git a/tools/perf/scripts/python/check-perf-trace.py b/tools/perf/scripts/python/check-perf-trace.py
index 964d934395ff..d9f7893e315c 100644
--- a/tools/perf/scripts/python/check-perf-trace.py
+++ b/tools/perf/scripts/python/check-perf-trace.py
@@ -51,8 +51,7 @@ def kmem__kmalloc(event_name, context, common_cpu,
flag_str("kmem__kmalloc", "gfp_flags", gfp_flags)),
-def trace_unhandled(event_name, context, common_cpu, common_secs, common_nsecs,
- common_pid, common_comm):
+def trace_unhandled(event_name, context, event_fields_dict):
try:
unhandled[event_name] += 1
except TypeError:
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 50771b5813ee..1f08f008d289 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -370,9 +370,9 @@ static int thread__set_comm_adjust(struct thread *self, const char *comm)
int event__process_comm(event_t *self, struct perf_session *session)
{
- struct thread *thread = perf_session__findnew(session, self->comm.pid);
+ struct thread *thread = perf_session__findnew(session, self->comm.tid);
- dump_printf(": %s:%d\n", self->comm.comm, self->comm.pid);
+ dump_printf(": %s:%d\n", self->comm.comm, self->comm.tid);
if (thread == NULL || thread__set_comm_adjust(thread, self->comm.comm)) {
dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
@@ -532,16 +532,11 @@ out_problem:
int event__process_task(event_t *self, struct perf_session *session)
{
- struct thread *thread = perf_session__findnew(session, self->fork.pid);
- struct thread *parent = perf_session__findnew(session, self->fork.ppid);
+ struct thread *thread = perf_session__findnew(session, self->fork.tid);
+ struct thread *parent = perf_session__findnew(session, self->fork.ptid);
dump_printf("(%d:%d):(%d:%d)\n", self->fork.pid, self->fork.tid,
self->fork.ppid, self->fork.ptid);
- /*
- * A thread clone will have the same PID for both parent and child.
- */
- if (thread == parent)
- return 0;
if (self->header.type == PERF_RECORD_EXIT)
return 0;
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index cbf7eae2ce09..07f89b66b318 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -965,7 +965,7 @@ static int hist_entry__parse_objdump_line(struct hist_entry *self, FILE *file,
* Parse hexa addresses followed by ':'
*/
line_ip = strtoull(tmp, &tmp2, 16);
- if (*tmp2 != ':')
+ if (*tmp2 != ':' || tmp == tmp2)
line_ip = -1;
}
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 81f39cab3aaa..33a632523743 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data,
int size __unused,
unsigned long long nsecs, char *comm)
{
- PyObject *handler, *retval, *context, *t, *obj;
+ PyObject *handler, *retval, *context, *t, *obj, *dict = NULL;
static char handler_name[256];
struct format_field *field;
unsigned long long val;
@@ -232,6 +232,14 @@ static void python_process_event(int cpu, void *data,
sprintf(handler_name, "%s__%s", event->system, event->name);
+ handler = PyDict_GetItemString(main_dict, handler_name);
+ if (handler && !PyCallable_Check(handler))
+ handler = NULL;
+ if (!handler) {
+ dict = PyDict_New();
+ if (!dict)
+ Py_FatalError("couldn't create Python dict");
+ }
s = nsecs / NSECS_PER_SEC;
ns = nsecs - s * NSECS_PER_SEC;
@@ -242,12 +250,20 @@ static void python_process_event(int cpu, void *data,
PyTuple_SetItem(t, n++, PyString_FromString(handler_name));
PyTuple_SetItem(t, n++,
PyCObject_FromVoidPtr(scripting_context, NULL));
- PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
- PyTuple_SetItem(t, n++, PyInt_FromLong(s));
- PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
- PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
- PyTuple_SetItem(t, n++, PyString_FromString(comm));
+ if (handler) {
+ PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
+ PyTuple_SetItem(t, n++, PyInt_FromLong(s));
+ PyTuple_SetItem(t, n++, PyInt_FromLong(ns));
+ PyTuple_SetItem(t, n++, PyInt_FromLong(pid));
+ PyTuple_SetItem(t, n++, PyString_FromString(comm));
+ } else {
+ PyDict_SetItemString(dict, "common_cpu", PyInt_FromLong(cpu));
+ PyDict_SetItemString(dict, "common_s", PyInt_FromLong(s));
+ PyDict_SetItemString(dict, "common_ns", PyInt_FromLong(ns));
+ PyDict_SetItemString(dict, "common_pid", PyInt_FromLong(pid));
+ PyDict_SetItemString(dict, "common_comm", PyString_FromString(comm));
+ }
for (field = event->format.fields; field; field = field->next) {
if (field->flags & FIELD_IS_STRING) {
int offset;
@@ -272,27 +288,31 @@ static void python_process_event(int cpu, void *data,
obj = PyLong_FromUnsignedLongLong(val);
}
}
- PyTuple_SetItem(t, n++, obj);
+ if (handler)
+ PyTuple_SetItem(t, n++, obj);
+ else
+ PyDict_SetItemString(dict, field->name, obj);
+
}
+ if (!handler)
+ PyTuple_SetItem(t, n++, dict);
if (_PyTuple_Resize(&t, n) == -1)
Py_FatalError("error resizing Python tuple");
- handler = PyDict_GetItemString(main_dict, handler_name);
- if (handler && PyCallable_Check(handler)) {
+ if (handler) {
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die(handler_name);
} else {
handler = PyDict_GetItemString(main_dict, "trace_unhandled");
if (handler && PyCallable_Check(handler)) {
- if (_PyTuple_Resize(&t, N_COMMON_FIELDS) == -1)
- Py_FatalError("error resizing Python tuple");
retval = PyObject_CallObject(handler, t);
if (retval == NULL)
handler_call_die("trace_unhandled");
}
+ Py_DECREF(dict);
}
Py_DECREF(t);
@@ -548,12 +568,10 @@ static int python_generate_script(const char *outfile)
}
fprintf(ofp, "def trace_unhandled(event_name, context, "
- "common_cpu, common_secs, common_nsecs,\n\t\t"
- "common_pid, common_comm):\n");
+ "event_fields_dict):\n");
- fprintf(ofp, "\t\tprint_header(event_name, common_cpu, "
- "common_secs, common_nsecs,\n\t\tcommon_pid, "
- "common_comm)\n\n");
+ fprintf(ofp, "\t\tprint ' '.join(['%%s=%%s'%%(k,str(v))"
+ "for k,v in sorted(event_fields_dict.items())])\n\n");
fprintf(ofp, "def print_header("
"event_name, cpu, secs, nsecs, pid, comm):\n"